implemented 'atlas install' command (#20530)
This commit is contained in:
parent
944e4cf585
commit
0f2775aacf
1 changed files with 90 additions and 52 deletions
|
|
@ -13,7 +13,7 @@ import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonuti
|
||||||
import parse_requires, osutils, packagesjson
|
import parse_requires, osutils, packagesjson
|
||||||
|
|
||||||
const
|
const
|
||||||
Version = "0.1"
|
Version = "0.2"
|
||||||
Usage = "atlas - Nim Package Cloner Version " & Version & """
|
Usage = "atlas - Nim Package Cloner Version " & Version & """
|
||||||
|
|
||||||
(c) 2021 Andreas Rumpf
|
(c) 2021 Andreas Rumpf
|
||||||
|
|
@ -21,6 +21,7 @@ Usage:
|
||||||
atlas [options] [command] [arguments]
|
atlas [options] [command] [arguments]
|
||||||
Command:
|
Command:
|
||||||
clone url|pkgname clone a package and all of its dependencies
|
clone url|pkgname clone a package and all of its dependencies
|
||||||
|
install proj.nimble use the .nimble file to setup the project's dependencies
|
||||||
search keyw keywB... search for package that contains the given keywords
|
search keyw keywB... search for package that contains the given keywords
|
||||||
extract file.nimble extract the requirements and custom commands from
|
extract file.nimble extract the requirements and custom commands from
|
||||||
the given Nimble file
|
the given Nimble file
|
||||||
|
|
@ -87,7 +88,7 @@ include testdata
|
||||||
|
|
||||||
proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, int) =
|
proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, int) =
|
||||||
when MockupRun:
|
when MockupRun:
|
||||||
assert TestLog[c.step].cmd == cmd
|
assert TestLog[c.step].cmd == cmd, $(TestLog[c.step].cmd, cmd)
|
||||||
case cmd
|
case cmd
|
||||||
of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit:
|
of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit:
|
||||||
result = (TestLog[c.step].output, TestLog[c.step].exitCode)
|
result = (TestLog[c.step].output, TestLog[c.step].exitCode)
|
||||||
|
|
@ -318,53 +319,55 @@ proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency];
|
||||||
work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2],
|
work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2],
|
||||||
rel: toDepRelation(tokens[1]))
|
rel: toDepRelation(tokens[1]))
|
||||||
|
|
||||||
|
template toDestDir(p: PackageName): string = p.string
|
||||||
|
|
||||||
|
proc collectDeps(c: var AtlasContext; work: var seq[Dependency];
|
||||||
|
dep: Dependency; nimbleFile: string): string =
|
||||||
|
# If there is a .nimble file, return the dependency path & srcDir
|
||||||
|
# else return "".
|
||||||
|
assert nimbleFile != ""
|
||||||
|
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 == 1:
|
||||||
|
# nimx uses dependencies like 'requires "sdl2"'.
|
||||||
|
# Via this hack we map them to the first tagged release.
|
||||||
|
# (See the `isStrictlySmallerThan` logic.)
|
||||||
|
tokens.add "<"
|
||||||
|
tokens.add InvalidCommit
|
||||||
|
elif tokens.len == 2 and tokens[1].startsWith("#"):
|
||||||
|
# Dependencies can also look like 'requires "sdl2#head"
|
||||||
|
var commit = tokens[1][1 .. ^1]
|
||||||
|
tokens[1] = "=="
|
||||||
|
tokens.add commit
|
||||||
|
|
||||||
|
if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0:
|
||||||
|
c.addUniqueDep work, tokens
|
||||||
|
result = toDestDir(dep.name) / nimbleInfo.srcDir
|
||||||
|
|
||||||
proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency];
|
proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency];
|
||||||
dep: Dependency; result: var seq[string];
|
dep: Dependency; result: var seq[string];
|
||||||
isMainProject: bool) =
|
isMainProject: bool) =
|
||||||
let nimbleFile = findNimbleFile(c, dep)
|
let nimbleFile = findNimbleFile(c, dep)
|
||||||
if nimbleFile != "":
|
if nimbleFile != "":
|
||||||
let nimbleInfo = extractRequiresInfo(c, nimbleFile)
|
let x = collectDeps(c, work, dep, nimbleFile)
|
||||||
for r in nimbleInfo.requires:
|
result.add x
|
||||||
var tokens: seq[string] = @[]
|
|
||||||
for token in tokenizeRequires(r):
|
|
||||||
tokens.add token
|
|
||||||
if tokens.len == 1:
|
|
||||||
# nimx uses dependencies like 'requires "sdl2"'.
|
|
||||||
# Via this hack we map them to the first tagged release.
|
|
||||||
# (See the `isStrictlySmallerThan` logic.)
|
|
||||||
tokens.add "<"
|
|
||||||
tokens.add InvalidCommit
|
|
||||||
elif tokens.len == 2 and tokens[1].startsWith("#"):
|
|
||||||
# Dependencies can also look like 'requires "sdl2#head"
|
|
||||||
var commit = tokens[1][1 .. ^1]
|
|
||||||
tokens[1] = "=="
|
|
||||||
tokens.add commit
|
|
||||||
|
|
||||||
if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0:
|
|
||||||
c.addUniqueDep work, tokens
|
|
||||||
|
|
||||||
result.add dep.name.string / nimbleInfo.srcDir
|
|
||||||
else:
|
else:
|
||||||
result.add dep.name.string
|
result.add toDestDir(dep.name)
|
||||||
|
|
||||||
proc clone(c: var AtlasContext; start: string): seq[string] =
|
proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] =
|
||||||
# non-recursive clone.
|
|
||||||
let oldErrors = c.errors
|
|
||||||
var work = @[Dependency(name: toName(start), url: toUrl(c, start), commit: "")]
|
|
||||||
|
|
||||||
if oldErrors != c.errors:
|
|
||||||
error c, toName(start), "cannot resolve package name"
|
|
||||||
return
|
|
||||||
|
|
||||||
c.projectDir = c.workspace / work[0].name.string
|
|
||||||
result = @[]
|
result = @[]
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < work.len:
|
while i < work.len:
|
||||||
let w = work[i]
|
let w = work[i]
|
||||||
|
let destDir = toDestDir(w.name)
|
||||||
let oldErrors = c.errors
|
let oldErrors = c.errors
|
||||||
if not dirExists(c.workspace / w.name.string):
|
|
||||||
|
if not dirExists(c.workspace / destDir):
|
||||||
withDir c, c.workspace:
|
withDir c, c.workspace:
|
||||||
let err = cloneUrl(c, w.url, w.name.string, false)
|
let err = cloneUrl(c, w.url, destDir, false)
|
||||||
if err != "":
|
if err != "":
|
||||||
error c, w.name, err
|
error c, w.name, err
|
||||||
if oldErrors == c.errors:
|
if oldErrors == c.errors:
|
||||||
|
|
@ -375,30 +378,38 @@ proc clone(c: var AtlasContext; start: string): seq[string] =
|
||||||
collectNewDeps(c, work, w, result, i == 0)
|
collectNewDeps(c, work, w, result, i == 0)
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
|
proc clone(c: var AtlasContext; start: string): seq[string] =
|
||||||
|
# non-recursive clone.
|
||||||
|
let url = toUrl(c, start)
|
||||||
|
var work = @[Dependency(name: toName(start), url: url, commit: "")]
|
||||||
|
|
||||||
|
if url == "":
|
||||||
|
error c, toName(start), "cannot resolve package name"
|
||||||
|
return
|
||||||
|
|
||||||
|
c.projectDir = c.workspace / toDestDir(work[0].name)
|
||||||
|
result = cloneLoop(c, work)
|
||||||
|
|
||||||
const
|
const
|
||||||
configPatternBegin = "############# begin Atlas config section ##########\n"
|
configPatternBegin = "############# begin Atlas config section ##########\n"
|
||||||
configPatternEnd = "############# end Atlas config section ##########\n"
|
configPatternEnd = "############# end Atlas config section ##########\n"
|
||||||
|
|
||||||
proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgHere: bool) =
|
proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) =
|
||||||
var paths = "--noNimblePath\n"
|
var paths = "--noNimblePath\n"
|
||||||
if cfgHere:
|
for d in deps:
|
||||||
let cwd = getCurrentDir()
|
let pkgname = toDestDir d.PackageName
|
||||||
for d in deps:
|
let x = relativePath(c.workspace / pkgname, cfgPath, '/')
|
||||||
let x = relativePath(c.workspace / d, cwd, '/')
|
paths.add "--path:\"" & x & "\"\n"
|
||||||
paths.add "--path:\"" & x & "\"\n"
|
|
||||||
else:
|
|
||||||
for d in deps:
|
|
||||||
paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n"
|
|
||||||
|
|
||||||
var cfgContent = configPatternBegin & paths & configPatternEnd
|
var cfgContent = configPatternBegin & paths & configPatternEnd
|
||||||
|
|
||||||
when MockupRun:
|
when MockupRun:
|
||||||
assert readFile(TestsDir / "nim.cfg") == cfgContent
|
assert readFile(TestsDir / "nim.cfg") == cfgContent
|
||||||
c.mockupSuccess = true
|
c.mockupSuccess = true
|
||||||
else:
|
else:
|
||||||
let cfg = if cfgHere: getCurrentDir() / "nim.cfg"
|
let cfg = cfgPath / "nim.cfg"
|
||||||
else: c.projectDir / "nim.cfg"
|
if cfgPath.len > 0 and not dirExists(cfgPath):
|
||||||
if not fileExists(cfg):
|
error(c, c.projectDir.PackageName, "could not write the nim.cfg")
|
||||||
|
elif not fileExists(cfg):
|
||||||
writeFile(cfg, cfgContent)
|
writeFile(cfg, cfgContent)
|
||||||
else:
|
else:
|
||||||
let content = readFile(cfg)
|
let content = readFile(cfg)
|
||||||
|
|
@ -420,6 +431,22 @@ proc error*(msg: string) =
|
||||||
writeStackTrace()
|
writeStackTrace()
|
||||||
quit "[Error] " & msg
|
quit "[Error] " & msg
|
||||||
|
|
||||||
|
proc findSrcDir(c: var AtlasContext): string =
|
||||||
|
for nimbleFile in walkPattern("*.nimble"):
|
||||||
|
let nimbleInfo = extractRequiresInfo(c, nimbleFile)
|
||||||
|
return nimbleInfo.srcDir
|
||||||
|
return ""
|
||||||
|
|
||||||
|
proc installDependencies(c: var AtlasContext; nimbleFile: string) =
|
||||||
|
# 1. find .nimble file in CWD
|
||||||
|
# 2. install deps from .nimble
|
||||||
|
var work: seq[Dependency] = @[]
|
||||||
|
let (path, pkgname, _) = splitFile(nimbleFile)
|
||||||
|
let dep = Dependency(name: toName(pkgname), url: "", commit: "")
|
||||||
|
discard collectDeps(c, work, dep, nimbleFile)
|
||||||
|
let paths = cloneLoop(c, work)
|
||||||
|
patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c))
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
var action = ""
|
var action = ""
|
||||||
var args: seq[string] = @[]
|
var args: seq[string] = @[]
|
||||||
|
|
@ -460,15 +487,26 @@ proc main =
|
||||||
of "clone":
|
of "clone":
|
||||||
singleArg()
|
singleArg()
|
||||||
let deps = clone(c, args[0])
|
let deps = clone(c, args[0])
|
||||||
patchNimCfg c, deps, false
|
patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c)
|
||||||
if c.cfgHere:
|
|
||||||
patchNimCfg c, deps, true
|
|
||||||
when MockupRun:
|
when MockupRun:
|
||||||
if not c.mockupSuccess:
|
if not c.mockupSuccess:
|
||||||
error "There were problems."
|
error "There were problems."
|
||||||
else:
|
else:
|
||||||
if c.errors > 0:
|
if c.errors > 0:
|
||||||
error "There were problems."
|
error "There were problems."
|
||||||
|
of "install":
|
||||||
|
if args.len > 1:
|
||||||
|
error "install command takes a single argument"
|
||||||
|
var nimbleFile = ""
|
||||||
|
if args.len == 1:
|
||||||
|
nimbleFile = args[0]
|
||||||
|
else:
|
||||||
|
for x in walkPattern("*.nimble"):
|
||||||
|
nimbleFile = x
|
||||||
|
break
|
||||||
|
if nimbleFile.len == 0:
|
||||||
|
error "could not find a .nimble file"
|
||||||
|
installDependencies(c, nimbleFile)
|
||||||
of "refresh":
|
of "refresh":
|
||||||
noArgs()
|
noArgs()
|
||||||
updatePackages(c)
|
updatePackages(c)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue