From a6443cdd87bb0f5fe183dcd7e9fd7c46bea19716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20M=20G=C3=B3mez?= Date: Thu, 4 Apr 2024 14:14:19 +0100 Subject: [PATCH] Adds the `paths` feature option (#1185) * Adds the `paths` feature option #https://github.com/nim-lang/nimble/issues/1166 * re-enable tests * do not allow `paths` escape the package root dir * improves `isSubdirOf` --- readme.markdown | 1 + src/nimble.nim | 36 ++++++++++++++++++++++++------ src/nimblepkg/nimscriptapi.nim | 3 ++- src/nimblepkg/packageinfotypes.nim | 3 ++- src/nimblepkg/packageparser.nim | 2 ++ tests/testdump/testdump.nimble | 1 + tests/tnimbledump.nim | 6 ++++- 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/readme.markdown b/readme.markdown index 38d95997..b6e33189 100644 --- a/readme.markdown +++ b/readme.markdown @@ -28,6 +28,7 @@ The Nimble changelog can be found + ## Repository information This repository has two main branches: `master` and `stable`. diff --git a/src/nimble.nim b/src/nimble.nim index 2f64a262..61b6e53d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -162,7 +162,7 @@ proc processFreeDependencies(pkgInfo: PackageInfo, for i in reverseDependencies: addRevDep(options.nimbleData, i, pkgInfo) -proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string], +proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[seq[string]], args: seq[string], options: Options) = ## Builds a package as specified by ``pkgInfo``. # Handle pre-`build` hook. @@ -184,7 +184,8 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: HashSet[string], args = args args.add "-d:NimblePkgVersion=" & $pkgInfo.basicInfo.version for path in paths: - args.add("--path:" & path.quoteShell) + for p in path: + args.add("--path:" & p.quoteShell) if options.verbosity >= HighPriority: # Hide Nim hints by default args.add("--hints:off") @@ -337,7 +338,7 @@ proc processLockedDependencies(pkgInfo: PackageInfo, options: Options): HashSet[PackageInfo] proc getDependenciesPaths(pkgInfo: PackageInfo, options: Options): - HashSet[string] + HashSet[seq[string]] proc processAllDependencies(pkgInfo: PackageInfo, options: Options): HashSet[PackageInfo] = @@ -356,6 +357,25 @@ proc allDependencies(pkgInfo: PackageInfo, options: Options): HashSet[PackageInf for requires in pkgInfo.taskRequires.values: result.incl pkgInfo.processFreeDependencies(requires, options) +proc isSubdirOf(subdir, baseDir: string): bool = + let + normalizedSubdir = subdir.normalizedPath + normalizedBaseDir = baseDir.normalizedPath & DirSep + + when defined(windows): + normalizedSubdir.toLower.startsWith(normalizedBaseDir.toLower) + else: + normalizedSubdir.startsWith(normalizedBaseDir) + +proc expandPaths(pkgInfo: PackageInfo, options: Options): seq[string] = + var pkgInfo = pkgInfo.toFullInfo(options) + let baseDir = pkgInfo.getRealDir() + result = @[baseDir] + for relativePath in pkgInfo.paths: + let path = baseDir & "/" & relativePath + if path.isSubdirOf(baseDir): + result.add path + proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, url: string, first: bool, fromLockFile: bool, vcsRevision = notSetSha1Hash, @@ -440,7 +460,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # if the build fails then the old package will still be installed. if pkgInfo.bin.len > 0 and not isNimPackage: - let paths = result.deps.map(dep => dep.getRealDir()) + let paths = result.deps.map(dep => dep.expandPaths(options)) let flags = if options.action.typ in {actionInstall, actionPath, actionUninstall, actionDevelop}: options.action.passNimFlags else: @@ -781,9 +801,9 @@ proc install(packages: seq[PkgTuple], options: Options, raise proc getDependenciesPaths(pkgInfo: PackageInfo, options: Options): - HashSet[string] = + HashSet[seq[string]] = let deps = pkgInfo.processAllDependencies(options) - return deps.map(dep => dep.getRealDir()) + return deps.map(dep => dep.expandPaths(options)) proc build(pkgInfo: PackageInfo, options: Options) = ## Builds the package `pkgInfo`. @@ -1123,6 +1143,7 @@ proc dump(options: Options) = fn "binDir", p.binDir fn "srcDir", p.srcDir fn "backend", p.backend + fn "paths", p.paths if json: s = j.pretty echo s @@ -1502,7 +1523,8 @@ proc updatePathsFile(pkgInfo: PackageInfo, options: Options) = let paths = pkgInfo.getDependenciesPaths(options) var pathsFileContent = "--noNimblePath\n" for path in paths: - pathsFileContent &= &"--path:{path.escape}\n" + for p in path: + pathsFileContent &= &"--path:{p.escape}\n" var action = if fileExists(nimblePathsFileName): "updated" else: "generated" writeFile(nimblePathsFileName, pathsFileContent) displayInfo(&"\"{nimblePathsFileName}\" is {action}.") diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 9cefad37..3f1700c7 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -26,7 +26,7 @@ var backend*: string ## The package's backend. skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*, - installExt*, bin*: seq[string] = @[] ## Nimble metadata. + installExt*, bin*, paths*: seq[string] = @[] ## Nimble metadata. requiresData*: seq[string] = @[] ## The package's dependencies. taskRequiresData*: Table[string, seq[string]] ## Task dependencies foreignDeps*: seq[string] = @[] ## The foreign dependencies. Only @@ -141,6 +141,7 @@ proc printPkgInfo(): string = printSeqIfLen installDirs printSeqIfLen installFiles printSeqIfLen installExt + printSeqIfLen paths printSeqIfLen bin printSeqIfLen "nimbleTasks", nimbleTasks.unzip()[0] printSeqIfLen beforeHooks diff --git a/src/nimblepkg/packageinfotypes.nim b/src/nimblepkg/packageinfotypes.nim index 8f2cf531..d1c0d3cb 100644 --- a/src/nimblepkg/packageinfotypes.nim +++ b/src/nimblepkg/packageinfotypes.nim @@ -69,7 +69,8 @@ type lockedDeps*: AllLockFileDeps metaData*: PackageMetaData isLink*: bool - + paths*: seq[string] + Package* = object ## Definition of package from packages.json. # Required fields in a package. name*: string diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 3a8c6fca..acb10dd6 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -271,6 +271,8 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = of "afterhooks": for i in ev.value.multiSplit: result.postHooks.incl(i.normalize) + of "paths": + result.paths.add(ev.value.multiSplit) else: raise nimbleError("Invalid field: " & ev.key) of "deps", "dependencies": diff --git a/tests/testdump/testdump.nimble b/tests/testdump/testdump.nimble index 630b52ac..3e388975 100644 --- a/tests/testdump/testdump.nimble +++ b/tests/testdump/testdump.nimble @@ -2,3 +2,4 @@ description = "Test package for dump command" version = "0.1.0" author = "nigredo-tori" license = "BSD" +paths = @["path"] \ No newline at end of file diff --git a/tests/tnimbledump.nim b/tests/tnimbledump.nim index 9e1fab61..1c6513c6 100644 --- a/tests/tnimbledump.nim +++ b/tests/tnimbledump.nim @@ -54,6 +54,7 @@ bin: "" binDir: "" srcDir: "" backend: "c" +paths: "path" """ let (outp, exitCode) = execNimble("dump", "--ini", "testdump") check: exitCode == 0 @@ -77,7 +78,10 @@ backend: "c" "bin": [], "binDir": "", "srcDir": "", - "backend": "c" + "backend": "c", + "paths": [ + "path" + ] } """ let (outp, exitCode) = execNimble("dump", "--json", "testdump")