Skip to content

Commit 0f2775a

Browse files
authored
implemented 'atlas install' command (#20530)
1 parent 944e4cf commit 0f2775a

File tree

1 file changed

+90
-52
lines changed

1 file changed

+90
-52
lines changed

tools/atlas/atlas.nim

Lines changed: 90 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonuti
1313
import parse_requires, osutils, packagesjson
1414

1515
const
16-
Version = "0.1"
16+
Version = "0.2"
1717
Usage = "atlas - Nim Package Cloner Version " & Version & """
1818
1919
(c) 2021 Andreas Rumpf
2020
Usage:
2121
atlas [options] [command] [arguments]
2222
Command:
2323
clone url|pkgname clone a package and all of its dependencies
24+
install proj.nimble use the .nimble file to setup the project's dependencies
2425
search keyw keywB... search for package that contains the given keywords
2526
extract file.nimble extract the requirements and custom commands from
2627
the given Nimble file
@@ -87,7 +88,7 @@ include testdata
8788

8889
proc exec(c: var AtlasContext; cmd: Command; args: openArray[string]): (string, int) =
8990
when MockupRun:
90-
assert TestLog[c.step].cmd == cmd
91+
assert TestLog[c.step].cmd == cmd, $(TestLog[c.step].cmd, cmd)
9192
case cmd
9293
of GitDiff, GitTags, GitRevParse, GitPull, GitCurrentCommit:
9394
result = (TestLog[c.step].output, TestLog[c.step].exitCode)
@@ -318,53 +319,55 @@ proc addUniqueDep(c: var AtlasContext; work: var seq[Dependency];
318319
work.add Dependency(name: toName(tokens[0]), url: url, commit: tokens[2],
319320
rel: toDepRelation(tokens[1]))
320321

322+
template toDestDir(p: PackageName): string = p.string
323+
324+
proc collectDeps(c: var AtlasContext; work: var seq[Dependency];
325+
dep: Dependency; nimbleFile: string): string =
326+
# If there is a .nimble file, return the dependency path & srcDir
327+
# else return "".
328+
assert nimbleFile != ""
329+
let nimbleInfo = extractRequiresInfo(c, nimbleFile)
330+
for r in nimbleInfo.requires:
331+
var tokens: seq[string] = @[]
332+
for token in tokenizeRequires(r):
333+
tokens.add token
334+
if tokens.len == 1:
335+
# nimx uses dependencies like 'requires "sdl2"'.
336+
# Via this hack we map them to the first tagged release.
337+
# (See the `isStrictlySmallerThan` logic.)
338+
tokens.add "<"
339+
tokens.add InvalidCommit
340+
elif tokens.len == 2 and tokens[1].startsWith("#"):
341+
# Dependencies can also look like 'requires "sdl2#head"
342+
var commit = tokens[1][1 .. ^1]
343+
tokens[1] = "=="
344+
tokens.add commit
345+
346+
if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0:
347+
c.addUniqueDep work, tokens
348+
result = toDestDir(dep.name) / nimbleInfo.srcDir
349+
321350
proc collectNewDeps(c: var AtlasContext; work: var seq[Dependency];
322351
dep: Dependency; result: var seq[string];
323352
isMainProject: bool) =
324353
let nimbleFile = findNimbleFile(c, dep)
325354
if nimbleFile != "":
326-
let nimbleInfo = extractRequiresInfo(c, nimbleFile)
327-
for r in nimbleInfo.requires:
328-
var tokens: seq[string] = @[]
329-
for token in tokenizeRequires(r):
330-
tokens.add token
331-
if tokens.len == 1:
332-
# nimx uses dependencies like 'requires "sdl2"'.
333-
# Via this hack we map them to the first tagged release.
334-
# (See the `isStrictlySmallerThan` logic.)
335-
tokens.add "<"
336-
tokens.add InvalidCommit
337-
elif tokens.len == 2 and tokens[1].startsWith("#"):
338-
# Dependencies can also look like 'requires "sdl2#head"
339-
var commit = tokens[1][1 .. ^1]
340-
tokens[1] = "=="
341-
tokens.add commit
342-
343-
if tokens.len >= 3 and cmpIgnoreCase(tokens[0], "nim") != 0:
344-
c.addUniqueDep work, tokens
345-
346-
result.add dep.name.string / nimbleInfo.srcDir
355+
let x = collectDeps(c, work, dep, nimbleFile)
356+
result.add x
347357
else:
348-
result.add dep.name.string
358+
result.add toDestDir(dep.name)
349359

350-
proc clone(c: var AtlasContext; start: string): seq[string] =
351-
# non-recursive clone.
352-
let oldErrors = c.errors
353-
var work = @[Dependency(name: toName(start), url: toUrl(c, start), commit: "")]
354-
355-
if oldErrors != c.errors:
356-
error c, toName(start), "cannot resolve package name"
357-
return
358-
359-
c.projectDir = c.workspace / work[0].name.string
360+
proc cloneLoop(c: var AtlasContext; work: var seq[Dependency]): seq[string] =
360361
result = @[]
361362
var i = 0
362363
while i < work.len:
363364
let w = work[i]
365+
let destDir = toDestDir(w.name)
364366
let oldErrors = c.errors
365-
if not dirExists(c.workspace / w.name.string):
367+
368+
if not dirExists(c.workspace / destDir):
366369
withDir c, c.workspace:
367-
let err = cloneUrl(c, w.url, w.name.string, false)
370+
let err = cloneUrl(c, w.url, destDir, false)
368371
if err != "":
369372
error c, w.name, err
370373
if oldErrors == c.errors:
@@ -375,30 +378,38 @@ proc clone(c: var AtlasContext; start: string): seq[string] =
375378
collectNewDeps(c, work, w, result, i == 0)
376379
inc i
377380

381+
proc clone(c: var AtlasContext; start: string): seq[string] =
382+
# non-recursive clone.
383+
let url = toUrl(c, start)
384+
var work = @[Dependency(name: toName(start), url: url, commit: "")]
385+
386+
if url == "":
387+
error c, toName(start), "cannot resolve package name"
388+
return
389+
390+
c.projectDir = c.workspace / toDestDir(work[0].name)
391+
result = cloneLoop(c, work)
392+
378393
const
379394
configPatternBegin = "############# begin Atlas config section ##########\n"
380395
configPatternEnd = "############# end Atlas config section ##########\n"
381396

382-
proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgHere: bool) =
397+
proc patchNimCfg(c: var AtlasContext; deps: seq[string]; cfgPath: string) =
383398
var paths = "--noNimblePath\n"
384-
if cfgHere:
385-
let cwd = getCurrentDir()
386-
for d in deps:
387-
let x = relativePath(c.workspace / d, cwd, '/')
388-
paths.add "--path:\"" & x & "\"\n"
389-
else:
390-
for d in deps:
391-
paths.add "--path:\"../" & d.replace("\\", "/") & "\"\n"
392-
399+
for d in deps:
400+
let pkgname = toDestDir d.PackageName
401+
let x = relativePath(c.workspace / pkgname, cfgPath, '/')
402+
paths.add "--path:\"" & x & "\"\n"
393403
var cfgContent = configPatternBegin & paths & configPatternEnd
394404

395405
when MockupRun:
396406
assert readFile(TestsDir / "nim.cfg") == cfgContent
397407
c.mockupSuccess = true
398408
else:
399-
let cfg = if cfgHere: getCurrentDir() / "nim.cfg"
400-
else: c.projectDir / "nim.cfg"
401-
if not fileExists(cfg):
409+
let cfg = cfgPath / "nim.cfg"
410+
if cfgPath.len > 0 and not dirExists(cfgPath):
411+
error(c, c.projectDir.PackageName, "could not write the nim.cfg")
412+
elif not fileExists(cfg):
402413
writeFile(cfg, cfgContent)
403414
else:
404415
let content = readFile(cfg)
@@ -420,6 +431,22 @@ proc error*(msg: string) =
420431
writeStackTrace()
421432
quit "[Error] " & msg
422433

434+
proc findSrcDir(c: var AtlasContext): string =
435+
for nimbleFile in walkPattern("*.nimble"):
436+
let nimbleInfo = extractRequiresInfo(c, nimbleFile)
437+
return nimbleInfo.srcDir
438+
return ""
439+
440+
proc installDependencies(c: var AtlasContext; nimbleFile: string) =
441+
# 1. find .nimble file in CWD
442+
# 2. install deps from .nimble
443+
var work: seq[Dependency] = @[]
444+
let (path, pkgname, _) = splitFile(nimbleFile)
445+
let dep = Dependency(name: toName(pkgname), url: "", commit: "")
446+
discard collectDeps(c, work, dep, nimbleFile)
447+
let paths = cloneLoop(c, work)
448+
patchNimCfg(c, paths, if c.cfgHere: getCurrentDir() else: findSrcDir(c))
449+
423450
proc main =
424451
var action = ""
425452
var args: seq[string] = @[]
@@ -460,15 +487,26 @@ proc main =
460487
of "clone":
461488
singleArg()
462489
let deps = clone(c, args[0])
463-
patchNimCfg c, deps, false
464-
if c.cfgHere:
465-
patchNimCfg c, deps, true
490+
patchNimCfg c, deps, if c.cfgHere: getCurrentDir() else: findSrcDir(c)
466491
when MockupRun:
467492
if not c.mockupSuccess:
468493
error "There were problems."
469494
else:
470495
if c.errors > 0:
471496
error "There were problems."
497+
of "install":
498+
if args.len > 1:
499+
error "install command takes a single argument"
500+
var nimbleFile = ""
501+
if args.len == 1:
502+
nimbleFile = args[0]
503+
else:
504+
for x in walkPattern("*.nimble"):
505+
nimbleFile = x
506+
break
507+
if nimbleFile.len == 0:
508+
error "could not find a .nimble file"
509+
installDependencies(c, nimbleFile)
472510
of "refresh":
473511
noArgs()
474512
updatePackages(c)

0 commit comments

Comments
 (0)