diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2023-05-24 16:39:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-24 16:39:58 +0200 |
commit | b63b5c930e143139197dbacd24bad7d263bbd2e3 (patch) | |
tree | 5a1c5c1765933da666b17d3eaab62f121f7c2413 | |
parent | 266cc69f1973773228534f074febd153c472b949 (diff) | |
download | Nim-b63b5c930e143139197dbacd24bad7d263bbd2e3.tar.gz |
Atlas: added 'use' command (#21902)
* Atlas: added 'use' command * typo
-rw-r--r-- | tools/atlas/atlas.md | 21 | ||||
-rw-r--r-- | tools/atlas/atlas.nim | 90 |
2 files changed, 104 insertions, 7 deletions
diff --git a/tools/atlas/atlas.md b/tools/atlas/atlas.md index 3e9bc32e5..40cf6411e 100644 --- a/tools/atlas/atlas.md +++ b/tools/atlas/atlas.md @@ -60,6 +60,27 @@ patch the `nim.cfg` then. Atlas supports the following commands: +## Use <url> / <package name> + +Clone the package behind `url` or `package name` and its dependencies into +the `_deps` directory and make it available for your current project which +should be in the current working directory. Atlas will create or patch +the files `$project.nimble` and `nim.cfg` for you so that you can simply +import the required modules. + +For example: + +``` + mkdir newproject + cd newproject + git init + atlas use lexim + # add `import lexim` to your example.nim file + nim c example.nim + +``` + + ### Clone/Update <url> Clones a URL and all of its dependencies (recursively) into the workspace. diff --git a/tools/atlas/atlas.nim b/tools/atlas/atlas.nim index 0358e107c..ddfbbd086 100644 --- a/tools/atlas/atlas.nim +++ b/tools/atlas/atlas.nim @@ -23,6 +23,8 @@ const Usage: atlas [options] [command] [arguments] Command: + use url|pkgname clone a package and all of its dependencies and make + it importable for the current project clone url|pkgname clone a package and all of its dependencies update url|pkgname update a package and all of its dependencies install proj.nimble use the .nimble file to setup the project's dependencies @@ -193,13 +195,14 @@ proc message(c: var AtlasContext; category: string; p: PackageName; args: vararg msg.add ' ' msg.add a stdout.writeLine msg - inc c.errors proc warn(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Warning] ", p, args) + inc c.errors proc error(c: var AtlasContext; p: PackageName; args: varargs[string]) = message(c, "[Error] ", p, args) + inc c.errors proc sameVersionAs(tag, ver: string): bool = const VersionChars = {'0'..'9', '.'} @@ -424,7 +427,7 @@ proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency]; else: result.add toDestDir(dep.name) -proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = +proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]; startIsDep: bool): seq[string] = result = @[] var i = 0 while i < work.len: @@ -433,7 +436,7 @@ proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] = let oldErrors = c.errors if not dirExists(c.workspace / destDir) and not dirExists(c.depsDir / destDir): - withDir c, (if i == 0: c.workspace else: c.depsDir): + withDir c, (if i != 0 or startIsDep: c.depsDir else: c.workspace): let err = cloneUrl(c, w.url, destDir, false) if err != "": error c, w.name, err @@ -453,7 +456,7 @@ proc readLockFile(c: var AtlasContext) = for d in items(data): c.lockFileToUse[d.dir] = d -proc clone(c: var AtlasContext; start: string): seq[string] = +proc clone(c: var AtlasContext; start: string; startIsDep: bool): seq[string] = # non-recursive clone. let url = toUrl(c, start) var work = @[Dependency(name: toName(start), url: url, commit: "")] @@ -465,7 +468,7 @@ proc clone(c: var AtlasContext; start: string): seq[string] = c.projectDir = c.workspace / toDestDir(work[0].name) if c.lockOption == useLock: readLockFile c - result = cloneLoop(c, work) + result = cloneLoop(c, work, startIsDep) if c.lockOption == genLock: writeFile c.projectDir / LockFileName, toJson(c.lockFileToWrite).pretty @@ -525,7 +528,7 @@ proc installDependencies(c: var AtlasContext; nimbleFile: string) = let (_, pkgname, _) = splitFile(nimbleFile) let dep = Dependency(name: toName(pkgname), url: "", commit: "") discard collectDeps(c, work, dep, nimbleFile) - let paths = cloneLoop(c, work) + let paths = cloneLoop(c, work, startIsDep = true) patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c)) proc updateWorkspace(c: var AtlasContext; dir, filter: string) = @@ -549,6 +552,71 @@ proc updateWorkspace(c: var AtlasContext; dir, filter: string) = else: error c, pkg, "could not fetch current branch name" +proc addUnique[T](s: var seq[T]; elem: sink T) = + if not s.contains(elem): s.add elem + +proc addDepFromNimble(c: var AtlasContext; deps: var seq[string]; project: PackageName; dep: string) = + var depDir = c.workspace / dep + if not dirExists(depDir): + depDir = c.depsDir / dep + if dirExists(depDir): + withDir c, depDir: + let src = findSrcDir(c) + if src.len != 0: + deps.addUnique dep / src + else: + deps.addUnique dep + else: + warn c, project, "cannot find: " & depDir + +proc patchNimbleFile(c: var AtlasContext; dep: string; deps: var seq[string]) = + let thisProject = getCurrentDir().splitPath.tail + let oldErrors = c.errors + let url = toUrl(c, dep) + if oldErrors != c.errors: + warn c, toName(dep), "cannot resolve package name" + else: + var nimbleFile = "" + for x in walkFiles("*.nimble"): + if nimbleFile.len == 0: + nimbleFile = x + else: + # ambiguous .nimble file + warn c, toName(dep), "cannot determine `.nimble` file; there are multiple to choose from" + return + # see if we have this requirement already listed. If so, do nothing: + var found = false + if nimbleFile.len > 0: + let nimbleInfo = extractRequiresInfo(c, nimbleFile) + for r in nimbleInfo.requires: + var tokens: seq[string] = @[] + for token in tokenizeRequires(r): + tokens.add token + if tokens.len > 0: + let oldErrors = c.errors + let urlB = toUrl(c, tokens[0]) + if oldErrors != c.errors: + warn c, toName(tokens[0]), "cannot resolve package name; found in: " & nimbleFile + if url == urlB: + found = true + + if cmpIgnoreCase(tokens[0], "nim") != 0: + c.addDepFromNimble deps, toName(thisProject), tokens[0] + + if not found: + let line = "requires \"$1@#head\"\n" % dep.escape("", "") + if nimbleFile.len > 0: + let oldContent = readFile(nimbleFile) + writeFile nimbleFile, oldContent & "\n" & line + message(c, "[Info] ", toName(thisProject), "updated: " & nimbleFile) + else: + let outfile = thisProject & ".nimble" + writeFile outfile, line + message(c, "[Info] ", toName(thisProject), "created: " & outfile) + c.addDepFromNimble deps, toName(thisProject), dep + else: + message(c, "[Info] ", toName(thisProject), "up to date: " & nimbleFile) + proc main = var action = "" var args: seq[string] = @[] @@ -627,7 +695,7 @@ proc main = error "No action." of "clone", "update": singleArg() - let deps = clone(c, args[0]) + let deps = clone(c, args[0], startIsDep = false) patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c) when MockupRun: if not c.mockupSuccess: @@ -635,6 +703,14 @@ proc main = else: if c.errors > 0: error "There were problems." + of "use": + singleArg() + discard clone(c, args[0], startIsDep = true) + var deps: seq[string] = @[] + patchNimbleFile(c, args[0], deps) + patchNimCfg c, deps, getCurrentDir() + if c.errors > 0: + error "There were problems." of "install": if args.len > 1: error "install command takes a single argument" |