@@ -13,14 +13,15 @@ import std/[parseopt, strutils, os, osproc, unicode, tables, sets, json, jsonuti
1313import parse_requires, osutils, packagesjson
1414
1515const
16- Version = " 0.1 "
16+ Version = " 0.2 "
1717 Usage = " atlas - Nim Package Cloner Version " & Version & """
1818
1919 (c) 2021 Andreas Rumpf
2020Usage:
2121 atlas [options] [command] [arguments]
2222Command:
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
8889proc 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+
321350proc 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+
378393const
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+
423450proc 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