From 7e4db798681f16279d5e8cba7675043e0dbd08e1 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 1 Aug 2021 02:11:26 +0300 Subject: [PATCH] Make special version a set of versions Special versions are made a set of versions. Those are aliases with which a single package can be referred. For example, a package can be simultaneously versions: * 0.1.0 - the normal version from the Nimble file. * #head - the latest commit in the main branch * #master - the main branch name * 3c91b869 - part of the sha1 hash of the latest commit in the main branch When the same package is downloaded a second time (determined by the checksum) instead of proposing to replace it just print a warning that the package is already installed and merge the special version of the new package with a special version of the already installed one. Additionally this commit: - Removes some legacy code for supporting the old package format in the reverse dependencies. - The names of the packages in the reverse dependencies are written without converting to lower case. - The tests are fixed according to the new behavior. Related to nim-lang/nimble#127 --- src/nimble.nim | 100 +++++++++++++++----------- src/nimblepkg/displaymessages.nim | 12 +++- src/nimblepkg/packageinfo.nim | 13 ++-- src/nimblepkg/packageinfotypes.nim | 5 +- src/nimblepkg/packagemetadatafile.nim | 34 +++++++-- src/nimblepkg/packageparser.nim | 4 +- src/nimblepkg/reversedeps.nim | 43 +++++------ src/nimblepkg/version.nim | 10 ++- tests/tdevelopfeature.nim | 28 ++++---- tests/tmultipkgs.nim | 37 +++++++--- tests/tnimscript.nim | 2 + tests/treversedeps.nim | 2 + 12 files changed, 183 insertions(+), 107 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 8b04f1b3..bc5ce811 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -76,8 +76,8 @@ proc processFreeDependencies(pkgInfo: PackageInfo, options: Options): var pkgList {.global.}: seq[PackageInfo] = @[] once: pkgList = initPkgList(pkgInfo, options) - display("Verifying", - "dependencies for $1@$2" % [pkgInfo.basicInfo.name, $pkgInfo.metaData.specialVersion], + display("Verifying", "dependencies for $1@$2" % + [pkgInfo.basicInfo.name, $pkgInfo.basicInfo.version], priority = HighPriority) var reverseDependencies: seq[PackageBasicInfo] = @[] @@ -106,7 +106,15 @@ proc processFreeDependencies(pkgInfo: PackageInfo, options: Options): let (packages, installedPkg) = install(toInstall, options, doPrompt = false, first = false, fromLockFile = false) - result.incl packages + for pkg in packages: + if result.contains pkg: + # If the result already contains the newly tried to install package + # we had to merge its special versions set into the set of the old + # one. + result[pkg].metaData.specialVersions.incl( + pkg.metaData.specialVersions) + else: + result.incl pkg pkg = installedPkg # For addRevDep fillMetaData(pkg, pkg.getRealDir(), false) @@ -119,7 +127,7 @@ proc processFreeDependencies(pkgInfo: PackageInfo, options: Options): # Process the dependencies of this dependency. result.incl processFreeDependencies(pkg.toFullInfo(options), options) if not pkg.isLink: - reverseDependencies.add((pkg.basicInfo.name, pkg.metaData.specialVersion, pkg.basicInfo.checksum)) + reverseDependencies.add(pkg.basicInfo) # Check if two packages of the same name (but different version) are listed # in the path. @@ -260,27 +268,24 @@ proc removePackage(pkgInfo: PackageInfo, options: Options) = reinstallSymlinksForOlderVersion(pkgDestDir, options) options.nimbleData.removeRevDep(pkgInfo) -proc packageExists(pkgInfo: PackageInfo, options: Options): bool = - let pkgDestDir = pkgInfo.getPkgDest(options) - return fileExists(pkgDestDir / packageMetaDataFileName) - -proc promptOverwriteExistingPackage(pkgInfo: PackageInfo, - options: Options): bool = - let message = "$1@$2 already exists. Overwrite?" % - [pkgInfo.basicInfo.name, $pkgInfo.metaData.specialVersion] - return options.prompt(message) - -proc removeOldPackage(pkgInfo: PackageInfo, options: Options) = +proc packageExists(pkgInfo: PackageInfo, options: Options): + Option[PackageInfo] = + ## Checks whether a package `pkgInfo` already exists in the Nimble cache. If a + ## package already exists returns the `PackageInfo` of the package in the + ## cache otherwise returns `none`. Raises a `NimbleError` in the case the + ## package exists in the cache but it is not valid. let pkgDestDir = pkgInfo.getPkgDest(options) - let oldPkgInfo = getPkgInfo(pkgDestDir, options) - removePackage(oldPkgInfo, options) - -proc promptRemovePackageIfExists(pkgInfo: PackageInfo, options: Options): bool = - if packageExists(pkgInfo, options): - if not promptOverwriteExistingPackage(pkgInfo, options): - return false - removeOldPackage(pkgInfo, options) - return true + if not fileExists(pkgDestDir / packageMetaDataFileName): + return none[PackageInfo]() + else: + var oldPkgInfo = initPackageInfo() + try: + oldPkgInfo = pkgDestDir.getPkgInfo(options) + except CatchableError as error: + raise nimbleError(&"The package inside \"{pkgDestDir}\" is invalid.", + details = error) + fillMetaData(oldPkgInfo, pkgDestDir, true) + return some(oldPkgInfo) proc processLockedDependencies(pkgInfo: PackageInfo, options: Options): HashSet[PackageInfo] @@ -329,9 +334,10 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, var depsOptions = options depsOptions.depsOnly = false - # Overwrite the version if the requested version is "#head" or similar. if requestedVer.kind == verSpecial: - pkgInfo.metaData.specialVersion = requestedVer.spe + # Add a version alias to special versions set if requested version is a + # special one. + pkgInfo.metaData.specialVersions.incl requestedVer.spe # Dependencies need to be processed before the creation of the pkg dir. if first and pkgInfo.lockedDeps.len > 0: @@ -343,10 +349,24 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, result.pkg = pkgInfo return result - display("Installing", "$1@$2" % [pkginfo.basicInfo.name, $pkginfo.metaData.specialVersion], - priority = HighPriority) + display("Installing", "$1@$2" % + [pkginfo.basicInfo.name, $pkginfo.basicInfo.version], + priority = HighPriority) - let isPackageAlreadyInCache = pkgInfo.packageExists(options) + let oldPkg = pkgInfo.packageExists(options) + if oldPkg.isSome: + # In the case we already have the same package in the cache then only merge + # the new package special versions to the old one. + displayWarning(pkgAlreadyExistsInTheCacheMsg(pkgInfo)) + var oldPkg = oldPkg.get + oldPkg.metaData.specialVersions.incl pkgInfo.metaData.specialVersions + saveMetaData(oldPkg.metaData, oldPkg.getNimbleFileDir, changeRoots = false) + if result.deps.contains oldPkg: + result.deps[oldPkg].metaData.specialVersions.incl( + oldPkg.metaData.specialVersions) + result.deps.incl oldPkg + result.pkg = oldPkg + return # Build before removing an existing package (if one exists). This way # if the build fails then the old package will still be installed. @@ -361,8 +381,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, try: buildFromDir(pkgInfo, paths, "-d:release" & flags, options) except CatchableError: - if not isPackageAlreadyInCache: - removeRevDep(options.nimbleData, pkgInfo) + removeRevDep(options.nimbleData, pkgInfo) raise let pkgDestDir = pkgInfo.getPkgDest(options) @@ -374,9 +393,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Don't copy artifacts if project local deps mode and "installing" the top # level package. if not (options.localdeps and options.isInstallingTopLevel(dir)): - if not promptRemovePackageIfExists(pkgInfo, options): - return - createDir(pkgDestDir) # Copy this package's files based on the preferences specified in PkgInfo. var filesInstalled: HashSet[string] @@ -797,18 +813,22 @@ proc list(options: Options) = echo(" ") proc listInstalled(options: Options) = - var h: OrderedTable[string, seq[Version]] + type + VersionChecksumTuple = tuple[version: Version, checksum: Sha1Hash] + var h: OrderedTable[string, seq[VersionChecksumTuple]] let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options) for pkg in pkgs: let pName = pkg.basicInfo.name - pVer = pkg.metaData.specialVersion + pVersion = pkg.basicInfo.version + pChecksum = pkg.basicInfo.checksum if not h.hasKey(pName): h[pName] = @[] var s = h[pName] - add(s, pVer) + add(s, (pVersion, pChecksum)) h[pName] = s - h.sort(proc (a, b: (string, seq[Version])): int = cmpIgnoreCase(a[0], b[0])) + h.sort(proc (a, b: (string, seq[VersionChecksumTuple])): int = + cmpIgnoreCase(a[0], b[0])) for k in keys(h): echo k & " [" & h[k].join(", ") & "]" @@ -837,7 +857,7 @@ proc listPaths(options: Options) = # There may be several, list all available ones and sort by version. for pkg in pkgs: if name == pkg.basicInfo.name: - installed.add((pkg.metaData.specialVersion, pkg.getRealDir)) + installed.add((pkg.basicInfo.version, pkg.getRealDir)) if installed.len > 0: sort(installed, cmp[VersionAndPath], Descending) @@ -1127,7 +1147,7 @@ proc uninstall(options: var Options) = if len(revDeps - pkgsToDelete) > 0: let pkgs = revDeps.collectNames(true) displayWarning( - cannotUninstallPkgMsg(pkgTup.name, pkg.metaData.specialVersion, pkgs)) + cannotUninstallPkgMsg(pkgTup.name, pkg.basicInfo.version, pkgs)) else: pkgsToDelete.incl pkg.toRevDep diff --git a/src/nimblepkg/displaymessages.nim b/src/nimblepkg/displaymessages.nim index 013b7a30..1068425b 100644 --- a/src/nimblepkg/displaymessages.nim +++ b/src/nimblepkg/displaymessages.nim @@ -6,7 +6,7 @@ ## the message to be repeated both in Nimble and the testing code. import strformat, strutils -import version +import version, packageinfotypes, sha1hashes const validationFailedMsg* = "Validation failed." @@ -143,3 +143,13 @@ proc invalidDevelopDependenciesVersionsMsg*(errors: seq[string]): string = for error in errors: result &= "\n" result &= error + +proc pkgAlreadyExistsInTheCacheMsg*(name, version, checksum: string): string = + &"A package \"{name}@{version}\" with checksum \"{checksum}\" already " & + "exists the the cache." + +proc pkgAlreadyExistsInTheCacheMsg*(pkgInfo: PackageInfo): string = + pkgAlreadyExistsInTheCacheMsg( + pkgInfo.basicInfo.name, + $pkgInfo.basicInfo.version, + $pkgInfo.basicInfo.checksum) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 20faba3c..ca30441d 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -279,7 +279,7 @@ proc setNameVersionChecksum*(pkgInfo: var PackageInfo, pkgDir: string) = if pkgInfo.basicInfo.version == notSetVersion: # if there is no previously set version from the `.nimble` file pkgInfo.basicInfo.version = version - pkgInfo.metaData.specialVersion = version + pkgInfo.metaData.specialVersions.incl version pkgInfo.basicInfo.checksum = checksum proc getInstalledPackageMin*(pkgDir, nimbleFilePath: string): PackageInfo = @@ -304,11 +304,10 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options): seq[PackageInfo] = result.add pkg proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool = - ## Determines whether the specified package's version is within the - ## specified range. The check works with ordinary versions as well as - ## special ones. - return withinRange(pkgInfo.basicInfo.version, verRange) or - withinRange(pkgInfo.metaData.specialVersion, verRange) + ## Determines whether the specified package's version is within the specified + ## range. As the ordinary version is always added to the special versions set + ## checking only the special versions is enough. + return withinRange(pkgInfo.metaData.specialVersions, verRange) proc resolveAlias*(dep: PkgTuple, options: Options): PkgTuple = ## Looks up the specified ``dep.name`` in the packages.json files to resolve @@ -496,7 +495,7 @@ proc iterInstallFiles*(realDir: string, pkgInfo: PackageInfo, action(file) proc getCacheDir*(pkgInfo: PackageBasicInfo): string = - &"{pkgInfo.name}-{pkgInfo.version}-{pkgInfo.checksum}" + &"{pkgInfo.name}-{pkgInfo.version}-{$pkgInfo.checksum}" proc getPkgDest*(pkgInfo: PackageBasicInfo, options: Options): string = options.getPkgsDir() / pkgInfo.getCacheDir() diff --git a/src/nimblepkg/packageinfotypes.nim b/src/nimblepkg/packageinfotypes.nim index e3e501e1..482ab1c3 100644 --- a/src/nimblepkg/packageinfotypes.nim +++ b/src/nimblepkg/packageinfotypes.nim @@ -27,7 +27,10 @@ type vcsRevision*: Sha1Hash files*: seq[string] binaries*: seq[string] - specialVersion*: Version + specialVersions*: HashSet[Version] + # Special versions are aliases with which a single package can be + # referred. For example a package can be versions `0.1.0`, `#head` and + # `#master` at the same time. PackageBasicInfo* = tuple name: string diff --git a/src/nimblepkg/packagemetadatafile.nim b/src/nimblepkg/packagemetadatafile.nim index 48d88fa0..6d28ab8e 100644 --- a/src/nimblepkg/packagemetadatafile.nim +++ b/src/nimblepkg/packagemetadatafile.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import json, os, strformat +import json, os, strformat, sets, sequtils import common, version, packageinfotypes, cli, tools, sha1hashes type @@ -17,20 +17,40 @@ const proc initPackageMetaData*(): PackageMetaData = result = PackageMetaData( - specialVersion: notSetVersion, vcsRevision: notSetSha1Hash) proc metaDataError(msg: string): ref MetaDataError = newNimbleError[MetaDataError](msg) -proc saveMetaData*(metaData: PackageMetaData, dirName: string) = +proc `%`(specialVersions: HashSet[Version]): JsonNode = + %specialVersions.toSeq + +proc initFromJson(specialVersions: var HashSet[Version], jsonNode: JsonNode, + jsonPath: var string) = + case jsonNode.kind + of JArray: + let originalJsonPathLen = jsonPath.len + for i in 0 ..< jsonNode.len: + jsonPath.add '[' + jsonPath.addInt i + jsonPath.add ']' + var version = newVersion("") + initFromJson(version, jsonNode[i], jsonPath) + specialVersions.incl version + jsonPath.setLen originalJsonPathLen + else: + assert false, "The `jsonNode` must be of kind JArray." + +proc saveMetaData*(metaData: PackageMetaData, dirName: string, + changeRoots = true) = ## Saves some important data to file in the package installation directory. var metaDataWithChangedPaths = metaData - for i, file in metaData.files: - metaDataWithChangedPaths.files[i] = changeRoot(dirName, "", file) + if changeRoots: + for i, file in metaData.files: + metaDataWithChangedPaths.files[i] = changeRoot(dirName, "", file) let json = %{ $pmdjkVersion: %packageMetaDataFileVersion, - $pmdjkMetaData: %metaDataWithChangedPaths } + $pmdjkMetaData: %metaDataWithChangedPaths} writeFile(dirName / packageMetaDataFileName, json.pretty) proc loadMetaData*(dirName: string, raiseIfNotFound: bool): PackageMetaData = @@ -39,7 +59,9 @@ proc loadMetaData*(dirName: string, raiseIfNotFound: bool): PackageMetaData = let fileName = dirName / packageMetaDataFileName if fileExists(fileName): {.warning[ProveInit]: off.} + {.warning[UnsafeSetLen]: off.} result = parseFile(fileName)[$pmdjkMetaData].to(PackageMetaData) + {.warning[UnsafeSetLen]: on.} {.warning[ProveInit]: on.} elif raiseIfNotFound: raise metaDataError(&"No {packageMetaDataFileName} file found in {dirName}") diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index d950ddf3..3e8f8faa 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -383,7 +383,7 @@ proc readPackageInfo(nf: NimbleFile, options: Options, onlyMinimalInfo=false): # some of the package meta data from its directory. result.basicInfo.checksum = calculateDirSha1Checksum(fileDir) # By default specialVersion is the same as version. - result.metaData.specialVersion = result.basicInfo.version + result.metaData.specialVersions.incl result.basicInfo.version # If the `fileDir` is a VCS repository we can get some of the package meta # data from it. result.metaData.vcsRevision = getVcsRevision(fileDir) @@ -497,7 +497,7 @@ proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo = # The `isLink` data from the meta data file is with priority because of the # old format develop packages. result.isLink = pkg.isLink - result.metaData.specialVersion = pkg.metaData.specialVersion + result.metaData.specialVersions.incl pkg.metaData.specialVersions assert not (pkg.isInstalled and pkg.isLink), "A package must not be simultaneously installed and linked." diff --git a/src/nimblepkg/reversedeps.nim b/src/nimblepkg/reversedeps.nim index 73980aa0..f3d06e93 100644 --- a/src/nimblepkg/reversedeps.nim +++ b/src/nimblepkg/reversedeps.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import json, sets, os, hashes, unicode +import json, sets, os, hashes import options, version, download, jsonhelpers, nimbledatafile, sha1hashes, packageinfotypes, packageinfo, packageparser @@ -51,7 +51,7 @@ proc addRevDep*(nimbleData: JsonNode, dep: PackageBasicInfo, let dependencies = nimbleData.addIfNotExist( $ndjkRevDep, - dep.name.toLower, + dep.name, $dep.version, $dep.checksum, newJArray()) @@ -59,7 +59,7 @@ proc addRevDep*(nimbleData: JsonNode, dep: PackageBasicInfo, var dependency: JsonNode if not pkg.isLink: dependency = %{ - $ndjkRevDepName: %pkg.basicInfo.name.toLower, + $ndjkRevDepName: %pkg.basicInfo.name, $ndjkRevDepVersion: %pkg.basicInfo.version, $ndjkRevDepChecksum: %pkg.basicInfo.checksum} else: @@ -87,18 +87,8 @@ proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) = # It is compared by its directory path. newVal.add rd elif rd[$ndjkRevDepChecksum].str != $pkg.basicInfo.checksum: - # For the reverse dependencies added since the introduction of the - # new format comparison of the checksums is specific enough. + # Installed dependencies are compared by checksum. newVal.add rd - else: - # But if the both checksums are not present, those are converted - # from the old format packages and they must be compared by the - # `name` and `specialVersion` fields. - if rd[$ndjkRevDepChecksum].str.len == 0 and - pkg.basicInfo.checksum == notSetSha1Hash: - if rd[$ndjkRevDepName].str != pkg.basicInfo.name.toLower or - rd[$ndjkRevDepVersion].str != $pkg.metaData.specialVersion: - newVal.add rd revDepsForVersion[checksum] = newVal let reverseDependencies = nimbleData[$ndjkRevDep] @@ -109,7 +99,7 @@ proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) = for key, val in reverseDependencies: remove(pkg, depTup, val) else: - let thisDep = nimbleData{$ndjkRevDep, depTup.name.toLower} + let thisDep = nimbleData{$ndjkRevDep, depTup.name} if thisDep.isNil: continue remove(pkg, depTup, thisDep) @@ -124,7 +114,7 @@ proc getRevDeps*(nimbleData: JsonNode, pkg: ReverseDependency): return let reverseDependencies = nimbleData[$ndjkRevDep]{ - pkg.pkgInfo.name.toLower}{$pkg.pkgInfo.version}{$pkg.pkgInfo.checksum} + pkg.pkgInfo.name}{$pkg.pkgInfo.version}{$pkg.pkgInfo.checksum} if reverseDependencies.isNil: return @@ -176,8 +166,7 @@ when isMainModule: proc initMetaData: PackageMetaData = result = PackageMetaData( - vcsRevision: notSetSha1Hash, - specialVersion: notSetVersion) + vcsRevision: notSetSha1Hash) proc parseRequires(requires: RequiresSeq): seq[PkgTuple] = requires.mapIt((it.name, it.versionRange.parseVersionRange)) @@ -200,7 +189,7 @@ when isMainModule: let nimforum1 = initPackageInfo( "nimforum", "0.1.0", "46a96c3f2b0ecb3d3f7bd71e12200ed401e9b9f2", - @[("jester", "0.1.0"), ("captcha", "1.0.0"), ("auth", "#head")]) + @[("jester", "0.1.0"), ("captcha", "1.0.0"), ("auth", "2.0.0")]) nimforum1RevDep = nimforum1.toRevDep nimforum2 = initPackageInfo( @@ -218,21 +207,22 @@ when isMainModule: jester = initPackageInfo( "jester", "0.1.0", "1b629f98b23614df292f176a1681fa439dcc05e2") - jesterWithoutSha1 = initPackageInfo("jester", "0.1.0", "") + jester2 = initPackageInfo( + "jester", "0.1.0", "deff1d836528db4fd128932ebd48e568e52b7bb4") captcha = initPackageInfo( "captcha", "1.0.0", "ce128561b06dd106a83638ad415a2a52548f388e") captchaRevDep = captcha.toRevDep auth = initPackageInfo( - "auth", "#head", "c81545df8a559e3da7d38d125e0eaf2b4478cd01") + "auth", "2.0.0", "c81545df8a559e3da7d38d125e0eaf2b4478cd01") authRevDep = auth.toRevDep suite "reverse dependencies": setup: var nimbleData = newNimbleDataNode() nimbleData.addRevDep(jester.basicInfo, nimforum1) - nimbleData.addRevDep(jesterWithoutSha1.basicInfo, play) + nimbleData.addRevDep(jester2.basicInfo, play) nimbleData.addRevDep(captcha.basicInfo, nimforum1) nimbleData.addRevDep(captcha.basicInfo, nimforum2) nimbleData.addRevDep(captcha.basicInfo, nimforumDevelop) @@ -253,7 +243,7 @@ when isMainModule: "checksum": "46a96c3f2b0ecb3d3f7bd71e12200ed401e9b9f2" } ], - "": [ + "deff1d836528db4fd128932ebd48e568e52b7bb4": [ { "name": "play", "version": "2.0.1", @@ -282,7 +272,7 @@ when isMainModule: } }, "auth": { - "#head": { + "2.0.0": { "c81545df8a559e3da7d38d125e0eaf2b4478cd01": [ { "name": "nimforum", @@ -313,7 +303,7 @@ when isMainModule: "reverseDeps": { "jester": { "0.1.0": { - "": [ + "deff1d836528db4fd128932ebd48e568e52b7bb4": [ { "name": "play", "version": "2.0.1", @@ -334,7 +324,7 @@ when isMainModule: } }, "auth": { - "#head": { + "2.0.0": { "c81545df8a559e3da7d38d125e0eaf2b4478cd01": [ { "name": "nimforum", @@ -367,4 +357,3 @@ when isMainModule: nimbleData.getAllRevDeps(authRevDep, revDeps) check revDeps == [authRevDep, nimforum1RevDep, nimforum2RevDep, nimforumDevelopRevDep, captchaRevDep].toHashSet - diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 3ecaf932..5515274e 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -2,7 +2,7 @@ # BSD License. Look at license.txt for more info. ## Module for handling versions and version ranges such as ``>= 1.0 & <= 1.5`` -import json +import json, sets import common, strutils, tables, hashes, parseutils type @@ -148,6 +148,14 @@ proc withinRange*(ver: Version, ran: VersionRange): bool = of verAny: return true +proc withinRange*(versions: HashSet[Version], range: VersionRange): bool = + ## Checks whether any of the versions from the set `versions` are in the range + ## `range`. + + for version in versions: + if withinRange(version, range): + return true + proc contains*(ran: VersionRange, ver: Version): bool = return withinRange(ver, ran) diff --git a/tests/tdevelopfeature.nim b/tests/tdevelopfeature.nim index e7af50fd..b0a2a0e5 100644 --- a/tests/tdevelopfeature.nim +++ b/tests/tdevelopfeature.nim @@ -17,8 +17,8 @@ suite "develop feature": dependentPkgName = "dependent" dependentPkgPath = "develop/dependent".normalizedPath includeFileName = "included.develop" - pkgAName = "packagea" - pkgBName = "packageb" + pkgAName = "PackageA" + pkgBName = "PackageB" pkgSrcDirTestName = "srcdirtest" pkgHybridName = "hybrid" depPath = "../dependency".normalizedPath @@ -173,7 +173,7 @@ suite "develop feature": let (output, exitCode) = execNimble( "develop", &"-p:{installDir}", pkgAName) - pkgAAbsPath = installDir / pkgAName + pkgAAbsPath = installDir / pkgAName.toLower developFileContent = developFile(@[], @[pkgAAbsPath]) check exitCode == QuitSuccess check parseFile(developFileName) == parseJson(developFileContent) @@ -190,8 +190,8 @@ suite "develop feature": let (output, exitCode) = execNimble( "develop", &"-p:{installDir}", pkgAName, pkgBName) - pkgAAbsPath = installDir / pkgAName - pkgBAbsPath = installDir / pkgBName + pkgAAbsPath = installDir / pkgAName.toLower + pkgBAbsPath = installDir / pkgBName.toLower developFileContent = developFile(@[], @[pkgAAbsPath, pkgBAbsPath]) check exitCode == QuitSuccess check parseFile(developFileName) == parseJson(developFileContent) @@ -518,13 +518,17 @@ suite "develop feature": check not devRevDepPath.isNil check devRevDepPath.str == depAbsPath - block checkSuccessfulUninstallAndRemovalFromNimbleData: + block checkSuccessfulUninstallButNotRemoveFromNimbleData: let - (_, exitCode) = execNimble("uninstall", "-i", pkgAName, "-y") + (_, exitCode) = execNimbleYes("uninstall", "-i", pkgAName) nimbleData = parseFile(installDir / nimbleDataFileName) check exitCode == QuitSuccess - check not nimbleData[$ndjkRevDep].hasKey(pkgAName) + # The package should remain in the Nimble data because in the case it + # is installed again it should continue to block its uninstalling + # without the "-i" option until all reverse dependencies (leaf nodes + # of the JSON object) are uninstalled. + check nimbleData[$ndjkRevDep].hasKey(pkgAName) test "follow develop dependency's develop file": cd "develop": @@ -848,8 +852,8 @@ suite "develop feature": "--with-dependencies", &"--develop-file:{developFile}", pkgBName) check exitCode == QuitSuccess let - pkgAPath = installDir / pkgAName - pkgBPath = installDir / pkgBName + pkgAPath = installDir / pkgAName.toLower + pkgBPath = installDir / pkgBName.toLower var lines = output.processOutput check lines.inLinesOrdered(pkgSetupInDevModeMsg(pkgAName, pkgAPath)) check lines.inLinesOrdered(pkgSetupInDevModeMsg(pkgBName, pkgBPath)) @@ -886,7 +890,7 @@ suite "develop feature": check errorCode == QuitFailure var lines = output.processOutput check lines.inLinesOrdered(pkgSetupInDevModeMsg( - pkgAName, installDir / pkgAName)) + pkgAName, installDir / pkgAName.toLower)) check lines.inLinesOrdered(pkgAddedInDevFileMsg( depNameAndVersion, depPath, developFileName)) check lines.inLinesOrdered(pkgAlreadyPresentAtDifferentPathMsg( @@ -904,6 +908,6 @@ suite "develop feature": includeFileName, developFileName)) check lines.inLinesOrdered(failedToLoadFileMsg(invalidInclFilePath)) let expectedDevelopFileContent = developFile( - @[includeFileName], @[dep2Path, installDir / pkgAName]) + @[includeFileName], @[dep2Path, installDir / pkgAName.toLower]) check parseFile(developFileName) == parseJson(expectedDevelopFileContent) diff --git a/tests/tmultipkgs.nim b/tests/tmultipkgs.nim index abcee9a1..976bd07e 100644 --- a/tests/tmultipkgs.nim +++ b/tests/tmultipkgs.nim @@ -3,22 +3,39 @@ {.used.} -import unittest, strutils +import unittest, os import testscommon +from nimblepkg/common import nimblePackagesDirName +from nimblepkg/version import `$` +from nimblepkg/sha1hashes import `$` +from nimblepkg/displaymessages import pkgAlreadyExistsInTheCacheMsg +from nimblepkg/tools import getNameVersionChecksum + +template installAlpha = + cleanDir installDir + var args {.inject.} = @["install", pkgMultiAlphaUrl] + let (output, exitCode) = execNimbleYes(args) + check exitCode == QuitSuccess + check output.processOutput.inLines("alpha installed successfully") + suite "multi": test "can install package from git subdir": - var - args = @["install", pkgMultiAlphaUrl] - (output, exitCode) = execNimbleYes(args) - check exitCode == QuitSuccess + installAlpha() - # Issue 785 - args.add @[pkgMultiBetaUrl, "-n"] - (output, exitCode) = execNimble(args) + test "do not replace a package if already installed": + installAlpha() + args.add pkgMultiBetaUrl + let (output, exitCode) = execNimbleYes(args) check exitCode == QuitSuccess - check output.contains("forced no") - check output.contains("beta installed successfully") + var lines = output.processOutput + for _, dir in walkDir(installDir / nimblePackagesDirName): + let (name, version, checksum) = getNameVersionChecksum(dir) + if name != "alpha": continue + check lines.inLinesOrdered( + pkgAlreadyExistsInTheCacheMsg(name, $version, $checksum)) + break + check lines.inLinesOrdered("beta installed successfully") test "can develop package from git subdir": cleanDir "beta" diff --git a/tests/tnimscript.nim b/tests/tnimscript.nim index 884e076d..789997b1 100644 --- a/tests/tnimscript.nim +++ b/tests/tnimscript.nim @@ -9,12 +9,14 @@ from nimblepkg/common import cd suite "nimscript": test "can install nimscript package": + cleanDir installDir cd "nimscript": let nim = findExe("nim").relativePath(base = getCurrentDir()) check execNimbleYes(["install", "--nim:" & nim]).exitCode == QuitSuccess test "before/after install pkg dirs are correct": + cleanDir installDir cd "nimscript": let (output, exitCode) = execNimbleYes(["install", "--nim:nim"]) check exitCode == QuitSuccess diff --git a/tests/treversedeps.nim b/tests/treversedeps.nim index 7928d349..6e29ccf4 100644 --- a/tests/treversedeps.nim +++ b/tests/treversedeps.nim @@ -47,6 +47,8 @@ suite "reverse dependencies": cd "revdep/pkgWithDep": verify execNimbleYes("install") + verify execNimbleYes("remove", "pkgA") + cd "revdep/pkgNoDep": verify execNimbleYes("install")