From ac1714ffef01fd6ff1197fe62eaba94469951488 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 10 Jan 2016 00:36:02 +0000 Subject: [PATCH 001/424] Fixes infinite loop. Ref @zielmicha/reactor.nim#1. --- src/nimblepkg/packageparser.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index c8555d4..3eb1907 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -25,7 +25,7 @@ proc raiseNewValidationError(msg: string, warnInstalled: bool) = # TODO: We warn everywhere for now. Raise the error in the next version. echo("WARNING: ", msg, ". Will be an error in next version!") else: - raiseNewValidationError(msg, warnInstalled) + raise newValidationError(msg, warnInstalled) proc validatePackageName*(name: string) = ## Raises an error if specified package name contains invalid characters. From 2b5d2a90736a079152cf204eb4966dc92dd7bd84 Mon Sep 17 00:00:00 2001 From: Hans Raaf Date: Mon, 11 Jan 2016 01:44:30 +0100 Subject: [PATCH 002/424] Fix for the Bash completion on OSX. --- nimble.bash-completion | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nimble.bash-completion b/nimble.bash-completion index 6cb6228..87f244b 100644 --- a/nimble.bash-completion +++ b/nimble.bash-completion @@ -5,7 +5,10 @@ _nimble() local cur=${COMP_WORDS[COMP_CWORD]} local prev=${COMP_WORDS[COMP_CWORD-1]} COMPREPLY=() - _init_completion || return + + if declare -F _init_completions >/dev/null 2>&1; then + _init_completion || return + fi case "$prev" in init|update|refresh|publish|search|build) From c6d874280746a1d7f43410771fc088a81f196dea Mon Sep 17 00:00:00 2001 From: Hans Raaf Date: Mon, 11 Jan 2016 01:46:08 +0100 Subject: [PATCH 003/424] Smarter uninstall Bash completion. Instead of offering just the base names of the packages the uninstall parameter completion now lists all installed versions. This makes it easy to uninstall whats not needed anymore and helps remembering the syntax for this task. Example: ``` $ nimble uninstall nake[TAB]@1.[TAB] nake@1.4 nake@1.6 nake@1.8 $ nimble uninstall nake@1.4 ``` --- nimble.bash-completion | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nimble.bash-completion b/nimble.bash-completion index 6cb6228..7b782de 100644 --- a/nimble.bash-completion +++ b/nimble.bash-completion @@ -17,9 +17,12 @@ _nimble() install) COMPREPLY=( $( nimble list 2> /dev/null | grep "^$cur" | grep -v '^ ' | tr -d ':') ) ;; - path|uninstall) + path) COMPREPLY=( $( nimble list -i 2> /dev/null | cut -d' ' -f1 | grep "^$cur" ) ) ;; + uninstall) + COMPREPLY=( $( nimble list -i 2> /dev/null | awk -F'( |\\[|\\])' '{ f=4; while($f) { l=length($f); if(substr($f, l, l)==",") { $f=substr($f, 0, l-1) }; print $1 "@" $f; f++; }}' | sort -f | grep "^$cur" ) ) + ;; list) COMPREPLY=( $( compgen -W '--ver -i --installed' -- $cur ) ) ;; From 14e0ca9a3b9f1479d9412d83b2b1aec5969c4667 Mon Sep 17 00:00:00 2001 From: Hans Raaf Date: Mon, 11 Jan 2016 02:15:16 +0100 Subject: [PATCH 004/424] This change sorts the list of the installed modules by name. It also adds some files to .gitignore to make checkins easier. --- .gitignore | 5 +++++ src/nimble.nim | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bd1ebed..5199260 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ nimcache/ /src/babel /src/nimble /tests/tester + +# executables from test and build +/nimble +/tests/nimscript/nimscript +/tests/issue27/issue27 diff --git a/src/nimble.nim b/src/nimble.nim index f28f4c6..46f098a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -631,7 +631,7 @@ proc list(options: Options) = echo(" ") proc listInstalled(options: Options) = - var h = initTable[string, seq[string]]() + var h = initOrderedTable[string, seq[string]]() let pkgs = getInstalledPkgs(options.getPkgsDir(), options) for x in pkgs.items(): let @@ -641,6 +641,8 @@ proc listInstalled(options: Options) = var s = h[pName] add(s, pVer) h[pName] = s + + h.sort(proc (a,b: auto): int = cmpIgnoreCase(a[0],b[0])) for k in keys(h): echo k & " [" & h[k].join(", ") & "]" From 2485ab67464f0227fd253072e23fbfb3021cd79b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 12 Jan 2016 20:08:13 +0000 Subject: [PATCH 005/424] Replaced 'auto' with explicit types in sort anon proc. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 46f098a..f649d35 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -642,7 +642,7 @@ proc listInstalled(options: Options) = add(s, pVer) h[pName] = s - h.sort(proc (a,b: auto): int = cmpIgnoreCase(a[0],b[0])) + h.sort(proc (a, b: (string, seq[string])): int = cmpIgnoreCase(a[0], b[0])) for k in keys(h): echo k & " [" & h[k].join(", ") & "]" From 670bcec61d42431678ffbfe7075474e240935578 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 19 Jan 2016 01:00:45 +0000 Subject: [PATCH 006/424] Update installation instructions for Unix users who install Nim. --- readme.markdown | 1 + src/nimble.nim.cfg | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 7e0a8ee..fae4af9 100644 --- a/readme.markdown +++ b/readme.markdown @@ -47,6 +47,7 @@ the following commands to clone nimble, compile it and then install it. git clone https://github.com/nim-lang/nimble.git cd nimble + git clone -b v0.13.0 --depth 1 https://github.com/nim-lang/nim vendor/nim nim c -r src/nimble install After these steps are completed successfully, nimble will be installed diff --git a/src/nimble.nim.cfg b/src/nimble.nim.cfg index 224124f..94025f2 100644 --- a/src/nimble.nim.cfg +++ b/src/nimble.nim.cfg @@ -1,3 +1,4 @@ --path:"$lib/packages/docutils" --noNimblePath ---path:"$nim/" \ No newline at end of file +--path:"$nim/" +--path:"./vendor/nim" From 83b1292d232b8f488d2ef74b548db19f202f6773 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 11 Feb 2016 16:24:13 +0000 Subject: [PATCH 007/424] Version 0.7.2. --- changelog.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index d028c32..e88fcf5 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,5 +1,12 @@ # Nimble changelog +## 0.7.2 - 11/02/2016 + +This is a hotfix release which alleviates problems when building Nimble. + +See Issue [#203](https://github.com/nim-lang/nimble/issues/203) for more +information. + ## 0.7.0 - 30/12/2015 This is a major release. From 2de92a8230b296e33fbfde51d2167b4aadff5631 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sun, 14 Feb 2016 21:13:02 +0200 Subject: [PATCH 008/424] Fixes symlink installation issue --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index f649d35..968e958 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -413,7 +413,7 @@ proc installFromDir(dir: string, latest: bool, options: Options, when defined(unix): # TODO: Verify that we are removing an old bin of this package, not # some other package's binary! - if existsFile(binDir / bin): removeFile(binDir / cleanBin) + if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) createSymlink(pkgDestDir / bin, binDir / cleanBin) elif defined(windows): From 2fdc267ba7b8d729158bf06f954c587a480f3bd1 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Mon, 15 Feb 2016 11:57:50 +0200 Subject: [PATCH 009/424] Added test for #206 --- tests/issue206/issue/issue206bin.nim | 2 ++ tests/issue206/issue206.nimble | 10 ++++++++++ tests/tester.nim | 7 +++++++ 3 files changed, 19 insertions(+) create mode 100644 tests/issue206/issue/issue206bin.nim create mode 100644 tests/issue206/issue206.nimble diff --git a/tests/issue206/issue/issue206bin.nim b/tests/issue206/issue/issue206bin.nim new file mode 100644 index 0000000..1726a88 --- /dev/null +++ b/tests/issue206/issue/issue206bin.nim @@ -0,0 +1,2 @@ + +echo "Hello" diff --git a/tests/issue206/issue206.nimble b/tests/issue206/issue206.nimble new file mode 100644 index 0000000..1daea5c --- /dev/null +++ b/tests/issue206/issue206.nimble @@ -0,0 +1,10 @@ +# Package +version = "0.1.0" +author = "Yuriy Glukhov" +description = "Test package for Issue 206" +license = "BSD" + +bin = @["issue/issue206bin"] + +# Dependencies +requires "nimrod >= 0.9.3" diff --git a/tests/tester.nim b/tests/tester.nim index eb73db5..886533b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -179,6 +179,13 @@ test "issue #108": check exitCode != QuitSuccess check "Nothing to build" in lines[^1] +test "issue #206": + cd "issue206": + var (output, exitCode) = execCmdEx("../" & path & " install -y") + check exitCode == QuitSuccess + (output, exitCode) = execCmdEx("../" & path & " install -y") + check exitCode == QuitSuccess + test "can list": check execCmdEx(path & " list").exitCode == QuitSuccess From 296499435e7810f09a6d2435baa0b091742f193d Mon Sep 17 00:00:00 2001 From: Rostyslav Dzinko Date: Wed, 17 Feb 2016 10:26:35 +0200 Subject: [PATCH 010/424] Fixed permission issue when installing package --- src/nimblepkg/tools.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 0c992c2..c68d0a2 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -70,7 +70,7 @@ proc changeRoot*(origRoot, newRoot, path: string): string = proc copyFileD*(fro, to: string): string = ## Returns the destination (``to``). echo(fro, " -> ", to) - copyFile(fro, to) + copyFileWithPermissions(fro, to) result = to proc copyDirD*(fro, to: string): seq[string] = From e51d1679c5549a5775bc8a6e185b2a7116c15978 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Thu, 25 Feb 2016 18:57:08 -0500 Subject: [PATCH 011/424] Fix for Issue 204 Github + https + trailing slash in URL causes failed checkouts / remote tag fetches. The issue appears to be indemic to github.com, not git itself --- src/nimble.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 968e958..6680f63 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -484,10 +484,17 @@ proc downloadPkg(url: string, verRange: VersionRange, ## which was downloaded. let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange)) createDir(downloadDir) - let modUrl = + var modUrl = if url.startsWith("git://") and options.config.cloneUsingHttps: "https://" & url[6 .. ^1] else: url + + # Fixes issue #204 + # github + https + trailing url slash causes a + # checkout/ls-remote to fail with Repository not found + if modUrl.contains("https://github.com") and modUrl.endswith("/"): + modUrl = modUrl[0 .. ^2] + echo("Downloading ", modUrl, " into ", downloadDir, " using ", downMethod, "...") result = ( From 8ed8b98c6104196683ee40559996cda431cb3e4b Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Fri, 26 Feb 2016 13:57:47 -0500 Subject: [PATCH 012/424] Switch to only checking for 'github.com' in url Avoids dealing with http:// v https:// v git:// urls --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6680f63..2e604ac 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -492,7 +492,7 @@ proc downloadPkg(url: string, verRange: VersionRange, # Fixes issue #204 # github + https + trailing url slash causes a # checkout/ls-remote to fail with Repository not found - if modUrl.contains("https://github.com") and modUrl.endswith("/"): + if modUrl.contains("github.com") and modUrl.endswith("/"): modUrl = modUrl[0 .. ^2] echo("Downloading ", modUrl, " into ", downloadDir, " using ", From 3bbf51bc7783123d1afc5cd95bc108910aa1f7dc Mon Sep 17 00:00:00 2001 From: def Date: Sun, 6 Mar 2016 23:21:29 +0100 Subject: [PATCH 013/424] Documentation: Build release binary of nimble This speeds up the building process by a factor of 2 because afterwards nimble builds itself again, but using -d:release. --- readme.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.markdown b/readme.markdown index fae4af9..93a1834 100644 --- a/readme.markdown +++ b/readme.markdown @@ -48,7 +48,7 @@ the following commands to clone nimble, compile it and then install it. git clone https://github.com/nim-lang/nimble.git cd nimble git clone -b v0.13.0 --depth 1 https://github.com/nim-lang/nim vendor/nim - nim c -r src/nimble install + nim -d:release c -r src/nimble install After these steps are completed successfully, nimble will be installed in ``~/.nimble/bin``. You must then add @@ -80,7 +80,7 @@ On Windows installing Nimble from source is slightly more complex: git clone https://github.com/nim-lang/nimble.git cd nimble - nim c src/nimble + nim -d:release c src/nimble cp src/nimble.exe src/nimble1.exe src/nimble1.exe install From 5aa4752b153ab3b74934a49ada424dd16bcb8c6a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 18 Mar 2016 13:48:38 +0200 Subject: [PATCH 014/424] Fixed cygwin stub --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2e604ac..cecd80e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -439,7 +439,7 @@ proc installFromDir(dir: string, latest: bool, options: Options, # For bash on Windows (Cygwin/Git bash). let bashDest = dest.changeFileExt("") echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) - writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") + writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") else: {.error: "Sorry, your platform is not supported.".} else: From 36d09de3201243daca56f122c3740415508f105f Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 6 Apr 2016 15:21:55 +0300 Subject: [PATCH 015/424] Fixed FD leak. --- src/nimblepkg/packageparser.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 3eb1907..cf641a9 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -118,6 +118,7 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = if fs != nil: var p: CfgParser open(p, fs, path) + defer: close(p) var currentSection = "" while true: var ev = next(p) @@ -172,7 +173,6 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = "Invalid package info, should not contain --" & ev.value) of cfgError: raise newException(NimbleError, "Error parsing .nimble file: " & ev.msg) - close(p) else: raise newException(ValueError, "Cannot open package info: " & path) @@ -269,4 +269,4 @@ proc getInstalledPkgs*(libsDir: string, options: Options): raise exc proc isNimScript*(nf: string, options: Options): bool = - result = readPackageInfo(nf, options).isNimScript \ No newline at end of file + result = readPackageInfo(nf, options).isNimScript From 08496341b78ec014eb8a9a4534f8a04ff58c07f4 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 6 Apr 2016 15:54:08 +0300 Subject: [PATCH 016/424] BONUS: Fixed tests because of dom's breaking changes ;) --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index cecd80e..1d7dd26 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -232,7 +232,7 @@ proc removeRevDep(options: Options, pkg: PackageInfo) = for key, val in options.nimbleData["reverseDeps"]: options.remove(pkg, depTup, val) else: - let thisDep = options.nimbleData["reverseDeps"][depTup.name] + let thisDep = options.nimbleData{"reverseDeps", depTup.name} if thisDep.isNil: continue options.remove(pkg, depTup, thisDep) From 04df41215baf3f592d9b8898653e08e253176798 Mon Sep 17 00:00:00 2001 From: Aidan Steele Date: Fri, 8 Apr 2016 19:28:10 +1000 Subject: [PATCH 017/424] Updated README syntax (#188) * Updated README syntax * Clarified README syntax between formats --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 93a1834..df3b405 100644 --- a/readme.markdown +++ b/readme.markdown @@ -490,7 +490,7 @@ A package is automatically a binary package as soon as it sets at least one ``bin`` value, like so: ```ini -bin = "main" +bin = "main" # NimScript config expects a seq instead, e.g. @["main"] ``` In this case when ``nimble install`` is invoked, nimble will build the ``main.nim`` From 8abf18633d85aea8ae5506ffd3fc1185fc76810b Mon Sep 17 00:00:00 2001 From: Aidan Steele Date: Sun, 10 Apr 2016 19:42:56 +1000 Subject: [PATCH 018/424] Package names are case insensitive (#190) --- src/nimblepkg/packageinfo.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 304398b..5c07957 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -142,7 +142,7 @@ proc getPackage*(pkg: string, options: Options, let packages = parseFile(options.getNimbleDir() / "packages_" & name.toLower() & ".json") for p in packages: - if p["name"].str == pkg: + if normalize(p["name"].str) == normalize(pkg): resPkg = p.fromJson() return true @@ -302,4 +302,4 @@ when isMainModule: doAssert toValidPackageName("foo__bar") == "foo_bar" doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe" - echo("All tests passed!") \ No newline at end of file + echo("All tests passed!") From 4c3f62adf3c333fa615d2f70f478525af086f4f6 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 13 Apr 2016 15:20:28 +0300 Subject: [PATCH 019/424] Renamed actionUpdate to actionRefresh --- src/nimble.nim | 4 ++-- src/nimblepkg/options.nim | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 1d7dd26..9dda608 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -55,7 +55,7 @@ proc update(options: Options) = ## ## If the download is not successful, an exception is raised. let parameter = - if options.action.typ == actionUpdate: + if options.action.typ == actionRefresh: options.action.optionalURL else: "" @@ -895,7 +895,7 @@ proc doAction(options: Options) = echo("Pre-hook prevented further execution.") return case options.action.typ - of actionUpdate: + of actionRefresh: update(options) of actionInstall: let (_, pkgInfo) = install(options.action.packages, options) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 7970294..f673f8d 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -18,7 +18,7 @@ type pkgInfoCache*: TableRef[string, PackageInfo] ActionType* = enum - actionNil, actionUpdate, actionInit, actionDump, actionPublish, + actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, actionCustom, actionTasks, actionVersion @@ -27,7 +27,7 @@ type case typ*: ActionType of actionNil, actionList, actionBuild, actionPublish, actionTasks, actionVersion: nil - of actionUpdate: + of actionRefresh: optionalURL*: string # Overrides default package list. of actionInstall, actionPath, actionUninstall: packages*: seq[PkgTuple] # Optional only for actionInstall. @@ -111,7 +111,7 @@ proc parseActionType*(action: string): ActionType = of "dump": result = actionDump of "update", "refresh": - result = actionUpdate + result = actionRefresh of "search": result = actionSearch of "list": @@ -141,7 +141,7 @@ proc initAction*(options: var Options, key: string) = options.action.projName = "" of actionDump: options.action.projName = "" - of actionUpdate: + of actionRefresh: options.action.optionalURL = "" of actionSearch: options.action.search = @[] @@ -215,7 +215,7 @@ proc parseArgument*(key: string, result: var Options) = result.action.packages.add(pkgTup) else: result.action.packages.add((key, VersionRange(kind: verAny))) - of actionUpdate: + of actionRefresh: result.action.optionalURL = key of actionSearch: result.action.search.add(key) @@ -320,4 +320,4 @@ proc getProxy*(options: Options): Proxy = else: "" return newProxy($parsed, auth) else: - return nil \ No newline at end of file + return nil From 966361c22ae5e0bea459d6b16cc2f72d7b039636 Mon Sep 17 00:00:00 2001 From: k0pernicus Date: Thu, 19 May 2016 10:47:46 -0400 Subject: [PATCH 020/424] Add a Troubleshooting section --- readme.markdown | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/readme.markdown b/readme.markdown index df3b405..70be1d3 100644 --- a/readme.markdown +++ b/readme.markdown @@ -645,6 +645,15 @@ their own packages to it! Take a look at **Example**: ``nim >= 0.10.0, jester``; with this value your package will depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``. +## Troubleshooting + +* "SSL support is not available. Cannot connect over SSL. [HttpRequestError]" + +Make sure that nimble is configured to run with SSL, adding a ```-d:ssl``` +flag to the file ```src/nimble.nim.cfg```. +After that, you can run ```src/nimble install``` and overwrite the existing +installation. + ## Contribution If you would like to help, feel free to fork and make any additions you see fit From 8e56412d7ad1af8b052789a871aa9a4c997cce16 Mon Sep 17 00:00:00 2001 From: k0pernicus Date: Thu, 19 May 2016 17:09:41 -0400 Subject: [PATCH 021/424] Add a table of contents --- readme.markdown | 121 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 40 deletions(-) diff --git a/readme.markdown b/readme.markdown index 70be1d3..041ae55 100644 --- a/readme.markdown +++ b/readme.markdown @@ -3,11 +3,51 @@ Nimble is a *beta*-grade *package manager* for the [Nim programming language](http://nim-lang.org). - Interested in learning **how to create a package**? Skip directly to that section [here](#creating-packages). -## Installation +## Contents + +* [Installation](#installation) + * [Unix](#installation_unix) + * [Windows](#installation_windows) + * [Using the pre-built archives](#inst_win_pre) + * [From source](#inst_win_source) +* [Nimble's folder structure and packages](#nimble_struct) +* [Nimble usage](#nimble_usage) + * [refresh](#nimble_refresh_u) + * [install](#nimble_install_u) + * [uninstall](#nimble_uninstall_u) + * [build](#nimble_build_u) + * [c](#nimble_c_u) + * [list](#nimble_list_u) + * [search](#nimble_search_u) + * [path](#nimble_path_u) + * [init](#nimble_init_u) + * [publish](#nimble_publish_u) + * [tasks](#nimble_tasks_u) + * [dump](#nimble_dump_u) +* [Configuration](#configuration) +* [Creating packages](#creating_packages) + * [Nimscript format](#nimscript_format) + * [Libraries](#libraries) + * [Binary packages](#binary_packages) + * [Hybrids](#hybrids) + * [Dependencies](#dependencies) + * [Nim compiler](#nim_compiler) + * [Versions](#versions) +* [Submitting your package to the package list](#submitting) +* [```.nimble``` reference](#nimble_reference) + * [\[Package\]](#package) + * [Required](#required) + * [Optional](#package_optional) + * [\[Dependencies\]](#deps) + * [Optional](#deps_optional) +* [Troubleshooting](#troubleshooting) +* [Contribution](#contribution) +* [About](#about) + +## Installation The latest version of Nimble (in the master branch) is primarily tested with the latest version of the Nim compiler (in the devel branch). You can be sure @@ -38,7 +78,7 @@ info. The following sections give platform-specific instructions on how to compile and install Nimble. -### Unix +### Unix On Unix-like operating systems Nimble can be compiled and installed with two simple @@ -55,14 +95,14 @@ in ``~/.nimble/bin``. You must then add ``~/.nimble/bin`` to your ``$PATH``. Updating nimble can then be done by executing ``nimble install nimble``. -### Windows +### Windows You can install Nimble via a pre-built installation archive which is available on the [releases](https://github.com/nim-lang/nimble/releases) page. Alternatively, you can also install Nimble from source, but the instructions for doing so are a bit different on Windows. -#### Using the pre-built archives +#### Using the pre-built archives Download the latest release archive from the [releases](https://github.com/nim-lang/nimble/releases) page. These archives @@ -74,7 +114,7 @@ One important thing to note is that this installation requires you have the Nim compiler in your PATH. Once the installation completes you should add ``C:\Users\YourName\.nimble\bin`` to your PATH. -#### From source +#### From source On Windows installing Nimble from source is slightly more complex: @@ -89,7 +129,8 @@ during installation Nimble recompiles itself causing an error. Once the installation completes you should add ``C:\Users\YourName\.nimble\bin`` to your PATH. -## Nimble's folder structure and packages +## Nimble's folder structure +and packages Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems and in your ``$home/.nimble`` on Windows. Libraries are stored in @@ -102,12 +143,12 @@ However, some Nimble packages can provide additional tools or commands. If you don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not work properly and you won't be able to run them. -## Nimble usage +## Nimble usage Once you have Nimble installed on your system you can run the ``nimble`` command to obtain a list of available commands. -### nimble refresh +### nimble refresh The ``refresh`` command is used to fetch and update the list of Nimble packages (see below). There is no automatic update mechanism, so you need to run this @@ -127,7 +168,7 @@ a third-party package list. Package lists can be specified in Nimble's config. Take a look at the config section below to see how to do this. -### nimble install +### nimble install The ``install`` command will download and install a package. You need to pass the name of the package (or packages) you want to install. If any of the @@ -170,7 +211,7 @@ list. See the [Creating Packages](#creating-packages) section for more info on t A URL to a repository can also be specified, Nimble will automatically detect the type of the repository that the url points to and install it. -### nimble uninstall +### nimble uninstall The ``uninstall`` command will remove an installed package. Attempting to remove a package which other packages depend on is disallowed and will result in an @@ -180,14 +221,14 @@ Similar to the ``install`` command you can specify a version range, for example: $ nimble uninstall nimgame@0.5 -### nimble build +### nimble build The ``build`` command is mostly used by developers who want to test building their ``.nimble`` package. This command will build the package in debug mode, without installing anything. The ``install`` command will build the package in release mode instead. -### nimble c +### nimble c The ``c`` (or ``compile``, ``js``, ``cc``, ``cpp``) command can be used by developers to compile individual modules inside their package. All options @@ -197,7 +238,7 @@ Nimble will use the backend specified in the package's ``.nimble`` file if the command ``c`` or ``compile`` is specified. The more specific ``js``, ``cc``, ``cpp`` can be used to override that. -### nimble list +### nimble list The ``list`` command will display the known list of packages available for Nimble. An optional ``--ver`` parameter can be specified to tell Nimble to @@ -205,7 +246,7 @@ query remote git repositories for the list of versions of the packages and to then print the versions. Please note however that this can be slow as each package must be queried separately. -### nimble search +### nimble search If you don't want to go through the whole output of the ``list`` command you can use the ``search`` command specifying as parameters the package name and/or @@ -233,7 +274,7 @@ query remote git repositories for the list of versions of the packages and to then print the versions. Please note however that this can be slow as each package must be queried separately. -### nimble path +### nimble path The nimble ``path`` command will show the absolute path to the installed packages matching the specified parameters. Since there can be many versions of @@ -251,7 +292,7 @@ which can be useful to read the bundled documentation. Example: $ cd `nimble path argument_parser` $ less README.md -### nimble init +### nimble init The nimble ``init`` command will start a simple wizard which will create a quick ``.nimble`` file for your project. @@ -260,25 +301,25 @@ As of version 0.7.0, the ``.nimble`` file that this command creates will use the new NimScript format. Check out the [Creating Packages](#creating-packages) section for more info. -### nimble publish +### nimble publish Publishes your Nimble package to the official Nimble package repository. **Note:** Requires a valid Github account. -### nimble tasks +### nimble tasks For a nimble package in the current working directory, list the tasks which that package defines. This is only supported for packages utilising the new nimscript .nimble files. -### nimble dump +### nimble dump Outputs information about the package in the current working directory in an ini-compatible format. Useful for tools wishing to read metadata about Nimble packages who do not want to use the NimScript evaluator. -## Configuration +## Configuration At startup Nimble will attempt to read ``~/.config/nimble/nimble.ini`` on Linux (on Windows it will attempt to read @@ -317,7 +358,7 @@ You can currently configure the following in this file: environment variables. **Default: ""** -## Creating Packages +## Creating Packages Nimble works on git repositories as its primary source of packages. Its list of packages is stored in a JSON file which is freely accessible in the @@ -361,7 +402,7 @@ Nimble currently supports installation of packages from a local directory, a git repository and a mercurial repository. The .nimble file must be present in the root of the directory or repository being installed. -### The new NimScript format +### The new NimScript format **Warning:** This feature is still very experimental. You are encouraged to try it, but be aware that it may change significantly in the future or @@ -443,7 +484,7 @@ also return ``false`` from these blocks to stop further execution. The ``nimscriptapi.nim`` module specifies this and includes other definitions which are also useful. Take a look at it for more information. -### Libraries +### Libraries Library packages are likely the most popular form of Nimble packages. They are meant to be used by other library packages or the ultimate binary packages. @@ -483,7 +524,7 @@ Directories and files can also be specified on a *whitelist* basis, if you specify either of ``InstallDirs``, ``InstallFiles`` or ``InstallExt`` then Nimble will **only** install the files specified. -### Binary packages +### Binary packages These are application packages which require building prior to installation. A package is automatically a binary package as soon as it sets at least one @@ -509,7 +550,7 @@ package you should ensure that the dependencies you specified are correct. You can do this by running ``nimble build`` or ``nimble install`` in the directory of your package. -### Hybrids +### Hybrids One thing to note about library and binary package hybrids is that your binary may share the name of the package. This will mean that you will @@ -521,7 +562,7 @@ The current convention to get around this problem is to append ``pkg`` to the name as is done for nimble. -### Dependencies +### Dependencies Dependencies are specified under the ``[Deps]`` section in a nimble file. The ``requires`` key field is used to specify them. For example: @@ -548,7 +589,7 @@ These have to be concrete however. This is done with the ``#`` character, for example: ``jester#head``. Which will make your package depend on the latest commit of Jester. -### Nim compiler +### Nim compiler The Nim compiler cannot read .nimble files. Its knowledge of Nimble is limited to the ``nimblePaths`` feature which allows it to use packages installed @@ -564,7 +605,7 @@ This means that you can safely compile using the compiler when developing your software, but you should use nimble to build the package before publishing it to ensure that the dependencies you specified are correct. -### Versions +### Versions Versions of cloned packages via git or mercurial are determined through the repository's *tags*. @@ -580,17 +621,17 @@ package after checking out the latest version. You can force the installation of the HEAD of the repository by specifying ``#head`` after the package name in your dependency list. -## Submitting your package to the package list. +## Submitting your package to the package list Nimble's packages list is stored on github and everyone is encouraged to add their own packages to it! Take a look at [nim-lang/packages](https://github.com/nim-lang/packages) to learn more. -## .nimble reference +## ```.nimble``` reference -### [Package] +### [Package] -#### Required +#### Required * ``name`` - The name of the package. *(This is not required in the new NimScript format)* * ``version`` - The *current* version of this package. This should be incremented @@ -599,7 +640,7 @@ their own packages to it! Take a look at * ``description`` - A string describing the package. * ``license`` - The name of the license in which this package is licensed under. -#### Optional +#### Optional * ``SkipDirs`` - A list of directory names which should be skipped during installation, separated by commas. @@ -636,25 +677,25 @@ their own packages to it! Take a look at ``js``. **Default**: c -### [Deps]/[Dependencies] +### [Deps]/[Dependencies] -#### Optional +#### Optional * ``requires`` - Specified a list of package names with an optional version range separated by commas. **Example**: ``nim >= 0.10.0, jester``; with this value your package will depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``. -## Troubleshooting +## Troubleshooting -* "SSL support is not available. Cannot connect over SSL. [HttpRequestError]" +* ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]``` Make sure that nimble is configured to run with SSL, adding a ```-d:ssl``` flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. -## Contribution +## Contribution If you would like to help, feel free to fork and make any additions you see fit and then send a pull request. @@ -663,7 +704,7 @@ If you have any questions about the project you can ask me directly on github, ask on the Nim [forum](http://forum.nim-lang.org), or ask on Freenode in the #nim channel. -## About +## About Nimble has been written by [Dominik Picheta](http://picheta.me/) with help from a number of From 977475c9a61d489253b8dd01bc7ad2e0a1b3d384 Mon Sep 17 00:00:00 2001 From: k0pernicus Date: Thu, 19 May 2016 17:19:28 -0400 Subject: [PATCH 022/424] Add new format from markdown-toc --- readme.markdown | 157 ++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/readme.markdown b/readme.markdown index 041ae55..9dc977f 100644 --- a/readme.markdown +++ b/readme.markdown @@ -4,50 +4,50 @@ Nimble is a *beta*-grade *package manager* for the [Nim programming language](http://nim-lang.org). Interested in learning **how to create a package**? Skip directly to that section -[here](#creating-packages). +[here](#creating-packages). -## Contents +- [Installation](#installation) + - [Unix](#unix) + - [Windows](#windows) + - [Using the pre-built archives](#using-the-pre-built-archives) + - [From source](#from-source) +- [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages) +- [Nimble usage](#nimble-usage) + - [nimble refresh](#nimble-refresh) + - [nimble install](#nimble-install) + - [nimble uninstall](#nimble-uninstall) + - [nimble build](#nimble-build) + - [nimble c](#nimble-c) + - [nimble list](#nimble-list) + - [nimble search](#nimble-search) + - [nimble path](#nimble-path) + - [nimble init](#nimble-init) + - [nimble publish](#nimble-publish) + - [nimble tasks](#nimble-tasks) + - [nimble dump](#nimble-dump) +- [Configuration](#configuration) +- [Creating Packages](#creating-packages) + - [The new NimScript format](#the-new-nimscript-format) + - [Libraries](#libraries) + - [Binary packages](#binary-packages) + - [Hybrids](#hybrids) + - [Dependencies](#dependencies) + - [Nim compiler](#nim-compiler) + - [Versions](#versions) +- [Submitting your package to the package list.](#submitting-your-package-to-the-package-list) +- [.nimble reference](#nimble-reference) + - [[Package]](#package) + - [Required](#required) + - [Optional](#optional) + - [[Deps]/[Dependencies]](#depsdependencies) + - [Optional](#optional) +- [Troubleshooting](#troubleshooting) +- [Contribution](#contribution) +- [About](#about) -* [Installation](#installation) - * [Unix](#installation_unix) - * [Windows](#installation_windows) - * [Using the pre-built archives](#inst_win_pre) - * [From source](#inst_win_source) -* [Nimble's folder structure and packages](#nimble_struct) -* [Nimble usage](#nimble_usage) - * [refresh](#nimble_refresh_u) - * [install](#nimble_install_u) - * [uninstall](#nimble_uninstall_u) - * [build](#nimble_build_u) - * [c](#nimble_c_u) - * [list](#nimble_list_u) - * [search](#nimble_search_u) - * [path](#nimble_path_u) - * [init](#nimble_init_u) - * [publish](#nimble_publish_u) - * [tasks](#nimble_tasks_u) - * [dump](#nimble_dump_u) -* [Configuration](#configuration) -* [Creating packages](#creating_packages) - * [Nimscript format](#nimscript_format) - * [Libraries](#libraries) - * [Binary packages](#binary_packages) - * [Hybrids](#hybrids) - * [Dependencies](#dependencies) - * [Nim compiler](#nim_compiler) - * [Versions](#versions) -* [Submitting your package to the package list](#submitting) -* [```.nimble``` reference](#nimble_reference) - * [\[Package\]](#package) - * [Required](#required) - * [Optional](#package_optional) - * [\[Dependencies\]](#deps) - * [Optional](#deps_optional) -* [Troubleshooting](#troubleshooting) -* [Contribution](#contribution) -* [About](#about) + -## Installation +## Installation The latest version of Nimble (in the master branch) is primarily tested with the latest version of the Nim compiler (in the devel branch). You can be sure @@ -78,7 +78,7 @@ info. The following sections give platform-specific instructions on how to compile and install Nimble. -### Unix +### Unix On Unix-like operating systems Nimble can be compiled and installed with two simple @@ -95,14 +95,14 @@ in ``~/.nimble/bin``. You must then add ``~/.nimble/bin`` to your ``$PATH``. Updating nimble can then be done by executing ``nimble install nimble``. -### Windows +### Windows You can install Nimble via a pre-built installation archive which is available on the [releases](https://github.com/nim-lang/nimble/releases) page. Alternatively, you can also install Nimble from source, but the instructions for doing so are a bit different on Windows. -#### Using the pre-built archives +#### Using the pre-built archives Download the latest release archive from the [releases](https://github.com/nim-lang/nimble/releases) page. These archives @@ -114,7 +114,7 @@ One important thing to note is that this installation requires you have the Nim compiler in your PATH. Once the installation completes you should add ``C:\Users\YourName\.nimble\bin`` to your PATH. -#### From source +#### From source On Windows installing Nimble from source is slightly more complex: @@ -129,8 +129,7 @@ during installation Nimble recompiles itself causing an error. Once the installation completes you should add ``C:\Users\YourName\.nimble\bin`` to your PATH. -## Nimble's folder structure -and packages +## Nimble's folder structure and packages Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems and in your ``$home/.nimble`` on Windows. Libraries are stored in @@ -143,12 +142,12 @@ However, some Nimble packages can provide additional tools or commands. If you don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not work properly and you won't be able to run them. -## Nimble usage +## Nimble usage Once you have Nimble installed on your system you can run the ``nimble`` command to obtain a list of available commands. -### nimble refresh +### nimble refresh The ``refresh`` command is used to fetch and update the list of Nimble packages (see below). There is no automatic update mechanism, so you need to run this @@ -168,7 +167,7 @@ a third-party package list. Package lists can be specified in Nimble's config. Take a look at the config section below to see how to do this. -### nimble install +### nimble install The ``install`` command will download and install a package. You need to pass the name of the package (or packages) you want to install. If any of the @@ -211,7 +210,7 @@ list. See the [Creating Packages](#creating-packages) section for more info on t A URL to a repository can also be specified, Nimble will automatically detect the type of the repository that the url points to and install it. -### nimble uninstall +### nimble uninstall The ``uninstall`` command will remove an installed package. Attempting to remove a package which other packages depend on is disallowed and will result in an @@ -221,14 +220,14 @@ Similar to the ``install`` command you can specify a version range, for example: $ nimble uninstall nimgame@0.5 -### nimble build +### nimble build The ``build`` command is mostly used by developers who want to test building their ``.nimble`` package. This command will build the package in debug mode, without installing anything. The ``install`` command will build the package in release mode instead. -### nimble c +### nimble c The ``c`` (or ``compile``, ``js``, ``cc``, ``cpp``) command can be used by developers to compile individual modules inside their package. All options @@ -238,7 +237,7 @@ Nimble will use the backend specified in the package's ``.nimble`` file if the command ``c`` or ``compile`` is specified. The more specific ``js``, ``cc``, ``cpp`` can be used to override that. -### nimble list +### nimble list The ``list`` command will display the known list of packages available for Nimble. An optional ``--ver`` parameter can be specified to tell Nimble to @@ -246,7 +245,7 @@ query remote git repositories for the list of versions of the packages and to then print the versions. Please note however that this can be slow as each package must be queried separately. -### nimble search +### nimble search If you don't want to go through the whole output of the ``list`` command you can use the ``search`` command specifying as parameters the package name and/or @@ -274,7 +273,7 @@ query remote git repositories for the list of versions of the packages and to then print the versions. Please note however that this can be slow as each package must be queried separately. -### nimble path +### nimble path The nimble ``path`` command will show the absolute path to the installed packages matching the specified parameters. Since there can be many versions of @@ -292,7 +291,7 @@ which can be useful to read the bundled documentation. Example: $ cd `nimble path argument_parser` $ less README.md -### nimble init +### nimble init The nimble ``init`` command will start a simple wizard which will create a quick ``.nimble`` file for your project. @@ -301,25 +300,25 @@ As of version 0.7.0, the ``.nimble`` file that this command creates will use the new NimScript format. Check out the [Creating Packages](#creating-packages) section for more info. -### nimble publish +### nimble publish Publishes your Nimble package to the official Nimble package repository. **Note:** Requires a valid Github account. -### nimble tasks +### nimble tasks For a nimble package in the current working directory, list the tasks which that package defines. This is only supported for packages utilising the new nimscript .nimble files. -### nimble dump +### nimble dump Outputs information about the package in the current working directory in an ini-compatible format. Useful for tools wishing to read metadata about Nimble packages who do not want to use the NimScript evaluator. -## Configuration +## Configuration At startup Nimble will attempt to read ``~/.config/nimble/nimble.ini`` on Linux (on Windows it will attempt to read @@ -358,7 +357,7 @@ You can currently configure the following in this file: environment variables. **Default: ""** -## Creating Packages +## Creating Packages Nimble works on git repositories as its primary source of packages. Its list of packages is stored in a JSON file which is freely accessible in the @@ -402,7 +401,7 @@ Nimble currently supports installation of packages from a local directory, a git repository and a mercurial repository. The .nimble file must be present in the root of the directory or repository being installed. -### The new NimScript format +### The new NimScript format **Warning:** This feature is still very experimental. You are encouraged to try it, but be aware that it may change significantly in the future or @@ -484,7 +483,7 @@ also return ``false`` from these blocks to stop further execution. The ``nimscriptapi.nim`` module specifies this and includes other definitions which are also useful. Take a look at it for more information. -### Libraries +### Libraries Library packages are likely the most popular form of Nimble packages. They are meant to be used by other library packages or the ultimate binary packages. @@ -524,7 +523,7 @@ Directories and files can also be specified on a *whitelist* basis, if you specify either of ``InstallDirs``, ``InstallFiles`` or ``InstallExt`` then Nimble will **only** install the files specified. -### Binary packages +### Binary packages These are application packages which require building prior to installation. A package is automatically a binary package as soon as it sets at least one @@ -550,7 +549,7 @@ package you should ensure that the dependencies you specified are correct. You can do this by running ``nimble build`` or ``nimble install`` in the directory of your package. -### Hybrids +### Hybrids One thing to note about library and binary package hybrids is that your binary may share the name of the package. This will mean that you will @@ -562,7 +561,7 @@ The current convention to get around this problem is to append ``pkg`` to the name as is done for nimble. -### Dependencies +### Dependencies Dependencies are specified under the ``[Deps]`` section in a nimble file. The ``requires`` key field is used to specify them. For example: @@ -589,7 +588,7 @@ These have to be concrete however. This is done with the ``#`` character, for example: ``jester#head``. Which will make your package depend on the latest commit of Jester. -### Nim compiler +### Nim compiler The Nim compiler cannot read .nimble files. Its knowledge of Nimble is limited to the ``nimblePaths`` feature which allows it to use packages installed @@ -605,7 +604,7 @@ This means that you can safely compile using the compiler when developing your software, but you should use nimble to build the package before publishing it to ensure that the dependencies you specified are correct. -### Versions +### Versions Versions of cloned packages via git or mercurial are determined through the repository's *tags*. @@ -621,17 +620,17 @@ package after checking out the latest version. You can force the installation of the HEAD of the repository by specifying ``#head`` after the package name in your dependency list. -## Submitting your package to the package list +## Submitting your package to the package list. Nimble's packages list is stored on github and everyone is encouraged to add their own packages to it! Take a look at [nim-lang/packages](https://github.com/nim-lang/packages) to learn more. -## ```.nimble``` reference +## .nimble reference -### [Package] +### [Package] -#### Required +#### Required * ``name`` - The name of the package. *(This is not required in the new NimScript format)* * ``version`` - The *current* version of this package. This should be incremented @@ -640,7 +639,7 @@ their own packages to it! Take a look at * ``description`` - A string describing the package. * ``license`` - The name of the license in which this package is licensed under. -#### Optional +#### Optional * ``SkipDirs`` - A list of directory names which should be skipped during installation, separated by commas. @@ -677,16 +676,16 @@ their own packages to it! Take a look at ``js``. **Default**: c -### [Deps]/[Dependencies] +### [Deps]/[Dependencies] -#### Optional +#### Optional * ``requires`` - Specified a list of package names with an optional version range separated by commas. **Example**: ``nim >= 0.10.0, jester``; with this value your package will depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``. -## Troubleshooting +## Troubleshooting * ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]``` @@ -695,7 +694,7 @@ flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. -## Contribution +## Contribution If you would like to help, feel free to fork and make any additions you see fit and then send a pull request. @@ -704,7 +703,7 @@ If you have any questions about the project you can ask me directly on github, ask on the Nim [forum](http://forum.nim-lang.org), or ask on Freenode in the #nim channel. -## About +## About Nimble has been written by [Dominik Picheta](http://picheta.me/) with help from a number of From 831dfaec0b5199d00bc01a0cd6ce31af2cdad269 Mon Sep 17 00:00:00 2001 From: k0pernicus Date: Thu, 19 May 2016 17:20:28 -0400 Subject: [PATCH 023/424] Fix typo and add title --- readme.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index 9dc977f..16e6c69 100644 --- a/readme.markdown +++ b/readme.markdown @@ -4,7 +4,9 @@ Nimble is a *beta*-grade *package manager* for the [Nim programming language](http://nim-lang.org). Interested in learning **how to create a package**? Skip directly to that section -[here](#creating-packages). +[here](#creating-packages). + +## Contents - [Installation](#installation) - [Unix](#unix) @@ -45,8 +47,6 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Contribution](#contribution) - [About](#about) - - ## Installation The latest version of Nimble (in the master branch) is primarily tested with From cec74dbdcc0d57527cec2d99b620ee1aae543f86 Mon Sep 17 00:00:00 2001 From: tormund Date: Mon, 23 May 2016 14:47:15 +0300 Subject: [PATCH 024/424] add install only dependencies --- src/nimble.nim | 169 ++++++++++++++++++++------------------ src/nimblepkg/options.nim | 3 + 2 files changed, 90 insertions(+), 82 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9dda608..e9f1264 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -363,101 +363,106 @@ proc installFromDir(dir: string, latest: bool, options: Options, let realDir = pkgInfo.getRealDir() let binDir = options.getBinDir() let pkgsDir = options.getPkgsDir() + var deps_options = options + deps_options.depsOnly = false + # Dependencies need to be processed before the creation of the pkg dir. - result.paths = processDeps(pkginfo, options) + result.paths = processDeps(pkginfo, deps_options) - echo("Installing ", pkginfo.name, "-", pkginfo.version) + if not options.depsOnly: + echo("Installing ", pkginfo.name, "-", pkginfo.version) - # Build before removing an existing package (if one exists). This way - # if the build fails then the old package will still be installed. - if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) + # Build before removing an existing package (if one exists). This way + # if the build fails then the old package will still be installed. + if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) - let versionStr = (if latest: "" else: '-' & pkgInfo.version) - let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) - if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): - if not options.prompt(pkgInfo.name & versionStr & - " already exists. Overwrite?"): - quit(QuitSuccess) - removePkgDir(pkgDestDir, options) - # Remove any symlinked binaries - for bin in pkgInfo.bin: - # TODO: Check that this binary belongs to the package being installed. - when defined(windows): - removeFile(binDir / bin.changeFileExt("cmd")) - removeFile(binDir / bin.changeFileExt("")) - # TODO: Remove this later. - # Remove .bat file too from previous installs. - removeFile(binDir / bin.changeFileExt("bat")) - else: - removeFile(binDir / bin) + let versionStr = (if latest: "" else: '-' & pkgInfo.version) + let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) + if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): + if not options.prompt(pkgInfo.name & versionStr & + " already exists. Overwrite?"): + quit(QuitSuccess) + removePkgDir(pkgDestDir, options) + # Remove any symlinked binaries + for bin in pkgInfo.bin: + # TODO: Check that this binary belongs to the package being installed. + when defined(windows): + removeFile(binDir / bin.changeFileExt("cmd")) + removeFile(binDir / bin.changeFileExt("")) + # TODO: Remove this later. + # Remove .bat file too from previous installs. + removeFile(binDir / bin.changeFileExt("bat")) + else: + removeFile(binDir / bin) - ## Will contain a list of files which have been installed. - var filesInstalled: HashSet[string] + ## Will contain a list of files which have been installed. + var filesInstalled: HashSet[string] - createDir(pkgDestDir) - if pkgInfo.bin.len > 0: - createDir(binDir) - # Copy all binaries and files that are not skipped - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) - # Set file permissions to +x for all binaries built, - # and symlink them on *nix OS' to $nimbleDir/bin/ - for bin in pkgInfo.bin: - if not existsFile(pkgDestDir / bin): - filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), - pkgDestDir / bin) + createDir(pkgDestDir) + if pkgInfo.bin.len > 0: + createDir(binDir) + # Copy all binaries and files that are not skipped + filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, + pkgInfo) + # Set file permissions to +x for all binaries built, + # and symlink them on *nix OS' to $nimbleDir/bin/ + for bin in pkgInfo.bin: + if not existsFile(pkgDestDir / bin): + filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), + pkgDestDir / bin) - let currentPerms = getFilePermissions(pkgDestDir / bin) - setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) - let cleanBin = bin.extractFilename - when defined(unix): - # TODO: Verify that we are removing an old bin of this package, not - # some other package's binary! - if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) - echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) - createSymlink(pkgDestDir / bin, binDir / cleanBin) - elif defined(windows): - # There is a bug on XP, described here: - # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called - # But this workaround brokes code page on newer systems, so we need to detect OS version - var osver = OSVERSIONINFO() - osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) - if GetVersionExA(osver) == WINBOOL(0): - raise newException(NimbleError, - "Can't detect OS version: GetVersionExA call failed") - let fixChcp = osver.dwMajorVersion <= 5 + let currentPerms = getFilePermissions(pkgDestDir / bin) + setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) + let cleanBin = bin.extractFilename + when defined(unix): + # TODO: Verify that we are removing an old bin of this package, not + # some other package's binary! + if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) + echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) + createSymlink(pkgDestDir / bin, binDir / cleanBin) + elif defined(windows): + # There is a bug on XP, described here: + # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called + # But this workaround brokes code page on newer systems, so we need to detect OS version + var osver = OSVERSIONINFO() + osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) + if GetVersionExA(osver) == WINBOOL(0): + raise newException(NimbleError, + "Can't detect OS version: GetVersionExA call failed") + let fixChcp = osver.dwMajorVersion <= 5 - let dest = binDir / cleanBin.changeFileExt("cmd") - echo("Creating stub: ", pkgDestDir / bin, " -> ", dest) - var contents = "@" - if options.config.chcp: - if fixChcp: - contents.add "chcp 65001 > nul && " - else: contents.add "chcp 65001 > nul\n@" - contents.add "\"" & pkgDestDir / bin & "\" %*\n" - writeFile(dest, contents) - # For bash on Windows (Cygwin/Git bash). - let bashDest = dest.changeFileExt("") - echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) - writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") - else: - {.error: "Sorry, your platform is not supported.".} - else: - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) + let dest = binDir / cleanBin.changeFileExt("cmd") + echo("Creating stub: ", pkgDestDir / bin, " -> ", dest) + var contents = "@" + if options.config.chcp: + if fixChcp: + contents.add "chcp 65001 > nul && " + else: contents.add "chcp 65001 > nul\n@" + contents.add "\"" & pkgDestDir / bin & "\" %*\n" + writeFile(dest, contents) + # For bash on Windows (Cygwin/Git bash). + let bashDest = dest.changeFileExt("") + echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) + writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") + else: + {.error: "Sorry, your platform is not supported.".} + else: + filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, + pkgInfo) - # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, url, filesInstalled) + # Save a nimblemeta.json file. + saveNimbleMeta(pkgDestDir, url, filesInstalled) - # Save the nimble data (which might now contain reverse deps added in - # processDeps). - saveNimbleData(options) + # Save the nimble data (which might now contain reverse deps added in + # processDeps). + saveNimbleData(options) + + echo(pkgInfo.name & " installed successfully.") + # Return the paths to the dependencies of this package. + result.paths.add pkgDestDir - # Return the paths to the dependencies of this package. - result.paths.add pkgDestDir result.pkg = pkgInfo - echo(pkgInfo.name & " installed successfully.") proc getNimbleTempDir(): string = ## Returns a path to a temporary directory. diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index f673f8d..4874ebc 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -10,6 +10,7 @@ import nimblepkg/config, nimblepkg/version, type Options* = object forcePrompts*: ForcePrompt + depsOnly*: bool queryVersions*: bool queryInstalled*: bool action*: Action @@ -83,6 +84,7 @@ Options: --ver Query remote server for package version information when searching or listing packages --nimbleDir dirname Set the Nimble directory. + -d --depsOnly Install only dependencies. For more information read the Github readme: https://github.com/nim-lang/nimble#readme @@ -254,6 +256,7 @@ proc parseFlag*(flag, val: string, result: var Options) = of "ver": result.queryVersions = true of "nimbledir": result.config.nimbleDir = val # overrides option from file of "installed", "i": result.queryInstalled = true + of "depsOnly", "d": result.depsOnly = true else: raise newException(NimbleError, "Unknown option: --" & flag) From 07e9ac09725c429456f929b0bc86d9373856b0f9 Mon Sep 17 00:00:00 2001 From: tormund Date: Mon, 23 May 2016 14:52:50 +0300 Subject: [PATCH 025/424] cleanup --- src/nimble.nim | 166 +++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e9f1264..13f953f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -369,100 +369,102 @@ proc installFromDir(dir: string, latest: bool, options: Options, # Dependencies need to be processed before the creation of the pkg dir. result.paths = processDeps(pkginfo, deps_options) - if not options.depsOnly: - echo("Installing ", pkginfo.name, "-", pkginfo.version) + if options.depsOnly: + result.pkg = pkgInfo + return result - # Build before removing an existing package (if one exists). This way - # if the build fails then the old package will still be installed. - if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) + echo("Installing ", pkginfo.name, "-", pkginfo.version) - let versionStr = (if latest: "" else: '-' & pkgInfo.version) - let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) - if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): - if not options.prompt(pkgInfo.name & versionStr & - " already exists. Overwrite?"): - quit(QuitSuccess) - removePkgDir(pkgDestDir, options) - # Remove any symlinked binaries - for bin in pkgInfo.bin: - # TODO: Check that this binary belongs to the package being installed. - when defined(windows): - removeFile(binDir / bin.changeFileExt("cmd")) - removeFile(binDir / bin.changeFileExt("")) - # TODO: Remove this later. - # Remove .bat file too from previous installs. - removeFile(binDir / bin.changeFileExt("bat")) - else: - removeFile(binDir / bin) + # Build before removing an existing package (if one exists). This way + # if the build fails then the old package will still be installed. + if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) - ## Will contain a list of files which have been installed. - var filesInstalled: HashSet[string] + let versionStr = (if latest: "" else: '-' & pkgInfo.version) + let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) + if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): + if not options.prompt(pkgInfo.name & versionStr & + " already exists. Overwrite?"): + quit(QuitSuccess) + removePkgDir(pkgDestDir, options) + # Remove any symlinked binaries + for bin in pkgInfo.bin: + # TODO: Check that this binary belongs to the package being installed. + when defined(windows): + removeFile(binDir / bin.changeFileExt("cmd")) + removeFile(binDir / bin.changeFileExt("")) + # TODO: Remove this later. + # Remove .bat file too from previous installs. + removeFile(binDir / bin.changeFileExt("bat")) + else: + removeFile(binDir / bin) - createDir(pkgDestDir) - if pkgInfo.bin.len > 0: - createDir(binDir) - # Copy all binaries and files that are not skipped - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) - # Set file permissions to +x for all binaries built, - # and symlink them on *nix OS' to $nimbleDir/bin/ - for bin in pkgInfo.bin: - if not existsFile(pkgDestDir / bin): - filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), - pkgDestDir / bin) + ## Will contain a list of files which have been installed. + var filesInstalled: HashSet[string] - let currentPerms = getFilePermissions(pkgDestDir / bin) - setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) - let cleanBin = bin.extractFilename - when defined(unix): - # TODO: Verify that we are removing an old bin of this package, not - # some other package's binary! - if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) - echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) - createSymlink(pkgDestDir / bin, binDir / cleanBin) - elif defined(windows): - # There is a bug on XP, described here: - # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called - # But this workaround brokes code page on newer systems, so we need to detect OS version - var osver = OSVERSIONINFO() - osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) - if GetVersionExA(osver) == WINBOOL(0): - raise newException(NimbleError, - "Can't detect OS version: GetVersionExA call failed") - let fixChcp = osver.dwMajorVersion <= 5 + createDir(pkgDestDir) + if pkgInfo.bin.len > 0: + createDir(binDir) + # Copy all binaries and files that are not skipped + filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, + pkgInfo) + # Set file permissions to +x for all binaries built, + # and symlink them on *nix OS' to $nimbleDir/bin/ + for bin in pkgInfo.bin: + if not existsFile(pkgDestDir / bin): + filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), + pkgDestDir / bin) - let dest = binDir / cleanBin.changeFileExt("cmd") - echo("Creating stub: ", pkgDestDir / bin, " -> ", dest) - var contents = "@" - if options.config.chcp: - if fixChcp: - contents.add "chcp 65001 > nul && " - else: contents.add "chcp 65001 > nul\n@" - contents.add "\"" & pkgDestDir / bin & "\" %*\n" - writeFile(dest, contents) - # For bash on Windows (Cygwin/Git bash). - let bashDest = dest.changeFileExt("") - echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) - writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") - else: - {.error: "Sorry, your platform is not supported.".} - else: - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) + let currentPerms = getFilePermissions(pkgDestDir / bin) + setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) + let cleanBin = bin.extractFilename + when defined(unix): + # TODO: Verify that we are removing an old bin of this package, not + # some other package's binary! + if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) + echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) + createSymlink(pkgDestDir / bin, binDir / cleanBin) + elif defined(windows): + # There is a bug on XP, described here: + # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called + # But this workaround brokes code page on newer systems, so we need to detect OS version + var osver = OSVERSIONINFO() + osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) + if GetVersionExA(osver) == WINBOOL(0): + raise newException(NimbleError, + "Can't detect OS version: GetVersionExA call failed") + let fixChcp = osver.dwMajorVersion <= 5 - # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, url, filesInstalled) + let dest = binDir / cleanBin.changeFileExt("cmd") + echo("Creating stub: ", pkgDestDir / bin, " -> ", dest) + var contents = "@" + if options.config.chcp: + if fixChcp: + contents.add "chcp 65001 > nul && " + else: contents.add "chcp 65001 > nul\n@" + contents.add "\"" & pkgDestDir / bin & "\" %*\n" + writeFile(dest, contents) + # For bash on Windows (Cygwin/Git bash). + let bashDest = dest.changeFileExt("") + echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) + writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") + else: + {.error: "Sorry, your platform is not supported.".} + else: + filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, + pkgInfo) - # Save the nimble data (which might now contain reverse deps added in - # processDeps). - saveNimbleData(options) + # Save a nimblemeta.json file. + saveNimbleMeta(pkgDestDir, url, filesInstalled) - echo(pkgInfo.name & " installed successfully.") - # Return the paths to the dependencies of this package. - result.paths.add pkgDestDir + # Save the nimble data (which might now contain reverse deps added in + # processDeps). + saveNimbleData(options) + # Return the paths to the dependencies of this package. + result.paths.add pkgDestDir result.pkg = pkgInfo + echo(pkgInfo.name & " installed successfully.") proc getNimbleTempDir(): string = ## Returns a path to a temporary directory. From e9e6f814d0fc4c5d536830cdbdbfb897fe0bfc70 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 31 May 2016 09:58:27 +0200 Subject: [PATCH 026/424] Hotfix: make nimble compile with nim devel again --- src/nimblepkg/options.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 4874ebc..fa261c4 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -4,8 +4,7 @@ import json, strutils, os, parseopt, strtabs, uri, tables from httpclient import Proxy, newProxy -import nimblepkg/config, nimblepkg/version, - nimblepkg/tools, nimblepkg/nimbletypes +import config, version, tools, nimbletypes type Options* = object From be991a10f32cec0478b8947af4d10116b77a4e99 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Fri, 3 Jun 2016 08:07:22 -0400 Subject: [PATCH 027/424] Fix infinitely recursive "update package lists?" prompt --- src/nimble.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 13f953f..fb231cc 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -524,7 +524,11 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options, options.prompt(pv.name & " not found in any local packages.json, " & "check internet for updated packages?"): update(options) - return getDownloadInfo(pv, options, doPrompt) + + # Once we've updated, try again, but don't prompt if not found + # (as we've already updated and a failure means it really + # isn't there) + return getDownloadInfo(pv, options, false) else: raise newException(NimbleError, "Package not found.") From 01a962fcbb1b0847cde494c92e1201bd2c429b63 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 11:10:07 +0100 Subject: [PATCH 028/424] Disable `--noNimblePath` in config. This allows nimble to be built when the `compiler` package has been installed into /opt/nimble/pkgs/. --- src/nimble.nim.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim.cfg b/src/nimble.nim.cfg index 94025f2..2146d12 100644 --- a/src/nimble.nim.cfg +++ b/src/nimble.nim.cfg @@ -1,4 +1,4 @@ --path:"$lib/packages/docutils" ---noNimblePath +#--noNimblePath --path:"$nim/" --path:"./vendor/nim" From 5deff1501a691108a16095e37f053e8d62738f4c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 11:10:52 +0100 Subject: [PATCH 029/424] Re-adds `-d:ssl` by default. Fixes #209. Fixes #210. --- src/nimble.nim.cfg | 1 + src/nimblepkg/config.nim | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim.cfg b/src/nimble.nim.cfg index 2146d12..223dfc3 100644 --- a/src/nimble.nim.cfg +++ b/src/nimble.nim.cfg @@ -2,3 +2,4 @@ #--noNimblePath --path:"$nim/" --path:"./vendor/nim" +-d:ssl diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index faeff6e..d9852fd 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -29,9 +29,9 @@ proc initConfig(): Config = result.packageLists = initTable[string, PackageList]() let defaultPkgList = PackageList(name: "Official", urls: @[ + "https://github.com/nim-lang/packages/raw/master/packages.json", "http://irclogs.nim-lang.org/packages.json", - "http://nim-lang.org/nimble/packages.json", - "https://github.com/nim-lang/packages/raw/master/packages.json" + "http://nim-lang.org/nimble/packages.json" ]) result.packageLists["official"] = defaultPkgList @@ -54,7 +54,7 @@ proc parseConfig*(): Config = f = newFileStream(confFile, fmRead) if f != nil: echo("[Warning] Using deprecated config file at ", confFile) - + if f != nil: echo("Reading from config file at ", confFile) var p: CfgParser From cbdc4ed3546503a79ae2fcc9b80e156842f090f9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 20:02:09 +0100 Subject: [PATCH 030/424] Bump version to 0.7.4. --- nimble.nimble | 6 +++--- src/nimble.nim | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index 28eea5d..1b51ec7 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,6 @@ # Package -version = "0.7.0" +version = "0.7.4" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" @@ -10,8 +10,8 @@ srcDir = "src" # Dependencies -requires "nim >= 0.12.1" +requires "nim >= 0.13.0" task tests, "Run the Nimble tester!": withDir "tests": - exec "nim c -r tester" \ No newline at end of file + exec "nim c -r tester" diff --git a/src/nimble.nim b/src/nimble.nim index fb231cc..f9ca7d1 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -31,7 +31,7 @@ else: dynlib: "kernel32", importc: "GetVersionExA".} const - nimbleVersion = "0.7.0" + nimbleVersion = "0.7.4" proc writeVersion() = echo("nimble v$# compiled at $# $#" % From b50426c3d3e42ba3b2897551acb3b5fb886d8d97 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 21:16:08 +0100 Subject: [PATCH 031/424] Set compiler.options.gPrefixDir to help it find the stdlib. Fixes #220. Fixes #173. --- nimble.nimble | 2 +- src/nimblepkg/nimscriptsupport.nim | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nimble.nimble b/nimble.nimble index 1b51ec7..84832eb 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -10,7 +10,7 @@ srcDir = "src" # Dependencies -requires "nim >= 0.13.0" +requires "nim >= 0.13.0", "compiler#head" task tests, "Run the Nimble tester!": withDir "tests": diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 267c4d3..c528c8b 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -192,6 +192,8 @@ proc findNimscriptApi(options: Options): string = if not inPath: raise newException(NimbleError, "Cannot find nimscriptapi.nim") +proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir + proc execScript(scriptName: string, flags: StringTableRef, options: Options) = ## Executes the specified script. ## @@ -199,6 +201,9 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes: compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi") + # Ensure the compiler can find its standard library #220. + compiler_options.gPrefixDir = getNimPrefixDir() + let pkgName = scriptName.splitFile.name # Ensure that "nimblepkg/nimscriptapi" is in the PATH. From e95df37ebedaf7b530df8c8153762f9f8e8b1992 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 21:33:55 +0100 Subject: [PATCH 032/424] Small readme installation instruction updates. --- readme.markdown | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/readme.markdown b/readme.markdown index 16e6c69..acaa028 100644 --- a/readme.markdown +++ b/readme.markdown @@ -54,12 +54,8 @@ the latest version of the Nim compiler (in the devel branch). You can be sure that Nimble will compile with that version of the compiler (a green travis build status is also a good sign that this is the case). -The latest version of Nimble (0.7.0) requires a version of Nim greater than -0.12.0. The latest version of Nimble which can be compiled using Nim -0.12.0 is 0.6.4. -Unfortunately, it is likely that you have the latest *release* of Nim -installed, 0.12.0 at the time of writing. So you will need to install -version 0.6.4 of Nimble. +The latest version of Nimble (0.7.4) requires a version of Nim greater than +or equal to 0.13.0. That being said, the latest version of Nim is recommended. Nimble has some runtime dependencies on external tools, these tools are used to download Nimble packages. @@ -87,8 +83,7 @@ the following commands to clone nimble, compile it and then install it. git clone https://github.com/nim-lang/nimble.git cd nimble - git clone -b v0.13.0 --depth 1 https://github.com/nim-lang/nim vendor/nim - nim -d:release c -r src/nimble install + nim -d:release c -r src/nimble -y install After these steps are completed successfully, nimble will be installed in ``~/.nimble/bin``. You must then add @@ -690,7 +685,7 @@ their own packages to it! Take a look at * ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]``` Make sure that nimble is configured to run with SSL, adding a ```-d:ssl``` -flag to the file ```src/nimble.nim.cfg```. +flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. From cc2c606fbe18d68af3aa42d44a256a9937ef9685 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 6 Jun 2016 22:04:49 +0100 Subject: [PATCH 033/424] Changelog for v0.7.4. --- changelog.markdown | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index e88fcf5..ef01790 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,5 +1,26 @@ # Nimble changelog +## 0.7.4 - 06/06/2016 + +This release is mainly a bug fix release. The installation problems +introduced by v0.7.0 should now be fixed. + +* Fixed symlink install issue + (Thank you [@yglukhov](https://github.com/yglukhov)). +* Fixed permission issue when installing packages + (Thank you [@SSPkrolik](https://github.com/SSPkrolik)). +* Work around for issue #204. + (Thank you [@Jeff-Ciesielski](https://github.com/Jeff-Ciesielski)). +* Fixed FD leak. + (Thank you [@yglukhov](https://github.com/yglukhov)). +* Implemented the ``--depsOnly`` option for the ``install`` command. +* Various fixes to installation/nimscript support problems introduced by +v0.7.0. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.2...v0.7.4 + ## 0.7.2 - 11/02/2016 This is a hotfix release which alleviates problems when building Nimble. From f6a19b54e47c7c99f2b473fc02915277273f8c41 Mon Sep 17 00:00:00 2001 From: def Date: Wed, 8 Jun 2016 16:28:24 +0200 Subject: [PATCH 034/424] Fix --depsOnly --- src/nimblepkg/options.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index fa261c4..baf0c35 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -255,7 +255,7 @@ proc parseFlag*(flag, val: string, result: var Options) = of "ver": result.queryVersions = true of "nimbledir": result.config.nimbleDir = val # overrides option from file of "installed", "i": result.queryInstalled = true - of "depsOnly", "d": result.depsOnly = true + of "depsonly", "d": result.depsOnly = true else: raise newException(NimbleError, "Unknown option: --" & flag) From e512b02fca15224e611b2d6c17011802b4e7ad5f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 17 Jun 2016 14:11:21 +0100 Subject: [PATCH 035/424] Fix compilation problem introduced by nim-lang/Nim#4357. --- src/nimblepkg/tools.nim | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index c68d0a2..369fa66 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -106,10 +106,11 @@ proc incl*(s: var HashSet[string], v: seq[string] | HashSet[string]) = for i in v: s.incl i -proc contains*(j: JsonNode, elem: JsonNode): bool = - for i in j: - if i == elem: - return true +when not declared(json.contains): + proc contains*(j: JsonNode, elem: JsonNode): bool = + for i in j: + if i == elem: + return true proc contains*(j: JsonNode, elem: tuple[key: string, val: JsonNode]): bool = for key, val in pairs(j): From 507dbf3ad3c13dae080f44fef71745a74394d35d Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Thu, 11 Aug 2016 15:01:33 +0200 Subject: [PATCH 036/424] updated readme.markdown --- readme.markdown | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/readme.markdown b/readme.markdown index acaa028..343219b 100644 --- a/readme.markdown +++ b/readme.markdown @@ -74,28 +74,21 @@ info. The following sections give platform-specific instructions on how to compile and install Nimble. -### Unix +### Source based installation -On Unix-like operating systems Nimble can be compiled and installed with two -simple -commands. After successfully grabbing the latest Nim compiler simply execute -the following commands to clone nimble, compile it and then install it. +Run this command in your **Nim** directory:: - git clone https://github.com/nim-lang/nimble.git - cd nimble - nim -d:release c -r src/nimble -y install + nim e install_nimble.nims -After these steps are completed successfully, nimble will be installed -in ``~/.nimble/bin``. You must then add -``~/.nimble/bin`` to your ``$PATH``. Updating nimble can then be done by -executing ``nimble install nimble``. +This assumes that you also used the source based installation and added +``$nim/bin`` to your ``PATH``. If you create a symlink to ``nim`` instead, +you also need to create a symlink for ``nimble``. ### Windows You can install Nimble via a pre-built installation archive which is available on the [releases](https://github.com/nim-lang/nimble/releases) page. -Alternatively, you can also install Nimble from source, but the instructions -for doing so are a bit different on Windows. +Alternatively, you can also install Nimble from source. #### Using the pre-built archives From dfb5dda51cc770521e4979e3f011a1b717c83bc3 Mon Sep 17 00:00:00 2001 From: Euan T Date: Sun, 4 Sep 2016 14:21:01 +0100 Subject: [PATCH 037/424] Fix spelling mistake of "initial". --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index f9ca7d1..cb2d800 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -760,7 +760,7 @@ proc init(options: Options) = raise newException(NimbleError, "Nimble file already exists.") # Ask for package version. - let pkgVersion = promptCustom("Enter intial version of package", "0.1.0") + let pkgVersion = promptCustom("Enter initial version of package", "0.1.0") validateVersion(pkgVersion) # Ask for package author From 781bed25de16bc9bd6cace0204afbc05ec5b3bd9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 4 Sep 2016 15:49:26 +0200 Subject: [PATCH 038/424] Fixes "can use nimscript's setCommand with flags" test. --- tests/tester.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 886533b..3f5a51d 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -7,7 +7,7 @@ const path = "../src/nimble" test "can compile nimble": check execCmdEx("nim c " & path).exitCode == QuitSuccess -template cd*(dir: string, body: stmt) = +template cd*(dir: string, body: untyped) = ## Sets the current dir to ``dir``, executes ``body`` and restores the ## previous working dir. let lastDir = getCurrentDir() @@ -103,7 +103,6 @@ test "can use nimscript's setCommand with flags": let (output, exitCode) = execCmdEx("../" & path & " cr") let lines = output.strip.splitLines() check exitCode == QuitSuccess - check "Hint: operation successful".normalize in lines[^2].normalize check "Hello World".normalize in lines[^1].normalize test "can list nimscript tasks": From 29d69e9cc7649acbea0759c5a6488039703d6042 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Thu, 15 Sep 2016 09:00:04 -0400 Subject: [PATCH 039/424] Add tilde expansion to nimbleDir. Fixes #239 --- src/nimblepkg/options.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index baf0c35..e67815c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -191,13 +191,13 @@ proc renameBabelToNimble(options: Options) {.deprecated.} = removeFile(nimbleDir / "babeldata.json") proc getNimbleDir*(options: Options): string = - options.config.nimbleDir + expandTilde(options.config.nimbleDir) proc getPkgsDir*(options: Options): string = - options.config.nimbleDir / "pkgs" + options.getNimbleDir() / "pkgs" proc getBinDir*(options: Options): string = - options.config.nimbleDir / "bin" + options.getNimbleDir() / "bin" proc parseCommand*(key: string, result: var Options) = result.action.typ = parseActionType(key) From e4838f47185c3496afb4ba7cde6bf5efd39a2550 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Mon, 19 Sep 2016 08:45:33 -0400 Subject: [PATCH 040/424] Add binDir checking/auto creation. Fixes #215 --- src/nimble.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/nimble.nim b/src/nimble.nim index cb2d800..72e4790 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -313,6 +313,11 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" echo("Building ", pkginfo.name, "/", bin, " using ", pkgInfo.backend, " backend...") + + let outputDir = pkgInfo.getOutputDir("") + if not existsDir(outputDir): + createDir(outputDir) + try: doCmd(getNimBin() & " $# $# --noBabelPath $# $# \"$#\"" % [pkgInfo.backend, releaseOpt, args, outputOpt, From f29f21d2e03c5b6dedb8c957355e03e315ce3e8a Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 21 Sep 2016 13:58:07 +0300 Subject: [PATCH 041/424] Store vcs revision in metadata --- src/nimble.nim | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 72e4790..4fc11cd 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -326,11 +326,14 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = raise newException(BuildFailed, "Build failed for package: " & pkgInfo.name) -proc saveNimbleMeta(pkgDestDir, url: string, filesInstalled: HashSet[string]) = +proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, filesInstalled: HashSet[string]) = var nimblemeta = %{"url": %url} - nimblemeta["files"] = newJArray() + if not vcsRevision.isNil: + nimblemeta["vcsRevision"] = %vcsRevision + let files = newJArray() + nimblemeta["files"] = files for file in filesInstalled: - nimblemeta["files"].add(%changeRoot(pkgDestDir, "", file)) + files.add(%changeRoot(pkgDestDir, "", file)) writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) proc removePkgDir(dir: string, options: Options) = @@ -358,6 +361,23 @@ proc removePkgDir(dir: string, options: Options) = quit(QuitSuccess) removeDir(dir) +proc vcsRevisionInDir(dir: string): string = + ## Returns current revision number of HEAD if dir is inside VCS, or nil in + ## case of failure. + var cmd = "" + if dirExists(dir / ".git"): + cmd = "git -C " & quoteShell(dir) & " rev-parse HEAD" + elif dirExists(dir / ".hg"): + cmd = "hg --cwd " & quoteShell(dir) & " id -i" + + if cmd.len > 0: + try: + let res = doCmdEx(cmd) + if res.exitCode == 0: + result = string(res.output).strip() + except: + discard + proc installFromDir(dir: string, latest: bool, options: Options, url: string): tuple[paths: seq[string], pkg: PackageInfo] = ## Returns where package has been installed to, together with paths @@ -458,8 +478,10 @@ proc installFromDir(dir: string, latest: bool, options: Options, filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, pkgInfo) + let vcsRevision = vcsRevisionInDir(realDir) + # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, url, filesInstalled) + saveNimbleMeta(pkgDestDir, url, vcsRevision, filesInstalled) # Save the nimble data (which might now contain reverse deps added in # processDeps). From f0dd4a1efc747fabe9526ac2b6a4200e2c3ca8fe Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 26 Sep 2016 19:11:12 +0200 Subject: [PATCH 042/424] Update changelog with changes since 0.7.4. --- changelog.markdown | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index ef01790..13d697d 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,5 +1,15 @@ # Nimble changelog +## 0.7.6 - 26/09/2016 + +This is a small release designed to coincide with the release of Nim 0.15.0. + +* Fixes ``--depsOnly`` flag ([commit](https://github.com/nim-lang/nimble/commit/f6a19b54e47c7c99f2b473fc02915277273f8c41)) +* Fixes compilation on 0.15.0. +* Fixes #239. +* Fixes #215. +* VCS information is now stored in the Nimble package metadata. + ## 0.7.4 - 06/06/2016 This release is mainly a bug fix release. The installation problems From 436b7c6e93f95601006a8bb7e545a5760466320a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 28 Sep 2016 23:30:09 +0200 Subject: [PATCH 043/424] HotFix: Support spaces in binary paths for doCmdEx. --- src/nimblepkg/tools.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 369fa66..7e2989f 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -2,11 +2,17 @@ # BSD License. Look at license.txt for more info. # # Various miscellaneous utility functions reside here. -import osproc, pegs, strutils, os, uri, sets, json +import osproc, pegs, strutils, os, uri, sets, json, parseutils import version, packageinfo, nimbletypes +proc extractBin(cmd: string): string = + if cmd[0] == '"': + return cmd.captureBetween('"') + else: + return cmd.split(' ')[0] + proc doCmd*(cmd: string) = - let bin = cmd.split(' ')[0] + let bin = extractBin(cmd) if findExe(bin) == "": raise newException(NimbleError, "'" & bin & "' not in PATH.") @@ -21,7 +27,7 @@ proc doCmd*(cmd: string) = "Execution failed with exit code " & $exitCode) proc doCmdEx*(cmd: string): tuple[output: TaintedString, exitCode: int] = - let bin = cmd.split(' ')[0] + let bin = extractBin(cmd) if findExe(bin) == "": raise newException(NimbleError, "'" & bin & "' not in PATH.") return execCmdEx(cmd) @@ -41,7 +47,7 @@ proc getNimBin*: string = proc getNimrodVersion*: Version = let nimBin = getNimBin() - let vOutput = doCmdEx(nimBin & " -v").output + let vOutput = doCmdEx('"' & nimBin & "\" -v").output var matches: array[0..MaxSubpatterns, string] if vOutput.find(peg"'Version'\s{(\d+\.)+\d}", matches) == -1: quit("Couldn't find Nim version.", QuitFailure) From 22d27cfaac379f673d39c92166a9bfeb4d9b7535 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 28 Sep 2016 23:32:01 +0200 Subject: [PATCH 044/424] Update changelog for v0.7.8. --- changelog.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index 13d697d..f40f584 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,5 +1,10 @@ # Nimble changelog +## 0.7.8 - 28/09/2016 + +This is a hotfix release which fixes crashes when Nimble (or Nim) is installed +to ``C:\Program Files`` or other paths with spaces in them. + ## 0.7.6 - 26/09/2016 This is a small release designed to coincide with the release of Nim 0.15.0. From e3682c96b3580739fb017c756c1d64be3d3208ea Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 29 Sep 2016 21:35:52 +0200 Subject: [PATCH 045/424] Bump version to v0.7.8. --- nimble.nimble | 2 +- src/nimble.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index 84832eb..973b86a 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,6 @@ # Package -version = "0.7.4" +version = "0.7.8" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" diff --git a/src/nimble.nim b/src/nimble.nim index 4fc11cd..f8d971c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -31,7 +31,7 @@ else: dynlib: "kernel32", importc: "GetVersionExA".} const - nimbleVersion = "0.7.4" + nimbleVersion = "0.7.8" proc writeVersion() = echo("nimble v$# compiled at $# $#" % From 36a61739b15a9ade8e4d48aad1d878562cd8c38a Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 8 Oct 2016 12:07:24 +0200 Subject: [PATCH 046/424] up to date readme.markdown --- readme.markdown | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/readme.markdown b/readme.markdown index 343219b..9dbec1d 100644 --- a/readme.markdown +++ b/readme.markdown @@ -86,36 +86,7 @@ you also need to create a symlink for ``nimble``. ### Windows -You can install Nimble via a pre-built installation archive which is -available on the [releases](https://github.com/nim-lang/nimble/releases) page. -Alternatively, you can also install Nimble from source. - -#### Using the pre-built archives - -Download the latest release archive from the -[releases](https://github.com/nim-lang/nimble/releases) page. These archives -will have a filename of the form ``nimble-x_win32`` where ``x`` is the -current version. - -Once you download that archive unzip it and execute the ``install.bat`` file. -One important thing to note is that this installation requires you have -the Nim compiler in your PATH. Once the installation completes you should -add ``C:\Users\YourName\.nimble\bin`` to your PATH. - -#### From source - -On Windows installing Nimble from source is slightly more complex: - - git clone https://github.com/nim-lang/nimble.git - cd nimble - nim -d:release c src/nimble - cp src/nimble.exe src/nimble1.exe - src/nimble1.exe install - -This is required because Windows will lock the process which is being run, but -during installation Nimble recompiles itself causing an error. -Once the installation completes you should -add ``C:\Users\YourName\.nimble\bin`` to your PATH. +The Windows installer ships with ``nimble.exe`` out of the box. ## Nimble's folder structure and packages From 75dbfe9d0e6c70e85792dbeb458ad5c9e690f79a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 8 Oct 2016 18:04:36 +0200 Subject: [PATCH 047/424] Improves readme installation instructions. Fixes #260. --- readme.markdown | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/readme.markdown b/readme.markdown index 9dbec1d..e897314 100644 --- a/readme.markdown +++ b/readme.markdown @@ -8,11 +8,8 @@ Interested in learning **how to create a package**? Skip directly to that sectio ## Contents +- [Requirements](#requirements) - [Installation](#installation) - - [Unix](#unix) - - [Windows](#windows) - - [Using the pre-built archives](#using-the-pre-built-archives) - - [From source](#from-source) - [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages) - [Nimble usage](#nimble-usage) - [nimble refresh](#nimble-refresh) @@ -47,15 +44,7 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Contribution](#contribution) - [About](#about) -## Installation - -The latest version of Nimble (in the master branch) is primarily tested with -the latest version of the Nim compiler (in the devel branch). You can be sure -that Nimble will compile with that version of the compiler (a green travis -build status is also a good sign that this is the case). - -The latest version of Nimble (0.7.4) requires a version of Nim greater than -or equal to 0.13.0. That being said, the latest version of Nim is recommended. +## Requirements Nimble has some runtime dependencies on external tools, these tools are used to download Nimble packages. @@ -71,22 +60,42 @@ If the version is less recent than 1.9.0 then Nimble may have trouble using it. See [this issue](https://github.com/nim-lang/nimble/issues/105) for more info. -The following sections give platform-specific instructions on how to -compile and install Nimble. +## Installation -### Source based installation +Nimble is now bundled with [Nim](http://nim-lang.org) +(since Nim version 0.15.0). +This means that you should have Nimble installed already, as long as you have +the latest version of Nim installed as well. Because of this **you likely do +not need to install Nimble manually**. -Run this command in your **Nim** directory:: +But in case you still want to install Nimble manually, you can follow the +following instructions. - nim e install_nimble.nims +There are two ways to install Nimble manually. The first is using the +``install_nimble.nims`` script included in the Nim distribution and +[repository](https://github.com/nim-lang/Nim/blob/devel/install_nimble.nims). +Simply execute this to install Nimble. -This assumes that you also used the source based installation and added -``$nim/bin`` to your ``PATH``. If you create a symlink to ``nim`` instead, -you also need to create a symlink for ``nimble``. +``` +nim e install_nimble.nims +``` -### Windows +This will clone the Nimble repository, compile Nimble and copy it into +Nim's bin directory. -The Windows installer ships with ``nimble.exe`` out of the box. +The second approach is to install Nimble as a Nimble package. You can do this +by compiling Nimble, then running ``nimble install`` in Nimble's directory. + +``` +git clone https://github.com/nim-lang/nimble.git +cd nimble +nim c src/nimble +src/nimble install +``` + +**Note for Windows users**: You will need to rename ``nimble.exe`` after +compilation to something else like ``nimble1.exe``, then run +``src\nimble1.exe install``. ## Nimble's folder structure and packages From 138a5a2ae9650713c9cba9b2af231f07af4117ee Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 8 Oct 2016 20:27:47 +0200 Subject: [PATCH 048/424] Statically read nimscriptapi.nim into the executable. Fixes #238. --- src/nimblepkg/nimscriptsupport.nim | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index c528c8b..092d021 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -28,6 +28,7 @@ type const internalCmd = "NimbleInternal" + nimscriptApi = staticRead("nimscriptapi.nim") proc raiseVariableError(ident, typ: string) {.noinline.} = raise newException(NimbleError, @@ -173,24 +174,20 @@ proc setupVM(module: PSym; scriptName: string, flags[a.getString 0] = a.getString 1 proc findNimscriptApi(options: Options): string = - ## Returns the directory containing ``nimscriptapi.nim`` - var inPath = false + ## Returns the directory containing ``nimscriptapi.nim`` or an empty string + ## if it cannot be found. + result = "" # Try finding it in exe's path if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"): result = getAppDir() - inPath = true - if not inPath: + if result.len == 0: let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options) var pkg: PackageInfo if pkgs.findPkg(("nimble", newVRAny()), pkg): let pkgDir = pkg.getRealDir() if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"): result = pkgDir - inPath = true - - if not inPath: - raise newException(NimbleError, "Cannot find nimscriptapi.nim") proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir @@ -208,7 +205,16 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = # Ensure that "nimblepkg/nimscriptapi" is in the PATH. let nimscriptApiPath = findNimscriptApi(options) - appendStr(searchPaths, nimscriptApiPath) + if nimscriptApiPath.len > 0: + echo("Using custom nimscriptapi.nim defined in ", + nimscriptApiPath / "nimblepkg") + appendStr(searchPaths, nimscriptApiPath) + else: + let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" + createDir(tmpNimscriptApiPath.splitFile.dir) + if not existsFile(tmpNimscriptApiPath): + writeFile(tmpNimscriptApiPath, nimscriptApi) + appendStr(searchPaths, getTempDir()) setDefaultLibpath() passes.gIncludeFile = includeModule From 0564cb238a902506d0d14aa3f4fd3ef74ba0521c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 8 Oct 2016 20:51:19 +0200 Subject: [PATCH 049/424] Fixes #129. --- src/nimblepkg/download.nim | 11 ++++------- tests/tester.nim | 4 ++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 1310886..5e6506f 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -174,13 +174,10 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, if verRange.spe == newSpecial(getHeadName(downMethod)): doClone(downMethod, url, downloadDir) # Grab HEAD. else: - # Mercurial requies a clone and checkout. The git clone operation is - # already fragmented into multiple steps so we just call doClone(). - if downMethod == DownloadMethod.git: - doClone(downMethod, url, downloadDir, $verRange.spe) - else: - doClone(downMethod, url, downloadDir, tip = false) - doCheckout(downMethod, downloadDir, $verRange.spe) + # Grab the full repo. + doClone(downMethod, url, downloadDir, tip = false) + # Then perform a checkout operation to get the specified branch/commit. + doCheckout(downMethod, downloadDir, $verRange.spe) result = verRange else: case downMethod diff --git a/tests/tester.nim b/tests/tester.nim index 3f5a51d..3aa669d 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -22,6 +22,10 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "issue 129 (installing commit hash)": + check execCmdEx(path & " install -y \"https://github.com/nimble-test/packagea.git@#1f9cb289c89\""). + exitCode == QuitSuccess + test "issue 113 (uninstallation problems)": cd "issue113/c": check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess From ec5b00318cde86e41048f856d130da472c54906e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 8 Oct 2016 20:54:08 +0200 Subject: [PATCH 050/424] Revert "Fixed cygwin stub" This reverts commit 5aa4752b153ab3b74934a49ada424dd16bcb8c6a. Refs #235. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index f8d971c..e584839 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -471,7 +471,7 @@ proc installFromDir(dir: string, latest: bool, options: Options, # For bash on Windows (Cygwin/Git bash). let bashDest = dest.changeFileExt("") echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) - writeFile(bashDest, "\"$(cygpath '" & pkgDestDir / bin & "')\" \"$@\"\l") + writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") else: {.error: "Sorry, your platform is not supported.".} else: From b0737ada9bfad90a49975dcd7c71d60fd3674d4c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 8 Oct 2016 21:13:49 +0200 Subject: [PATCH 051/424] Fixes #186. --- src/nimblepkg/nimscriptsupport.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 092d021..7f5e699 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -8,7 +8,7 @@ import compiler/ast, compiler/modules, compiler/passes, compiler/passaux, compiler/condsyms, compiler/sem, compiler/semdata, compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, - compiler/msgs, compiler/magicsys, compiler/lists + compiler/msgs, compiler/magicsys, compiler/lists, compiler/nimconf from compiler/scriptconfig import setupVM from compiler/idents import getIdent @@ -216,10 +216,10 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = writeFile(tmpNimscriptApiPath, nimscriptApi) appendStr(searchPaths, getTempDir()) - setDefaultLibpath() + initDefines() + loadConfigs(DefaultConfig) passes.gIncludeFile = includeModule passes.gImportModule = importModule - initDefines() defineSymbol("nimscript") defineSymbol("nimconfig") From df5b9b8c78d66d8386902bf209b3711d969677dc Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Oct 2016 14:55:21 +0200 Subject: [PATCH 052/424] Small improvements to readme. --- readme.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.markdown b/readme.markdown index e897314..12c6cd3 100644 --- a/readme.markdown +++ b/readme.markdown @@ -97,6 +97,10 @@ src/nimble install compilation to something else like ``nimble1.exe``, then run ``src\nimble1.exe install``. +This will install Nimble to the default Nimble packages location: +``~/.nimble/pkgs``. The binary will be installed to ``~/.nimble/bin``, so you +will need to add this directory to your PATH. + ## Nimble's folder structure and packages Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems From 65dbd97269f1a058f41551880415f28dfdbb3aaa Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Oct 2016 15:19:42 +0200 Subject: [PATCH 053/424] Moves nimbleVersion to common.nim and uses it in .nimble file. --- src/nimble.nim | 5 +--- src/nimblepkg/common.nim | 40 ++++++++++++++++++++++++++++++ src/nimblepkg/config.nim | 2 +- src/nimblepkg/download.nim | 2 +- src/nimblepkg/nimbletypes.nim | 36 --------------------------- src/nimblepkg/nimscriptsupport.nim | 2 +- src/nimblepkg/options.nim | 2 +- src/nimblepkg/packageinfo.nim | 2 +- src/nimblepkg/packageparser.nim | 2 +- src/nimblepkg/publish.nim | 2 +- src/nimblepkg/tools.nim | 2 +- 11 files changed, 49 insertions(+), 48 deletions(-) create mode 100644 src/nimblepkg/common.nim delete mode 100644 src/nimblepkg/nimbletypes.nim diff --git a/src/nimble.nim b/src/nimble.nim index e584839..2a7c04f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -7,7 +7,7 @@ import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils, from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, - nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes, + nimblepkg/download, nimblepkg/config, nimblepkg/common, nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser import nimblepkg/nimscriptsupport @@ -30,9 +30,6 @@ else: proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetVersionExA".} -const - nimbleVersion = "0.7.8" - proc writeVersion() = echo("nimble v$# compiled at $# $#" % [nimbleVersion, CompileDate, CompileTime]) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim new file mode 100644 index 0000000..1348d58 --- /dev/null +++ b/src/nimblepkg/common.nim @@ -0,0 +1,40 @@ +# BSD License. Look at license.txt for more info. +# +# Various miscellaneous common types reside here, to avoid problems with +# recursive imports + +when not defined(nimscript): + import sets + + import version + export version.NimbleError + + type + BuildFailed* = object of NimbleError + + PackageInfo* = object + mypath*: string ## The path of this .nimble file + isNimScript*: bool ## Determines if this pkg info was read from a nims file + isMinimal*: bool + isInstalled*: bool ## Determines if the pkg this info belongs to is installed + postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily + preHooks*: HashSet[string] + name*: string + version*: string + author*: string + description*: string + license*: string + skipDirs*: seq[string] + skipFiles*: seq[string] + skipExt*: seq[string] + installDirs*: seq[string] + installFiles*: seq[string] + installExt*: seq[string] + requires*: seq[PkgTuple] + bin*: seq[string] + binDir*: string + srcDir*: string + backend*: string + +const + nimbleVersion* = "0.7.8" diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index d9852fd..dbd1513 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -2,7 +2,7 @@ # BSD License. Look at license.txt for more info. import parsecfg, streams, strutils, os, tables, Uri -import tools, version, nimbletypes +import tools, version, common type Config* = object diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 5e6506f..5ce58b4 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -3,7 +3,7 @@ import parseutils, os, osproc, strutils, tables, pegs -import packageinfo, packageparser, version, tools, nimbletypes, options +import packageinfo, packageparser, version, tools, common, options type DownloadMethod* {.pure.} = enum diff --git a/src/nimblepkg/nimbletypes.nim b/src/nimblepkg/nimbletypes.nim deleted file mode 100644 index ae6ec47..0000000 --- a/src/nimblepkg/nimbletypes.nim +++ /dev/null @@ -1,36 +0,0 @@ -# BSD License. Look at license.txt for more info. -# -# Various miscellaneous common types reside here, to avoid problems with -# recursive imports - -import sets - -import version -export version.NimbleError - -type - BuildFailed* = object of NimbleError - - PackageInfo* = object - mypath*: string ## The path of this .nimble file - isNimScript*: bool ## Determines if this pkg info was read from a nims file - isMinimal*: bool - isInstalled*: bool ## Determines if the pkg this info belongs to is installed - postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily - preHooks*: HashSet[string] - name*: string - version*: string - author*: string - description*: string - license*: string - skipDirs*: seq[string] - skipFiles*: seq[string] - skipExt*: seq[string] - installDirs*: seq[string] - installFiles*: seq[string] - installExt*: seq[string] - requires*: seq[PkgTuple] - bin*: seq[string] - binDir*: string - srcDir*: string - backend*: string diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 7f5e699..c5e7b4a 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -15,7 +15,7 @@ from compiler/idents import getIdent from compiler/astalgo import strTableGet import compiler/options as compiler_options -import nimbletypes, version, options, packageinfo +import common, version, options, packageinfo import os, strutils, strtabs, times, osproc, sets type diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index e67815c..f1e9805 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -4,7 +4,7 @@ import json, strutils, os, parseopt, strtabs, uri, tables from httpclient import Proxy, newProxy -import config, version, tools, nimbletypes +import config, version, tools, common type Options* = object diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 5c07957..4fe5cca 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. import parsecfg, json, streams, strutils, parseutils, os, sets, tables -import version, tools, nimbletypes, options +import version, tools, common, options type Package* = object diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index cf641a9..c6259d4 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. import parsecfg, json, streams, strutils, parseutils, os, tables -import version, tools, nimbletypes, nimscriptsupport, options, packageinfo +import version, tools, common, nimscriptsupport, options, packageinfo ## Contains procedures for parsing .nimble files. Moved here from ``packageinfo`` ## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index e831c9d..e7fa836 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -5,7 +5,7 @@ ## nim-lang/packages automatically. import httpclient, base64, strutils, rdstdin, json, os, browsers, times, uri -import tools, nimbletypes +import tools, common type Auth = object diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 7e2989f..65c6f8d 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -3,7 +3,7 @@ # # Various miscellaneous utility functions reside here. import osproc, pegs, strutils, os, uri, sets, json, parseutils -import version, packageinfo, nimbletypes +import version, packageinfo, common proc extractBin(cmd: string): string = if cmd[0] == '"': From 1be5c052ae3e95ef8fdc745617e1f23b88ad839a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Oct 2016 15:20:31 +0200 Subject: [PATCH 054/424] Version 0.7.10. --- changelog.markdown | 22 ++++++++++++++++++++++ nimble.nimble | 3 ++- src/nimblepkg/common.nim | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/changelog.markdown b/changelog.markdown index f40f584..f038524 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -1,5 +1,27 @@ + +[comment]: # (Before releasing, make sure to follow the steps in https://github.com/nim-lang/nimble/wiki/Releasing-a-new-version) + # Nimble changelog +## 0.7.10 - 09/10/2016 + +This release includes multiple bug fixes. + +* Reverted patch that breaks binary stubs in Git Bash on Windows. +* The ``nimscriptapi.nim`` file is now statically compiled into the binary. + This should fix the "could not find nimscriptapi.nim" errors. The file can + still be overriden by placing a file named ``nimscriptapi.nim`` inside a + ``nimblepkg`` directory that is placed alongside the Nimble binary, or + by a ``nimscriptapi.nim`` file inside ``~/.nimble/pkgs/nimble-ver/nimblepkg/``. + For more information see the + [code that looks for this file](https://github.com/nim-lang/nimble/blob/v0.7.10/src/nimblepkg/nimscriptsupport.nim#L176). +* Nim files can now be imported in .nimble nimscript files. (Issue [#186](https://github.com/nim-lang/nimble/issues/186)) +* Requiring a specific git commit hash no longer fails. (Issue [#129](https://github.com/nim-lang/nimble/issues/129)) + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.8...v0.7.10 + ## 0.7.8 - 28/09/2016 This is a hotfix release which fixes crashes when Nimble (or Nim) is installed diff --git a/nimble.nimble b/nimble.nimble index 973b86a..99431ac 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,7 @@ +import src/nimblepkg/common # Package -version = "0.7.8" +version = nimbleVersion author = "Dominik Picheta" description = "Nim package manager." license = "BSD" diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 1348d58..417ff29 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -37,4 +37,4 @@ when not defined(nimscript): backend*: string const - nimbleVersion* = "0.7.8" + nimbleVersion* = "0.7.10" From 2eec3917324dcf464527ab477a72a0a2a85ea9e7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 26 Oct 2016 20:10:17 +0200 Subject: [PATCH 055/424] Fixes getInstalledPkgs returning minimal package information. This was introduced in commit https://github.com/nim-lang/nimble/commit/2cf03313fdd38121f6d3f406ad76d3c03cd9b6a5. --- src/nimble.nim | 1 + src/nimblepkg/packageparser.nim | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2a7c04f..fbe605f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -255,6 +255,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = ## ## Returns the list of paths to pass to the compiler during build phase. result = @[] + assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires") let pkglist = getInstalledPkgs(options.getPkgsDir(), options) var reverseDeps: seq[tuple[name, version: string]] = @[] for dep in pkginfo.requires: diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index c6259d4..fbe8cfc 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -250,7 +250,7 @@ proc getInstalledPkgs*(libsDir: string, options: Options): if nimbleFile != "": let meta = readMetaData(path) try: - var pkg = readPackageInfo(nimbleFile, options, true) + var pkg = readPackageInfo(nimbleFile, options, onlyMinimalInfo=false) pkg.isInstalled = true result.add((pkg, meta)) except ValidationError: From d854bc64c85645f38e0133663c06c996df96f7dc Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 26 Oct 2016 20:16:35 +0200 Subject: [PATCH 056/424] Fix import inside nimble.nimble when Nimble is installed. --- nimble.nimble | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nimble.nimble b/nimble.nimble index 99431ac..7b3917a 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,4 +1,10 @@ -import src/nimblepkg/common +when dirExists("src"): + # In the git repository the Nimble sources are in a ``src`` directory. + import src/nimblepkg/common +else: + # When the package is installed, the ``src`` directory disappears. + import nimblepkg/common + # Package version = nimbleVersion From 06b942680b5c335b8f3487fe5d152441a92cbfb2 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 26 Oct 2016 21:14:18 +0200 Subject: [PATCH 057/424] Remove spammy message about nimscriptapi.nim. --- src/nimblepkg/nimscriptsupport.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index c5e7b4a..129e06a 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -206,8 +206,7 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = # Ensure that "nimblepkg/nimscriptapi" is in the PATH. let nimscriptApiPath = findNimscriptApi(options) if nimscriptApiPath.len > 0: - echo("Using custom nimscriptapi.nim defined in ", - nimscriptApiPath / "nimblepkg") + # TODO: Once better output is implemented show a message here. appendStr(searchPaths, nimscriptApiPath) else: let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" From 4ce6f2b39526f6570834a8c0eb786b098bbf52e8 Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 31 Oct 2016 20:29:17 +0100 Subject: [PATCH 058/424] make Nimble compile with the changed compiler API --- src/nimblepkg/nimscriptsupport.nim | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index c528c8b..093a64a 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -8,10 +8,9 @@ import compiler/ast, compiler/modules, compiler/passes, compiler/passaux, compiler/condsyms, compiler/sem, compiler/semdata, compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, - compiler/msgs, compiler/magicsys, compiler/lists + compiler/msgs, compiler/magicsys, compiler/lists, compiler/idents from compiler/scriptconfig import setupVM -from compiler/idents import getIdent from compiler/astalgo import strTableGet import compiler/options as compiler_options @@ -67,6 +66,9 @@ proc extractRequires(ident: PSym, result: var seq[PkgTuple]) = else: raiseVariableError("requiresData", "seq[(string, VersionReq)]") +when declared(newIdentCache): + var identCache = newIdentCache() + proc setupVM(module: PSym; scriptName: string, flags: StringTableRef): PEvalContext = ## This procedure is exported in the compiler sources, but its implementation @@ -74,7 +76,10 @@ proc setupVM(module: PSym; scriptName: string, ## Specifically, the implementation of ``switch`` is problematic. Sooo ## I simply copied it here and edited it :) - result = newCtx(module) + when declared(newIdentCache): + result = newCtx(module, identCache) + else: + result = newCtx(module) result.mode = emRepl registerAdditionalOps(result) @@ -236,8 +241,12 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = cbApi getPkgDir: setResult(a, scriptName.splitFile.dir) - compileSystemModule() - processModule(m, llStreamOpen(scriptName, fmRead), nil) + when declared(newIdentCache): + compileSystemModule(identCache) + processModule(m, llStreamOpen(scriptName, fmRead), nil, identCache) + else: + compileSystemModule() + processModule(m, llStreamOpen(scriptName, fmRead), nil) proc cleanup() = # ensure everything can be called again: From 417136e57e09b1654b52a73ff4beba388428d607 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 5 Nov 2016 01:17:05 +0100 Subject: [PATCH 059/424] make Nimble compiler with the lastest version of the compiler API --- src/nimblepkg/nimscriptsupport.nim | 49 ++++++++++++++---------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index a873ee6..4b5ce03 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -18,6 +18,9 @@ import compiler/options as compiler_options import common, version, options, packageinfo import os, strutils, strtabs, times, osproc, sets +when not declared(resetAllModulesHard): + import compiler/modulegraphs + type ExecutionResult*[T] = object success*: bool @@ -197,8 +200,9 @@ proc findNimscriptApi(options: Options): string = proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir -proc execScript(scriptName: string, flags: StringTableRef, options: Options) = - ## Executes the specified script. +proc execScript(scriptName: string, flags: StringTableRef, + options: Options): PSym = + ## Executes the specified script. Returns the script's module symbol. ## ## No clean up is performed and must be done manually! if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes: @@ -234,9 +238,14 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = appendStr(searchPaths, compiler_options.libpath) - var m = makeModule(scriptName) - incl(m.flags, sfMainModule) - vm.globalCtx = setupVM(m, scriptName, flags) + when declared(resetAllModulesHard): + result = makeModule(scriptName) + else: + let graph = newModuleGraph() + result = graph.makeModule(scriptName) + + incl(result.flags, sfMainModule) + vm.globalCtx = setupVM(result, scriptName, flags) # Setup builtins defined in nimscriptapi.nim template cbApi(name, body) {.dirty.} = @@ -248,17 +257,18 @@ proc execScript(scriptName: string, flags: StringTableRef, options: Options) = setResult(a, scriptName.splitFile.dir) when declared(newIdentCache): - compileSystemModule(identCache) - processModule(m, llStreamOpen(scriptName, fmRead), nil, identCache) + graph.compileSystemModule(identCache) + graph.processModule(result, llStreamOpen(scriptName, fmRead), nil, identCache) else: compileSystemModule() - processModule(m, llStreamOpen(scriptName, fmRead), nil) + processModule(result, llStreamOpen(scriptName, fmRead), nil) proc cleanup() = # ensure everything can be called again: compiler_options.gProjectName = "" compiler_options.command = "" - resetAllModulesHard() + when declared(resetAllModulesHard): + resetAllModulesHard() clearPasses() msgs.gErrorMax = 1 msgs.writeLnHook = nil @@ -287,7 +297,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, compiler_options.command = internalCmd # Execute the nimscript file. - execScript(scriptName, nil, options) + let thisModule = execScript(scriptName, nil, options) # Check whether an error has occurred. if msgs.gErrorCounter > 0: @@ -305,12 +315,6 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, template trivialFieldSeq(field) = result.field.add getGlobalAsSeq(getSym(thisModule, astToStr field)) - # Grab the module Sym for .nimble file (nimscriptapi is included in it). - let idx = fileInfoIdx(scriptName) - let thisModule = getModule(idx) - assert(not thisModule.isNil) - assert thisModule.kind == skModule - # keep reasonable default: let name = getGlobal(thisModule.tab.strTableGet(getIdent"packageName")) if name.len > 0: result.name = name @@ -363,11 +367,7 @@ proc execTask*(scriptName, taskName: string, compiler_options.command = internalCmd echo("Executing task ", taskName, " in ", scriptName) - execScript(scriptName, result.flags, options) - # Explicitly execute the task procedure, instead of relying on hack. - let idx = fileInfoIdx(scriptName) - let thisModule = getModule(idx) - assert thisModule.kind == skModule + let thisModule = execScript(scriptName, result.flags, options) let prc = thisModule.tab.strTableGet(getIdent(taskName & "Task")) if prc.isNil: # Procedure not defined in the NimScript module. @@ -397,11 +397,8 @@ proc execHook*(scriptName, actionName: string, before: bool, else: actionName.toLower & "After" echo("Attempting to execute hook ", hookName, " in ", scriptName) - execScript(scriptName, result.flags, options) + let thisModule = execScript(scriptName, result.flags, options) # Explicitly execute the task procedure, instead of relying on hack. - let idx = fileInfoIdx(scriptName) - let thisModule = getModule(idx) - assert thisModule.kind == skModule let prc = thisModule.tab.strTableGet(getIdent(hookName)) if prc.isNil: # Procedure not defined in the NimScript module. @@ -435,7 +432,7 @@ proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = proc listTasks*(scriptName: string, options: Options) = setNimScriptCommand("help") - execScript(scriptName, nil, options) + discard execScript(scriptName, nil, options) # TODO: Make the 'task' template generate explicit data structure containing # all the task names + descriptions. cleanup() From ba46f95febc632aa65a0c6a614db12e893d60211 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 6 Nov 2016 19:58:20 +0100 Subject: [PATCH 060/424] cleanup tester and introduce safeMoveFile for Windows --- tests/tester.nim | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 3aa669d..079c539 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -51,12 +51,19 @@ test "issue 113 (uninstallation problems)": test "can refresh with default urls": check execCmdEx(path & " refresh").exitCode == QuitSuccess +proc safeMoveFile(src, dest: string) = + try: + moveFile(src, dest) + except OSError: + copyFile(src, dest) + removeFile(src) + test "can refresh with custom urls": # Backup current config let configFile = getConfigDir() / "nimble" / "nimble.ini" let configBakFile = getConfigDir() / "nimble" / "nimble.ini.bak" if fileExists(configFile): - moveFile(configFile, configBakFile) + safeMoveFile(configFile, configBakFile) # Ensure config dir exists createDir(getConfigDir() / "nimble") @@ -82,7 +89,7 @@ test "can refresh with custom urls": # Restore config if fileExists(configBakFile): - moveFile(configBakFile, configFile) + safeMoveFile(configBakFile, configFile) test "can install nimscript package": cd "nimscript": @@ -225,6 +232,6 @@ test "can uninstall": check execCmdEx(path & " uninstall -y PackageA@0.2 issue27b").exitCode == QuitSuccess - check (not dirExists(getHomeDir() / ".nimble" / "pkgs" / "PackageA-0.2.0")) + check(not dirExists(getHomeDir() / ".nimble" / "pkgs" / "PackageA-0.2.0")) check execCmdEx(path & " uninstall -y nimscript").exitCode == QuitSuccess From a0670e9620dacd8f5fb634f2ae10b56dc4d6186b Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 6 Nov 2016 19:58:37 +0100 Subject: [PATCH 061/424] finish migration to new compiler API --- src/nimblepkg/nimscriptsupport.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 4b5ce03..143b17b 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -269,6 +269,8 @@ proc cleanup() = compiler_options.command = "" when declared(resetAllModulesHard): resetAllModulesHard() + else: + resetSystemArtifacts() clearPasses() msgs.gErrorMax = 1 msgs.writeLnHook = nil From ee3ad4353e52d09678d4423d421a0ffe649ace60 Mon Sep 17 00:00:00 2001 From: Araq Date: Sun, 6 Nov 2016 23:06:37 +0100 Subject: [PATCH 062/424] fixes a 'break search loop' bug; got rid of most compiler warnings --- src/nimble.nim | 26 ++++++++++++++------------ src/nimblepkg/download.nim | 2 +- src/nimblepkg/nimscriptsupport.nim | 12 ++++++------ src/nimblepkg/options.nim | 5 ----- src/nimblepkg/packageinfo.nim | 4 ++-- src/nimblepkg/packageparser.nim | 7 +++---- src/nimblepkg/tools.nim | 2 +- src/nimblepkg/version.nim | 6 +++--- 8 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index fbe605f..729bbe2 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1,9 +1,11 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils, +import httpclient, parseopt, os, osproc, pegs, tables, parseutils, strtabs, json, algorithm, sets, uri +import strutils except toLower +from unicode import toLower from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, @@ -82,7 +84,7 @@ proc update(options: Options) = echo("Downloaded packages.json file is invalid, discarding.") continue copyFile(tempPath, - options.getNimbleDir() / "packages_$1.json" % list.name.toLower()) + options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii()) echo("Done.") break @@ -609,7 +611,6 @@ proc compile(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) let paths = processDeps(pkginfo, options) - let realDir = pkgInfo.getRealDir() var args = "" for path in paths: args.add("--path:\"" & path & "\" ") @@ -642,23 +643,24 @@ proc search(options: Options) = raise newException(NimbleError, "Please run nimble refresh.") let pkgList = getPackageList(options) var found = false - template onFound: stmt = + template onFound {.dirty.} = echoPackage(pkg) if options.queryVersions: echoPackageVersions(pkg) echo(" ") found = true - break + break forPkg for pkg in pkgList: - for word in options.action.search: - # Search by name. - if word.toLower() in pkg.name.toLower(): - onFound() - # Search by tag. - for tag in pkg.tags: - if word.toLower() in tag.toLower(): + block forPkg: + for word in options.action.search: + # Search by name. + if word.toLower() in pkg.name.toLower(): onFound() + # Search by tag. + for tag in pkg.tags: + if word.toLower() in tag.toLower(): + onFound() if not found: echo("No package found.") diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 5ce58b4..0e5059d 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -141,7 +141,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, ## method. ## ## Returns the version of the repository which has been downloaded. - template getLatestByTag(meth: stmt): stmt {.dirty, immediate.} = + template getLatestByTag(meth: untyped) {.dirty.} = echo("Found tags...") # Find latest version that fits our ``verRange``. var latest = findLatest(verRange, versions) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 143b17b..6e5eec2 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -94,10 +94,10 @@ proc setupVM(module: PSym; scriptName: string, proc listDirs(a: VmArgs, filter: set[PathComponent]) = let dir = getString(a, 0) - var result: seq[string] = @[] + var res: seq[string] = @[] for kind, path in walkDir(dir): - if kind in filter: result.add path - setResult(a, result) + if kind in filter: res.add path + setResult(a, res) template cbconf(name, body) {.dirty.} = result.registerCallback "stdlib.system." & astToStr(name), @@ -346,7 +346,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, elif cmpIgnoreStyle(backend, "javascript") == 0: result.backend = "js" else: - result.backend = backend.toLower() + result.backend = backend.toLowerAscii() # Grab all the global procs for i in thisModule.tab.data: @@ -395,8 +395,8 @@ proc execHook*(scriptName, actionName: string, before: bool, result.flags = newStringTable() compiler_options.command = internalCmd let hookName = - if before: actionName.toLower & "Before" - else: actionName.toLower & "After" + if before: actionName.toLowerAscii & "Before" + else: actionName.toLowerAscii & "After" echo("Attempting to execute hook ", hookName, " in ", scriptName) let thisModule = execScript(scriptName, result.flags, options) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index f1e9805..471be2b 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -293,11 +293,6 @@ proc parseCmdLine*(): Options = if result.action.typ == actionNil: writeHelp() - # TODO: Remove this after a couple of versions. - if getNimrodVersion() > newVersion("0.9.6"): - # Rename deprecated babel dir. - renameBabelToNimble(result) - proc getProxy*(options: Options): Proxy = ## Returns ``nil`` if no proxy is specified. var url = "" diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 4fe5cca..c4e5498 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -140,7 +140,7 @@ proc getPackage*(pkg: string, options: Options, for name, list in options.config.packageLists: echo("Searching in \"", name, "\" package list...") let packages = parseFile(options.getNimbleDir() / - "packages_" & name.toLower() & ".json") + "packages_" & name.toLowerAscii() & ".json") for p in packages: if normalize(p["name"].str) == normalize(pkg): resPkg = p.fromJson() @@ -152,7 +152,7 @@ proc getPackageList*(options: Options): seq[Package] = var namesAdded = initSet[string]() for name, list in options.config.packageLists: let packages = parseFile(options.getNimbleDir() / - "packages_" & name.toLower() & ".json") + "packages_" & name.toLowerAscii() & ".json") for p in packages: let pkg: Package = p.fromJson() if pkg.name notin namesAdded: diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index fbe8cfc..b0d1be7 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -7,8 +7,7 @@ import version, tools, common, nimscriptsupport, options, packageinfo ## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also ## depends on other procedures in ``packageinfo``. -when not declared(system.map): - from sequtils import map +from sequtils import apply type NimbleFile* = string @@ -105,7 +104,7 @@ proc multiSplit(s: string): seq[string] = ## done no entries are found in the list, the proc returns a sequence with ## the original string as the only entry. result = split(s, {char(0x0A), char(0x0D), ','}) - map(result, proc(x: var string) = x = x.strip()) + apply(result, proc(x: var string) = x = x.strip()) for i in countdown(result.len()-1, 0): if len(result[i]) < 1: result.del(i) @@ -154,7 +153,7 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = for i in ev.value.multiSplit: result.bin.add(i.addFileExt(ExeExt)) of "backend": - result.backend = ev.value.toLower() + result.backend = ev.value.toLowerAscii() case result.backend.normalize of "javascript": result.backend = "js" else: discard diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 65c6f8d..d7f6994 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -32,7 +32,7 @@ proc doCmdEx*(cmd: string): tuple[output: TaintedString, exitCode: int] = raise newException(NimbleError, "'" & bin & "' not in PATH.") return execCmdEx(cmd) -template cd*(dir: string, body: stmt) = +template cd*(dir: string, body: untyped) = ## Sets the current dir to ``dir``, executes ``body`` and restores the ## previous working dir. let lastDir = getCurrentDir() diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index cdc54ed..18fc4e7 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -40,11 +40,11 @@ proc newSpecial*(spe: string): Special = return Special(spe) proc `$`*(ver: Version): string {.borrow.} -proc hash*(ver: Version): THash {.borrow.} +proc hash*(ver: Version): Hash {.borrow.} proc `$`*(ver: Special): string {.borrow.} -proc hash*(ver: Special): THash {.borrow.} +proc hash*(ver: Special): Hash {.borrow.} proc `<`*(ver: Version, ver2: Version): bool = var sVer = string(ver).split('.') @@ -79,7 +79,7 @@ proc `==`*(ver: Version, ver2: Version): bool = return false proc `==`*(spe: Special, spe2: Special): bool = - return ($spe).toLower() == ($spe2).toLower() + return ($spe).toLowerAscii() == ($spe2).toLowerAscii() proc `<=`*(ver: Version, ver2: Version): bool = return (ver == ver2) or (ver < ver2) From 68b1b67733ffa403ca4a49ecf86643ce4cd6c3fa Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 9 Nov 2016 22:45:45 +0200 Subject: [PATCH 063/424] Fixed #274 --- nimble.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nimble.nimble b/nimble.nimble index 7b3917a..cf6b4d4 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,4 +1,4 @@ -when dirExists("src"): +when fileExists("src/nimblepkg/common.nim"): # In the git repository the Nimble sources are in a ``src`` directory. import src/nimblepkg/common else: From 8a1efc275e3e335af84e293bf7e4b842b3ca9520 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 11 Nov 2016 11:35:50 +0000 Subject: [PATCH 064/424] Fixes build (missing bootstrap.sh). Now builds against Nim 0.15.2. --- .travis.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b08a253..b334125 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,14 +5,16 @@ language: c install: - | - git clone https://github.com/nim-lang/Nim.git - cd Nim - sh bootstrap.sh + wget http://nim-lang.org/download/nim-0.15.2.tar.xz + tar -xf nim-0.15.2.tar.xz + cd nim-0.15.2 + sh build.sh cd .. + before_script: - set -e - set -x - - export PATH=`pwd`/Nim/bin:$PATH + - export PATH=`pwd`/nim-0.15.2/bin:$PATH script: - cd tests @@ -21,4 +23,4 @@ script: - ./src/nimble install -y notifications: - irc: "chat.freenode.net#nimbuild" \ No newline at end of file + irc: "chat.freenode.net#nimbuild" From 180653216cd971a9e40f59eddd6c193faaa412d0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 11 Nov 2016 11:40:40 +0000 Subject: [PATCH 065/424] Bump to v0.7.11. --- src/nimblepkg/common.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 417ff29..c0b2aac 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -37,4 +37,4 @@ when not defined(nimscript): backend*: string const - nimbleVersion* = "0.7.10" + nimbleVersion* = "0.7.11" From e6057a0084664680956777847af85c63ca79882f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 15 Nov 2016 21:30:34 +0100 Subject: [PATCH 066/424] Fixes travis build. Squashed commit of the following: commit 8811389f5071831b4fd55fa0c978767d722a4ed0 Author: Dominik Picheta Date: Tue Nov 15 21:24:03 2016 +0100 Cleans up troibobasbfdb commit 283e10b43517e1c03a277bdf0dd39ea017421d53 Author: Dominik Picheta Date: Tue Nov 15 21:12:03 2016 +0100 Too bad bash isn't style insensitive. commit 3cbf069230306c2977fe37f811c803b9a55b4ccf Author: Dominik Picheta Date: Tue Nov 15 21:09:27 2016 +0100 Attempt to add -lrt to linker flags. commit 0f3cbfabd9f9b2cf8c9ba9709175384d2f440ffd Author: Dominik Picheta Date: Tue Nov 15 20:58:52 2016 +0100 Print ldd version. commit badc29b79d6cc4f0770c483ac63079b0a3e9bd6c Author: Dominik Picheta Date: Tue Nov 15 20:50:35 2016 +0100 Attempt to debug. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b334125..97237da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ install: wget http://nim-lang.org/download/nim-0.15.2.tar.xz tar -xf nim-0.15.2.tar.xz cd nim-0.15.2 - sh build.sh + LDFLAGS=-lrt sh build.sh cd .. before_script: From 4fa4404df831f10e072e872580bca0a57f0a83b5 Mon Sep 17 00:00:00 2001 From: Chris Rohlfs Date: Mon, 21 Nov 2016 21:14:28 +1300 Subject: [PATCH 067/424] Fix install not working when spaces are in bin path --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index fbe605f..38d9d11 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -317,7 +317,7 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = createDir(outputDir) try: - doCmd(getNimBin() & " $# $# --noBabelPath $# $# \"$#\"" % + doCmd("\"" & getNimBin() & "\" $# $# --noBabelPath $# $# \"$#\"" % [pkgInfo.backend, releaseOpt, args, outputOpt, realDir / bin.changeFileExt("nim")]) except NimbleError: From bcbb85c5e438b2f62efd6fda0bb283b1feb6a60c Mon Sep 17 00:00:00 2001 From: Chris Rohlfs Date: Tue, 22 Nov 2016 01:41:40 +1300 Subject: [PATCH 068/424] Fix 'compile' not working when spaces are in bin path --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 38d9d11..2a9dfc9 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -628,7 +628,7 @@ proc compile(options: Options) = echo("Compiling ", bin, " (", pkgInfo.name, ") using ", backend, " backend...") - doCmd(getNimBin() & " $# --noBabelPath $# \"$#\"" % + doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# \"$#\"" % [backend, args, bin]) proc search(options: Options) = From b3f793ae0d42d57f888df83f2dbd6cc6d3bda1b8 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 24 Nov 2016 00:16:05 +0100 Subject: [PATCH 069/424] get rid of unnecessary cyclic module dependency --- src/nimblepkg/tools.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index d7f6994..10af1c6 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -3,7 +3,7 @@ # # Various miscellaneous utility functions reside here. import osproc, pegs, strutils, os, uri, sets, json, parseutils -import version, packageinfo, common +import version, common proc extractBin(cmd: string): string = if cmd[0] == '"': From 82868ea8183f7d70cb49cf9a21d7a1aaa917ca5d Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 24 Nov 2016 00:45:47 +0100 Subject: [PATCH 070/424] get rid of unnecessary cyclic module dependency --- src/nimblepkg/tools.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 65c6f8d..af2a0b2 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -3,7 +3,7 @@ # # Various miscellaneous utility functions reside here. import osproc, pegs, strutils, os, uri, sets, json, parseutils -import version, packageinfo, common +import version, common proc extractBin(cmd: string): string = if cmd[0] == '"': From de59767f43b483357c5484d9ec4768aa616376b5 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sat, 10 Dec 2016 11:39:32 +0200 Subject: [PATCH 071/424] Fixed installation from git dir --- nimble.nimble | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nimble.nimble b/nimble.nimble index cf6b4d4..78e6ba8 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,4 +1,7 @@ -when fileExists("src/nimblepkg/common.nim"): +import ospaths +template thisModuleFile: string = instantiationInfo(fullPaths = true).filename + +when fileExists(thisModuleFile.parentDir / "src/nimblepkg/common.nim"): # In the git repository the Nimble sources are in a ``src`` directory. import src/nimblepkg/common else: From 934c047068bc5f02cd9a424eafa2fbb9c0faa8a5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 13 Dec 2016 22:45:33 +0100 Subject: [PATCH 072/424] Remove mentions of the old .nimble format from readme. Fixes #262. --- readme.markdown | 67 ++++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/readme.markdown b/readme.markdown index 12c6cd3..a43d0b3 100644 --- a/readme.markdown +++ b/readme.markdown @@ -336,11 +336,11 @@ packages is stored in a JSON file which is freely accessible in the [nim-lang/packages repository](https://github.com/nim-lang/packages). This JSON file provides nimble with the required Git URL to clone the package and install it. Installation and build instructions are contained inside a -ini-style file with the ``.nimble`` file extension. The nimble file shares the +file with the ``.nimble`` file extension. The nimble file shares the package's name, i.e. a package named "foobar" should have a corresponding ``foobar.nimble`` file. -These files specify information about the package including its name, author, +These files specify information about the package including its the author, license, dependencies and more. Without one Nimble is not able to install a package. @@ -348,49 +348,9 @@ A .nimble file can be created easily using Nimble's ``init`` command. This command will ask you a bunch of questions about your package, then generate a .nimble file for you. -**Note:** As of version 0.7.0, the ``init`` command generates .nimble files -using the new NimScript format. Take a look at the next section for more -information. - A bare minimum .nimble file follows: ```ini -[Package] -name = "ProjectName" -version = "0.1.0" -author = "Your Name" -description = "Example .nimble file." -license = "MIT" - -[Deps] -Requires: "nim >= 0.10.0" -``` - -You may omit the dependencies entirely, but specifying the lowest version -of the Nim compiler required is recommended. - -Nimble currently supports installation of packages from a local directory, a -git repository and a mercurial repository. The .nimble file must be present in -the root of the directory or repository being installed. - -### The new NimScript format - -**Warning:** This feature is still very experimental. You are encouraged to -try it, but be aware that it may change significantly in the future or -may even be removed completely! - -Version 0.7.0 of Nimble introduces support for evaluating .nimble files -as Nim code. This means that you can define metadata about your package -using the Nim programming language. - -Because of Nim's flexibility the definitions remain declarative. With the added -ability of using the Nim language to enrich your package specification. -For example, you can define dependencies for specific platforms using Nim's -``when`` statement. - -The ini example above looks like this in the NimScript format: - -```nim # Package version = "0.1.0" @@ -403,7 +363,28 @@ license = "MIT" requires "nim >= 0.10.0" ``` -The format is indeed very similar to the ini format. Another great feature +You may omit the dependencies entirely, but specifying the lowest version +of the Nim compiler required is recommended. + +You can also specify multiple dependencies like so: + +``` +# Deps + +requires "nim >= 0.10.0", "foobar >= 0.1.0" +requires "fizzbuzz >= 1.0" + +Nimble currently supports installation of packages from a local directory, a +git repository and a mercurial repository. The .nimble file must be present in +the root of the directory or repository being installed. + +The .nimble file is very flexible because it is interpreted using NimScript. +Because of Nim's flexibility the definitions remain declarative. With the added +ability of using the Nim language to enrich your package specification. +For example, you can define dependencies for specific platforms using Nim's +``when`` statement. + +Another great feature is the ability to define custom Nimble package-specific commands. These are defined in the .nimble files of course. From d42a07e0f7eb1264df5f680b7130a953349cf4a7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 15 Dec 2016 23:31:45 +0100 Subject: [PATCH 073/424] Fixes nimbledata.json being read from default nimbleDir. --- src/nimblepkg/options.nim | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 471be2b..507ed0c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -263,23 +263,24 @@ proc initOptions*(): Options = result.action.typ = actionNil result.pkgInfoCache = newTable[string, PackageInfo]() -proc parseMisc(): Options = - result = initOptions() - result.config = parseConfig() - +proc parseMisc(options: var Options) = # Load nimbledata.json - let nimbledataFilename = result.getNimbleDir() / "nimbledata.json" + let nimbledataFilename = options.getNimbleDir() / "nimbledata.json" + if fileExists(nimbledataFilename): try: - result.nimbleData = parseFile(nimbledataFilename) + options.nimbleData = parseFile(nimbledataFilename) except: raise newException(NimbleError, "Couldn't parse nimbledata.json file " & "located at " & nimbledataFilename) else: - result.nimbleData = %{"reverseDeps": newJObject()} + options.nimbleData = %{"reverseDeps": newJObject()} proc parseCmdLine*(): Options = - result = parseMisc() + result = initOptions() + result.config = parseConfig() + + # Parse command line params. for kind, key, val in getOpt(): case kind of cmdArgument: @@ -290,6 +291,10 @@ proc parseCmdLine*(): Options = of cmdLongOption, cmdShortOption: parseFlag(key, val, result) of cmdEnd: assert(false) # cannot happen + + # Parse other things, for example the nimbledata.json file. + parseMisc(result) + if result.action.typ == actionNil: writeHelp() From a7913b5d23bde193e06e122d0139026b13f8ee08 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 15 Dec 2016 23:35:09 +0100 Subject: [PATCH 074/424] Improves tester. --- nimble.nimble | 2 +- tests/tester.nim | 109 +++++++++++++++++++++++++++-------------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index cf6b4d4..be3fb01 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -19,6 +19,6 @@ srcDir = "src" requires "nim >= 0.13.0", "compiler#head" -task tests, "Run the Nimble tester!": +task test, "Run the Nimble tester!": withDir "tests": exec "nim c -r tester" diff --git a/tests/tester.nim b/tests/tester.nim index 079c539..64b21bf 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -2,8 +2,15 @@ # BSD License. Look at license.txt for more info. import osproc, streams, unittest, strutils, os, sequtils, future +var rootDir = getCurrentDir().parentDir() +var nimblePath = rootDir / "src" / "nimble" & ExeExt +var installDir = rootDir / "tests" / "nimbleDir" const path = "../src/nimble" +# Clear nimble dir. +removeDir(installDir) +createDir(installDir) + test "can compile nimble": check execCmdEx("nim c " & path).exitCode == QuitSuccess @@ -15,6 +22,14 @@ template cd*(dir: string, body: untyped) = body setCurrentDir(lastDir) +proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = + var quotedArgs = @args + quotedArgs.insert(nimblePath) + quotedArgs.add("--nimbleDir:" & installDir) + quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) + + result = execCmdEx(quotedArgs.join(" ")) + proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) @@ -23,33 +38,34 @@ proc inLines(lines: seq[string], line: string): bool = if line.normalize in i.normalize: return true test "issue 129 (installing commit hash)": - check execCmdEx(path & " install -y \"https://github.com/nimble-test/packagea.git@#1f9cb289c89\""). - exitCode == QuitSuccess + let arguments = @["install", "-y", + "https://github.com/nimble-test/packagea.git@#1f9cb289c89"] + check execNimble(arguments).exitCode == QuitSuccess test "issue 113 (uninstallation problems)": cd "issue113/c": - check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess + check execNimble(["install", "-y"]).exitCode == QuitSuccess cd "issue113/b": - check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess + check execNimble(["install", "-y"]).exitCode == QuitSuccess cd "issue113/a": - check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess + check execNimble(["install", "-y"]).exitCode == QuitSuccess # Try to remove c. - let (output, exitCode) = execCmdEx(path & " remove -y c") + let (output, exitCode) = execNimble(["remove", "-y", "c"]) let lines = output.strip.splitLines() check exitCode != QuitSuccess check inLines(lines, "cannot uninstall c (0.1.0) because b (0.1.0) depends on it") - check execCmdEx(path & " remove -y a").exitCode == QuitSuccess - check execCmdEx(path & " remove -y b").exitCode == QuitSuccess + check execNimble(["remove", "-y", "a"]).exitCode == QuitSuccess + check execNimble(["remove", "-y", "b"]).exitCode == QuitSuccess cd "issue113/buildfail": - check execCmdEx("../../" & path & " install -y").exitCode != QuitSuccess + check execNimble(["install", "-y"]).exitCode != QuitSuccess - check execCmdEx(path & " remove -y c").exitCode == QuitSuccess + check execNimble(["remove", "-y", "c"]).exitCode == QuitSuccess test "can refresh with default urls": - check execCmdEx(path & " refresh").exitCode == QuitSuccess + check execNimble(["refresh"]).exitCode == QuitSuccess proc safeMoveFile(src, dest: string) = try: @@ -77,7 +93,7 @@ test "can refresh with custom urls": url = "http://nim-lang.org/nimble/packages.json" """.unindent) - let (output, exitCode) = execCmdEx(path & " refresh") + let (output, exitCode) = execNimble(["refresh"]) let lines = output.strip.splitLines() check exitCode == QuitSuccess check inLines(lines, "reading from config file") @@ -93,38 +109,38 @@ test "can refresh with custom urls": test "can install nimscript package": cd "nimscript": - check execCmdEx("../" & path & " install -y").exitCode == QuitSuccess + check execNimble(["install", "-y"]).exitCode == QuitSuccess test "can execute nimscript tasks": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " test") + let (output, exitCode) = execNimble("test") let lines = output.strip.splitLines() check exitCode == QuitSuccess check lines[^1] == "10" test "can use nimscript's setCommand": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " cTest") + let (output, exitCode) = execNimble("cTest") let lines = output.strip.splitLines() check exitCode == QuitSuccess check "Hint: operation successful".normalize in lines[^1].normalize test "can use nimscript's setCommand with flags": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " cr") + let (output, exitCode) = execNimble("cr") let lines = output.strip.splitLines() check exitCode == QuitSuccess check "Hello World".normalize in lines[^1].normalize test "can list nimscript tasks": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " tasks") + let (output, exitCode) = execNimble("tasks") check "test test description".normalize in output.normalize check exitCode == QuitSuccess test "can use pre/post hooks": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " hooks") + let (output, exitCode) = execNimble("hooks") let lines = output.strip.splitLines() check exitCode == QuitSuccess check inLines(lines, "First") @@ -133,20 +149,19 @@ test "can use pre/post hooks": test "pre hook can prevent action": cd "nimscript": - let (output, exitCode) = execCmdEx("../" & path & " hooks2") + let (output, exitCode) = execNimble("hooks2") let lines = output.strip.splitLines() check exitCode == QuitSuccess check(not inLines(lines, "Shouldn't happen")) check inLines(lines, "Hook prevented further execution") test "can install packagebin2": - check execCmdEx(path & - " install -y https://github.com/nimble-test/packagebin2.git").exitCode == - QuitSuccess + let args = ["install", "-y", "https://github.com/nimble-test/packagebin2.git"] + check execNimble(args).exitCode == QuitSuccess test "can reject same version dependencies": - let (outp, exitCode) = execCmdEx(path & - " install -y https://github.com/nimble-test/packagebin.git") + let (outp, exitCode) = execNimble( + "install", "-y", "https://github.com/nimble-test/packagebin.git") # We look at the error output here to avoid out-of-order problems caused by # stderr output being generated and flushed without first flushing stdout let ls = outp.strip.splitLines() @@ -155,83 +170,83 @@ test "can reject same version dependencies": "dependency on PackageA 0.2.0 and PackageA 0.5.0 [NimbleError]" test "can update": - check execCmdEx(path & " update").exitCode == QuitSuccess + check execNimble("update").exitCode == QuitSuccess test "issue #27": # Install b cd "issue27/b": - check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess + check execNimble("install", "-y").exitCode == QuitSuccess # Install a cd "issue27/a": - check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess + check execNimble("install", "-y").exitCode == QuitSuccess cd "issue27": - check execCmdEx("../" & path & " install -y").exitCode == QuitSuccess + check execNimble("install", "-y").exitCode == QuitSuccess test "issue #126": cd "issue126/a": - let (output, exitCode) = execCmdEx("../../" & path & " install -y") + let (output, exitCode) = execNimble("install", "-y") let lines = output.strip.splitLines() check exitCode != QuitSuccess # TODO check inLines(lines, "issue-126 is an invalid package name: cannot contain '-'") cd "issue126/b": - let (output1, exitCode1) = execCmdEx("../../" & path & " install -y") + let (output1, exitCode1) = execNimble("install", "-y") let lines1 = output1.strip.splitLines() check exitCode1 == QuitSuccess check inLines(lines1, "The .nimble file name must match name specified inside") test "issue #108": cd "issue108": - let (output, exitCode) = execCmdEx("../" & path & " build") + let (output, exitCode) = execNimble("build") let lines = output.strip.splitLines() check exitCode != QuitSuccess check "Nothing to build" in lines[^1] test "issue #206": cd "issue206": - var (output, exitCode) = execCmdEx("../" & path & " install -y") + var (output, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess - (output, exitCode) = execCmdEx("../" & path & " install -y") + (output, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess test "can list": - check execCmdEx(path & " list").exitCode == QuitSuccess + check execNimble("list").exitCode == QuitSuccess - check execCmdEx(path & " list -i").exitCode == QuitSuccess + check execNimble("list", "-i").exitCode == QuitSuccess test "can uninstall": block: - let (outp, exitCode) = execCmdEx(path & " uninstall -y issue27b") - # let ls = outp.processOutput() + let (outp, exitCode) = execNimble("uninstall", "-y", "issue27b") + let ls = outp.strip.splitLines() check exitCode != QuitSuccess check ls[ls.len-1] == " Cannot uninstall issue27b (0.1.0) because " & "issue27a (0.1.0) depends on it [NimbleError]" - check execCmdEx(path & " uninstall -y issue27").exitCode == QuitSuccess - check execCmdEx(path & " uninstall -y issue27a").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "issue27").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "issue27a").exitCode == QuitSuccess # Remove Package* - check execCmdEx(path & " uninstall -y PackageA@0.5").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "PackageA@0.5").exitCode == QuitSuccess - let (outp, exitCode) = execCmdEx(path & " uninstall -y PackageA") + let (outp, exitCode) = execNimble("uninstall", "-y", "PackageA") check exitCode != QuitSuccess let ls = outp.processOutput() check ls[ls.len-2].startsWith(" Cannot uninstall PackageA ") check ls[ls.len-1].startsWith(" Cannot uninstall PackageA ") - check execCmdEx(path & " uninstall -y PackageBin2").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "PackageBin2").exitCode == QuitSuccess # Case insensitive - check execCmdEx(path & " uninstall -y packagea").exitCode == QuitSuccess - check execCmdEx(path & " uninstall -y PackageA").exitCode != QuitSuccess + check execNimble("uninstall", "-y", "packagea").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "PackageA").exitCode != QuitSuccess # Remove the rest of the installed packages. - check execCmdEx(path & " uninstall -y PackageB").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "PackageB").exitCode == QuitSuccess - check execCmdEx(path & " uninstall -y PackageA@0.2 issue27b").exitCode == + check execNimble("uninstall", "-y", "PackageA@0.2", "issue27b").exitCode == QuitSuccess check(not dirExists(getHomeDir() / ".nimble" / "pkgs" / "PackageA-0.2.0")) - check execCmdEx(path & " uninstall -y nimscript").exitCode == QuitSuccess + check execNimble("uninstall", "-y", "nimscript").exitCode == QuitSuccess From 3c22ffd848420b94f4a905dc714635578b823277 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 19 Dec 2016 21:42:02 +0100 Subject: [PATCH 075/424] Implements a nimblepkg/cli module which formats output messages. --- src/nimblepkg/cli.nim | 92 ++++++++++++++++++++++++++++++++++++++++ src/nimblepkg/common.nim | 1 + 2 files changed, 93 insertions(+) create mode 100644 src/nimblepkg/cli.nim diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim new file mode 100644 index 0000000..f4ea604 --- /dev/null +++ b/src/nimblepkg/cli.nim @@ -0,0 +1,92 @@ +# Copyright (C) Dominik Picheta. All rights reserved. +# BSD License. Look at license.txt for more info. +# +# Rough rules/philosophy for the messages that Nimble displays are the following: +# - Green is only shown when the requested operation is successful. +# - Blue can be used to emphasise certain keywords, for example actions such +# as "Downloading" or "Reading". +# - Red is used when the requested operation fails with an error. +# - Yellow is used for warnings. +# +# - Dim for LowPriority. +# - Bright for HighPriority. +# - Normal for MediumPriority. + +import logging, terminal, sets, strutils + +type + CLI* = ref object + warnings: HashSet[(string, string)] + + Priority* = enum + HighPriority, MediumPriority, LowPriority + + DisplayType* = enum + Error, Warning, Message + +const + longestCategory = len("Downloading") + foregrounds: array[Error .. Message, ForegroundColor] = [fgRed, fgYellow, fgCyan] + styles: array[HighPriority .. LowPriority, set[Style]] = [{styleBright}, {}, {styleDim}] + +proc newCLI(): CLI = + result = CLI( + warnings: initSet[(string, string)]() + ) + +var globalCLI = newCLI() + + +proc calculateCategoryOffset(category: string): int = + assert category.len <= longestCategory + return longestCategory - category.len + +proc displayLine(category, line: string, displayType: DisplayType, + priority: Priority) = + # Calculate how much the `category` must be offset to align along a center + # line. + let offset = calculateCategoryOffset(category) + # Display the category. + setForegroundColor(stdout, foregrounds[displayType]) + writeStyled("$1$2 " % [repeatChar(offset), category], styles[priority]) + resetAttributes() + + # Display the message. + echo(line) + +proc display*(category, msg: string, displayType = Message, + priority = MediumPriority) = + # Multiple warnings containing the same messages should not be shown. + let warningPair = (category, msg) + if displayType == Warning: + if warningPair in globalCLI.warnings: + return + else: + globalCLI.warnings.incl(warningPair) + + # Display each line in the message. + var i = 0 + for line in msg.splitLines(): + if len(line) == 0: continue + displayLine(if i == 0: category else: "...", line, displayType, priority) + i.inc + +when isMainModule: + display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini", + priority = LowPriority) + + display("Reading", "official package list", + priority = LowPriority) + + display("Downloading", "daemonize v0.0.2 using Git", + priority = HighPriority) + + display("Warning", "dashes in package names will be deprecated", Warning, + priority = HighPriority) + + display("Error", """Unable to read package info for /Users/dom/.nimble/pkgs/nimble-0.7.11 +Reading as ini file failed with: + Invalid section: . +Evaluating as NimScript file failed with: + Users/dom/.nimble/pkgs/nimble-0.7.11/nimble.nimble(3, 23) Error: cannot open 'src/nimblepkg/common'. +""", Error, HighPriority) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index c0b2aac..eab71a1 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -1,3 +1,4 @@ +# Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. # # Various miscellaneous common types reside here, to avoid problems with From abb9d79ea407ba2f0c381c88f5c25bdc0dc712f7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 19 Dec 2016 22:28:19 +0100 Subject: [PATCH 076/424] Parse command line args first so that `-v` doesn't read config. --- src/nimble.nim | 10 ++-------- src/nimblepkg/options.nim | 35 ++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index a4d3bdb..e96a57a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -10,7 +10,8 @@ from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, - nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser + nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser, + nimblepkg/cli import nimblepkg/nimscriptsupport @@ -32,11 +33,6 @@ else: proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetVersionExA".} -proc writeVersion() = - echo("nimble v$# compiled at $# $#" % - [nimbleVersion, CompileDate, CompileTime]) - quit(QuitSuccess) - proc promptCustom(question, default: string): string = if default == "": stdout.write(question, ": ") @@ -961,8 +957,6 @@ proc doAction(options: Options) = dump(options) of actionTasks: listTasks(options) - of actionVersion: - writeVersion() of actionNil: assert false of actionCustom: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 507ed0c..4b1ac61 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -12,6 +12,7 @@ type depsOnly*: bool queryVersions*: bool queryInstalled*: bool + nimbleDir*: string action*: Action config*: Config nimbleData*: JsonNode ## Nimbledata.json @@ -21,12 +22,11 @@ type actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionCustom, actionTasks, actionVersion + actionCustom, actionTasks Action* = object case typ*: ActionType - of actionNil, actionList, actionBuild, actionPublish, actionTasks, - actionVersion: nil + of actionNil, actionList, actionBuild, actionPublish, actionTasks: nil of actionRefresh: optionalURL*: string # Overrides default package list. of actionInstall, actionPath, actionUninstall: @@ -93,6 +93,11 @@ proc writeHelp*() = echo(help) quit(QuitSuccess) +proc writeVersion() = + echo("nimble v$# compiled at $# $#" % + [nimbleVersion, CompileDate, CompileTime]) + quit(QuitSuccess) + proc parseActionType*(action: string): ActionType = case action.normalize() of "install", "path": @@ -153,7 +158,7 @@ proc initAction*(options: var Options, key: string) = options.action.arguments = @[] options.action.flags = newStringTable() of actionBuild, actionPublish, actionList, actionTasks, - actionNil, actionVersion: discard + actionNil: discard proc prompt*(options: Options, question: string): bool = ## Asks an interactive question and returns the result. @@ -191,7 +196,13 @@ proc renameBabelToNimble(options: Options) {.deprecated.} = removeFile(nimbleDir / "babeldata.json") proc getNimbleDir*(options: Options): string = - expandTilde(options.config.nimbleDir) + result = + if options.nimbleDir.len == 0: + options.config.nimbleDir + else: + options.nimbleDir + + return expandTilde(result) proc getPkgsDir*(options: Options): string = options.getNimbleDir() / "pkgs" @@ -247,13 +258,11 @@ proc parseFlag*(flag, val: string, result: var Options) = # TODO: These should not be global. case flag.normalize() of "help", "h": writeHelp() - of "version", "v": - assert result.action.typ == actionNil - result.action.typ = actionVersion + of "version", "v": writeVersion() of "accept", "y": result.forcePrompts = forcePromptYes of "reject", "n": result.forcePrompts = forcePromptNo of "ver": result.queryVersions = true - of "nimbledir": result.config.nimbleDir = val # overrides option from file + of "nimbledir": result.nimbleDir = val of "installed", "i": result.queryInstalled = true of "depsonly", "d": result.depsOnly = true else: @@ -262,6 +271,7 @@ proc parseFlag*(flag, val: string, result: var Options) = proc initOptions*(): Options = result.action.typ = actionNil result.pkgInfoCache = newTable[string, PackageInfo]() + result.nimbleDir = "" proc parseMisc(options: var Options) = # Load nimbledata.json @@ -278,9 +288,9 @@ proc parseMisc(options: var Options) = proc parseCmdLine*(): Options = result = initOptions() - result.config = parseConfig() - # Parse command line params. + # Parse command line params first. A simple `--version` shouldn't require + # a config to be parsed. for kind, key, val in getOpt(): case kind of cmdArgument: @@ -292,6 +302,9 @@ proc parseCmdLine*(): Options = parseFlag(key, val, result) of cmdEnd: assert(false) # cannot happen + # Parse config. + result.config = parseConfig() + # Parse other things, for example the nimbledata.json file. parseMisc(result) From dcbbb8b62e7a9267a0c39cf5a481a9cb41127def Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 19 Dec 2016 23:35:27 +0100 Subject: [PATCH 077/424] Switch 'refresh' command to new CLI module. --- src/nimble.nim | 18 ++++++++++++------ src/nimblepkg/cli.nim | 8 +++++--- src/nimblepkg/config.nim | 8 +++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e96a57a..2efe5fa 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1,6 +1,8 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. +import system except TResult + import httpclient, parseopt, os, osproc, pegs, tables, parseutils, strtabs, json, algorithm, sets, uri @@ -56,10 +58,10 @@ proc update(options: Options) = "" proc downloadList(list: PackageList, options: Options) = - echo("Downloading \"", list.name, "\" package list") + display("Downloading", list.name & " package list", priority = HighPriority) for i in 0 .. 0: maskedUrl.password = "***" - echo("Using proxy ", maskedUrl) + display("Connecting", "to proxy at " & $maskedUrl, + priority = LowPriority) try: downloadFile(url, tempPath, proxy = getProxy(options)) except: if i == Date: Mon, 19 Dec 2016 23:49:41 +0100 Subject: [PATCH 078/424] Implement message suppression. --- src/nimble.nim | 8 +++++++- src/nimblepkg/cli.nim | 26 ++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2efe5fa..1efe03b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -996,12 +996,18 @@ proc doAction(options: Options) = discard execHook(options, false) when isMainModule: + let error = "" when defined(release): try: parseCmdLine().doAction() except NimbleError: - quit("FAILURE: " & getCurrentExceptionMsg()) + error = getCurrentExceptionMsg() finally: removeDir(getNimbleTempDir()) else: parseCmdLine().doAction() + + displayTip() + if error.len > 0: + display("Error", error, Error, HighPriority) + quit(1) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 4688b77..bf95462 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -16,10 +16,12 @@ import logging, terminal, sets, strutils type CLI* = ref object + level: Priority warnings: HashSet[(string, string)] + suppressionCount: int ## Amount of messages which were not shown. Priority* = enum - HighPriority, MediumPriority, LowPriority + LowPriority, MediumPriority, HighPriority DisplayType* = enum Error, Warning, Message, Success @@ -28,12 +30,14 @@ const longestCategory = len("Downloading") foregrounds: array[Error .. Success, ForegroundColor] = [fgRed, fgYellow, fgCyan, fgGreen] - styles: array[HighPriority .. LowPriority, set[Style]] = - [{styleBright}, {}, {styleDim}] + styles: array[LowPriority .. HighPriority, set[Style]] = + [{styleDim}, {}, {styleBright}] proc newCLI(): CLI = result = CLI( - warnings: initSet[(string, string)]() + level: HighPriority, + warnings: initSet[(string, string)](), + suppressionCount: 0 ) var globalCLI = newCLI() @@ -66,6 +70,11 @@ proc display*(category, msg: string, displayType = Message, else: globalCLI.warnings.incl(warningPair) + # Suppress this message if its priority isn't high enough. + if priority < globalCLI.level: + globalCLI.suppressionCount.inc + return + # Display each line in the message. var i = 0 for line in msg.splitLines(): @@ -73,6 +82,15 @@ proc display*(category, msg: string, displayType = Message, displayLine(if i == 0: category else: "...", line, displayType, priority) i.inc +proc displayTip*() = + ## Called just before Nimble exits. Shows some tips for the user, for example + ## the amount of messages that were suppressed and how to show them. + if globalCLI.suppressionCount > 0: + let msg = "$1 messages have been suppressed, use --verbose to show them." % + $globalCLI.suppressionCount + display("Tip", msg, Warning, HighPriority) + + when isMainModule: display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini", priority = LowPriority) From 2dab010c231f35e6bb4626e4b291ba8962494304 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 00:01:39 +0100 Subject: [PATCH 079/424] Implement --verbosity switch. --- src/nimblepkg/cli.nim | 2 ++ src/nimblepkg/options.nim | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index bf95462..caa5236 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -90,6 +90,8 @@ proc displayTip*() = $globalCLI.suppressionCount display("Tip", msg, Warning, HighPriority) +proc setVerbosity*(level: Priority) = + globalCLI.level = level when isMainModule: display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini", diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 4b1ac61..97efee9 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -4,7 +4,7 @@ import json, strutils, os, parseopt, strtabs, uri, tables from httpclient import Proxy, newProxy -import config, version, tools, common +import config, version, tools, common, cli type Options* = object @@ -13,6 +13,7 @@ type queryVersions*: bool queryInstalled*: bool nimbleDir*: string + verbosity*: cli.Priority action*: Action config*: Config nimbleData*: JsonNode ## Nimbledata.json @@ -84,6 +85,7 @@ Options: information when searching or listing packages --nimbleDir dirname Set the Nimble directory. -d --depsOnly Install only dependencies. + --verbose Show all output. For more information read the Github readme: https://github.com/nim-lang/nimble#readme @@ -265,6 +267,7 @@ proc parseFlag*(flag, val: string, result: var Options) = of "nimbledir": result.nimbleDir = val of "installed", "i": result.queryInstalled = true of "depsonly", "d": result.depsOnly = true + of "verbose": result.verbosity = LowPriority else: raise newException(NimbleError, "Unknown option: --" & flag) @@ -272,6 +275,7 @@ proc initOptions*(): Options = result.action.typ = actionNil result.pkgInfoCache = newTable[string, PackageInfo]() result.nimbleDir = "" + result.verbosity = HighPriority proc parseMisc(options: var Options) = # Load nimbledata.json @@ -302,6 +306,9 @@ proc parseCmdLine*(): Options = parseFlag(key, val, result) of cmdEnd: assert(false) # cannot happen + # Set verbosity level. + setVerbosity(result.verbosity) + # Parse config. result.config = parseConfig() From ac352aa6b2ec3a38e1075b922d2bd735ceb544a1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 20:49:39 +0100 Subject: [PATCH 080/424] Rename 'update' proc to 'refresh'. --- src/nimble.nim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 1efe03b..293d846 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -47,7 +47,7 @@ proc promptCustom(question, default: string): string = if user == "": return default else: return user -proc update(options: Options) = +proc refresh(options: Options) = ## Downloads the package list from the specified URL. ## ## If the download is not successful, an exception is raised. @@ -547,15 +547,15 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options, if getPackage(pv.name, options, pkg): return (pkg.downloadMethod.getDownloadMethod(), pkg.url) else: - # If package is not found give the user a chance to update + # If package is not found give the user a chance to refresh # package.json if doPrompt and options.prompt(pv.name & " not found in any local packages.json, " & "check internet for updated packages?"): - update(options) + refresh(options) - # Once we've updated, try again, but don't prompt if not found - # (as we've already updated and a failure means it really + # Once we've refreshed, try again, but don't prompt if not found + # (as we've already refreshed and a failure means it really # isn't there) return getDownloadInfo(pv, options, false) else: @@ -572,7 +572,7 @@ proc install(packages: seq[PkgTuple], if doPrompt and options.prompt("No local packages.json found, download it from " & "internet?"): - update(options) + refresh(options) else: quit("Please run nimble refresh.", QuitFailure) @@ -936,7 +936,7 @@ proc doAction(options: Options) = return case options.action.typ of actionRefresh: - update(options) + refresh(options) of actionInstall: let (_, pkgInfo) = install(options.action.packages, options) if options.action.packages.len == 0: From effbfbc6a1a2d425634272a8c7378472277dcb6d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 20:58:57 +0100 Subject: [PATCH 081/424] Refresh command now supports a package list name as argument. --- src/nimble.nim | 12 ++++++++++-- src/nimblepkg/config.nim | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 293d846..30ae15d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -90,8 +90,16 @@ proc refresh(options: Options) = display("Success", "Package list downloaded.", Success, HighPriority) break - if parameter.isUrl: - downloadList(PackageList(name: "commandline", urls: @[parameter]), options) + if parameter.len > 0: + if parameter.isUrl: + let cmdLine = PackageList(name: "commandline", urls: @[parameter]) + downloadList(cmdLine, options) + else: + if parameter notin options.config.packageLists: + let msg = "Package list with the specified name not found." + raise newException(NimbleError, msg) + + downloadList(options.config.packageLists[parameter], options) else: # Try each package list in config for name, list in options.config.packageLists: diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 3daf952..8b42f5e 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -8,7 +8,7 @@ type Config* = object nimbleDir*: string chcp*: bool # Whether to change the code page in .cmd files on Win. - packageLists*: Table[string, PackageList] ## URLs to packages.json files + packageLists*: Table[string, PackageList] ## Names -> packages.json files cloneUsingHttps*: bool # Whether to replace git:// for https:// httpProxy*: Uri # Proxy for package list downloads. From 25a53eb4dc7a6b11a856159fb7e32e9a5977e802 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 21:14:00 +0100 Subject: [PATCH 082/424] Raise an error if 'refresh' does not download anything successfully. --- src/nimble.nim | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 30ae15d..73a5de7 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -59,6 +59,8 @@ proc refresh(options: Options) = proc downloadList(list: PackageList, options: Options) = display("Downloading", list.name & " package list", priority = HighPriority) + + var lastError = "" for i in 0 .. 0: if parameter.isUrl: let cmdLine = PackageList(name: "commandline", urls: @[parameter]) @@ -1004,7 +1010,7 @@ proc doAction(options: Options) = discard execHook(options, false) when isMainModule: - let error = "" + var error = "" when defined(release): try: parseCmdLine().doAction() From dcc36814c27e4cd68ee452b5fcd4018b144c2585 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 21:26:50 +0100 Subject: [PATCH 083/424] Fixed tests. --- tests/tester.nim | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 64b21bf..16cbe03 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -93,15 +93,15 @@ test "can refresh with custom urls": url = "http://nim-lang.org/nimble/packages.json" """.unindent) - let (output, exitCode) = execNimble(["refresh"]) + let (output, exitCode) = execNimble(["refresh", "--verbose"]) let lines = output.strip.splitLines() check exitCode == QuitSuccess - check inLines(lines, "reading from config file") - check inLines(lines, "downloading \"official\" package list") - check inLines(lines, "trying http://google.com") + check inLines(lines, "config file at") + check inLines(lines, "official package list") + check inLines(lines, "http://google.com") check inLines(lines, "packages.json file is invalid") check inLines(lines, "404 not found") - check inLines(lines, "done") + check inLines(lines, "Package list downloaded.") # Restore config if fileExists(configBakFile): @@ -113,21 +113,21 @@ test "can install nimscript package": test "can execute nimscript tasks": cd "nimscript": - let (output, exitCode) = execNimble("test") + let (output, exitCode) = execNimble("--verbose", "test") let lines = output.strip.splitLines() check exitCode == QuitSuccess check lines[^1] == "10" test "can use nimscript's setCommand": cd "nimscript": - let (output, exitCode) = execNimble("cTest") + let (output, exitCode) = execNimble("--verbose", "cTest") let lines = output.strip.splitLines() check exitCode == QuitSuccess check "Hint: operation successful".normalize in lines[^1].normalize test "can use nimscript's setCommand with flags": cd "nimscript": - let (output, exitCode) = execNimble("cr") + let (output, exitCode) = execNimble("--verbose", "cr") let lines = output.strip.splitLines() check exitCode == QuitSuccess check "Hello World".normalize in lines[^1].normalize From 3791f8a09a1807a95874942fde1b0dbf3a71e2d8 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 22:46:07 +0100 Subject: [PATCH 084/424] Switch to cli in processDeps. --- src/nimble.nim | 14 ++++++++++---- src/nimblepkg/tools.nim | 6 +++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 73a5de7..77133e5 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -274,24 +274,30 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = ## Returns the list of paths to pass to the compiler during build phase. result = @[] assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires") + display("Verifying", + "dependencies for $1 v$2" % [pkginfo.name, pkginfo.version], + priority = HighPriority) + let pkglist = getInstalledPkgs(options.getPkgsDir(), options) var reverseDeps: seq[tuple[name, version: string]] = @[] for dep in pkginfo.requires: if dep.name == "nimrod" or dep.name == "nim": let nimVer = getNimrodVersion() if not withinRange(nimVer, dep.ver): - quit("Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")") + let msg = "Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")" + raise newException(NimbleError, msg) else: - echo("Looking for ", dep.name, " (", $dep.ver, ")...") + let depDesc = "$1 ($2)" % [dep.name, $dep.ver] + display("Checking", "for $1" % depDesc, priority = MediumPriority) var pkg: PackageInfo if not findPkg(pkglist, dep, pkg): - echo("None found, installing...") + display("Installing", depDesc, priority = HighPriority) let (paths, installedPkg) = install(@[(dep.name, dep.ver)], options) result.add(paths) pkg = installedPkg # For addRevDep else: - echo("Dependency already satisfied.") + display("Info", "Dependency already satisfied", priority = HighPriority) result.add(pkg.mypath.splitFile.dir) # Process the dependencies of this dependency. result.add(processDeps(pkg, options)) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 10af1c6..f26c5e0 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -3,7 +3,7 @@ # # Various miscellaneous utility functions reside here. import osproc, pegs, strutils, os, uri, sets, json, parseutils -import version, common +import version, common, cli proc extractBin(cmd: string): string = if cmd[0] == '"': @@ -75,14 +75,14 @@ proc changeRoot*(origRoot, newRoot, path: string): string = proc copyFileD*(fro, to: string): string = ## Returns the destination (``to``). - echo(fro, " -> ", to) + display("Copying", "file $# to $#" % [fro, to], priority = LowPriority) copyFileWithPermissions(fro, to) result = to proc copyDirD*(fro, to: string): seq[string] = ## Returns the filenames of the files in the directory that were copied. result = @[] - echo("Copying directory: ", fro, " -> ", to) + display("Copying", "directory $# to $#" % [fro, to], priority = LowPriority) for path in walkDirRec(fro): createDir(changeRoot(fro, to, path.splitFile.dir)) result.add copyFileD(path, changeRoot(fro, to, path)) From c16c0b8864fcb2f57aeaf1bd85842babd163a806 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 23:25:56 +0100 Subject: [PATCH 085/424] Use CLI in packageparser. --- src/nimblepkg/packageparser.nim | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index b0d1be7..79f0145 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. import parsecfg, json, streams, strutils, parseutils, os, tables -import version, tools, common, nimscriptsupport, options, packageinfo +import version, tools, common, nimscriptsupport, options, packageinfo, cli ## Contains procedures for parsing .nimble files. Moved here from ``packageinfo`` ## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also @@ -20,11 +20,7 @@ proc newValidationError(msg: string, warnInstalled: bool): ref ValidationError = result.warnInstalled = warnInstalled proc raiseNewValidationError(msg: string, warnInstalled: bool) = - if warnInstalled: - # TODO: We warn everywhere for now. Raise the error in the next version. - echo("WARNING: ", msg, ". Will be an error in next version!") - else: - raise newValidationError(msg, warnInstalled) + raise newValidationError(msg, warnInstalled) proc validatePackageName*(name: string) = ## Raises an error if specified package name contains invalid characters. @@ -242,6 +238,14 @@ proc getInstalledPkgs*(libsDir: string, options: Options): ## Gets a list of installed packages. ## ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ + const + readErrorMsg = "Package installation for $1 v$2 is outdated or corrupt." + validationErrorMsg = readErrorMsg & "\nPackage did not pass validation: $3" + + proc createErrorMsg(tmplt, path, msg: string): string = + let (name, version) = getNameVersion(path) + return tmplt % [name, version, msg] + result = @[] for kind, path in walkDir(libsDir): if kind == pcDir: @@ -254,17 +258,15 @@ proc getInstalledPkgs*(libsDir: string, options: Options): result.add((pkg, meta)) except ValidationError: let exc = (ref ValidationError)(getCurrentException()) + exc.msg = createErrorMsg(validationErrorMsg, path, exc.msg) if exc.warnInstalled: - echo("WARNING: Unable to read package info for " & path & "\n" & - " Package did not pass validation: " & exc.msg) + display("Warning", exc.msg, Warning, HighPriority) else: - exc.msg = "Unable to read package info for " & path & "\n" & - " Package did not pass validation: " & exc.msg raise exc except: let exc = getCurrentException() - exc.msg = "Unable to read package info for " & path & "\n" & - " Error: " & exc.msg + let tmplt = readErrorMsg & "\nMore info: $3" + exc.msg = createErrorMsg(tmplt, path, exc.msg) raise exc proc isNimScript*(nf: string, options: Options): bool = From 60aa57be24855532e69bbe3337026a58ec35a469 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 20 Dec 2016 23:40:26 +0100 Subject: [PATCH 086/424] NimbleError is now captured in debug mode as well as release mode. --- src/nimble.nim | 24 ++++++++++++++---------- src/nimblepkg/common.nim | 5 ++++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 77133e5..4972502 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -420,7 +420,8 @@ proc installFromDir(dir: string, latest: bool, options: Options, result.pkg = pkgInfo return result - echo("Installing ", pkginfo.name, "-", pkginfo.version) + display("Installing", "$1 v$2" % [pkginfo.name, pkginfo.version], + priority = HighPriority) # Build before removing an existing package (if one exists). This way # if the build fails then the old package will still be installed. @@ -431,7 +432,7 @@ proc installFromDir(dir: string, latest: bool, options: Options, if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): if not options.prompt(pkgInfo.name & versionStr & " already exists. Overwrite?"): - quit(QuitSuccess) + raise NimbleQuit(msg: "") removePkgDir(pkgDestDir, options) # Remove any symlinked binaries for bin in pkgInfo.bin: @@ -1017,15 +1018,18 @@ proc doAction(options: Options) = when isMainModule: var error = "" - when defined(release): - try: - parseCmdLine().doAction() - except NimbleError: - error = getCurrentExceptionMsg() - finally: - removeDir(getNimbleTempDir()) - else: + + try: parseCmdLine().doAction() + except NimbleError: + error = getCurrentExceptionMsg() + when not defined(release): + let stackTrace = getStackTrace(getCurrentException()) + error = stackTrace & "\n\n" & error + except NimbleQuit: + nil + finally: + removeDir(getNimbleTempDir()) displayTip() if error.len > 0: diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index eab71a1..2d00f8c 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -8,7 +8,7 @@ when not defined(nimscript): import sets import version - export version.NimbleError + export version.NimbleError # TODO: Surely there is a better way? type BuildFailed* = object of NimbleError @@ -37,5 +37,8 @@ when not defined(nimscript): srcDir*: string backend*: string + ## Same as quit(QuitSuccess), but allows cleanup. + NimbleQuit* = ref object of Exception + const nimbleVersion* = "0.7.11" From e3f833d61c70e78f032406070ea5750ade599509 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 00:08:42 +0100 Subject: [PATCH 087/424] More replacements of 'echo' to CLI's 'display'. --- src/nimble.nim | 25 ++++++++++++++----------- src/nimblepkg/packageinfo.nim | 8 ++++---- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 4972502..9e5e002 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -469,12 +469,13 @@ proc installFromDir(dir: string, latest: bool, options: Options, # TODO: Verify that we are removing an old bin of this package, not # some other package's binary! if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) - echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin) + display("Creating", "symlink: $1 -> $2" % + [pkgDestDir / bin, binDir / cleanBin], priority = MediumPriority) createSymlink(pkgDestDir / bin, binDir / cleanBin) elif defined(windows): # There is a bug on XP, described here: # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called - # But this workaround brokes code page on newer systems, so we need to detect OS version + # But this workaround brakes code page on newer systems, so we need to detect OS version var osver = OSVERSIONINFO() osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) if GetVersionExA(osver) == WINBOOL(0): @@ -483,7 +484,8 @@ proc installFromDir(dir: string, latest: bool, options: Options, let fixChcp = osver.dwMajorVersion <= 5 let dest = binDir / cleanBin.changeFileExt("cmd") - echo("Creating stub: ", pkgDestDir / bin, " -> ", dest) + display("Creating", "stub: $1 -> $2" % [pkgDestDir / bin, dest], + priority = MediumPriority) var contents = "@" if options.config.chcp: if fixChcp: @@ -493,7 +495,8 @@ proc installFromDir(dir: string, latest: bool, options: Options, writeFile(dest, contents) # For bash on Windows (Cygwin/Git bash). let bashDest = dest.changeFileExt("") - echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest) + display("Creating", "Cygwin stub: $1 -> $2" % + [pkgDestDir / bin, bashDest], priority = MediumPriority) writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") else: {.error: "Sorry, your platform is not supported.".} @@ -514,7 +517,7 @@ proc installFromDir(dir: string, latest: bool, options: Options, result.paths.add pkgDestDir result.pkg = pkgInfo - echo(pkgInfo.name & " installed successfully.") + display(pkgInfo.name, " installed successfully.", priority = HighPriority) proc getNimbleTempDir(): string = ## Returns a path to a temporary directory. @@ -552,8 +555,8 @@ proc downloadPkg(url: string, verRange: VersionRange, if modUrl.contains("github.com") and modUrl.endswith("/"): modUrl = modUrl[0 .. ^2] - echo("Downloading ", modUrl, " into ", downloadDir, " using ", - downMethod, "...") + display("Downloading", "$1 using $2" % [modUrl, $downMethod], + priority = HighPriority) result = ( downloadDir, doDownload(modUrl, downloadDir, verRange, downMethod, options) @@ -595,7 +598,7 @@ proc install(packages: seq[PkgTuple], "internet?"): refresh(options) else: - quit("Please run nimble refresh.", QuitFailure) + raise newException(NimbleError, "Please run nimble refresh.") # Install each package. for pv in packages: @@ -650,8 +653,8 @@ proc compile(options: Options) = if bin == "": raise newException(NimbleError, "You need to specify a file to compile.") - echo("Compiling ", bin, " (", pkgInfo.name, ") using ", backend, - " backend...") + display("Compiling", "$1 ($2) using $3 backend" % [bin, pkgInfo.name, backend], + priority = HighPriority) doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# \"$#\"" % [backend, args, bin]) @@ -686,7 +689,7 @@ proc search(options: Options) = onFound() if not found: - echo("No package found.") + display("Error", "No package found.", Error, HighPriority) proc list(options: Options) = if needsRefresh(options): diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index c4e5498..3fdba56 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. import parsecfg, json, streams, strutils, parseutils, os, sets, tables -import version, tools, common, options +import version, tools, common, options, cli type Package* = object @@ -138,7 +138,7 @@ proc getPackage*(pkg: string, options: Options, ## convenience the proc returns a boolean specifying if the ``resPkg`` was ## successfully filled with good data. for name, list in options.config.packageLists: - echo("Searching in \"", name, "\" package list...") + display("Reading", "$1 package list" % name, priority = LowPriority) let packages = parseFile(options.getNimbleDir() / "packages_" & name.toLowerAscii() & ".json") for p in packages: @@ -178,8 +178,8 @@ proc findNimbleFile*(dir: string; error: bool): string = raise newException(NimbleError, "Specified directory does not contain a .nimble file.") else: - # TODO: Abstract logging. - echo("WARNING: No .nimble file found for ", dir) + display("Warning", "No .nimble file found for " & dir, Warning, + HighPriority) proc getInstalledPkgsMin*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = From 5fe69b389ff83f21ff60acf7ce8121b2d4a4e8d5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 00:17:56 +0100 Subject: [PATCH 088/424] Improvements to existing CLI messages. --- src/nimblepkg/config.nim | 4 ++-- src/nimblepkg/packageparser.nim | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 8b42f5e..1bd3784 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -55,10 +55,10 @@ proc parseConfig*(): Config = f = newFileStream(confFile, fmRead) if f != nil: display("Warning", "Using deprecated config file at " & confFile, - displayType = Warning) + Warning, HighPriority) if f != nil: - display("Reading", "config file at " & confFile) + display("Reading", "config file at " & confFile, priority = LowPriority) var p: CfgParser open(p, f, confFile) var currentSection = "" diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 79f0145..6ac61c0 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -239,13 +239,15 @@ proc getInstalledPkgs*(libsDir: string, options: Options): ## ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ const - readErrorMsg = "Package installation for $1 v$2 is outdated or corrupt." + readErrorMsg = "Installed package $1 v$2 is outdated or corrupt." validationErrorMsg = readErrorMsg & "\nPackage did not pass validation: $3" proc createErrorMsg(tmplt, path, msg: string): string = let (name, version) = getNameVersion(path) return tmplt % [name, version, msg] + display("Loading", "list of installed packages", priority = HighPriority) + result = @[] for kind, path in walkDir(libsDir): if kind == pcDir: From 87d6f85aea426c80148e30d72c92f434c9046c82 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 20:09:53 +0100 Subject: [PATCH 089/424] Implement debug messages and wrap exec output in them. --- src/nimblepkg/cli.nim | 17 ++++++++++++----- src/nimblepkg/options.nim | 4 +++- src/nimblepkg/tools.nim | 5 ++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index caa5236..2bd3c05 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -21,7 +21,7 @@ type suppressionCount: int ## Amount of messages which were not shown. Priority* = enum - LowPriority, MediumPriority, HighPriority + DebugPriority, LowPriority, MediumPriority, HighPriority DisplayType* = enum Error, Warning, Message, Success @@ -30,8 +30,8 @@ const longestCategory = len("Downloading") foregrounds: array[Error .. Success, ForegroundColor] = [fgRed, fgYellow, fgCyan, fgGreen] - styles: array[LowPriority .. HighPriority, set[Style]] = - [{styleDim}, {}, {styleBright}] + styles: array[DebugPriority .. HighPriority, set[Style]] = + [{styleDim}, {styleDim}, {}, {styleBright}] proc newCLI(): CLI = result = CLI( @@ -53,7 +53,8 @@ proc displayLine(category, line: string, displayType: DisplayType, # line. let offset = calculateCategoryOffset(category) # Display the category. - setForegroundColor(stdout, foregrounds[displayType]) + if priority != DebugPriority: + setForegroundColor(stdout, foregrounds[displayType]) writeStyled("$1$2 " % [repeatChar(offset), category], styles[priority]) resetAttributes() @@ -71,8 +72,10 @@ proc display*(category, msg: string, displayType = Message, globalCLI.warnings.incl(warningPair) # Suppress this message if its priority isn't high enough. + # TODO: Per-priority suppression counts? if priority < globalCLI.level: - globalCLI.suppressionCount.inc + if priority != DebugPriority: + globalCLI.suppressionCount.inc return # Display each line in the message. @@ -82,6 +85,10 @@ proc display*(category, msg: string, displayType = Message, displayLine(if i == 0: category else: "...", line, displayType, priority) i.inc +proc displayDebug*(category, msg: string) = + ## Convenience for displaying debug messages. + display(category, msg, priority = DebugPriority) + proc displayTip*() = ## Called just before Nimble exits. Shows some tips for the user, for example ## the amount of messages that were suppressed and how to show them. diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 97efee9..fe0b5fe 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -85,7 +85,8 @@ Options: information when searching or listing packages --nimbleDir dirname Set the Nimble directory. -d --depsOnly Install only dependencies. - --verbose Show all output. + --verbose Show all non-debug output. + --debug Show all output including debug messages. For more information read the Github readme: https://github.com/nim-lang/nimble#readme @@ -268,6 +269,7 @@ proc parseFlag*(flag, val: string, result: var Options) = of "installed", "i": result.queryInstalled = true of "depsonly", "d": result.depsOnly = true of "verbose": result.verbosity = LowPriority + of "debug": result.verbosity = DebugPriority else: raise newException(NimbleError, "Unknown option: --" & flag) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index f26c5e0..4b83f05 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -20,7 +20,10 @@ proc doCmd*(cmd: string) = stdout.flushFile() stderr.flushFile() - let exitCode = execCmd(cmd) + displayDebug("Executing", cmd) + let (output, exitCode) = execCmdEx(cmd) + displayDebug("Finished", "with exit code " & $exitCode) + displayDebug("Output", output) if exitCode != QuitSuccess: raise newException(NimbleError, From 87567161b84cd75ad286216c9a06e1812a4c3e43 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 21:45:43 +0100 Subject: [PATCH 090/424] All output from `install` command is now using the cli module. --- src/nimblepkg/download.nim | 11 ++++++----- src/nimblepkg/tools.nim | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 0e5059d..bb6f0e1 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -3,7 +3,7 @@ import parseutils, os, osproc, strutils, tables, pegs -import packageinfo, packageparser, version, tools, common, options +import packageinfo, packageparser, version, tools, common, options, cli type DownloadMethod* {.pure.} = enum @@ -142,7 +142,6 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, ## ## Returns the version of the repository which has been downloaded. template getLatestByTag(meth: untyped) {.dirty.} = - echo("Found tags...") # Find latest version that fits our ``verRange``. var latest = findLatest(verRange, versions) ## Note: HEAD is not used when verRange.kind is verAny. This is @@ -150,7 +149,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, # If no tagged versions satisfy our range latest.tag will be "". # We still clone in that scenario because we want to try HEAD in that case. - # https://github.com/nimrod-code/nimble/issues/22 + # https://github.com/nim-lang/nimble/issues/22 meth if $latest.ver != "": result = parseVersionRange($latest.ver) @@ -188,7 +187,8 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, let versions = getTagsListRemote(url, downMethod).getVersionList() if versions.len > 0: getLatestByTag: - echo("Cloning latest tagged version: ", latest.tag) + display("Cloning", "latest tagged version: " & latest.tag, + priority = MediumPriority) doClone(downMethod, url, downloadDir, latest.tag) else: # If no commits have been tagged on the repo we just clone HEAD. @@ -202,7 +202,8 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, if versions.len > 0: getLatestByTag: - echo("Switching to latest tagged version: ", latest.tag) + display("Switching", "to latest tagged version: " & latest.tag, + priority = MediumPriority) doCheckout(downMethod, downloadDir, latest.tag) verifyClone() diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 4b83f05..57ed674 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -23,6 +23,7 @@ proc doCmd*(cmd: string) = displayDebug("Executing", cmd) let (output, exitCode) = execCmdEx(cmd) displayDebug("Finished", "with exit code " & $exitCode) + # TODO: Improve to show output in real-time. displayDebug("Output", output) if exitCode != QuitSuccess: @@ -53,7 +54,7 @@ proc getNimrodVersion*: Version = let vOutput = doCmdEx('"' & nimBin & "\" -v").output var matches: array[0..MaxSubpatterns, string] if vOutput.find(peg"'Version'\s{(\d+\.)+\d}", matches) == -1: - quit("Couldn't find Nim version.", QuitFailure) + raise newException(NimbleError, "Couldn't find Nim version.") newVersion(matches[0]) proc samePaths*(p1, p2: string): bool = From 17ddbc3214a3a56e0c9b79287037f34174646592 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 22:11:47 +0100 Subject: [PATCH 091/424] Add colons to non-verb categories in cli.display. --- src/nimble.nim | 3 ++- src/nimblepkg/cli.nim | 2 +- src/nimblepkg/packageparser.nim | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9e5e002..651a50d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -517,7 +517,8 @@ proc installFromDir(dir: string, latest: bool, options: Options, result.paths.add pkgDestDir result.pkg = pkgInfo - display(pkgInfo.name, " installed successfully.", priority = HighPriority) + display("Success:", pkgInfo.name & " installed successfully.", + Success, HighPriority) proc getNimbleTempDir(): string = ## Returns a path to a temporary directory. diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 2bd3c05..5206411 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -95,7 +95,7 @@ proc displayTip*() = if globalCLI.suppressionCount > 0: let msg = "$1 messages have been suppressed, use --verbose to show them." % $globalCLI.suppressionCount - display("Tip", msg, Warning, HighPriority) + display("Tip:", msg, Warning, HighPriority) proc setVerbosity*(level: Priority) = globalCLI.level = level diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 6ac61c0..6b23513 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -246,7 +246,7 @@ proc getInstalledPkgs*(libsDir: string, options: Options): let (name, version) = getNameVersion(path) return tmplt % [name, version, msg] - display("Loading", "list of installed packages", priority = HighPriority) + display("Loading", "list of installed packages", priority = MediumPriority) result = @[] for kind, path in walkDir(libsDir): From 9be27cd665c2798342c1ce22c76c253bac1df09e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 22:18:11 +0100 Subject: [PATCH 092/424] Display suppressed messages tip only when an error occurred. --- src/nimble.nim | 6 +++--- src/nimblepkg/packageinfo.nim | 2 +- src/nimblepkg/packageparser.nim | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 651a50d..68c386c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -78,13 +78,13 @@ proc refresh(options: Options) = downloadFile(url, tempPath, proxy = getProxy(options)) except: let message = "Could not download: " & getCurrentExceptionMsg() - display("Warning", message, Warning) + display("Warning:", message, Warning) lastError = message continue if not validatePackagesList(tempPath): lastError = "Downloaded packages.json file is invalid" - display("Warning", lastError & ", discarding.", Warning) + display("Warning:", lastError & ", discarding.", Warning) continue copyFile(tempPath, @@ -1035,7 +1035,7 @@ when isMainModule: finally: removeDir(getNimbleTempDir()) - displayTip() if error.len > 0: + displayTip() display("Error", error, Error, HighPriority) quit(1) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 3fdba56..198ab4a 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -178,7 +178,7 @@ proc findNimbleFile*(dir: string; error: bool): string = raise newException(NimbleError, "Specified directory does not contain a .nimble file.") else: - display("Warning", "No .nimble file found for " & dir, Warning, + display("Warning:", "No .nimble file found for " & dir, Warning, HighPriority) proc getInstalledPkgsMin*(libsDir: string, options: Options): diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 6b23513..fc462fe 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -262,7 +262,7 @@ proc getInstalledPkgs*(libsDir: string, options: Options): let exc = (ref ValidationError)(getCurrentException()) exc.msg = createErrorMsg(validationErrorMsg, path, exc.msg) if exc.warnInstalled: - display("Warning", exc.msg, Warning, HighPriority) + display("Warning:", exc.msg, Warning, HighPriority) else: raise exc except: From 22929add0783b0bb1a8ddff21e91d2869203bc6c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Dec 2016 22:56:39 +0100 Subject: [PATCH 093/424] Spice up the prompts. --- src/nimblepkg/cli.nim | 31 +++++++++++++++++++++++++++++-- src/nimblepkg/options.nim | 21 +-------------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 5206411..3ac4b45 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -26,6 +26,9 @@ type DisplayType* = enum Error, Warning, Message, Success + ForcePrompt* = enum + dontForcePrompt, forcePromptYes, forcePromptNo + const longestCategory = len("Downloading") foregrounds: array[Error .. Success, ForegroundColor] = @@ -47,8 +50,8 @@ proc calculateCategoryOffset(category: string): int = assert category.len <= longestCategory return longestCategory - category.len -proc displayLine(category, line: string, displayType: DisplayType, - priority: Priority) = +proc displayCategory(category: string, displayType: DisplayType, + priority: Priority) = # Calculate how much the `category` must be offset to align along a center # line. let offset = calculateCategoryOffset(category) @@ -58,6 +61,10 @@ proc displayLine(category, line: string, displayType: DisplayType, writeStyled("$1$2 " % [repeatChar(offset), category], styles[priority]) resetAttributes() +proc displayLine(category, line: string, displayType: DisplayType, + priority: Priority) = + displayCategory(category, displayType, priority) + # Display the message. echo(line) @@ -97,6 +104,26 @@ proc displayTip*() = $globalCLI.suppressionCount display("Tip:", msg, Warning, HighPriority) +proc prompt*(forcePrompts: ForcePrompt, question: string): bool = + case forcePrompts + of forcePromptYes: + display("Prompt:", question & " -> [forced yes]", Warning, HighPriority) + return true + of forcePromptNo: + display("Prompt:", question & " -> [forced no]", Warning, HighPriority) + return false + of dontForcePrompt: + display("Prompt:", question & " [y/N]", Warning, HighPriority) + displayCategory("...", Warning, HighPriority) + let yn = stdin.readLine() + case yn.normalize + of "y", "yes": + return true + of "n", "no": + return false + else: + return false + proc setVerbosity*(level: Priority) = globalCLI.level = level diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index fe0b5fe..724857c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -45,9 +45,6 @@ type arguments*: seq[string] flags*: StringTableRef - ForcePrompt* = enum - dontForcePrompt, forcePromptYes, forcePromptNo - const help* = """ @@ -168,23 +165,7 @@ proc prompt*(options: Options, question: string): bool = ## ## The proc will return immediately without asking the user if the global ## forcePrompts has a value different than dontForcePrompt. - case options.forcePrompts - of forcePromptYes: - echo(question & " -> [forced yes]") - return true - of forcePromptNo: - echo(question & " -> [forced no]") - return false - of dontForcePrompt: - echo(question & " [y/N]") - let yn = stdin.readLine() - case yn.normalize - of "y", "yes": - return true - of "n", "no": - return false - else: - return false + return prompt(options.forcePrompts, question) proc renameBabelToNimble(options: Options) {.deprecated.} = let babelDir = getHomeDir() / ".babel" From a04848060bfbc321d3987301adbb00e87c21d7bd Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 11:29:48 +0100 Subject: [PATCH 094/424] Use cli for `remove` command messages. Improve prompt. --- src/nimble.nim | 31 +++++++++++++++++-------------- src/nimblepkg/cli.nim | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 68c386c..8cc3f1e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -873,13 +873,14 @@ proc uninstall(options: Options) = var pkgsToDelete: seq[PackageInfo] = @[] # Do some verification. for pkgTup in options.action.packages: - echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...") + display("Looking", "for $1 ($2)" % [pkgTup.name, $pkgTup.ver], + priority = HighPriority) let installedPkgs = getInstalledPkgs(options.getPkgsDir(), options) var pkgList = findAllPkgs(installedPkgs, pkgTup) if pkgList.len == 0: raise newException(NimbleError, "Package not found") - echo("Checking reverse dependencies...") + display("Checking", "reverse dependencies", priority = HighPriority) var errors: seq[string] = @[] for pkg in pkgList: # Check whether any packages depend on the ones the user is trying to @@ -888,17 +889,17 @@ proc uninstall(options: Options) = if not thisPkgsDep.isNil: var reason = "" if thisPkgsDep.len == 1: - reason = thisPkgsDep[0]["name"].str & - " (" & thisPkgsDep[0]["version"].str & ") depends on it" + reason = "$1 ($2) depends on it" % [thisPkgsDep[0]["name"].str, + thisPkgsDep[0]["version"].str] else: for i in 0 .. 0: displayTip() - display("Error", error, Error, HighPriority) + display("Error:", error, Error, HighPriority) quit(1) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 3ac4b45..e6cbcb5 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -114,7 +114,7 @@ proc prompt*(forcePrompts: ForcePrompt, question: string): bool = return false of dontForcePrompt: display("Prompt:", question & " [y/N]", Warning, HighPriority) - displayCategory("...", Warning, HighPriority) + displayCategory("Answer:", Warning, HighPriority) let yn = stdin.readLine() case yn.normalize of "y", "yes": From f972236ed9dd1ffddf9f0c7539716f494e63e122 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 22 Dec 2016 12:41:20 +0100 Subject: [PATCH 095/424] outline of how the support for native package managers should look like --- src/nimblepkg/nimscriptapi.nim | 57 +++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 1d7c4bd..d9b36cc 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -41,4 +41,59 @@ template builtin = discard proc getPkgDir*(): string = ## Returns the package directory containing the .nimble file currently ## being evaluated. - builtin \ No newline at end of file + builtin + +from strutils import contains + +type + Distribution* {.pure.} = enum ## an enum so that the poor programmer + ## cannot introduce typos + Windows, ## some version of Windows + Posix, ## some Posix system + MacOSX, ## some version of OSX + Linux, ## some version of Linux + Ubuntu, + Gentoo, + Fedora, + RedHat, + BSD, + FreeBSD, + OpenBSD + +proc detectOsImpl(d: Distribution): bool = + case d + of Distribution.Windows: ## some version of Windows + result = defined(windows) + of Distribution.Posix: result = defined(posix) + of Distribution.MacOSX: result = defined(macosx) + of Distribution.Linux: result = defined(linux) + of Distribution.Ubuntu, Distribution.Gentoo, Distribution.FreeBSD, + Distribution.OpenBSD, Distribution.Fedora: + result = $d in gorge"uname" + of Distribution.RedHat: + result = "Red Hat" in gorge"uname" + of Distribution.BSD: result = defined(bsd) + +template detectOs*(d: untyped): bool = + detectOsImpl(Distribution.d) + +var foreignDeps: seq[string] = @[] + +proc foreignCmd*(cmd: string; requiresSudo=false) = + foreignDeps.add((if requiresSudo: "sudo " else: "") & cmd) + +proc foreignDep*(foreignPackageName: string) = + let p = foreignPackageName + when defined(windows): + foreignCmd "Chocolatey install " & p + elif defined(bsd): + foreignCmd "ports install " & p, true + elif defined(linux): + if detectOs(Ubuntu): + foreignCmd "apt-get install " & p, true + elif detectOs(Gentoo): + foreignCmd "emerge install " & p, true + elif detectOs(Fedora): + foreignCmd "yum install " & p, true + else: + discard From cb1248a9b4b15e8b3a2cc6378c46c4bb8d4d4453 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 14:38:22 +0100 Subject: [PATCH 096/424] Fix --nimbledir for `c` command and separate flags into actions. --- src/nimblepkg/cli.nim | 4 ++ src/nimblepkg/options.nim | 78 +++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index e6cbcb5..3822187 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -96,6 +96,10 @@ proc displayDebug*(category, msg: string) = ## Convenience for displaying debug messages. display(category, msg, priority = DebugPriority) +proc displayDebug*(msg: string) = + ## Convenience for displaying debug messages with a default category. + displayDebug("Debug:", msg) + proc displayTip*() = ## Called just before Nimble exits. Shows some tips for the user, for example ## the amount of messages that were suppressed and how to show them. diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 724857c..11bd1ae 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -52,6 +52,7 @@ Usage: nimble COMMAND [opts] Commands: install [pkgname, ...] Installs a list of packages. + [-d, --depsOnly] Install only dependencies. init [pkgname] Initializes a new Nimble project. publish Publishes a package on nim-lang/packages. The current working directory needs to be the @@ -62,9 +63,11 @@ Commands: to the Nim compiler. refresh [url] Refreshes the package list. A package list URL can be optionally specified. - search [--ver] pkg/tag Searches for a specified package. Search is + search pkg/tag Searches for a specified package. Search is performed by tag and by name. - list [--ver] Lists all packages. + [--ver] Query remote server for package version. + list Lists all packages. + [--ver] Query remote server for package version. [-i, --installed] Lists all installed packages. tasks Lists the tasks specified in the Nimble package's Nimble file. @@ -81,7 +84,6 @@ Options: --ver Query remote server for package version information when searching or listing packages --nimbleDir dirname Set the Nimble directory. - -d --depsOnly Install only dependencies. --verbose Show all non-debug output. --debug Show all output including debug messages. @@ -100,14 +102,10 @@ proc writeVersion() = proc parseActionType*(action: string): ActionType = case action.normalize() - of "install", "path": - case action.normalize() - of "install": - result = actionInstall - of "path": - result = actionPath - else: - discard + of "install": + result = actionInstall + of "path": + result = actionPath of "build": result = actionBuild of "c", "compile", "js", "cpp", "cc": @@ -230,29 +228,47 @@ proc parseArgument*(key: string, result: var Options) = discard proc parseFlag*(flag, val: string, result: var Options) = - case result.action.typ - of actionCompile: - if val == "": - result.action.compileOptions.add("--" & flag) + var wasFlagHandled = true + + # Global flags. + case flag.normalize() + of "help", "h": writeHelp() + of "version", "v": writeVersion() + of "accept", "y": result.forcePrompts = forcePromptYes + of "reject", "n": result.forcePrompts = forcePromptNo + of "nimbledir": result.nimbleDir = val + of "verbose": result.verbosity = LowPriority + of "debug": result.verbosity = DebugPriority + # Action-specific flags. + of "installed", "i": + if result.action.typ in [actionSearch, actionList]: + result.queryInstalled = true else: - result.action.compileOptions.add("--" & flag & ":" & val) - of actionCustom: - result.action.flags[flag] = val + wasFlagHandled = false + of "depsonly", "d": + if result.action.typ == actionInstall: + result.depsOnly = true + else: + wasFlagHandled = false + of "ver": + if result.action.typ in [actionSearch, actionList]: + result.queryVersions = true + else: + wasFlagHandled = false else: - # TODO: These should not be global. - case flag.normalize() - of "help", "h": writeHelp() - of "version", "v": writeVersion() - of "accept", "y": result.forcePrompts = forcePromptYes - of "reject", "n": result.forcePrompts = forcePromptNo - of "ver": result.queryVersions = true - of "nimbledir": result.nimbleDir = val - of "installed", "i": result.queryInstalled = true - of "depsonly", "d": result.depsOnly = true - of "verbose": result.verbosity = LowPriority - of "debug": result.verbosity = DebugPriority + case result.action.typ + of actionCompile: + if val == "": + result.action.compileOptions.add("--" & flag) + else: + result.action.compileOptions.add("--" & flag & ":" & val) + of actionCustom: + result.action.flags[flag] = val else: - raise newException(NimbleError, "Unknown option: --" & flag) + wasFlagHandled = false + + if not wasFlagHandled: + raise newException(NimbleError, "Unknown option: --" & flag) proc initOptions*(): Options = result.action.typ = actionNil From 971dc300bb2f1c2f558a65c9d48b30a285c97a5d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 15:18:46 +0100 Subject: [PATCH 097/424] Usability fixes and output improvements for `compile` command. --- src/nimble.nim | 17 +++++++++++------ src/nimblepkg/tools.nim | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 8cc3f1e..95520df 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -635,6 +635,13 @@ proc build(options: Options) = buildFromDir(pkgInfo, paths, false) proc compile(options: Options) = + let bin = options.action.file + if bin == "": + raise newException(NimbleError, "You need to specify a file to compile.") + + if not fileExists(bin): + raise newException(NimbleError, "Specified file does not exist.") + var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) let paths = processDeps(pkginfo, options) @@ -644,20 +651,18 @@ proc compile(options: Options) = for option in options.action.compileOptions: args.add(option & " ") - let bin = options.action.file + let backend = if options.action.backend.len > 0: options.action.backend else: pkgInfo.backend - if bin == "": - raise newException(NimbleError, "You need to specify a file to compile.") - - display("Compiling", "$1 ($2) using $3 backend" % [bin, pkgInfo.name, backend], - priority = HighPriority) + display("Compiling", "$1 (from package $2) using $3 backend" % + [bin, pkgInfo.name, backend], priority = HighPriority) doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# \"$#\"" % [backend, args, bin]) + display("Success:", "Compilation finished", Success, HighPriority) proc search(options: Options) = ## Searches for matches in ``options.action.search``. diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 57ed674..d71c3f6 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -28,7 +28,8 @@ proc doCmd*(cmd: string) = if exitCode != QuitSuccess: raise newException(NimbleError, - "Execution failed with exit code " & $exitCode) + "Execution failed with exit code $1\nCommand: $2\nOutput: $3" % + [$exitCode, cmd, output]) proc doCmdEx*(cmd: string): tuple[output: TaintedString, exitCode: int] = let bin = extractBin(cmd) From 34af12a326eacf1e10c2bc134928cf03ae1c9efd Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 15:36:18 +0100 Subject: [PATCH 098/424] Use cli.display for `path` command. --- src/nimble.nim | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 95520df..48415d8 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -651,7 +651,6 @@ proc compile(options: Options) = for option in options.action.compileOptions: args.add(option & " ") - let backend = if options.action.backend.len > 0: options.action.backend @@ -726,7 +725,7 @@ proc listInstalled(options: Options) = type VersionAndPath = tuple[version: Version, path: string] proc listPaths(options: Options) = - ## Loops over installing packages displaying their installed paths. + ## Loops over the specified packages displaying their installed paths. ## ## If there are several packages installed, only the last one (the version ## listed in the packages.json) will be displayed. If any package name is not @@ -736,6 +735,10 @@ proc listPaths(options: Options) = ## On success the proc returns normally. assert options.action.typ == actionPath assert(not options.action.packages.isNil) + + if options.action.packages.len == 0: + raise newException(NimbleError, "A package name needs to be specified") + var errors = 0 for name, version in options.action.packages.items: var installed: seq[VersionAndPath] = @[] @@ -757,13 +760,16 @@ proc listPaths(options: Options) = v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version) installed.add(v) else: - echo "Warning: No .nimble file found for ", path + display("Warning:", "No .nimble file found for " & path, Warning, + MediumPriority) if installed.len > 0: sort(installed, system.cmp[VersionAndPath], Descending) + # The output for this command is used by tools so we do not use display(). echo installed[0].path else: - echo "Warning: Package '" & name & "' not installed" + display("Warning:", "Package '$1' is not installed" % name, Warning, + MediumPriority) errors += 1 if errors > 0: raise newException(NimbleError, From 9b67f424e6e005509b4d4dae2e72d8fdafb852ca Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 15:38:53 +0100 Subject: [PATCH 099/424] The `path` command no longer looks for .babel or .nims files. --- src/nimble.nim | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 48415d8..b236e9b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -748,11 +748,9 @@ proc listPaths(options: Options) = continue let - nimScriptFile = path / name.addFileExt("nims") - babelFile = path / name.addFileExt("babel") nimbleFile = path / name.addFileExt("nimble") - hasSpec = nimScriptFile.existsFile or - nimbleFile.existsFile or babelFile.existsFile + hasSpec = nimbleFile.existsFile + if hasSpec: var pkgInfo = getPkgInfo(path, options) var v: VersionAndPath From a111d5f3b957b6d7c8e889c89685f5aa824fb725 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 16:13:36 +0100 Subject: [PATCH 100/424] Implement promptCustom in cli and use it for `init` command. --- src/nimble.nim | 36 +++++++++++------------------------- src/nimblepkg/cli.nim | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index b236e9b..aab0a97 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -35,18 +35,6 @@ else: proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetVersionExA".} -proc promptCustom(question, default: string): string = - if default == "": - stdout.write(question, ": ") - let user = stdin.readLine() - if user.len == 0: return promptCustom(question, default) - else: return user - else: - stdout.write(question, " [", default, "]: ") - let user = stdin.readLine() - if user == "": return default - else: return user - proc refresh(options: Options) = ## Downloads the package list from the specified URL. ## @@ -804,9 +792,10 @@ proc dump(options: Options) = proc init(options: Options) = var nimbleFile: string = "" - echo("In order to initialise a new Nimble package, I will need to ask you\n" & + display("Info:", + "In order to initialise a new Nimble package, I will need to ask you\n" & "some questions. Default values are shown in square brackets, press\n" & - "enter to use them.") + "enter to use them.", priority = HighPriority) # Ask for package name. if options.action.projName != "": @@ -814,7 +803,7 @@ proc init(options: Options) = nimbleFile = pkgName.changeFileExt("nimble") else: var pkgName = os.getCurrentDir().splitPath.tail.toValidPackageName() - pkgName = promptCustom("Enter package name", pkgName) + pkgName = promptCustom("Package name?", pkgName) nimbleFile = pkgName.changeFileExt("nimble") validatePackageName(nimbleFile.changeFileExt("")) @@ -823,7 +812,7 @@ proc init(options: Options) = raise newException(NimbleError, "Nimble file already exists.") # Ask for package version. - let pkgVersion = promptCustom("Enter initial version of package", "0.1.0") + let pkgVersion = promptCustom("Initial version of package?", "0.1.0") validateVersion(pkgVersion) # Ask for package author @@ -836,25 +825,20 @@ proc init(options: Options) = let (name, exitCode) = doCmdEx("hg config ui.username") if exitCode == QuitSuccess and name.len > 0: defaultAuthor = name.strip() - let pkgAuthor = promptCustom("Enter your name", defaultAuthor) + let pkgAuthor = promptCustom("Your name?", defaultAuthor) # Ask for description - let pkgDesc = promptCustom("Enter package description", "") + let pkgDesc = promptCustom("Package description?", "") # Ask for license # TODO: Provide selection of licenses, or select random default license. - let pkgLicense = promptCustom("Enter package license", "MIT") + let pkgLicense = promptCustom("Package license?", "MIT") # Ask for Nim dependency let nimDepDef = getNimrodVersion() - let pkgNimDep = promptCustom("Enter lowest supported Nim version", $nimDepDef) + let pkgNimDep = promptCustom("Lowest supported Nim version?", $nimDepDef) validateVersion(pkgNimDep) - # Now generate the .nimble file. - if existsFile(os.getCurrentDir() / nimbleFile): - raise newException(NimbleError, - "Looks like a Nimble file has already been created.") - var outFile: File if open(f = outFile, filename = nimbleFile, mode = fmWrite): outFile.writeLine """# Package @@ -874,6 +858,8 @@ requires "nim >= $#" raise newException(NimbleError, "Unable to open file " & nimbleFile & " for writing: " & osErrorMsg(osLastError())) + display("Success:", "Nimble file created successfully", Success, HighPriority) + proc uninstall(options: Options) = if options.action.packages.len == 0: raise newException(NimbleError, diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 3822187..1c616e3 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -128,6 +128,20 @@ proc prompt*(forcePrompts: ForcePrompt, question: string): bool = else: return false +proc promptCustom*(question, default: string): string = + if default == "": + display("Prompt:", question, Warning, HighPriority) + displayCategory("Answer:", Warning, HighPriority) + let user = stdin.readLine() + if user.len == 0: return promptCustom(question, default) + else: return user + else: + display("Prompt:", question & " [" & default & "]", Warning, HighPriority) + displayCategory("Answer:", Warning, HighPriority) + let user = stdin.readLine() + if user == "": return default + else: return user + proc setVerbosity*(level: Priority) = globalCLI.level = level From c0f2bd03b1830f695fe0ebd7b93ae9e35615181d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 16:30:24 +0100 Subject: [PATCH 101/424] More use of the cli module. --- src/nimble.nim | 29 ++++++++++++++++++----------- src/nimblepkg/nimscriptsupport.nim | 10 ++++++---- src/nimblepkg/options.nim | 7 ++++--- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index aab0a97..e759f7d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -321,8 +321,8 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" - echo("Building ", pkginfo.name, "/", bin, " using ", pkgInfo.backend, - " backend...") + display("Building", "$1/$2 using $3 backend" % + [pkginfo.name, bin, pkgInfo.backend], priority = HighPriority) let outputDir = pkgInfo.getOutputDir("") if not existsDir(outputDir): @@ -362,13 +362,14 @@ proc removePkgDir(dir: string, options: Options) = if toSeq(walkDirRec(dir)).len == 0: removeDir(dir) else: - echo("WARNING: Cannot completely remove " & dir & - ". Files not installed by nimble are present.") + display("Warning:", ("Cannot completely remove $1. Files not installed " & + "by nimble are present.") % dir, Warning, HighPriority) except OSError, JsonParsingError: - echo("Error: Unable to read nimblemeta.json: ", getCurrentExceptionMsg()) + display("Warning", "Unable to read nimblemeta.json: " & + getCurrentExceptionMsg(), Warning, HighPriority) if not options.prompt("Would you like to COMPLETELY remove ALL files " & "in " & dir & "?"): - quit(QuitSuccess) + raise NimbleQuit(msg: "") removeDir(dir) proc vcsRevisionInDir(dir: string): string = @@ -955,7 +956,8 @@ proc doAction(options: Options) = createDir(options.getPkgsDir) if not execHook(options, true): - echo("Pre-hook prevented further execution.") + display("Warning", "Pre-hook prevented further execution.", Warning, + HighPriority) return case options.action.typ of actionRefresh: @@ -996,14 +998,19 @@ proc doAction(options: Options) = let execResult = execTask(nimbleFile, options.action.command, options) if not execResult.success: - echo("FAILURE: Could not find task ", options.action.command, " in ", - nimbleFile) - writeHelp() + writeHelp(false) + + raise newException(NimbleError, "Could not find task $1 in $2" % + [options.action.command, nimbleFile]) + if execResult.command.normalize == "nop": - echo("WARNING: Using `setCommand 'nop'` is not necessary.") + display("Warning:", "Using `setCommand 'nop'` is not necessary.", Warning, + HighPriority) return + if not execHook(options, false): return + if execResult.hasTaskRequestedCommand(): var newOptions = initOptions() newOptions.config = options.config diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 6e5eec2..a9c2ea6 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -15,7 +15,7 @@ from compiler/scriptconfig import setupVM from compiler/astalgo import strTableGet import compiler/options as compiler_options -import common, version, options, packageinfo +import common, version, options, packageinfo, cli import os, strutils, strtabs, times, osproc, sets when not declared(resetAllModulesHard): @@ -291,7 +291,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, if msgs.gErrorCounter > 0: raise newException(NimbleError, previousMsg) elif previousMsg.len > 0: - echo(previousMsg) + display("Info", previousMsg, priority = HighPriority) if output.normalize.startsWith("error"): raise newException(NimbleError, output) previousMsg = output @@ -367,7 +367,8 @@ proc execTask*(scriptName, taskName: string, result.success = true result.flags = newStringTable() compiler_options.command = internalCmd - echo("Executing task ", taskName, " in ", scriptName) + display("Executing", "task $# in $#" % [taskName, scriptName], + priority = HighPriority) let thisModule = execScript(scriptName, result.flags, options) let prc = thisModule.tab.strTableGet(getIdent(taskName & "Task")) @@ -397,7 +398,8 @@ proc execHook*(scriptName, actionName: string, before: bool, let hookName = if before: actionName.toLowerAscii & "Before" else: actionName.toLowerAscii & "After" - echo("Attempting to execute hook ", hookName, " in ", scriptName) + display("Attempting", "to execute hook $# in $#" % [hookName, scriptName], + priority = MediumPriority) let thisModule = execScript(scriptName, result.flags, options) # Explicitly execute the task procedure, instead of relying on hack. diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 11bd1ae..f68b492 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -91,14 +91,15 @@ For more information read the Github readme: https://github.com/nim-lang/nimble#readme """ -proc writeHelp*() = +proc writeHelp*(quit=true) = echo(help) - quit(QuitSuccess) + if quit: + raise NimbleQuit(msg: "") proc writeVersion() = echo("nimble v$# compiled at $# $#" % [nimbleVersion, CompileDate, CompileTime]) - quit(QuitSuccess) + raise NimbleQuit(msg: "") proc parseActionType*(action: string): ActionType = case action.normalize() From 8f34336e919c2625498d52255278d6f1c10795c8 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 16:49:24 +0100 Subject: [PATCH 102/424] Add hints for NimbleErrors which help the user fix them. --- src/nimble.nim | 16 +++++++++++----- src/nimblepkg/common.nim | 5 +++++ src/nimblepkg/packageparser.nim | 8 ++++++-- src/nimblepkg/version.nim | 1 + 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e759f7d..7c50a27 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -998,10 +998,10 @@ proc doAction(options: Options) = let execResult = execTask(nimbleFile, options.action.command, options) if not execResult.success: - writeHelp(false) - - raise newException(NimbleError, "Could not find task $1 in $2" % - [options.action.command, nimbleFile]) + raiseNimbleError(msg = "Could not find task $1 in $2" % + [options.action.command, nimbleFile], + hint = "Run `nimble --help` and/or `nimble tasks` for" & + " a list of possible commands.") if execResult.command.normalize == "nop": display("Warning:", "Using `setCommand 'nop'` is not necessary.", Warning, @@ -1027,14 +1027,18 @@ proc doAction(options: Options) = when isMainModule: var error = "" + var hint = "" try: parseCmdLine().doAction() except NimbleError: - error = getCurrentExceptionMsg() + let err = (ref NimbleError)(getCurrentException()) + error = err.msg when not defined(release): let stackTrace = getStackTrace(getCurrentException()) error = stackTrace & "\n\n" & error + if not err.isNil: + hint = err.hint except NimbleQuit: nil finally: @@ -1043,4 +1047,6 @@ when isMainModule: if error.len > 0: displayTip() display("Error:", error, Error, HighPriority) + if hint.len > 0: + display("Hint:", hint, Warning, HighPriority) quit(1) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 2d00f8c..1f5c39a 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -40,5 +40,10 @@ when not defined(nimscript): ## Same as quit(QuitSuccess), but allows cleanup. NimbleQuit* = ref object of Exception + proc raiseNimbleError*(msg: string, hint = "") = + var exc = newException(NimbleError, msg) + exc.hint = hint + raise exc + const nimbleVersion* = "0.7.11" diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index fc462fe..e857e61 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -241,6 +241,8 @@ proc getInstalledPkgs*(libsDir: string, options: Options): const readErrorMsg = "Installed package $1 v$2 is outdated or corrupt." validationErrorMsg = readErrorMsg & "\nPackage did not pass validation: $3" + hintMsg = "The corrupted package will need to be removed manually. To fix" & + " this error message, remove $1." proc createErrorMsg(tmplt, path, msg: string): string = let (name, version) = getNameVersion(path) @@ -261,14 +263,16 @@ proc getInstalledPkgs*(libsDir: string, options: Options): except ValidationError: let exc = (ref ValidationError)(getCurrentException()) exc.msg = createErrorMsg(validationErrorMsg, path, exc.msg) + exc.hint = hintMsg % path if exc.warnInstalled: display("Warning:", exc.msg, Warning, HighPriority) else: raise exc except: - let exc = getCurrentException() let tmplt = readErrorMsg & "\nMore info: $3" - exc.msg = createErrorMsg(tmplt, path, exc.msg) + let msg = createErrorMsg(tmplt, path, getCurrentException().msg) + var exc = newException(NimbleError, msg) + exc.hint = hintMsg % path raise exc proc isNimScript*(nf: string, options: Options): bool = diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 18fc4e7..a683c2e 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -34,6 +34,7 @@ type ParseVersionError* = object of ValueError NimbleError* = object of Exception + hint*: string proc newVersion*(ver: string): Version = return Version(ver) proc newSpecial*(spe: string): Special = return Special(spe) From 36e7bfba192aea5afca6aef92f91c62789630004 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 17:12:45 +0100 Subject: [PATCH 103/424] Use the cli module everywhere. --- src/nimblepkg/options.nim | 4 ++-- src/nimblepkg/packageinfo.nim | 10 ++++----- src/nimblepkg/packageparser.nim | 9 ++++---- src/nimblepkg/publish.nim | 38 ++++++++++++++++++--------------- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index f68b492..809ce14 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -330,8 +330,8 @@ proc getProxy*(options: Options): Proxy = elif existsEnv("https_proxy"): url = getEnv("https_proxy") except ValueError: - echo("WARNING: Unable to parse proxy from environment: ", - getCurrentExceptionMsg()) + display("Warning:", "Unable to parse proxy from environment: " & + getCurrentExceptionMsg(), Warning, HighPriority) if url.len > 0: var parsed = parseUri(url) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 198ab4a..d598570 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -116,13 +116,10 @@ proc fromJson(obj: JSonNode): Package = proc readMetaData*(path: string): MetaData = ## Reads the metadata present in ``~/.nimble/pkgs/pkg-0.1/nimblemeta.json`` var bmeta = path / "nimblemeta.json" - if not existsFile(bmeta): - bmeta = path / "babelmeta.json" - if existsFile(bmeta): - echo("WARNING: using deprecated babelmeta.json file in " & path) if not existsFile(bmeta): result.url = "" - echo("WARNING: No nimblemeta.json file found in " & path) + display("Warning:", "No nimblemeta.json file found in " & path, + Warning, HighPriority) return # TODO: Make this an error. let cont = readFile(bmeta) @@ -278,7 +275,8 @@ proc validatePackagesList*(path: string): bool = let pkgList = parseFile(path) if pkgList.kind == JArray: if pkgList.len == 0: - echo("WARNING: ", path, " contains no packages.") + display("Warning:", path & " contains no packages.", Warning, + HighPriority) return true except ValueError, JsonParsingError: return false diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index e857e61..1d8c1f9 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -87,10 +87,11 @@ proc validatePackageInfo(pkgInfo: PackageInfo, path: string) = proc nimScriptHint*(pkgInfo: PackageInfo) = if not pkgInfo.isNimScript: - # TODO: Turn this into a warning. - # TODO: Add a URL explaining more. - echo("NOTE: The .nimble file for this project could make use of " & - "additional features, if converted into the new NimScript format.") + display("Warning:", "The .nimble file for this project could make use of " & + "additional features, if converted into the new NimScript format." & + "\nFor more details see:" & + "https://github.com/nim-lang/nimble#creating-packages", + Warning, HighPriority) proc multiSplit(s: string): seq[string] = ## Returns ``s`` split by newline and comma characters. diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index e7fa836..1afcc3f 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -4,8 +4,9 @@ ## Implements 'nimble publish' to create a pull request against ## nim-lang/packages automatically. +import system except TResult import httpclient, base64, strutils, rdstdin, json, os, browsers, times, uri -import tools, common +import tools, common, cli type Auth = object @@ -22,19 +23,20 @@ proc createHeaders(a: Auth): string = "Accept: */*\c\L") proc getGithubAuth(): Auth = - echo("Please create a new personal access token on Github in order to " & - "allow Nimble to fork the packages repository.") + display("Info:", "Please create a new personal access token on Github in" & + " order to allow Nimble to fork the packages repository.", + priority = HighPriority) sleep(5000) - echo("Your default browser should open with the following URL: " & - "https://github.com/settings/tokens/new") + display("Info:", "Your default browser should open with the following URL: " & + "https://github.com/settings/tokens/new", priority = HighPriority) sleep(3000) openDefaultBrowser("https://github.com/settings/tokens/new") - result.token = readLineFromStdin("Personal access token: ").strip() + result.token = promptCustom("Personal access token?", "").strip() let resp = getContent("https://api.github.com/user", extraHeaders=createHeaders(result)).parseJson() result.user = resp["login"].str - echo("Successfully verified as ", result.user) + display("Success:", "Verified as " & result.user, Success, HighPriority) proc isCorrectFork(j: JsonNode): bool = # Check whether this is a fork of the nimble packages repo. @@ -56,7 +58,7 @@ proc createFork(a: Auth) = extraHeaders=createHeaders(a)) proc createPullRequest(a: Auth, packageName, branch: string) = - echo("Creating PR") + display("Info", "Creating PR", priority = HighPriority) discard postContent("https://api.github.com/repos/nim-lang/packages/pulls", extraHeaders=createHeaders(a), body="""{"title": "Add package $1", "head": "$2:$3", @@ -129,17 +131,19 @@ proc publish*(p: PackageInfo) = var pkgsDir = getTempDir() / "nimble-packages-fork" if not forkExists(auth): createFork(auth) - echo "waiting 10s to let Github create a fork ..." + display("Info:", "Waiting 10s to let Github create a fork", + priority = HighPriority) os.sleep(10_000) - echo "... done" + display("Info:", "Finished waiting", priority = LowPriority) if dirExists(pkgsDir): - echo("Removing old packages fork git directory.") + display("Removing", "old packages fork git directory.", + priority = LowPriority) removeDir(pkgsDir) - echo "Cloning packages into: ", pkgsDir + display("Cloning", "packages into: " & pkgsDir, priority = HighPriority) doCmd("git clone git@github.com:" & auth.user & "/packages " & pkgsDir) # Make sure to update the clone. - echo("Updating the fork...") + display("Updating", "the fork", priority = HighPriority) cd pkgsDir: doCmd("git pull https://github.com/nim-lang/packages.git master") doCmd("git push origin master") @@ -175,20 +179,20 @@ proc publish*(p: PackageInfo) = "No .git nor .hg directory found. Stopping.") if url.len == 0: - url = readLineFromStdin("Github URL of " & p.name & ": ") + url = promptCustom("Github URL of " & p.name & "?", "") if url.len == 0: userAborted() - let tags = readLineFromStdin("Please enter a whitespace separated list of tags: ") + let tags = promptCustom("Whitespace separated list of tags?", "") cd pkgsDir: editJson(p, url, tags, downloadMethod) let branchName = "add-" & p.name & getTime().getGMTime().format("HHmm") doCmd("git checkout -B " & branchName) doCmd("git commit packages.json -m \"Added package " & p.name & "\"") - echo("Pushing to remote of fork.") + display("Pushing", "to remote of fork.", priority = HighPriority) doCmd("git push " & getPackageOriginUrl(auth) & " " & branchName) createPullRequest(auth, p.name, branchName) - echo "Pull request successful." + display("Success:", "Pull request successful.", Success, HighPriority) when isMainModule: import packageinfo From da3b38ff60e5db47e68cadc9d0dfe0e7da69be4d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 21:43:39 +0100 Subject: [PATCH 104/424] Fixes tests. --- tests/tester.nim | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 16cbe03..3e4525f 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -123,14 +123,14 @@ test "can use nimscript's setCommand": let (output, exitCode) = execNimble("--verbose", "cTest") let lines = output.strip.splitLines() check exitCode == QuitSuccess - check "Hint: operation successful".normalize in lines[^1].normalize + check "Compilation finished".normalize in lines[^1].normalize test "can use nimscript's setCommand with flags": cd "nimscript": - let (output, exitCode) = execNimble("--verbose", "cr") + let (output, exitCode) = execNimble("--debug", "cr") let lines = output.strip.splitLines() check exitCode == QuitSuccess - check "Hello World".normalize in lines[^1].normalize + check "Hello World".normalize in lines[^2].normalize test "can list nimscript tasks": cd "nimscript": @@ -166,8 +166,8 @@ test "can reject same version dependencies": # stderr output being generated and flushed without first flushing stdout let ls = outp.strip.splitLines() check exitCode != QuitSuccess - check ls[ls.len-1] == "Error: unhandled exception: Cannot satisfy the " & - "dependency on PackageA 0.2.0 and PackageA 0.5.0 [NimbleError]" + check "Cannot satisfy the dependency on PackageA 0.2.0 and PackageA 0.5.0" in + ls[ls.len-1] test "can update": check execNimble("update").exitCode == QuitSuccess @@ -194,7 +194,7 @@ test "issue #126": cd "issue126/b": let (output1, exitCode1) = execNimble("install", "-y") let lines1 = output1.strip.splitLines() - check exitCode1 == QuitSuccess + check exitCode1 != QuitSuccess check inLines(lines1, "The .nimble file name must match name specified inside") test "issue #108": @@ -222,8 +222,8 @@ test "can uninstall": let ls = outp.strip.splitLines() check exitCode != QuitSuccess - check ls[ls.len-1] == " Cannot uninstall issue27b (0.1.0) because " & - "issue27a (0.1.0) depends on it [NimbleError]" + check "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends" & + " on it" in ls[ls.len-1] check execNimble("uninstall", "-y", "issue27").exitCode == QuitSuccess check execNimble("uninstall", "-y", "issue27a").exitCode == QuitSuccess @@ -234,8 +234,8 @@ test "can uninstall": let (outp, exitCode) = execNimble("uninstall", "-y", "PackageA") check exitCode != QuitSuccess let ls = outp.processOutput() - check ls[ls.len-2].startsWith(" Cannot uninstall PackageA ") - check ls[ls.len-1].startsWith(" Cannot uninstall PackageA ") + check "Cannot uninstall PackageA (0.2.0)" in ls[ls.len-2] + check "Cannot uninstall PackageA (0.6.0)" in ls[ls.len-1] check execNimble("uninstall", "-y", "PackageBin2").exitCode == QuitSuccess # Case insensitive From 8a16603ca72615df2181eabd2400f0d55a38f531 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 21:54:32 +0100 Subject: [PATCH 105/424] Use inLines in tester more to fix failures. --- tests/tester.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 3e4525f..69938dd 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -202,7 +202,7 @@ test "issue #108": let (output, exitCode) = execNimble("build") let lines = output.strip.splitLines() check exitCode != QuitSuccess - check "Nothing to build" in lines[^1] + check inLines(lines, "Nothing to build") test "issue #206": cd "issue206": @@ -234,8 +234,8 @@ test "can uninstall": let (outp, exitCode) = execNimble("uninstall", "-y", "PackageA") check exitCode != QuitSuccess let ls = outp.processOutput() - check "Cannot uninstall PackageA (0.2.0)" in ls[ls.len-2] - check "Cannot uninstall PackageA (0.6.0)" in ls[ls.len-1] + check inLines(ls, "Cannot uninstall PackageA (0.2.0)") + check inLines(ls, "Cannot uninstall PackageA (0.6.0)") check execNimble("uninstall", "-y", "PackageBin2").exitCode == QuitSuccess # Case insensitive From e457b54d09451a64c8c6a48e468b20b28e6d11f3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 22 Dec 2016 23:12:41 +0100 Subject: [PATCH 106/424] Small output adjustment. --- src/nimble.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 7c50a27..912cf5a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -285,7 +285,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = pkg = installedPkg # For addRevDep else: - display("Info", "Dependency already satisfied", priority = HighPriority) + display("Info:", "Dependency on $1 already satisfied" % depDesc, + priority = HighPriority) result.add(pkg.mypath.splitFile.dir) # Process the dependencies of this dependency. result.add(processDeps(pkg, options)) From 87aab627625ad7876c8ad67555420ae9fd36527f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Dec 2016 11:17:41 +0100 Subject: [PATCH 107/424] Fixes ToC in readme. --- readme.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index a43d0b3..49c5f94 100644 --- a/readme.markdown +++ b/readme.markdown @@ -26,7 +26,6 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [nimble dump](#nimble-dump) - [Configuration](#configuration) - [Creating Packages](#creating-packages) - - [The new NimScript format](#the-new-nimscript-format) - [Libraries](#libraries) - [Binary packages](#binary-packages) - [Hybrids](#hybrids) From 8d51fc4c2f3babc59eca5406c8d4ed9bd4992adb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Dec 2016 12:42:08 +0100 Subject: [PATCH 108/424] Many additions/improvements to readme. Fixes #221. Fixes #246. --- readme.markdown | 177 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 49 deletions(-) diff --git a/readme.markdown b/readme.markdown index 49c5f94..731f4d0 100644 --- a/readme.markdown +++ b/readme.markdown @@ -12,33 +12,36 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Installation](#installation) - [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages) - [Nimble usage](#nimble-usage) - - [nimble refresh](#nimble-refresh) - - [nimble install](#nimble-install) - - [nimble uninstall](#nimble-uninstall) - - [nimble build](#nimble-build) - - [nimble c](#nimble-c) - - [nimble list](#nimble-list) - - [nimble search](#nimble-search) - - [nimble path](#nimble-path) - - [nimble init](#nimble-init) - - [nimble publish](#nimble-publish) - - [nimble tasks](#nimble-tasks) - - [nimble dump](#nimble-dump) + - [nimble refresh](#nimble-refresh) + - [nimble install](#nimble-install) + - [nimble uninstall](#nimble-uninstall) + - [nimble build](#nimble-build) + - [nimble c](#nimble-c) + - [nimble list](#nimble-list) + - [nimble search](#nimble-search) + - [nimble path](#nimble-path) + - [nimble init](#nimble-init) + - [nimble publish](#nimble-publish) + - [nimble tasks](#nimble-tasks) + - [nimble dump](#nimble-dump) - [Configuration](#configuration) - [Creating Packages](#creating-packages) - - [Libraries](#libraries) - - [Binary packages](#binary-packages) - - [Hybrids](#hybrids) - - [Dependencies](#dependencies) - - [Nim compiler](#nim-compiler) - - [Versions](#versions) -- [Submitting your package to the package list.](#submitting-your-package-to-the-package-list) + - [Project structure](#project-structure) + - [Tests](#tests) + - [Libraries](#libraries) + - [Binary packages](#binary-packages) + - [Hybrids](#hybrids) + - [Dependencies](#dependencies) + - [Nim compiler](#nim-compiler) + - [Versions](#versions) + - [Releasing a new version](#releasing-a-new-version) +- [Publishing packages](#publishing-packages) - [.nimble reference](#nimble-reference) - - [[Package]](#package) - - [Required](#required) - - [Optional](#optional) - - [[Deps]/[Dependencies]](#depsdependencies) - - [Optional](#optional) + - [[Package]](#package) + - [Required](#required) + - [Optional](#optional) + - [[Deps]/[Dependencies]](#depsdependencies) + - [Optional](#optional) - [Troubleshooting](#troubleshooting) - [Contribution](#contribution) - [About](#about) @@ -194,9 +197,10 @@ Similar to the ``install`` command you can specify a version range, for example: ### nimble build The ``build`` command is mostly used by developers who want to test building -their ``.nimble`` package. This command will build the package in debug mode, -without installing anything. The ``install`` command will build the package -in release mode instead. +their ``.nimble`` package. This command will build the package with default +flags, i.e. a debug build which includes stack traces but no GDB debug +information. +The ``install`` command will build the package in release mode instead. ### nimble c @@ -372,6 +376,7 @@ You can also specify multiple dependencies like so: requires "nim >= 0.10.0", "foobar >= 0.1.0" requires "fizzbuzz >= 1.0" +``` Nimble currently supports installation of packages from a local directory, a git repository and a mercurial repository. The .nimble file must be present in @@ -435,12 +440,54 @@ also return ``false`` from these blocks to stop further execution. The ``nimscriptapi.nim`` module specifies this and includes other definitions which are also useful. Take a look at it for more information. +### Project structure + +There is nothing surprising about the recommended project structure. The advice +resembles that of many other package managers. + +| Directory | Purpose | +| ------------- | -------------------------------------- | +| ``.`` | Root directory containing .nimble file.| +| ``./src/`` | Project source code | +| ``./tests/`` | Project test files | +| ``./docs/`` | Project documentation | + +#### Tests + +A common problem that arises with tests is the fact that they need to import +the associated package. But the package is in the parent directory. This can +be solved in a few different ways: + +* Expect that the package has been installed locally into your + ``~/.nimble`` directory. +* Use a simple path modification to resolve the package properly. + +The latter is highly recommended. Reinstalling the package to test an actively +changing code base is a massive pain. + +To modify the path for your tests only, simply add a ``nim.cfg`` file into +your ``tests`` directory with the following contents: + +``` +--path:"../src/" +``` + +To make testing even more convenient, you may wish to define a ``test`` task +in your ``.nimble`` file. Like so: + +```nim +task "test", "Runs the test suite": + exec "nim c -r tests/tester" +``` + +You can compile and run a single tester application or multiple test files. + ### Libraries Library packages are likely the most popular form of Nimble packages. They are -meant to be used by other library packages or the ultimate binary packages. +meant to be used by other library or binary packages. -When nimble installs a library it will copy all the files in the package +When nimble installs a library it will copy all of its files into ``$nimbleDir/pkgs/pkgname-ver``. It's up to the package creator to make sure that the package directory layout is correct, this is so that users of the package can correctly import the package. @@ -482,23 +529,23 @@ A package is automatically a binary package as soon as it sets at least one ``bin`` value, like so: ```ini -bin = "main" # NimScript config expects a seq instead, e.g. @["main"] +bin = @["main"] ``` In this case when ``nimble install`` is invoked, nimble will build the ``main.nim`` file, copy it into ``$nimbleDir/pkgs/pkgname-ver/`` and subsequently create a -symlink to the binary in ``$nimbleDir/bin/``. On Windows a stub .bat file is +symlink to the binary in ``$nimbleDir/bin/``. On Windows a stub .cmd file is created instead. Other files will be copied in the same way as they are for library packages. -Binary packages should not install .nim files so you should include +Binary packages should not install .nim files so include ``SkipExt = "nim"`` in your .nimble file, unless you intend for your package to be a binary/library combo which is fine. -Dependencies are automatically installed before building. Before publishing your -package you should ensure that the dependencies you specified are correct. -You can do this by running ``nimble build`` or ``nimble install`` in the directory +Dependencies are automatically installed before building. +It's a good idea to test that the dependencies you specified are correct by +running by running ``nimble build`` or ``nimble install`` in the directory of your package. ### Hybrids @@ -515,28 +562,28 @@ done for nimble. ### Dependencies -Dependencies are specified under the ``[Deps]`` section in a nimble file. -The ``requires`` key field is used to specify them. For example: +Dependencies are specified using the ``requires`` function. For example: -```ini -[Deps] -Requires: "nim >= 0.10.0, jester > 0.1 & <= 0.5" +``` +# Dependencies +requires "nim >= 0.10.0", "jester > 0.1 & <= 0.5" ``` Dependency lists support version ranges. These versions may either be a concrete version like ``0.1``, or they may contain any of the less-than (``<``), greater-than (``>``), less-than-or-equal-to (``<=``) and greater-than-or-equal-to -(``>=``). Two version ranges may be combined using the ``&`` operator for example: -``> 0.2 & < 1.0`` which will install a package with the version greater than 0.2 +(``>=``) oeprators. +Two version ranges may be combined using the ``&`` operator, for example +``> 0.2 & < 1.0``, which will install a package with the version greater than 0.2 and less than 1.0. Specifying a concrete version as a dependency is not a good idea because your package may end up depending on two different versions of the same package. -If this happens Nimble will refuse to install the package. Similarly you should -not specify an upper-bound as this can lead to a similar issue. +If this happens Nimble will refuse to install the package. In addition to versions you may also specify git/hg tags, branches and commits. -These have to be concrete however. This is done with the ``#`` character, +Although these have to be specific; ranges of commits are not supported. +This is done with the ``#`` character, for example: ``jester#head``. Which will make your package depend on the latest commit of Jester. @@ -572,11 +619,43 @@ package after checking out the latest version. You can force the installation of the HEAD of the repository by specifying ``#head`` after the package name in your dependency list. -## Submitting your package to the package list. +#### Releasing a new version -Nimble's packages list is stored on github and everyone is encouraged to add -their own packages to it! Take a look at -[nim-lang/packages](https://github.com/nim-lang/packages) to learn more. +Version releases are done by creating a tag in your Git or Mercurial +repository. + +Whenever you want to release a new version, you should remember to first +increment the version in your ``.nimble`` file and commit your changes. Only +after that is done should you tag the release. + +To summarise, the steps for release are: + +* Increment the version in your ``.nimble`` file. +* Commit your changes. +* Tag your release, by for example running ``git tag v0.2.0``. +* Push your tags and commits. + +Once the new tag is in the remote repository, Nimble will be able to detect +the new version. + +## Publishing packages + +Publishing packages isn't a requirement. But doing so allows people to associate +a specific name to a URL pointing to your package. This mapping is stored +in an official packages repository located +[here](https://github.com/nim-lang/packages). + +This repository contains a ``packages.json`` file which lists all the published +packages. It contains a set of package names with associated metadata. You +can read more about this metadata in the +[readme for the packages repository](https://github.com/nim-lang/packages#readme). + +To publish your package you need to fork that repository, and add an entry +into the ``packages.json`` file for your package. Then create a pull request +with your changes. **You only need to do this +once**. + +Nimble includes a ``publish`` command which does this for you automatically. ## .nimble reference From 5fef5c577ec3a57ab8229fe0d5b09b65dc00c656 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 23 Dec 2016 15:58:21 +0100 Subject: [PATCH 109/424] make tests work on Windows again --- tests/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index 64b21bf..3c75132 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -3,7 +3,7 @@ import osproc, streams, unittest, strutils, os, sequtils, future var rootDir = getCurrentDir().parentDir() -var nimblePath = rootDir / "src" / "nimble" & ExeExt +var nimblePath = rootDir / "src" / addFileExt("nimble", ExeExt) var installDir = rootDir / "tests" / "nimbleDir" const path = "../src/nimble" From b3b4c6343f5cf2f988d939d54797a3301dadcc81 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 23 Dec 2016 16:01:10 +0100 Subject: [PATCH 110/424] moved new feature to separate 'distros.nim' module --- src/nimble.nim | 4 ++ src/nimblepkg/common.nim | 1 + src/nimblepkg/distros.nim | 59 ++++++++++++++++++++++++++++++ src/nimblepkg/nimscriptapi.nim | 58 ++--------------------------- src/nimblepkg/nimscriptsupport.nim | 42 +++++++++++++++------ src/nimblepkg/packageinfo.nim | 1 + 6 files changed, 99 insertions(+), 66 deletions(-) create mode 100644 src/nimblepkg/distros.nim diff --git a/src/nimble.nim b/src/nimble.nim index a4d3bdb..e108070 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -939,6 +939,10 @@ proc doAction(options: Options) = let (_, pkgInfo) = install(options.action.packages, options) if options.action.packages.len == 0: nimScriptHint(pkgInfo) + if pkgInfo.foreignDeps.len > 0: + echo("To finish the installation, run: ") + for i in 0.. 0: raise newException(NimbleError, previousMsg) # Extract all the necessary fields populated by the nimscript file. - proc getSym(thisModule: PSym, ident: string): PSym = - result = thisModule.tab.strTableGet(getIdent(ident)) + proc getSym(apiModule: PSym, ident: string): PSym = + result = apiModule.tab.strTableGet(getIdent(ident)) if result.isNil: raise newException(NimbleError, "Ident not found: " & ident) template trivialField(field) = - result.field = getGlobal(getSym(thisModule, astToStr field)) + result.field = getGlobal(getSym(apiModule, astToStr field)) template trivialFieldSeq(field) = - result.field.add getGlobalAsSeq(getSym(thisModule, astToStr field)) + result.field.add getGlobalAsSeq(getSym(apiModule, astToStr field)) # keep reasonable default: - let name = getGlobal(thisModule.tab.strTableGet(getIdent"packageName")) + let name = getGlobal(apiModule.tab.strTableGet(getIdent"packageName")) if name.len > 0: result.name = name trivialField version @@ -333,14 +352,15 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, trivialFieldSeq installDirs trivialFieldSeq installFiles trivialFieldSeq installExt + trivialFieldSeq foreignDeps - extractRequires(getSym(thisModule, "requiresData"), result.requires) + extractRequires(getSym(apiModule, "requiresData"), result.requires) - let binSeq = getGlobalAsSeq(getSym(thisModule, "bin")) + let binSeq = getGlobalAsSeq(getSym(apiModule, "bin")) for i in binSeq: result.bin.add(i.addFileExt(ExeExt)) - let backend = getGlobal(getSym(thisModule, "backend")) + let backend = getGlobal(getSym(apiModule, "backend")) if backend.len == 0: result.backend = "c" elif cmpIgnoreStyle(backend, "javascript") == 0: diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index c4e5498..bf2802f 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -37,6 +37,7 @@ proc initPackageInfo*(path: string): PackageInfo = result.installFiles = @[] result.installExt = @[] result.requires = @[] + result.foreignDeps = @[] result.bin = @[] result.srcDir = "" result.binDir = "" From 1d0f28e3219c0a65b59acb13e80edc986977cbfd Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Dec 2016 19:09:54 +0100 Subject: [PATCH 111/424] Preserve special versions in package installations. Ref #88. --- src/nimble.nim | 33 +++++---- src/nimblepkg/download.nim | 18 ++--- src/nimblepkg/packageinfo.nim | 13 +--- src/nimblepkg/packageparser.nim | 27 +++++-- src/nimblepkg/version.nim | 121 ++++++++++++++++++++------------ tests/tester.nim | 11 ++- 6 files changed, 139 insertions(+), 84 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 912cf5a..bdac95f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -263,7 +263,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = result = @[] assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires") display("Verifying", - "dependencies for $1 v$2" % [pkginfo.name, pkginfo.version], + "dependencies for $1@$2" % [pkginfo.name, pkginfo.version], priority = HighPriority) let pkglist = getInstalledPkgs(options.getPkgsDir(), options) @@ -275,7 +275,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = let msg = "Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")" raise newException(NimbleError, msg) else: - let depDesc = "$1 ($2)" % [dep.name, $dep.ver] + let depDesc = "$1@$2" % [dep.name, $dep.ver] display("Checking", "for $1" % depDesc, priority = MediumPriority) var pkg: PackageInfo if not findPkg(pkglist, dep, pkg): @@ -390,7 +390,7 @@ proc vcsRevisionInDir(dir: string): string = except: discard -proc installFromDir(dir: string, latest: bool, options: Options, +proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, url: string): tuple[paths: seq[string], pkg: PackageInfo] = ## Returns where package has been installed to, together with paths ## to the packages this package depends on. @@ -400,24 +400,29 @@ proc installFromDir(dir: string, latest: bool, options: Options, let realDir = pkgInfo.getRealDir() let binDir = options.getBinDir() let pkgsDir = options.getPkgsDir() - var deps_options = options - deps_options.depsOnly = false + var depsOptions = options + depsOptions.depsOnly = false + + # Overwrite the version if the requested version is "#head" or similar. + if requestedVer.kind == verSpecial: + pkgInfo.version = $requestedVer.spe # Dependencies need to be processed before the creation of the pkg dir. - result.paths = processDeps(pkginfo, deps_options) + result.paths = processDeps(pkginfo, depsOptions) if options.depsOnly: result.pkg = pkgInfo return result - display("Installing", "$1 v$2" % [pkginfo.name, pkginfo.version], + display("Installing", "$1 $2" % [pkginfo.name, pkginfo.version], priority = HighPriority) # Build before removing an existing package (if one exists). This way # if the build fails then the old package will still be installed. if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) - let versionStr = (if latest: "" else: '-' & pkgInfo.version) + let versionStr = '-' & pkgInfo.version + let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): if not options.prompt(pkgInfo.name & versionStr & @@ -527,7 +532,7 @@ proc getNimbleTempDir(): string = proc downloadPkg(url: string, verRange: VersionRange, downMethod: DownloadMethod, - options: Options): (string, VersionRange) = + options: Options): (string, Version) = ## Downloads the repository as specified by ``url`` and ``verRange`` using ## the download method specified. ## @@ -580,7 +585,7 @@ proc install(packages: seq[PkgTuple], options: Options, doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] = if packages == @[]: - result = installFromDir(getCurrentDir(), false, options, "") + result = installFromDir(getCurrentDir(), newVRAny(), options, "") else: # If packages.json is not present ask the user if they want to download it. if needsRefresh(options): @@ -597,11 +602,11 @@ proc install(packages: seq[PkgTuple], let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth, options) try: - result = installFromDir(downloadDir, false, options, url) + result = installFromDir(downloadDir, pv.ver, options, url) except BuildFailed: # The package failed to build. # Check if we tried building a tagged version of the package. - let headVer = parseVersionRange("#" & getHeadName(meth)) + let headVer = getHeadName(meth) if pv.ver.kind != verSpecial and downloadVersion != headVer: # If we tried building a tagged version of the package then # ask the user whether they want to try building #head. @@ -610,8 +615,8 @@ proc install(packages: seq[PkgTuple], " like to try installing '$1@#head' (latest unstable)?") % [pv.name, $downloadVersion]) if promptResult: - - result = install(@[(pv.name, headVer)], options, doPrompt) + let toInstall = @[(pv.name, headVer.toVersionRange())] + result = install(toInstall, options, doPrompt) else: raise newException(BuildFailed, "Aborting installation due to build failure") diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index bb6f0e1..cedd648 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -116,12 +116,12 @@ proc getDownloadMethod*(meth: string): DownloadMethod = else: raise newException(NimbleError, "Invalid download method: " & meth) -proc getHeadName*(meth: DownloadMethod): string = +proc getHeadName*(meth: DownloadMethod): Version = ## Returns the name of the download method specific head. i.e. for git ## it's ``head`` for hg it's ``tip``. case meth - of DownloadMethod.git: "head" - of DownloadMethod.hg: "tip" + of DownloadMethod.git: newVersion("#head") + of DownloadMethod.hg: newVersion("#tip") proc checkUrlType*(url: string): DownloadMethod = ## Determines the download method based on the URL. @@ -136,7 +136,7 @@ proc isURL*(name: string): bool = name.startsWith(peg" @'://' ") proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, - downMethod: DownloadMethod, options: Options): VersionRange = + downMethod: DownloadMethod, options: Options): Version = ## Downloads the repository specified by ``url`` using the specified download ## method. ## @@ -152,7 +152,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, # https://github.com/nim-lang/nimble/issues/22 meth if $latest.ver != "": - result = parseVersionRange($latest.ver) + result = latest.ver else: # Result should already be set to #head here. assert(not result.isNil) @@ -170,20 +170,20 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, removeDir(downloadDir) if verRange.kind == verSpecial: # We want a specific commit/branch/tag here. - if verRange.spe == newSpecial(getHeadName(downMethod)): + if verRange.spe == getHeadName(downMethod): doClone(downMethod, url, downloadDir) # Grab HEAD. else: # Grab the full repo. doClone(downMethod, url, downloadDir, tip = false) # Then perform a checkout operation to get the specified branch/commit. doCheckout(downMethod, downloadDir, $verRange.spe) - result = verRange + result = verRange.spe else: case downMethod of DownloadMethod.git: # For Git we have to query the repo remotely for its tags. This is # necessary as cloning with a --depth of 1 removes all tag info. - result = parseVersionRange("#head") + result = getHeadName(downMethod) let versions = getTagsListRemote(url, downMethod).getVersionList() if versions.len > 0: getLatestByTag: @@ -197,7 +197,7 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, verifyClone() of DownloadMethod.hg: doClone(downMethod, url, downloadDir) - result = parseVersionRange("#tip") + result = getHeadName(downMethod) let versions = getTagsList(downloadDir, downMethod).getVersionList() if versions.len > 0: diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index d598570..f278e63 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -4,7 +4,7 @@ import parsecfg, json, streams, strutils, parseutils, os, sets, tables import version, tools, common, options, cli type - Package* = object + Package* = object ## Definition of package from packages.json. # Required fields in a package. name*: string url*: string # Download location. @@ -57,7 +57,6 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] = ## ## Also works for file paths like: ## ``/home/user/.nimble/pkgs/package-0.1/package.nimble`` - if pkgPath.splitFile.ext == ".nimble" or pkgPath.splitFile.ext == ".babel": return getNameVersion(pkgPath.splitPath.head) @@ -288,14 +287,8 @@ when isMainModule: ("package-a", "0.1") doAssert getNameVersion("/home/user/.nimble/libs/package-a-0.1/package.nimble") == ("package-a", "0.1") - - validatePackageName("foo_bar") - validatePackageName("f_oo_b_a_r") - try: - validatePackageName("foo__bar") - assert false - except NimbleError: - assert true + doAssert getNameVersion("/home/user/.nimble/libs/package-#head") == + ("package", "#head") doAssert toValidPackageName("foo__bar") == "foo_bar" doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe" diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 1d8c1f9..819b6c8 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -193,6 +193,7 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, return options.pkgInfoCache[nf] result = initPackageInfo(nf) + let minimalInfo = getNameVersion(nf) validatePackageName(nf.splitFile.name) @@ -208,9 +209,8 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, if not success: if onlyMinimalInfo: - let tmp = getNameVersion(nf) - result.name = tmp.name - result.version = tmp.version + result.name = minimalInfo.name + result.version = minimalInfo.version result.isNimScript = true result.isMinimal = true else: @@ -226,6 +226,14 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, raise newException(NimbleError, msg) validatePackageInfo(result, nf) + + # The package directory name may include a "special" version + # (example #head). If so, it is given higher priority and therefore + # overwrites the .nimble file's version. + let version = parseVersionRange(minimalInfo.version) + if version.kind == verSpecial: + result.version = minimalInfo.version + if not result.isMinimal: options.pkgInfoCache[nf] = result @@ -240,7 +248,7 @@ proc getInstalledPkgs*(libsDir: string, options: Options): ## ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ const - readErrorMsg = "Installed package $1 v$2 is outdated or corrupt." + readErrorMsg = "Installed package '$1@$2' is outdated or corrupt." validationErrorMsg = readErrorMsg & "\nPackage did not pass validation: $3" hintMsg = "The corrupted package will need to be removed manually. To fix" & " this error message, remove $1." @@ -278,3 +286,14 @@ proc getInstalledPkgs*(libsDir: string, options: Options): proc isNimScript*(nf: string, options: Options): bool = result = readPackageInfo(nf, options).isNimScript + +when isMainModule: + validatePackageName("foo_bar") + validatePackageName("f_oo_b_a_r") + try: + validatePackageName("foo__bar") + assert false + except NimbleError: + assert true + + echo("Everything passed!") diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index a683c2e..080c469 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -5,7 +5,6 @@ import strutils, tables, hashes, parseutils type Version* = distinct string - Special* = distinct string VersionRangeEnum* = enum verLater, # > V @@ -23,7 +22,7 @@ type of verLater, verEarlier, verEqLater, verEqEarlier, verEq: ver*: Version of verSpecial: - spe*: Special + spe*: Version of verIntersect: verILeft, verIRight: VersionRange of verAny: @@ -36,18 +35,25 @@ type NimbleError* = object of Exception hint*: string -proc newVersion*(ver: string): Version = return Version(ver) -proc newSpecial*(spe: string): Special = return Special(spe) +proc newVersion*(ver: string): Version = + doAssert(ver[0] in {'#', '\0'} + Digits) + return Version(ver) proc `$`*(ver: Version): string {.borrow.} proc hash*(ver: Version): Hash {.borrow.} -proc `$`*(ver: Special): string {.borrow.} +proc isNil*(ver: Version): bool {.borrow.} -proc hash*(ver: Special): Hash {.borrow.} +proc isSpecial*(ver: Version): bool = + return ($ver)[0] == '#' proc `<`*(ver: Version, ver2: Version): bool = + # Handling for special versions such as "#head" or "#branch". + if ver.isSpecial or ver2.isSpecial: + return false + + # Handling for normal versions such as "0.1.0" or "1.0". var sVer = string(ver).split('.') var sVer2 = string(ver2).split('.') for i in 0..max(sVer.len, sVer2.len)-1: @@ -65,6 +71,9 @@ proc `<`*(ver: Version, ver2: Version): bool = return false proc `==`*(ver: Version, ver2: Version): bool = + if ver.isSpecial or ver2.isSpecial: + return ($ver).toLowerAscii() == ($ver2).toLowerAscii() + var sVer = string(ver).split('.') var sVer2 = string(ver2).split('.') for i in 0..max(sVer.len, sVer2.len)-1: @@ -79,9 +88,6 @@ proc `==`*(ver: Version, ver2: Version): bool = else: return false -proc `==`*(spe: Special, spe2: Special): bool = - return ($spe).toLowerAscii() == ($spe2).toLowerAscii() - proc `<=`*(ver: Version, ver2: Version): bool = return (ver == ver2) or (ver < ver2) @@ -97,39 +103,36 @@ proc `==`*(range1: VersionRange, range2: VersionRange): bool = of verAny: true proc withinRange*(ver: Version, ran: VersionRange): bool = - case ran.kind - of verLater: - return ver > ran.ver - of verEarlier: - return ver < ran.ver - of verEqLater: - return ver >= ran.ver - of verEqEarlier: - return ver <= ran.ver - of verEq: - return ver == ran.ver - of verSpecial: - return false - of verIntersect: - return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight) - of verAny: - return true - -proc withinRange*(spe: Special, ran: VersionRange): bool = - case ran.kind - of verLater, verEarlier, verEqLater, verEqEarlier, verEq, verIntersect: - return false - of verSpecial: - return spe == ran.spe - of verAny: - return true + if ver.isSpecial: + case ran.kind + of verLater, verEarlier, verEqLater, verEqEarlier, verEq, verIntersect: + return false + of verSpecial: + return ver == ran.spe + of verAny: + return true + else: + case ran.kind + of verLater: + return ver > ran.ver + of verEarlier: + return ver < ran.ver + of verEqLater: + return ver >= ran.ver + of verEqEarlier: + return ver <= ran.ver + of verEq: + return ver == ran.ver + of verSpecial: + return false + of verIntersect: + return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight) + of verAny: + return true proc contains*(ran: VersionRange, ver: Version): bool = return withinRange(ver, ran) -proc contains*(ran: VersionRange, spe: Special): bool = - return withinRange(spe, ran) - proc makeRange*(version: string, op: string): VersionRange = new(result) if version == "": @@ -153,9 +156,13 @@ proc makeRange*(version: string, op: string): VersionRange = proc parseVersionRange*(s: string): VersionRange = # >= 1.5 & <= 1.8 new(result) + if s.len == 0: + result.kind = verAny + return + if s[0] == '#': result.kind = verSpecial - result.spe = s[1 .. s.len-1].Special + result.spe = s.Version return var i = 0 @@ -200,6 +207,15 @@ proc parseVersionRange*(s: string): VersionRange = "Unexpected char in version range: " & s[i]) inc(i) +proc toVersionRange*(ver: Version): VersionRange = + ## Converts a version to either a verEq or verSpecial VersionRange. + new(result) + if ver.isSpecial: + result.kind = verSpecial + result.spe = ver + else: + result.kind = verEq + result.ver = ver proc parseRequires*(req: string): PkgTuple = try: @@ -231,7 +247,7 @@ proc `$`*(verRange: VersionRange): string = of verEq: result = "" of verSpecial: - return "#" & $verRange.spe + return $verRange.spe of verIntersect: return $verRange.verILeft & " & " & $verRange.verIRight of verAny: @@ -312,13 +328,26 @@ when isMainModule: #doAssert newVersion("0.1-rc1") < newVersion("0.1") # Special tests - doAssert newSpecial("ab26sgdt362") != newSpecial("ab26saggdt362") - doAssert newSpecial("ab26saggdt362") == newSpecial("ab26saggdt362") - doAssert newSpecial("head") == newSpecial("HEAD") - doAssert newSpecial("head") == newSpecial("head") + doAssert newVersion("#ab26sgdt362") != newVersion("#qwersaggdt362") + doAssert newVersion("#ab26saggdt362") == newVersion("#ab26saggdt362") + doAssert newVersion("#head") == newVersion("#HEAD") + doAssert newVersion("#head") == newVersion("#head") var sp = parseVersionRange("#ab26sgdt362") - doAssert newSpecial("ab26sgdt362") in sp - doAssert newSpecial("ab26saggdt362") notin sp + doAssert newVersion("#ab26sgdt362") in sp + doAssert newVersion("#ab26saggdt362") notin sp + + doAssert newVersion("#head") in parseVersionRange("#head") + + # TODO: It may be worth changing this in the future, although we can't be + # certain that #head is in fact newer than v0.1.0. + doAssert(not(newVersion("#head") > newVersion("0.1.0"))) + + # An empty version range should give verAny + doAssert parseVersionRange("").kind == verAny + + # toVersionRange tests + doAssert toVersionRange(newVersion("#head")).kind == verSpecial + doAssert toVersionRange(newVersion("0.2.0")).kind == verEq echo("Everything works!") diff --git a/tests/tester.nim b/tests/tester.nim index 69938dd..13c1040 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -2,6 +2,10 @@ # BSD License. Look at license.txt for more info. import osproc, streams, unittest, strutils, os, sequtils, future +# TODO: Each test should start off with a clean slate. Currently installed +# packages are shared between each test which causes a multitude of issues +# and is really fragile. + var rootDir = getCurrentDir().parentDir() var nimblePath = rootDir / "src" / "nimble" & ExeExt var installDir = rootDir / "tests" / "nimbleDir" @@ -41,6 +45,11 @@ test "issue 129 (installing commit hash)": let arguments = @["install", "-y", "https://github.com/nimble-test/packagea.git@#1f9cb289c89"] check execNimble(arguments).exitCode == QuitSuccess + # Verify that it was installed correctly. + check dirExists(installDir / "pkgs" / "packagea-#1f9cb289c89") + # Remove it so that it doesn't interfere with the uninstall tests. + check execNimble("uninstall", "-y", "packagea@#1f9cb289c89").exitCode == + QuitSuccess test "issue 113 (uninstallation problems)": cd "issue113/c": @@ -247,6 +256,6 @@ test "can uninstall": check execNimble("uninstall", "-y", "PackageA@0.2", "issue27b").exitCode == QuitSuccess - check(not dirExists(getHomeDir() / ".nimble" / "pkgs" / "PackageA-0.2.0")) + check(not dirExists(installDir / "pkgs" / "PackageA-0.2.0")) check execNimble("uninstall", "-y", "nimscript").exitCode == QuitSuccess From 380cb46da8c1e6d250489b1eda36aad3fe3f210c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Dec 2016 19:15:32 +0100 Subject: [PATCH 112/424] Fixes tests on case sensitive file systems. --- tests/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index 13c1040..a13d410 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -46,7 +46,7 @@ test "issue 129 (installing commit hash)": "https://github.com/nimble-test/packagea.git@#1f9cb289c89"] check execNimble(arguments).exitCode == QuitSuccess # Verify that it was installed correctly. - check dirExists(installDir / "pkgs" / "packagea-#1f9cb289c89") + check dirExists(installDir / "pkgs" / "PackageA-#1f9cb289c89") # Remove it so that it doesn't interfere with the uninstall tests. check execNimble("uninstall", "-y", "packagea@#1f9cb289c89").exitCode == QuitSuccess From f29a25a10d4de1cf56c6a0dde831dab0e859d409 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 26 Dec 2016 18:09:19 +0000 Subject: [PATCH 113/424] Implements #144. Warnings are now issued for incorrect namespacing. --- src/nimble.nim | 33 ++++++----- src/nimblepkg/packageinfo.nim | 101 ++++++++++++++++++++++++++++++- src/nimblepkg/packageparser.nim | 102 ++++++++++++++++++++++++++++---- 3 files changed, 206 insertions(+), 30 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index bdac95f..c5b0491 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -163,7 +163,7 @@ proc copyFilesRec(origDir, currentDir, dest: string, if options.prompt("Missing file " & src & ". Continue?"): continue else: - quit(QuitSuccess) + raise NimbleQuit(msg: "") createDir(dest / file.splitFile.dir) result.incl copyFileD(src, dest / file) @@ -174,7 +174,7 @@ proc copyFilesRec(origDir, currentDir, dest: string, if options.prompt("Missing directory " & src & ". Continue?"): continue else: - quit(QuitSuccess) + raise NimbleQuit(msg: "") result.incl copyDirD(origDir / dir, dest / dir) result.incl copyWithExt(origDir, currentDir, dest, pkgInfo) @@ -441,15 +441,23 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, else: removeFile(binDir / bin) - ## Will contain a list of files which have been installed. - var filesInstalled: HashSet[string] createDir(pkgDestDir) + # Copy this package's files based on the preferences specified in PkgInfo. + var filesInstalled = initSet[string]() + for file in getInstallFiles(realDir, pkgInfo, options): + createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir)) + let dest = changeRoot(realDir, pkgDestDir, file) + filesInstalled.incl copyFileD(file, dest) + + # Copy the .nimble file. + let dest = changeRoot(pkgInfo.mypath.splitFile.dir, pkgDestDir, + pkgInfo.mypath) + filesInstalled.incl copyFileD(pkgInfo.mypath, dest) + if pkgInfo.bin.len > 0: + # Make sure ~/.nimble/bin directory is created. createDir(binDir) - # Copy all binaries and files that are not skipped - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) # Set file permissions to +x for all binaries built, # and symlink them on *nix OS' to $nimbleDir/bin/ for bin in pkgInfo.bin: @@ -495,9 +503,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") else: {.error: "Sorry, your platform is not supported.".} - else: - filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options, - pkgInfo) let vcsRevision = vcsRevisionInDir(realDir) @@ -776,9 +781,7 @@ proc join(x: seq[PkgTuple]; y: string): string = result.add x[i][0] & " " & $x[i][1] proc dump(options: Options) = - let proj = addFileExt(options.action.projName, "nimble") - let p = if fileExists(proj): readPackageInfo(proj, options) - else: getPkgInfo(os.getCurrentDir(), options) + let p = getPkgInfo(os.getCurrentDir(), options) echo "name: ", p.name.escape echo "version: ", p.version.escape echo "author: ", p.author.escape @@ -925,7 +928,7 @@ proc uninstall(options: Options) = # removeRevDep needs the package dependency info, so we can't just pass # a minimal pkg info. - let pkgFull = readPackageInfo(pkg.mypath, options, false) + let pkgFull = getPkgInfo(pkg.mypath.splitFile.dir, options) # TODO: Simplify removeRevDep(options, pkgFull) removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.version), options) display("Removed", "$1 ($2)" % [pkg.name, $pkg.version], Success, @@ -943,7 +946,7 @@ proc execHook(options: Options, before: bool): bool = nimbleFile = findNimbleFile(getCurrentDir(), true) except NimbleError: return true # PackageInfos are cached so we can read them as many times as we want. - let pkgInfo = readPackageInfo(nimbleFile, options) + let pkgInfo = getPkgInfo(nimbleFile.splitFile.dir, options) # TODO: Simplify let actionName = if options.action.typ == actionCustom: options.action.command else: ($options.action.typ)[6 .. ^1] diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index f278e63..9de81ba 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -228,8 +228,7 @@ proc findAllPkgs*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]], result.add pkg.pkginfo proc getRealDir*(pkgInfo: PackageInfo): string = - ## Returns the ``pkgInfo.srcDir`` or the .mypath directory if package does - ## not specify the src dir. + ## Returns the directory containing the package source files. if pkgInfo.srcDir != "" and not pkgInfo.isInstalled: result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir else: @@ -280,6 +279,104 @@ proc validatePackagesList*(path: string): bool = except ValueError, JsonParsingError: return false +proc checkInstallFile(pkgInfo: PackageInfo, + origDir, file: string): bool = + ## Checks whether ``file`` should be installed. + ## ``True`` means file should be skipped. + + for ignoreFile in pkgInfo.skipFiles: + if ignoreFile.endswith("nimble"): + raise newException(NimbleError, ignoreFile & " must be installed.") + if samePaths(file, origDir / ignoreFile): + result = true + break + + for ignoreExt in pkgInfo.skipExt: + if file.splitFile.ext == ('.' & ignoreExt): + result = true + break + + if file.splitFile().name[0] == '.': result = true + +proc checkInstallDir(pkgInfo: PackageInfo, + origDir, dir: string): bool = + ## Determines whether ``dir`` should be installed. + ## ``True`` means dir should be skipped. + for ignoreDir in pkgInfo.skipDirs: + if samePaths(dir, origDir / ignoreDir): + result = true + break + + let thisDir = splitPath(dir).tail + assert thisDir != "" + if thisDir[0] == '.': result = true + if thisDir == "nimcache": result = true + +proc findWithExt(dir: string, pkgInfo: PackageInfo): seq[string] = + ## Returns the filenames of the files that should be copied. + result = @[] + for kind, path in walkDir(dir): + if kind == pcDir: + result.add findWithExt(path, pkgInfo) + else: + if path.splitFile.ext[1 .. ^1] in pkgInfo.installExt: + result.add path + +proc getFilesInDir(dir: string): seq[string] = + ## Returns a list of paths to files inside the specified directory and any + ## subdirectories that are in it. + result = @[] + for kind, path in walkDir(dir): + if kind == pcDir: + result.add getFilesInDir(path) + else: + result.add path + +proc getInstallFiles*(realDir: string, pkgInfo: PackageInfo, + options: Options): seq[string] = + ## Returns a list of files within the ``realDir`` that should be installed. + result = @[] + let whitelistMode = + pkgInfo.installDirs.len != 0 or + pkgInfo.installFiles.len != 0 or + pkgInfo.installExt.len != 0 + if whitelistMode: + for file in pkgInfo.installFiles: + let src = realDir / file + if not src.existsFile(): + if options.prompt("Missing file " & src & ". Continue?"): + continue + else: + raise NimbleQuit(msg: "") + result.add src + + for dir in pkgInfo.installDirs: + # TODO: Allow skipping files inside dirs? + let src = realDir / dir + if not src.existsDir(): + if options.prompt("Missing directory " & src & ". Continue?"): + continue + else: + raise NimbleQuit(msg: "") + + result.add getFilesInDir(src) + + result.add findWithExt(realDir, pkgInfo) + else: + for kind, file in walkDir(realDir): + if kind == pcDir: + let skip = pkgInfo.checkInstallDir(realDir, file) + + if skip: continue + + result.add getInstallFiles(file, pkgInfo, options) + else: + let skip = pkgInfo.checkInstallFile(realDir, file) + + if skip: continue + + result.add file + when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == ("packagea", "0.1") diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 819b6c8..b860228 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -14,13 +14,18 @@ type ValidationError* = object of NimbleError warnInstalled*: bool # Determines whether to show a warning for installed pkgs + warnAll*: bool -proc newValidationError(msg: string, warnInstalled: bool): ref ValidationError = +proc newValidationError(msg: string, warnInstalled: bool, + hint: string, warnAll: bool): ref ValidationError = result = newException(ValidationError, msg) result.warnInstalled = warnInstalled + result.warnAll = warnAll + result.hint = hint -proc raiseNewValidationError(msg: string, warnInstalled: bool) = - raise newValidationError(msg, warnInstalled) +proc raiseNewValidationError(msg: string, warnInstalled: bool, + hint: string = "", warnAll = false) = + raise newValidationError(msg, warnInstalled, hint, warnAll) proc validatePackageName*(name: string) = ## Raises an error if specified package name contains invalid characters. @@ -49,6 +54,10 @@ proc validatePackageName*(name: string) = else: prevWasUnderscore = false + if name.endsWith("pkg"): + raiseNewValidationError("\"$1\" is an invalid package name: cannot end" & + " with \"pkg\"" % name, false) + proc validateVersion*(ver: string) = for c in ver: if c notin ({'.'} + Digits): @@ -56,7 +65,57 @@ proc validateVersion*(ver: string) = "Version may only consist of numbers and the '.' character " & "but found '" & c & "'.", false) -proc validatePackageInfo(pkgInfo: PackageInfo, path: string) = +proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = + ## This ensures that a package's source code does not leak into + ## another package's namespace. + ## https://github.com/nim-lang/nimble/issues/144 + let realDir = pkgInfo.getRealDir() + for path in getInstallFiles(realDir, pkgInfo, options): + # Remove the root to leave only the package subdirectories. + # ~/package-0.1/package/utils.nim -> package/utils.nim. + var trailPath = changeRoot(realDir, "", path) + if trailPath.startsWith(DirSep): trailPath = trailPath[1 .. ^1] + let (dir, file, ext) = trailPath.splitFile + # We're only interested in nim files, because only they can pollute our + # namespace. + if ext != (ExtSep & "nim"): + continue + + if dir.len == 0: + if file != pkgInfo.name: + let msg = ("File inside package '$1' is outside of permitted " & + "namespace, should be " & + "named '$2' but was named '$3' instead. This will be an error" & + " in the future.") % + [pkgInfo.name, pkgInfo.name & ext, file & ext] + let hint = ("Rename this file to '$1', move it into a '$2' " & + "subdirectory, or prevent its installation by adding " & + "`skipFiles = @[\"$3\"]` to the .nimble file. See " & + "https://github.com/nim-lang/nimble#libraries for more info.") % + [pkgInfo.name & ext, pkgInfo.name & DirSep, file & ext] + raiseNewValidationError(msg, true, hint, true) + else: + assert(not pkgInfo.isMinimal) + let correctDir = + if pkgInfo.name in pkgInfo.bin: + pkgInfo.name & "pkg" + else: + pkgInfo.name + + if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): + let msg = ("File '$1' inside package '$2' is outside of the" & + " permitted namespace" & + ", should be inside a directory named '$3' but is in a" & + " directory named '$4' instead. This will be an error in the " & + "future.") % + [file & ext, pkgInfo.name, correctDir, dir] + let hint = ("Rename the directory to '$1' or prevent its " & + "installation by adding `skipDirs = @[\"$2\"]` to the " & + ".nimble file.") % [correctDir, dir] + raiseNewValidationError(msg, true, hint, true) + +proc validatePackageInfo(pkgInfo: PackageInfo, options: Options) = + let path = pkgInfo.myPath if pkgInfo.name == "": raiseNewValidationError("Incorrect .nimble file: " & path & " does not contain a name field.", false) @@ -83,7 +142,8 @@ proc validatePackageInfo(pkgInfo: PackageInfo, path: string) = raiseNewValidationError("'" & pkgInfo.backend & "' is an invalid backend.", false) - validateVersion(pkgInfo.version) + validatePackageStructure(pkginfo, options) + proc nimScriptHint*(pkgInfo: PackageInfo) = if not pkgInfo.isNimScript: @@ -172,7 +232,7 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = else: raise newException(ValueError, "Cannot open package info: " & path) -proc readPackageInfo*(nf: NimbleFile, options: Options, +proc readPackageInfo(nf: NimbleFile, options: Options, onlyMinimalInfo=false): PackageInfo = ## Reads package info from the specified Nimble file. ## @@ -182,7 +242,7 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, ## If both fail then returns an error. ## ## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are - ## populated. The isNimScript field can also be relied on. + ## populated. The ``isNimScript`` field can also be relied on. ## ## This version uses a cache stored in ``options``, so calling it multiple ## times on the same ``nf`` shouldn't require re-evaluation of the Nimble @@ -225,7 +285,8 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, " " & getCurrentExceptionMsg() & "." raise newException(NimbleError, msg) - validatePackageInfo(result, nf) + # Validate version ahead of time, we will be potentially overwriting it soon. + validateVersion(result.version) # The package directory name may include a "special" version # (example #head). If so, it is given higher priority and therefore @@ -237,10 +298,21 @@ proc readPackageInfo*(nf: NimbleFile, options: Options, if not result.isMinimal: options.pkgInfoCache[nf] = result + # Validate the rest of the package info last. + validatePackageInfo(result, options) + proc getPkgInfo*(dir: string, options: Options): PackageInfo = ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo. let nimbleFile = findNimbleFile(dir, true) - result = readPackageInfo(nimbleFile, options) + try: + result = readPackageInfo(nimbleFile, options) + except ValidationError: + let exc = (ref ValidationError)(getCurrentException()) + if exc.warnAll: + display("Warning:", exc.msg, Warning, HighPriority) + display("Hint:", exc.hint, Warning, HighPriority) + else: + raise proc getInstalledPkgs*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @@ -265,16 +337,17 @@ proc getInstalledPkgs*(libsDir: string, options: Options): let nimbleFile = findNimbleFile(path, false) if nimbleFile != "": let meta = readMetaData(path) + var pkg: PackageInfo try: - var pkg = readPackageInfo(nimbleFile, options, onlyMinimalInfo=false) - pkg.isInstalled = true - result.add((pkg, meta)) + pkg = readPackageInfo(nimbleFile, options, onlyMinimalInfo=false) except ValidationError: let exc = (ref ValidationError)(getCurrentException()) exc.msg = createErrorMsg(validationErrorMsg, path, exc.msg) exc.hint = hintMsg % path - if exc.warnInstalled: + if exc.warnInstalled or exc.warnAll: display("Warning:", exc.msg, Warning, HighPriority) + # Don't show hints here because they are only useful for package + # owners. else: raise exc except: @@ -284,6 +357,9 @@ proc getInstalledPkgs*(libsDir: string, options: Options): exc.hint = hintMsg % path raise exc + pkg.isInstalled = true + result.add((pkg, meta)) + proc isNimScript*(nf: string, options: Options): bool = result = readPackageInfo(nf, options).isNimScript From 95a29197eecbd521e9b04b0ddb345d93faac01fe Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 26 Dec 2016 23:03:01 +0000 Subject: [PATCH 114/424] Add tests for #144. --- tests/tester.nim | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/tester.nim b/tests/tester.nim index a13d410..2c4be73 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -41,6 +41,47 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "can validate package structure (#144)": + # Clear nimble dir. + removeDir(installDir) + createDir(installDir) + + # Test that no warnings are produced for correctly structured packages. + for package in ["a", "b", "c"]: + cd "packageStructure/" & package: + let (output, exitCode) = execNimble(["install", "-y"]) + check exitCode == QuitSuccess + let lines = output.strip.splitLines() + check(not inLines(lines, "warning")) + + # Test that warnings are produced for the incorrectly structured packages. + for package in ["x", "y", "z"]: + cd "packageStructure/" & package: + let (output, exitCode) = execNimble(["install", "-y"]) + check exitCode == QuitSuccess + let lines = output.strip.splitLines() + case package + of "x": + check inLines(lines, "File 'foobar.nim' inside package 'x' is outside" & + " of the permitted namespace, should be inside a" & + " directory named 'x' but is in a directory named" & + " 'incorrect' instead.") + of "y": + check inLines(lines, "File 'foobar.nim' inside package 'y' is outside" & + " of the permitted namespace, should be inside a" & + " directory named 'ypkg' but is in a directory" & + " named 'yWrong' instead.") + of "z": + check inLines(lines, "File inside package 'z' is outside of permitted" & + " namespace, should be named 'z.nim' but was" & + " named 'incorrect.nim' instead.") + else: + assert false + + # Clear nimble dir. + removeDir(installDir) + createDir(installDir) + test "issue 129 (installing commit hash)": let arguments = @["install", "-y", "https://github.com/nimble-test/packagea.git@#1f9cb289c89"] From 8453a4e2de8c0f87df5b4c14d28902fda547f788 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 26 Dec 2016 23:59:51 +0000 Subject: [PATCH 115/424] Add missing test files. --- tests/packageStructure/a/a.nim | 1 + tests/packageStructure/a/a.nimble | 11 +++++++++++ tests/packageStructure/b/b.nim | 1 + tests/packageStructure/b/b.nimble | 11 +++++++++++ tests/packageStructure/b/b/foobar.nim | 1 + tests/packageStructure/c/c.nim | 1 + tests/packageStructure/c/c.nimble | 13 +++++++++++++ tests/packageStructure/c/cpkg/foobar.nim | 1 + tests/packageStructure/x/incorrect/foobar.nim | 0 tests/packageStructure/x/x.nimble | 11 +++++++++++ tests/packageStructure/y/y.nim | 0 tests/packageStructure/y/y.nimble | 13 +++++++++++++ tests/packageStructure/y/yWrong/foobar.nim | 1 + tests/packageStructure/z/incorrect.nim | 0 tests/packageStructure/z/z.nimble | 11 +++++++++++ 15 files changed, 76 insertions(+) create mode 100644 tests/packageStructure/a/a.nim create mode 100644 tests/packageStructure/a/a.nimble create mode 100644 tests/packageStructure/b/b.nim create mode 100644 tests/packageStructure/b/b.nimble create mode 100644 tests/packageStructure/b/b/foobar.nim create mode 100644 tests/packageStructure/c/c.nim create mode 100644 tests/packageStructure/c/c.nimble create mode 100644 tests/packageStructure/c/cpkg/foobar.nim create mode 100644 tests/packageStructure/x/incorrect/foobar.nim create mode 100644 tests/packageStructure/x/x.nimble create mode 100644 tests/packageStructure/y/y.nim create mode 100644 tests/packageStructure/y/y.nimble create mode 100644 tests/packageStructure/y/yWrong/foobar.nim create mode 100644 tests/packageStructure/z/incorrect.nim create mode 100644 tests/packageStructure/z/z.nimble diff --git a/tests/packageStructure/a/a.nim b/tests/packageStructure/a/a.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/a/a.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/a/a.nimble b/tests/packageStructure/a/a.nimble new file mode 100644 index 0000000..d68102b --- /dev/null +++ b/tests/packageStructure/a/a.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package A" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/packageStructure/b/b.nim b/tests/packageStructure/b/b.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/b/b.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/b/b.nimble b/tests/packageStructure/b/b.nimble new file mode 100644 index 0000000..f9bdb47 --- /dev/null +++ b/tests/packageStructure/b/b.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package B" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/packageStructure/b/b/foobar.nim b/tests/packageStructure/b/b/foobar.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/b/b/foobar.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/c/c.nim b/tests/packageStructure/c/c.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/c/c.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/c/c.nimble b/tests/packageStructure/c/c.nimble new file mode 100644 index 0000000..54b0d2f --- /dev/null +++ b/tests/packageStructure/c/c.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package C" +license = "MIT" + +bin = @["c"] + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/packageStructure/c/cpkg/foobar.nim b/tests/packageStructure/c/cpkg/foobar.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/c/cpkg/foobar.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/x/incorrect/foobar.nim b/tests/packageStructure/x/incorrect/foobar.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/x/x.nimble b/tests/packageStructure/x/x.nimble new file mode 100644 index 0000000..68093e0 --- /dev/null +++ b/tests/packageStructure/x/x.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Incorrectly structured package X." +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/packageStructure/y/y.nim b/tests/packageStructure/y/y.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/y/y.nimble b/tests/packageStructure/y/y.nimble new file mode 100644 index 0000000..0a0f954 --- /dev/null +++ b/tests/packageStructure/y/y.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Incorrectly structured package Y" +license = "MIT" + +bin = @["y"] + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/packageStructure/y/yWrong/foobar.nim b/tests/packageStructure/y/yWrong/foobar.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/y/yWrong/foobar.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/z/incorrect.nim b/tests/packageStructure/z/incorrect.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/z/z.nimble b/tests/packageStructure/z/z.nimble new file mode 100644 index 0000000..226bc7f --- /dev/null +++ b/tests/packageStructure/z/z.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Incorrect package structure Z." +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + From d192de65117346cab15217c71aa4c0b1814b9072 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 00:42:05 +0000 Subject: [PATCH 116/424] Fixes version conflicts when building between special&non-special. Refs #289. Aporia still cannot be installed. In addition, the myVersion vs. version should be refactored into version vs. specialVersion. --- src/nimble.nim | 9 +++++---- src/nimblepkg/common.nim | 7 +++++-- src/nimblepkg/packageinfo.nim | 3 ++- src/nimblepkg/packageparser.nim | 16 ++++++++++++---- tests/issue289/issue289.nim | 1 + tests/issue289/issue289.nimble | 14 ++++++++++++++ tests/tester.nim | 8 ++++++++ 7 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 tests/issue289/issue289.nim create mode 100644 tests/issue289/issue289.nimble diff --git a/src/nimble.nim b/src/nimble.nim index c5b0491..0300158 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -296,12 +296,13 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = # in the path. var pkgsInPath: StringTableRef = newStringTable(modeCaseSensitive) for p in result: - let (name, version) = getNameVersion(p) - if pkgsInPath.hasKey(name) and pkgsInPath[name] != version: + let pkgInfo = getPkgInfo(p, options) + if pkgsInPath.hasKey(pkgInfo.name) and + pkgsInPath[pkgInfo.name] != pkgInfo.myVersion: raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % - [name, version, pkgsInPath[name]]) - pkgsInPath[name] = version + [pkgInfo.name, pkgInfo.myVersion, pkgsInPath[pkgInfo.name]]) + pkgsInPath[pkgInfo.name] = pkgInfo.myVersion # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 1f5c39a..9d1002d 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -14,14 +14,17 @@ when not defined(nimscript): BuildFailed* = object of NimbleError PackageInfo* = object - mypath*: string ## The path of this .nimble file + myPath*: string ## The path of this .nimble file + ## The version specified in the .nimble file.Assuming info is non-minimal, + ## it will always be a non-special version such as '0.1.4' + myVersion*: string isNimScript*: bool ## Determines if this pkg info was read from a nims file isMinimal*: bool isInstalled*: bool ## Determines if the pkg this info belongs to is installed postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily preHooks*: HashSet[string] name*: string - version*: string + version*: string ## Either `myVersion` or a special version such as #head. author*: string description*: string license*: string diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 9de81ba..cdbe4ff 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -21,7 +21,8 @@ type url*: string proc initPackageInfo*(path: string): PackageInfo = - result.mypath = path + result.myPath = path + result.myVersion = "" result.preHooks.init() result.postHooks.init() # reasonable default: diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index b860228..3d4a6b4 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -248,6 +248,8 @@ proc readPackageInfo(nf: NimbleFile, options: Options, ## times on the same ``nf`` shouldn't require re-evaluation of the Nimble ## file. + assert fileExists(nf) + # Check the cache. if options.pkgInfoCache.hasKey(nf): return options.pkgInfoCache[nf] @@ -286,6 +288,7 @@ proc readPackageInfo(nf: NimbleFile, options: Options, raise newException(NimbleError, msg) # Validate version ahead of time, we will be potentially overwriting it soon. + result.myVersion = result.version validateVersion(result.version) # The package directory name may include a "special" version @@ -301,11 +304,11 @@ proc readPackageInfo(nf: NimbleFile, options: Options, # Validate the rest of the package info last. validatePackageInfo(result, options) -proc getPkgInfo*(dir: string, options: Options): PackageInfo = - ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo. - let nimbleFile = findNimbleFile(dir, true) +proc getPkgInfoFromFile*(file: NimbleFile, options: Options): PackageInfo = + ## Reads the specified .nimble file and returns its data as a PackageInfo + ## object. Any validation errors are handled and displayed as warnings. try: - result = readPackageInfo(nimbleFile, options) + result = readPackageInfo(file, options) except ValidationError: let exc = (ref ValidationError)(getCurrentException()) if exc.warnAll: @@ -314,6 +317,11 @@ proc getPkgInfo*(dir: string, options: Options): PackageInfo = else: raise +proc getPkgInfo*(dir: string, options: Options): PackageInfo = + ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo. + let nimbleFile = findNimbleFile(dir, true) + getPkgInfoFromFile(nimbleFile, options) + proc getInstalledPkgs*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = ## Gets a list of installed packages. diff --git a/tests/issue289/issue289.nim b/tests/issue289/issue289.nim new file mode 100644 index 0000000..10c5f66 --- /dev/null +++ b/tests/issue289/issue289.nim @@ -0,0 +1 @@ +echo 42 diff --git a/tests/issue289/issue289.nimble b/tests/issue289/issue289.nimble new file mode 100644 index 0000000..ab9aec8 --- /dev/null +++ b/tests/issue289/issue289.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Package reproducing issues depending on #head and concrete version of the same package." +license = "MIT" + +bin = @["issue289"] + +# Dependencies + +requires "nim >= 0.15.3", "https://github.com/nimble-test/packagea.git 0.6.0" +requires "https://github.com/nimble-test/packagea.git#head" + diff --git a/tests/tester.nim b/tests/tester.nim index 2c4be73..266811b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -41,6 +41,14 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "can build with #head and versioned package (#289)": + # Clear nimble dir. + removeDir(installDir) + createDir(installDir) + + cd "issue289": + check execNimble(["install", "-y"]).exitCode == QuitSuccess + test "can validate package structure (#144)": # Clear nimble dir. removeDir(installDir) From 2886059817298ab6c4481cc843c79219f39fd204 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 12:19:13 +0000 Subject: [PATCH 117/424] Fixes #289. --- src/nimble.nim | 6 +++--- src/nimblepkg/packageinfo.nim | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 0300158..4d026d0 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -298,11 +298,11 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for p in result: let pkgInfo = getPkgInfo(p, options) if pkgsInPath.hasKey(pkgInfo.name) and - pkgsInPath[pkgInfo.name] != pkgInfo.myVersion: + pkgsInPath[pkgInfo.name] != pkgInfo.version: raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % - [pkgInfo.name, pkgInfo.myVersion, pkgsInPath[pkgInfo.name]]) - pkgsInPath[pkgInfo.name] = pkgInfo.myVersion + [pkgInfo.name, pkgInfo.version, pkgsInPath[pkgInfo.name]]) + pkgsInPath[pkgInfo.name] = pkgInfo.version # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index cdbe4ff..573d504 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -211,8 +211,9 @@ proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]], for pkg in pkglist: if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue - if withinRange(newVersion(pkg.pkginfo.version), dep.ver): - if not result or newVersion(r.version) < newVersion(pkg.pkginfo.version): + if withinRange(newVersion(pkg.pkginfo.myVersion), dep.ver) or + withinRange(newVersion(pkg.pkginfo.version), dep.ver): + if not result or newVersion(r.version) < newVersion(pkg.pkginfo.myVersion): r = pkg.pkginfo result = true From 432c91b938d211b1fbd87dba72246da859fb352e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 13:27:08 +0000 Subject: [PATCH 118/424] Renamed myVersion to version and version to specialVersion. --- src/nimble.nim | 36 ++++++++++++++++----------------- src/nimblepkg/common.nim | 8 ++++---- src/nimblepkg/packageinfo.nim | 25 +++++++++++++++-------- src/nimblepkg/packageparser.nim | 8 +++----- tests/tester.nim | 1 + 5 files changed, 43 insertions(+), 35 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 4d026d0..920196c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -210,7 +210,7 @@ proc addRevDep(options: Options, dep: tuple[name, version: string], options.nimbleData["reverseDeps"][dep.name] = newJObject() if not options.nimbleData["reverseDeps"][dep.name].hasKey(dep.version): options.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray() - let revDep = %{ "name": %pkg.name, "version": %pkg.version} + let revDep = %{ "name": %pkg.name, "version": %pkg.specialVersion} let thisDep = options.nimbleData["reverseDeps"][dep.name][dep.version] if revDep notin thisDep: thisDep.add revDep @@ -225,7 +225,7 @@ proc removeRevDep(options: Options, pkg: PackageInfo) = var newVal = newJArray() for revDep in val: if not (revDep["name"].str == pkg.name and - revDep["version"].str == pkg.version): + revDep["version"].str == pkg.specialVersion): newVal.add revDep thisDep[ver] = newVal @@ -263,7 +263,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = result = @[] assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires") display("Verifying", - "dependencies for $1@$2" % [pkginfo.name, pkginfo.version], + "dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion], priority = HighPriority) let pkglist = getInstalledPkgs(options.getPkgsDir(), options) @@ -290,7 +290,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = result.add(pkg.mypath.splitFile.dir) # Process the dependencies of this dependency. result.add(processDeps(pkg, options)) - reverseDeps.add((pkg.name, pkg.version)) + reverseDeps.add((pkg.name, pkg.specialVersion)) # Check if two packages of the same name (but different version) are listed # in the path. @@ -298,11 +298,11 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for p in result: let pkgInfo = getPkgInfo(p, options) if pkgsInPath.hasKey(pkgInfo.name) and - pkgsInPath[pkgInfo.name] != pkgInfo.version: + pkgsInPath[pkgInfo.name] != pkgInfo.specialVersion: raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % - [pkgInfo.name, pkgInfo.version, pkgsInPath[pkgInfo.name]]) - pkgsInPath[pkgInfo.name] = pkgInfo.version + [pkgInfo.name, pkgInfo.specialVersion, pkgsInPath[pkgInfo.name]]) + pkgsInPath[pkgInfo.name] = pkgInfo.specialVersion # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs @@ -406,7 +406,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Overwrite the version if the requested version is "#head" or similar. if requestedVer.kind == verSpecial: - pkgInfo.version = $requestedVer.spe + pkgInfo.specialVersion = $requestedVer.spe # Dependencies need to be processed before the creation of the pkg dir. result.paths = processDeps(pkginfo, depsOptions) @@ -415,14 +415,14 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, result.pkg = pkgInfo return result - display("Installing", "$1 $2" % [pkginfo.name, pkginfo.version], + display("Installing", "$1@$2" % [pkginfo.name, pkginfo.specialVersion], priority = HighPriority) # Build before removing an existing package (if one exists). This way # if the build fails then the old package will still be installed. if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) - let versionStr = '-' & pkgInfo.version + let versionStr = '-' & pkgInfo.specialVersion let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): @@ -713,7 +713,7 @@ proc listInstalled(options: Options) = for x in pkgs.items(): let pName = x.pkginfo.name - pVer = x.pkginfo.version + pVer = x.pkginfo.specialVersion if not h.hasKey(pName): h[pName] = @[] var s = h[pName] add(s, pVer) @@ -755,8 +755,8 @@ proc listPaths(options: Options) = if hasSpec: var pkgInfo = getPkgInfo(path, options) var v: VersionAndPath - v.version = newVersion(pkgInfo.version) - v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version) + v.version = newVersion(pkgInfo.specialVersion) + v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.specialVersion) installed.add(v) else: display("Warning:", "No .nimble file found for " & path, Warning, @@ -891,7 +891,7 @@ proc uninstall(options: Options) = for pkg in pkgList: # Check whether any packages depend on the ones the user is trying to # uninstall. - let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.version} + let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.specialVersion} if not thisPkgsDep.isNil: var reason = "" if thisPkgsDep.len == 1: @@ -905,7 +905,7 @@ proc uninstall(options: Options) = reason.add ", " reason.add " depend on it" errors.add("Cannot uninstall $1 ($2) because $3" % [pkgTup.name, - pkg.version, reason]) + pkg.specialVersion, reason]) else: pkgsToDelete.add pkg @@ -916,7 +916,7 @@ proc uninstall(options: Options) = for i in 0 .. ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) + echo(result.output) proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) From 53856db8ff11ae1e73495801fa9c93895c04e93f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 13:54:54 +0000 Subject: [PATCH 119/424] Fixes tests. --- src/nimble.nim | 8 ++++---- src/nimblepkg/packageparser.nim | 4 +++- tests/issue289/issue289.nimble | 2 +- tests/packageStructure/a/a.nimble | 2 +- tests/packageStructure/b/b.nimble | 2 +- tests/packageStructure/c/c.nimble | 2 +- tests/packageStructure/x/x.nimble | 2 +- tests/packageStructure/y/y.nimble | 2 +- tests/packageStructure/z/z.nimble | 2 +- tests/tester.nim | 1 - 10 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 920196c..3f9abdc 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -298,11 +298,11 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for p in result: let pkgInfo = getPkgInfo(p, options) if pkgsInPath.hasKey(pkgInfo.name) and - pkgsInPath[pkgInfo.name] != pkgInfo.specialVersion: + pkgsInPath[pkgInfo.name] != pkgInfo.version: raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % - [pkgInfo.name, pkgInfo.specialVersion, pkgsInPath[pkgInfo.name]]) - pkgsInPath[pkgInfo.name] = pkgInfo.specialVersion + [pkgInfo.name, pkgInfo.version, pkgsInPath[pkgInfo.name]]) + pkgsInPath[pkgInfo.name] = pkgInfo.version # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs @@ -409,7 +409,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, pkgInfo.specialVersion = $requestedVer.spe # Dependencies need to be processed before the creation of the pkg dir. - result.paths = processDeps(pkginfo, depsOptions) + result.paths = processDeps(pkgInfo, depsOptions) if options.depsOnly: result.pkg = pkgInfo diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 2f89c88..f3ead77 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -273,7 +273,6 @@ proc readPackageInfo(nf: NimbleFile, options: Options, if onlyMinimalInfo: result.name = minimalInfo.name result.version = minimalInfo.version - result.specialVersion = result.version result.isNimScript = true result.isMinimal = true else: @@ -288,6 +287,9 @@ proc readPackageInfo(nf: NimbleFile, options: Options, " " & getCurrentExceptionMsg() & "." raise newException(NimbleError, msg) + # By default specialVersion is the same as version. + result.specialVersion = result.version + # The package directory name may include a "special" version # (example #head). If so, it is given higher priority and therefore # overwrites the .nimble file's version. diff --git a/tests/issue289/issue289.nimble b/tests/issue289/issue289.nimble index ab9aec8..bd90b3b 100644 --- a/tests/issue289/issue289.nimble +++ b/tests/issue289/issue289.nimble @@ -9,6 +9,6 @@ bin = @["issue289"] # Dependencies -requires "nim >= 0.15.3", "https://github.com/nimble-test/packagea.git 0.6.0" +requires "nim >= 0.15.0", "https://github.com/nimble-test/packagea.git 0.6.0" requires "https://github.com/nimble-test/packagea.git#head" diff --git a/tests/packageStructure/a/a.nimble b/tests/packageStructure/a/a.nimble index d68102b..fd6878a 100644 --- a/tests/packageStructure/a/a.nimble +++ b/tests/packageStructure/a/a.nimble @@ -7,5 +7,5 @@ license = "MIT" # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/packageStructure/b/b.nimble b/tests/packageStructure/b/b.nimble index f9bdb47..ce659ef 100644 --- a/tests/packageStructure/b/b.nimble +++ b/tests/packageStructure/b/b.nimble @@ -7,5 +7,5 @@ license = "MIT" # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/packageStructure/c/c.nimble b/tests/packageStructure/c/c.nimble index 54b0d2f..88cfb84 100644 --- a/tests/packageStructure/c/c.nimble +++ b/tests/packageStructure/c/c.nimble @@ -9,5 +9,5 @@ bin = @["c"] # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/packageStructure/x/x.nimble b/tests/packageStructure/x/x.nimble index 68093e0..51ebde2 100644 --- a/tests/packageStructure/x/x.nimble +++ b/tests/packageStructure/x/x.nimble @@ -7,5 +7,5 @@ license = "MIT" # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/packageStructure/y/y.nimble b/tests/packageStructure/y/y.nimble index 0a0f954..0ce52f9 100644 --- a/tests/packageStructure/y/y.nimble +++ b/tests/packageStructure/y/y.nimble @@ -9,5 +9,5 @@ bin = @["y"] # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/packageStructure/z/z.nimble b/tests/packageStructure/z/z.nimble index 226bc7f..f872d3c 100644 --- a/tests/packageStructure/z/z.nimble +++ b/tests/packageStructure/z/z.nimble @@ -7,5 +7,5 @@ license = "MIT" # Dependencies -requires "nim >= 0.15.3" +requires "nim >= 0.15.0" diff --git a/tests/tester.nim b/tests/tester.nim index ce30768..266811b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -33,7 +33,6 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) - echo(result.output) proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) From 40e3abb91112d93df6b86a2dd52c4cbb90e7226e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 15:42:01 +0000 Subject: [PATCH 120/424] Attempt to workaround Nim 0.15.2 problem for tests. --- tests/tester.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 266811b..19e7943 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -51,8 +51,8 @@ test "can build with #head and versioned package (#289)": test "can validate package structure (#144)": # Clear nimble dir. - removeDir(installDir) - createDir(installDir) + #removeDir(installDir) + #createDir(installDir) # Test that no warnings are produced for correctly structured packages. for package in ["a", "b", "c"]: From 87f4ad106a9374b108b77b6c38602dd7dcd97b46 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 15:51:05 +0000 Subject: [PATCH 121/424] Fix the tests correctly this time (hopefully). --- tests/tester.nim | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 19e7943..4ac3ce7 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -51,8 +51,8 @@ test "can build with #head and versioned package (#289)": test "can validate package structure (#144)": # Clear nimble dir. - #removeDir(installDir) - #createDir(installDir) + removeDir(installDir) + createDir(installDir) # Test that no warnings are produced for correctly structured packages. for package in ["a", "b", "c"]: @@ -86,10 +86,6 @@ test "can validate package structure (#144)": else: assert false - # Clear nimble dir. - removeDir(installDir) - createDir(installDir) - test "issue 129 (installing commit hash)": let arguments = @["install", "-y", "https://github.com/nimble-test/packagea.git@#1f9cb289c89"] From 736ed97974c0b78210c7113d74b40e6602598072 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 27 Dec 2016 16:28:45 +0000 Subject: [PATCH 122/424] Fixes tests once and for all. --- tests/tester.nim | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 4ac3ce7..4d73b1b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -42,18 +42,13 @@ proc inLines(lines: seq[string], line: string): bool = if line.normalize in i.normalize: return true test "can build with #head and versioned package (#289)": - # Clear nimble dir. - removeDir(installDir) - createDir(installDir) - cd "issue289": check execNimble(["install", "-y"]).exitCode == QuitSuccess -test "can validate package structure (#144)": - # Clear nimble dir. - removeDir(installDir) - createDir(installDir) + check execNimble(["uninstall", "issue289", "-y"]).exitCode == QuitSuccess + check execNimble(["uninstall", "packagea", "-y"]).exitCode == QuitSuccess +test "can validate package structure (#144)": # Test that no warnings are produced for correctly structured packages. for package in ["a", "b", "c"]: cd "packageStructure/" & package: From 26755c0183dd156b83a2b14d92067215ead45a80 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Wed, 28 Dec 2016 00:08:05 +0100 Subject: [PATCH 123/424] hotfix: make nimble compile with latest compiler version --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 3f9abdc..fe28bdf 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -763,7 +763,7 @@ proc listPaths(options: Options) = MediumPriority) if installed.len > 0: - sort(installed, system.cmp[VersionAndPath], Descending) + sort(installed, cmp[VersionAndPath], Descending) # The output for this command is used by tools so we do not use display(). echo installed[0].path else: From ff82fc2536bc50b13cda462140918faeafaa3123 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 28 Dec 2016 15:50:31 +0000 Subject: [PATCH 124/424] Fixes #286. --- src/nimble.nim | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index fe28bdf..d63edc3 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -338,7 +338,15 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = raise newException(BuildFailed, "Build failed for package: " & pkgInfo.name) -proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, filesInstalled: HashSet[string]) = +proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, + filesInstalled, bins: HashSet[string]) = + ## Saves the specified data into a ``nimblemeta.json`` file inside + ## ``pkgDestDir``. + ## + ## filesInstalled - A list of absolute paths to files which have been + ## installed. + ## bins - A list of binary filenames which have been installed for this + ## package. var nimblemeta = %{"url": %url} if not vcsRevision.isNil: nimblemeta["vcsRevision"] = %vcsRevision @@ -346,6 +354,10 @@ proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, filesInstalled: HashSe nimblemeta["files"] = files for file in filesInstalled: files.add(%changeRoot(pkgDestDir, "", file)) + let binaries = newJArray() + nimblemeta["binaries"] = binaries + for bin in bins: + binaries.add(%bin) writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) proc removePkgDir(dir: string, options: Options) = @@ -366,6 +378,15 @@ proc removePkgDir(dir: string, options: Options) = else: display("Warning:", ("Cannot completely remove $1. Files not installed " & "by nimble are present.") % dir, Warning, HighPriority) + + # Remove binaries. + if nimblemeta.hasKey("binaries"): + for binary in nimblemeta["binaries"]: + removeFile(options.getBinDir() / binary.str) + else: + display("Warning:", ("Cannot completely remove $1. Binary symlinks may " & + "have been left over in $2.") % + [dir, options.getBinDir()]) except OSError, JsonParsingError: display("Warning", "Unable to read nimblemeta.json: " & getCurrentExceptionMsg(), Warning, HighPriority) @@ -436,9 +457,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, when defined(windows): removeFile(binDir / bin.changeFileExt("cmd")) removeFile(binDir / bin.changeFileExt("")) - # TODO: Remove this later. - # Remove .bat file too from previous installs. - removeFile(binDir / bin.changeFileExt("bat")) else: removeFile(binDir / bin) @@ -456,6 +474,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, pkgInfo.mypath) filesInstalled.incl copyFileD(pkgInfo.mypath, dest) + var binariesInstalled = initSet[string]() if pkgInfo.bin.len > 0: # Make sure ~/.nimble/bin directory is created. createDir(binDir) @@ -470,12 +489,10 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) let cleanBin = bin.extractFilename when defined(unix): - # TODO: Verify that we are removing an old bin of this package, not - # some other package's binary! - if existsFile(binDir / cleanBin): removeFile(binDir / cleanBin) display("Creating", "symlink: $1 -> $2" % [pkgDestDir / bin, binDir / cleanBin], priority = MediumPriority) createSymlink(pkgDestDir / bin, binDir / cleanBin) + binariesInstalled.incl(cleanBin) elif defined(windows): # There is a bug on XP, described here: # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called @@ -487,6 +504,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, "Can't detect OS version: GetVersionExA call failed") let fixChcp = osver.dwMajorVersion <= 5 + # Create cmd.exe/powershell stub. let dest = binDir / cleanBin.changeFileExt("cmd") display("Creating", "stub: $1 -> $2" % [pkgDestDir / bin, dest], priority = MediumPriority) @@ -497,18 +515,21 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, else: contents.add "chcp 65001 > nul\n@" contents.add "\"" & pkgDestDir / bin & "\" %*\n" writeFile(dest, contents) + binariesInstalled.incl(dest.extractFilename) # For bash on Windows (Cygwin/Git bash). let bashDest = dest.changeFileExt("") display("Creating", "Cygwin stub: $1 -> $2" % [pkgDestDir / bin, bashDest], priority = MediumPriority) writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") + binariesInstalled.incl(bashDest.extractFilename) else: {.error: "Sorry, your platform is not supported.".} let vcsRevision = vcsRevisionInDir(realDir) # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, url, vcsRevision, filesInstalled) + saveNimbleMeta(pkgDestDir, url, vcsRevision, filesInstalled, + binariesInstalled) # Save the nimble data (which might now contain reverse deps added in # processDeps). From 4332fb45cbcd7e8299daee7dccc9d4813f2711e1 Mon Sep 17 00:00:00 2001 From: Dmitry Polienko Date: Thu, 29 Dec 2016 17:57:13 +0700 Subject: [PATCH 125/424] Fix git ls-remote parsing --- src/nimblepkg/download.nim | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index cedd648..ea6cff6 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -91,8 +91,10 @@ proc getTagsListRemote*(url: string, meth: DownloadMethod): seq[string] = raise newException(OSError, "Unable to query remote tags for " & url & ". Git returned: " & output) for i in output.splitLines(): - if i == "": continue - let start = i.find("refs/tags/")+"refs/tags/".len + let refStart = i.find("refs/tags/") + # git outputs warnings, empty lines, etc + if refStart == -1: continue + let start = refStart+"refs/tags/".len let tag = i[start .. i.len-1] if not tag.endswith("^{}"): result.add(tag) From 767aaf56d0ca77f5b8bbbf874aa7d9a71534b093 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 29 Dec 2016 14:31:05 +0000 Subject: [PATCH 126/424] Improves readme and adds info about repo branches. --- readme.markdown | 81 +++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/readme.markdown b/readme.markdown index 731f4d0..29c989e 100644 --- a/readme.markdown +++ b/readme.markdown @@ -10,7 +10,6 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Requirements](#requirements) - [Installation](#installation) -- [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages) - [Nimble usage](#nimble-usage) - [nimble refresh](#nimble-refresh) - [nimble install](#nimble-install) @@ -43,6 +42,8 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [[Deps]/[Dependencies]](#depsdependencies) - [Optional](#optional) - [Troubleshooting](#troubleshooting) +- [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages) +- [Repository information](#repository-information) - [Contribution](#contribution) - [About](#about) @@ -103,19 +104,6 @@ This will install Nimble to the default Nimble packages location: ``~/.nimble/pkgs``. The binary will be installed to ``~/.nimble/bin``, so you will need to add this directory to your PATH. -## Nimble's folder structure and packages - -Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems -and in your ``$home/.nimble`` on Windows. Libraries are stored in -``$nimbleDir/pkgs``, and binaries are stored in ``$nimbleDir/bin``. Most Nimble -packages will provide ``.nim`` files and some documentation. The Nim -compiler is aware of Nimble and will automatically find the modules so you can -``import modulename`` and have that working without additional setup. - -However, some Nimble packages can provide additional tools or commands. If you -don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not -work properly and you won't be able to run them. - ## Nimble usage Once you have Nimble installed on your system you can run the ``nimble`` command @@ -517,9 +505,9 @@ structure may be enforced in the future. All files and folders in the directory of where the .nimble file resides will be copied as-is, you can however skip some directories or files by setting -the ``SkipDirs``, ``SkipFiles`` or ``SkipExt`` options in your .nimble file. +the ``skipDirs``, ``skipFiles`` or ``skipExt`` options in your .nimble file. Directories and files can also be specified on a *whitelist* basis, if you -specify either of ``InstallDirs``, ``InstallFiles`` or ``InstallExt`` then +specify either of ``installDirs``, ``installFiles`` or ``installExt`` then Nimble will **only** install the files specified. ### Binary packages @@ -540,7 +528,7 @@ created instead. Other files will be copied in the same way as they are for library packages. Binary packages should not install .nim files so include -``SkipExt = "nim"`` in your .nimble file, unless you intend for your package to +``skipExt = @["nim"]`` in your .nimble file, unless you intend for your package to be a binary/library combo which is fine. Dependencies are automatically installed before building. @@ -672,25 +660,25 @@ Nimble includes a ``publish`` command which does this for you automatically. #### Optional -* ``SkipDirs`` - A list of directory names which should be skipped during +* ``skipDirs`` - A list of directory names which should be skipped during installation, separated by commas. -* ``SkipFiles`` - A list of file names which should be skipped during +* ``skipFiles`` - A list of file names which should be skipped during installation, separated by commas. -* ``SkipExt`` - A list of file extensions which should be skipped during +* ``skipExt`` - A list of file extensions which should be skipped during installation, the extensions should be specified without a leading ``.`` and should be separated by commas. -* ``InstallDirs`` - A list of directories which should exclusively be installed, +* ``installDirs`` - A list of directories which should exclusively be installed, if this option is specified nothing else will be installed except the dirs - listed here, the files listed in ``InstallFiles``, the files which share the - extensions listed in ``InstallExt``, the .nimble file and the binary + listed here, the files listed in ``installFiles``, the files which share the + extensions listed in ``installExt``, the .nimble file and the binary (if ``bin`` is specified). Separated by commas. -* ``InstallFiles`` - A list of files which should be exclusively installed, - this complements ``InstallDirs`` and ``InstallExt``. Only the files listed - here, directories listed in ``InstallDirs``, files which share the extension - listed in ``InstallExt``, the .nimble file and the binary (if ``bin`` is +* ``installFiles`` - A list of files which should be exclusively installed, + this complements ``installDirs`` and ``installExt``. Only the files listed + here, directories listed in ``installDirs``, files which share the extension + listed in ``installExt``, the .nimble file and the binary (if ``bin`` is specified) will be installed. Separated by commas. -* ``InstallExt`` - A list of file extensions which should be exclusively - installed, this complements ``InstallDirs`` and ``InstallFiles``. +* ``installExt`` - A list of file extensions which should be exclusively + installed, this complements ``installDirs`` and ``installFiles``. Separated by commas. * ``srcDir`` - Specifies the directory which contains the .nim source files. **Default**: The directory in which the .nimble file resides; i.e. root dir of @@ -716,6 +704,19 @@ Nimble includes a ``publish`` command which does this for you automatically. **Example**: ``nim >= 0.10.0, jester``; with this value your package will depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``. +## Nimble's folder structure and packages + +Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems +and in your ``$home/.nimble`` on Windows. Libraries are stored in +``$nimbleDir/pkgs``, and binaries are stored in ``$nimbleDir/bin``. Most Nimble +packages will provide ``.nim`` files and some documentation. The Nim +compiler is aware of Nimble and will automatically find the modules so you can +``import modulename`` and have that working without additional setup. + +However, some Nimble packages can provide additional tools or commands. If you +don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not +work properly and you won't be able to run them. + ## Troubleshooting * ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]``` @@ -725,6 +726,28 @@ flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. +## Repository information + +This repository has two main branches: ``master`` and ``stable``. + +The ``master`` branch is... + +* default +* bleeding edge +* tested to compile with the latest Nim version + +The ``stable`` branch is... + +* installed by ``koch tools``/``koch nimble`` +* relatively stable +* should compile with Nim HEAD as well as the latest Nim version + +Note: The travis build only tests whether Nimble works with the latest Nim +version. + +A new Nim release (via ``koch xz``) will always bundle the latest tagged +Nimble release. + ## Contribution If you would like to help, feel free to fork and make any additions you see fit From 3d4d751a48967f4fc46ff9e16fecab97b88e66be Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 29 Dec 2016 15:19:26 +0000 Subject: [PATCH 127/424] Fixes #247. --- src/nimble.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index d63edc3..6cb744a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -482,8 +482,13 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # and symlink them on *nix OS' to $nimbleDir/bin/ for bin in pkgInfo.bin: if not existsFile(pkgDestDir / bin): - filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), - pkgDestDir / bin) + display("Warning:", ("Binary '$1' was already installed from source" & + " directory. Will be overwritten.") % bin, Warning, + HighPriority) + + # Copy the binary file. + filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), + pkgDestDir / bin) let currentPerms = getFilePermissions(pkgDestDir / bin) setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) From 039bc0e1c1431c2cb826067ebc0a9a36286b5ea5 Mon Sep 17 00:00:00 2001 From: Dmitry Polienko Date: Fri, 30 Dec 2016 14:47:48 +0700 Subject: [PATCH 128/424] Change dump to use fuzzy matching on argument --- src/nimble.nim | 24 +++++++++++++++++++++++- tests/testdump/testdump.nimble | 4 ++++ tests/tester.nim | 28 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/testdump/testdump.nimble diff --git a/src/nimble.nim b/src/nimble.nim index 6cb744a..36b1f4e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -807,8 +807,30 @@ proc join(x: seq[PkgTuple]; y: string): string = result.add y result.add x[i][0] & " " & $x[i][1] +proc getPackageByPattern(pattern: string, options: Options): PackageInfo = + ## Search for a package file using multiple strategies. + if pattern == "": + # Not specified - using current directory + result = getPkgInfo(os.getCurrentDir(), options) + elif pattern.splitFile.ext == ".nimble" and pattern.existsFile: + # project file specified + result = getPkgInfoFromFile(pattern, options) + elif pattern.existsDir: + # project directory specified + result = getPkgInfo(pattern, options) + else: + # Last resort - attempt to read as package identifier + let packages = getInstalledPkgsMin(options.getPkgsDir(), options) + let identTuple = parseRequires(pattern) + var skeletonInfo: PackageInfo + if not findPkg(packages, identTuple, skeletonInfo): + raise newException(NimbleError, + "Specified package not found" + ) + result = getPkgInfoFromFile(skeletonInfo.myPath, options) + proc dump(options: Options) = - let p = getPkgInfo(os.getCurrentDir(), options) + let p = getPackageByPattern(options.action.projName, options) echo "name: ", p.name.escape echo "version: ", p.version.escape echo "author: ", p.author.escape diff --git a/tests/testdump/testdump.nimble b/tests/testdump/testdump.nimble new file mode 100644 index 0000000..630b52a --- /dev/null +++ b/tests/testdump/testdump.nimble @@ -0,0 +1,4 @@ +description = "Test package for dump command" +version = "0.1.0" +author = "nigredo-tori" +license = "BSD" diff --git a/tests/tester.nim b/tests/tester.nim index 4d73b1b..ea1daa5 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -299,3 +299,31 @@ test "can uninstall": check(not dirExists(installDir / "pkgs" / "PackageA-0.2.0")) check execNimble("uninstall", "-y", "nimscript").exitCode == QuitSuccess + +test "can dump for current project": + cd "testdump": + let (outp, exitCode) = execNimble("dump") + check: exitCode == 0 + check: outp.processOutput.inLines("desc: \"Test package for dump command\"") + +test "can dump for project directory": + let (outp, exitCode) = execNimble("dump", "testdump") + check: exitCode == 0 + check: outp.processOutput.inLines("desc: \"Test package for dump command\"") + +test "can dump for project file": + let (outp, exitCode) = execNimble("dump", "testdump" / "testdump.nimble") + check: exitCode == 0 + check: outp.processOutput.inLines("desc: \"Test package for dump command\"") + +test "can dump for installed package": + cd "testdump": + check: execNimble("install", "-y").exitCode == 0 + defer: + discard execNimble("remove", "-y", "testdump") + + # Otherwise we might find subdirectory instead + cd "..": + let (outp, exitCode) = execNimble("dump", "testdump") + check: exitCode == 0 + check: outp.processOutput.inLines("desc: \"Test package for dump command\"") From 871252d2025ccc9330bfdaec6042ac0cab21ab77 Mon Sep 17 00:00:00 2001 From: Dmitry Polienko Date: Fri, 30 Dec 2016 14:52:26 +0700 Subject: [PATCH 129/424] Update usage message --- src/nimblepkg/options.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 809ce14..9d65398 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -74,7 +74,10 @@ Commands: path pkgname ... Shows absolute path to the installed packages specified. dump [pkgname] Outputs Nimble package information for - external tools. + external tools. The argument can be a + .nimble file, a project directory or + the name of an installed package. + Options: -h, --help Print this help message. From 850304ffcb0e5839db8f4bda3d4821b58cd161ce Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 30 Dec 2016 12:43:52 +0000 Subject: [PATCH 130/424] Fixes #189. --- src/nimble.nim | 20 ++++++++++++-------- src/nimblepkg/options.nim | 14 +++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 36b1f4e..f94d1d0 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -661,10 +661,10 @@ proc build(options: Options) = let paths = processDeps(pkginfo, options) buildFromDir(pkgInfo, paths, false) -proc compile(options: Options) = +proc execBackend(options: Options) = let bin = options.action.file if bin == "": - raise newException(NimbleError, "You need to specify a file to compile.") + raise newException(NimbleError, "You need to specify a file.") if not fileExists(bin): raise newException(NimbleError, "Specified file does not exist.") @@ -684,11 +684,15 @@ proc compile(options: Options) = else: pkgInfo.backend - display("Compiling", "$1 (from package $2) using $3 backend" % - [bin, pkgInfo.name, backend], priority = HighPriority) - doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# \"$#\"" % + if options.action.typ == actionCompile: + display("Compiling", "$1 (from package $2) using $3 backend" % + [bin, pkgInfo.name, backend], priority = HighPriority) + else: + display("Generating", ("documentation for $1 (from package $2) using $3 " & + "backend") % [bin, pkgInfo.name, backend], priority = HighPriority) + doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# \"$#\"" % [backend, args, bin]) - display("Success:", "Compilation finished", Success, HighPriority) + display("Success:", "Execution finished", Success, HighPriority) proc search(options: Options) = ## Searches for matches in ``options.action.search``. @@ -1035,8 +1039,8 @@ proc doAction(options: Options) = listPaths(options) of actionBuild: build(options) - of actionCompile: - compile(options) + of actionCompile, actionDoc: + execBackend(options) of actionInit: init(options) of actionPublish: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 9d65398..85a473c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -23,7 +23,7 @@ type actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionCustom, actionTasks + actionDoc, actionCustom, actionTasks Action* = object case typ*: ActionType @@ -36,7 +36,7 @@ type search*: seq[string] # Search string. of actionInit, actionDump: projName*: string - of actionCompile: + of actionCompile, actionDoc: file*: string backend*: string compileOptions*: seq[string] @@ -61,6 +61,8 @@ Commands: build Builds a package. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. + doc, doc2 [opts, ...] f.nim Builds documentation for a file inside a + package. Passes options to the Nim compiler. refresh [url] Refreshes the package list. A package list URL can be optionally specified. search pkg/tag Searches for a specified package. Search is @@ -114,6 +116,8 @@ proc parseActionType*(action: string): ActionType = result = actionBuild of "c", "compile", "js", "cpp", "cc": result = actionCompile + of "doc", "doc2": + result = actionDoc of "init": result = actionInit of "dump": @@ -140,7 +144,7 @@ proc initAction*(options: var Options, key: string) = case options.action.typ of actionInstall, actionPath: options.action.packages = @[] - of actionCompile: + of actionCompile, actionDoc: options.action.compileOptions = @[] options.action.file = "" if keyNorm == "c" or keyNorm == "compile": options.action.backend = "" @@ -222,7 +226,7 @@ proc parseArgument*(key: string, result: var Options) = raise newException(NimbleError, "Can only initialize one package at a time.") result.action.projName = key - of actionCompile: + of actionCompile, actionDoc: result.action.file = key of actionList, actionBuild, actionPublish: writeHelp() @@ -261,7 +265,7 @@ proc parseFlag*(flag, val: string, result: var Options) = wasFlagHandled = false else: case result.action.typ - of actionCompile: + of actionCompile, actionDoc: if val == "": result.action.compileOptions.add("--" & flag) else: From 56f547f52e7a166527a83f0e096d089b6f178f9b Mon Sep 17 00:00:00 2001 From: Luke Diamand Date: Fri, 30 Dec 2016 18:43:29 +0000 Subject: [PATCH 131/424] Remove quotes around "test" The example for adding a test section uses quotes around the test target, "test". However, this doesn't work, as it's not a valid identifier and nimble fails with: Error: identifier expected, but found '`"test" Task`'. Remove the quotes in the example. --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 29c989e..2c85498 100644 --- a/readme.markdown +++ b/readme.markdown @@ -464,7 +464,7 @@ To make testing even more convenient, you may wish to define a ``test`` task in your ``.nimble`` file. Like so: ```nim -task "test", "Runs the test suite": +task test, "Runs the test suite": exec "nim c -r tests/tester" ``` From ad21bb039f3607f77faf68208eb5ae16b8434548 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 31 Dec 2016 02:09:14 +0100 Subject: [PATCH 132/424] removed distros.nim; now part of Nim's stdlib --- src/nimblepkg/distros.nim | 59 --------------------------------------- 1 file changed, 59 deletions(-) delete mode 100644 src/nimblepkg/distros.nim diff --git a/src/nimblepkg/distros.nim b/src/nimblepkg/distros.nim deleted file mode 100644 index 8ce30c2..0000000 --- a/src/nimblepkg/distros.nim +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) Dominik Picheta. All rights reserved. -# BSD License. Look at license.txt for more info. - -## This module is implicitly imported in NimScript .nimble files. - -from strutils import contains - -type - Distribution* {.pure.} = enum ## an enum so that the poor programmer - ## cannot introduce typos - Windows, ## some version of Windows - Posix, ## some Posix system - MacOSX, ## some version of OSX - Linux, ## some version of Linux - Ubuntu, - Gentoo, - Fedora, - RedHat, - BSD, - FreeBSD, - OpenBSD - -proc detectOsImpl(d: Distribution): bool = - case d - of Distribution.Windows: ## some version of Windows - result = defined(windows) - of Distribution.Posix: result = defined(posix) - of Distribution.MacOSX: result = defined(macosx) - of Distribution.Linux: result = defined(linux) - of Distribution.Ubuntu, Distribution.Gentoo, Distribution.FreeBSD, - Distribution.OpenBSD, Distribution.Fedora: - result = ("-" & $d & " ") in gorge"uname -a" - of Distribution.RedHat: - result = "Red Hat" in gorge"uname -a" - of Distribution.BSD: result = defined(bsd) - -template detectOs*(d: untyped): bool = - detectOsImpl(Distribution.d) - -proc foreignCmd*(cmd: string; requiresSudo=false) = - nimscriptapi.foreignDeps.add((if requiresSudo: "sudo " else: "") & cmd) - -proc foreignDep*(foreignPackageName: string) = - let p = foreignPackageName - when defined(windows): - foreignCmd "Chocolatey install " & p - elif defined(bsd): - foreignCmd "ports install " & p, true - elif defined(linux): - if detectOs(Ubuntu): - foreignCmd "apt-get install " & p, true - elif detectOs(Gentoo): - foreignCmd "emerge install " & p, true - elif detectOs(Fedora): - foreignCmd "yum install " & p, true - elif detectOs(RedHat): - foreignCmd "rpm install " & p, true - else: - discard From 6b175056df6b9f8848c304e093ba833fb8a82b99 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 1 Jan 2017 15:56:44 +0000 Subject: [PATCH 133/424] Fixes #236. --- src/nimble.nim | 70 +++---------- src/nimblepkg/packageinfo.nim | 178 +++++++++++++++++++++++++--------- src/nimblepkg/version.nim | 3 + tests/tester.nim | 2 +- 4 files changed, 153 insertions(+), 100 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index f94d1d0..486490d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -45,45 +45,6 @@ proc refresh(options: Options) = else: "" - proc downloadList(list: PackageList, options: Options) = - display("Downloading", list.name & " package list", priority = HighPriority) - - var lastError = "" - for i in 0 .. 0: maskedUrl.password = "***" - display("Connecting", "to proxy at " & $maskedUrl, - priority = LowPriority) - - try: - downloadFile(url, tempPath, proxy = getProxy(options)) - except: - let message = "Could not download: " & getCurrentExceptionMsg() - display("Warning:", message, Warning) - lastError = message - continue - - if not validatePackagesList(tempPath): - lastError = "Downloaded packages.json file is invalid" - display("Warning:", lastError & ", discarding.", Warning) - continue - - copyFile(tempPath, - options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii()) - display("Success", "Package list downloaded.", Success, HighPriority) - lastError = "" - break - - if lastError.len != 0: - raise newException(NimbleError, "Refresh failed\n" & lastError) - if parameter.len > 0: if parameter.isUrl: let cmdLine = PackageList(name: "commandline", urls: @[parameter]) @@ -275,17 +236,27 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = let msg = "Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")" raise newException(NimbleError, msg) else: - let depDesc = "$1@$2" % [dep.name, $dep.ver] - display("Checking", "for $1" % depDesc, priority = MediumPriority) + let resolvedDep = dep.resolveAlias(options) + display("Checking", "for $1" % $resolvedDep, priority = MediumPriority) var pkg: PackageInfo - if not findPkg(pkglist, dep, pkg): - display("Installing", depDesc, priority = HighPriority) - let (paths, installedPkg) = install(@[(dep.name, dep.ver)], options) + var found = findPkg(pkgList, resolvedDep, pkg) + # Check if the original name exists. + if not found and resolvedDep.name != dep.name: + display("Checking", "for $1" % $dep, priority = MediumPriority) + found = findPkg(pkgList, dep, pkg) + if found: + display("Warning:", "Installed package $1 should be renamed to $2" % + [dep.name, resolvedDep.name], Warning, HighPriority) + + if not found: + display("Installing", $resolvedDep, priority = HighPriority) + let toInstall = @[(resolvedDep.name, resolvedDep.ver)] + let (paths, installedPkg) = install(toInstall, options) result.add(paths) pkg = installedPkg # For addRevDep else: - display("Info:", "Dependency on $1 already satisfied" % depDesc, + display("Info:", "Dependency on $1 already satisfied" % $dep, priority = HighPriority) result.add(pkg.mypath.splitFile.dir) # Process the dependencies of this dependency. @@ -619,15 +590,6 @@ proc install(packages: seq[PkgTuple], if packages == @[]: result = installFromDir(getCurrentDir(), newVRAny(), options, "") else: - # If packages.json is not present ask the user if they want to download it. - if needsRefresh(options): - if doPrompt and - options.prompt("No local packages.json found, download it from " & - "internet?"): - refresh(options) - else: - raise newException(NimbleError, "Please run nimble refresh.") - # Install each package. for pv in packages: let (meth, url) = getDownloadInfo(pv, options, doPrompt) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index e92eaf6..d09995f 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -1,7 +1,13 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. + +# Stdlib imports +import system except TResult import parsecfg, json, streams, strutils, parseutils, os, sets, tables -import version, tools, common, options, cli +import httpclient + +# Local imports +import version, tools, common, options, cli, config type Package* = object ## Definition of package from packages.json. @@ -16,6 +22,7 @@ type version*: string dvcsTag*: string web*: string # Info url for humans. + alias*: string ## A name of another package, that this package aliases. MetaData* = object url*: string @@ -102,16 +109,20 @@ proc fromJson(obj: JSonNode): Package = ## ## Aborts execution if the JSON node doesn't contain the required fields. result.name = obj.requiredField("name") - result.version = obj.optionalField("version") - result.url = obj.requiredField("url") - result.downloadMethod = obj.requiredField("method") - result.dvcsTag = obj.optionalField("dvcs-tag") - result.license = obj.requiredField("license") - result.tags = @[] - for t in obj["tags"]: - result.tags.add(t.str) - result.description = obj.requiredField("description") - result.web = obj.optionalField("web") + if obj.hasKey("alias"): + result.alias = obj.requiredField("alias") + else: + result.alias = "" + result.version = obj.optionalField("version") + result.url = obj.requiredField("url") + result.downloadMethod = obj.requiredField("method") + result.dvcsTag = obj.optionalField("dvcs-tag") + result.license = obj.requiredField("license") + result.tags = @[] + for t in obj["tags"]: + result.tags.add(t.str) + result.description = obj.requiredField("description") + result.web = obj.optionalField("web") proc readMetaData*(path: string): MetaData = ## Reads the metadata present in ``~/.nimble/pkgs/pkg-0.1/nimblemeta.json`` @@ -126,21 +137,107 @@ proc readMetaData*(path: string): MetaData = let jsonmeta = parseJson(cont) result.url = jsonmeta["url"].str -proc getPackage*(pkg: string, options: Options, - resPkg: var Package): bool = +proc needsRefresh*(options: Options): bool = + ## Determines whether a ``nimble refresh`` is needed. + ## + ## In the future this will check a stored time stamp to determine how long + ## ago the package list was refreshed. + result = true + for name, list in options.config.packageLists: + if fileExists(options.getNimbleDir() / "packages_" & name & ".json"): + result = false + +proc validatePackagesList(path: string): bool = + ## Determines whether package list at ``path`` is valid. + try: + let pkgList = parseFile(path) + if pkgList.kind == JArray: + if pkgList.len == 0: + display("Warning:", path & " contains no packages.", Warning, + HighPriority) + return true + except ValueError, JsonParsingError: + return false + +proc downloadList*(list: PackageList, options: Options) = + ## Downloads the specified package list and saves it in $nimbleDir. + display("Downloading", list.name & " package list", priority = HighPriority) + + var lastError = "" + for i in 0 .. 0: maskedUrl.password = "***" + display("Connecting", "to proxy at " & $maskedUrl, + priority = LowPriority) + + try: + downloadFile(url, tempPath, proxy = getProxy(options)) + except: + let message = "Could not download: " & getCurrentExceptionMsg() + display("Warning:", message, Warning) + lastError = message + continue + + if not validatePackagesList(tempPath): + lastError = "Downloaded packages.json file is invalid" + display("Warning:", lastError & ", discarding.", Warning) + continue + + copyFile(tempPath, + options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii()) + display("Success", "Package list downloaded.", Success, HighPriority) + lastError = "" + break + + if lastError.len != 0: + raise newException(NimbleError, "Refresh failed\n" & lastError) + +proc readPackageList(name: string, options: Options): JsonNode = + # If packages.json is not present ask the user if they want to download it. + if needsRefresh(options): + if options.prompt("No local packages.json found, download it from " & + "internet?"): + for name, list in options.config.packageLists: + downloadList(list, options) + else: + raise newException(NimbleError, "Please run nimble refresh.") + return parseFile(options.getNimbleDir() / "packages_" & + name.toLowerAscii() & ".json") + +proc getPackage*(pkg: string, options: Options, resPkg: var Package): bool +proc resolveAlias(pkg: Package, options: Options): Package = + result = pkg + # Resolve alias. + if pkg.alias.len > 0: + display("Warning:", "The $1 package has been renamed to $2" % + [pkg.name, pkg.alias], Warning, HighPriority) + if not getPackage(pkg.alias, options, result): + raise newException(NimbleError, "Alias for package not found: " & + pkg.alias) + +proc getPackage*(pkg: string, options: Options, resPkg: var Package): bool = ## Searches any packages.json files defined in ``options.config.packageLists`` ## Saves the found package into ``resPkg``. ## ## Pass in ``pkg`` the name of the package you are searching for. As ## convenience the proc returns a boolean specifying if the ``resPkg`` was ## successfully filled with good data. + ## + ## Aliases are handled and resolved. for name, list in options.config.packageLists: display("Reading", "$1 package list" % name, priority = LowPriority) - let packages = parseFile(options.getNimbleDir() / - "packages_" & name.toLowerAscii() & ".json") + let packages = readPackageList(name, options) for p in packages: if normalize(p["name"].str) == normalize(pkg): resPkg = p.fromJson() + resPkg = resolveAlias(resPkg, options) return true proc getPackageList*(options: Options): seq[Package] = @@ -148,8 +245,7 @@ proc getPackageList*(options: Options): seq[Package] = result = @[] var namesAdded = initSet[string]() for name, list in options.config.packageLists: - let packages = parseFile(options.getNimbleDir() / - "packages_" & name.toLowerAscii() & ".json") + let packages = readPackageList(name, options) for p in packages: let pkg: Package = p.fromJson() if pkg.name notin namesAdded: @@ -207,6 +303,17 @@ proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool = return withinRange(newVersion(pkgInfo.version), verRange) or withinRange(newVersion(pkgInfo.specialVersion), verRange) +proc resolveAlias*(dep: PkgTuple, options: Options): PkgTuple = + ## Looks up the specified ``dep.name`` in the packages.json files to resolve + ## a potential alias into the package's real name. + result = dep + var pkg: Package + # TODO: This needs better caching. + if getPackage(dep.name, options, pkg): + # The resulting ``pkg`` will contain the resolved name or the original if + # no alias is present. + result.name = pkg.name + proc findPkg*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]], dep: PkgTuple, r: var PackageInfo): bool = @@ -254,12 +361,15 @@ proc getOutputDir*(pkgInfo: PackageInfo, bin: string): string = proc echoPackage*(pkg: Package) = echo(pkg.name & ":") - echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")") - echo(" tags: " & pkg.tags.join(", ")) - echo(" description: " & pkg.description) - echo(" license: " & pkg.license) - if pkg.web.len > 0: - echo(" website: " & pkg.web) + if pkg.alias.len > 0: + echo(" Alias for ", pkg.alias) + else: + echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")") + echo(" tags: " & pkg.tags.join(", ")) + echo(" description: " & pkg.description) + echo(" license: " & pkg.license) + if pkg.web.len > 0: + echo(" website: " & pkg.web) proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string = result = pkg.name @@ -268,28 +378,6 @@ proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string = result.add "_" result.add verSimple -proc needsRefresh*(options: Options): bool = - ## Determines whether a ``nimble refresh`` is needed. - ## - ## In the future this will check a stored time stamp to determine how long - ## ago the package list was refreshed. - result = true - for name, list in options.config.packageLists: - if fileExists(options.getNimbleDir() / "packages_" & name & ".json"): - result = false - -proc validatePackagesList*(path: string): bool = - ## Determines whether package list at ``path`` is valid. - try: - let pkgList = parseFile(path) - if pkgList.kind == JArray: - if pkgList.len == 0: - display("Warning:", path & " contains no packages.", Warning, - HighPriority) - return true - except ValueError, JsonParsingError: - return false - proc checkInstallFile(pkgInfo: PackageInfo, origDir, file: string): bool = ## Checks whether ``file`` should be installed. diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 080c469..b4d42f5 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -291,6 +291,9 @@ proc findLatest*(verRange: VersionRange, if ver > result.ver: result = (ver, tag) +proc `$`*(dep: PkgTuple): string = + return dep.name & "@" & $dep.ver + when isMainModule: doAssert(newVersion("1.0") < newVersion("1.4")) doAssert(newVersion("1.0.1") > newVersion("1.0")) diff --git a/tests/tester.nim b/tests/tester.nim index ea1daa5..303fea4 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -172,7 +172,7 @@ test "can use nimscript's setCommand": let (output, exitCode) = execNimble("--verbose", "cTest") let lines = output.strip.splitLines() check exitCode == QuitSuccess - check "Compilation finished".normalize in lines[^1].normalize + check "Execution finished".normalize in lines[^1].normalize test "can use nimscript's setCommand with flags": cd "nimscript": From d70526fa9077b6d23696be8232d6f9a12b71a87c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 1 Jan 2017 16:34:03 +0000 Subject: [PATCH 134/424] Improve error when fork can't be created for publishing. References #284. --- src/nimblepkg/publish.nim | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 1afcc3f..1448a95 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -26,6 +26,8 @@ proc getGithubAuth(): Auth = display("Info:", "Please create a new personal access token on Github in" & " order to allow Nimble to fork the packages repository.", priority = HighPriority) + display("Hint:", "Make sure to give the access token access to public repos" & + " (public_repo scope)!", Warning, HighPriority) sleep(5000) display("Info:", "Your default browser should open with the following URL: " & "https://github.com/settings/tokens/new", priority = HighPriority) @@ -54,8 +56,12 @@ proc forkExists(a: Auth): bool = result = false proc createFork(a: Auth) = - discard postContent("https://api.github.com/repos/nim-lang/packages/forks", - extraHeaders=createHeaders(a)) + try: + discard postContent("https://api.github.com/repos/nim-lang/packages/forks", + extraHeaders=createHeaders(a)) + except HttpRequestError: + raise newException(NimbleError, "Unable to create fork. Access token" & + " might not have enough permissions.") proc createPullRequest(a: Auth, packageName, branch: string) = display("Info", "Creating PR", priority = HighPriority) From d25c8e29d43992e6fed009d792484884ebf166b9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 1 Jan 2017 17:14:12 +0000 Subject: [PATCH 135/424] Prevent crash when symlink already exists in $nimbleDir/bin. --- src/nimble.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nimble.nim b/src/nimble.nim index 486490d..5b84179 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -467,6 +467,10 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, when defined(unix): display("Creating", "symlink: $1 -> $2" % [pkgDestDir / bin, binDir / cleanBin], priority = MediumPriority) + if existsFile(binDir / cleanBin): + display("Warning:", "Symlink already exists in $1. Replacing." % binDir, + Warning, HighPriority) + removeFile(binDir / cleanBin) createSymlink(pkgDestDir / bin, binDir / cleanBin) binariesInstalled.incl(cleanBin) elif defined(windows): From df640de6c87d7f3b42803677d91d47960baf7533 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 1 Jan 2017 17:47:14 +0000 Subject: [PATCH 136/424] Bump to 0.8.0 and fill out changelog for this release. --- changelog.markdown | 40 ++++++++++++++++++++++++++++++++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index f038524..b65e92e 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,46 @@ # Nimble changelog +## 0.8.0 - 01/01/2017 + +This is a large release containing multiple new features and many bug fixes. + +* Implemented a completely new output system. + * Supports different message types and priorities. Each is differently + encoded using a color and a brightness. + * The amount of messages shown can be changed by using the new ``--verbose`` + and ``--debug`` flags, by default only high priority messages are shown. + * Duplicate warnings are filtered out to prevent too much noise. +* Package namespaces are now validated. You will see a warning whenever an + incorrectly namespaced package is read by Nimble, this can occur either + during installation or when the installed package database is being loaded. + The namespacing rules are described in Nimble's + [readme](https://github.com/nim-lang/nimble#libraries). + **Consider these warnings to be unstable, if you see something that you + think is incorrect please report it**. +* Special version dependencies are now installed into a directory with that + special version in its name. For example, ``compiler@#head`` will be installed + into ``~/.nimble/pkgs/compiler-#head``. This reduces the amount of redundant + installs. See [#88](https://github.com/nim-lang/nimble/issues/88) for + more information. +* Nimble now supports package aliases in the packages.json files. +* Fixed regression that caused transitive dependencies to not be installed. +* Fixed problem with ``install`` command when a ``src`` directory is present + in the current directory. +* Improved quoting of process execution arguments. +* Many improvements to custom ``--nimbleDir`` handling. All commands should now + support it correctly. +* Running ``nimble -v`` will no longer read the Nimble config before displaying + the version. +* Refresh command now supports a package list name as argument. +* Fixes issues with symlinks not being removed correctly. +* Changed the way the ``dump`` command locates the .nimble file. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.10...v0.8.0 +Full list of issues which have been closed: https://github.com/nim-lang/nimble/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-10-09+..+2017-01-01%22+ + ## 0.7.10 - 09/10/2016 This release includes multiple bug fixes. diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index c3ab2f9..6bb6a89 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -49,4 +49,4 @@ when not defined(nimscript): raise exc const - nimbleVersion* = "0.7.11" + nimbleVersion* = "0.8.0" From 8120ac02c803b3a4b9bdcda7b6939c9145226cb5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 14:41:08 +0000 Subject: [PATCH 137/424] Add foreign deps to nimble.nimble. --- nimble.nimble | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nimble.nimble b/nimble.nimble index 21473ab..7617ee7 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,4 +1,4 @@ -import ospaths +import ospaths, distros template thisModuleFile: string = instantiationInfo(fullPaths = true).filename when fileExists(thisModuleFile.parentDir / "src/nimblepkg/common.nim"): @@ -22,6 +22,11 @@ srcDir = "src" requires "nim >= 0.13.0", "compiler#head" +if detectOs(Ubuntu): + foreignDep "libssl-dev" +elif detectOs(MacOSX): + foreignDep "openssl" + task test, "Run the Nimble tester!": withDir "tests": exec "nim c -r tester" From 1c982a7e5fe7e332b481b5ff4dad3a78159df75f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 16:56:44 +0000 Subject: [PATCH 138/424] Use display for external deps and document this new feature. --- nimble.nimble | 12 +++++++----- readme.markdown | 39 +++++++++++++++++++++++++++++++++++++++ src/nimble.nim | 7 +++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index 7617ee7..68b439b 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,4 +1,4 @@ -import ospaths, distros +import ospaths template thisModuleFile: string = instantiationInfo(fullPaths = true).filename when fileExists(thisModuleFile.parentDir / "src/nimblepkg/common.nim"): @@ -22,10 +22,12 @@ srcDir = "src" requires "nim >= 0.13.0", "compiler#head" -if detectOs(Ubuntu): - foreignDep "libssl-dev" -elif detectOs(MacOSX): - foreignDep "openssl" +when defined(nimdistros): + import distros + if detectOs(Ubuntu): + foreignDep "libssl-dev" + else: + foreignDep "openssl" task test, "Run the Nimble tester!": withDir "tests": diff --git a/readme.markdown b/readme.markdown index 2c85498..97a28d5 100644 --- a/readme.markdown +++ b/readme.markdown @@ -31,6 +31,7 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Binary packages](#binary-packages) - [Hybrids](#hybrids) - [Dependencies](#dependencies) + - [External dependencies](#external-dependencies) - [Nim compiler](#nim-compiler) - [Versions](#versions) - [Releasing a new version](#releasing-a-new-version) @@ -575,6 +576,44 @@ This is done with the ``#`` character, for example: ``jester#head``. Which will make your package depend on the latest commit of Jester. +#### External dependencies + +**Warning:** This feature is brand new in Nimble v0.8.0. Breaking changes +related to it are more likely to be introduced than for any other Nimble +features. + +Starting with Nimble v0.8.0, you can now specify external dependencies. These +are dependencies which are not managed by Nimble and can only be installed via +your system's package manager or downloaded manually via the internet. + +As an example, to specify a dependency on openssl you may put this in your +.nimble file: + +```nim +when defined(nimdistros): + import distros + if detectOs(Ubuntu): + foreignDep "libssl-dev" + else: + foreignDep "openssl" +``` + +The ``when`` branch is important to support installation using older versions +of Nimble. + +The [distros module](nim-lang.org/docs/distros.html) in Nim's +standard library contains a list of all the supported Operating Systems and +Linux distributions. + +With this inside your .nimble file, Nimble will output the following after +installing your package (on macOS): + +``` + Hint: This package requires some external dependencies. + Hint: To install them you may be able to run: + Hint: sudo brew install openssl +``` + ### Nim compiler The Nim compiler cannot read .nimble files. Its knowledge of Nimble is diff --git a/src/nimble.nim b/src/nimble.nim index 82c1702..6889fbe 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -995,9 +995,12 @@ proc doAction(options: Options) = if options.action.packages.len == 0: nimScriptHint(pkgInfo) if pkgInfo.foreignDeps.len > 0: - echo("To finish the installation, run: ") + display("Hint:", "This package requires some external dependencies.", + Warning, HighPriority) + display("Hint:", "To install them you may be able to run:", + Warning, HighPriority) for i in 0.. Date: Tue, 3 Jan 2017 17:06:18 +0000 Subject: [PATCH 139/424] Define new symbol to support distros in older Nimble versions. --- nimble.nimble | 2 +- readme.markdown | 2 +- src/nimblepkg/nimscriptsupport.nim | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index 68b439b..fde18da 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -22,7 +22,7 @@ srcDir = "src" requires "nim >= 0.13.0", "compiler#head" -when defined(nimdistros): +when defined(nimbledistros): import distros if detectOs(Ubuntu): foreignDep "libssl-dev" diff --git a/readme.markdown b/readme.markdown index 97a28d5..8616438 100644 --- a/readme.markdown +++ b/readme.markdown @@ -590,7 +590,7 @@ As an example, to specify a dependency on openssl you may put this in your .nimble file: ```nim -when defined(nimdistros): +when defined(nimbledistros): import distros if detectOs(Ubuntu): foreignDep "libssl-dev" diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 3121e5b..bbdb954 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -241,6 +241,7 @@ proc execScript(scriptName: string, flags: StringTableRef, defineSymbol("nimscript") defineSymbol("nimconfig") defineSymbol("nimble") + defineSymbol("nimbledistros") registerPass(semPass) registerPass(evalPass) From 2f45eab060e7eec80f40fed53f678b778719dd42 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 17:43:59 +0000 Subject: [PATCH 140/424] Fixes #301. --- src/nimble.nim | 12 ++++++------ src/nimblepkg/packageparser.nim | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6889fbe..8f96561 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -227,7 +227,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = "dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion], priority = HighPriority) - let pkglist = getInstalledPkgs(options.getPkgsDir(), options) + let pkglist = getInstalledPkgsMin(options.getPkgsDir(), options) var reverseDeps: seq[tuple[name, version: string]] = @[] for dep in pkginfo.requires: if dep.name == "nimrod" or dep.name == "nim": @@ -260,7 +260,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = priority = HighPriority) result.add(pkg.mypath.splitFile.dir) # Process the dependencies of this dependency. - result.add(processDeps(pkg, options)) + result.add(processDeps(pkg.toFullInfo(options), options)) reverseDeps.add((pkg.name, pkg.specialVersion)) # Check if two packages of the same name (but different version) are listed @@ -947,9 +947,9 @@ proc uninstall(options: Options) = # removeRevDep needs the package dependency info, so we can't just pass # a minimal pkg info. - let pkgFull = getPkgInfo(pkg.mypath.splitFile.dir, options) # TODO: Simplify - removeRevDep(options, pkgFull) - removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.specialVersion), options) + removeRevDep(options, pkg.toFullInfo(options)) + removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.specialVersion), + options) display("Removed", "$1 ($2)" % [pkg.name, $pkg.specialVersion], Success, HighPriority) @@ -965,7 +965,7 @@ proc execHook(options: Options, before: bool): bool = nimbleFile = findNimbleFile(getCurrentDir(), true) except NimbleError: return true # PackageInfos are cached so we can read them as many times as we want. - let pkgInfo = getPkgInfo(nimbleFile.splitFile.dir, options) # TODO: Simplify + let pkgInfo = getPkgInfoFromFile(nimbleFile, options) let actionName = if options.action.typ == actionCustom: options.action.command else: ($options.action.typ)[6 .. ^1] diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index f3ead77..07262c0 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -320,7 +320,7 @@ proc getPkgInfoFromFile*(file: NimbleFile, options: Options): PackageInfo = proc getPkgInfo*(dir: string, options: Options): PackageInfo = ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo. let nimbleFile = findNimbleFile(dir, true) - getPkgInfoFromFile(nimbleFile, options) + return getPkgInfoFromFile(nimbleFile, options) proc getInstalledPkgs*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @@ -371,6 +371,10 @@ proc getInstalledPkgs*(libsDir: string, options: Options): proc isNimScript*(nf: string, options: Options): bool = result = readPackageInfo(nf, options).isNimScript +proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo = + assert(pkg.isMinimal, "Redundant call?") + return getPkgInfoFromFile(pkg.mypath, options) + when isMainModule: validatePackageName("foo_bar") validatePackageName("f_oo_b_a_r") From 4d7b3081a89c888bfb45667fdc7d54e233ead86b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 18:02:55 +0000 Subject: [PATCH 141/424] Fixes tests. --- src/nimblepkg/packageparser.nim | 6 ++++-- tests/tester.nim | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 07262c0..f7e96e1 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -372,8 +372,10 @@ proc isNimScript*(nf: string, options: Options): bool = result = readPackageInfo(nf, options).isNimScript proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo = - assert(pkg.isMinimal, "Redundant call?") - return getPkgInfoFromFile(pkg.mypath, options) + if pkg.isMinimal: + return getPkgInfoFromFile(pkg.mypath, options) + else: + return pkg when isMainModule: validatePackageName("foo_bar") diff --git a/tests/tester.nim b/tests/tester.nim index 769310a..41c27f9 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -33,6 +33,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) + #echo(result.output) proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) From fcbb3de78373792698b3647c579b809f1cbc043e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 18:41:51 +0000 Subject: [PATCH 142/424] More intelligent definition of `nimbledistros`. This fixes issues with using latest Nimble in an 0.15.2 environment. Squashed commit of the following: commit 4c5f791873b7965a25b9dbdb29a96b38a065c478 Author: Dominik Picheta Date: Tue Jan 3 18:41:30 2017 +0000 Disable output in tester. commit 9f4af9685a36fbebc5a71b6d39130c2d2b30bc05 Author: Dominik Picheta Date: Tue Jan 3 18:30:38 2017 +0000 Attempt at fixing tests. commit d0de031d1ce11be0f106eb6d92885b6833ce95b0 Author: Dominik Picheta Date: Tue Jan 3 18:16:40 2017 +0000 Testing. --- src/nimblepkg/nimscriptapi.nim | 3 +++ src/nimblepkg/nimscriptsupport.nim | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index b711851..81c3f9e 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -22,6 +22,9 @@ var foreignDeps*: seq[string] = @[] ## The foreign dependencies. Only ## exported for 'distros.nim'. +when defined(nimdistros) and defined(nimblesupportsdistros): + const nimbledistros = true + proc requires*(deps: varargs[string]) = ## Call this to set the list of requirements of your Nimble ## package. diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index bbdb954..2a74ea3 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -241,7 +241,7 @@ proc execScript(scriptName: string, flags: StringTableRef, defineSymbol("nimscript") defineSymbol("nimconfig") defineSymbol("nimble") - defineSymbol("nimbledistros") + defineSymbol("nimblesupportsdistros") registerPass(semPass) registerPass(evalPass) From b629048249ae63117ff90a813037dccab2965983 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 19:00:39 +0000 Subject: [PATCH 143/424] Just check for nimdistros instead of adding an additional define. --- nimble.nimble | 2 +- readme.markdown | 2 +- src/nimblepkg/nimscriptapi.nim | 3 --- src/nimblepkg/nimscriptsupport.nim | 1 - 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index fde18da..68b439b 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -22,7 +22,7 @@ srcDir = "src" requires "nim >= 0.13.0", "compiler#head" -when defined(nimbledistros): +when defined(nimdistros): import distros if detectOs(Ubuntu): foreignDep "libssl-dev" diff --git a/readme.markdown b/readme.markdown index 8616438..97a28d5 100644 --- a/readme.markdown +++ b/readme.markdown @@ -590,7 +590,7 @@ As an example, to specify a dependency on openssl you may put this in your .nimble file: ```nim -when defined(nimbledistros): +when defined(nimdistros): import distros if detectOs(Ubuntu): foreignDep "libssl-dev" diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 81c3f9e..b711851 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -22,9 +22,6 @@ var foreignDeps*: seq[string] = @[] ## The foreign dependencies. Only ## exported for 'distros.nim'. -when defined(nimdistros) and defined(nimblesupportsdistros): - const nimbledistros = true - proc requires*(deps: varargs[string]) = ## Call this to set the list of requirements of your Nimble ## package. diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 2a74ea3..3121e5b 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -241,7 +241,6 @@ proc execScript(scriptName: string, flags: StringTableRef, defineSymbol("nimscript") defineSymbol("nimconfig") defineSymbol("nimble") - defineSymbol("nimblesupportsdistros") registerPass(semPass) registerPass(evalPass) From dda0c39e34c6ed4750e45ab082c29bb49d90b158 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 19:25:36 +0000 Subject: [PATCH 144/424] Fixes #304. --- src/nimblepkg/packageparser.nim | 14 ++++++++------ tests/tester.nim | 4 ++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index f7e96e1..fef696b 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -290,12 +290,14 @@ proc readPackageInfo(nf: NimbleFile, options: Options, # By default specialVersion is the same as version. result.specialVersion = result.version - # The package directory name may include a "special" version - # (example #head). If so, it is given higher priority and therefore - # overwrites the .nimble file's version. - let version = parseVersionRange(minimalInfo.version) - if version.kind == verSpecial: - result.specialVersion = minimalInfo.version + # Only attempt to read a special version if `nf` is inside the $nimbleDir. + if nf.startsWith(options.getNimbleDir()): + # The package directory name may include a "special" version + # (example #head). If so, it is given higher priority and therefore + # overwrites the .nimble file's version. + let version = parseVersionRange(minimalInfo.version) + if version.kind == verSpecial: + result.specialVersion = minimalInfo.version if not result.isMinimal: options.pkgInfoCache[nf] = result diff --git a/tests/tester.nim b/tests/tester.nim index 41c27f9..78df424 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -42,6 +42,10 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "can distinguish package reading in nimbleDir vs. other dirs (#304)": + cd "issue304" / "package-test": + check execNimble("tasks").exitCode == QuitSuccess + test "can build with #head and versioned package (#289)": cd "issue289": check execNimble(["install", "-y"]).exitCode == QuitSuccess From 0628911758c052fad68235a10e024b26c14dc7e2 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 19:38:34 +0000 Subject: [PATCH 145/424] Show output for the compiler/docgen commands. Fixes #303. --- src/nimble.nim | 2 +- src/nimblepkg/tools.nim | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 8f96561..55a0b09 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -657,7 +657,7 @@ proc execBackend(options: Options) = display("Generating", ("documentation for $1 (from package $2) using $3 " & "backend") % [bin, pkgInfo.name, backend], priority = HighPriority) doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# \"$#\"" % - [backend, args, bin]) + [backend, args, bin], showOutput = true) display("Success:", "Execution finished", Success, HighPriority) proc search(options: Options) = diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index d71c3f6..3bd0365 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -11,7 +11,7 @@ proc extractBin(cmd: string): string = else: return cmd.split(' ')[0] -proc doCmd*(cmd: string) = +proc doCmd*(cmd: string, showOutput = false) = let bin = extractBin(cmd) if findExe(bin) == "": raise newException(NimbleError, "'" & bin & "' not in PATH.") @@ -24,7 +24,10 @@ proc doCmd*(cmd: string) = let (output, exitCode) = execCmdEx(cmd) displayDebug("Finished", "with exit code " & $exitCode) # TODO: Improve to show output in real-time. - displayDebug("Output", output) + if showOutput: + display("Output:", output, priority = HighPriority) + else: + displayDebug("Output", output) if exitCode != QuitSuccess: raise newException(NimbleError, From 17f1467e5d1f53e73a27d0828910f9b9080557f6 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 3 Jan 2017 20:04:48 +0000 Subject: [PATCH 146/424] Add missing test files. --- tests/issue304/package-test/package_test.nimble | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/issue304/package-test/package_test.nimble diff --git a/tests/issue304/package-test/package_test.nimble b/tests/issue304/package-test/package_test.nimble new file mode 100644 index 0000000..9886d31 --- /dev/null +++ b/tests/issue304/package-test/package_test.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Package for ensuring that issue #304 is resolved." +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + From 4f175749e4308f2636596d9bcaae1f11ba672bc7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 4 Jan 2017 16:05:43 +0000 Subject: [PATCH 147/424] Don't search for nimscriptapi overrides. Fixes #306. --- src/nimblepkg/nimscriptsupport.nim | 32 ++++++------------------------ 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 3121e5b..86fde03 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -182,22 +182,6 @@ proc setupVM(module: PSym; scriptName: string, if not flags.isNil: flags[a.getString 0] = a.getString 1 -proc findNimscriptApi(options: Options): string = - ## Returns the directory containing ``nimscriptapi.nim`` or an empty string - ## if it cannot be found. - result = "" - # Try finding it in exe's path - if fileExists(getAppDir() / "nimblepkg" / "nimscriptapi.nim"): - result = getAppDir() - - if result.len == 0: - let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options) - var pkg: PackageInfo - if pkgs.findPkg(("nimble", newVRAny()), pkg): - let pkgDir = pkg.getRealDir() - if fileExists(pkgDir / "nimblepkg" / "nimscriptapi.nim"): - result = pkgDir - proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir when declared(ModuleGraph): @@ -222,16 +206,12 @@ proc execScript(scriptName: string, flags: StringTableRef, let pkgName = scriptName.splitFile.name # Ensure that "nimblepkg/nimscriptapi" is in the PATH. - let nimscriptApiPath = findNimscriptApi(options) - if nimscriptApiPath.len > 0: - # TODO: Once better output is implemented show a message here. - appendStr(searchPaths, nimscriptApiPath) - else: - let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" - createDir(tmpNimscriptApiPath.splitFile.dir) - if not existsFile(tmpNimscriptApiPath): - writeFile(tmpNimscriptApiPath, nimscriptApi) - appendStr(searchPaths, getTempDir()) + # TODO: put this in a more isolated directory. + let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" + createDir(tmpNimscriptApiPath.splitFile.dir) + if not existsFile(tmpNimscriptApiPath): + writeFile(tmpNimscriptApiPath, nimscriptApi) + appendStr(searchPaths, getTempDir()) initDefines() loadConfigs(DefaultConfig) From 8a3c661b9898d94d81028ff8ed5fae2d5e29f882 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 5 Jan 2017 21:28:52 +0000 Subject: [PATCH 148/424] Add info about external dependency feature to changelog. --- changelog.markdown | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.markdown b/changelog.markdown index b65e92e..b3be182 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,7 +3,7 @@ # Nimble changelog -## 0.8.0 - 01/01/2017 +## 0.8.0 - 05/01/2017 This is a large release containing multiple new features and many bug fixes. @@ -25,6 +25,10 @@ This is a large release containing multiple new features and many bug fixes. into ``~/.nimble/pkgs/compiler-#head``. This reduces the amount of redundant installs. See [#88](https://github.com/nim-lang/nimble/issues/88) for more information. +* External dependencies can now be specified in .nimble files. Nimble doesn't + install these, but does instruct the user on how they can be installed. + More information about this feature can be found in the + [readme](https://github.com/nim-lang/nimble#external-dependencies). * Nimble now supports package aliases in the packages.json files. * Fixed regression that caused transitive dependencies to not be installed. * Fixed problem with ``install`` command when a ``src`` directory is present @@ -41,7 +45,7 @@ This is a large release containing multiple new features and many bug fixes. ---- Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.10...v0.8.0 -Full list of issues which have been closed: https://github.com/nim-lang/nimble/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-10-09+..+2017-01-01%22+ +Full list of issues which have been closed: https://github.com/nim-lang/nimble/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-10-09+..+2017-01-05%22+ ## 0.7.10 - 09/10/2016 From 08f503278162b2091c71545d0dbe7778c02926c4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 5 Jan 2017 21:32:01 +0000 Subject: [PATCH 149/424] Small changelog adjustment. --- changelog.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.markdown b/changelog.markdown index b3be182..76716f7 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -45,6 +45,7 @@ This is a large release containing multiple new features and many bug fixes. ---- Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.10...v0.8.0 + Full list of issues which have been closed: https://github.com/nim-lang/nimble/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-10-09+..+2017-01-05%22+ ## 0.7.10 - 09/10/2016 From d78af3acf10b218cadc960dafd99ce866d780e4f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 8 Jan 2017 18:15:36 +0100 Subject: [PATCH 150/424] Fixes aporia install. See nim-lang/aporia#136. Refs #311. --- src/nimble.nim | 13 +++++++--- src/nimblepkg/version.nim | 53 +++++++++++++++++---------------------- tests/tester.nim | 6 +++++ 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 55a0b09..e1f9ccc 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -227,7 +227,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = "dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion], priority = HighPriority) - let pkglist = getInstalledPkgsMin(options.getPkgsDir(), options) + var pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) var reverseDeps: seq[tuple[name, version: string]] = @[] for dep in pkginfo.requires: if dep.name == "nimrod" or dep.name == "nim": @@ -255,6 +255,9 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = result.add(paths) pkg = installedPkg # For addRevDep + + # This package has been installed so we add it to our pkgList. + pkgList.add((pkg, readMetaData(pkg.getRealDir()))) else: display("Info:", "Dependency on $1 already satisfied" % $dep, priority = HighPriority) @@ -441,9 +444,10 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, filesInstalled.incl copyFileD(file, dest) # Copy the .nimble file. - let dest = changeRoot(pkgInfo.mypath.splitFile.dir, pkgDestDir, - pkgInfo.mypath) - filesInstalled.incl copyFileD(pkgInfo.mypath, dest) + let dest = changeRoot(pkgInfo.myPath.splitFile.dir, pkgDestDir, + pkgInfo.myPath) + filesInstalled.incl copyFileD(pkgInfo.myPath, dest) + pkgInfo.myPath = dest var binariesInstalled = initSet[string]() if pkgInfo.bin.len > 0: @@ -518,6 +522,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Return the paths to the dependencies of this package. result.paths.add pkgDestDir result.pkg = pkgInfo + result.pkg.isInstalled = true display("Success:", pkgInfo.name & " installed successfully.", Success, HighPriority) diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index b4d42f5..0a70c88 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -51,7 +51,8 @@ proc isSpecial*(ver: Version): bool = proc `<`*(ver: Version, ver2: Version): bool = # Handling for special versions such as "#head" or "#branch". if ver.isSpecial or ver2.isSpecial: - return false + # TODO: This may need to be reverted. See #311. + return ($ver2).normalize == "#head" and ($ver).normalize != "#head" # Handling for normal versions such as "0.1.0" or "1.0". var sVer = string(ver).split('.') @@ -103,32 +104,23 @@ proc `==`*(range1: VersionRange, range2: VersionRange): bool = of verAny: true proc withinRange*(ver: Version, ran: VersionRange): bool = - if ver.isSpecial: - case ran.kind - of verLater, verEarlier, verEqLater, verEqEarlier, verEq, verIntersect: - return false - of verSpecial: - return ver == ran.spe - of verAny: - return true - else: - case ran.kind - of verLater: - return ver > ran.ver - of verEarlier: - return ver < ran.ver - of verEqLater: - return ver >= ran.ver - of verEqEarlier: - return ver <= ran.ver - of verEq: - return ver == ran.ver - of verSpecial: - return false - of verIntersect: - return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight) - of verAny: - return true + case ran.kind + of verLater: + return ver > ran.ver + of verEarlier: + return ver < ran.ver + of verEqLater: + return ver >= ran.ver + of verEqEarlier: + return ver <= ran.ver + of verEq: + return ver == ran.ver + of verSpecial: + return ver == ran.spe + of verIntersect: + return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight) + of verAny: + return true proc contains*(ran: VersionRange, ver: Version): bool = return withinRange(ver, ran) @@ -342,9 +334,10 @@ when isMainModule: doAssert newVersion("#head") in parseVersionRange("#head") - # TODO: It may be worth changing this in the future, although we can't be - # certain that #head is in fact newer than v0.1.0. - doAssert(not(newVersion("#head") > newVersion("0.1.0"))) + # We assume that #head > 0.1.0, in practice this shouldn't be a problem. + doAssert(newVersion("#head") > newVersion("0.1.0")) + doAssert(not(newVersion("#head") > newVersion("#head"))) + doAssert(withinRange(newVersion("#head"), parseVersionRange(">= 0.5.0"))) # An empty version range should give verAny doAssert parseVersionRange("").kind == verAny diff --git a/tests/tester.nim b/tests/tester.nim index 78df424..007572f 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -42,6 +42,12 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "picks #head when looking for packages": + cd "versionClashes" / "aporiaScenario": + check execNimble("install", "-y", "--verbose").exitCode == QuitSuccess + check execNimble("remove", "aporiascenario", "-y").exitCode == QuitSuccess + check execNimble("remove", "packagea", "-y").exitCode == QuitSuccess + test "can distinguish package reading in nimbleDir vs. other dirs (#304)": cd "issue304" / "package-test": check execNimble("tasks").exitCode == QuitSuccess From f847344784fcb3e8a8f153ecaa5d91d3e64fc6f5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 8 Jan 2017 18:16:56 +0100 Subject: [PATCH 151/424] Add missing test files. --- .../aporiaScenario/aporiaScenario.nimble | 13 +++++++++++++ tests/versionClashes/readme.md | 5 +++++ 2 files changed, 18 insertions(+) create mode 100644 tests/versionClashes/aporiaScenario/aporiaScenario.nimble create mode 100644 tests/versionClashes/readme.md diff --git a/tests/versionClashes/aporiaScenario/aporiaScenario.nimble b/tests/versionClashes/aporiaScenario/aporiaScenario.nimble new file mode 100644 index 0000000..3be5bbc --- /dev/null +++ b/tests/versionClashes/aporiaScenario/aporiaScenario.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = " " +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.2" +requires "https://github.com/nimble-test/packagea.git#head" +requires "https://github.com/nimble-test/packagea.git >= 0.5" + diff --git a/tests/versionClashes/readme.md b/tests/versionClashes/readme.md new file mode 100644 index 0000000..374f2b6 --- /dev/null +++ b/tests/versionClashes/readme.md @@ -0,0 +1,5 @@ +Tests to ensure that the following errors are correct. + +``` +Cannot satisfy dependency on gtk2 1.0 and gtk2 1.1 +``` \ No newline at end of file From c37420d507c2712a0c0e2920dd71e33d7a1999bd Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 8 Jan 2017 18:34:34 +0100 Subject: [PATCH 152/424] Bump to v0.8.2. --- src/nimblepkg/common.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 79729ed..bc89955 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -50,4 +50,4 @@ when not defined(nimscript): raise exc const - nimbleVersion* = "0.8.0" + nimbleVersion* = "0.8.2" From 297d3651aed16dcd6c8ae3ef46bab277fd5590ff Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 8 Jan 2017 18:38:29 +0100 Subject: [PATCH 153/424] Clarify install instructions to mention `koch`. --- readme.markdown | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/readme.markdown b/readme.markdown index 97a28d5..9513b8a 100644 --- a/readme.markdown +++ b/readme.markdown @@ -76,12 +76,12 @@ But in case you still want to install Nimble manually, you can follow the following instructions. There are two ways to install Nimble manually. The first is using the -``install_nimble.nims`` script included in the Nim distribution and -[repository](https://github.com/nim-lang/Nim/blob/devel/install_nimble.nims). -Simply execute this to install Nimble. +``koch`` tool included in the Nim distribution and +[repository](https://github.com/nim-lang/Nim/blob/devel/koch.nim). +Simply execute the following command to compile and install Nimble. ``` -nim e install_nimble.nims +./koch nimble ``` This will clone the Nimble repository, compile Nimble and copy it into @@ -765,6 +765,10 @@ flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. +* ``Error: ambiguous identifier: 'version' --use nimscriptapi.version or system.version`` + +Make sure that you are running at least version 0.16.0 of Nim (or the latest nightly). + ## Repository information This repository has two main branches: ``master`` and ``stable``. From 690fcf04a378da0eb3f4c164077bcfccc6cf2b6d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 8 Jan 2017 18:41:00 +0100 Subject: [PATCH 154/424] Add 0.8.2 changelog. --- changelog.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index 76716f7..85f8b27 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,11 @@ # Nimble changelog +## 0.8.2 - 08/01/2017 + +This is a small bug fix release which resolves problems with the installation +of Aporia (and likely other Nimble packages). + ## 0.8.0 - 05/01/2017 This is a large release containing multiple new features and many bug fixes. From 756beb6b5e846bb43898e097f7523e9b4dbedc75 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 9 Jan 2017 20:28:03 +0100 Subject: [PATCH 155/424] Increment to v0.8.3. --- src/nimblepkg/common.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index bc89955..dabda67 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -50,4 +50,4 @@ when not defined(nimscript): raise exc const - nimbleVersion* = "0.8.2" + nimbleVersion* = "0.8.3" From 97c67e64a4a1391b54a4ad531c9636258419d184 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 9 Jan 2017 20:28:17 +0100 Subject: [PATCH 156/424] Fixes #312. --- readme.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.markdown b/readme.markdown index 9513b8a..5a8cb99 100644 --- a/readme.markdown +++ b/readme.markdown @@ -441,6 +441,10 @@ resembles that of many other package managers. | ``./tests/`` | Project test files | | ``./docs/`` | Project documentation | +**Note:** Nimble will by default look for source files in ``.``, in order to +use this layout you will need to specify ``srcDir = "src"`` in your .nimble +file. + #### Tests A common problem that arises with tests is the fact that they need to import From 69efef5f4b87c567879802908d26355f30531cf0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 10 Jan 2017 23:53:46 +0100 Subject: [PATCH 157/424] Fixes #313. Fixes #314. Binary packages installation issues fixed. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index e1f9ccc..15f8fb7 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -447,7 +447,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, let dest = changeRoot(pkgInfo.myPath.splitFile.dir, pkgDestDir, pkgInfo.myPath) filesInstalled.incl copyFileD(pkgInfo.myPath, dest) - pkgInfo.myPath = dest var binariesInstalled = initSet[string]() if pkgInfo.bin.len > 0: @@ -523,6 +522,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, result.paths.add pkgDestDir result.pkg = pkgInfo result.pkg.isInstalled = true + result.pkg.myPath = dest display("Success:", pkgInfo.name & " installed successfully.", Success, HighPriority) From ee07fb83e7f54c6973da08755d39d4866016d142 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 11 Jan 2017 00:10:40 +0100 Subject: [PATCH 158/424] Always overwrite temporary nimscriptapi.nim in /tmp. --- src/nimblepkg/nimscriptsupport.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 86fde03..a154891 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -209,8 +209,7 @@ proc execScript(scriptName: string, flags: StringTableRef, # TODO: put this in a more isolated directory. let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" createDir(tmpNimscriptApiPath.splitFile.dir) - if not existsFile(tmpNimscriptApiPath): - writeFile(tmpNimscriptApiPath, nimscriptApi) + writeFile(tmpNimscriptApiPath, nimscriptApi) appendStr(searchPaths, getTempDir()) initDefines() From caae0a3cbd853dc9f0c9a9814970648fd413e7ec Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Fri, 27 Jan 2017 20:25:25 -0500 Subject: [PATCH 159/424] updating git command to fetch the url of the remote origin --- src/nimblepkg/publish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 1448a95..38beac6 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -122,7 +122,7 @@ proc editJson(p: PackageInfo; url, tags, downloadMethod: string) = proc getPackageOriginUrl(a: Auth): string = ## Adds 'user:pw' to the URL so that the user is not asked *again* for it. ## We need this for 'git push'. - let (output, exitCode) = doCmdEx("git config --get remote.origin.url") + let (output, exitCode) = doCmdEx("git ls-remote --get-url") result = "origin" if exitCode == 0: result = output.string.strip From f61345878093bb20502eaab6370adbf58a85b201 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Sat, 28 Jan 2017 10:47:04 -0500 Subject: [PATCH 160/424] whooops, missed part two of this changeset --- src/nimblepkg/publish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 38beac6..df67b2d 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -167,7 +167,7 @@ proc publish*(p: PackageInfo) = var url = "" var downloadMethod = "" if dirExists(os.getCurrentDir() / ".git"): - let (output, exitCode) = doCmdEx("git config --get remote.origin.url") + let (output, exitCode) = doCmdEx("git ls-remote --get-url") if exitCode == 0: url = output.string.strip if url.endsWith(".git"): url.setLen(url.len - 4) From f479213ad84ed1428cf7fbe132f50eb39bf013e2 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 15:57:15 +0100 Subject: [PATCH 161/424] Fixes #323. --- src/nimble.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 15f8fb7..9d19199 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -455,10 +455,10 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Set file permissions to +x for all binaries built, # and symlink them on *nix OS' to $nimbleDir/bin/ for bin in pkgInfo.bin: - if not existsFile(pkgDestDir / bin): + if existsFile(pkgDestDir / bin): display("Warning:", ("Binary '$1' was already installed from source" & " directory. Will be overwritten.") % bin, Warning, - HighPriority) + MediumPriority) # Copy the binary file. filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), From 64518698e2b5fae8cf2c0a0cac46fa764a02240b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 16:07:23 +0100 Subject: [PATCH 162/424] Travis: Use ubuntu 14.04 instead of 12.04. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 97237da..91459cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,12 @@ os: - linux +dist: trusty language: c install: - | - wget http://nim-lang.org/download/nim-0.15.2.tar.xz + wget https://nim-lang.org/download/nim-0.15.2.tar.xz tar -xf nim-0.15.2.tar.xz cd nim-0.15.2 LDFLAGS=-lrt sh build.sh From 015233a8b6813696d29901b0f45083e0cdef67c5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 16:16:17 +0100 Subject: [PATCH 163/424] Travis: Upgrade to Nim 0.16.0. --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 91459cb..5dead07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,16 @@ language: c install: - | - wget https://nim-lang.org/download/nim-0.15.2.tar.xz - tar -xf nim-0.15.2.tar.xz - cd nim-0.15.2 - LDFLAGS=-lrt sh build.sh + wget https://nim-lang.org/download/nim-0.16.0.tar.xz + tar -xf nim-0.16.0.tar.xz + cd nim-0.16.0 + sh build.sh cd .. before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.15.2/bin:$PATH + - export PATH=`pwd`/nim-0.16.0/bin:$PATH script: - cd tests From 4c99e3b6eb50cfe2c1a604d0c0dec97607eb002c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 16:58:53 +0100 Subject: [PATCH 164/424] Fixes #321. --- src/nimble.nim | 18 +++++++++--------- src/nimblepkg/common.nim | 12 ++++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9d19199..9edf446 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -309,8 +309,13 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = [pkgInfo.backend, releaseOpt, args, outputOpt, realDir / bin.changeFileExt("nim")]) except NimbleError: - raise newException(BuildFailed, "Build failed for package: " & - pkgInfo.name) + let currentExc = (ref NimbleError)(getCurrentException()) + let exc = newException(BuildFailed, "Build failed for package: " & + pkgInfo.name) + let (error, hint) = getOutputInfo(currentExc) + exc.msg.add("\nDetails:\n" & error) + exc.hint = hint + raise exc proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, filesInstalled, bins: HashSet[string]) = @@ -1072,13 +1077,8 @@ when isMainModule: try: parseCmdLine().doAction() except NimbleError: - let err = (ref NimbleError)(getCurrentException()) - error = err.msg - when not defined(release): - let stackTrace = getStackTrace(getCurrentException()) - error = stackTrace & "\n\n" & error - if not err.isNil: - hint = err.hint + let currentExc = (ref NimbleError)(getCurrentException()) + (error, hint) = getOutputInfo(currentExc) except NimbleQuit: nil finally: diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index dabda67..8a90e47 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -49,5 +49,17 @@ when not defined(nimscript): exc.hint = hint raise exc + proc getOutputInfo*(err: ref NimbleError): (string, string) = + var error = "" + var hint = "" + error = err.msg + when not defined(release): + let stackTrace = getStackTrace(err) + error = stackTrace & "\n\n" & error + if not err.isNil: + hint = err.hint + + return (error, hint) + const nimbleVersion* = "0.8.3" From c4d294ca9bfa8b69df48e6232c6768c197803716 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 20:47:47 +0100 Subject: [PATCH 165/424] Fixes #319. --- src/nimblepkg/packageparser.nim | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index fef696b..f93714d 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,14 +1,14 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, json, streams, strutils, parseutils, os, tables +import parsecfg, json, streams, strutils, parseutils, os, tables, future +from sequtils import apply, map + import version, tools, common, nimscriptsupport, options, packageinfo, cli ## Contains procedures for parsing .nimble files. Moved here from ``packageinfo`` ## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also ## depends on other procedures in ``packageinfo``. -from sequtils import apply - type NimbleFile* = string @@ -96,8 +96,12 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = raiseNewValidationError(msg, true, hint, true) else: assert(not pkgInfo.isMinimal) + # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. + let normalizedBinNames = pkgInfo.bin.map( + (x) => x.changeFileExt("").toLowerAscii() + ) let correctDir = - if pkgInfo.name in pkgInfo.bin: + if pkgInfo.name.toLowerAscii() in normalizedBinNames: pkgInfo.name & "pkg" else: pkgInfo.name From 0a280aa6dd0c7566fbf70775b69f33b100f2d1de Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 29 Jan 2017 21:31:31 +0100 Subject: [PATCH 166/424] Version 0.8.4 --- changelog.markdown | 10 ++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index 85f8b27..b6fdcff 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,16 @@ # Nimble changelog +## 0.8.4 - 29/01/2017 + +Another bug fix release which resolves problems related to stale nimscriptapi +files in /tmp/, no compilation output when ``nimble build`` fails, and issues +with the new package validation on Windows. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.2...v0.8.4 + ## 0.8.2 - 08/01/2017 This is a small bug fix release which resolves problems with the installation diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 8a90e47..d513101 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -62,4 +62,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.3" + nimbleVersion* = "0.8.4" From 83731a9b32fd8a1f41d5e780b1e2def0b4183a5c Mon Sep 17 00:00:00 2001 From: Andrea Ferretti Date: Fri, 10 Feb 2017 16:53:27 +0100 Subject: [PATCH 167/424] Fixed #329 --- src/nimble.nim | 5 +++-- src/nimblepkg/nimscriptsupport.nim | 23 ++++++++++++++--------- tests/nimscript/nimscript.nimble | 5 +++++ tests/tester.nim | 11 +++++++++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9edf446..1df791a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1063,8 +1063,9 @@ proc doAction(options: Options) = parseCommand(execResult.command, newOptions) for arg in execResult.arguments: parseArgument(arg, newOptions) - for flag, val in execResult.flags: - parseFlag(flag, val, newOptions) + for flag, vals in execResult.flags: + for val in vals: + parseFlag(flag, val, newOptions) doAction(newOptions) if options.action.typ != actionCustom: diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index a154891..5ef3ce3 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -16,17 +16,18 @@ from compiler/astalgo import strTableGet import compiler/options as compiler_options import common, version, options, packageinfo, cli -import os, strutils, strtabs, times, osproc, sets +import os, strutils, strtabs, tables, times, osproc, sets when not declared(resetAllModulesHard): import compiler/modulegraphs type + Flags = TableRef[string, seq[string]] ExecutionResult*[T] = object success*: bool command*: string arguments*: seq[string] - flags*: StringTableRef + flags*: Flags retVal*: T const @@ -74,8 +75,7 @@ proc extractRequires(ident: PSym, result: var seq[PkgTuple]) = when declared(newIdentCache): var identCache = newIdentCache() -proc setupVM(module: PSym; scriptName: string, - flags: StringTableRef): PEvalContext = +proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = ## This procedure is exported in the compiler sources, but its implementation ## is too Nim-specific to be used by Nimble. ## Specifically, the implementation of ``switch`` is problematic. Sooo @@ -180,15 +180,20 @@ proc setupVM(module: PSym; scriptName: string, setResult(a, compiler_options.command) cbconf switch: if not flags.isNil: - flags[a.getString 0] = a.getString 1 + let + key = a.getString 0 + value = a.getString 1 + if flags.hasKey(key): + flags[key].add(value) + else: + flags[key] = @[value] proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir when declared(ModuleGraph): var graph: ModuleGraph -proc execScript(scriptName: string, flags: StringTableRef, - options: Options): PSym = +proc execScript(scriptName: string, flags: Flags, options: Options): PSym = ## Executes the specified script. Returns the script's module symbol. ## ## No clean up is performed and must be done manually! @@ -364,7 +369,7 @@ proc execTask*(scriptName, taskName: string, ## ## `scriptName` should be a filename pointing to the nimscript file. result.success = true - result.flags = newStringTable() + result.flags = newTable[string, seq[string]]() compiler_options.command = internalCmd display("Executing", "task $# in $#" % [taskName, scriptName], priority = HighPriority) @@ -392,7 +397,7 @@ proc execHook*(scriptName, actionName: string, before: bool, ## ## `scriptName` should be a filename pointing to the nimscript file. result.success = true - result.flags = newStringTable() + result.flags = newTable[string, seq[string]]() compiler_options.command = internalCmd let hookName = if before: actionName.toLowerAscii & "Before" diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index bfa0405..ff8c5c6 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -21,6 +21,11 @@ task cr, "Testing `nimble c -r nimscript.nim` via setCommand": --r setCommand "c", "nimscript.nim" +task repeated, "Testing `nimble c nimscript.nim` with repeated flags": + --define: foo + --define: bar + setCommand "c", "nimscript.nim" + task api, "Testing nimscriptapi module functionality": echo(getPkgDir()) diff --git a/tests/tester.nim b/tests/tester.nim index 007572f..ca1bd1b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -192,6 +192,17 @@ test "can use nimscript's setCommand with flags": check exitCode == QuitSuccess check "Hello World".normalize in lines[^2].normalize +test "can use nimscript with repeated flags (issue #329)": + cd "nimscript": + let (output, exitCode) = execNimble("--debug", "repeated") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + var found = false + for line in lines: + if line.contains("--define:foo"): + found = true + check found == true + test "can list nimscript tasks": cd "nimscript": let (output, exitCode) = execNimble("tasks") From c13a1c89775d052cba375a98deeab5097a13ce78 Mon Sep 17 00:00:00 2001 From: Jeff Ciesielski Date: Tue, 21 Feb 2017 22:14:08 -0500 Subject: [PATCH 168/424] Add credential caching This change stores the user's github API token in ~/.nimble/api_token for ease of publishing. closes https://github.com/nim-lang/nimble/issues/307 --- src/nimble.nim | 2 +- src/nimblepkg/publish.nim | 39 ++++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 1df791a..6c174e6 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1028,7 +1028,7 @@ proc doAction(options: Options) = init(options) of actionPublish: var pkgInfo = getPkgInfo(getCurrentDir(), options) - publish(pkgInfo) + publish(pkgInfo, options) of actionDump: dump(options) of actionTasks: diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index df67b2d..a892503 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -6,7 +6,7 @@ import system except TResult import httpclient, base64, strutils, rdstdin, json, os, browsers, times, uri -import tools, common, cli +import tools, common, cli, config, options type Auth = object @@ -14,6 +14,9 @@ type pw: string token: string ## base64 encoding of user:pw +const + ApiKeyFile = "api_token" + proc userAborted() = raise newException(NimbleError, "User aborted the process.") @@ -22,18 +25,24 @@ proc createHeaders(a: Auth): string = "Content-Type: application/x-www-form-urlencoded\c\L" & "Accept: */*\c\L") -proc getGithubAuth(): Auth = - display("Info:", "Please create a new personal access token on Github in" & - " order to allow Nimble to fork the packages repository.", - priority = HighPriority) - display("Hint:", "Make sure to give the access token access to public repos" & - " (public_repo scope)!", Warning, HighPriority) - sleep(5000) - display("Info:", "Your default browser should open with the following URL: " & - "https://github.com/settings/tokens/new", priority = HighPriority) - sleep(3000) - openDefaultBrowser("https://github.com/settings/tokens/new") - result.token = promptCustom("Personal access token?", "").strip() +proc getGithubAuth(cfg: Config): Auth = + + try: + result.token = readFile(cfg.nimbleDir / ApiKeyFile) + except IOError: + display("Info:", "Please create a new personal access token on Github in" & + " order to allow Nimble to fork the packages repository.", + priority = HighPriority) + display("Hint:", "Make sure to give the access token access to public repos" & + " (public_repo scope)!", Warning, HighPriority) + sleep(5000) + display("Info:", "Your default browser should open with the following URL: " & + "https://github.com/settings/tokens/new", priority = HighPriority) + sleep(3000) + openDefaultBrowser("https://github.com/settings/tokens/new") + result.token = promptCustom("Personal access token?", "").strip() + writeFile(cfg.nimbleDir / ApiKeyFile, result.token) + let resp = getContent("https://api.github.com/user", extraHeaders=createHeaders(result)).parseJson() @@ -131,9 +140,9 @@ proc getPackageOriginUrl(a: Auth): string = result = "https://" & a.user & ':' & a.pw & '@' & result["https://".len .. ^1] -proc publish*(p: PackageInfo) = +proc publish*(p: PackageInfo, o: Options) = ## Publishes the package p. - let auth = getGithubAuth() + let auth = getGithubAuth(o.config) var pkgsDir = getTempDir() / "nimble-packages-fork" if not forkExists(auth): createFork(auth) From 8e143a097d9711051f8312426ee01254bb2db50a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 22 Feb 2017 18:17:18 +0100 Subject: [PATCH 169/424] Change name of file where publish token is saved. --- src/nimblepkg/publish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index a892503..5b123a3 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -15,7 +15,7 @@ type token: string ## base64 encoding of user:pw const - ApiKeyFile = "api_token" + ApiKeyFile = "github_api_token" proc userAborted() = raise newException(NimbleError, "User aborted the process.") From 32ed21695b9c01cef92f0f7f6d29f9cca30b30f9 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Sat, 11 Mar 2017 14:51:54 -0500 Subject: [PATCH 170/424] adding support for an environment variable --- src/nimblepkg/publish.nim | 44 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 5b123a3..a024490 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -16,6 +16,7 @@ type const ApiKeyFile = "github_api_token" + ApiTokenEnvironmentVariable = "NIMBLE_GITHUB_API_TOKEN" proc userAborted() = raise newException(NimbleError, "User aborted the process.") @@ -25,23 +26,36 @@ proc createHeaders(a: Auth): string = "Content-Type: application/x-www-form-urlencoded\c\L" & "Accept: */*\c\L") +proc requestNewToken(cfg: Config): string = + display("Info:", "Please create a new personal access token on Github in" & + " order to allow Nimble to fork the packages repository.", + priority = HighPriority) + display("Hint:", "Make sure to give the access token access to public repos" & + " (public_repo scope)!", Warning, HighPriority) + sleep(5000) + display("Info:", "Your default browser should open with the following URL: " & + "https://github.com/settings/tokens/new", priority = HighPriority) + sleep(3000) + openDefaultBrowser("https://github.com/settings/tokens/new") + let token = promptCustom("Personal access token?", "").strip() + # inform the user that their token will be written to disk + let token_write_path = cfg.nimbleDir / ApiKeyFile + display("Info:", "Writing access token to file:" & token_write_path, + priority = HighPriority) + writeFile(token_write_path, token) + return token + proc getGithubAuth(cfg: Config): Auth = - try: - result.token = readFile(cfg.nimbleDir / ApiKeyFile) - except IOError: - display("Info:", "Please create a new personal access token on Github in" & - " order to allow Nimble to fork the packages repository.", - priority = HighPriority) - display("Hint:", "Make sure to give the access token access to public repos" & - " (public_repo scope)!", Warning, HighPriority) - sleep(5000) - display("Info:", "Your default browser should open with the following URL: " & - "https://github.com/settings/tokens/new", priority = HighPriority) - sleep(3000) - openDefaultBrowser("https://github.com/settings/tokens/new") - result.token = promptCustom("Personal access token?", "").strip() - writeFile(cfg.nimbleDir / ApiKeyFile, result.token) + # always prefer the environment variable to asking for a new one + if existsEnv(ApiTokenEnvironmentVariable): + result.token = getEnv(ApiTokenEnvironmentVariable) + else: + # try to read from disk, if it cannot be found write a new one + try: + result.token = readFile(cfg.nimbleDir / ApiKeyFile) + except IOError: + result.token = requestNewToken(cfg) let resp = getContent("https://api.github.com/user", extraHeaders=createHeaders(result)).parseJson() From 26344e20830f6d9029844ecae310b9bdecc1f99b Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Sat, 11 Mar 2017 14:54:48 -0500 Subject: [PATCH 171/424] adding on-screen delay for new message --- src/nimblepkg/publish.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index a024490..562a388 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -43,6 +43,7 @@ proc requestNewToken(cfg: Config): string = display("Info:", "Writing access token to file:" & token_write_path, priority = HighPriority) writeFile(token_write_path, token) + sleep(3000) return token proc getGithubAuth(cfg: Config): Auth = From 47f5691c0b15c101ad21aa4a21950d555b50132b Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Mon, 13 Mar 2017 13:18:27 -0400 Subject: [PATCH 172/424] adding new display message about where the token is coming from --- src/nimblepkg/publish.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 562a388..9b24518 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -51,6 +51,9 @@ proc getGithubAuth(cfg: Config): Auth = # always prefer the environment variable to asking for a new one if existsEnv(ApiTokenEnvironmentVariable): result.token = getEnv(ApiTokenEnvironmentVariable) + display("Info:", "Using the '" & ApiTokenEnvironmentVariable & + "' environment varaible for the GitHub API Token.", + priority = HighPriority) else: # try to read from disk, if it cannot be found write a new one try: From ad869f9df65cb8972a555b954fc9dd4561667994 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Mon, 13 Mar 2017 13:38:32 -0400 Subject: [PATCH 173/424] fixing typo and adding message for retrieving API Token from file --- src/nimblepkg/publish.nim | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 9b24518..6dd2378 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -52,12 +52,15 @@ proc getGithubAuth(cfg: Config): Auth = if existsEnv(ApiTokenEnvironmentVariable): result.token = getEnv(ApiTokenEnvironmentVariable) display("Info:", "Using the '" & ApiTokenEnvironmentVariable & - "' environment varaible for the GitHub API Token.", + "' environment variable for the GitHub API Token.", priority = HighPriority) else: # try to read from disk, if it cannot be found write a new one try: - result.token = readFile(cfg.nimbleDir / ApiKeyFile) + let api_token_file_path = cfg.nimbleDir / ApiKeyFile + result.token = readFile(api_token_file_path) + display("Info:", "Using GitHub API Token in file: " & api_token_file_path, + priority = HighPriority) except IOError: result.token = requestNewToken(cfg) From 0d516b483ee27497202faca04e1ec4a56d458108 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Mon, 13 Mar 2017 14:47:16 -0400 Subject: [PATCH 174/424] fixing casing --- src/nimblepkg/publish.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 6dd2378..2a4ce93 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -39,10 +39,10 @@ proc requestNewToken(cfg: Config): string = openDefaultBrowser("https://github.com/settings/tokens/new") let token = promptCustom("Personal access token?", "").strip() # inform the user that their token will be written to disk - let token_write_path = cfg.nimbleDir / ApiKeyFile - display("Info:", "Writing access token to file:" & token_write_path, + let tokenWritePath = cfg.nimbleDir / ApiKeyFile + display("Info:", "Writing access token to file:" & tokenWritePath, priority = HighPriority) - writeFile(token_write_path, token) + writeFile(tokenWritePath, token) sleep(3000) return token @@ -57,9 +57,9 @@ proc getGithubAuth(cfg: Config): Auth = else: # try to read from disk, if it cannot be found write a new one try: - let api_token_file_path = cfg.nimbleDir / ApiKeyFile - result.token = readFile(api_token_file_path) - display("Info:", "Using GitHub API Token in file: " & api_token_file_path, + let apiTokenFilePath = cfg.nimbleDir / ApiKeyFile + result.token = readFile(apiTokenFilePath) + display("Info:", "Using GitHub API Token in file: " & apiTokenFilePath, priority = HighPriority) except IOError: result.token = requestNewToken(cfg) From 2e9c50e4879bfbfc3b31bc9d96d5ffc30c10e8cb Mon Sep 17 00:00:00 2001 From: Andrea Ferretti Date: Fri, 7 Apr 2017 15:09:13 +0200 Subject: [PATCH 175/424] Fixed https://github.com/nim-lang/nimble/issues/339 --- src/nimblepkg/options.nim | 45 ++++++++++++++++++++------------------- tests/tester.nim | 4 ++++ 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 85a473c..f2eadbe 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -235,11 +235,12 @@ proc parseArgument*(key: string, result: var Options) = else: discard -proc parseFlag*(flag, val: string, result: var Options) = +proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = var wasFlagHandled = true + let f = flag.normalize() # Global flags. - case flag.normalize() + case f of "help", "h": writeHelp() of "version", "v": writeVersion() of "accept", "y": result.forcePrompts = forcePromptYes @@ -248,28 +249,28 @@ proc parseFlag*(flag, val: string, result: var Options) = of "verbose": result.verbosity = LowPriority of "debug": result.verbosity = DebugPriority # Action-specific flags. - of "installed", "i": - if result.action.typ in [actionSearch, actionList]: - result.queryInstalled = true - else: - wasFlagHandled = false - of "depsonly", "d": - if result.action.typ == actionInstall: - result.depsOnly = true - else: - wasFlagHandled = false - of "ver": - if result.action.typ in [actionSearch, actionList]: - result.queryVersions = true - else: - wasFlagHandled = false else: case result.action.typ - of actionCompile, actionDoc: - if val == "": - result.action.compileOptions.add("--" & flag) + of actionSearch, actionList: + case f + of "installed", "i": + result.queryInstalled = true + of "ver": + result.queryVersions = true else: - result.action.compileOptions.add("--" & flag & ":" & val) + wasFlagHandled = false + of actionInstall: + case f + of "depsonly", "d": + result.depsOnly = true + else: + wasFlagHandled = false + of actionCompile, actionDoc: + let prefix = if kind == cmdShortOption: "-" else: "--" + if val == "": + result.action.compileOptions.add(prefix & flag) + else: + result.action.compileOptions.add(prefix & flag & ":" & val) of actionCustom: result.action.flags[flag] = val else: @@ -310,7 +311,7 @@ proc parseCmdLine*(): Options = else: parseArgument(key, result) of cmdLongOption, cmdShortOption: - parseFlag(key, val, result) + parseFlag(key, val, result, kind) of cmdEnd: assert(false) # cannot happen # Set verbosity level. diff --git a/tests/tester.nim b/tests/tester.nim index ca1bd1b..02a4843 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -52,6 +52,10 @@ test "can distinguish package reading in nimbleDir vs. other dirs (#304)": cd "issue304" / "package-test": check execNimble("tasks").exitCode == QuitSuccess +test "can accept short flags (#329)": + cd "nimscript": + check execNimble("c", "-d:release", "nimscript.nim").exitCode == QuitSuccess + test "can build with #head and versioned package (#289)": cd "issue289": check execNimble(["install", "-y"]).exitCode == QuitSuccess From 745a7863d2b72af0be6c0869aa1a18e000cd66c5 Mon Sep 17 00:00:00 2001 From: Andrea Ferretti Date: Fri, 7 Apr 2017 15:32:31 +0200 Subject: [PATCH 176/424] Fixed https://github.com/nim-lang/nimble/issues/305 --- src/nimblepkg/tools.nim | 20 ++++++++++++-------- tests/tester.nim | 4 ++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 3bd0365..29fbf5d 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -21,18 +21,22 @@ proc doCmd*(cmd: string, showOutput = false) = stderr.flushFile() displayDebug("Executing", cmd) - let (output, exitCode) = execCmdEx(cmd) - displayDebug("Finished", "with exit code " & $exitCode) - # TODO: Improve to show output in real-time. if showOutput: - display("Output:", output, priority = HighPriority) + let exitCode = execCmd(cmd) + displayDebug("Finished", "with exit code " & $exitCode) + if exitCode != QuitSuccess: + raise newException(NimbleError, + "Execution failed with exit code $1\nCommand: $2" % + [$exitCode, cmd]) else: + let (output, exitCode) = execCmdEx(cmd) + displayDebug("Finished", "with exit code " & $exitCode) displayDebug("Output", output) - if exitCode != QuitSuccess: - raise newException(NimbleError, - "Execution failed with exit code $1\nCommand: $2\nOutput: $3" % - [$exitCode, cmd, output]) + if exitCode != QuitSuccess: + raise newException(NimbleError, + "Execution failed with exit code $1\nCommand: $2\nOutput: $3" % + [$exitCode, cmd, output]) proc doCmdEx*(cmd: string): tuple[output: TaintedString, exitCode: int] = let bin = extractBin(cmd) diff --git a/tests/tester.nim b/tests/tester.nim index ca1bd1b..28856b3 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -188,9 +188,9 @@ test "can use nimscript's setCommand": test "can use nimscript's setCommand with flags": cd "nimscript": let (output, exitCode) = execNimble("--debug", "cr") - let lines = output.strip.splitLines() + # let lines = output.strip.splitLines() check exitCode == QuitSuccess - check "Hello World".normalize in lines[^2].normalize + # check "Hello World".normalize in lines[^2].normalize test "can use nimscript with repeated flags (issue #329)": cd "nimscript": From b98b697beab9dbbb83bd830bae96f75762e44d31 Mon Sep 17 00:00:00 2001 From: Andrea Ferretti Date: Fri, 7 Apr 2017 19:46:52 +0200 Subject: [PATCH 177/424] Fixed test --- tests/tester.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 28856b3..9ca27fa 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -188,9 +188,9 @@ test "can use nimscript's setCommand": test "can use nimscript's setCommand with flags": cd "nimscript": let (output, exitCode) = execNimble("--debug", "cr") - # let lines = output.strip.splitLines() + let lines = output.strip.splitLines() check exitCode == QuitSuccess - # check "Hello World".normalize in lines[^2].normalize + check inLines(lines, "Hello World") test "can use nimscript with repeated flags (issue #329)": cd "nimscript": From b7201c81a41ab1b8c7d7d54ec371b7ee28225471 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Sat, 22 Apr 2017 13:33:49 -0400 Subject: [PATCH 178/424] Modifying how package install path is validated Fix: * This addresses a bug where nimble will throw an exception in the middle of installation due to trying to evaluate paths that are not normalized. This was fixed by adding some additional validation checks that involve comparing paths by normalizing them first. [#338] --- src/nimblepkg/tools.nim | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 29fbf5d..ebc268d 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -79,7 +79,14 @@ proc changeRoot*(origRoot, newRoot, path: string): string = ## newRoot: /home/test/ ## path: /home/dom/bar/blah/2/foo.txt ## Return value -> /home/test/bar/blah/2/foo.txt - if path.startsWith(origRoot): + + ## The additional check of `path.samePaths(origRoot)` is necessary to prevent + ## a regression, where by ending the `srcDir` defintion in a nimble file in a + ## trailing separator would cause the `path.startsWith(origRoot)` evaluation to + ## fail because of the value of `origRoot` would be longer than `path` due to + ## the trailing separator. This would cause this method to throw during package + ## installation. + if path.startsWith(origRoot) or path.samePaths(origRoot): return newRoot / path[origRoot.len .. path.len-1] else: raise newException(ValueError, From 05f0de449211217da01a83775b1346cd807f5f31 Mon Sep 17 00:00:00 2001 From: Samantha Marshall Date: Mon, 24 Apr 2017 13:45:31 -0400 Subject: [PATCH 179/424] Adding tests to fix for #338 Test: * Added new test case for issue #338, where package installation would fail when the `srcDir` path ended in a directory separator. --- tests/issue338/issue338.nimble | 7 +++++++ tests/issue338/src/issue338.nim | 0 tests/tester.nim | 4 ++++ 3 files changed, 11 insertions(+) create mode 100644 tests/issue338/issue338.nimble create mode 100644 tests/issue338/src/issue338.nim diff --git a/tests/issue338/issue338.nimble b/tests/issue338/issue338.nimble new file mode 100644 index 0000000..fae4ae5 --- /dev/null +++ b/tests/issue338/issue338.nimble @@ -0,0 +1,7 @@ +# Package +version = "0.1.0" +author = "Samantha Marshall" +description = "test case to validate successful install when `srcDir` value ends in a directory separator" +license = "MIT" + +srcDir = "src/" diff --git a/tests/issue338/src/issue338.nim b/tests/issue338/src/issue338.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/tester.nim b/tests/tester.nim index 6749927..8cbf3d6 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -286,6 +286,10 @@ test "issue #206": (output, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess +test "issue #338": + cd "issue338": + check execNimble("install", "-y").exitCode == QuitSuccess + test "can list": check execNimble("list").exitCode == QuitSuccess From c1ffe62a68bb5d22c512b542f2558eb1539ede06 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 28 Apr 2017 16:52:34 +0200 Subject: [PATCH 180/424] Allow doAction to show help/version instead of CLI parser. --- src/nimble.nim | 5 +++++ src/nimblepkg/options.nim | 17 +++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6c174e6..ee2bccd 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -988,6 +988,11 @@ proc execHook(options: Options, before: bool): bool = result = res.retVal proc doAction(options: Options) = + if options.showHelp: + writeHelp() + if options.showVersion: + writeVersion() + if not existsDir(options.getNimbleDir()): createDir(options.getNimbleDir()) if not existsDir(options.getPkgsDir): diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index f2eadbe..8932d41 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -18,6 +18,8 @@ type config*: Config nimbleData*: JsonNode ## Nimbledata.json pkgInfoCache*: TableRef[string, PackageInfo] + showHelp*: bool + showVersion*: bool ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, @@ -45,7 +47,6 @@ type arguments*: seq[string] flags*: StringTableRef - const help* = """ Usage: nimble COMMAND [opts] @@ -88,7 +89,7 @@ Options: -n, --reject Reject all interactive prompts. --ver Query remote server for package version information when searching or listing packages - --nimbleDir dirname Set the Nimble directory. + --nimbleDir:dirname Set the Nimble directory. --verbose Show all non-debug output. --debug Show all output including debug messages. @@ -101,7 +102,7 @@ proc writeHelp*(quit=true) = if quit: raise NimbleQuit(msg: "") -proc writeVersion() = +proc writeVersion*() = echo("nimble v$# compiled at $# $#" % [nimbleVersion, CompileDate, CompileTime]) raise NimbleQuit(msg: "") @@ -229,7 +230,7 @@ proc parseArgument*(key: string, result: var Options) = of actionCompile, actionDoc: result.action.file = key of actionList, actionBuild, actionPublish: - writeHelp() + result.showHelp = true of actionCustom: result.action.arguments.add(key) else: @@ -241,8 +242,8 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = # Global flags. case f - of "help", "h": writeHelp() - of "version", "v": writeVersion() + of "help", "h": result.showHelp = true + of "version", "v": result.showVersion = true of "accept", "y": result.forcePrompts = forcePromptYes of "reject", "n": result.forcePrompts = forcePromptNo of "nimbledir": result.nimbleDir = val @@ -323,8 +324,8 @@ proc parseCmdLine*(): Options = # Parse other things, for example the nimbledata.json file. parseMisc(result) - if result.action.typ == actionNil: - writeHelp() + if result.action.typ == actionNil and not result.showVersion: + result.showHelp = true proc getProxy*(options: Options): Proxy = ## Returns ``nil`` if no proxy is specified. From d9f2e6c49e7cf7a6dcf64eea4e1d6dc56801efa0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 30 Apr 2017 15:40:46 +0100 Subject: [PATCH 181/424] Implement --noColor option. --- src/nimblepkg/cli.nim | 20 +++++++++++++++----- src/nimblepkg/options.nim | 6 ++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 1c616e3..76caaba 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -19,6 +19,7 @@ type level: Priority warnings: HashSet[(string, string)] suppressionCount: int ## Amount of messages which were not shown. + showColor: bool ## Whether messages should be colored. Priority* = enum DebugPriority, LowPriority, MediumPriority, HighPriority @@ -40,7 +41,8 @@ proc newCLI(): CLI = result = CLI( level: HighPriority, warnings: initSet[(string, string)](), - suppressionCount: 0 + suppressionCount: 0, + showColor: true ) var globalCLI = newCLI() @@ -55,11 +57,16 @@ proc displayCategory(category: string, displayType: DisplayType, # Calculate how much the `category` must be offset to align along a center # line. let offset = calculateCategoryOffset(category) + # Display the category. - if priority != DebugPriority: - setForegroundColor(stdout, foregrounds[displayType]) - writeStyled("$1$2 " % [repeatChar(offset), category], styles[priority]) - resetAttributes() + let text = "$1$2 " % [spaces(offset), category] + if globalCLI.showColor: + if priority != DebugPriority: + setForegroundColor(stdout, foregrounds[displayType]) + writeStyled(text, styles[priority]) + resetAttributes() + else: + stdout.write(text) proc displayLine(category, line: string, displayType: DisplayType, priority: Priority) = @@ -145,6 +152,9 @@ proc promptCustom*(question, default: string): string = proc setVerbosity*(level: Priority) = globalCLI.level = level +proc setShowColor*(val: bool) = + globalCLI.showColor = val + when isMainModule: display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini", priority = LowPriority) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 8932d41..b2a323b 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -20,6 +20,7 @@ type pkgInfoCache*: TableRef[string, PackageInfo] showHelp*: bool showVersion*: bool + noColor*: bool ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, @@ -92,6 +93,7 @@ Options: --nimbleDir:dirname Set the Nimble directory. --verbose Show all non-debug output. --debug Show all output including debug messages. + --noColor Don't colorise output. For more information read the Github readme: https://github.com/nim-lang/nimble#readme @@ -249,6 +251,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = of "nimbledir": result.nimbleDir = val of "verbose": result.verbosity = LowPriority of "debug": result.verbosity = DebugPriority + of "nocolor": result.noColor = true # Action-specific flags. else: case result.action.typ @@ -318,6 +321,9 @@ proc parseCmdLine*(): Options = # Set verbosity level. setVerbosity(result.verbosity) + # Set whether color should be shown. + setShowColor(not result.noColor) + # Parse config. result.config = parseConfig() From 5d5825a179d10ea2daa2bbf928962d49783301c3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 30 Apr 2017 21:39:08 +0100 Subject: [PATCH 182/424] Bump version to 0.8.5. --- src/nimblepkg/common.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index d513101..000e769 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -62,4 +62,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.4" + nimbleVersion* = "0.8.5" From cfe68bb441e43083299f88ce340c59693ea3df76 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 2 May 2017 14:01:02 +0100 Subject: [PATCH 183/424] Don't check Nim version when init'ing config (breaks .babel dir). --- src/nimblepkg/config.nim | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 1bd3784..b38c157 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -17,10 +17,7 @@ type urls*: seq[string] proc initConfig(): Config = - if getNimrodVersion() > newVersion("0.9.6"): - result.nimbleDir = getHomeDir() / ".nimble" - else: - result.nimbleDir = getHomeDir() / ".babel" + result.nimbleDir = getHomeDir() / ".nimble" result.httpProxy = initUri() From 30d6aaf9661f16a96974250c7285c3b8b942c694 Mon Sep 17 00:00:00 2001 From: antizealot1337 Date: Fri, 5 May 2017 07:04:01 -0400 Subject: [PATCH 184/424] Change to pass extra parameters to compiler (#347) * Change to pass extra parameters to compiler * Add extra space in from of path argument * Fix missing space that caused some nimble commands to fail --- src/nimble.nim | 17 ++++++++++------- src/nimblepkg/options.nim | 10 +++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index ee2bccd..9b68367 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -285,16 +285,14 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for i in reverseDeps: addRevDep(options, i, pkginfo) -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var string) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") let realDir = pkgInfo.getRealDir() - let releaseOpt = if forRelease: "-d:release" else: "" - var args = "" - for path in paths: args.add("--path:\"" & path & "\" ") + for path in paths: args.add(" --path:\"" & path & "\" ") for bin in pkgInfo.bin: let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" display("Building", "$1/$2 using $3 backend" % @@ -305,8 +303,8 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = createDir(outputDir) try: - doCmd("\"" & getNimBin() & "\" $# $# --noBabelPath $# $# \"$#\"" % - [pkgInfo.backend, releaseOpt, args, outputOpt, + doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# $# \"$#\"" % + [pkgInfo.backend, args, outputOpt, realDir / bin.changeFileExt("nim")]) except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) @@ -317,6 +315,10 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = exc.hint = hint raise exc +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = + var args = if forRelease: "-d:release" else: "" + buildFromDir(pkgInfo, paths, args) + proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, filesInstalled, bins: HashSet[string]) = ## Saves the specified data into a ``nimblemeta.json`` file inside @@ -635,7 +637,8 @@ proc build(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) let paths = processDeps(pkginfo, options) - buildFromDir(pkgInfo, paths, false) + var args = join(options.action.compileOptions, " ") + buildFromDir(pkgInfo, paths, args) proc execBackend(options: Options) = let bin = options.action.file diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index b2a323b..d68e524 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -30,7 +30,7 @@ type Action* = object case typ*: ActionType - of actionNil, actionList, actionBuild, actionPublish, actionTasks: nil + of actionNil, actionList, actionPublish, actionTasks: nil of actionRefresh: optionalURL*: string # Overrides default package list. of actionInstall, actionPath, actionUninstall: @@ -39,7 +39,7 @@ type search*: seq[string] # Search string. of actionInit, actionDump: projName*: string - of actionCompile, actionDoc: + of actionCompile, actionDoc, actionBuild: file*: string backend*: string compileOptions*: seq[string] @@ -147,7 +147,7 @@ proc initAction*(options: var Options, key: string) = case options.action.typ of actionInstall, actionPath: options.action.packages = @[] - of actionCompile, actionDoc: + of actionCompile, actionDoc, actionBuild: options.action.compileOptions = @[] options.action.file = "" if keyNorm == "c" or keyNorm == "compile": options.action.backend = "" @@ -166,7 +166,7 @@ proc initAction*(options: var Options, key: string) = options.action.command = key options.action.arguments = @[] options.action.flags = newStringTable() - of actionBuild, actionPublish, actionList, actionTasks, + of actionPublish, actionList, actionTasks, actionNil: discard proc prompt*(options: Options, question: string): bool = @@ -269,7 +269,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.depsOnly = true else: wasFlagHandled = false - of actionCompile, actionDoc: + of actionCompile, actionDoc, actionBuild: let prefix = if kind == cmdShortOption: "-" else: "--" if val == "": result.action.compileOptions.add(prefix & flag) From 4a71ccbbd4fd774b191d7e682cd31b037d3ee109 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 5 May 2017 12:36:54 +0100 Subject: [PATCH 185/424] Improve getNimPrefixDir to support choosenim and env var. See comment for more information. This commit also adds support for an environment variable so that users have a workaround when Nimble cannot find the Nim stdlib. --- readme.markdown | 7 +++++++ src/nimblepkg/nimscriptsupport.nim | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 5a8cb99..9bc6dbe 100644 --- a/readme.markdown +++ b/readme.markdown @@ -773,6 +773,13 @@ installation. Make sure that you are running at least version 0.16.0 of Nim (or the latest nightly). +* ``Error: cannot open '/home/user/.nimble/lib/system.nim'.`` + +Nimble cannot find the Nim standard library. This is considered a bug so +please report it. As a workaround you can set the ``NIM_LIB_PREFIX`` environment +variable to the directory where ``lib/system.nim`` (and other standard library +files) are found. + ## Repository information This repository has two main branches: ``master`` and ``stable``. diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 5ef3ce3..b3ad381 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -188,7 +188,20 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = else: flags[key] = @[value] -proc getNimPrefixDir(): string = splitPath(findExe("nim")).head.parentDir +proc getNimPrefixDir(): string = + let env = getEnv("NIM_LIB_PREFIX") + if env != "": + return env + + result = splitPath(findExe("nim")).head.parentDir + # The above heuristic doesn't work for 'choosenim' proxies. Thankfully in + # that case the `nimble` binary is beside the `nim` binary so things should + # just work. + if not dirExists(result / "lib"): + # By specifying an empty string we instruct the Nim compiler to use + # getAppDir().head as the prefix dir. See compiler/options module for + # the code responsible for this. + result = "" when declared(ModuleGraph): var graph: ModuleGraph From 85559825123339bc455249a84d80f3302850e3e4 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 5 May 2017 11:29:44 -0400 Subject: [PATCH 186/424] Change buildFromDir to accept a seq[string] instead of a string. Fixes #334 --- src/nimble.nim | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9b68367..61a7d83 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -285,14 +285,14 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for i in reverseDeps: addRevDep(options, i, pkginfo) -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var string) = +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var seq[string]) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") let realDir = pkgInfo.getRealDir() - for path in paths: args.add(" --path:\"" & path & "\" ") + for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" display("Building", "$1/$2 using $3 backend" % @@ -304,7 +304,7 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var string) = try: doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# $# \"$#\"" % - [pkgInfo.backend, args, outputOpt, + [pkgInfo.backend, join(args, " "), outputOpt, realDir / bin.changeFileExt("nim")]) except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) @@ -316,7 +316,11 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var string) = raise exc proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = - var args = if forRelease: "-d:release" else: "" + var args: seq[string] + if forRelease: + args = @["-d:release"] + else: + args = @[] buildFromDir(pkgInfo, paths, args) proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, @@ -637,7 +641,7 @@ proc build(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) let paths = processDeps(pkginfo, options) - var args = join(options.action.compileOptions, " ") + var args = options.action.compileOptions buildFromDir(pkgInfo, paths, args) proc execBackend(options: Options) = From 5adfe3015542907802ce2d2c2ae8320bd980f6e3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 5 May 2017 16:47:17 +0100 Subject: [PATCH 187/424] Version 0.8.6. --- changelog.markdown | 21 +++++++++++++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index b6fdcff..ccc4d30 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,27 @@ # Nimble changelog +## 0.8.6 - 05/05/2017 + +Yet another point release which includes various bug fixes and improvements. + +* Improves heuristic for finding Nim standard library to support choosenim + installations and adds ability to override it via ``NIM_LIB_PREFIX`` + environment variable. +* Implement ``--noColor`` option to remove color from the output. +* Fixes bug when ``srcDir`` contains trailing slash. +* Fixes failure when ``-d`` flag is passed to ``c`` command. +* Show raw output for certain commands. +* GitHub API token can now be specified via the ``NIMBLE_GITHUB_API_TOKEN`` + environment variable. +* GitHub API token is now stored in ``~/.nimble/api_token`` so that it + doesn't need to be specified each time. +* Fixes multiple flags not being passed in Nimble task. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.4...v0.8.6 + ## 0.8.4 - 29/01/2017 Another bug fix release which resolves problems related to stale nimscriptapi diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 000e769..73a12eb 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -62,4 +62,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.5" + nimbleVersion* = "0.8.6" From 659fcf194fb66cddc1a5cc40f054f359411ec345 Mon Sep 17 00:00:00 2001 From: ephja Date: Mon, 5 Jun 2017 11:16:23 +0200 Subject: [PATCH 188/424] fix typo --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 9bc6dbe..4d380c5 100644 --- a/readme.markdown +++ b/readme.markdown @@ -565,7 +565,7 @@ requires "nim >= 0.10.0", "jester > 0.1 & <= 0.5" Dependency lists support version ranges. These versions may either be a concrete version like ``0.1``, or they may contain any of the less-than (``<``), greater-than (``>``), less-than-or-equal-to (``<=``) and greater-than-or-equal-to -(``>=``) oeprators. +(``>=``) operators. Two version ranges may be combined using the ``&`` operator, for example ``> 0.2 & < 1.0``, which will install a package with the version greater than 0.2 and less than 1.0. From a69d7563f4f6da7cca1b5cf2e26bbad04fb273a6 Mon Sep 17 00:00:00 2001 From: Xiao-Yong Date: Wed, 7 Jun 2017 23:32:42 -0500 Subject: [PATCH 189/424] nimble accepts a .nimble file that is a link --- src/nimblepkg/packageinfo.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 860865c..ca2e1f4 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -257,7 +257,7 @@ proc findNimbleFile*(dir: string; error: bool): string = result = "" var hits = 0 for kind, path in walkDir(dir): - if kind == pcFile: + if kind in {pcFile, pcLinkToFile}: let ext = path.splitFile.ext case ext of ".babel", ".nimble": From 8a1fde9693e0d9745c5787257e07f01fdd2b0cad Mon Sep 17 00:00:00 2001 From: Jon Banafato Date: Thu, 15 Jun 2017 00:01:02 -0400 Subject: [PATCH 190/424] Fix publishing packages header and table of contents link --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 4d380c5..8a32227 100644 --- a/readme.markdown +++ b/readme.markdown @@ -669,7 +669,7 @@ To summarise, the steps for release are: Once the new tag is in the remote repository, Nimble will be able to detect the new version. -## Publishing packages +## Publishing packages Publishing packages isn't a requirement. But doing so allows people to associate a specific name to a URL pointing to your package. This mapping is stored From 9878279769dbe600adf32f54006924e5caf92453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=B8is=C3=A6ther=20Rasch?= Date: Sat, 24 Jun 2017 13:09:41 +0200 Subject: [PATCH 191/424] Add Windows and VCC artifacts to gitignore --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 5199260..5744c47 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,11 @@ nimcache/ /nimble /tests/nimscript/nimscript /tests/issue27/issue27 + +# Windows executables +*.exe +*.dll + +# VCC compiler and linker artifacts +*.ilk +*.pdb \ No newline at end of file From 183fed527bdbc0cb3e29db1d3dbe1a1002899bc6 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Sun, 25 Jun 2017 15:52:40 -0400 Subject: [PATCH 192/424] Make conventional structure more explicit in structure warnings and readme --- readme.markdown | 128 +++++++++++++++++++++----------- src/nimblepkg/packageparser.nim | 68 +++++++++-------- tests/tester.nim | 20 ++--- 3 files changed, 134 insertions(+), 82 deletions(-) diff --git a/readme.markdown b/readme.markdown index 8a32227..e1905d6 100644 --- a/readme.markdown +++ b/readme.markdown @@ -29,7 +29,6 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Tests](#tests) - [Libraries](#libraries) - [Binary packages](#binary-packages) - - [Hybrids](#hybrids) - [Dependencies](#dependencies) - [External dependencies](#external-dependencies) - [Nim compiler](#nim-compiler) @@ -50,14 +49,13 @@ Interested in learning **how to create a package**? Skip directly to that sectio ## Requirements -Nimble has some runtime dependencies on external tools, these tools are -used to download Nimble packages. -For -instance, if a package is hosted on [Github](https://github.com) you require to -have [git](http://www.git-scm.com) installed and added to your environment -``PATH``. Same goes for [Mercurial](http://mercurial.selenic.com) repositories -on [Bitbucket](https://bitbucket.org). Nimble packages are typically hosted in -Git repositories so you may be able to get away without installing Mercurial. +Nimble has some runtime dependencies on external tools, these tools are used to +download Nimble packages. For instance, if a package is hosted on +[Github](https://github.com) you require to have [git](http://www.git-scm.com) +installed and added to your environment ``PATH``. Same goes for +[Mercurial](http://mercurial.selenic.com) repositories on +[Bitbucket](https://bitbucket.org). Nimble packages are typically hosted in Git +repositories so you may be able to get away without installing Mercurial. **Warning:** Ensure that you have a fairly recent version of Git installed. If the version is less recent than 1.9.0 then Nimble may have trouble using it. @@ -188,8 +186,8 @@ Similar to the ``install`` command you can specify a version range, for example: The ``build`` command is mostly used by developers who want to test building their ``.nimble`` package. This command will build the package with default flags, i.e. a debug build which includes stack traces but no GDB debug -information. -The ``install`` command will build the package in release mode instead. +information. The ``install`` command will build the package in release mode +instead. ### nimble c @@ -431,19 +429,54 @@ which are also useful. Take a look at it for more information. ### Project structure -There is nothing surprising about the recommended project structure. The advice -resembles that of many other package managers. +A Nimble project includes a *source directory*, containing a at most one +primary source file, which shares the same name as the project itself (as well +as the project's nimble file). In most cases this source directory will also be +the root directory of the whole project. In all cases, the root directory will +contain the .nimble file. -| Directory | Purpose | -| ------------- | -------------------------------------- | -| ``.`` | Root directory containing .nimble file.| -| ``./src/`` | Project source code | -| ``./tests/`` | Project test files | -| ``./docs/`` | Project documentation | +If the project includes additional source files, or if there is more than one +primary (exported) module, they are all included in a single directory +hierarchy within the source directory. In the case of libraries, this directory +will have the same name as the project (see below for details). -**Note:** Nimble will by default look for source files in ``.``, in order to -use this layout you will need to specify ``srcDir = "src"`` in your .nimble -file. +The source directory can contain additional files and directories +not involved in building the project, as long as they are excluded +in the nimble file. + +Here's a sample one-module project directory: + +``` +. # The root directory of the project, also the source directory +├── LICENSE +├── README.md +├── my_project.nim # The primary source file +├── my_project.nimble # The project nimble file +└── tests # Another source directory, excluded in my_project.nimble + ├── nim.cfg + └── tests.nim +``` + +Here's a more complex example: + +``` +. # Root directory +├── my_project.nimble # Nimble file +├── nim_src # Source directory +│   ├── my_project.nim # Primary source file +│   ├── my_project # Secondary source directory +│   │   ├── util.nim +│   │   ├── common.nim +│   └── tests # Excluded directory +│   ├── nim.cfg +│   └── tests.nim +├── README.rst +└── Makefile +``` + +In this example, the source directory is specified in the .nimble file +with `srcDir = "nim_src"`. Inside of `my_project.nim`, the `util` and `common` +modules will be imported as `my_project.util` and `my_project.common`. #### Tests @@ -485,23 +518,31 @@ into ``$nimbleDir/pkgs/pkgname-ver``. It's up to the package creator to make sur that the package directory layout is correct, this is so that users of the package can correctly import the package. -By convention, it is suggested that the layout be as follows. The directory -layout is determined by the nature of your package, that is, whether your -package exposes only one module or multiple modules. +It is suggested that the layout be as follows. The directory layout is +determined by the nature of your package, that is, whether your package exposes +only one module or multiple modules. If your package exposes only a single module, then that module should be present in the root directory (the directory with the .nimble file) of your git -repository, it is recommended that in this case you name that module whatever -your package's name is. A good example of this is the -[jester](https://github.com/dom96/jester) package which exposes the ``jester`` -module. In this case the jester package is imported with ``import jester``. +repository, and should be named whatever your package's name is. A good example +of this is the [jester](https://github.com/dom96/jester) package which exposes +the ``jester`` module. In this case the jester package is imported with +``import jester``. If your package exposes multiple modules then the modules should be in a ``PackageName`` directory. This will allow for a certain measure of isolation from other packages which expose modules with the same names. In this case the package's modules will be imported with ``import PackageName/module``. -You are free to combine the two approaches described. +Here's a simple example multi-module library package: + +``` +. +├── util +│   ├── useful.nim +│   └── also_useful.nim +└── util.nimble +``` In regards to modules which you do **not** wish to be exposed. You should place them in a ``PackageName/private`` directory. Your modules may then import these @@ -532,26 +573,27 @@ created instead. Other files will be copied in the same way as they are for library packages. -Binary packages should not install .nim files so include -``skipExt = @["nim"]`` in your .nimble file, unless you intend for your package to -be a binary/library combo which is fine. +Binary packages should not install .nim files so include ``skipExt = @["nim"]`` +in your .nimble file, unless you intend for your package to be a binary/library +combo. Dependencies are automatically installed before building. It's a good idea to test that the dependencies you specified are correct by running by running ``nimble build`` or ``nimble install`` in the directory of your package. -### Hybrids +One thing to note about binary packages that contain source files aside from +the one(s) specified in `bin` (or that also expose multiple library modules, as +above) is that a binary may share the name of the package: this will mean +that you will not be able to put your additional .nim files in a ``pkgname`` +directory. The reason for this is that binaries on some operating systems do +not have an extension, so they will clash with a directory of the same name. -One thing to note about library and binary package hybrids is that your binary -may share the name of the package. This will mean that you will -not be able to put your .nim files in a ``pkgname`` directory. The reason you -will not be able to do this is because binaries on some operating systems -do not have an extension so they will clash with a directory of the same name. - -The current -convention to get around this problem is to append ``pkg`` to the name as is -done for nimble. +If this is the case, you should place your additional .nim files in a directory +with `pkg` appended after the name of the project. For instance, if you were +building a binary named `project`, you would put any additional source files in +a directory called `projectpkg`. From within project.nim you would then import +those modules namespaced with `projectpkg/`. ### Dependencies diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index f93714d..cbb69dd 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -69,7 +69,16 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = ## This ensures that a package's source code does not leak into ## another package's namespace. ## https://github.com/nim-lang/nimble/issues/144 - let realDir = pkgInfo.getRealDir() + let + realDir = pkgInfo.getRealDir() + normalizedBinNames = pkgInfo.bin.map( + (x) => x.changeFileExt("").toLowerAscii() + ) + correctDir = + if pkgInfo.name.toLowerAscii() in normalizedBinNames: + pkgInfo.name & "pkg" + else: + pkgInfo.name for path in getInstallFiles(realDir, pkgInfo, options): # Remove the root to leave only the package subdirectories. # ~/package-0.1/package/utils.nim -> package/utils.nim. @@ -83,39 +92,40 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = if dir.len == 0: if file != pkgInfo.name: - let msg = ("File inside package '$1' is outside of permitted " & - "namespace, should be " & - "named '$2' but was named '$3' instead. This will be an error" & - " in the future.") % - [pkgInfo.name, pkgInfo.name & ext, file & ext] - let hint = ("Rename this file to '$1', move it into a '$2' " & - "subdirectory, or prevent its installation by adding " & - "`skipFiles = @[\"$3\"]` to the .nimble file. See " & - "https://github.com/nim-lang/nimble#libraries for more info.") % - [pkgInfo.name & ext, pkgInfo.name & DirSep, file & ext] + # A source file was found in the top level of srcDir that doesn't share + # a name with the package. + let + msg = ("Package '$1' has an incorrect structure. " & + "The top level of the package source directory " & + "should contain at most one module, " & + "named '$2', but a file named '$3' was found. This " & + "will be an error in the future.") % + [pkgInfo.name, pkgInfo.name & ext, file & ext] + hint = ("If this is the primary source file in the package, " & + "Rename it to '$1'. If it's a source file required by " & + "the main module, or if it is one of several " & + "modules exposed by '$4', then move it into a '$2' subdirectory. " & + "If it's a test file or otherwise not required " & + "to build the the package '$1', prevent its installation " & + "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " & + "https://github.com/nim-lang/nimble#libraries for more info.") % + [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name] raiseNewValidationError(msg, true, hint, true) else: assert(not pkgInfo.isMinimal) # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. - let normalizedBinNames = pkgInfo.bin.map( - (x) => x.changeFileExt("").toLowerAscii() - ) - let correctDir = - if pkgInfo.name.toLowerAscii() in normalizedBinNames: - pkgInfo.name & "pkg" - else: - pkgInfo.name - if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): - let msg = ("File '$1' inside package '$2' is outside of the" & - " permitted namespace" & - ", should be inside a directory named '$3' but is in a" & - " directory named '$4' instead. This will be an error in the " & - "future.") % - [file & ext, pkgInfo.name, correctDir, dir] - let hint = ("Rename the directory to '$1' or prevent its " & - "installation by adding `skipDirs = @[\"$2\"]` to the " & - ".nimble file.") % [correctDir, dir] + let + msg = ("Package '$2' has an incorrect structure. " & + "It should contain a single directory hierarchy " & + "For source files, named '$3', but file '$1' " & + "is in a directory named '$4' instead. " & + "This will be an error in the future.") % + [file & ext, pkgInfo.name, correctDir, dir] + hint = ("If '$1' contains source files for building '$2', rename it " & + "to '$3'. Otherwise, prevent its installation " & + "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") % + [dir, pkgInfo.name, correctDir] raiseNewValidationError(msg, true, hint, true) proc validatePackageInfo(pkgInfo: PackageInfo, options: Options) = diff --git a/tests/tester.nim b/tests/tester.nim index 8cbf3d6..0b3d42c 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -80,19 +80,19 @@ test "can validate package structure (#144)": let lines = output.strip.splitLines() case package of "x": - check inLines(lines, "File 'foobar.nim' inside package 'x' is outside" & - " of the permitted namespace, should be inside a" & - " directory named 'x' but is in a directory named" & + check inLines(lines, "Package 'x' has an incorrect structure. It should" & + " contain a single directory hierarchy for source files," & + " named 'x', but file 'foobar.nim' is in a directory named" & " 'incorrect' instead.") of "y": - check inLines(lines, "File 'foobar.nim' inside package 'y' is outside" & - " of the permitted namespace, should be inside a" & - " directory named 'ypkg' but is in a directory" & - " named 'yWrong' instead.") + check inLines(lines, "Package 'y' has an incorrect structure. It should" & + " contain a single directory hierarchy for source files," & + " named 'ypkg', but file 'foobar.nim' is in a directory named" & + " 'yWrong' instead.") of "z": - check inLines(lines, "File inside package 'z' is outside of permitted" & - " namespace, should be named 'z.nim' but was" & - " named 'incorrect.nim' instead.") + check inLines(lines, "Package 'z' has an incorrect structure. The top level" & + " of the package source directory should contain at most one module," & + " named 'z.nim', but a file named 'incorrect.nim' was found.") else: assert false From c89ca099a2a108819bc6793d1864578323c0ddb6 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Sun, 25 Jun 2017 12:52:01 -0400 Subject: [PATCH 193/424] Allow locally stored package list files to be specified in config (#368) --- readme.markdown | 9 +++- src/nimble.nim | 6 +-- src/nimblepkg/config.nim | 15 +++++- src/nimblepkg/packageinfo.nim | 86 +++++++++++++++++++++-------------- tests/issue368/packages.json | 14 ++++++ tests/tester.nim | 85 +++++++++++++++++++++++++--------- 6 files changed, 153 insertions(+), 62 deletions(-) create mode 100644 tests/issue368/packages.json diff --git a/readme.markdown b/readme.markdown index 8a32227..e8972d7 100644 --- a/readme.markdown +++ b/readme.markdown @@ -297,6 +297,10 @@ nimbleDir = r"C:\Nimble\" [PackageList] name = "CustomPackages" url = "http://mydomain.org/packages.json" + +[PackageList] +name = "Local project packages" +path = r"C:\Projects\Nim\packages.json" ``` You can currently configure the following in this file: @@ -307,12 +311,13 @@ You can currently configure the following in this file: application packages. If ``true`` this will add ``chcp 65001`` to the .cmd stubs generated in ``~/.nimble/bin/``. **Default:** ``true`` -* ``[PackageList]`` + ``name`` + ``url`` - You can use this section to specify +* ``[PackageList]`` + ``name`` + (``url``|``path``) - You can use this section to specify a new custom package list. Multiple package lists can be specified. Nimble defaults to the "Official" package list, you can override it by specifying a ``[PackageList]`` section named "official". Multiple URLs can be specified under each section, Nimble will try each in succession if - downloading from the first fails. + downloading from the first fails. Alternately, ``path`` can specify a + local file path to copy a package list .json file from. * ``cloneUsingHttps`` - Whether to replace any ``git://`` inside URLs with ``https://``. **Default: true** diff --git a/src/nimble.nim b/src/nimble.nim index 9b68367..6770694 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -48,17 +48,17 @@ proc refresh(options: Options) = if parameter.len > 0: if parameter.isUrl: let cmdLine = PackageList(name: "commandline", urls: @[parameter]) - downloadList(cmdLine, options) + fetchList(cmdLine, options) else: if parameter notin options.config.packageLists: let msg = "Package list with the specified name not found." raise newException(NimbleError, msg) - downloadList(options.config.packageLists[parameter], options) + fetchList(options.config.packageLists[parameter], options) else: # Try each package list in config for name, list in options.config.packageLists: - downloadList(list, options) + fetchList(list, options) proc checkInstallFile(pkgInfo: PackageInfo, origDir, file: string): bool = diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index b38c157..4f2ab1b 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -15,6 +15,7 @@ type PackageList* = object name*: string urls*: seq[string] + path*: string proc initConfig(): Config = result.nimbleDir = getHomeDir() / ".nimble" @@ -35,6 +36,7 @@ proc initConfig(): Config = proc initPackageList(): PackageList = result.name = "" result.urls = @[] + result.path = "" proc addCurrentPkgList(config: var Config, currentPackageList: PackageList) = if currentPackageList.name.len > 0: @@ -53,7 +55,6 @@ proc parseConfig*(): Config = if f != nil: display("Warning", "Using deprecated config file at " & confFile, Warning, HighPriority) - if f != nil: display("Reading", "config file at " & confFile, priority = LowPriority) var p: CfgParser @@ -64,6 +65,10 @@ proc parseConfig*(): Config = var e = next(p) case e.kind of cfgEof: + if currentPackageList.urls.len == 0 and currentPackageList.path == "": + raise newException(NimbleError, "Package list '$1' requires either url or path" % currentPackageList.name) + if currentPackageList.urls.len > 0 and currentPackageList.path != "": + raise newException(NimbleError, "Attempted to specify `url` and `path` for the same package list '$1'" % currentPackageList.name) addCurrentPkgList(result, currentPackageList) break of cfgSectionStart: @@ -97,6 +102,14 @@ proc parseConfig*(): Config = of "packagelist": currentPackageList.urls.add(e.value) else: assert false + of "path": + case currentSection.normalize + of "packagelist": + if currentPackageList.path.len > 0: + raise newException(NimbleError, "Attempted to specify more than one `path` for the same package list.") + else: + currentPackageList.path = e.value.normalize + else: assert false else: raise newException(NimbleError, "Unable to parse config file:" & " Unknown key: " & e.key) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index ca2e1f4..95d093e 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -160,53 +160,69 @@ proc validatePackagesList(path: string): bool = except ValueError, JsonParsingError: return false -proc downloadList*(list: PackageList, options: Options) = - ## Downloads the specified package list and saves it in $nimbleDir. - display("Downloading", list.name & " package list", priority = HighPriority) +proc fetchList*(list: PackageList, options: Options) = + ## Downloads or copies the specified package list and saves it in $nimbleDir. + let verb = if list.urls.len > 0: "Downloading" else: "Copying" + display(verb, list.name & " package list", priority = HighPriority) - var lastError = "" - for i in 0 .. 0: maskedUrl.password = "***" - display("Connecting", "to proxy at " & $maskedUrl, - priority = LowPriority) - - try: - downloadFile(url, tempPath, proxy = getProxy(options)) - except: - let message = "Could not download: " & getCurrentExceptionMsg() - display("Warning:", message, Warning) - lastError = message - continue - - if not validatePackagesList(tempPath): - lastError = "Downloaded packages.json file is invalid" - display("Warning:", lastError & ", discarding.", Warning) - continue - - copyFile(tempPath, - options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii()) - display("Success", "Package list downloaded.", Success, HighPriority) + var lastError = "" - break + copyFromPath = "" + if list.urls.len > 0: + let httpclient = newHttpClient(proxy = getProxy(options)) + for i in 0 .. 0: maskedUrl.password = "***" + display("Connecting", "to proxy at " & $maskedUrl, + priority = LowPriority) + + try: + httpclient.downloadFile(url, tempPath) + except: + let message = "Could not download: " & getCurrentExceptionMsg() + display("Warning:", message, Warning) + lastError = message + continue + + if not validatePackagesList(tempPath): + lastError = "Downloaded packages.json file is invalid" + display("Warning:", lastError & ", discarding.", Warning) + continue + + copyFromPath = tempPath + display("Success", "Package list downloaded.", Success, HighPriority) + lastError = "" + break + + elif list.path != "": + if not validatePackagesList(list.path): + lastError = "Copied packages.json file is invalid" + display("Warning:", lastError & ", discarding.", Warning) + else: + copyFromPath = list.path + display("Success", "Package list copied.", Success, HighPriority) if lastError.len != 0: raise newException(NimbleError, "Refresh failed\n" & lastError) + if copyFromPath.len > 0: + copyFile(copyFromPath, + options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii()) + proc readPackageList(name: string, options: Options): JsonNode = # If packages.json is not present ask the user if they want to download it. if needsRefresh(options): if options.prompt("No local packages.json found, download it from " & "internet?"): for name, list in options.config.packageLists: - downloadList(list, options) + fetchList(list, options) else: raise newException(NimbleError, "Please run nimble refresh.") return parseFile(options.getNimbleDir() / "packages_" & diff --git a/tests/issue368/packages.json b/tests/issue368/packages.json new file mode 100644 index 0000000..5cc425e --- /dev/null +++ b/tests/issue368/packages.json @@ -0,0 +1,14 @@ +[ + { + "name": "discordnim", + "url": "https://github.com/Krognol/discordnim", + "method": "git", + "tags": [ + "library", + "discord" + ], + "description": "Discord library for Nim", + "license": "MIT", + "web": "https://github.com/Krognol/discordnim" + } +] diff --git a/tests/tester.nim b/tests/tester.nim index 8cbf3d6..d4ecabc 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -33,7 +33,6 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) - #echo(result.output) proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) @@ -138,9 +137,9 @@ proc safeMoveFile(src, dest: string) = copyFile(src, dest) removeFile(src) -test "can refresh with custom urls": +template testRefresh(body: untyped) = # Backup current config - let configFile = getConfigDir() / "nimble" / "nimble.ini" + let configFile {.inject.} = getConfigDir() / "nimble" / "nimble.ini" let configBakFile = getConfigDir() / "nimble" / "nimble.ini.bak" if fileExists(configFile): safeMoveFile(configFile, configBakFile) @@ -148,29 +147,73 @@ test "can refresh with custom urls": # Ensure config dir exists createDir(getConfigDir() / "nimble") - writeFile(configFile, """ - [PackageList] - name = "official" - url = "http://google.com" - url = "http://google.com/404" - url = "http://irclogs.nim-lang.org/packages.json" - url = "http://nim-lang.org/nimble/packages.json" - """.unindent) - - let (output, exitCode) = execNimble(["refresh", "--verbose"]) - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check inLines(lines, "config file at") - check inLines(lines, "official package list") - check inLines(lines, "http://google.com") - check inLines(lines, "packages.json file is invalid") - check inLines(lines, "404 not found") - check inLines(lines, "Package list downloaded.") + body # Restore config if fileExists(configBakFile): safeMoveFile(configBakFile, configFile) +test "can refresh with custom urls": + testRefresh(): + writeFile(configFile, """ + [PackageList] + name = "official" + url = "http://google.com" + url = "http://google.com/404" + url = "http://irclogs.nim-lang.org/packages.json" + url = "http://nim-lang.org/nimble/packages.json" + """.unindent) + + let (output, exitCode) = execNimble(["refresh", "--verbose"]) + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check inLines(lines, "config file at") + check inLines(lines, "official package list") + check inLines(lines, "http://google.com") + check inLines(lines, "packages.json file is invalid") + check inLines(lines, "404 not found") + check inLines(lines, "Package list downloaded.") + +test "can refresh with local package list": + testRefresh(): + writeFile(configFile, """ + [PackageList] + name = "local" + path = "$1" + """.unindent % (getCurrentDir() / "issue368" / "packages.json")) + let (output, exitCode) = execNimble(["refresh", "--verbose"]) + let lines = output.strip.splitLines() + check inLines(lines, "config file at") + check inLines(lines, "Copying") + check inLines(lines, "Package list copied.") + check exitCode == QuitSuccess + +test "package list source required": + testRefresh(): + writeFile(configFile, """ + [PackageList] + name = "local" + """) + let (output, exitCode) = execNimble(["refresh", "--verbose"]) + let lines = output.strip.splitLines() + check inLines(lines, "config file at") + check inLines(lines, "Package list 'local' requires either url or path") + check exitCode == QuitFailure + +test "package list can only have one source": + testRefresh(): + writeFile(configFile, """ + [PackageList] + name = "local" + path = "$1" + url = "http://nim-lang.org/nimble/packages.json" + """) + let (output, exitCode) = execNimble(["refresh", "--verbose"]) + let lines = output.strip.splitLines() + check inLines(lines, "config file at") + check inLines(lines, "Attempted to specify `url` and `path` for the same package list 'local'") + check exitCode == QuitFailure + test "can install nimscript package": cd "nimscript": check execNimble(["install", "-y"]).exitCode == QuitSuccess From f2836e5a5c65aa12201ddd0a3e2099abf6bcf9a6 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Sun, 25 Jun 2017 17:27:56 -0400 Subject: [PATCH 194/424] Roll back downloadFile upgrade --- src/nimblepkg/packageinfo.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 95d093e..942804b 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -169,7 +169,6 @@ proc fetchList*(list: PackageList, options: Options) = lastError = "" copyFromPath = "" if list.urls.len > 0: - let httpclient = newHttpClient(proxy = getProxy(options)) for i in 0 .. Date: Sun, 25 Jun 2017 17:40:06 -0400 Subject: [PATCH 195/424] Use path != "" instead of len check --- src/nimblepkg/config.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 4f2ab1b..ce62ef8 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -105,7 +105,7 @@ proc parseConfig*(): Config = of "path": case currentSection.normalize of "packagelist": - if currentPackageList.path.len > 0: + if currentPackageList.path != "": raise newException(NimbleError, "Attempted to specify more than one `path` for the same package list.") else: currentPackageList.path = e.value.normalize From 2a7e1f132c70bdef502f792556a44b8e1e28d89d Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Mon, 26 Jun 2017 17:12:46 -0400 Subject: [PATCH 196/424] Code Review from @dom96 --- readme.markdown | 27 ++++----------------------- src/nimblepkg/packageparser.nim | 4 ++-- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/readme.markdown b/readme.markdown index e1905d6..e90f0a0 100644 --- a/readme.markdown +++ b/readme.markdown @@ -429,7 +429,7 @@ which are also useful. Take a look at it for more information. ### Project structure -A Nimble project includes a *source directory*, containing a at most one +A Nimble project includes a *source directory*, containing at most one primary source file, which shares the same name as the project itself (as well as the project's nimble file). In most cases this source directory will also be the root directory of the whole project. In all cases, the root directory will @@ -457,27 +457,6 @@ Here's a sample one-module project directory: └── tests.nim ``` -Here's a more complex example: - -``` -. # Root directory -├── my_project.nimble # Nimble file -├── nim_src # Source directory -│   ├── my_project.nim # Primary source file -│   ├── my_project # Secondary source directory -│   │   ├── util.nim -│   │   ├── common.nim -│   └── tests # Excluded directory -│   ├── nim.cfg -│   └── tests.nim -├── README.rst -└── Makefile -``` - -In this example, the source directory is specified in the .nimble file -with `srcDir = "nim_src"`. Inside of `my_project.nim`, the `util` and `common` -modules will be imported as `my_project.util` and `my_project.common`. - #### Tests A common problem that arises with tests is the fact that they need to import @@ -534,7 +513,7 @@ If your package exposes multiple modules then the modules should be in a from other packages which expose modules with the same names. In this case the package's modules will be imported with ``import PackageName/module``. -Here's a simple example multi-module library package: +Here's a simple example multi-module library package called `util`: ``` . @@ -582,6 +561,8 @@ It's a good idea to test that the dependencies you specified are correct by running by running ``nimble build`` or ``nimble install`` in the directory of your package. +### Hybrids + One thing to note about binary packages that contain source files aside from the one(s) specified in `bin` (or that also expose multiple library modules, as above) is that a binary may share the name of the package: this will mean diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index cbb69dd..37bb679 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -102,7 +102,7 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = "will be an error in the future.") % [pkgInfo.name, pkgInfo.name & ext, file & ext] hint = ("If this is the primary source file in the package, " & - "Rename it to '$1'. If it's a source file required by " & + "rename it to '$1'. If it's a source file required by " & "the main module, or if it is one of several " & "modules exposed by '$4', then move it into a '$2' subdirectory. " & "If it's a test file or otherwise not required " & @@ -118,7 +118,7 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = let msg = ("Package '$2' has an incorrect structure. " & "It should contain a single directory hierarchy " & - "For source files, named '$3', but file '$1' " & + "for source files, named '$3', but file '$1' " & "is in a directory named '$4' instead. " & "This will be an error in the future.") % [file & ext, pkgInfo.name, correctDir, dir] From 34cc9b958f759d0f61bbd510ff131f7ab0c1b0d4 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Mon, 26 Jun 2017 20:29:36 -0400 Subject: [PATCH 197/424] Restore Hybrids heading to readme --- readme.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.markdown b/readme.markdown index e90f0a0..7bf8d1d 100644 --- a/readme.markdown +++ b/readme.markdown @@ -29,6 +29,7 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [Tests](#tests) - [Libraries](#libraries) - [Binary packages](#binary-packages) + - [Hybrids](#hybrids) - [Dependencies](#dependencies) - [External dependencies](#external-dependencies) - [Nim compiler](#nim-compiler) From 254658ee5d95514bc7a087fa7fa7c79f621e9b34 Mon Sep 17 00:00:00 2001 From: Nycto Date: Tue, 18 Jul 2017 09:23:47 -0700 Subject: [PATCH 198/424] Add test target --- src/nimble.nim | 24 ++++++++++++++++++++++++ src/nimblepkg/options.nim | 13 ++++++++----- tests/nimscript/nimscript.nimble | 4 ++-- tests/tester.nim | 24 ++++++++++++++++++++++-- tests/testsFail/testing123.nim | 4 ++++ tests/testsFail/testing123.nimble | 4 ++++ tests/testsFail/tests/a.nim | 6 ++++++ tests/testsFail/tests/b.nim | 6 ++++++ tests/testsFail/tests/c.nim | 7 +++++++ tests/testsPass/testing123.nim | 4 ++++ tests/testsPass/testing123.nimble | 4 ++++ tests/testsPass/tests/one.nim | 6 ++++++ tests/testsPass/tests/three.nim | 7 +++++++ tests/testsPass/tests/two.nim | 7 +++++++ 14 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 tests/testsFail/testing123.nim create mode 100644 tests/testsFail/testing123.nimble create mode 100644 tests/testsFail/tests/a.nim create mode 100644 tests/testsFail/tests/b.nim create mode 100644 tests/testsFail/tests/c.nim create mode 100644 tests/testsPass/testing123.nim create mode 100644 tests/testsPass/testing123.nimble create mode 100644 tests/testsPass/tests/one.nim create mode 100644 tests/testsPass/tests/three.nim create mode 100644 tests/testsPass/tests/two.nim diff --git a/src/nimble.nim b/src/nimble.nim index 6770694..42cce57 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -673,6 +673,28 @@ proc execBackend(options: Options) = [backend, args, bin], showOutput = true) display("Success:", "Execution finished", Success, HighPriority) +proc tempOutArg(file: string): string = + ## Returns the `--out` argument to pass to the compiler, using a temp file + let (_, name, _) = splitFile(file) + let dir = getNimbleTempDir() / "tests" + createDir(dir) + result = "--out:" & (dir / name) + +proc test(options: Options) = + ## Executes all tests + var files = toSeq(walkDir(getCurrentDir() / "tests")) + files.sort do (a, b: auto) -> int: + result = cmp(a.path, b.path) + + for file in files: + if file.path.endsWith(".nim") and file.kind in { pcFile, pcLinkToFile }: + var optsCopy = options + optsCopy.action.file = file.path + optsCopy.action.backend = "c -r" + optsCopy.action.compileOptions.add("--path:.") + optsCopy.action.compileOptions.add(file.path.tempOutArg) + execBackend(optsCopy) + proc search(options: Options) = ## Searches for matches in ``options.action.search``. ## @@ -1030,6 +1052,8 @@ proc doAction(options: Options) = listPaths(options) of actionBuild: build(options) + of actionTest: + test(options) of actionCompile, actionDoc: execBackend(options) of actionInit: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index d68e524..15d510f 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -25,7 +25,7 @@ type ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, - actionList, actionBuild, actionPath, actionUninstall, actionCompile, + actionList, actionBuild, actionTest, actionPath, actionUninstall, actionCompile, actionDoc, actionCustom, actionTasks Action* = object @@ -39,7 +39,7 @@ type search*: seq[string] # Search string. of actionInit, actionDump: projName*: string - of actionCompile, actionDoc, actionBuild: + of actionCompile, actionDoc, actionBuild, actionTest: file*: string backend*: string compileOptions*: seq[string] @@ -63,6 +63,7 @@ Commands: build Builds a package. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. + test Compiles and executes tests doc, doc2 [opts, ...] f.nim Builds documentation for a file inside a package. Passes options to the Nim compiler. refresh [url] Refreshes the package list. A package list URL @@ -117,6 +118,8 @@ proc parseActionType*(action: string): ActionType = result = actionPath of "build": result = actionBuild + of "test": + result = actionTest of "c", "compile", "js", "cpp", "cc": result = actionCompile of "doc", "doc2": @@ -147,7 +150,7 @@ proc initAction*(options: var Options, key: string) = case options.action.typ of actionInstall, actionPath: options.action.packages = @[] - of actionCompile, actionDoc, actionBuild: + of actionCompile, actionDoc, actionBuild, actionTest: options.action.compileOptions = @[] options.action.file = "" if keyNorm == "c" or keyNorm == "compile": options.action.backend = "" @@ -231,7 +234,7 @@ proc parseArgument*(key: string, result: var Options) = result.action.projName = key of actionCompile, actionDoc: result.action.file = key - of actionList, actionBuild, actionPublish: + of actionList, actionBuild, actionTest, actionPublish: result.showHelp = true of actionCustom: result.action.arguments.add(key) @@ -269,7 +272,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.depsOnly = true else: wasFlagHandled = false - of actionCompile, actionDoc, actionBuild: + of actionCompile, actionDoc, actionBuild, actionTest: let prefix = if kind == cmdShortOption: "-" else: "--" if val == "": result.action.compileOptions.add(prefix & flag) diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index ff8c5c6..d1adfba 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -11,7 +11,7 @@ bin = @["nimscript"] requires "nim >= 0.12.1" -task test, "test description": +task work, "test description": echo(5+5) task c_test, "Testing `setCommand \"c\", \"nimscript.nim\"`": @@ -42,4 +42,4 @@ before hooks2: return false task hooks2, "Testing the hooks again": - echo("Shouldn't happen") \ No newline at end of file + echo("Shouldn't happen") diff --git a/tests/tester.nim b/tests/tester.nim index 3bad7d0..ff64918 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -33,6 +33,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) + checkpoint(result.output) proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) @@ -220,7 +221,7 @@ test "can install nimscript package": test "can execute nimscript tasks": cd "nimscript": - let (output, exitCode) = execNimble("--verbose", "test") + let (output, exitCode) = execNimble("--verbose", "work") let lines = output.strip.splitLines() check exitCode == QuitSuccess check lines[^1] == "10" @@ -253,7 +254,7 @@ test "can use nimscript with repeated flags (issue #329)": test "can list nimscript tasks": cd "nimscript": let (output, exitCode) = execNimble("tasks") - check "test test description".normalize in output.normalize + check "work test description".normalize in output.normalize check exitCode == QuitSuccess test "can use pre/post hooks": @@ -400,3 +401,22 @@ test "can dump for installed package": let (outp, exitCode) = execNimble("dump", "testdump") check: exitCode == 0 check: outp.processOutput.inLines("desc: \"Test package for dump command\"") + +test "Runs passing unit tests": + cd "testsPass": + let (outp, exitCode) = execNimble("test") + check: exitCode == QuitSuccess + check: outp.processOutput.inLines("First test") + check: outp.processOutput.inLines("Second test") + check: outp.processOutput.inLines("Third test") + check: outp.processOutput.inLines("Executing my func") + +test "Runs failing unit tests": + cd "testsFail": + let (outp, exitCode) = execNimble("test") + check: exitCode == QuitFailure + check: outp.processOutput.inLines("First test") + check: outp.processOutput.inLines("Failing Second test") + check: not outp.processOutput.inLines("Third test") + + diff --git a/tests/testsFail/testing123.nim b/tests/testsFail/testing123.nim new file mode 100644 index 0000000..2c96a26 --- /dev/null +++ b/tests/testsFail/testing123.nim @@ -0,0 +1,4 @@ + +proc myFunc*() = + echo "Executing my func" + diff --git a/tests/testsFail/testing123.nimble b/tests/testsFail/testing123.nimble new file mode 100644 index 0000000..00e43bf --- /dev/null +++ b/tests/testsFail/testing123.nimble @@ -0,0 +1,4 @@ +version = "0.1.0" +author = "John Doe" +description = "Nimble Test" +license = "BSD" diff --git a/tests/testsFail/tests/a.nim b/tests/testsFail/tests/a.nim new file mode 100644 index 0000000..09f3215 --- /dev/null +++ b/tests/testsFail/tests/a.nim @@ -0,0 +1,6 @@ +import testing123, unittest + +test "can compile nimble": + echo "First test" + myFunc() + diff --git a/tests/testsFail/tests/b.nim b/tests/testsFail/tests/b.nim new file mode 100644 index 0000000..da5ab05 --- /dev/null +++ b/tests/testsFail/tests/b.nim @@ -0,0 +1,6 @@ +import testing123, unittest + +test "can compile nimble": + echo "Failing Second test" + assert(false) + diff --git a/tests/testsFail/tests/c.nim b/tests/testsFail/tests/c.nim new file mode 100644 index 0000000..0aae686 --- /dev/null +++ b/tests/testsFail/tests/c.nim @@ -0,0 +1,7 @@ +import testing123, unittest + +test "can compile nimble": + echo "Third test" + myFunc() + + diff --git a/tests/testsPass/testing123.nim b/tests/testsPass/testing123.nim new file mode 100644 index 0000000..2c96a26 --- /dev/null +++ b/tests/testsPass/testing123.nim @@ -0,0 +1,4 @@ + +proc myFunc*() = + echo "Executing my func" + diff --git a/tests/testsPass/testing123.nimble b/tests/testsPass/testing123.nimble new file mode 100644 index 0000000..00e43bf --- /dev/null +++ b/tests/testsPass/testing123.nimble @@ -0,0 +1,4 @@ +version = "0.1.0" +author = "John Doe" +description = "Nimble Test" +license = "BSD" diff --git a/tests/testsPass/tests/one.nim b/tests/testsPass/tests/one.nim new file mode 100644 index 0000000..09f3215 --- /dev/null +++ b/tests/testsPass/tests/one.nim @@ -0,0 +1,6 @@ +import testing123, unittest + +test "can compile nimble": + echo "First test" + myFunc() + diff --git a/tests/testsPass/tests/three.nim b/tests/testsPass/tests/three.nim new file mode 100644 index 0000000..0aae686 --- /dev/null +++ b/tests/testsPass/tests/three.nim @@ -0,0 +1,7 @@ +import testing123, unittest + +test "can compile nimble": + echo "Third test" + myFunc() + + diff --git a/tests/testsPass/tests/two.nim b/tests/testsPass/tests/two.nim new file mode 100644 index 0000000..91413e1 --- /dev/null +++ b/tests/testsPass/tests/two.nim @@ -0,0 +1,7 @@ +import testing123, unittest + +test "can compile nimble": + echo "Second test" + myFunc() + + From e756a14c15e498b5d0a831f7147dc61ce589f1f9 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 20 Jul 2017 00:42:28 +0300 Subject: [PATCH 199/424] Fixed branch checkout and handling of branch names with dashes. (#379) * Fixed branch checkout and handling of branch names with dashes. * Added assert --- src/nimblepkg/download.nim | 4 +++- src/nimblepkg/packageinfo.nim | 17 +++++++++++------ src/nimblepkg/version.nim | 4 ++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index ea6cff6..1db1096 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -178,7 +178,9 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, # Grab the full repo. doClone(downMethod, url, downloadDir, tip = false) # Then perform a checkout operation to get the specified branch/commit. - doCheckout(downMethod, downloadDir, $verRange.spe) + # `spe` starts with '#', trim it. + doAssert(($verRange.spe)[0] == '#') + doCheckout(downMethod, downloadDir, substr($verRange.spe, 1)) result = verRange.spe else: case downMethod diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 942804b..e85fcd1 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -72,15 +72,18 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] = result.name = "" result.version = "" let tail = pkgpath.splitPath.tail - if '-' notin tail: + + const specialSeparator = "-#" + var sepIdx = tail.find(specialSeparator) + if sepIdx == -1: + sepIdx = tail.rfind('-') + + if sepIdx == -1: result.name = tail return - for i in countdown(tail.len-1, 0): - if tail[i] == '-': - result.name = tail[0 .. i-1] - result.version = tail[i+1 .. tail.len-1] - break + result.name = tail[0 .. sepIdx - 1] + result.version = tail.substr(sepIdx + 1) proc optionalField(obj: JsonNode, name: string, default = ""): string = ## Queries ``obj`` for the optional ``name`` string. @@ -501,6 +504,8 @@ when isMainModule: ("package-a", "0.1") doAssert getNameVersion("/home/user/.nimble/libs/package-#head") == ("package", "#head") + doAssert getNameVersion("/home/user/.nimble/libs/package-#branch-with-dashes") == + ("package", "#branch-with-dashes") doAssert toValidPackageName("foo__bar") == "foo_bar" doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe" diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 0a70c88..e8803ba 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -36,7 +36,7 @@ type hint*: string proc newVersion*(ver: string): Version = - doAssert(ver[0] in {'#', '\0'} + Digits) + doAssert(ver[0] in {'#', '\0'} + Digits, "Wrong version: " & ver) return Version(ver) proc `$`*(ver: Version): string {.borrow.} @@ -196,7 +196,7 @@ proc parseVersionRange*(s: string): VersionRange = else: raise newException(ParseVersionError, - "Unexpected char in version range: " & s[i]) + "Unexpected char in version range '" & s & "': " & s[i]) inc(i) proc toVersionRange*(ver: Version): VersionRange = From 4a78953fc6d135f45de0b07bda18a44a351ba79d Mon Sep 17 00:00:00 2001 From: waylon531 Date: Tue, 25 Jul 2017 17:10:05 -0700 Subject: [PATCH 200/424] Added better url detection to publish Publish will now look at the hostname part of the ssh url to figure out what git server to use. This definitely works with both github and gitlab, and adds gitlab support to `nimble publish`. --- src/nimblepkg/publish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 2a4ce93..a0bca66 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -206,7 +206,7 @@ proc publish*(p: PackageInfo, o: Options) = if parsed.scheme == "": # Assuming that we got an ssh write/read URL. let sshUrl = parseUri("ssh://" & url) - url = "https://github.com/" & sshUrl.port & sshUrl.path + url = "https://" & sshUrl.hostname & "/" & sshUrl.port & sshUrl.path elif dirExists(os.getCurrentDir() / ".hg"): downloadMethod = "hg" # TODO: Retrieve URL from hg. From ebf4eace3929464dba59ea21e0f9f584760fa2cf Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 1 Aug 2017 19:11:21 +0100 Subject: [PATCH 201/424] Bump travis to Nim 0.17.0 --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5dead07..cc1bf7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,16 @@ language: c install: - | - wget https://nim-lang.org/download/nim-0.16.0.tar.xz - tar -xf nim-0.16.0.tar.xz - cd nim-0.16.0 + wget https://nim-lang.org/download/nim-0.17.0.tar.xz + tar -xf nim-0.17.0.tar.xz + cd nim-0.17.0 sh build.sh cd .. before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.16.0/bin:$PATH + - export PATH=`pwd`/nim-0.17.0/bin:$PATH script: - cd tests From 06a94ba28f1e021937b94b5f1995ba5ad98d6122 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Mon, 7 Aug 2017 17:22:47 +0300 Subject: [PATCH 202/424] Lower memory consumption --- src/nimble.nim | 2 +- src/nimblepkg/options.nim | 5 ++ src/nimblepkg/packageinfo.nim | 40 +++++++-------- src/nimblepkg/packageparser.nim | 86 ++++++++++++++++----------------- 4 files changed, 69 insertions(+), 64 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6770694..7321a96 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -445,7 +445,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, createDir(pkgDestDir) # Copy this package's files based on the preferences specified in PkgInfo. var filesInstalled = initSet[string]() - for file in getInstallFiles(realDir, pkgInfo, options): + discard forEachInstallFile(realDir, pkgInfo, options) do(file: string) -> bool: createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir)) let dest = changeRoot(realDir, pkgDestDir, file) filesInstalled.incl copyFileD(file, dest) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index d68e524..eee40cd 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -21,6 +21,7 @@ type showHelp*: bool showVersion*: bool noColor*: bool + disableValidation*: bool ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, @@ -107,6 +108,9 @@ proc writeHelp*(quit=true) = proc writeVersion*() = echo("nimble v$# compiled at $# $#" % [nimbleVersion, CompileDate, CompileTime]) + const gitVersion = staticExec("git rev-parse HEAD") + when gitVersion.len > 0: + echo "git hash: ", gitVersion raise NimbleQuit(msg: "") proc parseActionType*(action: string): ActionType = @@ -252,6 +256,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = of "verbose": result.verbosity = LowPriority of "debug": result.verbosity = DebugPriority of "nocolor": result.noColor = true + of "disablevalidation": result.disableValidation = true # Action-specific flags. else: case result.action.typ diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index e85fcd1..fcfead6 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -430,30 +430,30 @@ proc checkInstallDir(pkgInfo: PackageInfo, if thisDir[0] == '.': result = true if thisDir == "nimcache": result = true -proc findWithExt(dir: string, pkgInfo: PackageInfo): seq[string] = - ## Returns the filenames of the files that should be copied. - result = @[] +proc forEachFileWithExt(dir: string, pkgInfo: PackageInfo, + action: proc(f: string): bool): bool = + ## Runs `action` for each filename of the files that should be copied. + ## Stops if `action` returns `true`. for kind, path in walkDir(dir): if kind == pcDir: - result.add findWithExt(path, pkgInfo) + if forEachFileWithExt(path, pkgInfo, action): return true else: if path.splitFile.ext[1 .. ^1] in pkgInfo.installExt: - result.add path + if action(path): return true -proc getFilesInDir(dir: string): seq[string] = - ## Returns a list of paths to files inside the specified directory and any - ## subdirectories that are in it. - result = @[] +proc forEachFileInDir(dir: string, action: proc(f: string): bool): bool = + ## Runs `action` for each file in ``dir`` and any + ## subdirectories that are in it. Stops if `action` returns `true`. for kind, path in walkDir(dir): if kind == pcDir: - result.add getFilesInDir(path) + if forEachFileInDir(path, action): return true else: - result.add path + if action(path): return true -proc getInstallFiles*(realDir: string, pkgInfo: PackageInfo, - options: Options): seq[string] = - ## Returns a list of files within the ``realDir`` that should be installed. - result = @[] +proc forEachInstallFile*(realDir: string, pkgInfo: PackageInfo, + options: Options, action: proc(f: string): bool): bool = + ## Runs `action` for each file within the ``realDir`` that should be installed. + ## Stops if `action` returns `true`. let whitelistMode = pkgInfo.installDirs.len != 0 or pkgInfo.installFiles.len != 0 or @@ -466,7 +466,7 @@ proc getInstallFiles*(realDir: string, pkgInfo: PackageInfo, continue else: raise NimbleQuit(msg: "") - result.add src + if action(src): return true for dir in pkgInfo.installDirs: # TODO: Allow skipping files inside dirs? @@ -477,9 +477,9 @@ proc getInstallFiles*(realDir: string, pkgInfo: PackageInfo, else: raise NimbleQuit(msg: "") - result.add getFilesInDir(src) + if forEachFileInDir(src, action): return true - result.add findWithExt(realDir, pkgInfo) + if forEachFileWithExt(realDir, pkgInfo, action): return true else: for kind, file in walkDir(realDir): if kind == pcDir: @@ -487,13 +487,13 @@ proc getInstallFiles*(realDir: string, pkgInfo: PackageInfo, if skip: continue - result.add getInstallFiles(file, pkgInfo, options) + if forEachInstallFile(file, pkgInfo, options, action): return true else: let skip = pkgInfo.checkInstallFile(realDir, file) if skip: continue - result.add file + if action(file): return true when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 37bb679..2fddfa9 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -79,7 +79,8 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = pkgInfo.name & "pkg" else: pkgInfo.name - for path in getInstallFiles(realDir, pkgInfo, options): + + discard forEachInstallFile(realDir, pkgInfo, options) do(path: string) -> bool: # Remove the root to leave only the package subdirectories. # ~/package-0.1/package/utils.nim -> package/utils.nim. var trailPath = changeRoot(realDir, "", path) @@ -87,46 +88,44 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = let (dir, file, ext) = trailPath.splitFile # We're only interested in nim files, because only they can pollute our # namespace. - if ext != (ExtSep & "nim"): - continue - - if dir.len == 0: - if file != pkgInfo.name: - # A source file was found in the top level of srcDir that doesn't share - # a name with the package. - let - msg = ("Package '$1' has an incorrect structure. " & - "The top level of the package source directory " & - "should contain at most one module, " & - "named '$2', but a file named '$3' was found. This " & - "will be an error in the future.") % - [pkgInfo.name, pkgInfo.name & ext, file & ext] - hint = ("If this is the primary source file in the package, " & - "rename it to '$1'. If it's a source file required by " & - "the main module, or if it is one of several " & - "modules exposed by '$4', then move it into a '$2' subdirectory. " & - "If it's a test file or otherwise not required " & - "to build the the package '$1', prevent its installation " & - "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " & - "https://github.com/nim-lang/nimble#libraries for more info.") % - [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name] - raiseNewValidationError(msg, true, hint, true) - else: - assert(not pkgInfo.isMinimal) - # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. - if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): - let - msg = ("Package '$2' has an incorrect structure. " & - "It should contain a single directory hierarchy " & - "for source files, named '$3', but file '$1' " & - "is in a directory named '$4' instead. " & - "This will be an error in the future.") % - [file & ext, pkgInfo.name, correctDir, dir] - hint = ("If '$1' contains source files for building '$2', rename it " & - "to '$3'. Otherwise, prevent its installation " & - "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") % - [dir, pkgInfo.name, correctDir] - raiseNewValidationError(msg, true, hint, true) + if ext == (ExtSep & "nim"): + if dir.len == 0: + if file != pkgInfo.name: + # A source file was found in the top level of srcDir that doesn't share + # a name with the package. + let + msg = ("Package '$1' has an incorrect structure. " & + "The top level of the package source directory " & + "should contain at most one module, " & + "named '$2', but a file named '$3' was found. This " & + "will be an error in the future.") % + [pkgInfo.name, pkgInfo.name & ext, file & ext] + hint = ("If this is the primary source file in the package, " & + "rename it to '$1'. If it's a source file required by " & + "the main module, or if it is one of several " & + "modules exposed by '$4', then move it into a '$2' subdirectory. " & + "If it's a test file or otherwise not required " & + "to build the the package '$1', prevent its installation " & + "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " & + "https://github.com/nim-lang/nimble#libraries for more info.") % + [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name] + raiseNewValidationError(msg, true, hint, true) + else: + assert(not pkgInfo.isMinimal) + # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. + if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): + let + msg = ("Package '$2' has an incorrect structure. " & + "It should contain a single directory hierarchy " & + "for source files, named '$3', but file '$1' " & + "is in a directory named '$4' instead. " & + "This will be an error in the future.") % + [file & ext, pkgInfo.name, correctDir, dir] + hint = ("If '$1' contains source files for building '$2', rename it " & + "to '$3'. Otherwise, prevent its installation " & + "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") % + [dir, pkgInfo.name, correctDir] + raiseNewValidationError(msg, true, hint, true) proc validatePackageInfo(pkgInfo: PackageInfo, options: Options) = let path = pkgInfo.myPath @@ -317,8 +316,9 @@ proc readPackageInfo(nf: NimbleFile, options: Options, options.pkgInfoCache[nf] = result # Validate the rest of the package info last. - validateVersion(result.version) - validatePackageInfo(result, options) + if not options.disableValidation: + validateVersion(result.version) + validatePackageInfo(result, options) proc getPkgInfoFromFile*(file: NimbleFile, options: Options): PackageInfo = ## Reads the specified .nimble file and returns its data as a PackageInfo From 29c9cf8ce70f8ea100c2215861b6bdd30a7c3992 Mon Sep 17 00:00:00 2001 From: Daniil Yarancev Date: Thu, 10 Aug 2017 12:51:16 +0300 Subject: [PATCH 203/424] Removed deprecated warnings, also tiny refactoring --- src/nimble.nim | 2 +- src/nimblepkg/nimscriptsupport.nim | 6 ++-- src/nimblepkg/packageinfo.nim | 3 +- src/nimblepkg/publish.nim | 52 ++++++++++++++---------------- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6770694..8bb879a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1089,7 +1089,7 @@ when isMainModule: let currentExc = (ref NimbleError)(getCurrentException()) (error, hint) = getOutputInfo(currentExc) except NimbleQuit: - nil + discard finally: removeDir(getNimbleTempDir()) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index b3ad381..6bcf763 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -8,7 +8,7 @@ import compiler/ast, compiler/modules, compiler/passes, compiler/passaux, compiler/condsyms, compiler/sem, compiler/semdata, compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, - compiler/msgs, compiler/magicsys, compiler/lists, compiler/idents, + compiler/msgs, compiler/magicsys, compiler/idents, compiler/nimconf from compiler/scriptconfig import setupVM @@ -228,7 +228,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" createDir(tmpNimscriptApiPath.splitFile.dir) writeFile(tmpNimscriptApiPath, nimscriptApi) - appendStr(searchPaths, getTempDir()) + searchPaths.add(getTempDir()) initDefines() loadConfigs(DefaultConfig) @@ -241,7 +241,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = registerPass(semPass) registerPass(evalPass) - appendStr(searchPaths, compiler_options.libpath) + searchPaths.add(compiler_options.libpath) when declared(resetAllModulesHard): result = makeModule(scriptName) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index e85fcd1..7f6e8e6 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -186,7 +186,8 @@ proc fetchList*(list: PackageList, options: Options) = priority = LowPriority) try: - downloadFile(url, tempPath, proxy = proxy) + let client = newHttpClient(proxy = proxy) + client.downloadFile(url, tempPath) except: let message = "Could not download: " & getCurrentExceptionMsg() display("Warning:", message, Warning) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index a0bca66..96251d9 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -13,18 +13,22 @@ type user: string pw: string token: string ## base64 encoding of user:pw + http: HttpClient ## http client for doing API requests const ApiKeyFile = "github_api_token" ApiTokenEnvironmentVariable = "NIMBLE_GITHUB_API_TOKEN" + ReposUrl = "https://api.github.com/repos/" proc userAborted() = raise newException(NimbleError, "User aborted the process.") -proc createHeaders(a: Auth): string = - (("Authorization: token $1\c\L" % a.token) & - "Content-Type: application/x-www-form-urlencoded\c\L" & - "Accept: */*\c\L") +proc createHeaders(a: Auth) = + a.http.headers = newHttpHeaders({ + "Authorization": "token $1" % a.token, + "Content-Type": "application/x-www-form-urlencoded", + "Accept": "*/*" + }) proc requestNewToken(cfg: Config): string = display("Info:", "Please create a new personal access token on Github in" & @@ -47,7 +51,7 @@ proc requestNewToken(cfg: Config): string = return token proc getGithubAuth(cfg: Config): Auth = - + result.http = newHttpClient() # always prefer the environment variable to asking for a new one if existsEnv(ApiTokenEnvironmentVariable): result.token = getEnv(ApiTokenEnvironmentVariable) @@ -63,9 +67,8 @@ proc getGithubAuth(cfg: Config): Auth = priority = HighPriority) except IOError: result.token = requestNewToken(cfg) - - let resp = getContent("https://api.github.com/user", - extraHeaders=createHeaders(result)).parseJson() + createHeaders(result) + let resp = result.http.getContent("https://api.github.com/user").parseJson() result.user = resp["login"].str display("Success:", "Verified as " & result.user, Success, HighPriority) @@ -78,8 +81,7 @@ proc isCorrectFork(j: JsonNode): bool = proc forkExists(a: Auth): bool = try: - let x = getContent("https://api.github.com/repos/" & a.user & "/packages", - extraHeaders=createHeaders(a)) + let x = a.http.getContent(ReposUrl & a.user & "/packages") let j = parseJson(x) result = isCorrectFork(j) except JsonParsingError, IOError: @@ -87,16 +89,14 @@ proc forkExists(a: Auth): bool = proc createFork(a: Auth) = try: - discard postContent("https://api.github.com/repos/nim-lang/packages/forks", - extraHeaders=createHeaders(a)) + discard a.http.postContent(ReposUrl & "nim-lang/packages/forks") except HttpRequestError: raise newException(NimbleError, "Unable to create fork. Access token" & " might not have enough permissions.") proc createPullRequest(a: Auth, packageName, branch: string) = display("Info", "Creating PR", priority = HighPriority) - discard postContent("https://api.github.com/repos/nim-lang/packages/pulls", - extraHeaders=createHeaders(a), + discard a.http.postContent(ReposUrl & "nim-lang/packages/pulls", body="""{"title": "Add package $1", "head": "$2:$3", "base": "master"}""" % [packageName, a.user, branch]) @@ -139,14 +139,15 @@ proc cleanupWhitespace(s: string): string = proc editJson(p: PackageInfo; url, tags, downloadMethod: string) = var contents = parseFile("packages.json") doAssert contents.kind == JArray - contents.add(%{ - "name": %p.name, - "url": %url, - "method": %downloadMethod, - "tags": %tags.split(), - "description": %p.description, - "license": %p.license, - "web": %url}) + contents.add(%*{ + "name": p.name, + "url": url, + "method": downloadMethod, + "tags": tags.split(), + "description": p.description, + "license": p.license, + "web": url + }) writeFile("packages.json", contents.pretty.cleanupWhitespace) proc getPackageOriginUrl(a: Auth): string = @@ -228,9 +229,4 @@ proc publish*(p: PackageInfo, o: Options) = display("Pushing", "to remote of fork.", priority = HighPriority) doCmd("git push " & getPackageOriginUrl(auth) & " " & branchName) createPullRequest(auth, p.name, branchName) - display("Success:", "Pull request successful.", Success, HighPriority) - -when isMainModule: - import packageinfo - var p = getPkgInfo(getCurrentDir()) - publish(p) + display("Success:", "Pull request successful.", Success, HighPriority) \ No newline at end of file From 612c08468842b4c27b71b127dd07aaa7e6daaf8c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 14:50:32 +0100 Subject: [PATCH 204/424] Improvements to #385. --- src/nimble.nim | 10 ++-- src/nimblepkg/packageinfo.nim | 39 ++++++++-------- src/nimblepkg/packageparser.nim | 82 +++++++++++++++++---------------- 3 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index d2ef02e..5027b6e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -449,10 +449,12 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, createDir(pkgDestDir) # Copy this package's files based on the preferences specified in PkgInfo. var filesInstalled = initSet[string]() - discard forEachInstallFile(realDir, pkgInfo, options) do(file: string) -> bool: - createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir)) - let dest = changeRoot(realDir, pkgDestDir, file) - filesInstalled.incl copyFileD(file, dest) + iterInstallFiles(realDir, pkgInfo, options, + proc (file: string) = + createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir)) + let dest = changeRoot(realDir, pkgDestDir, file) + filesInstalled.incl copyFileD(file, dest) + ) # Copy the .nimble file. let dest = changeRoot(pkgInfo.myPath.splitFile.dir, pkgDestDir, diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index ab2b2c9..4c47197 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -431,30 +431,30 @@ proc checkInstallDir(pkgInfo: PackageInfo, if thisDir[0] == '.': result = true if thisDir == "nimcache": result = true -proc forEachFileWithExt(dir: string, pkgInfo: PackageInfo, - action: proc(f: string): bool): bool = - ## Runs `action` for each filename of the files that should be copied. - ## Stops if `action` returns `true`. +proc iterFilesWithExt(dir: string, pkgInfo: PackageInfo, + action: proc (f: string)) = + ## Runs `action` for each filename of the files that have a whitelisted + ## file extension. for kind, path in walkDir(dir): if kind == pcDir: - if forEachFileWithExt(path, pkgInfo, action): return true + iterFilesWithExt(path, pkgInfo, action) else: if path.splitFile.ext[1 .. ^1] in pkgInfo.installExt: - if action(path): return true + action(path) -proc forEachFileInDir(dir: string, action: proc(f: string): bool): bool = +proc iterFilesInDir(dir: string, action: proc (f: string)) = ## Runs `action` for each file in ``dir`` and any - ## subdirectories that are in it. Stops if `action` returns `true`. + ## subdirectories that are in it. for kind, path in walkDir(dir): if kind == pcDir: - if forEachFileInDir(path, action): return true + iterFilesInDir(path, action) else: - if action(path): return true + action(path) -proc forEachInstallFile*(realDir: string, pkgInfo: PackageInfo, - options: Options, action: proc(f: string): bool): bool = - ## Runs `action` for each file within the ``realDir`` that should be installed. - ## Stops if `action` returns `true`. +proc iterInstallFiles*(realDir: string, pkgInfo: PackageInfo, + options: Options, action: proc (f: string)) = + ## Runs `action` for each file within the ``realDir`` that should be + ## installed. let whitelistMode = pkgInfo.installDirs.len != 0 or pkgInfo.installFiles.len != 0 or @@ -467,7 +467,8 @@ proc forEachInstallFile*(realDir: string, pkgInfo: PackageInfo, continue else: raise NimbleQuit(msg: "") - if action(src): return true + + action(src) for dir in pkgInfo.installDirs: # TODO: Allow skipping files inside dirs? @@ -478,9 +479,9 @@ proc forEachInstallFile*(realDir: string, pkgInfo: PackageInfo, else: raise NimbleQuit(msg: "") - if forEachFileInDir(src, action): return true + iterFilesInDir(src, action) - if forEachFileWithExt(realDir, pkgInfo, action): return true + iterFilesWithExt(realDir, pkgInfo, action) else: for kind, file in walkDir(realDir): if kind == pcDir: @@ -488,13 +489,13 @@ proc forEachInstallFile*(realDir: string, pkgInfo: PackageInfo, if skip: continue - if forEachInstallFile(file, pkgInfo, options, action): return true + iterInstallFiles(file, pkgInfo, options, action) else: let skip = pkgInfo.checkInstallFile(realDir, file) if skip: continue - if action(file): return true + action(file) when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 2fddfa9..b69bd75 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -80,7 +80,7 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = else: pkgInfo.name - discard forEachInstallFile(realDir, pkgInfo, options) do(path: string) -> bool: + proc onFile(path: string) = # Remove the root to leave only the package subdirectories. # ~/package-0.1/package/utils.nim -> package/utils.nim. var trailPath = changeRoot(realDir, "", path) @@ -88,44 +88,48 @@ proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) = let (dir, file, ext) = trailPath.splitFile # We're only interested in nim files, because only they can pollute our # namespace. - if ext == (ExtSep & "nim"): - if dir.len == 0: - if file != pkgInfo.name: - # A source file was found in the top level of srcDir that doesn't share - # a name with the package. - let - msg = ("Package '$1' has an incorrect structure. " & - "The top level of the package source directory " & - "should contain at most one module, " & - "named '$2', but a file named '$3' was found. This " & - "will be an error in the future.") % - [pkgInfo.name, pkgInfo.name & ext, file & ext] - hint = ("If this is the primary source file in the package, " & - "rename it to '$1'. If it's a source file required by " & - "the main module, or if it is one of several " & - "modules exposed by '$4', then move it into a '$2' subdirectory. " & - "If it's a test file or otherwise not required " & - "to build the the package '$1', prevent its installation " & - "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " & - "https://github.com/nim-lang/nimble#libraries for more info.") % - [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name] - raiseNewValidationError(msg, true, hint, true) - else: - assert(not pkgInfo.isMinimal) - # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. - if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): - let - msg = ("Package '$2' has an incorrect structure. " & - "It should contain a single directory hierarchy " & - "for source files, named '$3', but file '$1' " & - "is in a directory named '$4' instead. " & - "This will be an error in the future.") % - [file & ext, pkgInfo.name, correctDir, dir] - hint = ("If '$1' contains source files for building '$2', rename it " & - "to '$3'. Otherwise, prevent its installation " & - "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") % - [dir, pkgInfo.name, correctDir] - raiseNewValidationError(msg, true, hint, true) + if ext != (ExtSep & "nim"): + return + + if dir.len == 0: + if file != pkgInfo.name: + # A source file was found in the top level of srcDir that doesn't share + # a name with the package. + let + msg = ("Package '$1' has an incorrect structure. " & + "The top level of the package source directory " & + "should contain at most one module, " & + "named '$2', but a file named '$3' was found. This " & + "will be an error in the future.") % + [pkgInfo.name, pkgInfo.name & ext, file & ext] + hint = ("If this is the primary source file in the package, " & + "rename it to '$1'. If it's a source file required by " & + "the main module, or if it is one of several " & + "modules exposed by '$4', then move it into a '$2' subdirectory. " & + "If it's a test file or otherwise not required " & + "to build the the package '$1', prevent its installation " & + "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " & + "https://github.com/nim-lang/nimble#libraries for more info.") % + [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name] + raiseNewValidationError(msg, true, hint, true) + else: + assert(not pkgInfo.isMinimal) + # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize. + if not (dir.startsWith(correctDir & DirSep) or dir == correctDir): + let + msg = ("Package '$2' has an incorrect structure. " & + "It should contain a single directory hierarchy " & + "for source files, named '$3', but file '$1' " & + "is in a directory named '$4' instead. " & + "This will be an error in the future.") % + [file & ext, pkgInfo.name, correctDir, dir] + hint = ("If '$1' contains source files for building '$2', rename it " & + "to '$3'. Otherwise, prevent its installation " & + "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") % + [dir, pkgInfo.name, correctDir] + raiseNewValidationError(msg, true, hint, true) + + iterInstallFiles(realDir, pkgInfo, options, onFile) proc validatePackageInfo(pkgInfo: PackageInfo, options: Options) = let path = pkgInfo.myPath From 23e2932be87f05dcf7287f2b094f556e704ac542 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 14:51:31 +0100 Subject: [PATCH 205/424] Tester improvements. --- tests/tester.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index 3bad7d0..3bb4095 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -77,6 +77,7 @@ test "can validate package structure (#144)": let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess let lines = output.strip.splitLines() + checkpoint(output) case package of "x": check inLines(lines, "Package 'x' has an incorrect structure. It should" & @@ -128,7 +129,9 @@ test "issue 113 (uninstallation problems)": check execNimble(["remove", "-y", "c"]).exitCode == QuitSuccess test "can refresh with default urls": - check execNimble(["refresh"]).exitCode == QuitSuccess + let (output, exitCode) = execNimble(["refresh"]) + checkpoint(output) + check exitCode == QuitSuccess proc safeMoveFile(src, dest: string) = try: @@ -162,9 +165,11 @@ test "can refresh with custom urls": url = "http://google.com/404" url = "http://irclogs.nim-lang.org/packages.json" url = "http://nim-lang.org/nimble/packages.json" + url = "https://github.com/nim-lang/packages/raw/master/packages.json" """.unindent) let (output, exitCode) = execNimble(["refresh", "--verbose"]) + checkpoint(output) let lines = output.strip.splitLines() check exitCode == QuitSuccess check inLines(lines, "config file at") From c379a79910620e9391c78f4eeced09a5a179a601 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 14:52:11 +0100 Subject: [PATCH 206/424] Bump to v0.8.7 (devel). --- src/nimblepkg/common.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 73a12eb..ffdd323 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -62,4 +62,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.6" + nimbleVersion* = "0.8.7" From 79b78ff781f4dd98678be56c38b502084509abfc Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 15:59:30 +0100 Subject: [PATCH 207/424] Add diamond_deps tests for #184. --- tests/diamond_deps/a/a.nimble | 14 ++++++++++++++ tests/diamond_deps/b/b.nimble | 11 +++++++++++ tests/diamond_deps/c/c.nimble | 11 +++++++++++ tests/diamond_deps/d/d.nimble | 11 +++++++++++ tests/tester.nim | 15 +++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 tests/diamond_deps/a/a.nimble create mode 100644 tests/diamond_deps/b/b.nimble create mode 100644 tests/diamond_deps/c/c.nimble create mode 100644 tests/diamond_deps/d/d.nimble diff --git a/tests/diamond_deps/a/a.nimble b/tests/diamond_deps/a/a.nimble new file mode 100644 index 0000000..a140030 --- /dev/null +++ b/tests/diamond_deps/a/a.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "a" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3", "b", "c" + + +task test, "test": + echo("hello") diff --git a/tests/diamond_deps/b/b.nimble b/tests/diamond_deps/b/b.nimble new file mode 100644 index 0000000..2d64846 --- /dev/null +++ b/tests/diamond_deps/b/b.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "b" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3", "d" + diff --git a/tests/diamond_deps/c/c.nimble b/tests/diamond_deps/c/c.nimble new file mode 100644 index 0000000..2062240 --- /dev/null +++ b/tests/diamond_deps/c/c.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "c" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3", "d" + diff --git a/tests/diamond_deps/d/d.nimble b/tests/diamond_deps/d/d.nimble new file mode 100644 index 0000000..763e7db --- /dev/null +++ b/tests/diamond_deps/d/d.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "d" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.3" + diff --git a/tests/tester.nim b/tests/tester.nim index 3bb4095..5f5fb8a 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -405,3 +405,18 @@ test "can dump for installed package": let (outp, exitCode) = execNimble("dump", "testdump") check: exitCode == 0 check: outp.processOutput.inLines("desc: \"Test package for dump command\"") + +test "can install diamond deps (#184)": + cd "diamond_deps": + cd "d": + check execNimble("install", "-y").exitCode == 0 + cd "c": + check execNimble("install", "-y").exitCode == 0 + cd "b": + check execNimble("install", "-y").exitCode == 0 + cd "a": + # TODO: This doesn't really test anything. But I couldn't quite + # reproduce #184. + let (output, exitCode) = execNimble("install", "-y") + checkpoint(output) + check exitCode == 0 \ No newline at end of file From ee34150d70160df488dcef80c565444cb7a731ac Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 20:48:17 +0100 Subject: [PATCH 208/424] Fixes #331. --- src/nimble.nim | 63 +++++++++--------------------- src/nimblepkg/packageinfo.nim | 2 +- src/nimblepkg/packageinstaller.nim | 52 ++++++++++++++++++++++++ tests/tester.nim | 37 +++++++++++++++++- 4 files changed, 106 insertions(+), 48 deletions(-) create mode 100644 src/nimblepkg/packageinstaller.nim diff --git a/src/nimble.nim b/src/nimble.nim index 5027b6e..57c8736 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -13,7 +13,7 @@ from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser, - nimblepkg/cli + nimblepkg/cli, nimblepkg/packageinstaller import nimblepkg/nimscriptsupport @@ -364,10 +364,21 @@ proc removePkgDir(dir: string, options: Options) = display("Warning:", ("Cannot completely remove $1. Files not installed " & "by nimble are present.") % dir, Warning, HighPriority) - # Remove binaries. if nimblemeta.hasKey("binaries"): + # Remove binaries. for binary in nimblemeta["binaries"]: removeFile(options.getBinDir() / binary.str) + + # Search for an older version of the package we are removing. + let (pkgName, _) = getNameVersion(dir) + let pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) + var pkgInfo: PackageInfo + if pkgList.findPkg((pkgName, newVRAny()), pkgInfo): + pkgInfo = pkgInfo.toFullInfo(options) + for bin in pkgInfo.bin: + let symlinkDest = pkgInfo.getRealDir() / bin + let symlinkFilename = options.getBinDir() / bin.extractFilename + discard setupBinSymlink(symlinkDest, symlinkFilename) else: display("Warning:", ("Cannot completely remove $1. Binary symlinks may " & "have been left over in $2.") % @@ -477,49 +488,11 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin), pkgDestDir / bin) - let currentPerms = getFilePermissions(pkgDestDir / bin) - setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec}) - let cleanBin = bin.extractFilename - when defined(unix): - display("Creating", "symlink: $1 -> $2" % - [pkgDestDir / bin, binDir / cleanBin], priority = MediumPriority) - if existsFile(binDir / cleanBin): - display("Warning:", "Symlink already exists in $1. Replacing." % binDir, - Warning, HighPriority) - removeFile(binDir / cleanBin) - createSymlink(pkgDestDir / bin, binDir / cleanBin) - binariesInstalled.incl(cleanBin) - elif defined(windows): - # There is a bug on XP, described here: - # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called - # But this workaround brakes code page on newer systems, so we need to detect OS version - var osver = OSVERSIONINFO() - osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) - if GetVersionExA(osver) == WINBOOL(0): - raise newException(NimbleError, - "Can't detect OS version: GetVersionExA call failed") - let fixChcp = osver.dwMajorVersion <= 5 - - # Create cmd.exe/powershell stub. - let dest = binDir / cleanBin.changeFileExt("cmd") - display("Creating", "stub: $1 -> $2" % [pkgDestDir / bin, dest], - priority = MediumPriority) - var contents = "@" - if options.config.chcp: - if fixChcp: - contents.add "chcp 65001 > nul && " - else: contents.add "chcp 65001 > nul\n@" - contents.add "\"" & pkgDestDir / bin & "\" %*\n" - writeFile(dest, contents) - binariesInstalled.incl(dest.extractFilename) - # For bash on Windows (Cygwin/Git bash). - let bashDest = dest.changeFileExt("") - display("Creating", "Cygwin stub: $1 -> $2" % - [pkgDestDir / bin, bashDest], priority = MediumPriority) - writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n") - binariesInstalled.incl(bashDest.extractFilename) - else: - {.error: "Sorry, your platform is not supported.".} + # Set up a symlink. + let symlinkDest = pkgDestDir / bin + let symlinkFilename = binDir / bin.extractFilename + for filename in setupBinSymlink(symlinkDest, symlinkFilename): + binariesInstalled.incl(filename) let vcsRevision = vcsRevisionInDir(realDir) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 4c47197..389342d 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -300,7 +300,7 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options): ## minimal. This has the advantage that it does not depend on the ## ``packageparser`` module, and so can be used by ``nimscriptsupport``. ## - ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ + ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ (options.getPkgsDir) result = @[] for kind, path in walkDir(libsDir): if kind == pcDir: diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim new file mode 100644 index 0000000..3b9c330 --- /dev/null +++ b/src/nimblepkg/packageinstaller.nim @@ -0,0 +1,52 @@ +# Copyright (C) Dominik Picheta. All rights reserved. +# BSD License. Look at license.txt for more info. +import os, strutils + +# Local imports +import cli + +proc setupBinSymlink*(symlinkDest, symlinkFilename: string): seq[string] = + result = @[] + let currentPerms = getFilePermissions(symlinkDest) + setFilePermissions(symlinkDest, currentPerms + {fpUserExec}) + when defined(unix): + display("Creating", "symlink: $1 -> $2" % + [symlinkDest, symlinkFilename], priority = MediumPriority) + if existsFile(symlinkFilename): + let msg = "Symlink already exists in $1. Replacing." % symlinkFilename + display("Warning:", msg, Warning, HighPriority) + removeFile(symlinkFilename) + + createSymlink(symlinkDest, symlinkFilename) + result.add symlinkFilename.extractFilename + elif defined(windows): + # There is a bug on XP, described here: + # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called + # But this workaround brakes code page on newer systems, so we need to detect OS version + var osver = OSVERSIONINFO() + osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO)) + if GetVersionExA(osver) == WINBOOL(0): + raise newException(NimbleError, + "Can't detect OS version: GetVersionExA call failed") + let fixChcp = osver.dwMajorVersion <= 5 + + # Create cmd.exe/powershell stub. + let dest = symlinkFilename.changeFileExt("cmd") + display("Creating", "stub: $1 -> $2" % [symlinkDest, dest], + priority = MediumPriority) + var contents = "@" + if options.config.chcp: + if fixChcp: + contents.add "chcp 65001 > nul && " + else: contents.add "chcp 65001 > nul\n@" + contents.add "\"" & symlinkDest & "\" %*\n" + writeFile(dest, contents) + result.add dest.extractFilename + # For bash on Windows (Cygwin/Git bash). + let bashDest = dest.changeFileExt("") + display("Creating", "Cygwin stub: $1 -> $2" % + [symlinkDest, bashDest], priority = MediumPriority) + writeFile(bashDest, "\"" & symlinkDest & "\" \"$@\"\n") + result.add bashDest.extractFilename + else: + {.error: "Sorry, your platform is not supported.".} \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index 5f5fb8a..bb06d8d 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -43,7 +43,9 @@ proc inLines(lines: seq[string], line: string): bool = test "picks #head when looking for packages": cd "versionClashes" / "aporiaScenario": - check execNimble("install", "-y", "--verbose").exitCode == QuitSuccess + let (output, exitCode) = execNimble("install", "-y", "--verbose") + checkpoint output + check exitCode == QuitSuccess check execNimble("remove", "aporiascenario", "-y").exitCode == QuitSuccess check execNimble("remove", "packagea", "-y").exitCode == QuitSuccess @@ -419,4 +421,35 @@ test "can install diamond deps (#184)": # reproduce #184. let (output, exitCode) = execNimble("install", "-y") checkpoint(output) - check exitCode == 0 \ No newline at end of file + check exitCode == 0 + +suite "can handle two binary versions": + setup: + cd "binaryPackage/v1": + check execNimble("install", "-y").exitCode == QuitSuccess + + cd "binaryPackage/v2": + check execNimble("install", "-y").exitCode == QuitSuccess + + test "can execute v2": + let (output, exitCode) = + execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + check exitCode == QuitSuccess + check output.strip() == "v2" + + test "can update symlink to earlier version after removal": + check execNimble("remove", "binaryPackage@2.0", "-y").exitCode==QuitSuccess + + let (output, exitCode) = + execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + check exitCode == QuitSuccess + check output.strip() == "v1" + + test "can keep symlink version after earlier version removal": + check execNimble("remove", "binaryPackage@1.0", "-y").exitCode==QuitSuccess + + let (output, exitCode) = + execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + check exitCode == QuitSuccess + check output.strip() == "v2" + From d1eae2f1a01cc853adfe455b7c65e9b28a2b1108 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 12 Aug 2017 22:01:47 +0100 Subject: [PATCH 209/424] Fixes #351. --- src/nimble.nim | 2 +- tests/tester.nim | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 57c8736..d3ef1e9 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -634,7 +634,7 @@ proc execBackend(options: Options) = var args = "" for path in paths: args.add("--path:\"" & path & "\" ") for option in options.action.compileOptions: - args.add(option & " ") + args.add("\"" & option & "\" ") let backend = if options.action.backend.len > 0: diff --git a/tests/tester.nim b/tests/tester.nim index bb06d8d..804a656 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -453,3 +453,11 @@ suite "can handle two binary versions": check exitCode == QuitSuccess check output.strip() == "v2" +test "can pass args with spaces to Nim (#351)": + cd "binaryPackage/v2": + let (output, exitCode) = execCmdEx(nimblePath & + " c -r" & + " -d:myVar=\"string with spaces\"" & + " binaryPackage") + checkpoint output + check exitCode == QuitSuccess \ No newline at end of file From bc6ce4b9ea5891cd6df0e092f14dca3c28d99d3b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 13 Aug 2017 00:06:23 +0100 Subject: [PATCH 210/424] Add missing binaryPackage test files. --- tests/binaryPackage/v1/binaryPackage.nim | 1 + tests/binaryPackage/v1/binaryPackage.nimble | 12 ++++++++++++ tests/binaryPackage/v2/binaryPackage.nim | 1 + tests/binaryPackage/v2/binaryPackage.nimble | 12 ++++++++++++ 4 files changed, 26 insertions(+) create mode 100644 tests/binaryPackage/v1/binaryPackage.nim create mode 100644 tests/binaryPackage/v1/binaryPackage.nimble create mode 100644 tests/binaryPackage/v2/binaryPackage.nim create mode 100644 tests/binaryPackage/v2/binaryPackage.nimble diff --git a/tests/binaryPackage/v1/binaryPackage.nim b/tests/binaryPackage/v1/binaryPackage.nim new file mode 100644 index 0000000..e094d7c --- /dev/null +++ b/tests/binaryPackage/v1/binaryPackage.nim @@ -0,0 +1 @@ +echo("v1") \ No newline at end of file diff --git a/tests/binaryPackage/v1/binaryPackage.nimble b/tests/binaryPackage/v1/binaryPackage.nimble new file mode 100644 index 0000000..6031ae9 --- /dev/null +++ b/tests/binaryPackage/v1/binaryPackage.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.0" +author = "Dominik Picheta" +description = "binary" +license = "MIT" + +bin = @["binaryPackage"] + +# Dependencies + +requires "nim >= 0.15.3" diff --git a/tests/binaryPackage/v2/binaryPackage.nim b/tests/binaryPackage/v2/binaryPackage.nim new file mode 100644 index 0000000..1168967 --- /dev/null +++ b/tests/binaryPackage/v2/binaryPackage.nim @@ -0,0 +1 @@ +echo("v2") \ No newline at end of file diff --git a/tests/binaryPackage/v2/binaryPackage.nimble b/tests/binaryPackage/v2/binaryPackage.nimble new file mode 100644 index 0000000..cfe2a9e --- /dev/null +++ b/tests/binaryPackage/v2/binaryPackage.nimble @@ -0,0 +1,12 @@ +# Package + +version = "2.0" +author = "Dominik Picheta" +description = "binary" +license = "MIT" + +bin = @["binaryPackage"] + +# Dependencies + +requires "nim >= 0.15.3" From 84d63c8988ae4a1fd539db2791d8a11f182d58c1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 13 Aug 2017 15:02:09 +0100 Subject: [PATCH 211/424] Fixes compilation on Windows. --- src/nimble.nim | 22 ++-------------------- src/nimblepkg/packageinstaller.nim | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index d3ef1e9..12706f4 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -17,24 +17,6 @@ import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, import nimblepkg/nimscriptsupport -when not defined(windows): - from posix import getpid -else: - # This is just for Win XP support. - # TODO: Drop XP support? - from winlean import WINBOOL, DWORD - type - OSVERSIONINFO* {.final, pure.} = object - dwOSVersionInfoSize*: DWORD - dwMajorVersion*: DWORD - dwMinorVersion*: DWORD - dwBuildNumber*: DWORD - dwPlatformId*: DWORD - szCSDVersion*: array[0..127, char] - - proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall, - dynlib: "kernel32", importc: "GetVersionExA".} - proc refresh(options: Options) = ## Downloads the package list from the specified URL. ## @@ -378,7 +360,7 @@ proc removePkgDir(dir: string, options: Options) = for bin in pkgInfo.bin: let symlinkDest = pkgInfo.getRealDir() / bin let symlinkFilename = options.getBinDir() / bin.extractFilename - discard setupBinSymlink(symlinkDest, symlinkFilename) + discard setupBinSymlink(symlinkDest, symlinkFilename, options) else: display("Warning:", ("Cannot completely remove $1. Binary symlinks may " & "have been left over in $2.") % @@ -491,7 +473,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Set up a symlink. let symlinkDest = pkgDestDir / bin let symlinkFilename = binDir / bin.extractFilename - for filename in setupBinSymlink(symlinkDest, symlinkFilename): + for filename in setupBinSymlink(symlinkDest, symlinkFilename, options): binariesInstalled.incl(filename) let vcsRevision = vcsRevisionInDir(realDir) diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index 3b9c330..96e2963 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -3,9 +3,26 @@ import os, strutils # Local imports -import cli +import cli, common, options -proc setupBinSymlink*(symlinkDest, symlinkFilename: string): seq[string] = +when defined(windows): + # This is just for Win XP support. + # TODO: Drop XP support? + from winlean import WINBOOL, DWORD + type + OSVERSIONINFO* {.final, pure.} = object + dwOSVersionInfoSize*: DWORD + dwMajorVersion*: DWORD + dwMinorVersion*: DWORD + dwBuildNumber*: DWORD + dwPlatformId*: DWORD + szCSDVersion*: array[0..127, char] + + proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall, + dynlib: "kernel32", importc: "GetVersionExA".} + +proc setupBinSymlink*(symlinkDest, symlinkFilename: string, + options: Options): seq[string] = result = @[] let currentPerms = getFilePermissions(symlinkDest) setFilePermissions(symlinkDest, currentPerms + {fpUserExec}) From 56dd4018310d526deb1cd02a596510c1af887086 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 13 Aug 2017 15:04:40 +0100 Subject: [PATCH 212/424] Implements `develop` command. Refs #240. --- src/nimble.nim | 137 +++++++++++++------- src/nimblepkg/download.nim | 36 +++++ src/nimblepkg/options.nim | 16 ++- src/nimblepkg/packageinfo.nim | 5 + src/nimblepkg/tools.nim | 17 +++ tests/develop/binary/binary.nim | 1 + tests/develop/binary/binary.nimble | 14 ++ tests/develop/hybrid/hybrid.nim | 1 + tests/develop/hybrid/hybrid.nimble | 12 ++ tests/develop/srcdirtest/src/srcdirtest.nim | 1 + tests/develop/srcdirtest/srcdirtest.nimble | 12 ++ tests/tester.nim | 39 +++++- 12 files changed, 234 insertions(+), 57 deletions(-) create mode 100644 tests/develop/binary/binary.nim create mode 100644 tests/develop/binary/binary.nimble create mode 100644 tests/develop/hybrid/hybrid.nim create mode 100644 tests/develop/hybrid/hybrid.nimble create mode 100644 tests/develop/srcdirtest/src/srcdirtest.nim create mode 100644 tests/develop/srcdirtest/srcdirtest.nimble diff --git a/src/nimble.nim b/src/nimble.nim index 12706f4..0295903 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -306,7 +306,8 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = buildFromDir(pkgInfo, paths, args) proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, - filesInstalled, bins: HashSet[string]) = + filesInstalled, bins: HashSet[string], + isLink: bool = false) = ## Saves the specified data into a ``nimblemeta.json`` file inside ## ``pkgDestDir``. ## @@ -314,6 +315,9 @@ proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, ## installed. ## bins - A list of binary filenames which have been installed for this ## package. + ## + ## isLink - Determines whether the installed package is a .nimble-link. + # TODO: Move to packageinstaller.nim var nimblemeta = %{"url": %url} if not vcsRevision.isNil: nimblemeta["vcsRevision"] = %vcsRevision @@ -325,8 +329,20 @@ proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, nimblemeta["binaries"] = binaries for bin in bins: binaries.add(%bin) + nimblemeta["isLink"] = %isLink writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) +proc saveNimbleMeta(pkgDestDir, pkgDir, vcsRevision: string) = + ## Overload of saveNimbleMeta for linked (.nimble-link) packages. + ## + ## pkgDestDir - The directory where the package has been installed. + ## For example: ~/.nimble/pkgs/jester-#head/ + ## + ## pkgDir - The directory where the original package files are. + ## For example: ~/projects/jester/ + saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision, + initSet[string](), initSet[string](), true) + proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. try: @@ -399,7 +415,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, var pkgInfo = getPkgInfo(dir, options) let realDir = pkgInfo.getRealDir() let binDir = options.getBinDir() - let pkgsDir = options.getPkgsDir() var depsOptions = options depsOptions.depsOnly = false @@ -421,12 +436,11 @@ 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: buildFromDir(pkgInfo, result.paths, true) - let versionStr = '-' & pkgInfo.specialVersion - - let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr) + let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): - if not options.prompt(pkgInfo.name & versionStr & - " already exists. Overwrite?"): + let msg = "$1@$2 already exists. Overwrite?" % + [pkgInfo.name, pkgInfo.specialVersion] + if not options.prompt(msg): raise NimbleQuit(msg: "") removePkgDir(pkgDestDir, options) # Remove any symlinked binaries @@ -495,49 +509,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, display("Success:", pkgInfo.name & " installed successfully.", Success, HighPriority) -proc getNimbleTempDir(): string = - ## Returns a path to a temporary directory. - ## - ## The returned path will be the same for the duration of the process but - ## different for different runs of it. You have to make sure to create it - ## first. In release builds the directory will be removed when nimble finishes - ## its work. - result = getTempDir() / "nimble_" - when defined(windows): - proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32", - importc: "GetCurrentProcessId".} - result.add($GetCurrentProcessId()) - else: - result.add($getpid()) - -proc downloadPkg(url: string, verRange: VersionRange, - downMethod: DownloadMethod, - options: Options): (string, Version) = - ## Downloads the repository as specified by ``url`` and ``verRange`` using - ## the download method specified. - ## - ## Returns the directory where it was downloaded and the concrete version - ## which was downloaded. - let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange)) - createDir(downloadDir) - var modUrl = - if url.startsWith("git://") and options.config.cloneUsingHttps: - "https://" & url[6 .. ^1] - else: url - - # Fixes issue #204 - # github + https + trailing url slash causes a - # checkout/ls-remote to fail with Repository not found - if modUrl.contains("github.com") and modUrl.endswith("/"): - modUrl = modUrl[0 .. ^2] - - display("Downloading", "$1 using $2" % [modUrl, $downMethod], - priority = HighPriority) - result = ( - downloadDir, - doDownload(modUrl, downloadDir, verRange, downMethod, options) - ) - proc getDownloadInfo*(pv: PkgTuple, options: Options, doPrompt: bool): (DownloadMethod, string) = if pv.name.isURL: @@ -931,6 +902,70 @@ proc listTasks(options: Options) = let nimbleFile = findNimbleFile(getCurrentDir(), true) nimscriptsupport.listTasks(nimbleFile, options) +proc developFromDir(dir: string, options: Options) = + if options.depsOnly: + raiseNimbleError("Cannot develop dependencies only.") + + var pkgInfo = getPkgInfo(dir, options) + if pkgInfo.bin.len > 0: + if "nim" in pkgInfo.skipExt: + raiseNimbleError("Cannot develop packages that are binaries only.") + + display("Warning:", "This package's binaries will not be compiled " & + "nor symlinked for development.", Warning, HighPriority) + + # Overwrite the version to #head always. + pkgInfo.specialVersion = "#head" + + # Dependencies need to be processed before the creation of the pkg dir. + discard processDeps(pkgInfo, options) + + # This is similar to the code in `installFromDir`, except that we + # *consciously* not worry about the package's binaries. + let pkgDestDir = pkgInfo.getPkgDest(options) + if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): + let msg = "$1@$2 already exists. Overwrite?" % + [pkgInfo.name, pkgInfo.specialVersion] + if not options.prompt(msg): + raise NimbleQuit(msg: "") + removePkgDir(pkgDestDir, options) + + createDir(pkgDestDir) + # The .nimble-link file contains the path to the real .nimble file, + # and a secondary path to the source directory of the package. + # The secondary path is necessary so that the package's .nimble file doesn't + # need to be read. This will mean that users will need to re-run + # `nimble develop` if they change their `srcDir` but I think it's a worthy + # compromise. + let contents = pkgInfo.myPath & "\n" & pkgInfo.getRealDir() + writeFile(pkgDestDir / pkgInfo.name.addFileExt("nimble-link"), contents) + + # TODO: Handle dependencies of the package we are developing (they need to be + # installed). + + # Save a nimblemeta.json file. + saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir)) + + # Save the nimble data (which might now contain reverse deps added in + # processDeps). + saveNimbleData(options) + +proc develop(options: Options) = + if options.action.packages == @[]: + developFromDir(getCurrentDir(), options) + else: + # Install each package. + for pv in options.action.packages: + let downloadDir = getCurrentDir() / pv.name + if dirExists(downloadDir): + let msg = "Cannot clone into '$1': directory exists." % downloadDir + let hint = "Remove the directory, or run this command somewhere else." + raiseNimbleError(msg, hint) + + let (meth, url) = getDownloadInfo(pv, options, true) + discard downloadPkg(url, pv.ver, meth, options, downloadDir) + developFromDir(downloadDir, options) + proc execHook(options: Options, before: bool): bool = ## Returns whether to continue. result = true @@ -1002,6 +1037,8 @@ proc doAction(options: Options) = dump(options) of actionTasks: listTasks(options) + of actionDevelop: + develop(options) of actionNil: assert false of actionCustom: diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 1db1096..216c36e 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -212,6 +212,42 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, verifyClone() +proc downloadPkg*(url: string, verRange: VersionRange, + downMethod: DownloadMethod, + options: Options, + downloadPath = ""): (string, Version) = + ## Downloads the repository as specified by ``url`` and ``verRange`` using + ## the download method specified. + ## + ## If `downloadPath` isn't specified a location in /tmp/ will be used. + ## + ## Returns the directory where it was downloaded and the concrete version + ## which was downloaded. + let downloadDir = + if downloadPath == "": + (getNimbleTempDir() / getDownloadDirName(url, verRange)) + else: + downloadPath + + createDir(downloadDir) + var modUrl = + if url.startsWith("git://") and options.config.cloneUsingHttps: + "https://" & url[6 .. ^1] + else: url + + # Fixes issue #204 + # github + https + trailing url slash causes a + # checkout/ls-remote to fail with Repository not found + if modUrl.contains("github.com") and modUrl.endswith("/"): + modUrl = modUrl[0 .. ^2] + + display("Downloading", "$1 using $2" % [modUrl, $downMethod], + priority = HighPriority) + result = ( + downloadDir, + doDownload(modUrl, downloadDir, verRange, downMethod, options) + ) + proc echoPackageVersions*(pkg: Package) = let downMethod = pkg.downloadMethod.getDownloadMethod() case downMethod diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index eee40cd..5890a00 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -27,15 +27,16 @@ type actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionDoc, actionCustom, actionTasks + actionDoc, actionCustom, actionTasks, actionDevelop Action* = object case typ*: ActionType of actionNil, actionList, actionPublish, actionTasks: nil of actionRefresh: optionalURL*: string # Overrides default package list. - of actionInstall, actionPath, actionUninstall: - packages*: seq[PkgTuple] # Optional only for actionInstall. + of actionInstall, actionPath, actionUninstall, actionDevelop: + packages*: seq[PkgTuple] # Optional only for actionInstall + # and actionDevelop. of actionSearch: search*: seq[string] # Search string. of actionInit, actionDump: @@ -56,6 +57,9 @@ Usage: nimble COMMAND [opts] Commands: install [pkgname, ...] Installs a list of packages. [-d, --depsOnly] Install only dependencies. + develop [pkgname, ...] Clones a list of packages for development. + Symlinks the cloned packages or any package + in the current working directory. init [pkgname] Initializes a new Nimble project. publish Publishes a package on nim-lang/packages. The current working directory needs to be the @@ -141,6 +145,8 @@ proc parseActionType*(action: string): ActionType = result = actionPublish of "tasks": result = actionTasks + of "develop": + result = actionDevelop else: result = actionCustom @@ -149,7 +155,7 @@ proc initAction*(options: var Options, key: string) = ## `key`. let keyNorm = key.normalize() case options.action.typ - of actionInstall, actionPath: + of actionInstall, actionPath, actionDevelop, actionUninstall: options.action.packages = @[] of actionCompile, actionDoc, actionBuild: options.action.compileOptions = @[] @@ -164,8 +170,6 @@ proc initAction*(options: var Options, key: string) = options.action.optionalURL = "" of actionSearch: options.action.search = @[] - of actionUninstall: - options.action.packages = @[] of actionCustom: options.action.command = key options.action.arguments = @[] diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 389342d..f854676 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -497,6 +497,11 @@ proc iterInstallFiles*(realDir: string, pkgInfo: PackageInfo, action(file) +proc getPkgDest*(pkgInfo: PackageInfo, options: Options): string = + let versionStr = '-' & pkgInfo.specialVersion + let pkgDestDir = options.getPkgsDir() / (pkgInfo.name & versionStr) + return pkgDestDir + when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == ("packagea", "0.1") diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index ebc268d..00e518c 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -141,3 +141,20 @@ proc contains*(j: JsonNode, elem: tuple[key: string, val: JsonNode]): bool = for key, val in pairs(j): if key == elem.key and val == elem.val: return true + +when not defined(windows): + from posix import getpid +proc getNimbleTempDir*(): string = + ## Returns a path to a temporary directory. + ## + ## The returned path will be the same for the duration of the process but + ## different for different runs of it. You have to make sure to create it + ## first. In release builds the directory will be removed when nimble finishes + ## its work. + result = getTempDir() / "nimble_" + when defined(windows): + proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32", + importc: "GetCurrentProcessId".} + result.add($GetCurrentProcessId()) + else: + result.add($getpid()) \ No newline at end of file diff --git a/tests/develop/binary/binary.nim b/tests/develop/binary/binary.nim new file mode 100644 index 0000000..53c687a --- /dev/null +++ b/tests/develop/binary/binary.nim @@ -0,0 +1 @@ +echo("hello") \ No newline at end of file diff --git a/tests/develop/binary/binary.nimble b/tests/develop/binary/binary.nimble new file mode 100644 index 0000000..b80a50e --- /dev/null +++ b/tests/develop/binary/binary.nimble @@ -0,0 +1,14 @@ +# Package + +version = "1.0" +author = "Dominik Picheta" +description = "binary" +license = "MIT" + +bin = @["binary"] + +skipExt = @["nim"] + +# Dependencies + +requires "nim >= 0.16.0" diff --git a/tests/develop/hybrid/hybrid.nim b/tests/develop/hybrid/hybrid.nim new file mode 100644 index 0000000..53c687a --- /dev/null +++ b/tests/develop/hybrid/hybrid.nim @@ -0,0 +1 @@ +echo("hello") \ No newline at end of file diff --git a/tests/develop/hybrid/hybrid.nimble b/tests/develop/hybrid/hybrid.nimble new file mode 100644 index 0000000..d580fad --- /dev/null +++ b/tests/develop/hybrid/hybrid.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.0" +author = "Dominik Picheta" +description = "hybrid" +license = "MIT" + +bin = @["hybrid"] + +# Dependencies + +requires "nim >= 0.16.0" diff --git a/tests/develop/srcdirtest/src/srcdirtest.nim b/tests/develop/srcdirtest/src/srcdirtest.nim new file mode 100644 index 0000000..53c687a --- /dev/null +++ b/tests/develop/srcdirtest/src/srcdirtest.nim @@ -0,0 +1 @@ +echo("hello") \ No newline at end of file diff --git a/tests/develop/srcdirtest/srcdirtest.nimble b/tests/develop/srcdirtest/srcdirtest.nimble new file mode 100644 index 0000000..c0f8136 --- /dev/null +++ b/tests/develop/srcdirtest/srcdirtest.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.0" +author = "Dominik Picheta" +description = "srcdir" +license = "MIT" + +srcDir = "src" + +# Dependencies + +requires "nim >= 0.16.0" diff --git a/tests/tester.nim b/tests/tester.nim index 804a656..603023b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -460,4 +460,41 @@ test "can pass args with spaces to Nim (#351)": " -d:myVar=\"string with spaces\"" & " binaryPackage") checkpoint output - check exitCode == QuitSuccess \ No newline at end of file + check exitCode == QuitSuccess + +suite "develop feature": + test "can reject binary packages": + cd "develop/binary": + let (output, exitCode) = execNimble("develop") + checkpoint output + check output.processOutput.inLines("cannot develop packages") + check exitCode == QuitFailure + + test "can develop hybrid": + cd "develop/hybrid": + let (output, exitCode) = execNimble("develop") + checkpoint output + check output.processOutput.inLines("will not be compiled") + check exitCode == QuitSuccess + + let path = installDir / "pkgs" / "hybrid-#head" / "hybrid.nimble-link" + check fileExists(path) + let split = readFile(path).splitLines() + check split.len == 2 + check split[0].endsWith("develop/hybrid/hybrid.nimble") + check split[1].endsWith("develop/hybrid") + + test "can develop with srcDir": + cd "develop/srcdirtest": + let (output, exitCode) = execNimble("develop") + checkpoint output + check(not output.processOutput.inLines("will not be compiled")) + check exitCode == QuitSuccess + + let path = installDir / "pkgs" / "srcdirtest-#head" / + "srcdirtest.nimble-link" + check fileExists(path) + let split = readFile(path).splitLines() + check split.len == 2 + check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble") + check split[1].endsWith("develop/srcdirtest/src") \ No newline at end of file From 9f0aae0432abf99d4232e073dd9a8b0d6ea0c28e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 13 Aug 2017 15:11:38 +0100 Subject: [PATCH 213/424] Check for Windows compilation in the tester. --- tests/tester.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/tester.nim b/tests/tester.nim index 603023b..af544f9 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -18,6 +18,9 @@ createDir(installDir) test "can compile nimble": check execCmdEx("nim c " & path).exitCode == QuitSuccess +test "can compile with --os:windows": + check execCmdEx("nim check --os:windows " & path).exitCode == QuitSuccess + template cd*(dir: string, body: untyped) = ## Sets the current dir to ``dir``, executes ``body`` and restores the ## previous working dir. From 1ef7e493500ae6d66dcf37cef38686bb6948bee9 Mon Sep 17 00:00:00 2001 From: Zach Smith Date: Sun, 13 Aug 2017 17:40:50 -0400 Subject: [PATCH 214/424] Don't normalize package list paths. That strips meaningful characters. --- src/nimblepkg/config.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index ce62ef8..45f8154 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -108,7 +108,7 @@ proc parseConfig*(): Config = if currentPackageList.path != "": raise newException(NimbleError, "Attempted to specify more than one `path` for the same package list.") else: - currentPackageList.path = e.value.normalize + currentPackageList.path = e.value else: assert false else: raise newException(NimbleError, "Unable to parse config file:" & From a5f325f0328eaa9a5736f001cd5396918b37c2c1 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 14 Aug 2017 22:55:00 +0100 Subject: [PATCH 215/424] Small refactoring. --- src/nimble.nim | 41 ---------------------------- src/nimblepkg/packageinstaller.nim | 43 +++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 0295903..b8e7ffb 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -305,44 +305,6 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = args = @[] buildFromDir(pkgInfo, paths, args) -proc saveNimbleMeta(pkgDestDir, url, vcsRevision: string, - filesInstalled, bins: HashSet[string], - isLink: bool = false) = - ## Saves the specified data into a ``nimblemeta.json`` file inside - ## ``pkgDestDir``. - ## - ## filesInstalled - A list of absolute paths to files which have been - ## installed. - ## bins - A list of binary filenames which have been installed for this - ## package. - ## - ## isLink - Determines whether the installed package is a .nimble-link. - # TODO: Move to packageinstaller.nim - var nimblemeta = %{"url": %url} - if not vcsRevision.isNil: - nimblemeta["vcsRevision"] = %vcsRevision - let files = newJArray() - nimblemeta["files"] = files - for file in filesInstalled: - files.add(%changeRoot(pkgDestDir, "", file)) - let binaries = newJArray() - nimblemeta["binaries"] = binaries - for bin in bins: - binaries.add(%bin) - nimblemeta["isLink"] = %isLink - writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) - -proc saveNimbleMeta(pkgDestDir, pkgDir, vcsRevision: string) = - ## Overload of saveNimbleMeta for linked (.nimble-link) packages. - ## - ## pkgDestDir - The directory where the package has been installed. - ## For example: ~/.nimble/pkgs/jester-#head/ - ## - ## pkgDir - The directory where the original package files are. - ## For example: ~/projects/jester/ - saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision, - initSet[string](), initSet[string](), true) - proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. try: @@ -940,9 +902,6 @@ proc developFromDir(dir: string, options: Options) = let contents = pkgInfo.myPath & "\n" & pkgInfo.getRealDir() writeFile(pkgDestDir / pkgInfo.name.addFileExt("nimble-link"), contents) - # TODO: Handle dependencies of the package we are developing (they need to be - # installed). - # Save a nimblemeta.json file. saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir)) diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index 96e2963..d34a9a7 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -1,9 +1,9 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import os, strutils +import os, strutils, sets, json # Local imports -import cli, common, options +import cli, common, options, tools when defined(windows): # This is just for Win XP support. @@ -66,4 +66,41 @@ proc setupBinSymlink*(symlinkDest, symlinkFilename: string, writeFile(bashDest, "\"" & symlinkDest & "\" \"$@\"\n") result.add bashDest.extractFilename else: - {.error: "Sorry, your platform is not supported.".} \ No newline at end of file + {.error: "Sorry, your platform is not supported.".} + +proc saveNimbleMeta*(pkgDestDir, url, vcsRevision: string, + filesInstalled, bins: HashSet[string], + isLink: bool = false) = + ## Saves the specified data into a ``nimblemeta.json`` file inside + ## ``pkgDestDir``. + ## + ## filesInstalled - A list of absolute paths to files which have been + ## installed. + ## bins - A list of binary filenames which have been installed for this + ## package. + ## + ## isLink - Determines whether the installed package is a .nimble-link. + var nimblemeta = %{"url": %url} + if not vcsRevision.isNil: + nimblemeta["vcsRevision"] = %vcsRevision + let files = newJArray() + nimblemeta["files"] = files + for file in filesInstalled: + files.add(%changeRoot(pkgDestDir, "", file)) + let binaries = newJArray() + nimblemeta["binaries"] = binaries + for bin in bins: + binaries.add(%bin) + nimblemeta["isLink"] = %isLink + writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) + +proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision: string) = + ## Overload of saveNimbleMeta for linked (.nimble-link) packages. + ## + ## pkgDestDir - The directory where the package has been installed. + ## For example: ~/.nimble/pkgs/jester-#head/ + ## + ## pkgDir - The directory where the original package files are. + ## For example: ~/projects/jester/ + saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision, + initSet[string](), initSet[string](), true) \ No newline at end of file From 5f1de1e4ffd5e750119584639e2b23d9145f2fab Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 16 Aug 2017 22:20:24 +0100 Subject: [PATCH 216/424] Don't fail immediately when user doesn't want to load packages.json. --- src/nimblepkg/packageinfo.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index f854676..b2f0ea7 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -227,7 +227,9 @@ proc readPackageList(name: string, options: Options): JsonNode = for name, list in options.config.packageLists: fetchList(list, options) else: - raise newException(NimbleError, "Please run nimble refresh.") + # The user might not need a package list for now. So let's try + # going further. + return newJArray() return parseFile(options.getNimbleDir() / "packages_" & name.toLowerAscii() & ".json") From 97dc0ffb453a97374a87188bf9164eb8b935e643 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 16 Aug 2017 22:22:00 +0100 Subject: [PATCH 217/424] Implements basic support for building with .nimble-link'ed packages. --- src/nimble.nim | 50 +++++++++++++-------- src/nimblepkg/common.nim | 1 + src/nimblepkg/packageinfo.nim | 24 +++++++--- src/nimblepkg/packageparser.nim | 11 ++++- tests/develop/dependent/dependent.nimble | 12 +++++ tests/develop/dependent/src/dependent.nim | 3 ++ tests/develop/srcdirtest/src/srcdirtest.nim | 3 ++ tests/tester.nim | 17 ++++--- 8 files changed, 90 insertions(+), 31 deletions(-) create mode 100644 tests/develop/dependent/dependent.nimble create mode 100644 tests/develop/dependent/src/dependent.nim diff --git a/src/nimble.nim b/src/nimble.nim index b8e7ffb..0d93af9 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -4,7 +4,7 @@ import system except TResult import httpclient, parseopt, os, osproc, pegs, tables, parseutils, - strtabs, json, algorithm, sets, uri + strtabs, json, algorithm, sets, uri, future, sequtils import strutils except toLower from unicode import toLower @@ -198,11 +198,12 @@ proc removeRevDep(options: Options, pkg: PackageInfo) = proc install(packages: seq[PkgTuple], options: Options, - doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] -proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = + doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] +proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = ## Verifies and installs dependencies. ## - ## Returns the list of paths to pass to the compiler during build phase. + ## Returns the list of PackageInfo (for paths) to pass to the compiler + ## during build phase. result = @[] assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires") display("Verifying", @@ -233,8 +234,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = if not found: display("Installing", $resolvedDep, priority = HighPriority) let toInstall = @[(resolvedDep.name, resolvedDep.ver)] - let (paths, installedPkg) = install(toInstall, options) - result.add(paths) + let (pkgs, installedPkg) = install(toInstall, options) + result.add(pkgs) pkg = installedPkg # For addRevDep @@ -243,7 +244,12 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = else: display("Info:", "Dependency on $1 already satisfied" % $dep, priority = HighPriority) - result.add(pkg.mypath.splitFile.dir) + if pkg.isLinked: + # TODO (#393): This can be optimised since the .nimble-link files have + # a secondary line that specifies the srcDir. + pkg = pkg.toFullInfo(options) + + result.add(pkg) # Process the dependencies of this dependency. result.add(processDeps(pkg.toFullInfo(options), options)) reverseDeps.add((pkg.name, pkg.specialVersion)) @@ -251,8 +257,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = # Check if two packages of the same name (but different version) are listed # in the path. var pkgsInPath: StringTableRef = newStringTable(modeCaseSensitive) - for p in result: - let pkgInfo = getPkgInfo(p, options) + for pkgInfo in result: if pkgsInPath.hasKey(pkgInfo.name) and pkgsInPath[pkgInfo.name] != pkgInfo.version: raise newException(NimbleError, @@ -267,7 +272,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] = for i in reverseDeps: addRevDep(options, i, pkginfo) -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var seq[string]) = +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], + args: var seq[string]) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, @@ -369,7 +375,10 @@ proc vcsRevisionInDir(dir: string): string = discard proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, - url: string): tuple[paths: seq[string], pkg: PackageInfo] = + url: string): tuple[ + deps: seq[PackageInfo], + pkg: PackageInfo + ] = ## Returns where package has been installed to, together with paths ## to the packages this package depends on. ## The return value of this function is used by @@ -385,7 +394,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, pkgInfo.specialVersion = $requestedVer.spe # Dependencies need to be processed before the creation of the pkg dir. - result.paths = processDeps(pkgInfo, depsOptions) + result.deps = processDeps(pkgInfo, depsOptions) if options.depsOnly: result.pkg = pkgInfo @@ -396,7 +405,9 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Build before removing an existing package (if one exists). This way # if the build fails then the old package will still be installed. - if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true) + if pkgInfo.bin.len > 0: + let paths = result.deps.map(dep => dep.getRealDir()) + buildFromDir(pkgInfo, paths, true) let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): @@ -462,8 +473,8 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # processDeps). saveNimbleData(options) - # Return the paths to the dependencies of this package. - result.paths.add pkgDestDir + # Return the dependencies of this package (mainly for paths). + result.deps.add pkgInfo result.pkg = pkgInfo result.pkg.isInstalled = true result.pkg.myPath = dest @@ -496,7 +507,7 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options, proc install(packages: seq[PkgTuple], options: Options, - doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] = + doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] = if packages == @[]: result = installFromDir(getCurrentDir(), newVRAny(), options, "") else: @@ -530,7 +541,8 @@ proc install(packages: seq[PkgTuple], proc build(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) - let paths = processDeps(pkginfo, options) + let deps = processDeps(pkginfo, options) + let paths = deps.map(dep => dep.getRealDir()) var args = options.action.compileOptions buildFromDir(pkgInfo, paths, args) @@ -544,10 +556,10 @@ proc execBackend(options: Options) = var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) - let paths = processDeps(pkginfo, options) + let deps = processDeps(pkginfo, options) var args = "" - for path in paths: args.add("--path:\"" & path & "\" ") + for dep in deps: args.add("--path:\"" & dep.getRealDir() & "\" ") for option in options.action.compileOptions: args.add("\"" & option & "\" ") diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index ffdd323..81bd0f9 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -18,6 +18,7 @@ when not defined(nimscript): isNimScript*: bool ## Determines if this pkg info was read from a nims file isMinimal*: bool isInstalled*: bool ## Determines if the pkg this info belongs to is installed + isLinked*: bool ## Determines if the pkg this info belongs to has been linked via `develop` postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily preHooks*: HashSet[string] name*: string diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index b2f0ea7..85821d5 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -66,7 +66,7 @@ proc getNameVersion*(pkgpath: string): tuple[name, version: string] = ## ## Also works for file paths like: ## ``/home/user/.nimble/pkgs/package-0.1/package.nimble`` - if pkgPath.splitFile.ext == ".nimble" or pkgPath.splitFile.ext == ".babel": + if pkgPath.splitFile.ext in [".nimble", ".nimble-link", ".babel"]: return getNameVersion(pkgPath.splitPath.head) result.name = "" @@ -281,7 +281,7 @@ proc findNimbleFile*(dir: string; error: bool): string = if kind in {pcFile, pcLinkToFile}: let ext = path.splitFile.ext case ext - of ".babel", ".nimble": + of ".babel", ".nimble", ".nimble-link": result = path inc hits else: discard @@ -293,8 +293,16 @@ proc findNimbleFile*(dir: string; error: bool): string = raise newException(NimbleError, "Specified directory does not contain a .nimble file.") else: - display("Warning:", "No .nimble file found for " & dir, Warning, - HighPriority) + display("Warning:", "No .nimble or .nimble-link file found for " & + dir, Warning, HighPriority) + + if result.splitFile.ext == ".nimble-link": + # Return the path of the real .nimble file. + let lines = readFile(result).splitLines() + result = lines[0] + if not fileExists(result): + raiseNimbleError("The .nimble-link file is pointing to a missing" & + " file: " & result) proc getInstalledPkgsMin*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @@ -309,13 +317,15 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options): let nimbleFile = findNimbleFile(path, false) if nimbleFile != "": let meta = readMetaData(path) - let (name, version) = getNameVersion(nimbleFile) + let (name, version) = getNameVersion(path) var pkg = initPackageInfo(nimbleFile) pkg.name = name pkg.version = version pkg.specialVersion = version pkg.isMinimal = true pkg.isInstalled = true + pkg.isLinked = + cmpPaths(nimbleFile.splitFile().dir, path) != 0 result.add((pkg, meta)) proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool = @@ -369,7 +379,7 @@ proc findAllPkgs*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]], proc getRealDir*(pkgInfo: PackageInfo): string = ## Returns the directory containing the package source files. - if pkgInfo.srcDir != "" and not pkgInfo.isInstalled: + if pkgInfo.srcDir != "" and (not pkgInfo.isInstalled or pkgInfo.isLinked): result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir else: result = pkgInfo.mypath.splitFile.dir @@ -515,6 +525,8 @@ when isMainModule: ("package", "#head") doAssert getNameVersion("/home/user/.nimble/libs/package-#branch-with-dashes") == ("package", "#branch-with-dashes") + # readPackageInfo (and possibly more) depends on this not raising. + doAssert getNameVersion("/home/user/.nimble/libs/package") == ("package", "") doAssert toValidPackageName("foo__bar") == "foo_bar" doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe" diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index b69bd75..befa513 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -292,6 +292,11 @@ proc readPackageInfo(nf: NimbleFile, options: Options, result.version = minimalInfo.version result.isNimScript = true result.isMinimal = true + + # It's possible this proc will receive a .nimble-link file eventually, + # I added this assert to hopefully make this error clear for everyone. + let msg = "No version detected. Received nimble-link?" + assert result.version.len > 0, msg else: try: readPackageInfoFromNims(nf, options, result) @@ -386,6 +391,8 @@ proc getInstalledPkgs*(libsDir: string, options: Options): raise exc pkg.isInstalled = true + pkg.isLinked = + cmpPaths(nimbleFile.splitFile().dir, path) != 0 result.add((pkg, meta)) proc isNimScript*(nf: string, options: Options): bool = @@ -393,7 +400,9 @@ proc isNimScript*(nf: string, options: Options): bool = proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo = if pkg.isMinimal: - return getPkgInfoFromFile(pkg.mypath, options) + result = getPkgInfoFromFile(pkg.mypath, options) + result.isInstalled = pkg.isInstalled + result.isLinked = pkg.isLinked else: return pkg diff --git a/tests/develop/dependent/dependent.nimble b/tests/develop/dependent/dependent.nimble new file mode 100644 index 0000000..7bab4b7 --- /dev/null +++ b/tests/develop/dependent/dependent.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.0" +author = "Dominik Picheta" +description = "dependent" +license = "MIT" + +srcDir = "src" + +# Dependencies + +requires "nim >= 0.16.0", "srcdirtest" diff --git a/tests/develop/dependent/src/dependent.nim b/tests/develop/dependent/src/dependent.nim new file mode 100644 index 0000000..37231ba --- /dev/null +++ b/tests/develop/dependent/src/dependent.nim @@ -0,0 +1,3 @@ +import srcdirtest + +doAssert foo() == "correct" \ No newline at end of file diff --git a/tests/develop/srcdirtest/src/srcdirtest.nim b/tests/develop/srcdirtest/src/srcdirtest.nim index 53c687a..54b5b46 100644 --- a/tests/develop/srcdirtest/src/srcdirtest.nim +++ b/tests/develop/srcdirtest/src/srcdirtest.nim @@ -1 +1,4 @@ +proc foo*(): string = + return "correct" + echo("hello") \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index af544f9..b835ec8 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -24,10 +24,11 @@ test "can compile with --os:windows": template cd*(dir: string, body: untyped) = ## Sets the current dir to ``dir``, executes ``body`` and restores the ## previous working dir. - let lastDir = getCurrentDir() - setCurrentDir(dir) - body - setCurrentDir(lastDir) + block: + let lastDir = getCurrentDir() + setCurrentDir(dir) + body + setCurrentDir(lastDir) proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = var quotedArgs = @args @@ -500,4 +501,10 @@ suite "develop feature": let split = readFile(path).splitLines() check split.len == 2 check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble") - check split[1].endsWith("develop/srcdirtest/src") \ No newline at end of file + check split[1].endsWith("develop/srcdirtest/src") + + cd "develop/dependent": + let (output, exitCode) = execNimble("c", "-r", "src/dependent") + checkpoint output + check(output.processOutput.inLines("hello")) + check exitCode == QuitSuccess \ No newline at end of file From d72045ddc51b87633549de292e4a3e047ee50b01 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 16 Aug 2017 23:35:52 +0100 Subject: [PATCH 218/424] Attempt to fix tests. --- tests/tester.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index b835ec8..986c87f 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -504,7 +504,7 @@ suite "develop feature": check split[1].endsWith("develop/srcdirtest/src") cd "develop/dependent": - let (output, exitCode) = execNimble("c", "-r", "src/dependent") + let (output, exitCode) = execNimble("c", "-r", "src/dependent.nim") checkpoint output check(output.processOutput.inLines("hello")) check exitCode == QuitSuccess \ No newline at end of file From f746f4f0f390cdb1c8953ec838ec8588be9ca483 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 18 Aug 2017 23:20:30 +0100 Subject: [PATCH 219/424] Add docs for nimble develop. --- readme.markdown | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/readme.markdown b/readme.markdown index ec89917..ec8518d 100644 --- a/readme.markdown +++ b/readme.markdown @@ -172,6 +172,26 @@ list. See the [Creating Packages](#creating-packages) section for more info on t A URL to a repository can also be specified, Nimble will automatically detect the type of the repository that the url points to and install it. +### nimble develop + +The ``develop`` command allows you to link an existing copy of a package into +your installation directory. This is so that when developing a package you +don't need to keep reinstalling it for every single change. + + $ cd ~/projects/jester + $ nimble develop + +Any packages depending on ``jester`` will now use the code in +``~/projects/jester``. + +If you specify a package name to this command, Nimble will clone it into the +current working directory. + + $ nimble develop jester + +The ``jester`` package will be cloned into ``./jester`` and it will be linked +to your installation directory. + ### nimble uninstall The ``uninstall`` command will remove an installed package. Attempting to remove From 3bdce8d332feda71a31df2a0780860f755712fad Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 19 Aug 2017 20:56:29 +0100 Subject: [PATCH 220/424] Fixes removal of linked packages (and speeds up removal). --- src/nimble.nim | 9 ++++++--- src/nimblepkg/packageinstaller.nim | 4 ++-- tests/tester.nim | 12 +++++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 0d93af9..56a3b93 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -336,6 +336,7 @@ proc removePkgDir(dir: string, options: Options) = removeFile(options.getBinDir() / binary.str) # Search for an older version of the package we are removing. + # So that we can reinstate its symlink. let (pkgName, _) = getNameVersion(dir) let pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) var pkgInfo: PackageInfo @@ -818,7 +819,7 @@ proc uninstall(options: Options) = for pkgTup in options.action.packages: display("Looking", "for $1 ($2)" % [pkgTup.name, $pkgTup.ver], priority = HighPriority) - let installedPkgs = getInstalledPkgs(options.getPkgsDir(), options) + let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) var pkgList = findAllPkgs(installedPkgs, pkgTup) if pkgList.len == 0: raise newException(NimbleError, "Package not found") @@ -912,10 +913,12 @@ proc developFromDir(dir: string, options: Options) = # `nimble develop` if they change their `srcDir` but I think it's a worthy # compromise. let contents = pkgInfo.myPath & "\n" & pkgInfo.getRealDir() - writeFile(pkgDestDir / pkgInfo.name.addFileExt("nimble-link"), contents) + let nimbleLinkPath = pkgDestDir / pkgInfo.name.addFileExt("nimble-link") + writeFile(nimbleLinkPath, contents) # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir)) + saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir), + nimbleLinkPath) # Save the nimble data (which might now contain reverse deps added in # processDeps). diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index d34a9a7..e48a910 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -94,7 +94,7 @@ proc saveNimbleMeta*(pkgDestDir, url, vcsRevision: string, nimblemeta["isLink"] = %isLink writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta) -proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision: string) = +proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision, nimbleLinkPath: string) = ## Overload of saveNimbleMeta for linked (.nimble-link) packages. ## ## pkgDestDir - The directory where the package has been installed. @@ -103,4 +103,4 @@ proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision: string) = ## pkgDir - The directory where the original package files are. ## For example: ~/projects/jester/ saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision, - initSet[string](), initSet[string](), true) \ No newline at end of file + toSet[string]([nimbleLinkPath]), initSet[string](), true) \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index 986c87f..ad8906a 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -507,4 +507,14 @@ suite "develop feature": let (output, exitCode) = execNimble("c", "-r", "src/dependent.nim") checkpoint output check(output.processOutput.inLines("hello")) - check exitCode == QuitSuccess \ No newline at end of file + check exitCode == QuitSuccess + + test "can uninstall linked package": + cd "develop/srcdirtest": + let (_, exitCode) = execNimble("develop", "-y") + check exitCode == QuitSuccess + + let (output, exitCode) = execNimble("uninstall", "-y", "srcdirtest") + checkpoint(output) + check exitCode == QuitSuccess + check(not output.processOutput.inLines("warning")) From c46e3dcd4d6c97ebf0b69d4610f96251356066b4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 19 Aug 2017 21:02:15 +0100 Subject: [PATCH 221/424] Speeds up the `list -i` command. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 56a3b93..1b2835d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -625,7 +625,7 @@ proc list(options: Options) = proc listInstalled(options: Options) = var h = initOrderedTable[string, seq[string]]() - let pkgs = getInstalledPkgs(options.getPkgsDir(), options) + let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options) for x in pkgs.items(): let pName = x.pkginfo.name From bdfb6818244b397eead352dff2b34b02790c407e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 19 Aug 2017 21:22:48 +0100 Subject: [PATCH 222/424] Fixes #290. --- src/nimble.nim | 2 ++ src/nimblepkg/cli.nim | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 1b2835d..e7058f1 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -650,6 +650,7 @@ proc listPaths(options: Options) = ## but at the end quits with a non zero exit error. ## ## On success the proc returns normally. + cli.setSuppressMessages(true) assert options.action.typ == actionPath assert(not options.action.packages.isNil) @@ -720,6 +721,7 @@ proc getPackageByPattern(pattern: string, options: Options): PackageInfo = result = getPkgInfoFromFile(skeletonInfo.myPath, options) proc dump(options: Options) = + cli.setSuppressMessages(true) let p = getPackageByPattern(options.action.projName, options) echo "name: ", p.name.escape echo "version: ", p.version.escape diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 76caaba..0d2a906 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -20,6 +20,10 @@ type warnings: HashSet[(string, string)] suppressionCount: int ## Amount of messages which were not shown. showColor: bool ## Whether messages should be colored. + suppressMessages: bool ## Whether Warning, Message and Success messages + ## should be suppressed, useful for + ## commands like `dump` whose output should be + ## machine readable. Priority* = enum DebugPriority, LowPriority, MediumPriority, HighPriority @@ -42,7 +46,8 @@ proc newCLI(): CLI = level: HighPriority, warnings: initSet[(string, string)](), suppressionCount: 0, - showColor: true + showColor: true, + suppressMessages: false ) var globalCLI = newCLI() @@ -77,6 +82,13 @@ proc displayLine(category, line: string, displayType: DisplayType, proc display*(category, msg: string, displayType = Message, priority = MediumPriority) = + + # Don't print any Warning, Message or Success messages when suppression of + # warnings is enabled. That is, unless the user asked for --verbose output. + if globalCLI.suppressMessages and displayType >= Warning and + globalCLI.level == HighPriority: + return + # Multiple warnings containing the same messages should not be shown. let warningPair = (category, msg) if displayType == Warning: @@ -155,6 +167,9 @@ proc setVerbosity*(level: Priority) = proc setShowColor*(val: bool) = globalCLI.showColor = val +proc setSuppressMessages*(val: bool) = + globalCLI.suppressMessages = val + when isMainModule: display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini", priority = LowPriority) From acbce88bacb4b0a60c912f8b0d7806255ca85c23 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 19 Aug 2017 22:03:45 +0100 Subject: [PATCH 223/424] Fixes cloning repo for `develop` command. --- src/nimble.nim | 10 +++++++++- src/nimblepkg/options.nim | 2 +- tests/tester.nim | 8 ++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e7058f1..38fef3a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -926,13 +926,21 @@ proc developFromDir(dir: string, options: Options) = # processDeps). saveNimbleData(options) + display("Success:", (pkgInfo.name & " linked successfully to '$1'.") % + dir, Success, HighPriority) + proc develop(options: Options) = if options.action.packages == @[]: developFromDir(getCurrentDir(), options) else: # Install each package. for pv in options.action.packages: - let downloadDir = getCurrentDir() / pv.name + let name = + if isURL(pv.name): + parseUri(pv.name).path + else: + pv.name + let downloadDir = getCurrentDir() / name if dirExists(downloadDir): let msg = "Cannot clone into '$1': directory exists." % downloadDir let hint = "Remove the directory, or run this command somewhere else." diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 5890a00..ae2cdb2 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -219,7 +219,7 @@ proc parseArgument*(key: string, result: var Options) = case result.action.typ of actionNil: assert false - of actionInstall, actionPath, actionUninstall: + of actionInstall, actionPath, actionDevelop, actionUninstall: # Parse pkg@verRange if '@' in key: let i = find(key, '@') diff --git a/tests/tester.nim b/tests/tester.nim index ad8906a..0732177 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -518,3 +518,11 @@ suite "develop feature": checkpoint(output) check exitCode == QuitSuccess check(not output.processOutput.inLines("warning")) + + test "can git clone for develop": + let cloneDir = installDir / "developTmp" + createDir(cloneDir) + cd cloneDir: + let url = "https://github.com/nimble-test/packagea.git" + let (output, exitCode) = execNimble("develop", "-y", url) + check exitCode == QuitSuccess \ No newline at end of file From 555a10dcb8c53bfc574db2d4629722ebe0d30424 Mon Sep 17 00:00:00 2001 From: Federico Ceratto Date: Wed, 23 Aug 2017 18:44:50 +0100 Subject: [PATCH 224/424] Add completion for zsh --- nimble.zsh-completion | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 nimble.zsh-completion diff --git a/nimble.zsh-completion b/nimble.zsh-completion new file mode 100644 index 0000000..0d59b59 --- /dev/null +++ b/nimble.zsh-completion @@ -0,0 +1,51 @@ +#compdef nimble + +_nimble() { + local line + + _arguments -C \ + '1: :(install init publish uninstall build c cc js doc doc2 refresh search list tasks path dump develop)' \ + '*::options:->options' \ + '(--version)--version[show version]' \ + '(--help)--help[show help]' \ + '(-)--help[display help information]' \ + '(-)--version[display version information]' \ + '(-y --accept)'{-y,--accept}'[accept all interactive prompts]' \ + {-n,--reject}'[reject all interactive prompts]' \ + '--ver[Query remote server for package version information when searching or listing packages]' \ + '--nimbleDir dirname[Set the Nimble directory]' \ + '(-d --depsOnly)'{-d,--depsOnly}'[Install only dependencies]' + + if [ $#line -eq 0 ]; then + # if the command line is empty and "nimble tasks" is successfull, add custom tasks + tasks=$(nimble tasks) + if [ $? -eq 0 ]; then + compadd - $(echo $tasks | cut -f1 -d" " | tr '\n' ' ') + fi + fi + + case $line[1] in + install) + _nimble_installable_packages + ;; + uninstall|path|dump) + _nimble_installed_packages + ;; + init|publish|build|refresh|search|tasks) + (( ret )) && _message 'no more arguments' + ;; + *) + (( ret )) && _message 'no more arguments' + ;; + esac +} + +function _nimble_installable_packages { + compadd - $(nimble list 2> /dev/null | grep -v '^ ' | tr -d ':') +} + +function _nimble_installed_packages { + compadd - $(nimble list -i 2> /dev/null | grep ']$' | cut -d' ' -f1) +} + +_nimble "$@" From 43489da1f2c635999bc2cb18120030d728a12540 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 28 Aug 2017 23:00:56 +0100 Subject: [PATCH 225/424] Added implementation details about .nimble-link files to readme. --- readme.markdown | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/readme.markdown b/readme.markdown index ec8518d..f8dbf62 100644 --- a/readme.markdown +++ b/readme.markdown @@ -860,6 +860,21 @@ If you have any questions about the project you can ask me directly on github, ask on the Nim [forum](http://forum.nim-lang.org), or ask on Freenode in the #nim channel. +## Implementation details + +### .nimble-link + +These files are created by Nimble when using the ``develop`` command. They +are very simple and contain two lines. + +**The first line:** Always a path to the `.nimble` file. +**The second line:** Always a path to the Nimble package's source code. Usually +``$pkgDir/src``, depending on what ``srcDir`` is set to. + +The paths written by Nimble are **always** absolute. But Nimble (and the +Nim compiler) also supports relative paths, which will be read relative to +the `.nimble-link` file. + ## About Nimble has been written by [Dominik Picheta](http://picheta.me/) with help from From 9d0b978845ce1efdd703bd30a3474bba3eb03404 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 28 Aug 2017 23:18:46 +0100 Subject: [PATCH 226/424] Fixes readme formatting. --- readme.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.markdown b/readme.markdown index f8dbf62..b3c73c3 100644 --- a/readme.markdown +++ b/readme.markdown @@ -868,6 +868,7 @@ These files are created by Nimble when using the ``develop`` command. They are very simple and contain two lines. **The first line:** Always a path to the `.nimble` file. + **The second line:** Always a path to the Nimble package's source code. Usually ``$pkgDir/src``, depending on what ``srcDir`` is set to. From 3c1e669eaa8b613040150f8063aaee7b74ae980e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 2 Sep 2017 15:39:57 +0100 Subject: [PATCH 227/424] Only consider #head to be newest not other special versions. Refs #311. --- src/nimblepkg/version.nim | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index e8803ba..7fa7a73 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -35,24 +35,30 @@ type NimbleError* = object of Exception hint*: string -proc newVersion*(ver: string): Version = - doAssert(ver[0] in {'#', '\0'} + Digits, "Wrong version: " & ver) - return Version(ver) - proc `$`*(ver: Version): string {.borrow.} proc hash*(ver: Version): Hash {.borrow.} proc isNil*(ver: Version): bool {.borrow.} +proc newVersion*(ver: string): Version = + doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits, + "Wrong version: " & ver) + return Version(ver) + proc isSpecial*(ver: Version): bool = - return ($ver)[0] == '#' + return ($ver).len > 0 and ($ver)[0] == '#' proc `<`*(ver: Version, ver2: Version): bool = # Handling for special versions such as "#head" or "#branch". if ver.isSpecial or ver2.isSpecial: # TODO: This may need to be reverted. See #311. - return ($ver2).normalize == "#head" and ($ver).normalize != "#head" + if ver2.isSpecial and ($ver2).normalize == "#head": + return ($ver).normalize != "#head" + + if not ver2.isSpecial: + # `#aa111 < 1.1` + return ($ver).normalize != "#head" # Handling for normal versions such as "0.1.0" or "1.0". var sVer = string(ver).split('.') @@ -338,6 +344,10 @@ when isMainModule: doAssert(newVersion("#head") > newVersion("0.1.0")) doAssert(not(newVersion("#head") > newVersion("#head"))) doAssert(withinRange(newVersion("#head"), parseVersionRange(">= 0.5.0"))) + doAssert newVersion("#a111") < newVersion("#head") + # We assume that all other special versions are not higher than a normal + # version. + doAssert newVersion("#a111") < newVersion("1.1") # An empty version range should give verAny doAssert parseVersionRange("").kind == verAny From 92e9ec5e59979f6453b975600182a2ab032d16bb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 2 Sep 2017 23:19:03 +0100 Subject: [PATCH 228/424] Fixes #373. Implements #287. Fixes #271. --- src/nimble.nim | 98 ++++++------------------ src/nimblepkg/reversedeps.nim | 115 ++++++++++++++++++++++++++++ tests/revdep/mydep/mydep.nimble | 10 +++ tests/revdep/pkgNoDep/pkgA.nimble | 11 +++ tests/revdep/pkgWithDep/pkgA.nimble | 11 +++ tests/tester.nim | 32 ++++++++ 6 files changed, 203 insertions(+), 74 deletions(-) create mode 100644 src/nimblepkg/reversedeps.nim create mode 100644 tests/revdep/mydep/mydep.nimble create mode 100644 tests/revdep/pkgNoDep/pkgA.nimble create mode 100644 tests/revdep/pkgWithDep/pkgA.nimble diff --git a/src/nimble.nim b/src/nimble.nim index 38fef3a..f8ac7c1 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -13,7 +13,7 @@ from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser, - nimblepkg/cli, nimblepkg/packageinstaller + nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps import nimblepkg/nimscriptsupport @@ -141,61 +141,6 @@ proc copyFilesRec(origDir, currentDir, dest: string, result.incl copyFileD(pkgInfo.mypath, changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath)) -proc saveNimbleData(options: Options) = - # TODO: This file should probably be locked. - writeFile(options.getNimbleDir() / "nimbledata.json", - pretty(options.nimbleData)) - -proc addRevDep(options: Options, dep: tuple[name, version: string], - pkg: PackageInfo) = - # let depNameVer = dep.name & '-' & dep.version - if not options.nimbleData["reverseDeps"].hasKey(dep.name): - options.nimbleData["reverseDeps"][dep.name] = newJObject() - if not options.nimbleData["reverseDeps"][dep.name].hasKey(dep.version): - options.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray() - let revDep = %{ "name": %pkg.name, "version": %pkg.specialVersion} - let thisDep = options.nimbleData["reverseDeps"][dep.name][dep.version] - if revDep notin thisDep: - thisDep.add revDep - -proc removeRevDep(options: Options, pkg: PackageInfo) = - ## Removes ``pkg`` from the reverse dependencies of every package. - assert(not pkg.isMinimal) - proc remove(options: Options, pkg: PackageInfo, depTup: PkgTuple, - thisDep: JsonNode) = - for ver, val in thisDep: - if ver.newVersion in depTup.ver: - var newVal = newJArray() - for revDep in val: - if not (revDep["name"].str == pkg.name and - revDep["version"].str == pkg.specialVersion): - newVal.add revDep - thisDep[ver] = newVal - - for depTup in pkg.requires: - if depTup.name.isURL(): - # We sadly must go through everything in this case... - for key, val in options.nimbleData["reverseDeps"]: - options.remove(pkg, depTup, val) - else: - let thisDep = options.nimbleData{"reverseDeps", depTup.name} - if thisDep.isNil: continue - options.remove(pkg, depTup, thisDep) - - # Clean up empty objects/arrays - var newData = newJObject() - for key, val in options.nimbleData["reverseDeps"]: - if val.len != 0: - var newVal = newJObject() - for ver, elem in val: - if elem.len != 0: - newVal[ver] = elem - if newVal.len != 0: - newData[key] = newVal - options.nimbleData["reverseDeps"] = newData - - saveNimbleData(options) - proc install(packages: seq[PkgTuple], options: Options, doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] @@ -270,7 +215,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = # (unsatisfiable dependendencies). # N.B. NimbleData is saved in installFromDir. for i in reverseDeps: - addRevDep(options, i, pkginfo) + addRevDep(options.nimbleData, i, pkginfo) proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], args: var seq[string]) = @@ -416,6 +361,11 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, [pkgInfo.name, pkgInfo.specialVersion] if not options.prompt(msg): raise NimbleQuit(msg: "") + + # Remove reverse deps. + let pkgInfo = getPkgInfo(pkgDestDir, options) + options.nimbleData.removeRevDep(pkgInfo) + removePkgDir(pkgDestDir, options) # Remove any symlinked binaries for bin in pkgInfo.bin: @@ -426,7 +376,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, else: removeFile(binDir / bin) - createDir(pkgDestDir) # Copy this package's files based on the preferences specified in PkgInfo. var filesInstalled = initSet[string]() @@ -831,21 +780,20 @@ proc uninstall(options: Options) = for pkg in pkgList: # Check whether any packages depend on the ones the user is trying to # uninstall. - let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.specialVersion} - if not thisPkgsDep.isNil: - var reason = "" - if thisPkgsDep.len == 1: - reason = "$1 ($2) depends on it" % [thisPkgsDep[0]["name"].str, - thisPkgsDep[0]["version"].str] - else: - for i in 0 .. 0: + errors.add("Cannot uninstall $1 ($2) because $3" % + [pkgTup.name, pkg.specialVersion, reason]) else: pkgsToDelete.add pkg @@ -869,12 +817,14 @@ proc uninstall(options: Options) = # removeRevDep needs the package dependency info, so we can't just pass # a minimal pkg info. - removeRevDep(options, pkg.toFullInfo(options)) + removeRevDep(options.nimbleData, pkg.toFullInfo(options)) removePkgDir(options.getPkgsDir / (pkg.name & '-' & pkg.specialVersion), options) display("Removed", "$1 ($2)" % [pkg.name, $pkg.specialVersion], Success, HighPriority) + saveNimbleData(options) + proc listTasks(options: Options) = let nimbleFile = findNimbleFile(getCurrentDir(), true) nimscriptsupport.listTasks(nimbleFile, options) diff --git a/src/nimblepkg/reversedeps.nim b/src/nimblepkg/reversedeps.nim new file mode 100644 index 0000000..551ee19 --- /dev/null +++ b/src/nimblepkg/reversedeps.nim @@ -0,0 +1,115 @@ +# Copyright (C) Dominik Picheta. All rights reserved. +# BSD License. Look at license.txt for more info. + +import os, json + +import options, common, version, download, packageinfo + +proc saveNimbleData*(options: Options) = + # TODO: This file should probably be locked. + writeFile(options.getNimbleDir() / "nimbledata.json", + pretty(options.nimbleData)) + +proc addRevDep*(nimbleData: JsonNode, dep: tuple[name, version: string], + pkg: PackageInfo) = + # Add a record which specifies that `pkg` has a dependency on `dep`, i.e. + # the reverse dependency of `dep` is `pkg`. + if not nimbleData["reverseDeps"].hasKey(dep.name): + nimbleData["reverseDeps"][dep.name] = newJObject() + if not nimbleData["reverseDeps"][dep.name].hasKey(dep.version): + nimbleData["reverseDeps"][dep.name][dep.version] = newJArray() + let revDep = %{ "name": %pkg.name, "version": %pkg.specialVersion} + let thisDep = nimbleData["reverseDeps"][dep.name][dep.version] + if revDep notin thisDep: + thisDep.add revDep + +proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) = + ## Removes ``pkg`` from the reverse dependencies of every package. + assert(not pkg.isMinimal) + proc remove(pkg: PackageInfo, depTup: PkgTuple, thisDep: JsonNode) = + for ver, val in thisDep: + if ver.newVersion in depTup.ver: + var newVal = newJArray() + for revDep in val: + if not (revDep["name"].str == pkg.name and + revDep["version"].str == pkg.specialVersion): + newVal.add revDep + thisDep[ver] = newVal + + for depTup in pkg.requires: + if depTup.name.isURL(): + # We sadly must go through everything in this case... + for key, val in nimbleData["reverseDeps"]: + remove(pkg, depTup, val) + else: + let thisDep = nimbleData{"reverseDeps", depTup.name} + if thisDep.isNil: continue + remove(pkg, depTup, thisDep) + + # Clean up empty objects/arrays + var newData = newJObject() + for key, val in nimbleData["reverseDeps"]: + if val.len != 0: + var newVal = newJObject() + for ver, elem in val: + if elem.len != 0: + newVal[ver] = elem + if newVal.len != 0: + newData[key] = newVal + nimbleData["reverseDeps"] = newData + +proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] = + ## Returns a list of *currently installed* reverse dependencies for `pkg`. + result = @[] + let thisPkgsDep = + options.nimbleData["reverseDeps"]{pkg.name}{pkg.specialVersion} + if not thisPkgsDep.isNil: + let pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) + for pkg in thisPkgsDep: + let pkgTup = ( + name: pkg["name"].getStr(), + ver: parseVersionRange(pkg["version"].getStr()) + ) + var pkgInfo: PackageInfo + if not findPkg(pkgList, pkgTup, pkgInfo): + continue + + result.add(pkgTup) + +when isMainModule: + var nimbleData = %{"reverseDeps": newJObject()} + + let nimforum1 = PackageInfo( + isMinimal: false, + name: "nimforum", + specialVersion: "0.1.0", + requires: @[("jester", parseVersionRange("0.1.0")), + ("captcha", parseVersionRange("1.0.0")), + ("auth", parseVersionRange("#head"))] + ) + let nimforum2 = PackageInfo(isMinimal: false, name: "nimforum", specialVersion: "0.2.0") + let play = PackageInfo(isMinimal: false, name: "play", specialVersion: "#head") + + nimbleData.addRevDep(("jester", "0.1.0"), nimforum1) + nimbleData.addRevDep(("jester", "0.1.0"), play) + nimbleData.addRevDep(("captcha", "1.0.0"), nimforum1) + nimbleData.addRevDep(("auth", "#head"), nimforum1) + nimbleData.addRevDep(("captcha", "1.0.0"), nimforum2) + nimbleData.addRevDep(("auth", "#head"), nimforum2) + + doAssert nimbleData["reverseDeps"]["jester"]["0.1.0"].len == 2 + doAssert nimbleData["reverseDeps"]["captcha"]["1.0.0"].len == 2 + doAssert nimbleData["reverseDeps"]["auth"]["#head"].len == 2 + + block: + nimbleData.removeRevDep(nimforum1) + let jester = nimbleData["reverseDeps"]["jester"]["0.1.0"][0] + doAssert jester["name"].getStr() == play.name + doAssert jester["version"].getStr() == play.specialVersion + + let captcha = nimbleData["reverseDeps"]["captcha"]["1.0.0"][0] + doAssert captcha["name"].getStr() == nimforum2.name + doAssert captcha["version"].getStr() == nimforum2.specialVersion + + echo("Everything works!") + diff --git a/tests/revdep/mydep/mydep.nimble b/tests/revdep/mydep/mydep.nimble new file mode 100644 index 0000000..1d5f3a9 --- /dev/null +++ b/tests/revdep/mydep/mydep.nimble @@ -0,0 +1,10 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Random dep" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.0" \ No newline at end of file diff --git a/tests/revdep/pkgNoDep/pkgA.nimble b/tests/revdep/pkgNoDep/pkgA.nimble new file mode 100644 index 0000000..fd6878a --- /dev/null +++ b/tests/revdep/pkgNoDep/pkgA.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package A" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.0" + diff --git a/tests/revdep/pkgWithDep/pkgA.nimble b/tests/revdep/pkgWithDep/pkgA.nimble new file mode 100644 index 0000000..842af28 --- /dev/null +++ b/tests/revdep/pkgWithDep/pkgA.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package A" +license = "MIT" + +# Dependencies + +requires "nim >= 0.15.0", "mydep" + diff --git a/tests/tester.nim b/tests/tester.nim index 0732177..8496b8d 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -38,6 +38,15 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = result = execCmdEx(quotedArgs.join(" ")) +proc execNimbleYes(args: varargs[string]): tuple[output: string, exitCode: int]= + # issue #6314 + execNimble(@args & "-y") + +template verify(res: (string, int)) = + let r = res + checkpoint r[0] + check r[1] == QuitSuccess + proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) @@ -466,6 +475,29 @@ test "can pass args with spaces to Nim (#351)": checkpoint output check exitCode == QuitSuccess +suite "reverse dependencies": + test "basic test": + cd "revdep/mydep": + verify execNimbleYes("install") + + cd "revdep/pkgWithDep": + verify execNimbleYes("install") + + verify execNimbleYes("remove", "pkgA") + verify execNimbleYes("remove", "mydep") + + test "issue #373": + cd "revdep/mydep": + verify execNimbleYes("install") + + cd "revdep/pkgWithDep": + verify execNimbleYes("install") + + cd "revdep/pkgNoDep": + verify execNimbleYes("install") + + verify execNimbleYes("remove", "mydep") + suite "develop feature": test "can reject binary packages": cd "develop/binary": From 301a366dd21b6dee121e36ad678a2fbab19e9b18 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 3 Sep 2017 17:37:52 +0100 Subject: [PATCH 229/424] Refactoring and many fixes to PR #378. (Broken) This commit is broken due to a cleanup issue with NimScript eval. --- src/nimble.nim | 105 ++++++------------ src/nimblepkg/nimscriptexecutor.nim | 70 ++++++++++++ src/nimblepkg/nimscriptsupport.nim | 6 +- src/nimblepkg/options.nim | 19 ++-- src/nimblepkg/packageparser.nim | 1 + tests/testCommand/testOverride/myTester.nim | 1 + tests/testCommand/testOverride/pkga.nimble | 9 ++ .../testsFail/testing123.nim | 0 .../testsFail/testing123.nimble | 0 tests/{ => testCommand}/testsFail/tests/a.nim | 0 tests/{ => testCommand}/testsFail/tests/b.nim | 0 tests/{ => testCommand}/testsFail/tests/c.nim | 0 .../testsPass/testing123.nim | 0 .../testsPass/testing123.nimble | 0 .../{ => testCommand}/testsPass/tests/one.nim | 0 .../testsPass/tests/three.nim | 0 .../{ => testCommand}/testsPass/tests/two.nim | 0 tests/tester.nim | 39 ++++--- 18 files changed, 150 insertions(+), 100 deletions(-) create mode 100644 src/nimblepkg/nimscriptexecutor.nim create mode 100644 tests/testCommand/testOverride/myTester.nim create mode 100644 tests/testCommand/testOverride/pkga.nimble rename tests/{ => testCommand}/testsFail/testing123.nim (100%) rename tests/{ => testCommand}/testsFail/testing123.nimble (100%) rename tests/{ => testCommand}/testsFail/tests/a.nim (100%) rename tests/{ => testCommand}/testsFail/tests/b.nim (100%) rename tests/{ => testCommand}/testsFail/tests/c.nim (100%) rename tests/{ => testCommand}/testsPass/testing123.nim (100%) rename tests/{ => testCommand}/testsPass/testing123.nimble (100%) rename tests/{ => testCommand}/testsPass/tests/one.nim (100%) rename tests/{ => testCommand}/testsPass/tests/three.nim (100%) rename tests/{ => testCommand}/testsPass/tests/two.nim (100%) diff --git a/src/nimble.nim b/src/nimble.nim index 3a933aa..883468a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -13,7 +13,8 @@ from sequtils import toSeq import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser, - nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps + nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps, + nimblepkg/nimscriptexecutor import nimblepkg/nimscriptsupport @@ -529,28 +530,6 @@ proc execBackend(options: Options) = [backend, args, bin], showOutput = true) display("Success:", "Execution finished", Success, HighPriority) -proc tempOutArg(file: string): string = - ## Returns the `--out` argument to pass to the compiler, using a temp file - let (_, name, _) = splitFile(file) - let dir = getNimbleTempDir() / "tests" - createDir(dir) - result = "--out:" & (dir / name) - -proc test(options: Options) = - ## Executes all tests - var files = toSeq(walkDir(getCurrentDir() / "tests")) - files.sort do (a, b: auto) -> int: - result = cmp(a.path, b.path) - - for file in files: - if file.path.endsWith(".nim") and file.kind in { pcFile, pcLinkToFile }: - var optsCopy = options - optsCopy.action.file = file.path - optsCopy.action.backend = "c -r" - optsCopy.action.compileOptions.add("--path:.") - optsCopy.action.compileOptions.add(file.path.tempOutArg) - execBackend(optsCopy) - proc search(options: Options) = ## Searches for matches in ``options.action.search``. ## @@ -922,25 +901,23 @@ proc develop(options: Options) = discard downloadPkg(url, pv.ver, meth, options, downloadDir) developFromDir(downloadDir, options) -proc execHook(options: Options, before: bool): bool = - ## Returns whether to continue. - result = true - var nimbleFile = "" - try: - nimbleFile = findNimbleFile(getCurrentDir(), true) - except NimbleError: return true - # PackageInfos are cached so we can read them as many times as we want. - let pkgInfo = getPkgInfoFromFile(nimbleFile, options) - let actionName = - if options.action.typ == actionCustom: options.action.command - else: ($options.action.typ)[6 .. ^1] - let hookExists = - if before: actionName.normalize in pkgInfo.preHooks - else: actionName.normalize in pkgInfo.postHooks - if pkgInfo.isNimScript and hookExists: - let res = execHook(nimbleFile, actionName, before, options) - if res.success: - result = res.retVal +proc test(options: Options) = + ## Executes all tests. + var files = toSeq(walkDir(getCurrentDir() / "tests")) + files.sort((a, b) => cmp(a.path, b.path)) + + for file in files: + if file.path.endsWith(".nim") and file.kind in {pcFile, pcLinkToFile}: + var optsCopy = options.briefClone() + optsCopy.action.typ = actionCompile + optsCopy.action.file = file.path + optsCopy.action.backend = "c" + optsCopy.action.compileOptions = @[] + optsCopy.action.compileOptions.add("-r") + optsCopy.action.compileOptions.add("--path:.") + execBackend(optsCopy) + + display("Success:", "All tests passed", Success, HighPriority) proc doAction(options: Options) = if options.showHelp: @@ -982,8 +959,6 @@ proc doAction(options: Options) = listPaths(options) of actionBuild: build(options) - of actionTest: - test(options) of actionCompile, actionDoc: execBackend(options) of actionInit: @@ -1000,37 +975,19 @@ proc doAction(options: Options) = of actionNil: assert false of actionCustom: - # Custom command. Attempt to call a NimScript task. - let nimbleFile = findNimbleFile(getCurrentDir(), true) - if not nimbleFile.isNimScript(options): - writeHelp() + let isPreDefined = options.action.command.normalize == "test" - let execResult = execTask(nimbleFile, options.action.command, options) - if not execResult.success: - raiseNimbleError(msg = "Could not find task $1 in $2" % - [options.action.command, nimbleFile], - hint = "Run `nimble --help` and/or `nimble tasks` for" & - " a list of possible commands.") - - if execResult.command.normalize == "nop": - display("Warning:", "Using `setCommand 'nop'` is not necessary.", Warning, - HighPriority) - return - - if not execHook(options, false): - return - - if execResult.hasTaskRequestedCommand(): - var newOptions = initOptions() - newOptions.config = options.config - newOptions.nimbleData = options.nimbleData - parseCommand(execResult.command, newOptions) - for arg in execResult.arguments: - parseArgument(arg, newOptions) - for flag, vals in execResult.flags: - for val in vals: - parseFlag(flag, val, newOptions) - doAction(newOptions) + var execResult: ExecutionResult[void] + if execCustom(options, execResult, failFast=not isPreDefined): + if execResult.hasTaskRequestedCommand(): + doAction(execResult.getOptionsForCommand(options)) + else: + # If there is no task defined for the `test` task, we run the pre-defined + # fallback logic. + if isPreDefined: + test(options) + # Run the post hook for `test` in case it exists. + discard execHook(options, false) if options.action.typ != actionCustom: discard execHook(options, false) diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim new file mode 100644 index 0000000..4e1e3c2 --- /dev/null +++ b/src/nimblepkg/nimscriptexecutor.nim @@ -0,0 +1,70 @@ +# Copyright (C) Dominik Picheta. All rights reserved. +# BSD License. Look at license.txt for more info. + +import os, tables, strutils, sets + +import packageparser, common, packageinfo, options, nimscriptsupport, cli + +proc execHook*(options: Options, before: bool): bool = + ## Returns whether to continue. + result = true + var nimbleFile = "" + try: + nimbleFile = findNimbleFile(getCurrentDir(), true) + except NimbleError: return true + # PackageInfos are cached so we can read them as many times as we want. + let pkgInfo = getPkgInfoFromFile(nimbleFile, options) + let actionName = + if options.action.typ == actionCustom: options.action.command + else: ($options.action.typ)[6 .. ^1] + let hookExists = + if before: actionName.normalize in pkgInfo.preHooks + else: actionName.normalize in pkgInfo.postHooks + if pkgInfo.isNimScript and hookExists: + let res = execHook(nimbleFile, actionName, before, options) + if res.success: + result = res.retVal + +proc execCustom*(options: Options, + execResult: var ExecutionResult[void], + failFast = true): bool = + ## Executes the custom command using the nimscript backend. + ## + ## If failFast is true then exceptions will be raised when something is wrong. + ## Otherwise this function will just return false. + + # Custom command. Attempt to call a NimScript task. + let nimbleFile = findNimbleFile(getCurrentDir(), true) + if not nimbleFile.isNimScript(options) and failFast: + writeHelp() + + execResult = execTask(nimbleFile, options.action.command, options) + if not execResult.success: + if not failFast: + return + raiseNimbleError(msg = "Could not find task $1 in $2" % + [options.action.command, nimbleFile], + hint = "Run `nimble --help` and/or `nimble tasks` for" & + " a list of possible commands.") + + if execResult.command.normalize == "nop": + display("Warning:", "Using `setCommand 'nop'` is not necessary.", Warning, + HighPriority) + return + + if not execHook(options, false): + return + + return true + +proc getOptionsForCommand*(execResult: ExecutionResult, + options: Options): Options = + ## Creates an Options object for the requested command. + var newOptions = options.briefClone() + parseCommand(execResult.command, newOptions) + for arg in execResult.arguments: + parseArgument(arg, newOptions) + for flag, vals in execResult.flags: + for val in vals: + parseFlag(flag, val, newOptions) + return newOptions diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 6bcf763..7188479 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -454,6 +454,6 @@ proc listTasks*(scriptName: string, options: Options) = setNimScriptCommand("help") discard execScript(scriptName, nil, options) - # TODO: Make the 'task' template generate explicit data structure containing - # all the task names + descriptions. - cleanup() + # TODO (#402): Make the 'task' template generate explicit data structure + # containing all the task names + descriptions. + cleanup() \ No newline at end of file diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 97eb870..2609254 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -27,7 +27,7 @@ type actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionDoc, actionCustom, actionTasks, actionDevelop, actionTest + actionDoc, actionCustom, actionTasks, actionDevelop Action* = object case typ*: ActionType @@ -41,7 +41,7 @@ type search*: seq[string] # Search string. of actionInit, actionDump: projName*: string - of actionCompile, actionDoc, actionBuild, actionTest: + of actionCompile, actionDoc, actionBuild: file*: string backend*: string compileOptions*: seq[string] @@ -126,8 +126,6 @@ proc parseActionType*(action: string): ActionType = result = actionPath of "build": result = actionBuild - of "test": - result = actionTest of "c", "compile", "js", "cpp", "cc": result = actionCompile of "doc", "doc2": @@ -160,7 +158,7 @@ proc initAction*(options: var Options, key: string) = case options.action.typ of actionInstall, actionPath, actionDevelop, actionUninstall: options.action.packages = @[] - of actionCompile, actionDoc, actionBuild, actionTest: + of actionCompile, actionDoc, actionBuild: options.action.compileOptions = @[] options.action.file = "" if keyNorm == "c" or keyNorm == "compile": options.action.backend = "" @@ -242,7 +240,7 @@ proc parseArgument*(key: string, result: var Options) = result.action.projName = key of actionCompile, actionDoc: result.action.file = key - of actionList, actionBuild, actionTest, actionPublish: + of actionList, actionBuild, actionPublish: result.showHelp = true of actionCustom: result.action.arguments.add(key) @@ -281,7 +279,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.depsOnly = true else: wasFlagHandled = false - of actionCompile, actionDoc, actionBuild, actionTest: + of actionCompile, actionDoc, actionBuild: let prefix = if kind == cmdShortOption: "-" else: "--" if val == "": result.action.compileOptions.add(prefix & flag) @@ -370,3 +368,10 @@ proc getProxy*(options: Options): Proxy = return newProxy($parsed, auth) else: return nil + +proc briefClone*(options: Options): Options = + ## Clones the few important fields and creates a new Options object. + var newOptions = initOptions() + newOptions.config = options.config + newOptions.nimbleData = options.nimbleData + return newOptions \ No newline at end of file diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index befa513..d7096b5 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -268,6 +268,7 @@ proc readPackageInfo(nf: NimbleFile, options: Options, assert fileExists(nf) # Check the cache. + echo(nf, options.pkgInfoCache.hasKey(nf)) if options.pkgInfoCache.hasKey(nf): return options.pkgInfoCache[nf] diff --git a/tests/testCommand/testOverride/myTester.nim b/tests/testCommand/testOverride/myTester.nim new file mode 100644 index 0000000..0e1a8f3 --- /dev/null +++ b/tests/testCommand/testOverride/myTester.nim @@ -0,0 +1 @@ +echo("overriden") \ No newline at end of file diff --git a/tests/testCommand/testOverride/pkga.nimble b/tests/testCommand/testOverride/pkga.nimble new file mode 100644 index 0000000..74bef6c --- /dev/null +++ b/tests/testCommand/testOverride/pkga.nimble @@ -0,0 +1,9 @@ +version = "0.1.0" +author = "John Doe" +description = "Nimble Test" +license = "BSD" + +skipFiles = @["myTester.nim"] + +task test, "Custom tester": + exec "nim c -r myTester.nim" \ No newline at end of file diff --git a/tests/testsFail/testing123.nim b/tests/testCommand/testsFail/testing123.nim similarity index 100% rename from tests/testsFail/testing123.nim rename to tests/testCommand/testsFail/testing123.nim diff --git a/tests/testsFail/testing123.nimble b/tests/testCommand/testsFail/testing123.nimble similarity index 100% rename from tests/testsFail/testing123.nimble rename to tests/testCommand/testsFail/testing123.nimble diff --git a/tests/testsFail/tests/a.nim b/tests/testCommand/testsFail/tests/a.nim similarity index 100% rename from tests/testsFail/tests/a.nim rename to tests/testCommand/testsFail/tests/a.nim diff --git a/tests/testsFail/tests/b.nim b/tests/testCommand/testsFail/tests/b.nim similarity index 100% rename from tests/testsFail/tests/b.nim rename to tests/testCommand/testsFail/tests/b.nim diff --git a/tests/testsFail/tests/c.nim b/tests/testCommand/testsFail/tests/c.nim similarity index 100% rename from tests/testsFail/tests/c.nim rename to tests/testCommand/testsFail/tests/c.nim diff --git a/tests/testsPass/testing123.nim b/tests/testCommand/testsPass/testing123.nim similarity index 100% rename from tests/testsPass/testing123.nim rename to tests/testCommand/testsPass/testing123.nim diff --git a/tests/testsPass/testing123.nimble b/tests/testCommand/testsPass/testing123.nimble similarity index 100% rename from tests/testsPass/testing123.nimble rename to tests/testCommand/testsPass/testing123.nimble diff --git a/tests/testsPass/tests/one.nim b/tests/testCommand/testsPass/tests/one.nim similarity index 100% rename from tests/testsPass/tests/one.nim rename to tests/testCommand/testsPass/tests/one.nim diff --git a/tests/testsPass/tests/three.nim b/tests/testCommand/testsPass/tests/three.nim similarity index 100% rename from tests/testsPass/tests/three.nim rename to tests/testCommand/testsPass/tests/three.nim diff --git a/tests/testsPass/tests/two.nim b/tests/testCommand/testsPass/tests/two.nim similarity index 100% rename from tests/testsPass/tests/two.nim rename to tests/testCommand/testsPass/tests/two.nim diff --git a/tests/tester.nim b/tests/tester.nim index aed84c2..582e5ac 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -557,22 +557,29 @@ suite "develop feature": createDir(cloneDir) cd cloneDir: let url = "https://github.com/nimble-test/packagea.git" - let (output, exitCode) = execNimble("develop", "-y", url) + let (_, exitCode) = execNimble("develop", "-y", url) check exitCode == QuitSuccess -test "Runs passing unit tests": - cd "testsPass": - let (outp, exitCode) = execNimble("test") - check: exitCode == QuitSuccess - check: outp.processOutput.inLines("First test") - check: outp.processOutput.inLines("Second test") - check: outp.processOutput.inLines("Third test") - check: outp.processOutput.inLines("Executing my func") +suite "test command": + test "Runs passing unit tests": + cd "testCommand/testsPass": + let (outp, exitCode) = execNimble("test") + check exitCode == QuitSuccess + check outp.processOutput.inLines("First test") + check outp.processOutput.inLines("Second test") + check outp.processOutput.inLines("Third test") + check outp.processOutput.inLines("Executing my func") -test "Runs failing unit tests": - cd "testsFail": - let (outp, exitCode) = execNimble("test") - check: exitCode == QuitFailure - check: outp.processOutput.inLines("First test") - check: outp.processOutput.inLines("Failing Second test") - check: not outp.processOutput.inLines("Third test") + test "Runs failing unit tests": + cd "testCommand/testsFail": + let (outp, exitCode) = execNimble("test") + check exitCode == QuitFailure + check outp.processOutput.inLines("First test") + check outp.processOutput.inLines("Failing Second test") + check(not outp.processOutput.inLines("Third test")) + + test "test command can be overriden": + cd "testCommand/testOverride": + let (outp, exitCode) = execNimble("test") + check exitCode == QuitSuccess + check outp.processOutput.inLines("overriden") \ No newline at end of file From d9b174b7dfc1471cfdbbf5aa766f86d3890fa078 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 3 Sep 2017 17:44:15 +0100 Subject: [PATCH 230/424] Work around NimScript eval problems by caching better. --- src/nimblepkg/options.nim | 1 + src/nimblepkg/packageparser.nim | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 2609254..9dce5e7 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -374,4 +374,5 @@ proc briefClone*(options: Options): Options = var newOptions = initOptions() newOptions.config = options.config newOptions.nimbleData = options.nimbleData + newOptions.pkgInfoCache = options.pkgInfoCache return newOptions \ No newline at end of file diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index d7096b5..befa513 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -268,7 +268,6 @@ proc readPackageInfo(nf: NimbleFile, options: Options, assert fileExists(nf) # Check the cache. - echo(nf, options.pkgInfoCache.hasKey(nf)) if options.pkgInfoCache.hasKey(nf): return options.pkgInfoCache[nf] From 5b82e06d0010126b698280fc6196286e3f5660b7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 3 Sep 2017 18:26:17 +0100 Subject: [PATCH 231/424] Version 0.8.8. --- changelog.markdown | 30 ++++++++++++++++++++++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index ccc4d30..9c487c6 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,36 @@ # Nimble changelog +## 0.8.8 - 03/09/2017 + +This is a relatively big release containing 57 commits, with multiple new +features and many bug fixes. + +* **Implemented the `develop` command.** See + [readme](https://github.com/nim-lang/nimble#nimble-develop) for details. +* **Implemented a default `test` task** for packages that don't define it. +* **Lowered the memory consumption** in cases where a package contained many files. +* Nimble now accepts .nimble symlinks. +* Locally stored package list files can now be specified in the Nimble config. +* Fixed branch checkout and handling of branch names with dashes. +* Improved URL detection in ``publish`` feature. +* Fixed many issues related to binary management. Packages are now resymlinked + when an newer version is removed. + ([#331](https://github.com/nim-lang/nimble/issues/331)) +* Fixed issues with CLI arg passing to the Nim compiler. + ([#351](https://github.com/nim-lang/nimble/issues/351)) +* Improved performance of ``list -i`` command. +* Fixed issue where warnings weren't suppressed for some commands. + ([#290](https://github.com/nim-lang/nimble/issues/290)) +* Special versions other than `#head` are no longer considered to be newest. +* Improves the reverse dependency lookup by cross checking it with the + installed list of packages. + ([#287](https://github.com/nim-lang/nimble/issues/287)) + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.6...v0.8.8 + ## 0.8.6 - 05/05/2017 Yet another point release which includes various bug fixes and improvements. diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 81bd0f9..609432f 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.7" + nimbleVersion* = "0.8.8" From fc81b5b58eac62ad5ae89d4e8a28b0a3f4bb8e5b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 6 Sep 2017 22:35:09 +0100 Subject: [PATCH 232/424] Update repo info docs in readme. --- readme.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.markdown b/readme.markdown index b3c73c3..31bf262 100644 --- a/readme.markdown +++ b/readme.markdown @@ -848,8 +848,7 @@ The ``stable`` branch is... Note: The travis build only tests whether Nimble works with the latest Nim version. -A new Nim release (via ``koch xz``) will always bundle the latest tagged -Nimble release. +A new Nim release (via ``koch xz``) will always bundle the ``stable`` branch. ## Contribution From 5a739b4c03a2edadf123eb669e4fadfacf9c6adc Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Fri, 8 Sep 2017 17:42:11 +0300 Subject: [PATCH 233/424] Fixes #403 --- src/nimble.nim | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 883468a..a3d0096 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -615,15 +615,23 @@ proc listPaths(options: Options) = if kind != pcDir or not path.startsWith(options.getPkgsDir / name): continue - let - nimbleFile = path / name.addFileExt("nimble") - hasSpec = nimbleFile.existsFile + var nimbleFile = path / name.addFileExt("nimble") + var nimbleLinkTargetPath: string + if not nimbleFile.existsFile: + let nimbleLinkFile = path / name.addFileExt("nimble-link") + if fileExists(nimbleLinkFile): + let lns = readFile(nimbleLinkFile).splitLines() + nimbleFile = lns[0] + nimbleLinkTargetPath = lns[1] - if hasSpec: + if nimbleFile.existsFile: var pkgInfo = getPkgInfo(path, options) var v: VersionAndPath v.version = newVersion(pkgInfo.specialVersion) - v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.specialVersion) + if nimbleLinkTargetPath.len == 0: + v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.specialVersion) + else: + v.path = nimbleLinkTargetPath installed.add(v) else: display("Warning:", "No .nimble file found for " & path, Warning, From 9068e8e43a1bc2d2f250d3ce43d408073c159095 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sat, 9 Sep 2017 23:15:08 +0300 Subject: [PATCH 234/424] Added a test --- tests/tester.nim | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/tester.nim b/tests/tester.nim index 582e5ac..51328ea 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -560,6 +560,17 @@ suite "develop feature": let (_, exitCode) = execNimble("develop", "-y", url) check exitCode == QuitSuccess + test "nimble path points to develop": + cd "develop/srcdirtest": + var (output, exitCode) = execNimble("develop") + checkpoint output + check exitCode == QuitSuccess + + (output, exitCode) = execNimble("path", "srcdirtest") + checkpoint output + check exitCode == QuitSuccess + check output.strip() == getCurrentDir() / "src" + suite "test command": test "Runs passing unit tests": cd "testCommand/testsPass": From 88b4a9ed8a4833b9830180d0d6412ae95250a86d Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Sat, 9 Sep 2017 23:33:31 +0300 Subject: [PATCH 235/424] Introduced NimbleLink object with its read/write routines --- src/nimble.nim | 10 +++++----- src/nimblepkg/packageinfo.nim | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index a3d0096..9b9de0b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -620,9 +620,9 @@ proc listPaths(options: Options) = if not nimbleFile.existsFile: let nimbleLinkFile = path / name.addFileExt("nimble-link") if fileExists(nimbleLinkFile): - let lns = readFile(nimbleLinkFile).splitLines() - nimbleFile = lns[0] - nimbleLinkTargetPath = lns[1] + let lnk = readNimbleLink(nimbleLinkFile) + nimbleFile = lnk.nimbleFilePath + nimbleLinkTargetPath = lnk.packageDir if nimbleFile.existsFile: var pkgInfo = getPkgInfo(path, options) @@ -873,9 +873,9 @@ proc developFromDir(dir: string, options: Options) = # need to be read. This will mean that users will need to re-run # `nimble develop` if they change their `srcDir` but I think it's a worthy # compromise. - let contents = pkgInfo.myPath & "\n" & pkgInfo.getRealDir() let nimbleLinkPath = pkgDestDir / pkgInfo.name.addFileExt("nimble-link") - writeFile(nimbleLinkPath, contents) + writeNimbleLink(nimbleLinkPath, + NimbleLink(nimbleFilePath: pkgInfo.myPath, packageDir: pkgInfo.getRealDir())) # Save a nimblemeta.json file. saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir), diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 85821d5..fecdae0 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -27,6 +27,10 @@ type MetaData* = object url*: string + NimbleLink* = object + nimbleFilePath*: string + packageDir*: string + proc initPackageInfo*(path: string): PackageInfo = result.myPath = path result.specialVersion = "" @@ -141,6 +145,15 @@ proc readMetaData*(path: string): MetaData = let jsonmeta = parseJson(cont) result.url = jsonmeta["url"].str +proc readNimbleLink*(nimbleLinkPath: string): NimbleLink = + let s = readFile(nimbleLinkPath).splitLines() + result.nimbleFilePath = s[0] + result.packageDir = s[1] + +proc writeNimbleLink*(nimbleLinkPath: string, contents: NimbleLink) = + let c = contents.nimbleFilePath & "\n" & contents.packageDir + writeFile(nimbleLinkPath, c) + proc needsRefresh*(options: Options): bool = ## Determines whether a ``nimble refresh`` is needed. ## @@ -298,8 +311,7 @@ proc findNimbleFile*(dir: string; error: bool): string = if result.splitFile.ext == ".nimble-link": # Return the path of the real .nimble file. - let lines = readFile(result).splitLines() - result = lines[0] + result = readNimbleLink(result).nimbleFilePath if not fileExists(result): raiseNimbleError("The .nimble-link file is pointing to a missing" & " file: " & result) From a2470470899ac31a3dbf6631f6171179aeee870d Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 20 Sep 2017 18:18:22 +0300 Subject: [PATCH 236/424] Fixed nondeterminism in version sorting --- src/nimble.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9b9de0b..0af471e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -630,9 +630,13 @@ proc listPaths(options: Options) = v.version = newVersion(pkgInfo.specialVersion) if nimbleLinkTargetPath.len == 0: v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.specialVersion) + installed.add(v) else: + # If we have a nimble-developed package, this is really the path we're + # looking for. v.path = nimbleLinkTargetPath - installed.add(v) + installed = @[v] + break else: display("Warning:", "No .nimble file found for " & path, Warning, MediumPriority) From fc6912a1391e8c9e597cfbf79c5221a804ddd024 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 30 Sep 2017 13:49:59 +0100 Subject: [PATCH 237/424] Verify that GIT hash was retrieved correctly during compilation. --- src/nimblepkg/options.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 9dce5e7..81115da 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -113,9 +113,12 @@ proc writeHelp*(quit=true) = proc writeVersion*() = echo("nimble v$# compiled at $# $#" % [nimbleVersion, CompileDate, CompileTime]) - const gitVersion = staticExec("git rev-parse HEAD") - when gitVersion.len > 0: - echo "git hash: ", gitVersion + const execResult = gorgeEx("git rev-parse HEAD") + when execResult[0].len > 0 and execResult[1] == QuitSuccess: + echo "git hash: ", execResult[0] + else: + {.warning: "Couldn't determine GIT hash: " & execResult[0].} + echo "git hash: couldn't determine git hash" raise NimbleQuit(msg: "") proc parseActionType*(action: string): ActionType = From a02a1431e2167bf2fdf59c25d7a4ed4696c6bbc4 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 30 Sep 2017 14:16:57 +0100 Subject: [PATCH 238/424] Simplify implementation of `path` for Nimble links. --- src/nimble.nim | 28 ++++++++-------------------- tests/tester.nim | 4 ++-- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 0af471e..985f1fe 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -615,28 +615,13 @@ proc listPaths(options: Options) = if kind != pcDir or not path.startsWith(options.getPkgsDir / name): continue - var nimbleFile = path / name.addFileExt("nimble") - var nimbleLinkTargetPath: string - if not nimbleFile.existsFile: - let nimbleLinkFile = path / name.addFileExt("nimble-link") - if fileExists(nimbleLinkFile): - let lnk = readNimbleLink(nimbleLinkFile) - nimbleFile = lnk.nimbleFilePath - nimbleLinkTargetPath = lnk.packageDir - + var nimbleFile = findNimbleFile(path, false) if nimbleFile.existsFile: var pkgInfo = getPkgInfo(path, options) var v: VersionAndPath v.version = newVersion(pkgInfo.specialVersion) - if nimbleLinkTargetPath.len == 0: - v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.specialVersion) - installed.add(v) - else: - # If we have a nimble-developed package, this is really the path we're - # looking for. - v.path = nimbleLinkTargetPath - installed = @[v] - break + v.path = pkgInfo.getRealDir() + installed = @[v] else: display("Warning:", "No .nimble file found for " & path, Warning, MediumPriority) @@ -878,8 +863,11 @@ proc developFromDir(dir: string, options: Options) = # `nimble develop` if they change their `srcDir` but I think it's a worthy # compromise. let nimbleLinkPath = pkgDestDir / pkgInfo.name.addFileExt("nimble-link") - writeNimbleLink(nimbleLinkPath, - NimbleLink(nimbleFilePath: pkgInfo.myPath, packageDir: pkgInfo.getRealDir())) + let nimbleLink = NimbleLink( + nimbleFilePath: pkgInfo.myPath, + packageDir: pkgInfo.getRealDir() + ) + writeNimbleLink(nimbleLinkPath, nimbleLink) # Save a nimblemeta.json file. saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir), diff --git a/tests/tester.nim b/tests/tester.nim index 51328ea..ac38812 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -15,8 +15,8 @@ const path = "../src/nimble" removeDir(installDir) createDir(installDir) -test "can compile nimble": - check execCmdEx("nim c " & path).exitCode == QuitSuccess +# Always recompile. +doAssert execCmdEx("nim c " & path).exitCode == QuitSuccess test "can compile with --os:windows": check execCmdEx("nim check --os:windows " & path).exitCode == QuitSuccess From 7164fca394151e60b60a60216f6bf56c5ba23d2e Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Wed, 4 Oct 2017 10:45:39 +0200 Subject: [PATCH 239/424] Improve the readme - Improve grammar and spelling - Capitalize Nimble - Fix the link to docs/distros.html - Switch all supporting links to HTTPS - Link to the license file directly --- readme.markdown | 85 +++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/readme.markdown b/readme.markdown index 31bf262..b479d77 100644 --- a/readme.markdown +++ b/readme.markdown @@ -1,7 +1,7 @@ # Nimble [![Build Status](https://travis-ci.org/nim-lang/nimble.svg?branch=master)](https://travis-ci.org/nim-lang/nimble) Nimble is a *beta*-grade *package manager* for the [Nim programming -language](http://nim-lang.org). +language](https://nim-lang.org). Interested in learning **how to create a package**? Skip directly to that section [here](#creating-packages). @@ -52,20 +52,20 @@ Interested in learning **how to create a package**? Skip directly to that sectio Nimble has some runtime dependencies on external tools, these tools are used to download Nimble packages. For instance, if a package is hosted on -[Github](https://github.com) you require to have [git](http://www.git-scm.com) +[GitHub](https://github.com), you need to have [git](https://www.git-scm.com) installed and added to your environment ``PATH``. Same goes for [Mercurial](http://mercurial.selenic.com) repositories on [Bitbucket](https://bitbucket.org). Nimble packages are typically hosted in Git repositories so you may be able to get away without installing Mercurial. **Warning:** Ensure that you have a fairly recent version of Git installed. -If the version is less recent than 1.9.0 then Nimble may have trouble using it. +If the version is older than 1.9.0, then Nimble may have trouble using it. See [this issue](https://github.com/nim-lang/nimble/issues/105) for more -info. +information. ## Installation -Nimble is now bundled with [Nim](http://nim-lang.org) +Nimble is now bundled with [Nim](https://nim-lang.org) (since Nim version 0.15.0). This means that you should have Nimble installed already, as long as you have the latest version of Nim installed as well. Because of this **you likely do @@ -143,9 +143,9 @@ Example: nake installed successfully Nimble always fetches and installs the latest version of a package. Note that -latest version is defined as the latest tagged version in the git (or hg) +latest version is defined as the latest tagged version in the Git (or Mercurial) repository, if the package has no tagged versions then the latest commit in the -remote repository will be installed. If you already have that version installed +remote repository will be installed. If you already have that version installed, Nimble will ask you whether you wish it to overwrite your local copy. You can force Nimble to download the latest commit from the package's repo, for @@ -153,10 +153,10 @@ example: $ nimble install nimgame@#head -This is of course git specific, for hg use ``tip`` instead of ``head``. A +This is of course Git-specific, for Mercurial, use ``tip`` instead of ``head``. A branch, tag, or commit hash may also be specified in the place of ``head``. -Instead of specifying a VCS branch you may also specify a version range, for +Instead of specifying a VCS branch, you may also specify a version range, for example: $ nimble install nimgame@"> 0.5" @@ -224,7 +224,7 @@ the command ``c`` or ``compile`` is specified. The more specific ``js``, ``cc``, The ``list`` command will display the known list of packages available for Nimble. An optional ``--ver`` parameter can be specified to tell Nimble to -query remote git repositories for the list of versions of the packages and to +query remote Git repositories for the list of versions of the packages and to then print the versions. Please note however that this can be slow as each package must be queried separately. @@ -252,8 +252,8 @@ substrings). Example: Searches are case insensitive. An optional ``--ver`` parameter can be specified to tell Nimble to -query remote git repositories for the list of versions of the packages and to -then print the versions. Please note however that this can be slow as each +query remote Git repositories for the list of versions of the packages and +then print the versions. However, please note that this can be slow as each package must be queried separately. ### nimble path @@ -287,11 +287,11 @@ Check out the [Creating Packages](#creating-packages) section for more info. Publishes your Nimble package to the official Nimble package repository. -**Note:** Requires a valid Github account. +**Note:** Requires a valid GitHub account. ### nimble tasks -For a nimble package in the current working directory, list the tasks which that +For a Nimble package in the current working directory, list the tasks which that package defines. This is only supported for packages utilising the new nimscript .nimble files. @@ -324,7 +324,7 @@ path = r"C:\Projects\Nim\packages.json" You can currently configure the following in this file: -* ``nimbleDir`` - The directory which nimble uses for package installation. +* ``nimbleDir`` - The directory which Nimble uses for package installation. **Default:** ``~/.nimble/`` * ``chcp`` - Whether to change the current code page when executing Nim application packages. If ``true`` this will add ``chcp 65001`` to the @@ -347,17 +347,17 @@ You can currently configure the following in this file: ## Creating Packages -Nimble works on git repositories as its primary source of packages. Its list of +Nimble works on Git repositories as its primary source of packages. Its list of packages is stored in a JSON file which is freely accessible in the [nim-lang/packages repository](https://github.com/nim-lang/packages). -This JSON file provides nimble with the required Git URL to clone the package +This JSON file provides Nimble with the required Git URL to clone the package and install it. Installation and build instructions are contained inside a -file with the ``.nimble`` file extension. The nimble file shares the +file with the ``.nimble`` file extension. The Nimble file shares the package's name, i.e. a package named "foobar" should have a corresponding ``foobar.nimble`` file. -These files specify information about the package including its the author, -license, dependencies and more. Without one Nimble is not able to install +These files specify information about the package including its author, +license, dependencies and more. Without one, Nimble is not able to install a package. A .nimble file can be created easily using Nimble's ``init`` command. This @@ -392,7 +392,7 @@ requires "fizzbuzz >= 1.0" ``` Nimble currently supports installation of packages from a local directory, a -git repository and a mercurial repository. The .nimble file must be present in +Git repository and a mercurial repository. The .nimble file must be present in the root of the directory or repository being installed. The .nimble file is very flexible because it is interpreted using NimScript. @@ -420,7 +420,7 @@ Hello World! You can place any Nim code inside these tasks. As long as that code does not access the FFI. The ``nimscript`` -[module](http://nim-lang.org/docs/nimscript.html) in Nim's standard library defines +[module](https://nim-lang.org/docs/nimscript.html) in Nim's standard library defines additional functionality such as the ability to execute external processes which makes this feature very powerful. @@ -457,7 +457,7 @@ which are also useful. Take a look at it for more information. A Nimble project includes a *source directory*, containing at most one primary source file, which shares the same name as the project itself (as well -as the project's nimble file). In most cases this source directory will also be +as the project's .nimble file). In most cases this source directory will also be the root directory of the whole project. In all cases, the root directory will contain the .nimble file. @@ -468,7 +468,7 @@ will have the same name as the project (see below for details). The source directory can contain additional files and directories not involved in building the project, as long as they are excluded -in the nimble file. +in the .nimble file. Here's a sample one-module project directory: @@ -477,7 +477,7 @@ Here's a sample one-module project directory: ├── LICENSE ├── README.md ├── my_project.nim # The primary source file -├── my_project.nimble # The project nimble file +├── my_project.nimble # The project .nimble file └── tests # Another source directory, excluded in my_project.nimble ├── nim.cfg └── tests.nim @@ -518,7 +518,7 @@ You can compile and run a single tester application or multiple test files. Library packages are likely the most popular form of Nimble packages. They are meant to be used by other library or binary packages. -When nimble installs a library it will copy all of its files +When Nimble installs a library, it will copy all of its files into ``$nimbleDir/pkgs/pkgname-ver``. It's up to the package creator to make sure that the package directory layout is correct, this is so that users of the package can correctly import the package. @@ -528,7 +528,7 @@ determined by the nature of your package, that is, whether your package exposes only one module or multiple modules. If your package exposes only a single module, then that module should be -present in the root directory (the directory with the .nimble file) of your git +present in the root directory (the directory with the .nimble file) of your Git repository, and should be named whatever your package's name is. A good example of this is the [jester](https://github.com/dom96/jester) package which exposes the ``jester`` module. In this case the jester package is imported with @@ -571,7 +571,7 @@ A package is automatically a binary package as soon as it sets at least one bin = @["main"] ``` -In this case when ``nimble install`` is invoked, nimble will build the ``main.nim`` +In this case when ``nimble install`` is invoked, Nimble will build the ``main.nim`` file, copy it into ``$nimbleDir/pkgs/pkgname-ver/`` and subsequently create a symlink to the binary in ``$nimbleDir/bin/``. On Windows a stub .cmd file is created instead. @@ -621,9 +621,9 @@ and less than 1.0. Specifying a concrete version as a dependency is not a good idea because your package may end up depending on two different versions of the same package. -If this happens Nimble will refuse to install the package. +If this happens, Nimble will refuse to install the package. -In addition to versions you may also specify git/hg tags, branches and commits. +In addition to versions you may also specify Git/Mercurial tags, branches and commits. Although these have to be specific; ranges of commits are not supported. This is done with the ``#`` character, for example: ``jester#head``. Which will make your package depend on the @@ -654,7 +654,7 @@ when defined(nimdistros): The ``when`` branch is important to support installation using older versions of Nimble. -The [distros module](nim-lang.org/docs/distros.html) in Nim's +The [distros module](https://nim-lang.org/docs/distros.html) in Nim's standard library contains a list of all the supported Operating Systems and Linux distributions. @@ -680,18 +680,18 @@ It resolves the dependencies and feeds the path of each package to the compiler so that it knows precisely which version to use. This means that you can safely compile using the compiler when developing your -software, but you should use nimble to build the package before publishing it +software, but you should use Nimble to build the package before publishing it to ensure that the dependencies you specified are correct. ### Versions -Versions of cloned packages via git or mercurial are determined through the +Versions of cloned packages via Git or Mercurial are determined through the repository's *tags*. When installing a package which needs to be downloaded, after the download is -complete and if the package is distributed through a VCS, nimble will check the -cloned repository's tags list. If no tags exist, nimble will simply install the -HEAD (or tip in mercurial) of the repository. If tags exist, nimble will attempt +complete and if the package is distributed through a VCS, Nimble will check the +cloned repository's tags list. If no tags exist, Nimble will simply install the +HEAD (or tip in Mercurial) of the repository. If tags exist, Nimble will attempt to look for tags which resemble versions (e.g. v0.1) and will then find the latest version out of the available tags, once it does so it will install the package after checking out the latest version. @@ -781,7 +781,7 @@ Nimble includes a ``publish`` command which does this for you automatically. root dir of the package. * ``bin`` - A list of files which should be built separated by commas with no file extension required. This option turns your package into a *binary - package*, nimble will build the files specified and install them appropriately. + package*, Nimble will build the files specified and install them appropriately. * ``backend`` - Specifies the backend which will be used to build the files listed in ``bin``. Possible values include: ``c``, ``cc``, ``cpp``, ``objc``, ``js``. @@ -813,7 +813,7 @@ work properly and you won't be able to run them. * ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]``` -Make sure that nimble is configured to run with SSL, adding a ```-d:ssl``` +Make sure that Nimble is configured to run with SSL, adding a ```-d:ssl``` flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. @@ -855,8 +855,8 @@ A new Nim release (via ``koch xz``) will always bundle the ``stable`` branch. If you would like to help, feel free to fork and make any additions you see fit and then send a pull request. -If you have any questions about the project you can ask me directly on github, -ask on the Nim [forum](http://forum.nim-lang.org), or ask on Freenode in +If you have any questions about the project, you can ask me directly on GitHub, +ask on the Nim [forum](https://forum.nim-lang.org), or ask on Freenode in the #nim channel. ## Implementation details @@ -877,7 +877,8 @@ the `.nimble-link` file. ## About -Nimble has been written by [Dominik Picheta](http://picheta.me/) with help from +Nimble has been written by [Dominik Picheta](https://picheta.me/) with help from a number of [contributors](https://github.com/nim-lang/nimble/graphs/contributors). -It is licensed under the BSD license (Look at license.txt for more info). +It is licensed under the 3-clause BSD license, see [license.txt](license.txt) +for more information. From c7b97bb206c459715fdfe5b082928d21191cd7ab Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 15 Oct 2017 15:28:29 +0100 Subject: [PATCH 240/424] Implements `check` command. --- readme.markdown | 14 +++++++++++ src/nimble.nim | 21 +++++++++++++++++ src/nimblepkg/cli.nim | 1 - src/nimblepkg/nimscriptexecutor.nim | 5 ++++ src/nimblepkg/options.nim | 12 +++++++--- src/nimblepkg/packageparser.nim | 10 ++++++++ tests/tester.nim | 36 ++++++++++++++++++++++++++++- 7 files changed, 94 insertions(+), 5 deletions(-) diff --git a/readme.markdown b/readme.markdown index b479d77..4ebadcf 100644 --- a/readme.markdown +++ b/readme.markdown @@ -129,6 +129,20 @@ a third-party package list. Package lists can be specified in Nimble's config. Take a look at the config section below to see how to do this. +### nimble check + +The ``check`` command will read your package's .nimble file. It will then +verify that the package's structure is valid. + +Example: + + $ nimble check + Error: Package 'x' has an incorrect structure. It should contain a single directory hierarchy for source files, named 'x', but file 'foobar.nim' is in a directory named 'incorrect' instead. This will be an error in the future. + Hint: If 'incorrect' contains source files for building 'x', rename it to 'x'. Otherwise, prevent its installation by adding `skipDirs = @["incorrect"]` to the .nimble file. + Failure: Validation failed + + + ### nimble install The ``install`` command will download and install a package. You need to pass diff --git a/src/nimble.nim b/src/nimble.nim index 985f1fe..f27410a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -919,6 +919,25 @@ proc test(options: Options) = display("Success:", "All tests passed", Success, HighPriority) +proc check(options: Options) = + ## Validates a package a in the current working directory. + let nimbleFile = findNimbleFile(getCurrentDir(), true) + var error: ValidationError + var pkgInfo: PackageInfo + var validationResult = false + try: + validationResult = validate(nimbleFile, options, error, pkgInfo) + except: + raiseNimbleError("Could not validate package:\n" & getCurrentExceptionMsg()) + + if validationResult: + display("Success:", pkgInfo.name & " is valid!", Success, HighPriority) + else: + display("Error:", error.msg, Error, HighPriority) + display("Hint:", error.hint, Warning, HighPriority) + display("Failure:", "Validation failed", Error, HighPriority) + quit(QuitFailure) + proc doAction(options: Options) = if options.showHelp: writeHelp() @@ -972,6 +991,8 @@ proc doAction(options: Options) = listTasks(options) of actionDevelop: develop(options) + of actionCheck: + check(options) of actionNil: assert false of actionCustom: diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 0d2a906..0bd16cc 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -82,7 +82,6 @@ proc displayLine(category, line: string, displayType: DisplayType, proc display*(category, msg: string, displayType = Message, priority = MediumPriority) = - # Don't print any Warning, Message or Success messages when suppression of # warnings is enabled. That is, unless the user asked for --verbose output. if globalCLI.suppressMessages and displayType >= Warning and diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim index 4e1e3c2..70fc165 100644 --- a/src/nimblepkg/nimscriptexecutor.nim +++ b/src/nimblepkg/nimscriptexecutor.nim @@ -8,6 +8,11 @@ import packageparser, common, packageinfo, options, nimscriptsupport, cli proc execHook*(options: Options, before: bool): bool = ## Returns whether to continue. result = true + + # For certain commands hooks should not be evaluated. + if options.action.typ in noHookActions: + return + var nimbleFile = "" try: nimbleFile = findNimbleFile(getCurrentDir(), true) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 81115da..3b2c465 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -27,11 +27,11 @@ type actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionDoc, actionCustom, actionTasks, actionDevelop + actionDoc, actionCustom, actionTasks, actionDevelop, actionCheck Action* = object case typ*: ActionType - of actionNil, actionList, actionPublish, actionTasks: nil + of actionNil, actionList, actionPublish, actionTasks, actionCheck: nil of actionRefresh: optionalURL*: string # Overrides default package list. of actionInstall, actionPath, actionUninstall, actionDevelop: @@ -60,6 +60,8 @@ Commands: develop [pkgname, ...] Clones a list of packages for development. Symlinks the cloned packages or any package in the current working directory. + check Verifies the validity of a package in the + current working directory. init [pkgname] Initializes a new Nimble project. publish Publishes a package on nim-lang/packages. The current working directory needs to be the @@ -105,6 +107,8 @@ For more information read the Github readme: https://github.com/nim-lang/nimble#readme """ +const noHookActions* = {actionCheck} + proc writeHelp*(quit=true) = echo(help) if quit: @@ -151,6 +155,8 @@ proc parseActionType*(action: string): ActionType = result = actionTasks of "develop": result = actionDevelop + of "check": + result = actionCheck else: result = actionCustom @@ -178,7 +184,7 @@ proc initAction*(options: var Options, key: string) = options.action.command = key options.action.arguments = @[] options.action.flags = newStringTable() - of actionPublish, actionList, actionTasks, + of actionPublish, actionList, actionTasks, actionCheck, actionNil: discard proc prompt*(options: Options, question: string): bool = diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index befa513..f3e10f6 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -329,6 +329,16 @@ proc readPackageInfo(nf: NimbleFile, options: Options, validateVersion(result.version) validatePackageInfo(result, options) +proc validate*(file: NimbleFile, options: Options, + error: var ValidationError, pkgInfo: var PackageInfo): bool = + try: + pkgInfo = readPackageInfo(file, options) + except ValidationError as exc: + error = exc[] + return false + + return true + proc getPkgInfoFromFile*(file: NimbleFile, options: Options): PackageInfo = ## Reads the specified .nimble file and returns its data as a PackageInfo ## object. Any validation errors are handled and displayed as warnings. diff --git a/tests/tester.nim b/tests/tester.nim index ac38812..d780f40 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -593,4 +593,38 @@ suite "test command": cd "testCommand/testOverride": let (outp, exitCode) = execNimble("test") check exitCode == QuitSuccess - check outp.processOutput.inLines("overriden") \ No newline at end of file + check outp.processOutput.inLines("overriden") + +suite "check command": + test "can succeed package": + cd "binaryPackage/v1": + let (outp, exitCode) = execNimble("check") + check exitCode == QuitSuccess + check outp.processOutput.inLines("success") + check outp.processOutput.inLines("binaryPackage is valid") + + cd "packageStructure/a": + let (outp, exitCode) = execNimble("check") + check exitCode == QuitSuccess + check outp.processOutput.inLines("success") + check outp.processOutput.inLines("a is valid") + + cd "packageStructure/b": + let (outp, exitCode) = execNimble("check") + check exitCode == QuitSuccess + check outp.processOutput.inLines("success") + check outp.processOutput.inLines("b is valid") + + cd "packageStructure/c": + let (outp, exitCode) = execNimble("check") + check exitCode == QuitSuccess + check outp.processOutput.inLines("success") + check outp.processOutput.inLines("c is valid") + + test "can fail package": + cd "packageStructure/x": + let (outp, exitCode) = execNimble("check") + check exitCode == QuitFailure + check outp.processOutput.inLines("failure") + check outp.processOutput.inLines("validation failed") + check outp.processOutput.inLines("package 'x' has an incorrect structure") \ No newline at end of file From 4992707e8b2486a886c99425bc9844d6dbc7b957 Mon Sep 17 00:00:00 2001 From: Xiao-Yong Date: Thu, 19 Oct 2017 12:58:50 -0500 Subject: [PATCH 241/424] Put "nimblepkg/nimscriptapi.nim" under nimbleDir, fix #363 (#416) * Put "nimblepkg/nimscriptapi.nim" under nimbleDir, fix #363 By default, the module will be under $HOME/.nimble/nimblecache/nimblepkg/nimscriptapi.nim and the following directory will be in the searchPaths $HOME/.nimble/nimblecache/ * Put "nimblepkg/nimscriptapi.nim" under nimbleDir, fix #363 By default, the module will be under $HOME/.nimble/nimblecache/nimblepkg/nimscriptapi.nim and the following directory will be in the searchPaths $HOME/.nimble/nimblecache/ --- src/nimblepkg/nimscriptsupport.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 7188479..c186458 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -224,11 +224,12 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = let pkgName = scriptName.splitFile.name # Ensure that "nimblepkg/nimscriptapi" is in the PATH. - # TODO: put this in a more isolated directory. - let tmpNimscriptApiPath = getTempDir() / "nimblepkg" / "nimscriptapi.nim" - createDir(tmpNimscriptApiPath.splitFile.dir) - writeFile(tmpNimscriptApiPath, nimscriptApi) - searchPaths.add(getTempDir()) + block: + let t = options.getNimbleDir / "nimblecache" + let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim" + createDir(tmpNimscriptApiPath.splitFile.dir) + writeFile(tmpNimscriptApiPath, nimscriptApi) + searchPaths.add(t) initDefines() loadConfigs(DefaultConfig) From 8ca1cc095759883d06dadf9afbdf6afa1f980001 Mon Sep 17 00:00:00 2001 From: Xiao-Yong Jin Date: Mon, 23 Oct 2017 15:51:32 -0500 Subject: [PATCH 242/424] Tests for the existence of project.nim file Matches nim's command line handling of 'nim c project' The error message also states the files being tested. --- src/nimble.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index f27410a..bea1124 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -498,12 +498,15 @@ proc build(options: Options) = buildFromDir(pkgInfo, paths, args) proc execBackend(options: Options) = - let bin = options.action.file + let + bin = options.action.file + binDotNim = bin.addFileExt("nim") if bin == "": raise newException(NimbleError, "You need to specify a file.") - if not fileExists(bin): - raise newException(NimbleError, "Specified file does not exist.") + if not (fileExists(bin) or fileExists(binDotNim)): + raise newException(NimbleError, + "Specified file, " & bin & " or " & binDotNim & ", does not exist.") var pkgInfo = getPkgInfo(getCurrentDir(), options) nimScriptHint(pkgInfo) From f85219872421b47e6b4a8bcbc7c317c9d1304e2d Mon Sep 17 00:00:00 2001 From: Daniil Yarancev <21169548+Yardanico@users.noreply.github.com> Date: Wed, 1 Nov 2017 22:07:40 +0300 Subject: [PATCH 243/424] Fix deprecated warnings (#420) * Fix deprecated warning * Fix deprecation warnings --- src/nimble.nim | 6 +++--- src/nimblepkg/packageinfo.nim | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index bea1124..da7e12e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -786,9 +786,9 @@ proc uninstall(options: Options) = if revDeps.len == 1: reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver] else: - for i in 0 .. 0: - for i in 0 .. Date: Mon, 13 Nov 2017 20:30:00 +0100 Subject: [PATCH 244/424] gitignore files produced by tests --- tests/.gitignore | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/.gitignore diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..8258bb3 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,15 @@ +/binaryPackage/v1/binaryPackage +/binaryPackage/v2/binaryPackage +/develop/dependent/src/dependent +/issue206/issue/issue206bin +/issue289/issue289 +/issue428/nimbleDir/ +/nimbleDir/ +/packageStructure/c/c +/packageStructure/y/y +/testCommand/testOverride/myTester +/testCommand/testsFail/tests/a +/testCommand/testsFail/tests/b +/testCommand/testsPass/tests/one +/testCommand/testsPass/tests/three +/testCommand/testsPass/tests/two From 4cc1d44bdd9dbcd988681a6e98fa8168f1af1055 Mon Sep 17 00:00:00 2001 From: antizealot1337 Date: Thu, 21 Dec 2017 18:11:02 -0500 Subject: [PATCH 245/424] Reuse -y to mean accept defaults for init command for #288 (#437) * Reuse -y to mean accept defaults for init command * Change cli.promptCustom to accept a ForcePrompt value and delegate prompting responsiblity to it * Add prompt for different license selection * Remove extra spaces in category in promptCustom and promptList * Fix bug that always returned MIT * Add LGPL3 to array of licenses * Change to not prompt at all for package name * Change to not prompt for author if acquired from vcs and moved before prompting for version * Reduce excess indenting * Create tools.writeContents to contain file writting functionality and use it to write the nimble file * Create package src directory and add it to the nimble file * Write an initial source file * Create directory and files needed for testing * Add package created message and change priority of nimble file creation * Rearrange args for promptCustom and add another promptCustom function that doesn't accept ForcePrompt * Add package type prompt, remove writeContents proc, rename initial test file, provide alternate initial file contents based on type, and other minor improvements --- src/nimble.nim | 167 ++++++++++++++++++++++++++++++-------- src/nimblepkg/cli.nim | 46 ++++++++--- src/nimblepkg/options.nim | 16 +++- src/nimblepkg/tools.nim | 8 +- 4 files changed, 185 insertions(+), 52 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index da7e12e..2c52d5c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -693,73 +693,168 @@ proc dump(options: Options) = proc init(options: Options) = var nimbleFile: string = "" - display("Info:", - "In order to initialise a new Nimble package, I will need to ask you\n" & - "some questions. Default values are shown in square brackets, press\n" & - "enter to use them.", priority = HighPriority) + if options.forcePrompts != forcePromptYes: + display("Info:", + "In order to initialise a new Nimble package, I will need to ask you\n" & + "some questions. Default values are shown in square brackets, press\n" & + "enter to use them.", priority = HighPriority) # Ask for package name. - if options.action.projName != "": - let pkgName = options.action.projName - nimbleFile = pkgName.changeFileExt("nimble") - else: - var pkgName = os.getCurrentDir().splitPath.tail.toValidPackageName() - pkgName = promptCustom("Package name?", pkgName) - nimbleFile = pkgName.changeFileExt("nimble") + let pkgName = + if options.action.projName != "": + options.action.projName + else: + os.getCurrentDir().splitPath.tail.toValidPackageName() + nimbleFile = pkgName.changeFileExt("nimble") validatePackageName(nimbleFile.changeFileExt("")) if existsFile(os.getCurrentDir() / nimbleFile): raise newException(NimbleError, "Nimble file already exists.") - # Ask for package version. - let pkgVersion = promptCustom("Initial version of package?", "0.1.0") - validateVersion(pkgVersion) + display("Using", "$# for new package name" % [pkgName.escape()], + priority = HighPriority) # Ask for package author - var defaultAuthor = "Anonymous" - if findExe("git") != "": - let (name, exitCode) = doCmdEx("git config --global user.name") - if exitCode == QuitSuccess and name.len > 0: - defaultAuthor = name.strip() - elif defaultAuthor == "Anonymous" and findExe("hg") != "": - let (name, exitCode) = doCmdEx("hg config ui.username") - if exitCode == QuitSuccess and name.len > 0: - defaultAuthor = name.strip() - let pkgAuthor = promptCustom("Your name?", defaultAuthor) + proc getAuthor(): string = + if findExe("git") != "": + let (name, exitCode) = doCmdEx("git config --global user.name") + if exitCode == QuitSuccess and name.len > 0: + result = name.strip() + display("Using", "$# for new package author" % [result.escape()], + priority = HighPriority) + elif findExe("hg") != "": + let (name, exitCode) = doCmdEx("hg config ui.username") + if exitCode == QuitSuccess and name.len > 0: + result = name.strip() + display("Using", "$# for new package author" % [result.escape()], + priority = HighPriority) + else: + result = promptCustom(options, "Your name?", "Anonymous") + let pkgAuthor = getAuthor() + + # Declare the src/ directory + let pkgSrcDir = "src" + display("Using", "$# for new package source directory" % [pkgSrcDir.escape()], + priority = HighPriority) + + # Determine the type of package + let pkgType = promptList(options, "Package type?", [ + "lib", + "bin", + ]) + + # Ask for package version. + let pkgVersion = promptCustom(options, "Initial version of package?", "0.1.0") + validateVersion(pkgVersion) # Ask for description - let pkgDesc = promptCustom("Package description?", "") + let pkgDesc = promptCustom(options, "Package description?", + "A new awesome nimble package") # Ask for license - # TODO: Provide selection of licenses, or select random default license. - let pkgLicense = promptCustom("Package license?", "MIT") + let pkgLicense = options.promptList("Package License?", [ + "MIT", + "BSD2", + "GPLv3", + "LGPLv3", + "Apache2", + ]) # Ask for Nim dependency let nimDepDef = getNimrodVersion() - let pkgNimDep = promptCustom("Lowest supported Nim version?", $nimDepDef) + let pkgNimDep = promptCustom(options, "Lowest supported Nim version?", + $nimDepDef) validateVersion(pkgNimDep) - var outFile: File - if open(f = outFile, filename = nimbleFile, mode = fmWrite): - outFile.writeLine """# Package + let pkgTestDir = "tests" + + # Create source directory + os.createDir(pkgSrcDir) + + display("Success:", "Source directory created successfully", Success, + MediumPriority) + + # Create initial source file + cd pkgSrcDir: + let pkgFile = pkgName.changeFileExt("nim") + try: + if pkgType == "bin": + pkgFile.writeFile "# Hello Nim!\necho \"Hello, World!\"\n" + else: + pkgFile.writeFile """# $# +# Copyright $# +# $# +""" % [pkgName, pkgAuthor, pkgDesc] + display("Success:", "Created initial source file successfully", Success, + MediumPriority) + except: + raise newException(NimbleError, "Unable to open file " & pkgFile & + " for writing: " & osErrorMsg(osLastError())) + + # Create test directory + os.createDir(pkgTestDir) + + display("Success:", "Test directory created successfully", Success, + MediumPriority) + + cd pkgTestDir: + try: + "test1.nims".writeFile("""switch("path", "$$projectDir/../$#")""" % + [pkgSrcDir]) + display("Success:", "Test config file created successfully", Success, + MediumPriority) + except: + raise newException(NimbleError, "Unable to open file " & "test1.nims" & + " for writing: " & osErrorMsg(osLastError())) + try: + "test1.nim".writeFile("doAssert(1 + 1 == 2)\n") + display("Success:", "Test file created successfully", Success, + MediumPriority) + except: + raise newException(NimbleError, "Unable to open file " & "test1.nim" & + " for writing: " & osErrorMsg(osLastError())) + + # Write the nimble file + try: + if pkgType == "lib": + nimbleFile.writeFile """# Package version = $# author = $# description = $# license = $# +srcDir = $# # Dependencies requires "nim >= $#" """ % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(), - pkgLicense.escape(), pkgNimDep] - close(outFile) - else: - raise newException(NimbleError, "Unable to open file " & nimbleFile & + pkgLicense.escape(), pkgSrcDir.escape(), pkgNimDep] + else: + nimbleFile.writeFile """# Package + +version = $# +author = $# +description = $# +license = $# +srcDir = $# +bin = @[$#] + +# Dependencies + +requires "nim >= $#" +""" % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(), + pkgLicense.escape(), pkgSrcDir.escape(), pkgName.escape(), pkgNimDep] + except: + raise newException(NimbleError, "Unable to open file " & "test1.nim" & " for writing: " & osErrorMsg(osLastError())) - display("Success:", "Nimble file created successfully", Success, HighPriority) + display("Success:", "Nimble file created successfully", Success, + MediumPriority) + + display("Success:", "Package $# created successfully" % [pkgName], Success, + HighPriority) proc uninstall(options: Options) = if options.action.packages.len == 0: diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 0bd16cc..a232940 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -146,19 +146,43 @@ proc prompt*(forcePrompts: ForcePrompt, question: string): bool = else: return false -proc promptCustom*(question, default: string): string = - if default == "": - display("Prompt:", question, Warning, HighPriority) - displayCategory("Answer:", Warning, HighPriority) - let user = stdin.readLine() - if user.len == 0: return promptCustom(question, default) - else: return user +proc promptCustom*(forcePrompts: ForcePrompt, question, default: string): string = + case forcePrompts: + of forcePromptYes: + display("Prompt:", question & " -> [forced " & default & "]", Warning, + HighPriority) + return default else: - display("Prompt:", question & " [" & default & "]", Warning, HighPriority) + if default == "": + display("Prompt:", question, Warning, HighPriority) + displayCategory("Answer:", Warning, HighPriority) + let user = stdin.readLine() + if user.len == 0: return promptCustom(forcePrompts, question, default) + else: return user + else: + display("Prompt:", question & " [" & default & "]", Warning, HighPriority) + displayCategory("Answer:", Warning, HighPriority) + let user = stdin.readLine() + if user == "": return default + else: return user + +proc promptCustom*(question, default: string): string = + return promptCustom(dontForcePrompt, question, default) + +proc promptList*(forcePrompts: ForcePrompt, question: string, args: openarray[string]): string = + case forcePrompts: + of forcePromptYes: + result = args[0] + display("Prompt:", question & " -> [forced " & result & "]", Warning, + HighPriority) + else: + display("Prompt:", question & " [" & join(args, "/") & "]", Warning, HighPriority) displayCategory("Answer:", Warning, HighPriority) - let user = stdin.readLine() - if user == "": return default - else: return user + result = stdin.readLine() + for arg in args: + if arg.cmpIgnoreCase(result) == 0: + return arg + return promptList(forcePrompts, question, args) proc setVerbosity*(level: Priority) = globalCLI.level = level diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 3b2c465..4af9f0c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -194,6 +194,20 @@ proc prompt*(options: Options, question: string): bool = ## forcePrompts has a value different than dontForcePrompt. return prompt(options.forcePrompts, question) +proc promptCustom*(options: Options, question, default: string): string = + ## Asks an interactive question and returns the result. + ## + ## The proc will return "default" without asking the user if the global + ## forcePrompts is forcePromptYes. + return promptCustom(options.forcePrompts, question, default) + +proc promptList*(options: Options, question: string, args: openarray[string]): string = + ## Asks an interactive question and returns the result. + ## + ## The proc will return one of the provided args. If not prompting the first + ## options is selected. + return promptList(options.forcePrompts, question, args) + proc renameBabelToNimble(options: Options) {.deprecated.} = let babelDir = getHomeDir() / ".babel" let nimbleDir = getHomeDir() / ".nimble" @@ -384,4 +398,4 @@ proc briefClone*(options: Options): Options = newOptions.config = options.config newOptions.nimbleData = options.nimbleData newOptions.pkgInfoCache = options.pkgInfoCache - return newOptions \ No newline at end of file + return newOptions diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 00e518c..7ed5501 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -80,10 +80,10 @@ proc changeRoot*(origRoot, newRoot, path: string): string = ## path: /home/dom/bar/blah/2/foo.txt ## Return value -> /home/test/bar/blah/2/foo.txt - ## The additional check of `path.samePaths(origRoot)` is necessary to prevent - ## a regression, where by ending the `srcDir` defintion in a nimble file in a + ## The additional check of `path.samePaths(origRoot)` is necessary to prevent + ## a regression, where by ending the `srcDir` defintion in a nimble file in a ## trailing separator would cause the `path.startsWith(origRoot)` evaluation to - ## fail because of the value of `origRoot` would be longer than `path` due to + ## fail because of the value of `origRoot` would be longer than `path` due to ## the trailing separator. This would cause this method to throw during package ## installation. if path.startsWith(origRoot) or path.samePaths(origRoot): @@ -157,4 +157,4 @@ proc getNimbleTempDir*(): string = importc: "GetCurrentProcessId".} result.add($GetCurrentProcessId()) else: - result.add($getpid()) \ No newline at end of file + result.add($getpid()) From 209fca53e71d89bdbf6ff05c25ad5a407ef06318 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Fri, 22 Dec 2017 00:15:03 +0100 Subject: [PATCH 246/424] Terminate copy iteration when hitting in-place nimbleDir (#429) * terminate copy iteration when hitting in-place nimbleDir; fixes #428 * investigate travis issue * more investigations * more investigations * fix nim version issue --- src/nimblepkg/packageinfo.nim | 4 ++-- tests/issue428/dummy.nimble | 10 ++++++++++ tests/tester.nim | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/issue428/dummy.nimble diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 929587b..0428d2a 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -510,13 +510,13 @@ proc iterInstallFiles*(realDir: string, pkgInfo: PackageInfo, for kind, file in walkDir(realDir): if kind == pcDir: let skip = pkgInfo.checkInstallDir(realDir, file) - if skip: continue + # we also have to stop recursing if we reach an in-place nimbleDir + if file == options.getNimbleDir().expandFilename(): continue iterInstallFiles(file, pkgInfo, options, action) else: let skip = pkgInfo.checkInstallFile(realDir, file) - if skip: continue action(file) diff --git a/tests/issue428/dummy.nimble b/tests/issue428/dummy.nimble new file mode 100644 index 0000000..a249eab --- /dev/null +++ b/tests/issue428/dummy.nimble @@ -0,0 +1,10 @@ +# Package + +version = "0.1.0" +author = "Author" +description = "dummy" +license = "MIT" + +# Dependencies + +requires "nim >= 0.17.0" \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index d780f40..06384e5 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -354,6 +354,13 @@ test "issue #338": cd "issue338": check execNimble("install", "-y").exitCode == QuitSuccess +test "issue #428": + cd "issue428": + # Note: Can't use execNimble because it patches nimbleDir + check execCmdEx(nimblePath & " -y --nimbleDir=./nimbleDir install").exitCode == QuitSuccess + check dirExists("nimbleDir/pkgs/dummy-0.1.0") + check(not dirExists("nimbleDir/pkgs/dummy-0.1.0/nimbleDir")) + test "can list": check execNimble("list").exitCode == QuitSuccess From e32e2cdcbeb6c344abab389750e40316d9659f43 Mon Sep 17 00:00:00 2001 From: Xiao-Yong Date: Thu, 21 Dec 2017 17:43:59 -0600 Subject: [PATCH 247/424] Initialize nimbleDir option from the environment variable NIMBLE_DIR (#417) * Initialize options from the environment variable NIMBLE_DIR * Tests for the existence of project.nim file Matches nim's command line handling of 'nim c project' The error message also states the files being tested. * Fix deprecated warnings (#420) * Fix deprecated warning * Fix deprecation warnings * Initialize options from the environment variable NIMBLE_DIR * inform user about using NIMBLE_DIR env --- src/nimblepkg/options.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 4af9f0c..b220b42 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -319,7 +319,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = proc initOptions*(): Options = result.action.typ = actionNil result.pkgInfoCache = newTable[string, PackageInfo]() - result.nimbleDir = "" + result.nimbleDir = getEnv("NIMBLE_DIR") result.verbosity = HighPriority proc parseMisc(options: var Options) = @@ -366,6 +366,11 @@ proc parseCmdLine*(): Options = if result.action.typ == actionNil and not result.showVersion: result.showHelp = true + # Inform user that we use their environment variables. + if result.getNimbleDir == getEnv("NIMBLE_DIR"): + display("Info:", "Using the 'NIMBLE_DIR' environment variable.", + priority = HighPriority) + proc getProxy*(options: Options): Proxy = ## Returns ``nil`` if no proxy is specified. var url = "" From 74856a87084b73451254555b2c20ad932cf84270 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 22 Dec 2017 11:31:33 -0500 Subject: [PATCH 248/424] Prevent reserved names on Windows from being package names. Fixes #349 --- src/nimblepkg/packageparser.nim | 28 ++++++++++++++++++++++ tests/tester.nim | 42 ++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index f3e10f6..8eb029f 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -16,6 +16,31 @@ type warnInstalled*: bool # Determines whether to show a warning for installed pkgs warnAll*: bool +const reservedNames = [ + "CON", + "PRN", + "AUX", + "NUL", + "COM1", + "COM2", + "COM3", + "COM4", + "COM5", + "COM6", + "COM7", + "COM8", + "COM9", + "LPT1", + "LPT2", + "LPT3", + "LPT4", + "LPT5", + "LPT6", + "LPT7", + "LPT8", + "LPT9", +] + proc newValidationError(msg: string, warnInstalled: bool, hint: string, warnAll: bool): ref ValidationError = result = newException(ValidationError, msg) @@ -57,6 +82,9 @@ proc validatePackageName*(name: string) = if name.endsWith("pkg"): raiseNewValidationError("\"$1\" is an invalid package name: cannot end" & " with \"pkg\"" % name, false) + if name.toUpperAscii() in reservedNames: + raiseNewValidationError( + "\"$1\" is an invalid package name: reserved name" % name, false) proc validateVersion*(ver: string) = for c in ver: diff --git a/tests/tester.nim b/tests/tester.nim index 06384e5..68f2e08 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -354,6 +354,46 @@ test "issue #338": cd "issue338": check execNimble("install", "-y").exitCode == QuitSuccess +test "issue #349": + let reservedNames = [ + "CON", + "PRN", + "AUX", + "NUL", + "COM1", + "COM2", + "COM3", + "COM4", + "COM5", + "COM6", + "COM7", + "COM8", + "COM9", + "LPT1", + "LPT2", + "LPT3", + "LPT4", + "LPT5", + "LPT6", + "LPT7", + "LPT8", + "LPT9", + ] + + proc checkName(name: string) = + let (outp, code) = execNimble("init", "-y", name) + let msg = outp.strip.splitLines() + check code == QuitFailure + check inLines(msg, + "\"$1\" is an invalid package name: reserved name" % name) + removeFile(name.changeFileExt("nimble")) + removeDir("src") + removeDir("tests") + + for reserved in reservedNames: + checkName(reserved.toUpperAscii()) + checkName(reserved.toLowerAscii()) + test "issue #428": cd "issue428": # Note: Can't use execNimble because it patches nimbleDir @@ -634,4 +674,4 @@ suite "check command": check exitCode == QuitFailure check outp.processOutput.inLines("failure") check outp.processOutput.inLines("validation failed") - check outp.processOutput.inLines("package 'x' has an incorrect structure") \ No newline at end of file + check outp.processOutput.inLines("package 'x' has an incorrect structure") From 3cc9c4b2f575d383c4d5f23938a76abee0bc950d Mon Sep 17 00:00:00 2001 From: Neelesh Chandola Date: Fri, 5 Jan 2018 18:52:57 +0530 Subject: [PATCH 249/424] Fix #446 --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2c52d5c..cd7c8c6 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -729,7 +729,7 @@ proc init(options: Options) = result = name.strip() display("Using", "$# for new package author" % [result.escape()], priority = HighPriority) - else: + if result.len == 0: result = promptCustom(options, "Your name?", "Anonymous") let pkgAuthor = getAuthor() From 4770556939a7dfd53c608926a6ccf0320dd5e77f Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Mon, 8 Jan 2018 00:37:20 -0600 Subject: [PATCH 250/424] Fix for #280 --- src/nimble.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/nimble.nim b/src/nimble.nim index cd7c8c6..a6d52ab 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -468,7 +468,17 @@ proc install(packages: seq[PkgTuple], let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth, options) try: + # Run pre-install hook in download directory now that package is downloaded + cd downloadDir: + if not execHook(options, true): + raise newException(NimbleError, "Pre-hook prevented further execution.") + result = installFromDir(downloadDir, pv.ver, options, url) + + # Run post-install hook in installed directory now that package is installed + # Standard hooks run in current directory so it won't detect this new package + cd result.pkg.myPath.parentDir(): + discard execHook(options, false) except BuildFailed: # The package failed to build. # Check if we tried building a tagged version of the package. From 182893c5290dabd2b7cf0ce2b264f39b17009e58 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 9 Jan 2018 21:56:12 +0000 Subject: [PATCH 251/424] Show better error when standard library cannot be found. --- src/nimblepkg/nimscriptsupport.nim | 18 +++++++++++++++++- src/nimblepkg/packageparser.nim | 6 ++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index c186458..50567da 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -188,7 +188,10 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = else: flags[key] = @[value] -proc getNimPrefixDir(): string = +proc isValidLibPath(lib: string): bool = + return fileExists(lib / "system.nim") + +proc getNimPrefixDir: string = let env = getEnv("NIM_LIB_PREFIX") if env != "": return env @@ -221,6 +224,19 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Ensure the compiler can find its standard library #220. compiler_options.gPrefixDir = getNimPrefixDir() + # Verify that lib path points to existing stdlib. + compiler_options.setDefaultLibpath() + if not isValidLibPath(compiler_options.libpath): + let msg = "Nimble cannot find Nim's standard library.\nLast try in:\n - $1" % + compiler_options.libpath + let hint = "Nimble does its best to find Nim's standard library, " & + "sometimes this fails. You can set the environment variable " & + "NIM_LIB_PREFIX to where Nim's `lib` directory is located as " & + "a workaround. " & + "See https://github.com/nim-lang/nimble#troubleshooting for " & + "more info." + raiseNimbleError(msg, hint) + let pkgName = scriptName.splitFile.name # Ensure that "nimblepkg/nimscriptapi" is in the PATH. diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 8eb029f..17f4464 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -329,12 +329,14 @@ proc readPackageInfo(nf: NimbleFile, options: Options, try: readPackageInfoFromNims(nf, options, result) result.isNimScript = true - except NimbleError: + except NimbleError as exc: + if exc.hint.len > 0: + raise let msg = "Could not read package info file in " & nf & ";\n" & " Reading as ini file failed with: \n" & " " & iniError.msg & ".\n" & " Evaluating as NimScript file failed with: \n" & - " " & getCurrentExceptionMsg() & "." + " " & exc.msg & "." raise newException(NimbleError, msg) # By default specialVersion is the same as version. From c271435a84ba4516f4a6a0c285ea25ccd97c2373 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 9 Jan 2018 21:57:39 +0000 Subject: [PATCH 252/424] Lower priority of messages from NimScript parser. --- src/nimblepkg/nimscriptsupport.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 50567da..e0576df 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -313,7 +313,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, if msgs.gErrorCounter > 0: raise newException(NimbleError, previousMsg) elif previousMsg.len > 0: - display("Info", previousMsg, priority = HighPriority) + display("Info", previousMsg, priority = MediumPriority) if output.normalize.startsWith("error"): raise newException(NimbleError, output) previousMsg = output From 6354132959f3018883d7b93dbd6af8bbddff5b0e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 9 Jan 2018 22:32:08 +0000 Subject: [PATCH 253/424] Implement nimLibPrefix config var and add better messages for it. --- readme.markdown | 6 +++++- src/nimblepkg/config.nim | 5 +++++ src/nimblepkg/nimscriptsupport.nim | 16 ++++++++++++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index 4ebadcf..02d3583 100644 --- a/readme.markdown +++ b/readme.markdown @@ -358,6 +358,9 @@ You can currently configure the following in this file: Nimble will also attempt to read the ``http_proxy`` and ``https_proxy`` environment variables. **Default: ""** +* ``nimLibPrefix`` - Specifies the Nim standard library prefix to help Nimble + find the Nim standard library. + **Default: ""** ## Creating Packages @@ -841,7 +844,8 @@ Make sure that you are running at least version 0.16.0 of Nim (or the latest nig Nimble cannot find the Nim standard library. This is considered a bug so please report it. As a workaround you can set the ``NIM_LIB_PREFIX`` environment variable to the directory where ``lib/system.nim`` (and other standard library -files) are found. +files) are found. Alternatively you can also configure this in Nimble's +config file. ## Repository information diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 45f8154..78e3950 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -11,6 +11,7 @@ type packageLists*: Table[string, PackageList] ## Names -> packages.json files cloneUsingHttps*: bool # Whether to replace git:// for https:// httpProxy*: Uri # Proxy for package list downloads. + nimLibPrefix*: string # Nim stdlib prefix. PackageList* = object name*: string @@ -33,6 +34,8 @@ proc initConfig(): Config = ]) result.packageLists["official"] = defaultPkgList + result.nimLibPrefix = "" + proc initPackageList(): PackageList = result.name = "" result.urls = @[] @@ -110,6 +113,8 @@ proc parseConfig*(): Config = else: currentPackageList.path = e.value else: assert false + of "nimlibprefix": + result.nimLibPrefix = e.value else: raise newException(NimbleError, "Unable to parse config file:" & " Unknown key: " & e.key) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index e0576df..f86eb69 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -191,11 +191,19 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = proc isValidLibPath(lib: string): bool = return fileExists(lib / "system.nim") -proc getNimPrefixDir: string = +proc getNimPrefixDir(options: Options): string = let env = getEnv("NIM_LIB_PREFIX") if env != "": + let msg = "Using env var NIM_LIB_PREFIX: " & env + display("Warning:", msg, Warning, HighPriority) return env + if options.config.nimLibPrefix != "": + result = options.config.nimLibPrefix + let msg = "Using Nim stdlib prefix from Nimble config file: " & result + display("Warning:", msg, Warning, HighPriority) + return + result = splitPath(findExe("nim")).head.parentDir # The above heuristic doesn't work for 'choosenim' proxies. Thankfully in # that case the `nimble` binary is beside the `nim` binary so things should @@ -222,10 +230,14 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = compiler_options.implicitImports.add("nimblepkg/nimscriptapi") # Ensure the compiler can find its standard library #220. - compiler_options.gPrefixDir = getNimPrefixDir() + compiler_options.gPrefixDir = getNimPrefixDir(options) + display("Setting", "Nim stdlib prefix to " & compiler_options.gPrefixDir, + priority=LowPriority) # Verify that lib path points to existing stdlib. compiler_options.setDefaultLibpath() + display("Setting", "Nim stdlib path to " & compiler_options.libpath, + priority=LowPriority) if not isValidLibPath(compiler_options.libpath): let msg = "Nimble cannot find Nim's standard library.\nLast try in:\n - $1" % compiler_options.libpath From 3dae26447e8bba2844b9914fd0acde478ed0d798 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 14 Jan 2018 16:01:51 +0000 Subject: [PATCH 254/424] Improve project structure docs. --- readme.markdown | 88 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/readme.markdown b/readme.markdown index 02d3583..e1c80c9 100644 --- a/readme.markdown +++ b/readme.markdown @@ -472,32 +472,62 @@ which are also useful. Take a look at it for more information. ### Project structure -A Nimble project includes a *source directory*, containing at most one -primary source file, which shares the same name as the project itself (as well -as the project's .nimble file). In most cases this source directory will also be -the root directory of the whole project. In all cases, the root directory will -contain the .nimble file. - -If the project includes additional source files, or if there is more than one -primary (exported) module, they are all included in a single directory -hierarchy within the source directory. In the case of libraries, this directory -will have the same name as the project (see below for details). - -The source directory can contain additional files and directories -not involved in building the project, as long as they are excluded -in the .nimble file. - -Here's a sample one-module project directory: +For a package named "foobar", the recommended project structure is the following: ``` -. # The root directory of the project, also the source directory +. # The root directory of the project ├── LICENSE ├── README.md -├── my_project.nim # The primary source file -├── my_project.nimble # The project .nimble file -└── tests # Another source directory, excluded in my_project.nimble +├── foobar.nimble # The project .nimble file +└── src + └── foobar.nim # Imported via `import foobar` +└── tests # Contains the tests ├── nim.cfg - └── tests.nim + ├── tfoo1.nim # First test + └── tfoo2.nim # Second test + +``` + +Note that the .nimble file needs to be in the project's root directory. This +directory structure will be created if you run ``nimble init`` inside a +``foobar`` directory. + +**Warning:** When source files are placed in a ``src`` directory, the +.nimble file must contain a ``srcDir = "src"`` directive. The ``nimble init`` +command takes care of that for you. + +When introducing more modules into your package, you should place them in a +separate directory named ``foobar`` (i.e. your package's name). For example: + +``` +. # The root directory of the project +├── ... +├── foobar.nimble # The project .nimble file +├── src +│ ├── foobar +│ │ ├── utils.nim # Imported via `import foobar/utils` +│ │ └── common.nim # Imported via `import foobar/common` +│ └── foobar.nim # Imported via `import foobar` +└── ... +``` + +#### Private modules + +You may wish to hide certain modules in your package from the users. Create a +``private`` directory for that purpose. For example: + +``` +. # The root directory of the project +├── ... +├── foobar.nimble # The project .nimble file +├── src +│ ├── foobar +│ │ ├── private +│ │ │ └── hidden.nim # Imported via `import foobar/private/hidden` +│ │ ├── utils.nim # Imported via `import foobar/utils` +│ │ └── common.nim # Imported via `import foobar/common` +│ └── foobar.nim # Imported via `import foobar` +└── ... ``` #### Tests @@ -520,15 +550,19 @@ your ``tests`` directory with the following contents: --path:"../src/" ``` -To make testing even more convenient, you may wish to define a ``test`` task -in your ``.nimble`` file. Like so: +Nimble offers a pre-defined ``test`` task which compiles and runs all files +in the ``tests`` directory beginning with 't' in their filename. + +You may wish to override this ``test`` task in your ``.nimble`` file. This +is particularly useful when you have a single test suite program. Just add +the following to your ``.nimble`` file to override the default ``test`` task. ```nim task test, "Runs the test suite": exec "nim c -r tests/tester" ``` -You can compile and run a single tester application or multiple test files. +Running ``nimble test`` will now use the ``test`` task you have defined. ### Libraries @@ -556,14 +590,14 @@ If your package exposes multiple modules then the modules should be in a from other packages which expose modules with the same names. In this case the package's modules will be imported with ``import PackageName/module``. -Here's a simple example multi-module library package called `util`: +Here's a simple example multi-module library package called `kool`: ``` . -├── util +├── kool │   ├── useful.nim │   └── also_useful.nim -└── util.nimble +└── kool.nimble ``` In regards to modules which you do **not** wish to be exposed. You should place From 5dc0404dee0f64e801761080e06d8ba5324ab29f Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Mon, 15 Jan 2018 05:17:40 -0600 Subject: [PATCH 255/424] Fix for #398 (#451) * Fix for #398 * Updated fix for #398 --- src/nimblepkg/publish.nim | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 96251d9..c597aa3 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -11,8 +11,7 @@ import tools, common, cli, config, options type Auth = object user: string - pw: string - token: string ## base64 encoding of user:pw + token: string ## Github access token http: HttpClient ## http client for doing API requests const @@ -50,8 +49,9 @@ proc requestNewToken(cfg: Config): string = sleep(3000) return token -proc getGithubAuth(cfg: Config): Auth = - result.http = newHttpClient() +proc getGithubAuth(o: Options): Auth = + let cfg = o.config + result.http = newHttpClient(proxy = getProxy(o)) # always prefer the environment variable to asking for a new one if existsEnv(ApiTokenEnvironmentVariable): result.token = getEnv(ApiTokenEnvironmentVariable) @@ -150,21 +150,9 @@ proc editJson(p: PackageInfo; url, tags, downloadMethod: string) = }) writeFile("packages.json", contents.pretty.cleanupWhitespace) -proc getPackageOriginUrl(a: Auth): string = - ## Adds 'user:pw' to the URL so that the user is not asked *again* for it. - ## We need this for 'git push'. - let (output, exitCode) = doCmdEx("git ls-remote --get-url") - result = "origin" - if exitCode == 0: - result = output.string.strip - if result.endsWith(".git"): result.setLen(result.len - 4) - if result.startsWith("https://"): - result = "https://" & a.user & ':' & a.pw & '@' & - result["https://".len .. ^1] - proc publish*(p: PackageInfo, o: Options) = ## Publishes the package p. - let auth = getGithubAuth(o.config) + let auth = getGithubAuth(o) var pkgsDir = getTempDir() / "nimble-packages-fork" if not forkExists(auth): createFork(auth) @@ -177,13 +165,17 @@ proc publish*(p: PackageInfo, o: Options) = display("Removing", "old packages fork git directory.", priority = LowPriority) removeDir(pkgsDir) - display("Cloning", "packages into: " & pkgsDir, priority = HighPriority) - doCmd("git clone git@github.com:" & auth.user & "/packages " & pkgsDir) - # Make sure to update the clone. - display("Updating", "the fork", priority = HighPriority) + createDir(pkgsDir) cd pkgsDir: + # Avoid git clone to prevent token from being stored in repo + # https://github.com/blog/1270-easier-builds-and-deployments-using-git-over-https-and-oauth + display("Copying", "packages fork into: " & pkgsDir, priority = HighPriority) + doCmd("git init") + doCmd("git pull https://github.com/" & auth.user & "/packages") + # Make sure to update the fork + display("Updating", "the fork", priority = HighPriority) doCmd("git pull https://github.com/nim-lang/packages.git master") - doCmd("git push origin master") + doCmd("git push https://" & auth.token & "@github.com/" & auth.user & "/packages master") if not dirExists(pkgsDir): raise newException(NimbleError, @@ -227,6 +219,6 @@ proc publish*(p: PackageInfo, o: Options) = doCmd("git checkout -B " & branchName) doCmd("git commit packages.json -m \"Added package " & p.name & "\"") display("Pushing", "to remote of fork.", priority = HighPriority) - doCmd("git push " & getPackageOriginUrl(auth) & " " & branchName) + doCmd("git push https://" & auth.token & "@github.com/" & auth.user & "/packages " & branchName) createPullRequest(auth, p.name, branchName) display("Success:", "Pull request successful.", Success, HighPriority) \ No newline at end of file From fd84b139bd35d77834ce144668351d7f50d109e8 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 27 Jan 2018 15:36:45 +0000 Subject: [PATCH 256/424] Fixes breaking changes in 0.18.0. --- src/nimblepkg/packageinfo.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 0428d2a..9c384ff 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -463,7 +463,7 @@ proc iterFilesWithExt(dir: string, pkgInfo: PackageInfo, if kind == pcDir: iterFilesWithExt(path, pkgInfo, action) else: - if path.splitFile.ext[1 .. ^1] in pkgInfo.installExt: + if path.splitFile.ext.substr(1) in pkgInfo.installExt: action(path) proc iterFilesInDir(dir: string, action: proc (f: string)) = From 2b9215256bade9d7846c9bcbba56e470b91b5182 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 27 Jan 2018 15:37:19 +0000 Subject: [PATCH 257/424] Show friendly error message when stdlib is outdated. --- src/nimblepkg/nimscriptsupport.nim | 45 +++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index f86eb69..0222980 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -16,7 +16,7 @@ from compiler/astalgo import strTableGet import compiler/options as compiler_options import common, version, options, packageinfo, cli -import os, strutils, strtabs, tables, times, osproc, sets +import os, strutils, strtabs, tables, times, osproc, sets, pegs when not declared(resetAllModulesHard): import compiler/modulegraphs @@ -214,6 +214,33 @@ proc getNimPrefixDir(options: Options): string = # the code responsible for this. result = "" +proc getLibVersion(lib: string): Version = + ## This is quite a hacky procedure, but there is no other way to extract + ## this out of the ``system`` module. We could evaluate it, but that would + ## cause an error if the stdlib is out of date. The purpose of this + ## proc is to give a nice error message to the user instead of a confusing + ## Nim compile error. + let systemPath = lib / "system.nim" + if not fileExists(systemPath): + raiseNimbleError("system module not found in stdlib path: " & lib) + + let systemFile = readFile(systemPath) + let majorPeg = peg"'NimMajor' @ '=' \s* {\d*}" + let minorPeg = peg"'NimMinor' @ '=' \s* {\d*}" + let patchPeg = peg"'NimPatch' @ '=' \s* {\d*}" + + var majorMatches: array[1, string] + let major = find(systemFile, majorPeg, majorMatches) + var minorMatches: array[1, string] + let minor = find(systemFile, minorPeg, minorMatches) + var patchMatches: array[1, string] + let patch = find(systemFile, patchPeg, patchMatches) + + if major != -1 and minor != -1 and patch != -1: + return newVersion(majorMatches[0] & "." & minorMatches[0] & "." & patchMatches[0]) + else: + return system.NimVersion.newVersion() + when declared(ModuleGraph): var graph: ModuleGraph @@ -249,6 +276,22 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = "more info." raiseNimbleError(msg, hint) + # Verify that the stdlib that was found isn't older than the stdlib that Nimble + # was compiled with. + let libVersion = getLibVersion(compiler_options.libpath) + if NimVersion.newVersion() > libVersion: + let msg = ("Nimble cannot use an older stdlib than the one it was compiled " & + "with.\n Stdlib in '$#' has version: $#.\n Nimble needs at least: $#.") % + [compiler_options.libpath, $libVersion, NimVersion] + let hint = "You may be running a newer version of Nimble than you intended " & + "to. Run an older version of Nimble that is compatible with " & + "the stdlib that Nimble is attempting to use or set the environment variable " & + "NIM_LIB_PREFIX to where a different stdlib's `lib` directory is located as " & + "a workaround." & + "See https://github.com/nim-lang/nimble#troubleshooting for " & + "more info." + raiseNimbleError(msg, hint) + let pkgName = scriptName.splitFile.name # Ensure that "nimblepkg/nimscriptapi" is in the PATH. From d00f59708a532a9c841361b325b2654cf36798b6 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Tue, 30 Jan 2018 17:01:31 +0200 Subject: [PATCH 258/424] Fixed nimble path --- src/nimble.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index a6d52ab..407b207 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -625,7 +625,7 @@ proc listPaths(options: Options) = var installed: seq[VersionAndPath] = @[] # There may be several, list all available ones and sort by version. for kind, path in walkDir(options.getPkgsDir): - if kind != pcDir or not path.startsWith(options.getPkgsDir / name): + if kind != pcDir or not path.startsWith(options.getPkgsDir / name & "-"): continue var nimbleFile = findNimbleFile(path, false) @@ -634,7 +634,7 @@ proc listPaths(options: Options) = var v: VersionAndPath v.version = newVersion(pkgInfo.specialVersion) v.path = pkgInfo.getRealDir() - installed = @[v] + installed.add(v) else: display("Warning:", "No .nimble file found for " & path, Warning, MediumPriority) From 383e4fd7bc0c9182d6b89b8ec2fb7c2183431dbd Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Feb 2018 19:06:42 +0000 Subject: [PATCH 259/424] Merges #450 manually with some adjustments. --- src/nimblepkg/options.nim | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index b220b42..b1591b0 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -221,11 +221,17 @@ proc renameBabelToNimble(options: Options) {.deprecated.} = removeFile(nimbleDir / "babeldata.json") proc getNimbleDir*(options: Options): string = - result = - if options.nimbleDir.len == 0: - options.config.nimbleDir - else: - options.nimbleDir + result = options.config.nimbleDir + if options.nimbleDir.len != 0: + # --nimbleDir: takes priority... + result = options.nimbleDir + else: + # ...followed by the environment variable. + let env = getEnv("NIMBLE_DIR") + if env.len != 0: + display("Warning:", "Using the environment variable: NIMBLE_DIR='" & + env & "'", Warning) + result = env return expandTilde(result) @@ -319,7 +325,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = proc initOptions*(): Options = result.action.typ = actionNil result.pkgInfoCache = newTable[string, PackageInfo]() - result.nimbleDir = getEnv("NIMBLE_DIR") + result.nimbleDir = "" result.verbosity = HighPriority proc parseMisc(options: var Options) = @@ -366,11 +372,6 @@ proc parseCmdLine*(): Options = if result.action.typ == actionNil and not result.showVersion: result.showHelp = true - # Inform user that we use their environment variables. - if result.getNimbleDir == getEnv("NIMBLE_DIR"): - display("Info:", "Using the 'NIMBLE_DIR' environment variable.", - priority = HighPriority) - proc getProxy*(options: Options): Proxy = ## Returns ``nil`` if no proxy is specified. var url = "" From 7d3f3f9127ed7f6df08b313467d444a1064d266e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Feb 2018 20:22:32 +0000 Subject: [PATCH 260/424] Fixes #445. --- src/nimblepkg/options.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index b1591b0..725b5ba 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -253,9 +253,10 @@ proc parseArgument*(key: string, result: var Options) = # Parse pkg@verRange if '@' in key: let i = find(key, '@') - let pkgTup = (key[0 .. i-1], - key[i+1 .. key.len-1].parseVersionRange()) - result.action.packages.add(pkgTup) + let (pkgName, pkgVer) = (key[0 .. i-1], key[i+1 .. key.len-1]) + if pkgVer.len == 0: + raise newException(NimbleError, "Version range expected after '@'.") + result.action.packages.add((pkgName, pkgVer.parseVersionRange())) else: result.action.packages.add((key, VersionRange(kind: verAny))) of actionRefresh: From 25ffe273f7dce4016cbb329c07d2a4b8abe93e39 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Feb 2018 22:27:14 +0000 Subject: [PATCH 261/424] Implements #421. --- src/nimble.nim | 19 ++++++----- src/nimblepkg/download.nim | 59 +++++++++++++++++++++-------------- src/nimblepkg/packageinfo.nim | 2 +- tests/tester.nim | 5 +++ 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 407b207..edb3b3d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -434,13 +434,16 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, Success, HighPriority) proc getDownloadInfo*(pv: PkgTuple, options: Options, - doPrompt: bool): (DownloadMethod, string) = + doPrompt: bool): (DownloadMethod, string, + Table[string, string]) = if pv.name.isURL: - return (checkUrlType(pv.name), pv.name) + let (url, metadata) = getUrlData(pv.name) + return (checkUrlType(url), url, metadata) else: var pkg: Package if getPackage(pv.name, options, pkg): - return (pkg.downloadMethod.getDownloadMethod(), pkg.url) + let (url, metadata) = getUrlData(pkg.url) + return (pkg.downloadMethod.getDownloadMethod(), url, metadata) else: # If package is not found give the user a chance to refresh # package.json @@ -464,9 +467,10 @@ proc install(packages: seq[PkgTuple], else: # Install each package. for pv in packages: - let (meth, url) = getDownloadInfo(pv, options, doPrompt) + let (meth, url, metadata) = getDownloadInfo(pv, options, doPrompt) + let subdir = metadata.getOrDefault("subdir") let (downloadDir, downloadVersion) = - downloadPkg(url, pv.ver, meth, options) + downloadPkg(url, pv.ver, meth, subdir, options) try: # Run pre-install hook in download directory now that package is downloaded cd downloadDir: @@ -1005,8 +1009,9 @@ proc develop(options: Options) = let hint = "Remove the directory, or run this command somewhere else." raiseNimbleError(msg, hint) - let (meth, url) = getDownloadInfo(pv, options, true) - discard downloadPkg(url, pv.ver, meth, options, downloadDir) + let (meth, url, metadata) = getDownloadInfo(pv, options, true) + let subdir = metadata.getOrDefault("subdir") + discard downloadPkg(url, pv.ver, meth, subdir, options, downloadDir) developFromDir(downloadDir, options) proc test(options: Options) = diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 216c36e..cad8d3d 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parseutils, os, osproc, strutils, tables, pegs +import parseutils, os, osproc, strutils, tables, pegs, uri import packageinfo, packageparser, version, tools, common, options, cli @@ -132,13 +132,24 @@ proc checkUrlType*(url: string): DownloadMethod = elif doCmdEx("hg identify " & url).exitCode == QuitSuccess: return DownloadMethod.hg else: - raise newException(NimbleError, "Unable to identify url.") + raise newException(NimbleError, "Unable to identify url: " & url) + +proc getUrlData*(url: string): (string, Table[string, string]) = + var uri = parseUri(url) + # TODO: use uri.parseQuery once it lands... this code is quick and dirty. + var subdir = "" + if uri.query.startsWith("subdir="): + subdir = uri.query[7 .. ^1] + + uri.query = "" + return ($uri, {"subdir": subdir}.toTable()) proc isURL*(name: string): bool = name.startsWith(peg" @'://' ") -proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, - downMethod: DownloadMethod, options: Options): Version = +proc doDownload(url: string, downloadDir: string, verRange: VersionRange, + downMethod: DownloadMethod, + options: Options): Version = ## Downloads the repository specified by ``url`` using the specified download ## method. ## @@ -159,16 +170,6 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, # Result should already be set to #head here. assert(not result.isNil) - proc verifyClone() = - ## Makes sure that the downloaded package's version satisfies the requested - ## version range. - let pkginfo = getPkgInfo(downloadDir, options) - if pkginfo.version.newVersion notin verRange: - raise newException(NimbleError, - "Downloaded package's version does not satisfy requested version " & - "range: wanted $1 got $2." % - [$verRange, $pkginfo.version]) - removeDir(downloadDir) if verRange.kind == verSpecial: # We want a specific commit/branch/tag here. @@ -197,8 +198,6 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, else: # If no commits have been tagged on the repo we just clone HEAD. doClone(downMethod, url, downloadDir) # Grab HEAD. - - verifyClone() of DownloadMethod.hg: doClone(downMethod, url, downloadDir) result = getHeadName(downMethod) @@ -210,10 +209,9 @@ proc doDownload*(url: string, downloadDir: string, verRange: VersionRange, priority = MediumPriority) doCheckout(downMethod, downloadDir, latest.tag) - verifyClone() - proc downloadPkg*(url: string, verRange: VersionRange, downMethod: DownloadMethod, + subdir: string, options: Options, downloadPath = ""): (string, Version) = ## Downloads the repository as specified by ``url`` and ``verRange`` using @@ -221,8 +219,8 @@ proc downloadPkg*(url: string, verRange: VersionRange, ## ## If `downloadPath` isn't specified a location in /tmp/ will be used. ## - ## Returns the directory where it was downloaded and the concrete version - ## which was downloaded. + ## Returns the directory where it was downloaded (subdir is appended) and + ## the concrete version which was downloaded. let downloadDir = if downloadPath == "": (getNimbleTempDir() / getDownloadDirName(url, verRange)) @@ -241,13 +239,28 @@ proc downloadPkg*(url: string, verRange: VersionRange, if modUrl.contains("github.com") and modUrl.endswith("/"): modUrl = modUrl[0 .. ^2] - display("Downloading", "$1 using $2" % [modUrl, $downMethod], - priority = HighPriority) + if subdir.len > 0: + display("Downloading", "$1 using $2 (subdir is '$3')" % + [modUrl, $downMethod, subdir], + priority = HighPriority) + else: + display("Downloading", "$1 using $2" % [modUrl, $downMethod], + priority = HighPriority) result = ( - downloadDir, + downloadDir / subdir, doDownload(modUrl, downloadDir, verRange, downMethod, options) ) + if verRange.kind != verSpecial: + ## Makes sure that the downloaded package's version satisfies the requested + ## version range. + let pkginfo = getPkgInfo(result[0], options) + if pkginfo.version.newVersion notin verRange: + raise newException(NimbleError, + "Downloaded package's version does not satisfy requested version " & + "range: wanted $1 got $2." % + [$verRange, $pkginfo.version]) + proc echoPackageVersions*(pkg: Package) = let downMethod = pkg.downloadMethod.getDownloadMethod() case downMethod diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 9c384ff..10e8bfa 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -304,7 +304,7 @@ proc findNimbleFile*(dir: string; error: bool): string = elif hits == 0: if error: raise newException(NimbleError, - "Specified directory does not contain a .nimble file.") + "Specified directory ($1) does not contain a .nimble file." % dir) else: display("Warning:", "No .nimble or .nimble-link file found for " & dir, Warning, HighPriority) diff --git a/tests/tester.nim b/tests/tester.nim index 68f2e08..c907348 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -675,3 +675,8 @@ suite "check command": check outp.processOutput.inLines("failure") check outp.processOutput.inLines("validation failed") check outp.processOutput.inLines("package 'x' has an incorrect structure") + +suite "multi": + test "can install package from git subdir": + let args = ["install", "-y", "https://github.com/nimble-test/multi?subdir=alpha"] + check execNimble(args).exitCode == QuitSuccess \ No newline at end of file From 7e3058657c4ff3ca70288595fc2a21f791c50f7c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Feb 2018 22:43:28 +0000 Subject: [PATCH 262/424] Fixes problem with subdirs and 'develop'. Documents package urls. --- readme.markdown | 16 ++++++++++++++-- src/nimble.nim | 2 +- tests/tester.nim | 5 +++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index e1c80c9..c414684 100644 --- a/readme.markdown +++ b/readme.markdown @@ -183,8 +183,17 @@ the current working directory. This can be useful for developers who are testing locally their ``.nimble`` files before submitting them to the official package list. See the [Creating Packages](#creating-packages) section for more info on this. -A URL to a repository can also be specified, Nimble will automatically detect -the type of the repository that the url points to and install it. +#### Package URLs + +A valid URL to a Git or Merurial repository can also be specified, Nimble will +automatically detect the type of the repository that the url points to and +install it. + +For repositories containing the Nimble package in a subdirectory, you can +instruct Nimble about the location of your package using the ``?subdir=`` +query parameter. For example: + + $ nimble install https://github.com/nimble-test/multi?subdir=alpha ### nimble develop @@ -206,6 +215,9 @@ current working directory. The ``jester`` package will be cloned into ``./jester`` and it will be linked to your installation directory. +Just as with the ``install`` command, a package URL may also be specified +instead of a name. + ### nimble uninstall The ``uninstall`` command will remove an installed package. Attempting to remove diff --git a/src/nimble.nim b/src/nimble.nim index edb3b3d..f51f7fd 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1012,7 +1012,7 @@ proc develop(options: Options) = let (meth, url, metadata) = getDownloadInfo(pv, options, true) let subdir = metadata.getOrDefault("subdir") discard downloadPkg(url, pv.ver, meth, subdir, options, downloadDir) - developFromDir(downloadDir, options) + developFromDir(downloadDir / subdir, options) proc test(options: Options) = ## Executes all tests. diff --git a/tests/tester.nim b/tests/tester.nim index c907348..f94ec45 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -679,4 +679,9 @@ suite "check command": suite "multi": test "can install package from git subdir": let args = ["install", "-y", "https://github.com/nimble-test/multi?subdir=alpha"] + check execNimble(args).exitCode == QuitSuccess + + test "can develop package from git subdir": + removeDir("nimble-test/multi") + let args = ["develop", "-y", "https://github.com/nimble-test/multi?subdir=beta"] check execNimble(args).exitCode == QuitSuccess \ No newline at end of file From cf1b83792d1d46f9ae299847e0a28df2bc29895d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Feb 2018 22:44:57 +0000 Subject: [PATCH 263/424] Run travis tests against 0.17.2 instead of 0.17.0. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc1bf7e..f9acefc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,16 @@ language: c install: - | - wget https://nim-lang.org/download/nim-0.17.0.tar.xz - tar -xf nim-0.17.0.tar.xz - cd nim-0.17.0 + wget https://nim-lang.org/download/nim-0.17.2.tar.xz + tar -xf nim-0.17.2.tar.xz + cd nim-0.17.2 sh build.sh cd .. before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.17.0/bin:$PATH + - export PATH=`pwd`/nim-0.17.2/bin:$PATH script: - cd tests From 6a2da5627c029460f6f714a44f5275762102fa4b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 23 Feb 2018 23:15:12 +0000 Subject: [PATCH 264/424] Version 0.8.10. --- changelog.markdown | 32 ++++++++++++++++++++++++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index 9c487c6..29c1bef 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,38 @@ # Nimble changelog +## 0.8.10 - 23/02/2018 + +The first release of 2018! Another fairly big release containing 40 commits. +This release fixes many +issues, with most being fixed by our brilliant contributors. Thanks a lot +everyone! + +One big new feature is the new support for multiple Nimble packages in a single +Git/Hg repository. You can now specify ``?subdir=`` at the end of your +repo's URL and Nimble will know to look in ```` for your package. + +* **Implemented support for multi-package repos.** See + [#421](https://github.com/nim-lang/nimble/issues/421) for the relevant issue. +* **Better error message when the user has an outdated stdlib version that confuses Nimble** +* **The validity of a Nimble package can now be checked using the new ``check`` command** +* Nimble no longer silently ignores an erroneous '@' in for example + ``nimble install compiler@``. +* Issues with the ``nimble path`` command have been fixed. +* The ``nimble publish`` command has been improved and stabilised. +* Messages for the ``NIM_LIB_PREFIX`` env var have been improved. +* ``before install`` is now called when packages are installed by their name. + See [#280](https://github.com/nim-lang/nimble/issues/280). +* Fixed issue with ``nimble init``. See [#446](https://github.com/nim-lang/nimble/issues/446). +* Nimble now rejects [reserved names on Windows](https://github.com/nim-lang/nimble/commit/74856a87084b73451254555b2c20ad932cf84270). +* The ``NIMBLE_DIR`` environment variable is now supported, in addition to the + command line flag and config setting. +* The ``init`` command has been improved significantly. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.8...v0.8.10 + ## 0.8.8 - 03/09/2017 This is a relatively big release containing 57 commits, with multiple new diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 609432f..436775e 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.8" + nimbleVersion* = "0.8.10" From 64eb27419862044fca0c8595a0bd0a522aaf083a Mon Sep 17 00:00:00 2001 From: k0pernicus Date: Mon, 26 Feb 2018 18:46:29 +0100 Subject: [PATCH 265/424] Add a new troubleshooting --- readme.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.markdown b/readme.markdown index c414684..be1ea69 100644 --- a/readme.markdown +++ b/readme.markdown @@ -881,6 +881,10 @@ flag to the file ```src/nimble.nim.cfg```. After that, you can run ```src/nimble install``` and overwrite the existing installation. +* ``Could not download: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure`` + +If you are on macOS, you need to set and export the ```DYLD_LIBRARY_PATH``` environment variable to the directory where your OpenSSL libraries are. For example, if you use OpenSSL, you have to set ```export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib``` in your ```$HOME/.bashrc``` file. + * ``Error: ambiguous identifier: 'version' --use nimscriptapi.version or system.version`` Make sure that you are running at least version 0.16.0 of Nim (or the latest nightly). From bf49330d2c4dff42c447f72a2be68daf78ff9a2f Mon Sep 17 00:00:00 2001 From: shinriyo Date: Tue, 20 Mar 2018 11:39:56 +0900 Subject: [PATCH 266/424] for a sense of unity. another is .nimble. so I modified. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index f51f7fd..dab343c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -724,7 +724,7 @@ proc init(options: Options) = validatePackageName(nimbleFile.changeFileExt("")) if existsFile(os.getCurrentDir() / nimbleFile): - raise newException(NimbleError, "Nimble file already exists.") + raise newException(NimbleError, ".nimble file already exists.") display("Using", "$# for new package name" % [pkgName.escape()], priority = HighPriority) From 21357d3fa5a104332881bbaa90854df06a4226e2 Mon Sep 17 00:00:00 2001 From: shinriyo Date: Wed, 21 Mar 2018 12:09:24 +0900 Subject: [PATCH 267/424] apply review feedback I fix. --- src/nimble.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index dab343c..43ff68c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -724,7 +724,9 @@ proc init(options: Options) = validatePackageName(nimbleFile.changeFileExt("")) if existsFile(os.getCurrentDir() / nimbleFile): - raise newException(NimbleError, ".nimble file already exists.") + let path = os.getCurrentDir() / nimbleFile + let errMsg = "Nimble file already exists: $#" % path + raise newException(NimbleError, errMsg); display("Using", "$# for new package name" % [pkgName.escape()], priority = HighPriority) From 35c12cd97296af74eab3fd0eaf49c82bffc789b7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Mar 2018 11:10:23 +0000 Subject: [PATCH 268/424] Fixes to PR. --- src/nimble.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 43ff68c..b936ad9 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -723,10 +723,10 @@ proc init(options: Options) = nimbleFile = pkgName.changeFileExt("nimble") validatePackageName(nimbleFile.changeFileExt("")) - if existsFile(os.getCurrentDir() / nimbleFile): - let path = os.getCurrentDir() / nimbleFile - let errMsg = "Nimble file already exists: $#" % path - raise newException(NimbleError, errMsg); + let nimbleFilePath = os.getCurrentDir() / nimbleFile + if existsFile(nimbleFilePath): + let errMsg = "Nimble file already exists: $#" % nimbleFilePath + raise newException(NimbleError, errMsg) display("Using", "$# for new package name" % [pkgName.escape()], priority = HighPriority) From 898d4de826c8a8b985e7d5d01e9b54fba08b55de Mon Sep 17 00:00:00 2001 From: Xiao-Yong Jin Date: Tue, 27 Mar 2018 11:46:22 -0500 Subject: [PATCH 269/424] noColor if stdout is not a tty --- src/nimblepkg/options.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 725b5ba..0836bdc 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import json, strutils, os, parseopt, strtabs, uri, tables +import json, strutils, os, parseopt, strtabs, uri, tables, terminal from httpclient import Proxy, newProxy import config, version, tools, common, cli @@ -328,6 +328,7 @@ proc initOptions*(): Options = result.pkgInfoCache = newTable[string, PackageInfo]() result.nimbleDir = "" result.verbosity = HighPriority + result.noColor = not isatty(stdout) proc parseMisc(options: var Options) = # Load nimbledata.json From 9fb0e557f2433128ccdfb0637a3796850cca5ff9 Mon Sep 17 00:00:00 2001 From: Willi Schinmeyer Date: Sat, 31 Mar 2018 20:12:07 +0200 Subject: [PATCH 270/424] document that nimble init uses the current directory --- readme.markdown | 4 ++-- src/nimblepkg/options.nim | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index be1ea69..a3fabfd 100644 --- a/readme.markdown +++ b/readme.markdown @@ -303,7 +303,7 @@ which can be useful to read the bundled documentation. Example: ### nimble init The nimble ``init`` command will start a simple wizard which will create -a quick ``.nimble`` file for your project. +a quick ``.nimble`` file for your project in the current directory. As of version 0.7.0, the ``.nimble`` file that this command creates will use the new NimScript format. @@ -391,7 +391,7 @@ a package. A .nimble file can be created easily using Nimble's ``init`` command. This command will ask you a bunch of questions about your package, then generate a -.nimble file for you. +.nimble file for you in the current directory. A bare minimum .nimble file follows: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 0836bdc..63fe5a0 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -62,7 +62,8 @@ Commands: in the current working directory. check Verifies the validity of a package in the current working directory. - init [pkgname] Initializes a new Nimble project. + init [pkgname] Initializes a new Nimble project in the + current directory. publish Publishes a package on nim-lang/packages. The current working directory needs to be the toplevel directory of the Nimble package. From b86dca4105c5e318a2c0e64f214e631e954c1423 Mon Sep 17 00:00:00 2001 From: "Ahmed T. Youssef" Date: Fri, 4 May 2018 17:53:39 +0200 Subject: [PATCH 271/424] Add link to the Pull request after nim publish (#483) * Add link to the pull requests page * Add version bump * inline PR url in the nim publish output * Small fixes on top of PR. --- src/nimblepkg/common.nim | 2 +- src/nimblepkg/publish.nim | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 436775e..a95e780 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.10" + nimbleVersion* = "0.8.11" diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index c597aa3..ce8dbe5 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -94,11 +94,13 @@ proc createFork(a: Auth) = raise newException(NimbleError, "Unable to create fork. Access token" & " might not have enough permissions.") -proc createPullRequest(a: Auth, packageName, branch: string) = +proc createPullRequest(a: Auth, packageName, branch: string): string = display("Info", "Creating PR", priority = HighPriority) - discard a.http.postContent(ReposUrl & "nim-lang/packages/pulls", + var body = a.http.postContent(ReposUrl & "nim-lang/packages/pulls", body="""{"title": "Add package $1", "head": "$2:$3", "base": "master"}""" % [packageName, a.user, branch]) + var pr = parseJson(body) + return pr{"html_url"}.getStr() proc `%`(s: openArray[string]): JsonNode = result = newJArray() @@ -220,5 +222,5 @@ proc publish*(p: PackageInfo, o: Options) = doCmd("git commit packages.json -m \"Added package " & p.name & "\"") display("Pushing", "to remote of fork.", priority = HighPriority) doCmd("git push https://" & auth.token & "@github.com/" & auth.user & "/packages " & branchName) - createPullRequest(auth, p.name, branchName) - display("Success:", "Pull request successful.", Success, HighPriority) \ No newline at end of file + let prUrl = createPullRequest(auth, p.name, branchName) + display("Success:", "Pull request successful, check at " & prUrl , Success, HighPriority) From e2869714b8bdc7af8f7be581f481fe2914c25a2a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 13 May 2018 20:07:27 +0200 Subject: [PATCH 272/424] prepare Nimble for the upcoming compiler API changes (#488) * prepare Nimble for the upcoming compiler API changes * attempt to make tests green --- src/nimblepkg/nimscriptsupport.nim | 222 +++++++++++++++++++++-------- 1 file changed, 162 insertions(+), 60 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 0222980..6f55881 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -9,7 +9,7 @@ import compiler/condsyms, compiler/sem, compiler/semdata, compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, compiler/msgs, compiler/magicsys, compiler/idents, - compiler/nimconf + compiler/nimconf, compiler/nversion from compiler/scriptconfig import setupVM from compiler/astalgo import strTableGet @@ -75,13 +75,14 @@ proc extractRequires(ident: PSym, result: var seq[PkgTuple]) = when declared(newIdentCache): var identCache = newIdentCache() -proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = +proc setupVM(graph: ModuleGraph; module: PSym; scriptName: string, flags: Flags): PEvalContext = ## This procedure is exported in the compiler sources, but its implementation ## is too Nim-specific to be used by Nimble. ## Specifically, the implementation of ``switch`` is problematic. Sooo ## I simply copied it here and edited it :) - - when declared(newIdentCache): + when declared(NimCompilerApiVersion): + result = newCtx(module, identCache, graph) + elif declared(newIdentCache): result = newCtx(module, identCache) else: result = newCtx(module) @@ -89,6 +90,7 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = registerAdditionalOps(result) # captured vars: + let conf = graph.config var errorMsg: string var vthisDir = scriptName.splitFile.dir @@ -152,13 +154,25 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = cbconf thisDir: setResult(a, vthisDir) cbconf put: - compiler_options.setConfigVar(getString(a, 0), getString(a, 1)) + when declared(NimCompilerApiVersion): + compiler_options.setConfigVar(conf, getString(a, 0), getString(a, 1)) + else: + compiler_options.setConfigVar(getString(a, 0), getString(a, 1)) cbconf get: - setResult(a, compiler_options.getConfigVar(a.getString 0)) + when declared(NimCompilerApiVersion): + setResult(a, compiler_options.getConfigVar(conf, a.getString 0)) + else: + setResult(a, compiler_options.getConfigVar(a.getString 0)) cbconf exists: - setResult(a, compiler_options.existsConfigVar(a.getString 0)) + when declared(NimCompilerApiVersion): + setResult(a, compiler_options.existsConfigVar(conf, a.getString 0)) + else: + setResult(a, compiler_options.existsConfigVar(a.getString 0)) cbconf nimcacheDir: - setResult(a, compiler_options.getNimcacheDir()) + when declared(NimCompilerApiVersion): + setResult(a, compiler_options.getNimcacheDir(conf)) + else: + setResult(a, compiler_options.getNimcacheDir()) cbconf paramStr: setResult(a, os.paramStr(int a.getInt 0)) cbconf paramCount: @@ -168,16 +182,29 @@ proc setupVM(module: PSym; scriptName: string, flags: Flags): PEvalContext = cbconf cmpIgnoreCase: setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) cbconf setCommand: - compiler_options.command = a.getString 0 - let arg = a.getString 1 - if arg.len > 0: - gProjectName = arg - try: - gProjectFull = canonicalizePath(gProjectPath / gProjectName) - except OSError: - gProjectFull = gProjectName + when declared(NimCompilerApiVersion): + conf.command = a.getString 0 + let arg = a.getString 1 + if arg.len > 0: + conf.projectName = arg + try: + conf.projectFull = canonicalizePath(conf, conf.projectPath / conf.projectName) + except OSError: + conf.projectFull = conf.projectName + else: + compiler_options.command = a.getString 0 + let arg = a.getString 1 + if arg.len > 0: + gProjectName = arg + try: + gProjectFull = canonicalizePath(gProjectPath / gProjectName) + except OSError: + gProjectFull = gProjectName cbconf getCommand: - setResult(a, compiler_options.command) + when declared(NimCompilerApiVersion): + setResult(a, conf.command) + else: + setResult(a, compiler_options.command) cbconf switch: if not flags.isNil: let @@ -248,7 +275,13 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = ## Executes the specified script. Returns the script's module symbol. ## ## No clean up is performed and must be done manually! - when declared(resetAllModulesHard): + graph = newModuleGraph() + + let conf = graph.config + when declared(NimCompilerApiVersion): + if "nimblepkg/nimscriptapi" notin conf.implicitImports: + conf.implicitImports.add("nimblepkg/nimscriptapi") + elif declared(resetAllModulesHard): # for compatibility with older Nim versions: if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes: compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi") @@ -257,17 +290,30 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = compiler_options.implicitImports.add("nimblepkg/nimscriptapi") # Ensure the compiler can find its standard library #220. - compiler_options.gPrefixDir = getNimPrefixDir(options) - display("Setting", "Nim stdlib prefix to " & compiler_options.gPrefixDir, - priority=LowPriority) + when declared(NimCompilerApiVersion): + conf.prefixDir = getNimPrefixDir(options) + display("Setting", "Nim stdlib prefix to " & conf.prefixDir, + priority=LowPriority) - # Verify that lib path points to existing stdlib. - compiler_options.setDefaultLibpath() - display("Setting", "Nim stdlib path to " & compiler_options.libpath, + template myLibPath(): untyped = conf.libpath + + # Verify that lib path points to existing stdlib. + setDefaultLibpath(conf) + else: + compiler_options.gPrefixDir = getNimPrefixDir(options) + display("Setting", "Nim stdlib prefix to " & compiler_options.gPrefixDir, + priority=LowPriority) + + template myLibPath(): untyped = compiler_options.libpath + + # Verify that lib path points to existing stdlib. + compiler_options.setDefaultLibpath() + + display("Setting", "Nim stdlib path to " & myLibPath(), priority=LowPriority) - if not isValidLibPath(compiler_options.libpath): + if not isValidLibPath(myLibPath()): let msg = "Nimble cannot find Nim's standard library.\nLast try in:\n - $1" % - compiler_options.libpath + myLibPath() let hint = "Nimble does its best to find Nim's standard library, " & "sometimes this fails. You can set the environment variable " & "NIM_LIB_PREFIX to where Nim's `lib` directory is located as " & @@ -278,11 +324,11 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Verify that the stdlib that was found isn't older than the stdlib that Nimble # was compiled with. - let libVersion = getLibVersion(compiler_options.libpath) + let libVersion = getLibVersion(myLibPath()) if NimVersion.newVersion() > libVersion: let msg = ("Nimble cannot use an older stdlib than the one it was compiled " & "with.\n Stdlib in '$#' has version: $#.\n Nimble needs at least: $#.") % - [compiler_options.libpath, $libVersion, NimVersion] + [myLibPath(), $libVersion, NimVersion] let hint = "You may be running a newer version of Nimble than you intended " & "to. Run an older version of Nimble that is compatible with " & "the stdlib that Nimble is attempting to use or set the environment variable " & @@ -300,29 +346,45 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim" createDir(tmpNimscriptApiPath.splitFile.dir) writeFile(tmpNimscriptApiPath, nimscriptApi) - searchPaths.add(t) + when declared(NimCompilerApiVersion): + conf.searchPaths.add(t) + else: + searchPaths.add(t) - initDefines() - loadConfigs(DefaultConfig) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule + when declared(NimCompilerApiVersion): + initDefines(conf.symbols) + loadConfigs(DefaultConfig, conf) + passes.gIncludeFile = includeModule + passes.gImportModule = importModule - defineSymbol("nimscript") - defineSymbol("nimconfig") - defineSymbol("nimble") - registerPass(semPass) - registerPass(evalPass) + defineSymbol(conf.symbols, "nimscript") + defineSymbol(conf.symbols, "nimconfig") + defineSymbol(conf.symbols, "nimble") + registerPass(semPass) + registerPass(evalPass) - searchPaths.add(compiler_options.libpath) + conf.searchPaths.add(conf.libpath) + else: + initDefines() + loadConfigs(DefaultConfig) + passes.gIncludeFile = includeModule + passes.gImportModule = importModule + + defineSymbol("nimscript") + defineSymbol("nimconfig") + defineSymbol("nimble") + registerPass(semPass) + registerPass(evalPass) + + searchPaths.add(compiler_options.libpath) when declared(resetAllModulesHard): result = makeModule(scriptName) else: - graph = newModuleGraph() result = graph.makeModule(scriptName) incl(result.flags, sfMainModule) - vm.globalCtx = setupVM(result, scriptName, flags) + vm.globalCtx = setupVM(graph, result, scriptName, flags) # Setup builtins defined in nimscriptapi.nim template cbApi(name, body) {.dirty.} = @@ -342,17 +404,30 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = proc cleanup() = # ensure everything can be called again: - compiler_options.gProjectName = "" - compiler_options.command = "" - when declared(resetAllModulesHard): + when declared(NimCompilerApiVersion): + let conf = graph.config + conf.projectName = "" + conf.command = "" + else: + compiler_options.gProjectName = "" + compiler_options.command = "" + when declared(NimCompilerApiVersion): + resetSystemArtifacts(graph) + elif declared(resetAllModulesHard): resetAllModulesHard() else: resetSystemArtifacts() clearPasses() - msgs.gErrorMax = 1 - msgs.writeLnHook = nil - vm.globalCtx = nil - initDefines() + when declared(NimCompilerApiVersion): + conf.errorMax = 1 + msgs.writeLnHook = nil + vm.globalCtx = nil + initDefines(conf.symbols) + else: + msgs.gErrorMax = 1 + msgs.writeLnHook = nil + vm.globalCtx = nil + initDefines() proc readPackageInfoFromNims*(scriptName: string, options: Options, result: var PackageInfo) = @@ -360,12 +435,21 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, ## that it populates. # Setup custom error handling. - msgs.gErrorMax = high(int) + when declared(NimCompilerApiVersion): + let conf = graph.config + conf.errorMax = high(int) + else: + msgs.gErrorMax = high(int) + + template errCounter(): int = + when declared(NimCompilerApiVersion): conf.errorCounter + else: msgs.gErrorCounter + var previousMsg = "" msgs.writeLnHook = proc (output: string) = # The error counter is incremented after the writeLnHook is invoked. - if msgs.gErrorCounter > 0: + if errCounter() > 0: raise newException(NimbleError, previousMsg) elif previousMsg.len > 0: display("Info", previousMsg, priority = MediumPriority) @@ -373,7 +457,10 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, raise newException(NimbleError, output) previousMsg = output - compiler_options.command = internalCmd + when declared(NimCompilerApiVersion): + conf.command = internalCmd + else: + compiler_options.command = internalCmd # Execute the nimscript file. let thisModule = execScript(scriptName, nil, options) @@ -390,7 +477,7 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, doAssert apiModule != nil # Check whether an error has occurred. - if msgs.gErrorCounter > 0: + if errCounter() > 0: raise newException(NimbleError, previousMsg) # Extract all the necessary fields populated by the nimscript file. @@ -448,6 +535,13 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, cleanup() +when declared(NimCompilerApiVersion): + template nimCommand(): untyped = conf.command + template nimProjectName(): untyped = conf.projectName +else: + template nimCommand(): untyped = compiler_options.command + template nimProjectName(): untyped = compiler_options.gProjectName + proc execTask*(scriptName, taskName: string, options: Options): ExecutionResult[void] = ## Executes the specified task in the specified script. @@ -455,7 +549,9 @@ proc execTask*(scriptName, taskName: string, ## `scriptName` should be a filename pointing to the nimscript file. result.success = true result.flags = newTable[string, seq[string]]() - compiler_options.command = internalCmd + when declared(NimCompilerApiVersion): + let conf = graph.config + nimCommand() = internalCmd display("Executing", "task $# in $#" % [taskName, scriptName], priority = HighPriority) @@ -468,9 +564,9 @@ proc execTask*(scriptName, taskName: string, discard vm.globalCtx.execProc(prc, []) # Read the command, arguments and flags set by the executed task. - result.command = compiler_options.command + result.command = nimCommand() result.arguments = @[] - for arg in compiler_options.gProjectName.split(): + for arg in nimProjectName().split(): result.arguments.add(arg) cleanup() @@ -481,9 +577,11 @@ proc execHook*(scriptName, actionName: string, before: bool, ## the "before" or the "after" hook. ## ## `scriptName` should be a filename pointing to the nimscript file. + when declared(NimCompilerApiVersion): + let conf = graph.config result.success = true result.flags = newTable[string, seq[string]]() - compiler_options.command = internalCmd + nimCommand() = internalCmd let hookName = if before: actionName.toLowerAscii & "Before" else: actionName.toLowerAscii & "After" @@ -505,18 +603,22 @@ proc execHook*(scriptName, actionName: string, before: bool, else: assert false # Read the command, arguments and flags set by the executed task. - result.command = compiler_options.command + result.command = nimCommand() result.arguments = @[] - for arg in compiler_options.gProjectName.split(): + for arg in nimProjectName().split(): result.arguments.add(arg) cleanup() proc getNimScriptCommand(): string = - compiler_options.command + when declared(NimCompilerApiVersion): + let conf = graph.config + nimCommand() proc setNimScriptCommand(command: string) = - compiler_options.command = command + when declared(NimCompilerApiVersion): + let conf = graph.config + nimCommand() = command proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = ## Determines whether the last executed task used ``setCommand`` From 02945e57b5abf0ff303d5d722f1fba4006717d21 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 14 May 2018 12:35:30 +0200 Subject: [PATCH 273/424] prepare Nimble for the upcoming compiler API (#489) * prepare Nimble for the upcoming compiler API changes * attempt to make tests green * make some tests green with the upcoming compiler API --- src/nimblepkg/nimscriptsupport.nim | 2 +- src/nimblepkg/version.nim | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 6f55881..07a3eaa 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -269,7 +269,7 @@ proc getLibVersion(lib: string): Version = return system.NimVersion.newVersion() when declared(ModuleGraph): - var graph: ModuleGraph + var graph = newModuleGraph() proc execScript(scriptName: string, flags: Flags, options: Options): PSym = ## Executes the specified script. Returns the script's module symbol. diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 7fa7a73..e19e45b 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -166,7 +166,7 @@ proc parseVersionRange*(s: string): VersionRange = var i = 0 var op = "" var version = "" - while true: + while i < s.len: case s[i] of '>', '<', '=': op.add(s[i]) @@ -189,10 +189,6 @@ proc parseVersionRange*(s: string): VersionRange = of '0'..'9', '.': version.add(s[i]) - of '\0': - result = makeRange(version, op) - break - of ' ': # Make sure '0.9 8.03' is not allowed. if version != "" and i < s.len: @@ -204,6 +200,7 @@ proc parseVersionRange*(s: string): VersionRange = raise newException(ParseVersionError, "Unexpected char in version range '" & s & "': " & s[i]) inc(i) + result = makeRange(version, op) proc toVersionRange*(ver: Version): VersionRange = ## Converts a version to either a verEq or verSpecial VersionRange. From 12b5a9a4d1448dca6ee5b8aa9ab59d336d1fd2c9 Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 17 May 2018 00:22:40 +0200 Subject: [PATCH 274/424] fixes #491 --- src/nimblepkg/nimscriptsupport.nim | 2 +- tests/tester.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 07a3eaa..804f540 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -275,7 +275,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = ## Executes the specified script. Returns the script's module symbol. ## ## No clean up is performed and must be done manually! - graph = newModuleGraph() + graph = newModuleGraph(graph.config) let conf = graph.config when declared(NimCompilerApiVersion): diff --git a/tests/tester.nim b/tests/tester.nim index f94ec45..acd6bdc 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -34,7 +34,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = var quotedArgs = @args quotedArgs.insert(nimblePath) quotedArgs.add("--nimbleDir:" & installDir) - quotedArgs = quoted_args.map((x: string) => ("\"" & x & "\"")) + quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\"")) result = execCmdEx(quotedArgs.join(" ")) checkpoint(result.output) From 364f7bc260097a0cdd705b7cb81066a1ba103f0f Mon Sep 17 00:00:00 2001 From: Aearnus Date: Sun, 20 May 2018 22:45:43 -0700 Subject: [PATCH 275/424] Added SSH key note --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index a3fabfd..b09372d 100644 --- a/readme.markdown +++ b/readme.markdown @@ -313,7 +313,7 @@ Check out the [Creating Packages](#creating-packages) section for more info. Publishes your Nimble package to the official Nimble package repository. -**Note:** Requires a valid GitHub account. +**Note:** Requires a valid GitHub account with an SSH key attached to it. To upload your public key onto your GitHub account, follow [this link](https://github.com/settings/keys). ### nimble tasks From 5fcd7e5965631f91adee4fde0148ec0ed820beb0 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 31 May 2018 14:59:35 +0300 Subject: [PATCH 276/424] Fixed getPkgDir --- src/nimblepkg/nimscriptsupport.nim | 2 +- tests/nimscript/nimscript.nimble | 2 +- tests/tester.nim | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 804f540..c959dc2 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -388,7 +388,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Setup builtins defined in nimscriptapi.nim template cbApi(name, body) {.dirty.} = - vm.globalCtx.registerCallback pkgName & "." & astToStr(name), + vm.globalCtx.registerCallback "nimscriptapi." & astToStr(name), proc (a: VmArgs) = body diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index d1adfba..5842afd 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -27,7 +27,7 @@ task repeated, "Testing `nimble c nimscript.nim` with repeated flags": setCommand "c", "nimscript.nim" task api, "Testing nimscriptapi module functionality": - echo(getPkgDir()) + echo("PKG_DIR: ", getPkgDir()) before hooks: echo("First") diff --git a/tests/tester.nim b/tests/tester.nim index acd6bdc..2651d50 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -294,6 +294,13 @@ test "pre hook can prevent action": check(not inLines(lines, "Shouldn't happen")) check inLines(lines, "Hook prevented further execution") +test "nimble script api": + cd "nimscript": + let (output, exitCode) = execNimble("api") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check inLines(lines, "PKG_DIR: " & getCurrentDir()) + test "can install packagebin2": let args = ["install", "-y", "https://github.com/nimble-test/packagebin2.git"] check execNimble(args).exitCode == QuitSuccess From 3b177e278b8d2f77b87c3ec7b09377708c3ab722 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sun, 10 Jun 2018 14:50:40 +0200 Subject: [PATCH 277/424] Make Nimble compatible with the upcoming compiler API changes (#500) * Make Nimble compatible with the upcoming compiler API changes * make travis use nim-0.18.0 * make Nimble compile with older compiler versions * attempt to make tests green with Nim v0.18 --- .travis.yml | 8 +- src/nimblepkg/nimscriptsupport.nim | 146 ++++++++++++++++++++--------- src/nimblepkg/tools.nim | 2 +- 3 files changed, 107 insertions(+), 49 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9acefc..24b9744 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,16 +6,16 @@ language: c install: - | - wget https://nim-lang.org/download/nim-0.17.2.tar.xz - tar -xf nim-0.17.2.tar.xz - cd nim-0.17.2 + wget https://nim-lang.org/download/nim-0.18.0.tar.xz + tar -xf nim-0.18.0.tar.xz + cd nim-0.18.0 sh build.sh cd .. before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.17.2/bin:$PATH + - export PATH=`pwd`/nim-0.18.0/bin:$PATH script: - cd tests diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index c959dc2..4d2f412 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -40,15 +40,26 @@ proc raiseVariableError(ident, typ: string) {.noinline.} = proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit} -proc getGlobal(ident: PSym): string = - let n = vm.globalCtx.getGlobalValue(ident) +when declared(NimCompilerApiVersion): + const finalApi = NimCompilerApiVersion >= 2 +else: + const finalApi = false + +proc getGlobal(g: ModuleGraph; ident: PSym): string = + when finalApi: + let n = vm.getGlobalValue(PCtx g.vm, ident) + else: + let n = vm.globalCtx.getGlobalValue(ident) if n.isStrLit: result = if n.strVal.isNil: "" else: n.strVal else: raiseVariableError(ident.name.s, "string") -proc getGlobalAsSeq(ident: PSym): seq[string] = - let n = vm.globalCtx.getGlobalValue(ident) +proc getGlobalAsSeq(g: ModuleGraph; ident: PSym): seq[string] = + when finalApi: + let n = vm.getGlobalValue(PCtx g.vm, ident) + else: + let n = vm.globalCtx.getGlobalValue(ident) result = @[] if n.kind == nkBracket: for x in n: @@ -59,8 +70,11 @@ proc getGlobalAsSeq(ident: PSym): seq[string] = else: raiseVariableError(ident.name.s, "seq[string]") -proc extractRequires(ident: PSym, result: var seq[PkgTuple]) = - let n = vm.globalCtx.getGlobalValue(ident) +proc extractRequires(g: ModuleGraph; ident: PSym, result: var seq[PkgTuple]) = + when finalApi: + let n = vm.getGlobalValue(PCtx g.vm, ident) + else: + let n = vm.globalCtx.getGlobalValue(ident) if n.kind == nkBracket: for x in n: if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit: @@ -268,14 +282,20 @@ proc getLibVersion(lib: string): Version = else: return system.NimVersion.newVersion() -when declared(ModuleGraph): +when finalApi: + var graph = newModuleGraph(identCache, newConfigRef()) + +elif declared(ModuleGraph): var graph = newModuleGraph() proc execScript(scriptName: string, flags: Flags, options: Options): PSym = ## Executes the specified script. Returns the script's module symbol. ## ## No clean up is performed and must be done manually! - graph = newModuleGraph(graph.config) + when finalApi: + graph = newModuleGraph(graph.cache, graph.config) + else: + graph = newModuleGraph(graph.config) let conf = graph.config when declared(NimCompilerApiVersion): @@ -353,15 +373,22 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = when declared(NimCompilerApiVersion): initDefines(conf.symbols) - loadConfigs(DefaultConfig, conf) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule + when NimCompilerApiVersion >= 2: + loadConfigs(DefaultConfig, graph.cache, conf) + else: + loadConfigs(DefaultConfig, conf) + passes.gIncludeFile = includeModule + passes.gImportModule = importModule defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimconfig") defineSymbol(conf.symbols, "nimble") - registerPass(semPass) - registerPass(evalPass) + when NimCompilerApiVersion >= 2: + registerPass(graph, semPass) + registerPass(graph, evalPass) + else: + registerPass(semPass) + registerPass(evalPass) conf.searchPaths.add(conf.libpath) else: @@ -384,18 +411,31 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = result = graph.makeModule(scriptName) incl(result.flags, sfMainModule) - vm.globalCtx = setupVM(graph, result, scriptName, flags) + when finalApi: + graph.vm = setupVM(graph, result, scriptName, flags) - # Setup builtins defined in nimscriptapi.nim - template cbApi(name, body) {.dirty.} = - vm.globalCtx.registerCallback "nimscriptapi." & astToStr(name), - proc (a: VmArgs) = - body + # Setup builtins defined in nimscriptapi.nim + template cbApi(name, body) {.dirty.} = + PCtx(graph.vm).registerCallback "nimscriptapi." & astToStr(name), + proc (a: VmArgs) = + body + + else: + vm.globalCtx = setupVM(graph, result, scriptName, flags) + + # Setup builtins defined in nimscriptapi.nim + template cbApi(name, body) {.dirty.} = + vm.globalCtx.registerCallback "nimscriptapi." & astToStr(name), + proc (a: VmArgs) = + body cbApi getPkgDir: setResult(a, scriptName.splitFile.dir) - when declared(newIdentCache): + when finalApi: + graph.compileSystemModule() + graph.processModule(result, llStreamOpen(scriptName, fmRead)) + elif declared(newIdentCache): graph.compileSystemModule(identCache) graph.processModule(result, llStreamOpen(scriptName, fmRead), nil, identCache) else: @@ -417,11 +457,18 @@ proc cleanup() = resetAllModulesHard() else: resetSystemArtifacts() - clearPasses() + when finalApi: + clearPasses(graph) + else: + clearPasses() when declared(NimCompilerApiVersion): conf.errorMax = 1 - msgs.writeLnHook = nil - vm.globalCtx = nil + when NimCompilerApiVersion >= 2: + conf.writeLnHook = nil + graph.vm = nil + else: + msgs.writeLnHook = nil + vm.globalCtx = nil initDefines(conf.symbols) else: msgs.gErrorMax = 1 @@ -446,16 +493,21 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, else: msgs.gErrorCounter var previousMsg = "" - msgs.writeLnHook = - proc (output: string) = - # The error counter is incremented after the writeLnHook is invoked. - if errCounter() > 0: - raise newException(NimbleError, previousMsg) - elif previousMsg.len > 0: - display("Info", previousMsg, priority = MediumPriority) - if output.normalize.startsWith("error"): - raise newException(NimbleError, output) - previousMsg = output + + proc writelnHook(output: string) = + # The error counter is incremented after the writeLnHook is invoked. + if errCounter() > 0: + raise newException(NimbleError, previousMsg) + elif previousMsg.len > 0: + display("Info", previousMsg, priority = MediumPriority) + if output.normalize.startsWith("error"): + raise newException(NimbleError, output) + previousMsg = output + + when finalApi: + conf.writelnHook = writelnHook + else: + msgs.writeLnHook = writelnHook when declared(NimCompilerApiVersion): conf.command = internalCmd @@ -482,18 +534,18 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, # Extract all the necessary fields populated by the nimscript file. proc getSym(apiModule: PSym, ident: string): PSym = - result = apiModule.tab.strTableGet(getIdent(ident)) + result = apiModule.tab.strTableGet(getIdent(identCache, ident)) if result.isNil: raise newException(NimbleError, "Ident not found: " & ident) template trivialField(field) = - result.field = getGlobal(getSym(apiModule, astToStr field)) + result.field = getGlobal(graph, getSym(apiModule, astToStr field)) template trivialFieldSeq(field) = - result.field.add getGlobalAsSeq(getSym(apiModule, astToStr field)) + result.field.add getGlobalAsSeq(graph, getSym(apiModule, astToStr field)) # keep reasonable default: - let name = getGlobal(apiModule.tab.strTableGet(getIdent"packageName")) + let name = getGlobal(graph, apiModule.tab.strTableGet(getIdent(identCache, "packageName"))) if name.len > 0: result.name = name trivialField version @@ -510,13 +562,13 @@ proc readPackageInfoFromNims*(scriptName: string, options: Options, trivialFieldSeq installExt trivialFieldSeq foreignDeps - extractRequires(getSym(apiModule, "requiresData"), result.requires) + extractRequires(graph, getSym(apiModule, "requiresData"), result.requires) - let binSeq = getGlobalAsSeq(getSym(apiModule, "bin")) + let binSeq = getGlobalAsSeq(graph, getSym(apiModule, "bin")) for i in binSeq: result.bin.add(i.addFileExt(ExeExt)) - let backend = getGlobal(getSym(apiModule, "backend")) + let backend = getGlobal(graph, getSym(apiModule, "backend")) if backend.len == 0: result.backend = "c" elif cmpIgnoreStyle(backend, "javascript") == 0: @@ -556,12 +608,15 @@ proc execTask*(scriptName, taskName: string, priority = HighPriority) let thisModule = execScript(scriptName, result.flags, options) - let prc = thisModule.tab.strTableGet(getIdent(taskName & "Task")) + let prc = thisModule.tab.strTableGet(getIdent(identCache, taskName & "Task")) if prc.isNil: # Procedure not defined in the NimScript module. result.success = false return - discard vm.globalCtx.execProc(prc, []) + when finalApi: + discard vm.execProc(PCtx(graph.vm), prc, []) + else: + discard vm.globalCtx.execProc(prc, []) # Read the command, arguments and flags set by the executed task. result.command = nimCommand() @@ -590,13 +645,16 @@ proc execHook*(scriptName, actionName: string, before: bool, let thisModule = execScript(scriptName, result.flags, options) # Explicitly execute the task procedure, instead of relying on hack. - let prc = thisModule.tab.strTableGet(getIdent(hookName)) + let prc = thisModule.tab.strTableGet(getIdent(identCache, hookName)) if prc.isNil: # Procedure not defined in the NimScript module. result.success = false cleanup() return - let returnVal = vm.globalCtx.execProc(prc, []) + when finalApi: + let returnVal = vm.execProc(PCtx(graph.vm), prc, []) + else: + let returnVal = vm.globalCtx.execProc(prc, []) case returnVal.kind of nkCharLit..nkUInt64Lit: result.retVal = returnVal.intVal == 1 diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 7ed5501..5586cd1 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -87,7 +87,7 @@ proc changeRoot*(origRoot, newRoot, path: string): string = ## the trailing separator. This would cause this method to throw during package ## installation. if path.startsWith(origRoot) or path.samePaths(origRoot): - return newRoot / path[origRoot.len .. path.len-1] + return newRoot / path.substr(origRoot.len, path.len-1) else: raise newException(ValueError, "Cannot change root of path: Path does not begin with original root.") From a7ed90e4b6171c919958b372d9c72f6bfeef698a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 25 Jun 2018 23:31:11 +0100 Subject: [PATCH 278/424] Fixes regression introduced by new Nim VM code. https://github.com/nim-lang/Nim/issues/8096 --- src/nimble.nim.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nimble.nim.cfg b/src/nimble.nim.cfg index 223dfc3..e459055 100644 --- a/src/nimble.nim.cfg +++ b/src/nimble.nim.cfg @@ -3,3 +3,4 @@ --path:"$nim/" --path:"./vendor/nim" -d:ssl +-d:nimcore # Enable 'gorge' in Nim's VM. See https://github.com/nim-lang/Nim/issues/8096 From 8d4b0b34dd8df3523a007029b37a62915fca3b2b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 13 Jul 2018 14:55:35 +0200 Subject: [PATCH 279/424] Add missing call to cleanup() --- src/nimblepkg/nimscriptsupport.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 4d2f412..412f046 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -612,6 +612,7 @@ proc execTask*(scriptName, taskName: string, if prc.isNil: # Procedure not defined in the NimScript module. result.success = false + cleanup() return when finalApi: discard vm.execProc(PCtx(graph.vm), prc, []) From eecf4f95b3aa8f944e5a7af2ba0d8c24ee1e6a7d Mon Sep 17 00:00:00 2001 From: trialism <32341807+trialism@users.noreply.github.com> Date: Fri, 17 Aug 2018 13:00:55 +0200 Subject: [PATCH 280/424] Improved handling of proxy environment variables --- src/nimblepkg/options.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 63fe5a0..ac9e0ae 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -386,6 +386,10 @@ proc getProxy*(options: Options): Proxy = url = getEnv("http_proxy") elif existsEnv("https_proxy"): url = getEnv("https_proxy") + elif existsEnv("HTTP_PROXY"): + url = getEnv("HTTP_PROXY") + elif existsEnv("HTTPS_PROXY"): + url = getEnv("HTTPS_PROXY") except ValueError: display("Warning:", "Unable to parse proxy from environment: " & getCurrentExceptionMsg(), Warning, HighPriority) From 2e803ec9cf4408d77ec950785bb7b6ad18894eae Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 21 Aug 2018 17:52:24 +0100 Subject: [PATCH 281/424] Fixes #520. --- src/nimblepkg/packageinfo.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 10e8bfa..e6e3726 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -107,8 +107,8 @@ proc requiredField(obj: JsonNode, name: string): string = ## Queries ``obj`` for the required ``name`` string. ## ## Aborts execution if the field does not exist or is of invalid json type. - result = optionalField(obj, name, nil) - if result == nil: + result = optionalField(obj, name) + if result.len == 0: raise newException(NimbleError, "Package in packages.json file does not contain a " & name & " field.") From db222bbae19cd7eea3faf57d38d303170c843473 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 23 Aug 2018 00:33:06 +0100 Subject: [PATCH 282/424] Improves pre and post hooks. Fixes #524. --- src/nimble.nim | 42 +++++---- src/nimblepkg/nimscriptsupport.nim | 2 +- tests/nimscript/nimscript.nimble | 6 ++ tests/tester.nim | 133 ++++++++++++++++------------- 4 files changed, 107 insertions(+), 76 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index b936ad9..fc2a3a0 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -330,6 +330,13 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, ## to the packages this package depends on. ## The return value of this function is used by ## ``processDeps`` to gather a list of paths to pass to the nim compiler. + + # Handle pre-`install` hook. + if not options.depsOnly: + cd dir: # Make sure `execHook` executes the correct .nimble file. + if not execHook(options, true): + raise newException(NimbleError, "Pre-hook prevented further execution.") + var pkgInfo = getPkgInfo(dir, options) let realDir = pkgInfo.getRealDir() let binDir = options.getBinDir() @@ -433,6 +440,12 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, display("Success:", pkgInfo.name & " installed successfully.", Success, HighPriority) + # Run post-install hook now that package is installed. The `execHook` proc + # executes the hook defined in the CWD, so we set it to where the package + # has been installed. + cd dest.splitFile.dir: + discard execHook(options, false) + proc getDownloadInfo*(pv: PkgTuple, options: Options, doPrompt: bool): (DownloadMethod, string, Table[string, string]) = @@ -472,17 +485,7 @@ proc install(packages: seq[PkgTuple], let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth, subdir, options) try: - # Run pre-install hook in download directory now that package is downloaded - cd downloadDir: - if not execHook(options, true): - raise newException(NimbleError, "Pre-hook prevented further execution.") - result = installFromDir(downloadDir, pv.ver, options, url) - - # Run post-install hook in installed directory now that package is installed - # Standard hooks run in current directory so it won't detect this new package - cd result.pkg.myPath.parentDir(): - discard execHook(options, false) except BuildFailed: # The package failed to build. # Check if we tried building a tagged version of the package. @@ -945,6 +948,10 @@ proc developFromDir(dir: string, options: Options) = if options.depsOnly: raiseNimbleError("Cannot develop dependencies only.") + cd dir: # Make sure `execHook` executes the correct .nimble file. + if not execHook(options, true): + raise newException(NimbleError, "Pre-hook prevented further execution.") + var pkgInfo = getPkgInfo(dir, options) if pkgInfo.bin.len > 0: if "nim" in pkgInfo.skipExt: @@ -994,6 +1001,10 @@ proc developFromDir(dir: string, options: Options) = display("Success:", (pkgInfo.name & " linked successfully to '$1'.") % dir, Success, HighPriority) + # Execute the post-develop hook. + cd dir: + discard execHook(options, false) + proc develop(options: Options) = if options.action.packages == @[]: developFromDir(getCurrentDir(), options) @@ -1064,10 +1075,6 @@ proc doAction(options: Options) = if not existsDir(options.getPkgsDir): createDir(options.getPkgsDir) - if not execHook(options, true): - display("Warning", "Pre-hook prevented further execution.", Warning, - HighPriority) - return case options.action.typ of actionRefresh: refresh(options) @@ -1111,6 +1118,10 @@ proc doAction(options: Options) = of actionNil: assert false of actionCustom: + if not execHook(options, true): + display("Warning", "Pre-hook prevented further execution.", Warning, + HighPriority) + return let isPreDefined = options.action.command.normalize == "test" var execResult: ExecutionResult[void] @@ -1125,9 +1136,6 @@ proc doAction(options: Options) = # Run the post hook for `test` in case it exists. discard execHook(options, false) - if options.action.typ != actionCustom: - discard execHook(options, false) - when isMainModule: var error = "" var hint = "" diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 412f046..91ab7ff 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -362,7 +362,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Ensure that "nimblepkg/nimscriptapi" is in the PATH. block: - let t = options.getNimbleDir / "nimblecache" + let t = getTempDir() / "nimblecache" let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim" createDir(tmpNimscriptApiPath.splitFile.dir) writeFile(tmpNimscriptApiPath, nimscriptApi) diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index 5842afd..4493d47 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -43,3 +43,9 @@ before hooks2: task hooks2, "Testing the hooks again": echo("Shouldn't happen") + +before install: + echo("Before PkgDir: ", getPkgDir()) + +after install: + echo("After PkgDir: ", getPkgDir()) \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index 2651d50..f9b4399 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -36,7 +36,10 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs.add("--nimbleDir:" & installDir) quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\"")) - result = execCmdEx(quotedArgs.join(" ")) + let path = getCurrentDir().parentDir() / "src" + + let cmd = "PATH=" & path & ":$PATH " & quotedArgs.join(" ") + result = execCmdEx(cmd) checkpoint(result.output) proc execNimbleYes(args: varargs[string]): tuple[output: string, exitCode: int]= @@ -235,71 +238,82 @@ test "package list can only have one source": check inLines(lines, "Attempted to specify `url` and `path` for the same package list 'local'") check exitCode == QuitFailure -test "can install nimscript package": - cd "nimscript": - check execNimble(["install", "-y"]).exitCode == QuitSuccess +suite "nimscript": + test "can install nimscript package": + cd "nimscript": + check execNimble(["install", "-y"]).exitCode == QuitSuccess -test "can execute nimscript tasks": - cd "nimscript": - let (output, exitCode) = execNimble("--verbose", "work") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check lines[^1] == "10" + test "before/after install pkg dirs are correct": + cd "nimscript": + let (output, exitCode) = execNimble(["install", "-y"]) + check exitCode == QuitSuccess + let lines = output.strip.splitLines() + check lines[0].startsWith("Before PkgDir:") + check lines[0].endsWith("tests/nimscript") + check lines[^1].startsWith("After PkgDir:") + check lines[^1].endsWith("tests/nimbleDir/pkgs/nimscript-0.1.0") -test "can use nimscript's setCommand": - cd "nimscript": - let (output, exitCode) = execNimble("--verbose", "cTest") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check "Execution finished".normalize in lines[^1].normalize + test "can execute nimscript tasks": + cd "nimscript": + let (output, exitCode) = execNimble("--verbose", "work") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check lines[^1] == "10" -test "can use nimscript's setCommand with flags": - cd "nimscript": - let (output, exitCode) = execNimble("--debug", "cr") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check inLines(lines, "Hello World") + test "can use nimscript's setCommand": + cd "nimscript": + let (output, exitCode) = execNimble("--verbose", "cTest") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check "Execution finished".normalize in lines[^1].normalize -test "can use nimscript with repeated flags (issue #329)": - cd "nimscript": - let (output, exitCode) = execNimble("--debug", "repeated") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - var found = false - for line in lines: - if line.contains("--define:foo"): - found = true - check found == true + test "can use nimscript's setCommand with flags": + cd "nimscript": + let (output, exitCode) = execNimble("--debug", "cr") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check inLines(lines, "Hello World") -test "can list nimscript tasks": - cd "nimscript": - let (output, exitCode) = execNimble("tasks") - check "work test description".normalize in output.normalize - check exitCode == QuitSuccess + test "can use nimscript with repeated flags (issue #329)": + cd "nimscript": + let (output, exitCode) = execNimble("--debug", "repeated") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + var found = false + for line in lines: + if line.contains("--define:foo"): + found = true + check found == true -test "can use pre/post hooks": - cd "nimscript": - let (output, exitCode) = execNimble("hooks") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check inLines(lines, "First") - check inLines(lines, "middle") - check inLines(lines, "last") + test "can list nimscript tasks": + cd "nimscript": + let (output, exitCode) = execNimble("tasks") + check "work test description".normalize in output.normalize + check exitCode == QuitSuccess -test "pre hook can prevent action": - cd "nimscript": - let (output, exitCode) = execNimble("hooks2") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check(not inLines(lines, "Shouldn't happen")) - check inLines(lines, "Hook prevented further execution") + test "can use pre/post hooks": + cd "nimscript": + let (output, exitCode) = execNimble("hooks") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check inLines(lines, "First") + check inLines(lines, "middle") + check inLines(lines, "last") -test "nimble script api": - cd "nimscript": - let (output, exitCode) = execNimble("api") - let lines = output.strip.splitLines() - check exitCode == QuitSuccess - check inLines(lines, "PKG_DIR: " & getCurrentDir()) + test "pre hook can prevent action": + cd "nimscript": + let (output, exitCode) = execNimble("hooks2") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check(not inLines(lines, "Shouldn't happen")) + check inLines(lines, "Hook prevented further execution") + + test "nimble script api": + cd "nimscript": + let (output, exitCode) = execNimble("api") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check inLines(lines, "PKG_DIR: " & getCurrentDir()) test "can install packagebin2": let args = ["install", "-y", "https://github.com/nimble-test/packagebin2.git"] @@ -491,6 +505,9 @@ test "can install diamond deps (#184)": checkpoint(output) check exitCode == 0 +test "issues #280 and #524": + check execNimble("install", "-y", "https://github.com/nimble-test/issue280and524.git").exitCode == 0 + suite "can handle two binary versions": setup: cd "binaryPackage/v1": From e06ad6e49707f42bc4801610ba5cb96f8cc3cc4d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 23 Aug 2018 00:42:48 +0100 Subject: [PATCH 283/424] Adds .nimble/bin to PATH in travis. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 24b9744..d2e7808 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ install: before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.18.0/bin:$PATH + - export PATH=`pwd`/nim-0.18.0/bin:$HOME/.nimble/bin:$PATH script: - cd tests From 8134427266f50c0b37a96faea964a3709a062f4f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 27 Aug 2018 17:27:09 +0100 Subject: [PATCH 284/424] Fixes `isNil` errors for compatibility with latest Nim. --- src/nimble.nim | 1 - src/nimblepkg/download.nim | 3 --- src/nimblepkg/nimscriptsupport.nim | 2 +- src/nimblepkg/packageinfo.nim | 3 +-- src/nimblepkg/packageinstaller.nim | 2 +- src/nimblepkg/version.nim | 2 -- 6 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index fc2a3a0..f0d8878 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -622,7 +622,6 @@ proc listPaths(options: Options) = ## On success the proc returns normally. cli.setSuppressMessages(true) assert options.action.typ == actionPath - assert(not options.action.packages.isNil) if options.action.packages.len == 0: raise newException(NimbleError, "A package name needs to be specified") diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index cad8d3d..226fe27 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -166,9 +166,6 @@ proc doDownload(url: string, downloadDir: string, verRange: VersionRange, meth if $latest.ver != "": result = latest.ver - else: - # Result should already be set to #head here. - assert(not result.isNil) removeDir(downloadDir) if verRange.kind == verSpecial: diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 91ab7ff..0de2010 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -51,7 +51,7 @@ proc getGlobal(g: ModuleGraph; ident: PSym): string = else: let n = vm.globalCtx.getGlobalValue(ident) if n.isStrLit: - result = if n.strVal.isNil: "" else: n.strVal + result = n.strVal else: raiseVariableError(ident.name.s, "string") diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index e6e3726..6306840 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -371,8 +371,7 @@ proc findPkg*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]], if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue if withinRange(pkg.pkgInfo, dep.ver): - let isNewer = (not r.version.isNil) and - newVersion(r.version) < newVersion(pkg.pkginfo.version) + let isNewer = newVersion(r.version) < newVersion(pkg.pkginfo.version) if not result or isNewer: r = pkg.pkginfo result = true diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index e48a910..125db93 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -81,7 +81,7 @@ proc saveNimbleMeta*(pkgDestDir, url, vcsRevision: string, ## ## isLink - Determines whether the installed package is a .nimble-link. var nimblemeta = %{"url": %url} - if not vcsRevision.isNil: + if vcsRevision.len > 0: nimblemeta["vcsRevision"] = %vcsRevision let files = newJArray() nimblemeta["files"] = files diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index e19e45b..6b1e7df 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -39,8 +39,6 @@ proc `$`*(ver: Version): string {.borrow.} proc hash*(ver: Version): Hash {.borrow.} -proc isNil*(ver: Version): bool {.borrow.} - proc newVersion*(ver: string): Version = doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits, "Wrong version: " & ver) From 9cf83b281fc4436cc3954b1514042a6c19c9417b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 27 Aug 2018 21:20:43 +0100 Subject: [PATCH 285/424] Re-define ``task`` template in nimscriptapi.nim in prep for #482. --- src/nimblepkg/nimscriptapi.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index b711851..5abfb99 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -27,6 +27,26 @@ proc requires*(deps: varargs[string]) = ## package. for d in deps: requiresData.add(d) +# TODO: New release of Nim will move this `task` template under a +# `when not defined(nimble)`. This will allow us to override it in the future. +when not declared(task): + template task*(name: untyped; description: string; body: untyped): untyped = + ## Defines a task. Hidden tasks are supported via an empty description. + ## Example: + ## + ## .. code-block:: nim + ## task build, "default build is via the C backend": + ## setCommand "c" + proc `name Task`*() = body + + let cmd = getCommand() + if cmd.len == 0 or cmd ==? "help": + setCommand "help" + writeTask(astToStr(name), description) + elif cmd ==? astToStr(name): + setCommand "nop" + `name Task`() + template before*(action: untyped, body: untyped): untyped = ## Defines a block of code which is evaluated before ``action`` is executed. proc `action Before`*(): bool = From 67cf608f55d27b6a49572c5db90d390ce0cb4105 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 27 Aug 2018 22:31:17 +0100 Subject: [PATCH 286/424] Build against a pinned version of Nim devel on travis. --- .travis.yml | 16 ++++++++++------ readme.markdown | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index d2e7808..518a12f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,18 +4,22 @@ dist: trusty language: c +cache: + directories: + - "$HOME/.nimble" + - "$HOME/.choosenim" + install: + - export CHOOSENIM_CHOOSE_VERSION="#7bb93c730ea87f" - | - wget https://nim-lang.org/download/nim-0.18.0.tar.xz - tar -xf nim-0.18.0.tar.xz - cd nim-0.18.0 - sh build.sh - cd .. + curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh + sh init.sh -y before_script: - set -e - set -x - - export PATH=`pwd`/nim-0.18.0/bin:$HOME/.nimble/bin:$PATH + - export CHOOSENIM_NO_ANALYTICS=1 + - export PATH=$HOME/.nimble/bin:$PATH script: - cd tests diff --git a/readme.markdown b/readme.markdown index b09372d..185835b 100644 --- a/readme.markdown +++ b/readme.markdown @@ -905,7 +905,7 @@ The ``master`` branch is... * default * bleeding edge -* tested to compile with the latest Nim version +* tested to compile with a pinned (close to HEAD) commit of Nim The ``stable`` branch is... From f9c54f76075ef7f178bb12dc67c15a42a6bdf44e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 28 Aug 2018 15:17:32 +0100 Subject: [PATCH 287/424] Fixes Travis CI run with choosenim. Squashed commit of the following: commit 0f8a7e178d32a4236d1bd32179cb2dd9f6dbb631 Author: Dominik Picheta Date: Tue Aug 28 14:56:03 2018 +0100 Fixes NIM_PREFIX_DIR affecting testing logs. commit f566e8bcd1eed775e69fe758e415b9df41bcd421 Author: Dominik Picheta Date: Tue Aug 28 14:26:45 2018 +0100 Attempt to fix travis. --- .travis.yml | 1 + tests/tester.nim | 53 ++++++++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 518a12f..4f39d6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ cache: install: - export CHOOSENIM_CHOOSE_VERSION="#7bb93c730ea87f" + - export NIM_LIB_PREFIX="$HOME/.choosenim/toolchains/nim-"$CHOOSENIM_CHOOSE_VERSION - | curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh sh init.sh -y diff --git a/tests/tester.nim b/tests/tester.nim index f9b4399..3861c72 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -52,7 +52,12 @@ template verify(res: (string, int)) = check r[1] == QuitSuccess proc processOutput(output: string): seq[string] = - output.strip.splitLines().filter((x: string) => (x.len > 0)) + output.strip.splitLines().filter( + (x: string) => ( + x.len > 0 and + "Using env var NIM_LIB_PREFIX" notin x + ) + ) proc inLines(lines: seq[string], line: string): bool = for i in lines: @@ -87,7 +92,7 @@ test "can validate package structure (#144)": cd "packageStructure/" & package: let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check(not inLines(lines, "warning")) # Test that warnings are produced for the incorrectly structured packages. @@ -95,7 +100,7 @@ test "can validate package structure (#144)": cd "packageStructure/" & package: let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() checkpoint(output) case package of "x": @@ -135,7 +140,7 @@ test "issue 113 (uninstallation problems)": # Try to remove c. let (output, exitCode) = execNimble(["remove", "-y", "c"]) - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode != QuitSuccess check inLines(lines, "cannot uninstall c (0.1.0) because b (0.1.0) depends on it") @@ -189,7 +194,7 @@ test "can refresh with custom urls": let (output, exitCode) = execNimble(["refresh", "--verbose"]) checkpoint(output) - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check inLines(lines, "config file at") check inLines(lines, "official package list") @@ -206,7 +211,7 @@ test "can refresh with local package list": path = "$1" """.unindent % (getCurrentDir() / "issue368" / "packages.json")) let (output, exitCode) = execNimble(["refresh", "--verbose"]) - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check inLines(lines, "config file at") check inLines(lines, "Copying") check inLines(lines, "Package list copied.") @@ -219,7 +224,7 @@ test "package list source required": name = "local" """) let (output, exitCode) = execNimble(["refresh", "--verbose"]) - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check inLines(lines, "config file at") check inLines(lines, "Package list 'local' requires either url or path") check exitCode == QuitFailure @@ -233,7 +238,7 @@ test "package list can only have one source": url = "http://nim-lang.org/nimble/packages.json" """) let (output, exitCode) = execNimble(["refresh", "--verbose"]) - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check inLines(lines, "config file at") check inLines(lines, "Attempted to specify `url` and `path` for the same package list 'local'") check exitCode == QuitFailure @@ -247,7 +252,7 @@ suite "nimscript": cd "nimscript": let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check lines[0].startsWith("Before PkgDir:") check lines[0].endsWith("tests/nimscript") check lines[^1].startsWith("After PkgDir:") @@ -256,28 +261,28 @@ suite "nimscript": test "can execute nimscript tasks": cd "nimscript": let (output, exitCode) = execNimble("--verbose", "work") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check lines[^1] == "10" test "can use nimscript's setCommand": cd "nimscript": let (output, exitCode) = execNimble("--verbose", "cTest") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check "Execution finished".normalize in lines[^1].normalize test "can use nimscript's setCommand with flags": cd "nimscript": let (output, exitCode) = execNimble("--debug", "cr") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check inLines(lines, "Hello World") test "can use nimscript with repeated flags (issue #329)": cd "nimscript": let (output, exitCode) = execNimble("--debug", "repeated") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess var found = false for line in lines: @@ -294,7 +299,7 @@ suite "nimscript": test "can use pre/post hooks": cd "nimscript": let (output, exitCode) = execNimble("hooks") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check inLines(lines, "First") check inLines(lines, "middle") @@ -303,7 +308,7 @@ suite "nimscript": test "pre hook can prevent action": cd "nimscript": let (output, exitCode) = execNimble("hooks2") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check(not inLines(lines, "Shouldn't happen")) check inLines(lines, "Hook prevented further execution") @@ -311,7 +316,7 @@ suite "nimscript": test "nimble script api": cd "nimscript": let (output, exitCode) = execNimble("api") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode == QuitSuccess check inLines(lines, "PKG_DIR: " & getCurrentDir()) @@ -324,7 +329,7 @@ test "can reject same version dependencies": "install", "-y", "https://github.com/nimble-test/packagebin.git") # We look at the error output here to avoid out-of-order problems caused by # stderr output being generated and flushed without first flushing stdout - let ls = outp.strip.splitLines() + let ls = outp.strip.processOutput() check exitCode != QuitSuccess check "Cannot satisfy the dependency on PackageA 0.2.0 and PackageA 0.5.0" in ls[ls.len-1] @@ -347,20 +352,20 @@ test "issue #27": test "issue #126": cd "issue126/a": let (output, exitCode) = execNimble("install", "-y") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode != QuitSuccess # TODO check inLines(lines, "issue-126 is an invalid package name: cannot contain '-'") cd "issue126/b": let (output1, exitCode1) = execNimble("install", "-y") - let lines1 = output1.strip.splitLines() + let lines1 = output1.strip.processOutput() check exitCode1 != QuitSuccess check inLines(lines1, "The .nimble file name must match name specified inside") test "issue #108": cd "issue108": let (output, exitCode) = execNimble("build") - let lines = output.strip.splitLines() + let lines = output.strip.processOutput() check exitCode != QuitSuccess check inLines(lines, "Nothing to build") @@ -403,7 +408,7 @@ test "issue #349": proc checkName(name: string) = let (outp, code) = execNimble("init", "-y", name) - let msg = outp.strip.splitLines() + let msg = outp.strip.processOutput() check code == QuitFailure check inLines(msg, "\"$1\" is an invalid package name: reserved name" % name) @@ -431,7 +436,7 @@ test "can uninstall": block: let (outp, exitCode) = execNimble("uninstall", "-y", "issue27b") - let ls = outp.strip.splitLines() + let ls = outp.strip.processOutput() check exitCode != QuitSuccess check "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends" & " on it" in ls[ls.len-1] @@ -587,7 +592,7 @@ suite "develop feature": let path = installDir / "pkgs" / "hybrid-#head" / "hybrid.nimble-link" check fileExists(path) - let split = readFile(path).splitLines() + let split = readFile(path).processOutput() check split.len == 2 check split[0].endsWith("develop/hybrid/hybrid.nimble") check split[1].endsWith("develop/hybrid") @@ -602,7 +607,7 @@ suite "develop feature": let path = installDir / "pkgs" / "srcdirtest-#head" / "srcdirtest.nimble-link" check fileExists(path) - let split = readFile(path).splitLines() + let split = readFile(path).processOutput() check split.len == 2 check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble") check split[1].endsWith("develop/srcdirtest/src") From 2145f266e1fe179461ef71dedd57e6bd4c76a211 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 28 Aug 2018 16:15:02 +0100 Subject: [PATCH 288/424] Fix custom `task` template. --- src/nimblepkg/nimscriptapi.nim | 8 ++++---- tests/tester.nim | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 5abfb99..0e0ce45 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -40,12 +40,12 @@ when not declared(task): proc `name Task`*() = body let cmd = getCommand() - if cmd.len == 0 or cmd ==? "help": + if cmd.len == 0 or cmd == "help": setCommand "help" - writeTask(astToStr(name), description) - elif cmd ==? astToStr(name): + echo(astToStr(name), " ", description) + elif cmd == astToStr(name): setCommand "nop" - `name Task`() + `name Task`() template before*(action: untyped, body: untyped): untyped = ## Defines a block of code which is evaluated before ``action`` is executed. diff --git a/tests/tester.nim b/tests/tester.nim index 3861c72..b84a620 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -293,7 +293,8 @@ suite "nimscript": test "can list nimscript tasks": cd "nimscript": let (output, exitCode) = execNimble("tasks") - check "work test description".normalize in output.normalize + check "work".normalize in output.normalize + check "test description".normalize in output.normalize check exitCode == QuitSuccess test "can use pre/post hooks": From 70c9954c41b061e9b01c997d37056baf8d1be8df Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 28 Aug 2018 17:20:25 +0100 Subject: [PATCH 289/424] Fixes regression introduced by 02945e57b5ab. --- src/nimblepkg/version.nim | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 6b1e7df..d86e22c 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -182,7 +182,7 @@ proc parseVersionRange*(s: string): VersionRange = raise newException(ParseVersionError, "Having more than one `&` in a version range is pointless") - break + return of '0'..'9', '.': version.add(s[i]) @@ -291,16 +291,16 @@ when isMainModule: doAssert(newVersion("1.0") < newVersion("1.4")) doAssert(newVersion("1.0.1") > newVersion("1.0")) doAssert(newVersion("1.0.6") <= newVersion("1.0.6")) - #doAssert(not withinRange(newVersion("0.1.0"), parseVersionRange("> 0.1"))) + doAssert(not withinRange(newVersion("0.1.0"), parseVersionRange("> 0.1"))) doAssert(not (newVersion("0.1.0") < newVersion("0.1"))) doAssert(not (newVersion("0.1.0") > newVersion("0.1"))) doAssert(newVersion("0.1.0") < newVersion("0.1.0.0.1")) doAssert(newVersion("0.1.0") <= newVersion("0.1")) var inter1 = parseVersionRange(">= 1.0 & <= 1.5") + doAssert inter1.kind == verIntersect var inter2 = parseVersionRange("1.0") doAssert(inter2.kind == verEq) - #echo(parseVersionRange(">= 0.8 0.9")) doAssert(not withinRange(newVersion("1.5.1"), inter1)) doAssert(withinRange(newVersion("1.0.2.3.4.5.6.7.8.9.10.11.12"), inter1)) @@ -351,4 +351,7 @@ when isMainModule: doAssert toVersionRange(newVersion("#head")).kind == verSpecial doAssert toVersionRange(newVersion("0.2.0")).kind == verEq + # Something raised on IRC + doAssert newVersion("1") == newVersion("1.0") + echo("Everything works!") From 57f73ea2688047ed47889ce6b9029247b387cee9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 28 Aug 2018 17:45:28 +0100 Subject: [PATCH 290/424] Fixes #285. --- tests/tester.nim | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index b84a620..6f7b549 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -714,4 +714,25 @@ suite "multi": test "can develop package from git subdir": removeDir("nimble-test/multi") let args = ["develop", "-y", "https://github.com/nimble-test/multi?subdir=beta"] - check execNimble(args).exitCode == QuitSuccess \ No newline at end of file + check execNimble(args).exitCode == QuitSuccess + +suite "Module tests": + test "version": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/version").exitCode == QuitSuccess + + test "reversedeps": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/reversedeps").exitCode == QuitSuccess + + test "packageparser": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/packageparser").exitCode == QuitSuccess + + test "packageinfo": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/packageinfo").exitCode == QuitSuccess + + test "cli": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/cli").exitCode == QuitSuccess \ No newline at end of file From a3a60eca51a181149b067dad56db2792f7386b4f Mon Sep 17 00:00:00 2001 From: antizealot1337 Date: Sat, 1 Sep 2018 08:09:37 -0400 Subject: [PATCH 291/424] Prompt for multiple selections interactively when possible (#441) * Add interactive selection ability and preserve old behavior if not available * Add description of library and binary packages * Add function origin to doc * Fix typos and windows compilation test * Change select message type and fix style * Change to use TAB to cycle through options --- src/nimble.nim | 4 ++- src/nimblepkg/cli.nim | 84 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index f0d8878..66f0607 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -757,7 +757,9 @@ proc init(options: Options) = priority = HighPriority) # Determine the type of package - let pkgType = promptList(options, "Package type?", [ + let pkgType = promptList(options, """Package type? +Library packages provide functionality for other packages. +Binary packages produce executables.""", [ "lib", "bin", ]) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index a232940..ab9f494 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -12,7 +12,10 @@ # - Bright for HighPriority. # - Normal for MediumPriority. -import logging, terminal, sets, strutils +import logging, terminal, sets, strutils, os + +when defined(windows): + import winlean type CLI* = ref object @@ -169,6 +172,74 @@ proc promptCustom*(forcePrompts: ForcePrompt, question, default: string): string proc promptCustom*(question, default: string): string = return promptCustom(dontForcePrompt, question, default) +proc promptListInteractive(question: string, args: openarray[string]): string = + display("Prompt:", question, Warning, HighPriority) + display("Select", "Cycle with 'Tab', 'Enter' when done", Message, + HighPriority) + displayCategory("Choices:", Warning, HighPriority) + var + current = 0 + selected = false + # Incase the cursor is at the bottom of the terminal + for arg in args: + stdout.write "\n" + # Reset the cursor to the start of the selection prompt + cursorUp(stdout, args.len) + cursorForward(stdout, longestCategory) + hideCursor(stdout) + + # The selection loop + while not selected: + # Loop through the options + for i, arg in args: + # Check if the option is the current + if i == current: + setForegroundColor(fgWhite) + writeStyled(" " & arg, {styleBright}) + else: + setForegroundColor(fgWhite) + writeStyled(" " & arg, {styleDim}) + # Move the cursor back to the start + for s in 0..<(arg.len + 1): + cursorBackward(stdout) + # Move down for the next item + cursorDown(stdout) + # Move the cursor back up to the start of the selection prompt + for i in 0..<(args.len()): + cursorUp(stdout) + resetAttributes(stdout) + + # Begin key input + while true: + case getch(): + of '\t': + current = (current + 1) mod args.len + break + of '\r': + selected = true + break + else: discard + + # Erase all lines of the selection + for i in 0.. [forced " & result & "]", Warning, HighPriority) else: - display("Prompt:", question & " [" & join(args, "/") & "]", Warning, HighPriority) - displayCategory("Answer:", Warning, HighPriority) - result = stdin.readLine() - for arg in args: - if arg.cmpIgnoreCase(result) == 0: - return arg - return promptList(forcePrompts, question, args) + if isatty(stdout): + return promptListInteractive(question, args) + else: + return promptListFallback(question, args) proc setVerbosity*(level: Priority) = globalCLI.level = level From fe21329f3d657539fb007483ab3536b406814c71 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 1 Sep 2018 23:01:16 +0100 Subject: [PATCH 292/424] Fixes #531. Fixes #393. Replaces #465. --- src/nimble.nim | 25 ++++++++----------------- src/nimblepkg/packageinfo.nim | 13 +++++++++++-- tests/tester.nim | 22 ++++++++++++++++------ 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 66f0607..49232f8 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -190,11 +190,6 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = else: display("Info:", "Dependency on $1 already satisfied" % $dep, priority = HighPriority) - if pkg.isLinked: - # TODO (#393): This can be optimised since the .nimble-link files have - # a secondary line that specifies the srcDir. - pkg = pkg.toFullInfo(options) - result.add(pkg) # Process the dependencies of this dependency. result.add(processDeps(pkg.toFullInfo(options), options)) @@ -627,23 +622,19 @@ proc listPaths(options: Options) = raise newException(NimbleError, "A package name needs to be specified") var errors = 0 + let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options) for name, version in options.action.packages.items: var installed: seq[VersionAndPath] = @[] # There may be several, list all available ones and sort by version. - for kind, path in walkDir(options.getPkgsDir): - if kind != pcDir or not path.startsWith(options.getPkgsDir / name & "-"): - continue - - var nimbleFile = findNimbleFile(path, false) - if nimbleFile.existsFile: - var pkgInfo = getPkgInfo(path, options) + for x in pkgs.items(): + let + pName = x.pkginfo.name + pVer = x.pkginfo.specialVersion + if name == pName: var v: VersionAndPath - v.version = newVersion(pkgInfo.specialVersion) - v.path = pkgInfo.getRealDir() + v.version = newVersion(pVer) + v.path = x.pkginfo.getRealDir() installed.add(v) - else: - display("Warning:", "No .nimble file found for " & path, Warning, - MediumPriority) if installed.len > 0: sort(installed, cmp[VersionAndPath], Descending) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 6306840..a9e2b97 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -336,8 +336,17 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options): pkg.specialVersion = version pkg.isMinimal = true pkg.isInstalled = true - pkg.isLinked = - cmpPaths(nimbleFile.splitFile().dir, path) != 0 + let nimbleFileDir = nimbleFile.splitFile().dir + pkg.isLinked = cmpPaths(nimbleFileDir, path) != 0 + + # Read the package's 'srcDir' (this is stored in the .nimble-link so + # we can easily grab it) + if pkg.isLinked: + let nimbleLinkPath = path / name.addFileExt("nimble-link") + let realSrcPath = readNimbleLink(nimbleLinkPath).packageDir + assert realSrcPath.startsWith(nimbleFileDir) + pkg.srcDir = realSrcPath.replace(nimbleFileDir) + pkg.srcDir.removePrefix(DirSep) result.add((pkg, meta)) proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool = diff --git a/tests/tester.nim b/tests/tester.nim index 6f7b549..efcb619 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -595,8 +595,8 @@ suite "develop feature": check fileExists(path) let split = readFile(path).processOutput() check split.len == 2 - check split[0].endsWith("develop/hybrid/hybrid.nimble") - check split[1].endsWith("develop/hybrid") + check split[0].endsWith("develop" / "hybrid" / "hybrid.nimble") + check split[1].endsWith("develop" / "hybrid") test "can develop with srcDir": cd "develop/srcdirtest": @@ -610,11 +610,11 @@ suite "develop feature": check fileExists(path) let split = readFile(path).processOutput() check split.len == 2 - check split[0].endsWith("develop/srcdirtest/srcdirtest.nimble") - check split[1].endsWith("develop/srcdirtest/src") + check split[0].endsWith("develop" / "srcdirtest" / "srcdirtest.nimble") + check split[1].endsWith("develop" / "srcdirtest" / "src") cd "develop/dependent": - let (output, exitCode) = execNimble("c", "-r", "src/dependent.nim") + let (output, exitCode) = execNimble("c", "-r", "src" / "dependent.nim") checkpoint output check(output.processOutput.inLines("hello")) check exitCode == QuitSuccess @@ -644,10 +644,20 @@ suite "develop feature": check exitCode == QuitSuccess (output, exitCode) = execNimble("path", "srcdirtest") + checkpoint output check exitCode == QuitSuccess check output.strip() == getCurrentDir() / "src" +suite "path command": + test "can get correct path for srcDir (#531)": + check execNimble("uninstall", "srcdirtest", "-y").exitCode == QuitSuccess + cd "develop/srcdirtest": + let (output, exitCode) = execNimble("install", "-y") + check exitCode == QuitSuccess + let (output, exitCode) = execNimble("path", "srcdirtest") + check output.strip() == installDir / "pkgs" / "srcdirtest-1.0" + suite "test command": test "Runs passing unit tests": cd "testCommand/testsPass": @@ -735,4 +745,4 @@ suite "Module tests": test "cli": cd "..": - check execCmdEx("nim c -r src/nimblepkg/cli").exitCode == QuitSuccess \ No newline at end of file + check execCmdEx("nim c -r src/nimblepkg/cli").exitCode == QuitSuccess From 225a0ef661b48973f43a0a47ece18076fe30caa7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 1 Sep 2018 23:29:26 +0100 Subject: [PATCH 293/424] Fixes #501. --- src/nimblepkg/packageinfo.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index a9e2b97..9da59d5 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -311,10 +311,14 @@ proc findNimbleFile*(dir: string; error: bool): string = if result.splitFile.ext == ".nimble-link": # Return the path of the real .nimble file. + let nimbleLinkPath = result result = readNimbleLink(result).nimbleFilePath if not fileExists(result): - raiseNimbleError("The .nimble-link file is pointing to a missing" & - " file: " & result) + let msg = "The .nimble-link file is pointing to a missing file: " & result + let hintMsg = + "Remove '$1' or restore the file it points to." % nimbleLinkPath + display("Warning:", msg, Warning, HighPriority) + display("Hint:", hintMsg, Warning, HighPriority) proc getInstalledPkgsMin*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = From d606867da636e3377cb5c8d55e9653388e1121cb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 2 Sep 2018 01:11:50 +0100 Subject: [PATCH 294/424] Fixes #436. `Develop` clones HEAD and full history. --- src/nimble.nim | 11 ++++++++++- src/nimblepkg/download.nim | 16 +++++++++------- src/nimblepkg/options.nim | 2 ++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 49232f8..2c58030 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1016,7 +1016,16 @@ proc develop(options: Options) = let (meth, url, metadata) = getDownloadInfo(pv, options, true) let subdir = metadata.getOrDefault("subdir") - discard downloadPkg(url, pv.ver, meth, subdir, options, downloadDir) + + # Download the HEAD and make sure the full history is downloaded. + let ver = + if pv.ver.kind == verAny: + parseVersionRange("#head") + else: + pv.ver + var options = options + options.forceFullClone = true + discard downloadPkg(url, ver, meth, subdir, options, downloadDir) developFromDir(downloadDir / subdir, options) proc test(options: Options) = diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 226fe27..f8954e9 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -42,17 +42,17 @@ proc doPull(meth: DownloadMethod, downloadDir: string) = doCmd("hg pull") proc doClone(meth: DownloadMethod, url, downloadDir: string, branch = "", - tip = true) = + onlyTip = true) = case meth of DownloadMethod.git: let - depthArg = if tip: "--depth 1 " else: "" + depthArg = if onlyTip: "--depth 1 " else: "" branchArg = if branch == "": "" else: "-b " & branch & " " doCmd("git clone --recursive " & depthArg & branchArg & url & " " & downloadDir) of DownloadMethod.hg: let - tipArg = if tip: "-r tip " else: "" + tipArg = if onlyTip: "-r tip " else: "" branchArg = if branch == "": "" else: "-b " & branch & " " doCmd("hg clone " & tipArg & branchArg & url & " " & downloadDir) @@ -171,10 +171,11 @@ proc doDownload(url: string, downloadDir: string, verRange: VersionRange, if verRange.kind == verSpecial: # We want a specific commit/branch/tag here. if verRange.spe == getHeadName(downMethod): - doClone(downMethod, url, downloadDir) # Grab HEAD. + # Grab HEAD. + doClone(downMethod, url, downloadDir, onlyTip = not options.forceFullClone) else: # Grab the full repo. - doClone(downMethod, url, downloadDir, tip = false) + doClone(downMethod, url, downloadDir, onlyTip = false) # Then perform a checkout operation to get the specified branch/commit. # `spe` starts with '#', trim it. doAssert(($verRange.spe)[0] == '#') @@ -191,12 +192,13 @@ proc doDownload(url: string, downloadDir: string, verRange: VersionRange, getLatestByTag: display("Cloning", "latest tagged version: " & latest.tag, priority = MediumPriority) - doClone(downMethod, url, downloadDir, latest.tag) + doClone(downMethod, url, downloadDir, latest.tag, + onlyTip = not options.forceFullClone) else: # If no commits have been tagged on the repo we just clone HEAD. doClone(downMethod, url, downloadDir) # Grab HEAD. of DownloadMethod.hg: - doClone(downMethod, url, downloadDir) + doClone(downMethod, url, downloadDir, onlyTip = not options.forceFullClone) result = getHeadName(downMethod) let versions = getTagsList(downloadDir, downMethod).getVersionList() diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index ac9e0ae..a0e56b4 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -22,6 +22,8 @@ type showVersion*: bool noColor*: bool disableValidation*: bool + ## Whether packages' repos should always be downloaded with their history. + forceFullClone*: bool ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, From 7d1f09662668f64f22a779a9cf541b1cff8684e9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 2 Sep 2018 20:05:14 +0100 Subject: [PATCH 295/424] Ask user to remove whole directory, not just .nimble-link. --- src/nimblepkg/packageinfo.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 9da59d5..9fbde28 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -316,7 +316,7 @@ proc findNimbleFile*(dir: string; error: bool): string = if not fileExists(result): let msg = "The .nimble-link file is pointing to a missing file: " & result let hintMsg = - "Remove '$1' or restore the file it points to." % nimbleLinkPath + "Remove '$1' or restore the file it points to." % dir display("Warning:", msg, Warning, HighPriority) display("Hint:", hintMsg, Warning, HighPriority) From 260eb854fd6b3b554d391749056a047fec3b945f Mon Sep 17 00:00:00 2001 From: Christopher Pridgen Date: Tue, 4 Sep 2018 21:19:11 -0400 Subject: [PATCH 296/424] Fixes #503 by creating directory if current and name differ --- src/nimble.nim | 26 ++++++++++++++++---------- src/nimblepkg/options.nim | 3 ++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2c58030..f1f213c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -698,25 +698,31 @@ proc dump(options: Options) = echo "backend: ", p.backend.escape proc init(options: Options) = - var nimbleFile: string = "" - if options.forcePrompts != forcePromptYes: display("Info:", "In order to initialise a new Nimble package, I will need to ask you\n" & "some questions. Default values are shown in square brackets, press\n" & "enter to use them.", priority = HighPriority) - # Ask for package name. + # Determine the package name. let pkgName = if options.action.projName != "": options.action.projName else: os.getCurrentDir().splitPath.tail.toValidPackageName() - nimbleFile = pkgName.changeFileExt("nimble") - validatePackageName(nimbleFile.changeFileExt("")) + # Validate the package name. + validatePackageName(pkgName) - let nimbleFilePath = os.getCurrentDir() / nimbleFile + # Determine the package root. + let pkgRoot = if pkgName == os.getCurrentDir().splitPath.tail: + os.getCurrentDir() + else: + os.getCurrentDir() / pkgName + + let nimbleFile = (pkgRoot / pkgName).changeFileExt("nimble") + + let nimbleFilePath = pkgRoot / nimbleFile if existsFile(nimbleFilePath): let errMsg = "Nimble file already exists: $#" % nimbleFilePath raise newException(NimbleError, errMsg) @@ -781,13 +787,13 @@ Binary packages produce executables.""", [ let pkgTestDir = "tests" # Create source directory - os.createDir(pkgSrcDir) + os.createDir(pkgRoot / pkgSrcDir) display("Success:", "Source directory created successfully", Success, MediumPriority) # Create initial source file - cd pkgSrcDir: + cd pkgRoot / pkgSrcDir: let pkgFile = pkgName.changeFileExt("nim") try: if pkgType == "bin": @@ -804,12 +810,12 @@ Binary packages produce executables.""", [ " for writing: " & osErrorMsg(osLastError())) # Create test directory - os.createDir(pkgTestDir) + os.createDir(pkgRoot / pkgTestDir) display("Success:", "Test directory created successfully", Success, MediumPriority) - cd pkgTestDir: + cd pkgRoot / pkgTestDir: try: "test1.nims".writeFile("""switch("path", "$$projectDir/../$#")""" % [pkgSrcDir]) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index a0e56b4..a54b41d 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -65,7 +65,8 @@ Commands: check Verifies the validity of a package in the current working directory. init [pkgname] Initializes a new Nimble project in the - current directory. + current directory or if a name is provided a + new directory of the same name. publish Publishes a package on nim-lang/packages. The current working directory needs to be the toplevel directory of the Nimble package. From e6c41248e62802b782cd740d309f951c6cb8eadd Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 7 Sep 2018 01:40:01 +0200 Subject: [PATCH 297/424] prepare Nimble for NimCompilerApiVersion 3 --- src/nimblepkg/nimscriptsupport.nim | 44 +++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 0de2010..5fdfaa6 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -45,6 +45,9 @@ when declared(NimCompilerApiVersion): else: const finalApi = false +when NimCompilerApiVersion >= 3: + import compiler / pathutils + proc getGlobal(g: ModuleGraph; ident: PSym): string = when finalApi: let n = vm.getGlobalValue(PCtx g.vm, ident) @@ -201,10 +204,17 @@ proc setupVM(graph: ModuleGraph; module: PSym; scriptName: string, flags: Flags) let arg = a.getString 1 if arg.len > 0: conf.projectName = arg - try: - conf.projectFull = canonicalizePath(conf, conf.projectPath / conf.projectName) - except OSError: - conf.projectFull = conf.projectName + when NimCompilerApiVersion >= 3: + try: + conf.projectFull = canonicalizePath(conf, + conf.projectPath / RelativeFile(conf.projectName)) + except OSError: + conf.projectFull = AbsoluteFile conf.projectName + else: + try: + conf.projectFull = canonicalizePath(conf, conf.projectPath / conf.projectName) + except OSError: + conf.projectFull = conf.projectName else: compiler_options.command = a.getString 0 let arg = a.getString 1 @@ -311,11 +321,19 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Ensure the compiler can find its standard library #220. when declared(NimCompilerApiVersion): - conf.prefixDir = getNimPrefixDir(options) - display("Setting", "Nim stdlib prefix to " & conf.prefixDir, - priority=LowPriority) + when NimCompilerApiVersion >= 3: + conf.prefixDir = AbsoluteDir getNimPrefixDir(options) + display("Setting", "Nim stdlib prefix to " & conf.prefixDir.string, + priority=LowPriority) - template myLibPath(): untyped = conf.libpath + template myLibPath(): untyped = conf.libpath.string + + else: + conf.prefixDir = getNimPrefixDir(options) + display("Setting", "Nim stdlib prefix to " & conf.prefixDir, + priority=LowPriority) + + template myLibPath(): untyped = conf.libpath # Verify that lib path points to existing stdlib. setDefaultLibpath(conf) @@ -367,7 +385,10 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = createDir(tmpNimscriptApiPath.splitFile.dir) writeFile(tmpNimscriptApiPath, nimscriptApi) when declared(NimCompilerApiVersion): - conf.searchPaths.add(t) + when NimCompilerApiVersion >= 3: + conf.searchPaths.add(AbsoluteDir t) + else: + conf.searchPaths.add(t) else: searchPaths.add(t) @@ -434,7 +455,10 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = when finalApi: graph.compileSystemModule() - graph.processModule(result, llStreamOpen(scriptName, fmRead)) + when NimCompilerApiVersion >= 3: + graph.processModule(result, llStreamOpen(AbsoluteFile scriptName, fmRead)) + else: + graph.processModule(result, llStreamOpen(scriptName, fmRead)) elif declared(newIdentCache): graph.compileSystemModule(identCache) graph.processModule(result, llStreamOpen(scriptName, fmRead), nil, identCache) From cc71c6f80e696d7c6f93e49e8de2bca5c3eb4957 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 15:43:43 +0100 Subject: [PATCH 298/424] Improves `nimble init` (more licenses and consistent identifiers). --- src/nimble.nim | 66 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index f1f213c..396348a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -699,10 +699,13 @@ proc dump(options: Options) = proc init(options: Options) = if options.forcePrompts != forcePromptYes: - display("Info:", - "In order to initialise a new Nimble package, I will need to ask you\n" & - "some questions. Default values are shown in square brackets, press\n" & - "enter to use them.", priority = HighPriority) + display( + "Info:", + "Package initialisation requires info which could not be inferred.\n" & + "Default values are shown in square brackets, press\n" & + "enter to use them.", + priority = HighPriority + ) # Determine the package name. let pkgName = @@ -715,7 +718,8 @@ proc init(options: Options) = validatePackageName(pkgName) # Determine the package root. - let pkgRoot = if pkgName == os.getCurrentDir().splitPath.tail: + let pkgRoot = + if pkgName == os.getCurrentDir().splitPath.tail: os.getCurrentDir() else: os.getCurrentDir() / pkgName @@ -754,12 +758,16 @@ proc init(options: Options) = priority = HighPriority) # Determine the type of package - let pkgType = promptList(options, """Package type? -Library packages provide functionality for other packages. -Binary packages produce executables.""", [ - "lib", - "bin", - ]) + let pkgType = promptList( + options, + """Package type? +Library - provides functionality for other packages. +Binary - produces an executable for the end-user. +Hybrid - combination of library and binary + +For more information see https://goo.gl/cm2RX5""", + ["library", "binary", "hybrid"] + ) # Ask for package version. let pkgVersion = promptCustom(options, "Initial version of package?", "0.1.0") @@ -770,14 +778,33 @@ Binary packages produce executables.""", [ "A new awesome nimble package") # Ask for license - let pkgLicense = options.promptList("Package License?", [ + # License list is based on: + # https://www.blackducksoftware.com/top-open-source-licenses + var pkgLicense = options.promptList( + """Package License? +This should ideally be a valid SPDX identifier. See https://spdx.org/licenses/. +""", [ "MIT", - "BSD2", - "GPLv3", - "LGPLv3", - "Apache2", + "GPL-2.0", + "Apache-2.0", + "ISC", + "GPL-3.0", + "BSD-3-Clause", + "LGPL-2.1", + "LGPL-3.0", + "EPL-2.0", + # This is what npm calls "UNLICENSED" (which is too similar to "Unlicense") + "Proprietary", + "Other" ]) + if pkgLicense.toLower == "other": + pkgLicense = promptCustom(options, + """Package license? +Please specify a valid SPDX identifier.""", + "MIT" + ) + # Ask for Nim dependency let nimDepDef = getNimrodVersion() let pkgNimDep = promptCustom(options, "Lowest supported Nim version?", @@ -864,8 +891,11 @@ requires "nim >= $#" """ % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(), pkgLicense.escape(), pkgSrcDir.escape(), pkgName.escape(), pkgNimDep] except: - raise newException(NimbleError, "Unable to open file " & "test1.nim" & - " for writing: " & osErrorMsg(osLastError())) + raise newException( + NimbleError, + "Unable to open file " & nimbleFile & " for writing: " & + osErrorMsg(osLastError()) + ) display("Success:", "Nimble file created successfully", Success, MediumPriority) From ae4fc39a7ade6b158c9f88668ec58adb04a0b9b3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 16:01:40 +0100 Subject: [PATCH 299/424] Fixes check for existing .nimble file in `nimble init.` --- src/nimble.nim | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 396348a..22d7955 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -698,15 +698,6 @@ proc dump(options: Options) = echo "backend: ", p.backend.escape proc init(options: Options) = - if options.forcePrompts != forcePromptYes: - display( - "Info:", - "Package initialisation requires info which could not be inferred.\n" & - "Default values are shown in square brackets, press\n" & - "enter to use them.", - priority = HighPriority - ) - # Determine the package name. let pkgName = if options.action.projName != "": @@ -726,11 +717,18 @@ proc init(options: Options) = let nimbleFile = (pkgRoot / pkgName).changeFileExt("nimble") - let nimbleFilePath = pkgRoot / nimbleFile - if existsFile(nimbleFilePath): - let errMsg = "Nimble file already exists: $#" % nimbleFilePath + if existsFile(nimbleFile): + let errMsg = "Nimble file already exists: $#" % nimbleFile raise newException(NimbleError, errMsg) + if options.forcePrompts != forcePromptYes: + display( + "Info:", + "Package initialisation requires info which could not be inferred.\n" & + "Default values are shown in square brackets, press\n" & + "enter to use them.", + priority = HighPriority + ) display("Using", "$# for new package name" % [pkgName.escape()], priority = HighPriority) From 3ee1e115f4aa250706baf1da2c562f5326f1c98d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 18:15:42 +0100 Subject: [PATCH 300/424] Improves the directory structure that `init` creates. Fixes #413. Refs #315. --- src/nimble.nim | 103 ++++-------------------- src/nimblepkg/init.nim | 171 ++++++++++++++++++++++++++++++++++++++++ src/nimblepkg/tools.nim | 4 + 3 files changed, 189 insertions(+), 89 deletions(-) create mode 100644 src/nimblepkg/init.nim diff --git a/src/nimble.nim b/src/nimble.nim index 22d7955..87b0996 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -14,7 +14,7 @@ import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser, nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps, - nimblepkg/nimscriptexecutor + nimblepkg/nimscriptexecutor, nimblepkg/init import nimblepkg/nimscriptsupport @@ -809,94 +809,19 @@ Please specify a valid SPDX identifier.""", $nimDepDef) validateVersion(pkgNimDep) - let pkgTestDir = "tests" - - # Create source directory - os.createDir(pkgRoot / pkgSrcDir) - - display("Success:", "Source directory created successfully", Success, - MediumPriority) - - # Create initial source file - cd pkgRoot / pkgSrcDir: - let pkgFile = pkgName.changeFileExt("nim") - try: - if pkgType == "bin": - pkgFile.writeFile "# Hello Nim!\necho \"Hello, World!\"\n" - else: - pkgFile.writeFile """# $# -# Copyright $# -# $# -""" % [pkgName, pkgAuthor, pkgDesc] - display("Success:", "Created initial source file successfully", Success, - MediumPriority) - except: - raise newException(NimbleError, "Unable to open file " & pkgFile & - " for writing: " & osErrorMsg(osLastError())) - - # Create test directory - os.createDir(pkgRoot / pkgTestDir) - - display("Success:", "Test directory created successfully", Success, - MediumPriority) - - cd pkgRoot / pkgTestDir: - try: - "test1.nims".writeFile("""switch("path", "$$projectDir/../$#")""" % - [pkgSrcDir]) - display("Success:", "Test config file created successfully", Success, - MediumPriority) - except: - raise newException(NimbleError, "Unable to open file " & "test1.nims" & - " for writing: " & osErrorMsg(osLastError())) - try: - "test1.nim".writeFile("doAssert(1 + 1 == 2)\n") - display("Success:", "Test file created successfully", Success, - MediumPriority) - except: - raise newException(NimbleError, "Unable to open file " & "test1.nim" & - " for writing: " & osErrorMsg(osLastError())) - - # Write the nimble file - try: - if pkgType == "lib": - nimbleFile.writeFile """# Package - -version = $# -author = $# -description = $# -license = $# -srcDir = $# - -# Dependencies - -requires "nim >= $#" -""" % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(), - pkgLicense.escape(), pkgSrcDir.escape(), pkgNimDep] - else: - nimbleFile.writeFile """# Package - -version = $# -author = $# -description = $# -license = $# -srcDir = $# -bin = @[$#] - -# Dependencies - -requires "nim >= $#" -""" % [pkgVersion.escape(), pkgAuthor.escape(), pkgDesc.escape(), - pkgLicense.escape(), pkgSrcDir.escape(), pkgName.escape(), pkgNimDep] - except: - raise newException( - NimbleError, - "Unable to open file " & nimbleFile & " for writing: " & - osErrorMsg(osLastError()) - ) - - display("Success:", "Nimble file created successfully", Success, - MediumPriority) + createPkgStructure( + ( + pkgName, + pkgVersion, + pkgAuthor, + pkgDesc, + pkgLicense, + pkgSrcDir, + pkgNimDep, + pkgType + ), + pkgRoot + ) display("Success:", "Package $# created successfully" % [pkgName], Success, HighPriority) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim new file mode 100644 index 0000000..42c7f4e --- /dev/null +++ b/src/nimblepkg/init.nim @@ -0,0 +1,171 @@ +import os, strutils + +import ./cli, ./tools + +type + PkgInitInfo* = tuple + pkgName: string + pkgVersion: string + pkgAuthor: string + pkgDesc: string + pkgLicense: string + pkgSrcDir: string + pkgNimDep: string + pkgType: string + +proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = + # Create source directory + createDirD(pkgRoot / info.pkgSrcDir) + + # Initialise the source code directories and create some example code. + var nimbleFileOptions = "" + case info.pkgType + of "binary": + let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") + writeFile(mainFile, +""" +# This is just an example to get you started. A typical binary package +# uses this file as the main entry point of the application. + +when isMainModule: + echo("Hello, World!") +""" + ) + nimbleFileOptions.add("bin = @[\"$1\"]\n" % info.pkgName) + of "library": + let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") + writeFile(mainFile, +""" +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two files together. + return x + y +""" + ) + + createDirD(pkgRoot / info.pkgSrcDir / info.pkgName) + let submodule = pkgRoot / info.pkgSrcDir / info.pkgName / + "submodule".addFileExt("nim") + writeFile(submodule, +""" +# This is just an example to get you started. Users of your library will +# import this file by writing ``import $1/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +type + Submodule* = object + name*: string + +proc initSubmodule*(): Submodule = + ## Initialises a new ``Submodule`` object. + Submodule(name: "Anonymous") +""" % info.pkgName + ) + of "hybrid": + let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") + writeFile(mainFile, +""" +# This is just an example to get you started. A typical hybrid package +# uses this file as the main entry point of the application. + +import $1pkg/submodule + +when isMainModule: + echo(getWelcomeMessage()) +""" % info.pkgName + ) + + let pkgSubDir = pkgRoot / info.pkgSrcDir / info.pkgName & "pkg" + createDirD(pkgSubDir) + let submodule = pkgSubDir / "submodule".addFileExt("nim") + writeFile(submodule, +""" +# This is just an example to get you started. Users of your hybrid library will +# import this file by writing ``import $1pkg/submodule``. Feel free to rename or +# remove this file altogether. You may create additional modules alongside +# this file as required. + +proc getWelcomeMessage*(): string = "Hello, World!" +""" % info.pkgName + ) + nimbleFileOptions.add("installExt = @[\"nim\"]\n") + nimbleFileOptions.add("bin = @[\"$1\"]\n" % info.pkgName) + else: + assert false, "Invalid package type specified." + + let pkgTestDir = "tests" + # Create test directory + case info.pkgType + of "binary": + discard + of "hybrid", "library": + let pkgTestPath = pkgRoot / pkgTestDir + createDirD(pkgTestPath) + + writeFile(pkgTestPath / "config".addFileExt("nims"), + "switch(\"path\", \"$$projectDir/../$#\")" % info.pkgSrcDir + ) + + if info.pkgType == "library": + writeFile(pkgTestPath / "test1".addFileExt("nim"), +""" +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import $1 +test "can add": + check add(5, 5) == 10 +""" % info.pkgName + ) + else: + writeFile(pkgTestPath / "test1".addFileExt("nim"), +""" +# This is just an example to get you started. You may wish to put all of your +# tests into a single file, or separate them into multiple `test1`, `test2` +# etc. files (better names are recommended, just make sure the name starts with +# the letter 't'). +# +# To run these tests, simply execute `nimble test`. + +import unittest + +import $1pkg/submodule +test "correct welcome": + check getWelcomeMessage() == "Hello, World!" +""" % info.pkgName + ) + else: + assert false, "Invalid package type specified." + + # Write the nimble file + let nimbleFile = pkgRoot / info.pkgName.changeFileExt("nimble") + writeFile(nimbleFile, """# Package + +version = $# +author = $# +description = $# +license = $# +srcDir = $# +$# + +# Dependencies + +requires "nim >= $#" +""" % [ + info.pkgVersion.escape(), info.pkgAuthor.escape(), info.pkgDesc.escape(), + info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions, + info.pkgNimDep + ] + ) + + display("Info:", "Nimble file created successfully", priority=MediumPriority) \ No newline at end of file diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 5586cd1..8dc71e2 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -106,6 +106,10 @@ proc copyDirD*(fro, to: string): seq[string] = createDir(changeRoot(fro, to, path.splitFile.dir)) result.add copyFileD(path, changeRoot(fro, to, path)) +proc createDirD*(dir: string) = + display("Creating", "directory $#" % dir, priority = LowPriority) + createDir(dir) + proc getDownloadDirName*(uri: string, verRange: VersionRange): string = ## Creates a directory name based on the specified ``uri`` (url) result = "" From 5d765fcc277d687ebd28e3d3b80e9878248153ce Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 22:16:03 +0100 Subject: [PATCH 301/424] Fixes #496. --- src/nimble.nim | 6 ++++-- tests/testCommand/testsFail/tests/{a.nim => t1.nim} | 0 tests/testCommand/testsFail/tests/{b.nim => t2.nim} | 0 tests/testCommand/testsFail/tests/{c.nim => t3.nim} | 0 tests/testCommand/testsIgnore/testing123.nim | 4 ++++ tests/testCommand/testsIgnore/testing123.nimble | 4 ++++ tests/testCommand/testsIgnore/tests/foobar/tignored.nim | 1 + tests/testCommand/testsIgnore/tests/ignore.nim | 1 + tests/testCommand/testsIgnore/tests/taccept.nim | 7 +++++++ tests/testCommand/testsPass/tests/{one.nim => t1.nim} | 0 tests/testCommand/testsPass/tests/{two.nim => t2.nim} | 0 tests/testCommand/testsPass/tests/{three.nim => t3.nim} | 0 tests/tester.nim | 9 ++++++++- 13 files changed, 29 insertions(+), 3 deletions(-) rename tests/testCommand/testsFail/tests/{a.nim => t1.nim} (100%) rename tests/testCommand/testsFail/tests/{b.nim => t2.nim} (100%) rename tests/testCommand/testsFail/tests/{c.nim => t3.nim} (100%) create mode 100644 tests/testCommand/testsIgnore/testing123.nim create mode 100644 tests/testCommand/testsIgnore/testing123.nimble create mode 100644 tests/testCommand/testsIgnore/tests/foobar/tignored.nim create mode 100644 tests/testCommand/testsIgnore/tests/ignore.nim create mode 100644 tests/testCommand/testsIgnore/tests/taccept.nim rename tests/testCommand/testsPass/tests/{one.nim => t1.nim} (100%) rename tests/testCommand/testsPass/tests/{two.nim => t2.nim} (100%) rename tests/testCommand/testsPass/tests/{three.nim => t3.nim} (100%) diff --git a/src/nimble.nim b/src/nimble.nim index 87b0996..582912b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -988,12 +988,14 @@ proc develop(options: Options) = developFromDir(downloadDir / subdir, options) proc test(options: Options) = - ## Executes all tests. + ## Executes all tests starting with 't' in the ``tests`` directory. + ## Subdirectories are not walked. var files = toSeq(walkDir(getCurrentDir() / "tests")) files.sort((a, b) => cmp(a.path, b.path)) for file in files: - if file.path.endsWith(".nim") and file.kind in {pcFile, pcLinkToFile}: + let (_, name, ext) = file.path.splitFile() + if ext == ".nim" and name[0] == 't' and file.kind in {pcFile, pcLinkToFile}: var optsCopy = options.briefClone() optsCopy.action.typ = actionCompile optsCopy.action.file = file.path diff --git a/tests/testCommand/testsFail/tests/a.nim b/tests/testCommand/testsFail/tests/t1.nim similarity index 100% rename from tests/testCommand/testsFail/tests/a.nim rename to tests/testCommand/testsFail/tests/t1.nim diff --git a/tests/testCommand/testsFail/tests/b.nim b/tests/testCommand/testsFail/tests/t2.nim similarity index 100% rename from tests/testCommand/testsFail/tests/b.nim rename to tests/testCommand/testsFail/tests/t2.nim diff --git a/tests/testCommand/testsFail/tests/c.nim b/tests/testCommand/testsFail/tests/t3.nim similarity index 100% rename from tests/testCommand/testsFail/tests/c.nim rename to tests/testCommand/testsFail/tests/t3.nim diff --git a/tests/testCommand/testsIgnore/testing123.nim b/tests/testCommand/testsIgnore/testing123.nim new file mode 100644 index 0000000..2c96a26 --- /dev/null +++ b/tests/testCommand/testsIgnore/testing123.nim @@ -0,0 +1,4 @@ + +proc myFunc*() = + echo "Executing my func" + diff --git a/tests/testCommand/testsIgnore/testing123.nimble b/tests/testCommand/testsIgnore/testing123.nimble new file mode 100644 index 0000000..00e43bf --- /dev/null +++ b/tests/testCommand/testsIgnore/testing123.nimble @@ -0,0 +1,4 @@ +version = "0.1.0" +author = "John Doe" +description = "Nimble Test" +license = "BSD" diff --git a/tests/testCommand/testsIgnore/tests/foobar/tignored.nim b/tests/testCommand/testsIgnore/tests/foobar/tignored.nim new file mode 100644 index 0000000..9d61174 --- /dev/null +++ b/tests/testCommand/testsIgnore/tests/foobar/tignored.nim @@ -0,0 +1 @@ +echo "Should be ignored" diff --git a/tests/testCommand/testsIgnore/tests/ignore.nim b/tests/testCommand/testsIgnore/tests/ignore.nim new file mode 100644 index 0000000..b63fe4d --- /dev/null +++ b/tests/testCommand/testsIgnore/tests/ignore.nim @@ -0,0 +1 @@ +echo "Should be ignored" \ No newline at end of file diff --git a/tests/testCommand/testsIgnore/tests/taccept.nim b/tests/testCommand/testsIgnore/tests/taccept.nim new file mode 100644 index 0000000..e020a08 --- /dev/null +++ b/tests/testCommand/testsIgnore/tests/taccept.nim @@ -0,0 +1,7 @@ +import testing123, unittest + +test "can accept": + echo "First test" + myFunc() + + diff --git a/tests/testCommand/testsPass/tests/one.nim b/tests/testCommand/testsPass/tests/t1.nim similarity index 100% rename from tests/testCommand/testsPass/tests/one.nim rename to tests/testCommand/testsPass/tests/t1.nim diff --git a/tests/testCommand/testsPass/tests/two.nim b/tests/testCommand/testsPass/tests/t2.nim similarity index 100% rename from tests/testCommand/testsPass/tests/two.nim rename to tests/testCommand/testsPass/tests/t2.nim diff --git a/tests/testCommand/testsPass/tests/three.nim b/tests/testCommand/testsPass/tests/t3.nim similarity index 100% rename from tests/testCommand/testsPass/tests/three.nim rename to tests/testCommand/testsPass/tests/t3.nim diff --git a/tests/tester.nim b/tests/tester.nim index efcb619..9ac57df 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -38,7 +38,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = let path = getCurrentDir().parentDir() / "src" - let cmd = "PATH=" & path & ":$PATH " & quotedArgs.join(" ") + let cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib PATH=" & path & ":$PATH " & quotedArgs.join(" ") result = execCmdEx(cmd) checkpoint(result.output) @@ -682,6 +682,13 @@ suite "test command": check exitCode == QuitSuccess check outp.processOutput.inLines("overriden") + test "certain files are ignored": + cd "testCommand/testsIgnore": + let (outp, exitCode) = execNimble("test") + check exitCode == QuitSuccess + check(not outp.processOutput.inLines("Should be ignored")) + check outp.processOutput.inLines("First test") + suite "check command": test "can succeed package": cd "binaryPackage/v1": From 5dfe81556b7903d84454b2a9e48ca60773e1bbeb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 22:26:27 +0100 Subject: [PATCH 302/424] Adds test for #476. Closes #476. --- tests/testCommand/testsCWD/testing123.nimble | 4 ++++ tests/testCommand/testsCWD/tests/tcwd.nim | 2 ++ tests/tester.nim | 12 +++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/testCommand/testsCWD/testing123.nimble create mode 100644 tests/testCommand/testsCWD/tests/tcwd.nim diff --git a/tests/testCommand/testsCWD/testing123.nimble b/tests/testCommand/testsCWD/testing123.nimble new file mode 100644 index 0000000..00e43bf --- /dev/null +++ b/tests/testCommand/testsCWD/testing123.nimble @@ -0,0 +1,4 @@ +version = "0.1.0" +author = "John Doe" +description = "Nimble Test" +license = "BSD" diff --git a/tests/testCommand/testsCWD/tests/tcwd.nim b/tests/testCommand/testsCWD/tests/tcwd.nim new file mode 100644 index 0000000..444a862 --- /dev/null +++ b/tests/testCommand/testsCWD/tests/tcwd.nim @@ -0,0 +1,2 @@ +import os +echo(getCurrentDir()) \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index 9ac57df..c26bb00 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -38,7 +38,11 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = let path = getCurrentDir().parentDir() / "src" - let cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib PATH=" & path & ":$PATH " & quotedArgs.join(" ") + var cmd = "PATH=" & path & ":$PATH " & quotedArgs.join(" ") + when defined(macosx): + # TODO: Yeah, this is really specific to my machine but for my own sanity... + cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib " & cmd + result = execCmdEx(cmd) checkpoint(result.output) @@ -689,6 +693,12 @@ suite "test command": check(not outp.processOutput.inLines("Should be ignored")) check outp.processOutput.inLines("First test") + test "CWD is root of package": + cd "testCommand/testsCWD": + let (outp, exitCode) = execNimble("test") + check exitCode == QuitSuccess + check outp.processOutput.inLines(getCurrentDir()) + suite "check command": test "can succeed package": cd "binaryPackage/v1": From fb879efb72d7a2e3d3a65c8aadb69db9a1d66eac Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 9 Sep 2018 23:24:53 +0100 Subject: [PATCH 303/424] Binary packages no longer install .nim files implicitly. Refs #469. --- src/nimblepkg/packageparser.nim | 12 ++++++++++++ tests/packageStructure/validBinary/y.nim | 0 tests/packageStructure/validBinary/y.nimble | 13 +++++++++++++ .../packageStructure/validBinary/yWrong/foobar.nim | 1 + tests/packageStructure/y/y.nimble | 1 + tests/tester.nim | 2 +- 6 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tests/packageStructure/validBinary/y.nim create mode 100644 tests/packageStructure/validBinary/y.nimble create mode 100644 tests/packageStructure/validBinary/yWrong/foobar.nim diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 17f4464..04a5730 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -277,6 +277,15 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = else: raise newException(ValueError, "Cannot open package info: " & path) +proc inferInstallRules(pkgInfo: var PackageInfo, options: Options) = + # Binary packages shouldn't install .nim files by default. + # (As long as the package info doesn't explicitly specify what should be + # installed.) + let installInstructions = + pkgInfo.installDirs.len + pkgInfo.installExt.len + pkgInfo.installFiles.len + if installInstructions == 0 and pkgInfo.bin.len > 0: + pkgInfo.skipExt.add("nim") + proc readPackageInfo(nf: NimbleFile, options: Options, onlyMinimalInfo=false): PackageInfo = ## Reads package info from the specified Nimble file. @@ -354,6 +363,9 @@ proc readPackageInfo(nf: NimbleFile, options: Options, if not result.isMinimal: options.pkgInfoCache[nf] = result + # Apply rules to infer which files should/shouldn't be installed. See #469. + inferInstallRules(result, options) + # Validate the rest of the package info last. if not options.disableValidation: validateVersion(result.version) diff --git a/tests/packageStructure/validBinary/y.nim b/tests/packageStructure/validBinary/y.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/validBinary/y.nimble b/tests/packageStructure/validBinary/y.nimble new file mode 100644 index 0000000..087141b --- /dev/null +++ b/tests/packageStructure/validBinary/y.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package Y" +license = "MIT" + +bin = @["y"] + +# Dependencies + +requires "nim >= 0.15.0" + diff --git a/tests/packageStructure/validBinary/yWrong/foobar.nim b/tests/packageStructure/validBinary/yWrong/foobar.nim new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/packageStructure/validBinary/yWrong/foobar.nim @@ -0,0 +1 @@ + diff --git a/tests/packageStructure/y/y.nimble b/tests/packageStructure/y/y.nimble index 0ce52f9..4eb3ba5 100644 --- a/tests/packageStructure/y/y.nimble +++ b/tests/packageStructure/y/y.nimble @@ -5,6 +5,7 @@ author = "Dominik Picheta" description = "Incorrectly structured package Y" license = "MIT" +installExt = @["nim"] bin = @["y"] # Dependencies diff --git a/tests/tester.nim b/tests/tester.nim index c26bb00..c408777 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -92,7 +92,7 @@ test "can build with #head and versioned package (#289)": test "can validate package structure (#144)": # Test that no warnings are produced for correctly structured packages. - for package in ["a", "b", "c"]: + for package in ["a", "b", "c", "validBinary"]: cd "packageStructure/" & package: let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess From 9f4081e8888958a065d993b13bb5ae31ad6075e3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 10 Sep 2018 00:24:20 +0100 Subject: [PATCH 304/424] Softened package structure rules when srcDir is not specified. Fixes #469. --- src/nimblepkg/packageparser.nim | 16 +++++++++++++--- tests/packageStructure/softened/myPkg.nim | 0 tests/packageStructure/softened/myPkg.nimble | 15 +++++++++++++++ .../softened/myPkg/submodule.nim | 0 tests/packageStructure/softened/tests/mytest.nim | 0 tests/tester.nim | 2 +- 6 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/packageStructure/softened/myPkg.nim create mode 100644 tests/packageStructure/softened/myPkg.nimble create mode 100644 tests/packageStructure/softened/myPkg/submodule.nim create mode 100644 tests/packageStructure/softened/tests/mytest.nim diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 04a5730..8448286 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -286,6 +286,16 @@ proc inferInstallRules(pkgInfo: var PackageInfo, options: Options) = if installInstructions == 0 and pkgInfo.bin.len > 0: pkgInfo.skipExt.add("nim") + # When a package doesn't specify a `srcDir` it's fair to assume that + # the .nim files are in the root of the package. So we can explicitly select + # them and prevent the installation of anything else. The user can always + # override this with `installFiles`. + if pkgInfo.srcDir == "": + if dirExists(pkgInfo.getRealDir() / pkgInfo.name): + pkgInfo.installDirs.add(pkgInfo.name) + if fileExists(pkgInfo.getRealDir() / pkgInfo.name.addFileExt("nim")): + pkgInfo.installFiles.add(pkgInfo.name.addFileExt("nim")) + proc readPackageInfo(nf: NimbleFile, options: Options, onlyMinimalInfo=false): PackageInfo = ## Reads package info from the specified Nimble file. @@ -360,12 +370,12 @@ proc readPackageInfo(nf: NimbleFile, options: Options, if version.kind == verSpecial: result.specialVersion = minimalInfo.version - if not result.isMinimal: - options.pkgInfoCache[nf] = result - # Apply rules to infer which files should/shouldn't be installed. See #469. inferInstallRules(result, options) + if not result.isMinimal: + options.pkgInfoCache[nf] = result + # Validate the rest of the package info last. if not options.disableValidation: validateVersion(result.version) diff --git a/tests/packageStructure/softened/myPkg.nim b/tests/packageStructure/softened/myPkg.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/softened/myPkg.nimble b/tests/packageStructure/softened/myPkg.nimble new file mode 100644 index 0000000..525080d --- /dev/null +++ b/tests/packageStructure/softened/myPkg.nimble @@ -0,0 +1,15 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Correctly structured package myPkg. See #469." +license = "MIT" + +# This is inferred implicitly by Nimble: +# installDirs = @["myPkg"] +# installFiles = @["myPkg.nim"] + +# Dependencies + +requires "nim >= 0.15.0" + diff --git a/tests/packageStructure/softened/myPkg/submodule.nim b/tests/packageStructure/softened/myPkg/submodule.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/packageStructure/softened/tests/mytest.nim b/tests/packageStructure/softened/tests/mytest.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/tester.nim b/tests/tester.nim index c408777..8ec6f22 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -92,7 +92,7 @@ test "can build with #head and versioned package (#289)": test "can validate package structure (#144)": # Test that no warnings are produced for correctly structured packages. - for package in ["a", "b", "c", "validBinary"]: + for package in ["a", "b", "c", "validBinary", "softened"]: cd "packageStructure/" & package: let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess From 09091792615eacd503e87ca70252c572a4bde2b5 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 10 Sep 2018 21:46:10 +0100 Subject: [PATCH 305/424] Breaking change: hybrid packages require `installExt = @["nim"]`. --- tests/develop/hybrid/hybrid.nimble | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/develop/hybrid/hybrid.nimble b/tests/develop/hybrid/hybrid.nimble index d580fad..ae478e1 100644 --- a/tests/develop/hybrid/hybrid.nimble +++ b/tests/develop/hybrid/hybrid.nimble @@ -6,6 +6,7 @@ description = "hybrid" license = "MIT" bin = @["hybrid"] +installExt = @["nim"] # Dependencies From c09b273eaf45a94d0f5189b613662a66c5e1a30c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 11 Sep 2018 21:11:41 +0100 Subject: [PATCH 306/424] Handle removeDir error when removing Nimble's temp dir. Replaces #537. --- src/nimble.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 582912b..6f5ea0a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1110,7 +1110,11 @@ when isMainModule: except NimbleQuit: discard finally: - removeDir(getNimbleTempDir()) + try: + removeDir(getNimbleTempDir()) + except OSError: + let msg = "Couldn't remove Nimble's temp dir" + display("Warning:", msg, Warning, MediumPriority) if error.len > 0: displayTip() From 3ba8bd940d45796e6dc5ff71b810b5312ac19f84 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 11 Sep 2018 23:35:59 +0100 Subject: [PATCH 307/424] Fixes Nimble installation problem due to breaking change (090917926). --- nimble.nimble | 1 + 1 file changed, 1 insertion(+) diff --git a/nimble.nimble b/nimble.nimble index 68b439b..7a8e416 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -17,6 +17,7 @@ license = "BSD" bin = @["nimble"] srcDir = "src" +installExt = @["nim"] # Dependencies From 964af450dd15f5409edad8e3c74b9ba111992d3b Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sat, 15 Sep 2018 21:36:33 +0200 Subject: [PATCH 308/424] Properly guard access to NimCompilerApiVersion. Makes master compile on latest released Nim 0.18.0. --- src/nimblepkg/nimscriptsupport.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 5fdfaa6..89c23c9 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -42,12 +42,12 @@ proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit} when declared(NimCompilerApiVersion): const finalApi = NimCompilerApiVersion >= 2 + + when NimCompilerApiVersion >= 3: + import compiler / pathutils else: const finalApi = false -when NimCompilerApiVersion >= 3: - import compiler / pathutils - proc getGlobal(g: ModuleGraph; ident: PSym): string = when finalApi: let n = vm.getGlobalValue(PCtx g.vm, ident) From af1c1d73c32b6e9fe7a8aecf3768d9f482b18180 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 19 Sep 2018 23:53:27 +0100 Subject: [PATCH 309/424] Version 0.9.0. --- changelog.markdown | 37 +++++++++++++++++++++++++++++++++++++ src/nimblepkg/common.nim | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/changelog.markdown b/changelog.markdown index 29c1bef..2b1e385 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,43 @@ # Nimble changelog +## 0.9.0 - 19/09/2018 + +This is a major new release which contains at least one breaking change. +Unfortunately even though it was planned, support for lock files did not +make it into this release. The release does +however contain a large number of fixes spread across 57 commits. + +The breaking change in this release is to do with the handling of binary +package. **Any package that specifies a ``bin`` value in it's .nimble file** +**will no longer install any Nim source code files**, in other words it's not +going to be a hybrid package by default. This means that so called "hybrid +packages" now need to specify ``installExt = @["nim"]`` in their metadata, +otherwise they will become binary packages only. + +- **Breaking:** hybrid packages require ``installExt = @["nim"]`` + ([Commit](https://github.com/nim-lang/nimble/commit/09091792615eacd503e87ca70252c572a4bde2b5)) +- **The ``init`` command can now show a list of choices for information such as** + **the license.** +- **The ``init`` command now creates correct project structures for all package** + **types.** +- **Fatal errors are no longer created when the path inside a .nimble-link file** + **doesn't exist.** +- **The ``develop`` command now always clones HEAD and grabs the full repo history.** +- **The default ``test`` task no longer executes all tests (only those starting with 't').** +- Colour is no longer used when `isatty` is false. +- ``publish`` now shows the URL of the created PR. +- The ``getPkgDir`` procedure has been fixed in the Nimble file API. +- Improved handling of proxy environment variables. +- Codebase has been improved not to rely on `nil` in strings and seqs. +- The handling of pre- and post-hooks has been improved significantly. +- Fixed the ``path`` command for packages with a ``srcDir`` and optimised the + package look-up. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.10...v0.9.0 + ## 0.8.10 - 23/02/2018 The first release of 2018! Another fairly big release containing 40 commits. diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index a95e780..19faed5 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.8.11" + nimbleVersion* = "0.9.0" From a218bc3793609dd17e78f42d92572b6567016366 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 8 Oct 2018 21:31:25 +0200 Subject: [PATCH 310/424] Don't prepend file:// twice --- src/nimble.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6f5ea0a..1f7e519 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -942,8 +942,7 @@ proc developFromDir(dir: string, options: Options) = writeNimbleLink(nimbleLinkPath, nimbleLink) # Save a nimblemeta.json file. - saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir), - nimbleLinkPath) + saveNimbleMeta(pkgDestDir, dir, vcsRevisionInDir(dir), nimbleLinkPath) # Save the nimble data (which might now contain reverse deps added in # processDeps). From 66d79bf9a0970542351988fa31f487a1e70144f7 Mon Sep 17 00:00:00 2001 From: Clyybber Date: Sun, 14 Oct 2018 18:45:18 +0200 Subject: [PATCH 311/424] Replace deprecated procs (#560) * Replace deprecated procs * Remove deprecated proc * Use sugar instead of future * Use sugar instead of future 2 * Remove renameBabelToNimble since it wasn't exported or used anyways * Use sugar instead of future 3 * Use toUnix --- src/nimble.nim | 2 +- src/nimblepkg/nimscriptsupport.nim | 4 ++-- src/nimblepkg/options.nim | 12 ------------ src/nimblepkg/packageparser.nim | 2 +- src/nimblepkg/publish.nim | 4 ++-- tests/tester.nim | 2 +- 6 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 1f7e519..807abdc 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -4,7 +4,7 @@ import system except TResult import httpclient, parseopt, os, osproc, pegs, tables, parseutils, - strtabs, json, algorithm, sets, uri, future, sequtils + strtabs, json, algorithm, sets, uri, sugar, sequtils import strutils except toLower from unicode import toLower diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 89c23c9..757a85d 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -154,7 +154,7 @@ proc setupVM(graph: ModuleGraph; module: PSym; scriptName: string, flags: Flags) cbos copyFile: os.copyFile(getString(a, 0), getString(a, 1)) cbos getLastModificationTime: - setResult(a, toSeconds(getLastModificationTime(getString(a, 0)))) + setResult(a, toUnix(getLastModificationTime(getString(a, 0)))) cbos rawExec: setResult(a, osproc.execCmd getString(a, 0)) @@ -713,4 +713,4 @@ proc listTasks*(scriptName: string, options: Options) = discard execScript(scriptName, nil, options) # TODO (#402): Make the 'task' template generate explicit data structure # containing all the task names + descriptions. - cleanup() \ No newline at end of file + cleanup() diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index a54b41d..e464e3c 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -212,18 +212,6 @@ proc promptList*(options: Options, question: string, args: openarray[string]): s ## options is selected. return promptList(options.forcePrompts, question, args) -proc renameBabelToNimble(options: Options) {.deprecated.} = - let babelDir = getHomeDir() / ".babel" - let nimbleDir = getHomeDir() / ".nimble" - if dirExists(babelDir): - if options.prompt("Found deprecated babel package directory, would you " & - "like to rename it to nimble?"): - copyDir(babelDir, nimbleDir) - copyFile(babelDir / "babeldata.json", nimbleDir / "nimbledata.json") - - removeDir(babelDir) - removeFile(nimbleDir / "babeldata.json") - proc getNimbleDir*(options: Options): string = result = options.config.nimbleDir if options.nimbleDir.len != 0: diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 8448286..cf77dcc 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, json, streams, strutils, parseutils, os, tables, future +import parsecfg, json, streams, strutils, parseutils, os, tables, sugar from sequtils import apply, map import version, tools, common, nimscriptsupport, options, packageinfo, cli diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index ce8dbe5..0b07a07 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -76,7 +76,7 @@ proc getGithubAuth(o: Options): Auth = proc isCorrectFork(j: JsonNode): bool = # Check whether this is a fork of the nimble packages repo. result = false - if j{"fork"}.getBVal(): + if j{"fork"}.getBool(): result = j{"parent"}{"full_name"}.getStr() == "nim-lang/packages" proc forkExists(a: Auth): bool = @@ -217,7 +217,7 @@ proc publish*(p: PackageInfo, o: Options) = cd pkgsDir: editJson(p, url, tags, downloadMethod) - let branchName = "add-" & p.name & getTime().getGMTime().format("HHmm") + let branchName = "add-" & p.name & getTime().utc.format("HHmm") doCmd("git checkout -B " & branchName) doCmd("git commit packages.json -m \"Added package " & p.name & "\"") display("Pushing", "to remote of fork.", priority = HighPriority) diff --git a/tests/tester.nim b/tests/tester.nim index 8ec6f22..8a78216 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import osproc, streams, unittest, strutils, os, sequtils, future +import osproc, streams, unittest, strutils, os, sequtils, sugar # TODO: Each test should start off with a clean slate. Currently installed # packages are shared between each test which causes a multitude of issues From 22aa3c1d1392d7878d039250ecf0ffeadf3ba0cc Mon Sep 17 00:00:00 2001 From: Jabba Laci Date: Sat, 20 Oct 2018 00:40:41 +0200 Subject: [PATCH 312/424] #555: `nimble test` removes the created binaries (#566) --- src/nimble.nim | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/nimble.nim b/src/nimble.nim index 807abdc..fe165d7 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1002,7 +1002,17 @@ proc test(options: Options) = optsCopy.action.compileOptions = @[] optsCopy.action.compileOptions.add("-r") optsCopy.action.compileOptions.add("--path:.") + let + binFileName = file.path.changeFileExt(ExeExt) + existsBefore = existsFile(binFileName) + execBackend(optsCopy) + + let + existsAfter = existsFile(binFileName) + canRemove = not existsBefore and existsAfter + if canRemove: + removeFile(binFileName) display("Success:", "All tests passed", Success, HighPriority) From 10260a12237fd1dd63bd167e02bb2cf456c096e6 Mon Sep 17 00:00:00 2001 From: juancarlospaco Date: Mon, 12 Nov 2018 03:36:45 -0300 Subject: [PATCH 313/424] Fix #579 --- src/nimblepkg/cli.nim | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index ab9f494..c8a39bf 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -43,6 +43,8 @@ const [fgRed, fgYellow, fgCyan, fgGreen] styles: array[DebugPriority .. HighPriority, set[Style]] = [{styleDim}, {styleDim}, {}, {styleBright}] + arrowL = when defined(windows): "> " else: "▸ " ## CLI Arrow indicator Left. + arrowR = when defined(windows): " <" else: " ◂" ## CLI Arrow indicator Right. proc newCLI(): CLI = result = CLI( @@ -192,15 +194,15 @@ proc promptListInteractive(question: string, args: openarray[string]): string = while not selected: # Loop through the options for i, arg in args: + setBackgroundColor(bgBlack) # We dont known theme of terminal, use Black. + setForegroundColor(fgWhite) # Check if the option is the current if i == current: - setForegroundColor(fgWhite) - writeStyled(" " & arg, {styleBright}) + writeStyled(arrowL & arg & arrowR, {styleBright, styleUnderscore, styleReverse}) else: - setForegroundColor(fgWhite) - writeStyled(" " & arg, {styleDim}) + writeStyled(" " & arg & " ", {styleDim}) # Move the cursor back to the start - for s in 0..<(arg.len + 1): + for s in 0..<(arg.len + 4): cursorBackward(stdout) # Move down for the next item cursorDown(stdout) From 51035411953414514db63328c1efa3a748026501 Mon Sep 17 00:00:00 2001 From: juancarlospaco Date: Tue, 20 Nov 2018 13:59:49 -0300 Subject: [PATCH 314/424] Just add a simple arrow --- src/nimblepkg/cli.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index c8a39bf..a0dc9d3 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -43,8 +43,7 @@ const [fgRed, fgYellow, fgCyan, fgGreen] styles: array[DebugPriority .. HighPriority, set[Style]] = [{styleDim}, {styleDim}, {}, {styleBright}] - arrowL = when defined(windows): "> " else: "▸ " ## CLI Arrow indicator Left. - arrowR = when defined(windows): " <" else: " ◂" ## CLI Arrow indicator Right. + proc newCLI(): CLI = result = CLI( @@ -198,7 +197,7 @@ proc promptListInteractive(question: string, args: openarray[string]): string = setForegroundColor(fgWhite) # Check if the option is the current if i == current: - writeStyled(arrowL & arg & arrowR, {styleBright, styleUnderscore, styleReverse}) + writeStyled("> " & arg & " <", {styleBright}) else: writeStyled(" " & arg & " ", {styleDim}) # Move the cursor back to the start From d9055dbac617d80e2d72f23197528033f8abb80e Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 21 Nov 2018 23:27:29 +0000 Subject: [PATCH 315/424] Use fgDefault instead of setting bg/fg. --- src/nimblepkg/cli.nim | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index a0dc9d3..862ffe5 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -191,10 +191,9 @@ proc promptListInteractive(question: string, args: openarray[string]): string = # The selection loop while not selected: + setForegroundColor(fgDefault) # Loop through the options for i, arg in args: - setBackgroundColor(bgBlack) # We dont known theme of terminal, use Black. - setForegroundColor(fgWhite) # Check if the option is the current if i == current: writeStyled("> " & arg & " <", {styleBright}) From ba6577d36cae8e1968e7f3f36fa8cbdf5387c26c Mon Sep 17 00:00:00 2001 From: Matt Haggard Date: Thu, 29 Nov 2018 18:08:02 -0700 Subject: [PATCH 316/424] Don't swallow control-C (#588) * Don't swallow control-C * Raise NimbleError instead of quitting * Import NimbleError from common rather than version --- src/nimblepkg/cli.nim | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 862ffe5..d8d52d5 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -13,6 +13,7 @@ # - Normal for MediumPriority. import logging, terminal, sets, strutils, os +import ./common when defined(windows): import winlean @@ -218,6 +219,9 @@ proc promptListInteractive(question: string, args: openarray[string]): string = of '\r': selected = true break + of '\3': + showCursor(stdout) + raise newException(NimbleError, "Keyboard interrupt") else: discard # Erase all lines of the selection From 119be481df581035a4cdf61ddbf448b9acbd5c3c Mon Sep 17 00:00:00 2001 From: technicallyagd <43739261+technicallyagd@users.noreply.github.com> Date: Tue, 11 Dec 2018 06:51:43 +0800 Subject: [PATCH 317/424] Additional information on Nim compiler integration (#554) * Additional information on Nim compiler integration * Move the information to a dedicated section Emphasize the fact that no extra step is required if using default `nimbleDir`. * Adds changes requested * NimblePath to nimblePath for consistency * Update readme.markdown --- readme.markdown | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 185835b..9c1f924 100644 --- a/readme.markdown +++ b/readme.markdown @@ -733,7 +733,7 @@ installing your package (on macOS): ### Nim compiler The Nim compiler cannot read .nimble files. Its knowledge of Nimble is -limited to the ``nimblePaths`` feature which allows it to use packages installed +limited to the ``nimblePath`` feature which allows it to use packages installed in Nimble's package directory when compiling your software. This means that it cannot resolve dependencies, and it can only use the latest version of a package when compiling. @@ -746,6 +746,27 @@ This means that you can safely compile using the compiler when developing your software, but you should use Nimble to build the package before publishing it to ensure that the dependencies you specified are correct. +### Compile with `nim` after changing the nimble directory + +The Nim compiler has been preconfigured to look at the default nimble directory while compiling, +so no extra step is required to use nimble managed packages in your code. +However, if you are using a custom `nimbleDir`, you need to specify the +`--nimblePath:PATH` option. For example, +if your `nimble` directory is located at `/some/custom/path/nimble`, this should work: + +``` +nim c --nimblePath:/some/custom/path/nimble/pkgs main.nim +``` + +Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode), +and the editor extension may not allow users to pass custom option to `nim check`, which +will cause `nim check` to scream `Error: cannot open file:`. In this case, +you will have to use [Nim compiler's configuration files](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files). Simply add the line: +``` +nimblePath = "/some/custom/path/nimble/pkgs" +``` +to the `nim.cfg` located in any directory listed in the [documentation](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files), this should resolve the problem. + ### Versions Versions of cloned packages via Git or Mercurial are determined through the From 22485bbd6aa1ba4f19d70fbcdc92e4d4e246862b Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Thu, 13 Dec 2018 19:15:10 +0200 Subject: [PATCH 318/424] Fixed finExe in nimscript --- src/nimblepkg/nimscriptsupport.nim | 2 ++ tests/nimscript/nimscript.nimble | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 757a85d..2806251 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -155,6 +155,8 @@ proc setupVM(graph: ModuleGraph; module: PSym; scriptName: string, flags: Flags) os.copyFile(getString(a, 0), getString(a, 1)) cbos getLastModificationTime: setResult(a, toUnix(getLastModificationTime(getString(a, 0)))) + cbos findExe: + setResult(a, os.findExe(getString(a, 0))) cbos rawExec: setResult(a, osproc.execCmd getString(a, 0)) diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index 4493d47..4625abb 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -27,6 +27,7 @@ task repeated, "Testing `nimble c nimscript.nim` with repeated flags": setCommand "c", "nimscript.nim" task api, "Testing nimscriptapi module functionality": + doAssert(findExe("nim").len != 0) echo("PKG_DIR: ", getPkgDir()) before hooks: @@ -48,4 +49,4 @@ before install: echo("Before PkgDir: ", getPkgDir()) after install: - echo("After PkgDir: ", getPkgDir()) \ No newline at end of file + echo("After PkgDir: ", getPkgDir()) From 68bb97f30ae996ddd89938625c102d69cb0af650 Mon Sep 17 00:00:00 2001 From: markfirmware Date: Tue, 18 Dec 2018 02:49:49 -0500 Subject: [PATCH 319/424] Update readme.markdown (#596) --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 9c1f924..119ed98 100644 --- a/readme.markdown +++ b/readme.markdown @@ -647,7 +647,7 @@ combo. Dependencies are automatically installed before building. It's a good idea to test that the dependencies you specified are correct by -running by running ``nimble build`` or ``nimble install`` in the directory +running ``nimble build`` or ``nimble install`` in the directory of your package. ### Hybrids From 88f5545c750d789a9245b216a77b93e9fd150632 Mon Sep 17 00:00:00 2001 From: genotrance Date: Tue, 8 Jan 2019 13:58:19 -0600 Subject: [PATCH 320/424] Allow removal of reverse dependencies with uninstall --deps flag (#601) * Fix for #398 * Updated fix for #398 * Enable uninstall of reverse deps * Update README * Updates based on feedback --- readme.markdown | 12 ++++++------ src/nimble.nim | 33 ++++++++++++++++++--------------- src/nimblepkg/options.nim | 8 ++++++++ src/nimblepkg/packageinfo.nim | 4 ++++ src/nimblepkg/reversedeps.nim | 13 +++++++++++++ tests/tester.nim | 21 +++++++++++++++++++++ 6 files changed, 70 insertions(+), 21 deletions(-) diff --git a/readme.markdown b/readme.markdown index 119ed98..00aa259 100644 --- a/readme.markdown +++ b/readme.markdown @@ -221,8 +221,8 @@ instead of a name. ### nimble uninstall The ``uninstall`` command will remove an installed package. Attempting to remove -a package which other packages depend on is disallowed and will result in an -error. You must currently manually remove the reverse dependencies first. +a package which other packages depend on will result in an error. You can use the +``--inclDeps`` or ``-i`` flag to remove all dependent packages along with the package. Similar to the ``install`` command you can specify a version range, for example: @@ -749,16 +749,16 @@ to ensure that the dependencies you specified are correct. ### Compile with `nim` after changing the nimble directory The Nim compiler has been preconfigured to look at the default nimble directory while compiling, -so no extra step is required to use nimble managed packages in your code. -However, if you are using a custom `nimbleDir`, you need to specify the +so no extra step is required to use nimble managed packages in your code. +However, if you are using a custom `nimbleDir`, you need to specify the `--nimblePath:PATH` option. For example, if your `nimble` directory is located at `/some/custom/path/nimble`, this should work: ``` nim c --nimblePath:/some/custom/path/nimble/pkgs main.nim -``` +``` -Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode), +Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode), and the editor extension may not allow users to pass custom option to `nim check`, which will cause `nim check` to scream `Error: cannot open file:`. In this case, you will have to use [Nim compiler's configuration files](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files). Simply add the line: diff --git a/src/nimble.nim b/src/nimble.nim index fe165d7..9456e78 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -846,22 +846,25 @@ proc uninstall(options: Options) = for pkg in pkgList: # Check whether any packages depend on the ones the user is trying to # uninstall. - let revDeps = getRevDeps(options, pkg) - var reason = "" - if revDeps.len == 1: - reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver] + if options.uninstallRevDeps: + getAllRevDeps(options, pkg, pkgsToDelete) else: - for i in 0 ..< revDeps.len: - reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver]) - if i != revDeps.len-1: - reason.add ", " - reason.add " depend on it" + let revDeps = getRevDeps(options, pkg) + var reason = "" + if revDeps.len == 1: + reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver] + else: + for i in 0 ..< revDeps.len: + reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver]) + if i != revDeps.len-1: + reason.add ", " + reason.add " depend on it" - if revDeps.len > 0: - errors.add("Cannot uninstall $1 ($2) because $3" % - [pkgTup.name, pkg.specialVersion, reason]) - else: - pkgsToDelete.add pkg + if revDeps.len > 0: + errors.add("Cannot uninstall $1 ($2) because $3" % + [pkgTup.name, pkg.specialVersion, reason]) + else: + pkgsToDelete.add pkg if pkgsToDelete.len == 0: raise newException(NimbleError, "\n " & errors.join("\n ")) @@ -1007,7 +1010,7 @@ proc test(options: Options) = existsBefore = existsFile(binFileName) execBackend(optsCopy) - + let existsAfter = existsFile(binFileName) canRemove = not existsBefore and existsAfter diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index e464e3c..83700e8 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -10,6 +10,7 @@ type Options* = object forcePrompts*: ForcePrompt depsOnly*: bool + uninstallRevDeps*: bool queryVersions*: bool queryInstalled*: bool nimbleDir*: string @@ -71,6 +72,7 @@ Commands: The current working directory needs to be the toplevel directory of the Nimble package. uninstall [pkgname, ...] Uninstalls a list of packages. + [-i, --inclDeps] Uninstall package and dependent package(s). build Builds a package. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. @@ -301,6 +303,12 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.depsOnly = true else: wasFlagHandled = false + of actionUninstall: + case f + of "incldeps", "i": + result.uninstallRevDeps = true + else: + wasFlagHandled = false of actionCompile, actionDoc, actionBuild: let prefix = if kind == cmdShortOption: "-" else: "--" if val == "": diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 9fbde28..1261494 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -538,6 +538,10 @@ proc getPkgDest*(pkgInfo: PackageInfo, options: Options): string = let pkgDestDir = options.getPkgsDir() / (pkgInfo.name & versionStr) return pkgDestDir +proc `==`*(pkg1: PackageInfo, pkg2: PackageInfo): bool = + if pkg1.name == pkg2.name and pkg1.myPath == pkg2.myPath: + return true + when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == ("packagea", "0.1") diff --git a/src/nimblepkg/reversedeps.nim b/src/nimblepkg/reversedeps.nim index 551ee19..0da2a84 100644 --- a/src/nimblepkg/reversedeps.nim +++ b/src/nimblepkg/reversedeps.nim @@ -76,6 +76,19 @@ proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] = result.add(pkgTup) +proc getAllRevDeps*(options: Options, pkg: PackageInfo, result: var seq[PackageInfo]) = + if pkg in result: + return + + let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) + for rdepTup in getRevDeps(options, pkg): + for rdepInfo in findAllPkgs(installedPkgs, rdepTup): + if rdepInfo in result: + continue + + getAllRevDeps(options, rdepInfo, result) + result.add pkg + when isMainModule: var nimbleData = %{"reverseDeps": newJObject()} diff --git a/tests/tester.nim b/tests/tester.nim index 8a78216..372900e 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -568,6 +568,27 @@ suite "reverse dependencies": verify execNimbleYes("remove", "pkgA") verify execNimbleYes("remove", "mydep") + test "revdep fail test": + cd "revdep/mydep": + verify execNimbleYes("install") + + cd "revdep/pkgWithDep": + verify execNimbleYes("install") + + let (output, exitCode) = execNimble("uninstall", "mydep") + checkpoint output + check output.processOutput.inLines("cannot uninstall mydep") + check exitCode == QuitFailure + + test "revdep -i test": + cd "revdep/mydep": + verify execNimbleYes("install") + + cd "revdep/pkgWithDep": + verify execNimbleYes("install") + + verify execNimbleYes("remove", "mydep", "-i") + test "issue #373": cd "revdep/mydep": verify execNimbleYes("install") From 4be5308941653a2de4946083562d7932c9de6c29 Mon Sep 17 00:00:00 2001 From: Leorize Date: Sun, 20 Jan 2019 15:53:06 +0700 Subject: [PATCH 321/424] config: don't error out if no package list found --- src/nimblepkg/config.nim | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 78e3950..5706485 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -68,11 +68,12 @@ proc parseConfig*(): Config = var e = next(p) case e.kind of cfgEof: - if currentPackageList.urls.len == 0 and currentPackageList.path == "": - raise newException(NimbleError, "Package list '$1' requires either url or path" % currentPackageList.name) - if currentPackageList.urls.len > 0 and currentPackageList.path != "": - raise newException(NimbleError, "Attempted to specify `url` and `path` for the same package list '$1'" % currentPackageList.name) - addCurrentPkgList(result, currentPackageList) + if currentSection.len > 0: + if currentPackageList.urls.len == 0 and currentPackageList.path == "": + raise newException(NimbleError, "Package list '$1' requires either url or path" % currentPackageList.name) + if currentPackageList.urls.len > 0 and currentPackageList.path != "": + raise newException(NimbleError, "Attempted to specify `url` and `path` for the same package list '$1'" % currentPackageList.name) + addCurrentPkgList(result, currentPackageList) break of cfgSectionStart: addCurrentPkgList(result, currentPackageList) From 61e6afe16735ddb248f63288f80f315aabb42146 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 28 Jan 2019 23:42:38 -0800 Subject: [PATCH 322/424] brew doesn't require sudo --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index 00aa259..31ab0fc 100644 --- a/readme.markdown +++ b/readme.markdown @@ -727,7 +727,7 @@ installing your package (on macOS): ``` Hint: This package requires some external dependencies. Hint: To install them you may be able to run: - Hint: sudo brew install openssl + Hint: brew install openssl ``` ### Nim compiler From 3d6dc90cd4dfc12b8ae9d1958e84610cf21b34bb Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Thu, 31 Jan 2019 20:45:16 +0100 Subject: [PATCH 323/424] Strip whitespace from authentication token. My token had a newline in the file, resulting in the following HTTP request being made to Github: ``` GET /user HTTP/1.1 Host: api.github.com Connection: Keep-Alive authorization: token xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx content-type: application/x-www-form-urlencoded accept: */* user-agent: Nim httpclient/0.19.9 ``` Unfortunately the friendly error message returned by the Github server is lost in translation because getContent() throws an exception, never handling the body. --- src/nimblepkg/publish.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 0b07a07..2d73478 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -62,7 +62,7 @@ proc getGithubAuth(o: Options): Auth = # try to read from disk, if it cannot be found write a new one try: let apiTokenFilePath = cfg.nimbleDir / ApiKeyFile - result.token = readFile(apiTokenFilePath) + result.token = readFile(apiTokenFilePath).strip() display("Info:", "Using GitHub API Token in file: " & apiTokenFilePath, priority = HighPriority) except IOError: From 1678142723ef1f4b607c592ed9dc62e637834f12 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 14 Feb 2019 10:15:52 +0100 Subject: [PATCH 324/424] Fix regression in version string parsing (#563) --- src/nimblepkg/version.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index d86e22c..ae85e99 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -189,7 +189,7 @@ proc parseVersionRange*(s: string): VersionRange = of ' ': # Make sure '0.9 8.03' is not allowed. - if version != "" and i < s.len: + if version != "" and i < s.len - 1: if s[i+1] in {'0'..'9', '.'}: raise newException(ParseVersionError, "Whitespace is not allowed in a version literal.") From ee0bf06f01bf99e6bdf2cf14896a3edf91169b31 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 14 Feb 2019 10:54:43 +0100 Subject: [PATCH 325/424] Enforce the execution of the correct task types Fixes #533 --- src/nimble.nim | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 9456e78..cd87b84 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -214,7 +214,9 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = addRevDep(options.nimbleData, i, pkginfo) proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], - args: var seq[string]) = + args: var seq[string], options: Options) = + doAssert(options.action.typ == actionBuild) + ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, @@ -244,13 +246,14 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], exc.hint = hint raise exc -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool, + options: Options) = var args: seq[string] if forRelease: args = @["-d:release"] else: args = @[] - buildFromDir(pkgInfo, paths, args) + buildFromDir(pkgInfo, paths, args, options) proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. @@ -325,6 +328,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, ## to the packages this package depends on. ## The return value of this function is used by ## ``processDeps`` to gather a list of paths to pass to the nim compiler. + doAssert(options.action.typ == actionInstall) # Handle pre-`install` hook. if not options.depsOnly: @@ -356,7 +360,9 @@ 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: let paths = result.deps.map(dep => dep.getRealDir()) - buildFromDir(pkgInfo, paths, true) + let optsCopy = options.briefClone() + optsCopy.action.typ = actionBuild + buildFromDir(pkgInfo, paths, true, optsCopy) let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): @@ -470,8 +476,14 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options, proc install(packages: seq[PkgTuple], options: Options, doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] = + var optsCopy = options.briefClone() + optsCopy.action.typ = actionInstall + # Pass an empty seq here because we're executing `install` inside the package + # directory + optsCopy.action.packages = @[] + if packages == @[]: - result = installFromDir(getCurrentDir(), newVRAny(), options, "") + result = installFromDir(getCurrentDir(), newVRAny(), optsCopy, "") else: # Install each package. for pv in packages: @@ -480,7 +492,7 @@ proc install(packages: seq[PkgTuple], let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth, subdir, options) try: - result = installFromDir(downloadDir, pv.ver, options, url) + result = installFromDir(downloadDir, pv.ver, optsCopy, url) except BuildFailed: # The package failed to build. # Check if we tried building a tagged version of the package. @@ -507,7 +519,7 @@ proc build(options: Options) = let deps = processDeps(pkginfo, options) let paths = deps.map(dep => dep.getRealDir()) var args = options.action.compileOptions - buildFromDir(pkgInfo, paths, args) + buildFromDir(pkgInfo, paths, args, options) proc execBackend(options: Options) = let @@ -549,7 +561,8 @@ proc search(options: Options) = ## Searches for matches in ``options.action.search``. ## ## Searches are done in a case insensitive way making all strings lower case. - assert options.action.typ == actionSearch + doAssert(options.action.typ == actionSearch) + if options.action.search == @[]: raise newException(NimbleError, "Please specify a search string.") if needsRefresh(options): @@ -899,6 +912,8 @@ proc listTasks(options: Options) = nimscriptsupport.listTasks(nimbleFile, options) proc developFromDir(dir: string, options: Options) = + doAssert(options.action.typ == actionDevelop) + if options.depsOnly: raiseNimbleError("Cannot develop dependencies only.") From 2fc3efcd8444004de35d2b2a6adee926c82deb06 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 14 Feb 2019 11:07:52 +0100 Subject: [PATCH 326/424] Add before/after hooks for build action Fixes #606 --- src/nimble.nim | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index cd87b84..f1f3e9d 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -223,6 +223,11 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") let realDir = pkgInfo.getRealDir() + + cd realDir: + if not execHook(options, true): + raise newException(NimbleError, "Pre-hook prevented further execution.") + for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" @@ -246,6 +251,9 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], exc.hint = hint raise exc + cd realDir: + discard execHook(options, false) + proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool, options: Options) = var args: seq[string] @@ -360,7 +368,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: let paths = result.deps.map(dep => dep.getRealDir()) - let optsCopy = options.briefClone() + var optsCopy = options.briefClone() optsCopy.action.typ = actionBuild buildFromDir(pkgInfo, paths, true, optsCopy) From 1c8919092ef82d8319c21368b3ab432c3d8544e1 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 14 Feb 2019 11:32:00 +0100 Subject: [PATCH 327/424] Warn the user if no tests are found Fixes #558 --- src/nimble.nim | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/nimble.nim b/src/nimble.nim index f1f3e9d..f488e2c 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1016,6 +1016,11 @@ proc test(options: Options) = ## Executes all tests starting with 't' in the ``tests`` directory. ## Subdirectories are not walked. var files = toSeq(walkDir(getCurrentDir() / "tests")) + + if files.len < 1: + display("Warning:", "No tests found!", Warning, HighPriority) + return + files.sort((a, b) => cmp(a.path, b.path)) for file in files: From cd5db600dc7cd3a3306e5c0c4c56f2c399af29e1 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 14 Feb 2019 19:22:36 +0100 Subject: [PATCH 328/424] Fix problem in briefClone It was too brief. So brief that forgot to copy some important fields. --- src/nimblepkg/options.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 83700e8..749a4ed 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -409,5 +409,7 @@ proc briefClone*(options: Options): Options = var newOptions = initOptions() newOptions.config = options.config newOptions.nimbleData = options.nimbleData + newOptions.nimbleDir = options.nimbleDir + newOptions.forcePrompts = options.forcePrompts newOptions.pkgInfoCache = options.pkgInfoCache return newOptions From 5749f82ca51f4f1193be35d387ade7ce00058494 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 17 Mar 2019 11:27:50 +0000 Subject: [PATCH 329/424] Revert "Add before/after hooks for build action" This reverts commit 2fc3efcd8444004de35d2b2a6adee926c82deb06. --- src/nimble.nim | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index f488e2c..2b0d35a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -223,11 +223,6 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") let realDir = pkgInfo.getRealDir() - - cd realDir: - if not execHook(options, true): - raise newException(NimbleError, "Pre-hook prevented further execution.") - for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" @@ -251,9 +246,6 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], exc.hint = hint raise exc - cd realDir: - discard execHook(options, false) - proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool, options: Options) = var args: seq[string] @@ -368,7 +360,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: let paths = result.deps.map(dep => dep.getRealDir()) - var optsCopy = options.briefClone() + let optsCopy = options.briefClone() optsCopy.action.typ = actionBuild buildFromDir(pkgInfo, paths, true, optsCopy) From c6f1417099d02db6f24a7792e11c7aa7ac03fbea Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 17 Mar 2019 11:28:19 +0000 Subject: [PATCH 330/424] Revert "Enforce the execution of the correct task types" This reverts commit ee0bf06f01bf99e6bdf2cf14896a3edf91169b31. --- src/nimble.nim | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2b0d35a..e0b10f3 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -214,9 +214,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = addRevDep(options.nimbleData, i, pkginfo) proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], - args: var seq[string], options: Options) = - doAssert(options.action.typ == actionBuild) - + args: var seq[string]) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, @@ -246,14 +244,13 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], exc.hint = hint raise exc -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool, - options: Options) = +proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = var args: seq[string] if forRelease: args = @["-d:release"] else: args = @[] - buildFromDir(pkgInfo, paths, args, options) + buildFromDir(pkgInfo, paths, args) proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. @@ -328,7 +325,6 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, ## to the packages this package depends on. ## The return value of this function is used by ## ``processDeps`` to gather a list of paths to pass to the nim compiler. - doAssert(options.action.typ == actionInstall) # Handle pre-`install` hook. if not options.depsOnly: @@ -360,9 +356,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: let paths = result.deps.map(dep => dep.getRealDir()) - let optsCopy = options.briefClone() - optsCopy.action.typ = actionBuild - buildFromDir(pkgInfo, paths, true, optsCopy) + buildFromDir(pkgInfo, paths, true) let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): @@ -476,14 +470,8 @@ proc getDownloadInfo*(pv: PkgTuple, options: Options, proc install(packages: seq[PkgTuple], options: Options, doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] = - var optsCopy = options.briefClone() - optsCopy.action.typ = actionInstall - # Pass an empty seq here because we're executing `install` inside the package - # directory - optsCopy.action.packages = @[] - if packages == @[]: - result = installFromDir(getCurrentDir(), newVRAny(), optsCopy, "") + result = installFromDir(getCurrentDir(), newVRAny(), options, "") else: # Install each package. for pv in packages: @@ -492,7 +480,7 @@ proc install(packages: seq[PkgTuple], let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth, subdir, options) try: - result = installFromDir(downloadDir, pv.ver, optsCopy, url) + result = installFromDir(downloadDir, pv.ver, options, url) except BuildFailed: # The package failed to build. # Check if we tried building a tagged version of the package. @@ -519,7 +507,7 @@ proc build(options: Options) = let deps = processDeps(pkginfo, options) let paths = deps.map(dep => dep.getRealDir()) var args = options.action.compileOptions - buildFromDir(pkgInfo, paths, args, options) + buildFromDir(pkgInfo, paths, args) proc execBackend(options: Options) = let @@ -561,8 +549,7 @@ proc search(options: Options) = ## Searches for matches in ``options.action.search``. ## ## Searches are done in a case insensitive way making all strings lower case. - doAssert(options.action.typ == actionSearch) - + assert options.action.typ == actionSearch if options.action.search == @[]: raise newException(NimbleError, "Please specify a search string.") if needsRefresh(options): @@ -912,8 +899,6 @@ proc listTasks(options: Options) = nimscriptsupport.listTasks(nimbleFile, options) proc developFromDir(dir: string, options: Options) = - doAssert(options.action.typ == actionDevelop) - if options.depsOnly: raiseNimbleError("Cannot develop dependencies only.") From c8d79fc0228682677330a9f57d14389aaa641153 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 26 Mar 2019 10:06:06 +0100 Subject: [PATCH 331/424] update the installation instructions --- readme.markdown | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/readme.markdown b/readme.markdown index 31ab0fc..f246c7e 100644 --- a/readme.markdown +++ b/readme.markdown @@ -86,23 +86,6 @@ Simply execute the following command to compile and install Nimble. This will clone the Nimble repository, compile Nimble and copy it into Nim's bin directory. -The second approach is to install Nimble as a Nimble package. You can do this -by compiling Nimble, then running ``nimble install`` in Nimble's directory. - -``` -git clone https://github.com/nim-lang/nimble.git -cd nimble -nim c src/nimble -src/nimble install -``` - -**Note for Windows users**: You will need to rename ``nimble.exe`` after -compilation to something else like ``nimble1.exe``, then run -``src\nimble1.exe install``. - -This will install Nimble to the default Nimble packages location: -``~/.nimble/pkgs``. The binary will be installed to ``~/.nimble/bin``, so you -will need to add this directory to your PATH. ## Nimble usage From 6542c1ef161b4594387e6da8babe2087aec4adc8 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 29 Apr 2019 23:03:57 +0100 Subject: [PATCH 332/424] Squashed merge of #635 by @genotrance. Squashed commit of the following: commit e86a376f2faf9d26109405a3a9f73f986185f62d Author: Ganesh Viswanathan Date: Sun Apr 28 15:37:22 2019 -0500 Fix caching issue commit 640ce3f2e464e52668b5350fdc5a8fe506e79d38 Author: Ganesh Viswanathan Date: Thu Apr 25 18:38:48 2019 -0500 Clean up per feedback commit ae3ef9f7a0cbad574b725d1bc7a83bd6115e19cc Author: Ganesh Viswanathan Date: Thu Apr 25 16:39:26 2019 -0500 Fix for 0.19.4 commit 915d6b2be43e33bc51327585193b1899386ee250 Author: Ganesh Viswanathan Date: Thu Apr 25 16:13:42 2019 -0500 Keep nimscript separate, pin devel commit c278bd6ba09771dc079029a87e3a375998f0b447 Author: Ganesh Viswanathan Date: Mon Apr 22 14:57:44 2019 -0500 Hardcode version, json{}, code width 80, isScriptResultCached, no blank paramStr check commit 64e5489e256d5fc5abbfe3345789f65edf5980b7 Author: Ganesh Viswanathan Date: Wed Apr 17 21:07:03 2019 -0500 Remove compiler dependency commit a031fffd70c118c16eb3e16d3b1ed10472baf5d7 Author: Ganesh Viswanathan Date: Wed Apr 17 16:49:09 2019 -0500 Add devel to travis commit d49916e2a05b6bd7716f45bd8f74253fc8037827 Author: Ganesh Viswanathan Date: Wed Apr 17 16:43:14 2019 -0500 Interactive live, json to file commit 24131deea4693199922f9a5697aa3d072cceaee1 Author: Ganesh Viswanathan Date: Wed Apr 17 12:40:27 2019 -0500 Fix empty param, json echo commit b22fe37d47fd03367d49129ea4d2d56a779a6f26 Merge: 5cf0240 2942f11 Author: Ganesh Viswanathan Date: Tue Apr 16 22:23:17 2019 -0500 Merge branch 'nocompiler' of https://github.com/genotrance/nimble into nocompiler commit 5cf0240b728ab6ff4a39ddf629ba5833eb8985f5 Author: Ganesh Viswanathan Date: Tue Apr 16 22:23:06 2019 -0500 No hints, live output commit 2942f116c7774e0fa91f770cebde32bc431923a5 Author: Ganesh Viswanathan Date: Tue Apr 16 21:02:28 2019 -0500 Remove osx, test with stable commit 85f3865ef195c7b813f0b9e30b5cc8c9b2756518 Author: Ganesh Viswanathan Date: Tue Apr 16 18:19:42 2019 -0500 Remove ospaths, fix tests for Windows commit 74201bcfe4de00bdece5b31715618975f9ce8e6e Author: Ganesh Viswanathan Date: Tue Apr 16 14:00:14 2019 -0500 No success for missing task commit 8c2e65e223d32366b03004d9711364504c5d7916 Author: Ganesh Viswanathan Date: Tue Apr 16 13:44:32 2019 -0500 Fix packageName to name commit b05d9480281ebae7a0f5fd0331c8627bbf2a77d5 Author: Ganesh Viswanathan Date: Tue Apr 16 13:29:37 2019 -0500 Add switch support commit deecd903102a9baa5d4674cb9871cd9dbb658a04 Author: Ganesh Viswanathan Date: Tue Apr 16 12:24:01 2019 -0500 API cleanup, json setCommand fix commit 1e95fd4104ec3ffb69fe67b9c2fac23f991e163a Author: Ganesh Viswanathan Date: Tue Apr 16 10:45:12 2019 -0500 getParams once, hash nimscriptapi, fix loop in setcommand commit 51d03b3845cd562796bb32d41d5ad17cd09a91e7 Author: Ganesh Viswanathan Date: Tue Apr 16 07:21:32 2019 -0500 getPkgDir impl commit 7d0a40aa286d114d7557b229852f3c314795dc5d Author: Ganesh Viswanathan Date: Mon Apr 15 14:24:02 2019 -0500 Before/after hook info commit cbb3af3e970b20322030331d4849436b821f25ca Author: Ganesh Viswanathan Date: Mon Apr 15 13:44:56 2019 -0500 Remove nims from package dir after exec commit 0ed53d60bcdc8bb11beddb965590ed3ee63349d4 Author: Ganesh Viswanathan Date: Sat Apr 13 00:44:26 2019 -0500 Return bool from hooks commit ab38b81b81e68cfccf3ca84fd854422cd3733c84 Author: Ganesh Viswanathan Date: Fri Apr 12 23:20:13 2019 -0500 Initial version commit b9ef88b9f79b48435e7b4beeff959b4223f4b8ba Merge: 220ebae c8d79fc Author: Ganesh Viswanathan Date: Tue Mar 26 20:16:21 2019 -0500 Merge remote-tracking branch 'upstream/master' into nocompiler commit 220ebae355c945963591b002a43b262a70640aa5 Merge: 3d7227c 119be48 Author: Ganesh Viswanathan Date: Wed Dec 12 18:02:10 2018 -0600 Merge remote-tracking branch 'upstream/master' commit 3d7227c8900c205aada488d60565c90e17759639 Merge: cf7263d 66d79bf Author: Ganesh Viswanathan Date: Wed Oct 17 13:39:51 2018 -0500 Merge remote-tracking branch 'upstream/master' commit cf7263d6caf27ca4930ed54b05d4aa4f36e1dff1 Merge: 2fc3106 ee4c0ae Author: Ganesh Viswanathan Date: Thu Sep 13 23:03:41 2018 -0500 Merge remote-tracking branch 'upstream/master' commit 2fc310623b9f49ea012fc04fa09713fda140a7a3 Merge: e9a8850 c249f9b Author: Ganesh Viswanathan Date: Thu Apr 26 16:27:31 2018 -0500 Merge remote-tracking branch 'upstream/master' commit e9a885099b0b97bf3e0cddcde27e8c6b0bd51b10 Merge: 7adfd7b 75b7a21 Author: Ganesh Viswanathan Date: Thu Mar 8 14:26:46 2018 -0600 Merge remote-tracking branch 'upstream/master' commit 7adfd7be2b38a52886640579845de378139ca0cc Author: Ganesh Viswanathan Date: Mon Jan 15 00:35:55 2018 -0600 Updated fix for #398 commit de18319159b76a9da6765f35ea4d2e2c963d688a Merge: 93ba4a0 3dae264 Author: Ganesh Viswanathan Date: Sun Jan 14 22:01:20 2018 -0600 Merge remote-tracking branch 'upstream/master' commit 93ba4a00820ccb9a5362f0398cf3b5b4782bbefe Author: Ganesh Viswanathan Date: Sat Jan 13 19:52:34 2018 -0600 Fix for #398 --- .travis.yml | 14 +-- nimble.nimble | 14 +-- src/nimble.nim | 6 +- src/nimblepkg/nimscriptapi.nim | 155 +++++++++++++++++++++--- src/nimblepkg/nimscriptexecutor.nim | 4 +- src/nimblepkg/nimscriptwrapper.nim | 176 ++++++++++++++++++++++++++++ src/nimblepkg/packageinfo.nim | 2 +- src/nimblepkg/packageparser.nim | 20 +++- tests/caching/caching.nimble | 10 ++ tests/tester.nim | 44 +++++-- 10 files changed, 389 insertions(+), 56 deletions(-) mode change 100644 => 100755 src/nimblepkg/nimscriptapi.nim create mode 100755 src/nimblepkg/nimscriptwrapper.nim mode change 100644 => 100755 src/nimblepkg/packageparser.nim create mode 100644 tests/caching/caching.nimble diff --git a/.travis.yml b/.travis.yml index 4f39d6d..0e5d3a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,24 +1,24 @@ os: - linux -dist: trusty + - osx language: c +env: + - BRANCH=0.19.4 + - BRANCH=#4f9366975441be889a8cd4fbfb4e41f6830dc542 + cache: directories: - - "$HOME/.nimble" - - "$HOME/.choosenim" + - "$HOME/.choosenim/toolchains/nim-0.19.4" install: - - export CHOOSENIM_CHOOSE_VERSION="#7bb93c730ea87f" - - export NIM_LIB_PREFIX="$HOME/.choosenim/toolchains/nim-"$CHOOSENIM_CHOOSE_VERSION + - export CHOOSENIM_CHOOSE_VERSION=$BRANCH - | curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh sh init.sh -y before_script: - - set -e - - set -x - export CHOOSENIM_NO_ANALYTICS=1 - export PATH=$HOME/.nimble/bin:$PATH diff --git a/nimble.nimble b/nimble.nimble index 7a8e416..66c1b63 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,16 +1,6 @@ -import ospaths -template thisModuleFile: string = instantiationInfo(fullPaths = true).filename - -when fileExists(thisModuleFile.parentDir / "src/nimblepkg/common.nim"): - # In the git repository the Nimble sources are in a ``src`` directory. - import src/nimblepkg/common -else: - # When the package is installed, the ``src`` directory disappears. - import nimblepkg/common - # Package -version = nimbleVersion +version = "0.9.0" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" @@ -21,7 +11,7 @@ installExt = @["nim"] # Dependencies -requires "nim >= 0.13.0", "compiler#head" +requires "nim >= 0.13.0" when defined(nimdistros): import distros diff --git a/src/nimble.nim b/src/nimble.nim index e0b10f3..26f4a2a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -16,7 +16,7 @@ import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps, nimblepkg/nimscriptexecutor, nimblepkg/init -import nimblepkg/nimscriptsupport +import nimblepkg/nimscriptwrapper proc refresh(options: Options) = ## Downloads the package list from the specified URL. @@ -896,7 +896,7 @@ proc uninstall(options: Options) = proc listTasks(options: Options) = let nimbleFile = findNimbleFile(getCurrentDir(), true) - nimscriptsupport.listTasks(nimbleFile, options) + nimscriptwrapper.listTasks(nimbleFile, options) proc developFromDir(dir: string, options: Options) = if options.depsOnly: @@ -1103,7 +1103,7 @@ proc doAction(options: Options) = return let isPreDefined = options.action.command.normalize == "test" - var execResult: ExecutionResult[void] + var execResult: ExecutionResult[bool] if execCustom(options, execResult, failFast=not isPreDefined): if execResult.hasTaskRequestedCommand(): doAction(execResult.getOptionsForCommand(options)) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim old mode 100644 new mode 100755 index 0e0ce45..813c5d3 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -3,6 +3,9 @@ ## This module is implicitly imported in NimScript .nimble files. +import system except getCommand, setCommand, switch, `--` +import strformat, strutils, tables + var packageName* = "" ## Set this to the package name. It ## is usually not required to do that, nims' filename is @@ -22,30 +25,134 @@ var foreignDeps*: seq[string] = @[] ## The foreign dependencies. Only ## exported for 'distros.nim'. + beforeHooks: seq[string] = @[] + afterHooks: seq[string] = @[] + commandLineParams: seq[string] = @[] + flags: TableRef[string, seq[string]] + + command = "e" + project = "" + success = false + retVal = true + projectFile = "" + proc requires*(deps: varargs[string]) = ## Call this to set the list of requirements of your Nimble ## package. for d in deps: requiresData.add(d) +proc getParams() = + for i in 2 .. paramCount(): + let + param = paramStr(i) + if param.fileExists(): + projectFile = param + elif param[0] != '-': + commandLineParams.add paramStr(i).normalize + +proc getCommand*(): string = + return command + +proc setCommand*(cmd: string, prj = "") = + command = cmd + if prj.len != 0: + project = prj + +proc switch*(key: string, value="") = + if flags.isNil: + flags = newTable[string, seq[string]]() + + if flags.hasKey(key): + flags[key].add(value) + else: + flags[key] = @[value] + +template `--`*(key, val: untyped) = + switch(astToStr(key), strip astToStr(val)) + +template `--`*(key: untyped) = + switch(astToStr(key), "") + +template printIfLen(varName) = + if varName.len != 0: + iniOut &= astToStr(varName) & ": \"" & varName & "\"\n" + +template printSeqIfLen(varName) = + if varName.len != 0: + iniOut &= astToStr(varName) & ": \"" & varName.join(", ") & "\"\n" + +proc printPkgInfo() = + if backend.len == 0: + backend = "c" + + var + iniOut = "[Package]\n" + if packageName.len != 0: + iniOut &= "name: \"" & packageName & "\"\n" + printIfLen version + printIfLen author + printIfLen description + printIfLen license + printIfLen srcdir + printIfLen binDir + printIfLen backend + + printSeqIfLen skipDirs + printSeqIfLen skipFiles + printSeqIfLen skipExt + printSeqIfLen installDirs + printSeqIfLen installFiles + printSeqIfLen installExt + printSeqIfLen bin + printSeqIfLen beforeHooks + printSeqIfLen afterHooks + + if requiresData.len != 0: + iniOut &= "\n[Deps]\n" + iniOut &= &"requires: \"{requiresData.join(\", \")}\"\n" + + echo iniOut + +proc onExit*() = + if "printPkgInfo".normalize in commandLineParams: + printPkgInfo() + else: + var + output = "" + output &= "\"success\": " & $success & ", " + output &= "\"command\": \"" & command & "\", " + if project.len != 0: + output &= "\"project\": \"" & project & "\", " + if not flags.isNil and flags.len != 0: + output &= "\"flags\": {" + for key, val in flags.pairs: + output &= "\"" & key & "\": [" + for v in val: + output &= "\"" & v & "\", " + output = output[0 .. ^3] & "], " + output = output[0 .. ^3] & "}, " + + output &= "\"retVal\": " & $retVal + + writeFile(projectFile & ".out", "{" & output & "}") + # TODO: New release of Nim will move this `task` template under a # `when not defined(nimble)`. This will allow us to override it in the future. -when not declared(task): - template task*(name: untyped; description: string; body: untyped): untyped = - ## Defines a task. Hidden tasks are supported via an empty description. - ## Example: - ## - ## .. code-block:: nim - ## task build, "default build is via the C backend": - ## setCommand "c" - proc `name Task`*() = body +template task*(name: untyped; description: string; body: untyped): untyped = + ## Defines a task. Hidden tasks are supported via an empty description. + ## Example: + ## + ## .. code-block:: nim + ## task build, "default build is via the C backend": + ## setCommand "c" + proc `name Task`*() = body - let cmd = getCommand() - if cmd.len == 0 or cmd == "help": - setCommand "help" - echo(astToStr(name), " ", description) - elif cmd == astToStr(name): - setCommand "nop" - `name Task`() + if commandLineParams.len == 0 or "help" in commandLineParams: + success = true + echo(astToStr(name), " ", description) + elif astToStr(name).normalize in commandLineParams: + success = true + `name Task`() template before*(action: untyped, body: untyped): untyped = ## Defines a block of code which is evaluated before ``action`` is executed. @@ -53,15 +160,27 @@ template before*(action: untyped, body: untyped): untyped = result = true body + beforeHooks.add astToStr(action) + + if (astToStr(action) & "Before").normalize in commandLineParams: + success = true + retVal = `action Before`() + template after*(action: untyped, body: untyped): untyped = ## Defines a block of code which is evaluated after ``action`` is executed. proc `action After`*(): bool = result = true body -template builtin = discard + afterHooks.add astToStr(action) + + if (astToStr(action) & "After").normalize in commandLineParams: + success = true + retVal = `action After`() proc getPkgDir*(): string = ## Returns the package directory containing the .nimble file currently ## being evaluated. - builtin + result = projectFile.rsplit(seps={'/', '\\', ':'}, maxsplit=1)[0] + +getParams() diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim index 70fc165..fad0d1e 100644 --- a/src/nimblepkg/nimscriptexecutor.nim +++ b/src/nimblepkg/nimscriptexecutor.nim @@ -3,7 +3,7 @@ import os, tables, strutils, sets -import packageparser, common, packageinfo, options, nimscriptsupport, cli +import packageparser, common, packageinfo, options, nimscriptwrapper, cli proc execHook*(options: Options, before: bool): bool = ## Returns whether to continue. @@ -31,7 +31,7 @@ proc execHook*(options: Options, before: bool): bool = result = res.retVal proc execCustom*(options: Options, - execResult: var ExecutionResult[void], + execResult: var ExecutionResult[bool], failFast = true): bool = ## Executes the custom command using the nimscript backend. ## diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim new file mode 100755 index 0000000..44d6b81 --- /dev/null +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -0,0 +1,176 @@ +# Copyright (C) Andreas Rumpf. All rights reserved. +# BSD License. Look at license.txt for more info. + +## Implements the new configuration system for Nimble. Uses Nim as a +## scripting language. + +import common, version, options, packageinfo, cli +import hashes, json, os, streams, strutils, strtabs, + tables, times, osproc, sets, pegs + +type + Flags = TableRef[string, seq[string]] + ExecutionResult*[T] = object + success*: bool + command*: string + arguments*: seq[string] + flags*: Flags + retVal*: T + +const + internalCmd = "e" + nimscriptApi = staticRead("nimscriptapi.nim") + +proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, + live = true): tuple[output: string, exitCode: int] = + let + shash = $projectDir.hash().abs() + nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & shash & ".nims" + + let + isScriptResultCopied = + nimsFileCopied.fileExists() and + nimsFileCopied.getLastModificationTime() >= nimsFile.getLastModificationTime() + + if not isScriptResultCopied: + nimsFile.copyFile(nimsFileCopied) + + defer: + nimsFileCopied.removeFile() + + let + cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & + " " & nimsFileCopied.quoteShell & " " & actionName).strip() + + if live: + result.exitCode = execCmd(cmd) + let + outFile = nimsFileCopied & ".out" + if outFile.fileExists(): + result.output = outFile.readFile() + discard outFile.tryRemoveFile() + else: + result = execCmdEx(cmd, options = {poUsePath}) + +proc getNimsFile(scriptName: string, options: Options): string = + let + cacheDir = getTempDir() / "nimblecache" + shash = $scriptName.parentDir().hash().abs() + prjCacheDir = cacheDir / scriptName.splitFile().name & "_" & shash + + result = prjCacheDir / scriptName.extractFilename().changeFileExt ".nims" + +proc setupNimscript(scriptName: string, options: Options) = + let + cacheDir = getTempDir() / "nimblecache" + nimscriptApiFile = cacheDir / "nimscriptapi.nim" + nimsFile = getNimsFile(scriptName, options) + + let + isNimscriptApiCached = + nimscriptApiFile.fileExists() and nimscriptApiFile.getLastModificationTime() > + getAppFilename().getLastModificationTime() + + isScriptResultCached = + nimsFile.fileExists() and nimsFile.getLastModificationTime() > + scriptName.getLastModificationTime() + + if not isNimscriptApiCached: + createDir(cacheDir) + writeFile(nimscriptApiFile, nimscriptApi) + + if not isScriptResultCached: + createDir(nimsFile.parentDir()) + writeFile(nimsFile, """ +import system except getCommand, setCommand, switch, `--`, + packageName, version, author, description, license, srcDir, binDir, backend, + skipDirs, skipFiles, skipExt, installDirs, installFiles, installExt, bin, foreignDeps, + requires, task, packageName +""" & + "import nimscriptapi, strutils\n" & scriptName.readFile() & "\nonExit()\n") + +proc getIniFile*(scriptName: string, options: Options): string = + let + nimsFile = getNimsFile(scriptName, options) + + result = nimsFile.changeFileExt(".ini") + + let + isIniResultCached = + result.fileExists() and result.getLastModificationTime() > + scriptName.getLastModificationTime() + + if not isIniResultCached: + setupNimscript(scriptName, options) + let + (output, exitCode) = + execNimscript(nimsFile, scriptName.parentDir(), "printPkgInfo", options, live=false) + + if exitCode == 0 and output.len != 0: + result.writeFile(output) + else: + raise newException(NimbleError, output & "\nprintPkgInfo() failed") + +proc execScript(scriptName, actionName: string, options: Options): + ExecutionResult[bool] = + let + nimsFile = getNimsFile(scriptName, options) + + if not nimsFile.fileExists(): + setupNimScript(scriptName, options) + + let + (output, exitCode) = execNimscript(nimsFile, scriptName.parentDir(), actionName, options) + + if exitCode != 0: + raise newException(NimbleError, output) + + let + j = + if output.len != 0: + parseJson(output) + else: + parseJson("{}") + + result.flags = newTable[string, seq[string]]() + result.success = j{"success"}.getBool() + result.command = j{"command"}.getStr() + if "project" in j: + result.arguments.add j["project"].getStr() + if "flags" in j: + for flag, vals in j["flags"].pairs: + result.flags[flag] = @[] + for val in vals.items(): + result.flags[flag].add val.getStr() + result.retVal = j{"retVal"}.getBool() + +proc execTask*(scriptName, taskName: string, + options: Options): ExecutionResult[bool] = + ## Executes the specified task in the specified script. + ## + ## `scriptName` should be a filename pointing to the nimscript file. + display("Executing", "task $# in $#" % [taskName, scriptName], + priority = HighPriority) + + result = execScript(scriptName, taskName, options) + +proc execHook*(scriptName, actionName: string, before: bool, + options: Options): ExecutionResult[bool] = + ## Executes the specified action's hook. Depending on ``before``, either + ## the "before" or the "after" hook. + ## + ## `scriptName` should be a filename pointing to the nimscript file. + let hookName = + if before: actionName.toLowerAscii & "Before" + else: actionName.toLowerAscii & "After" + display("Attempting", "to execute hook $# in $#" % [hookName, scriptName], + priority = MediumPriority) + + result = execScript(scriptName, hookName, options) + +proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = + ## Determines whether the last executed task used ``setCommand`` + return execResult.command != internalCmd + +proc listTasks*(scriptName: string, options: Options) = + discard execScript(scriptName, "", options) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 1261494..c54b97d 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -324,7 +324,7 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options): seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = ## Gets a list of installed packages. The resulting package info is ## minimal. This has the advantage that it does not depend on the - ## ``packageparser`` module, and so can be used by ``nimscriptsupport``. + ## ``packageparser`` module, and so can be used by ``nimscriptwrapper``. ## ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ (options.getPkgsDir) result = @[] diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim old mode 100644 new mode 100755 index cf77dcc..5c034eb --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,12 +1,12 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, json, streams, strutils, parseutils, os, tables, sugar +import parsecfg, json, sets, streams, strutils, parseutils, os, tables, sugar from sequtils import apply, map -import version, tools, common, nimscriptsupport, options, packageinfo, cli +import version, tools, common, nimscriptwrapper, options, packageinfo, cli ## Contains procedures for parsing .nimble files. Moved here from ``packageinfo`` -## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also +## because it depends on ``nimscriptwrapper`` (``nimscriptwrapper`` also ## depends on other procedures in ``packageinfo``. type @@ -259,6 +259,12 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = case result.backend.normalize of "javascript": result.backend = "js" else: discard + of "beforehooks": + for i in ev.value.multiSplit: + result.preHooks.incl(i.normalize) + of "afterhooks": + for i in ev.value.multiSplit: + result.postHooks.incl(i.normalize) else: raise newException(NimbleError, "Invalid field: " & ev.key) of "deps", "dependencies": @@ -277,6 +283,14 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = else: raise newException(ValueError, "Cannot open package info: " & path) +proc readPackageInfoFromNims(scriptName: string, options: Options, + result: var PackageInfo) = + let + iniFile = getIniFile(scriptName, options) + + if iniFile.fileExists(): + readPackageInfoFromNimble(iniFile, result) + proc inferInstallRules(pkgInfo: var PackageInfo, options: Options) = # Binary packages shouldn't install .nim files by default. # (As long as the package info doesn't explicitly specify what should be diff --git a/tests/caching/caching.nimble b/tests/caching/caching.nimble new file mode 100644 index 0000000..d3035a9 --- /dev/null +++ b/tests/caching/caching.nimble @@ -0,0 +1,10 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Test package" +license = "BSD" + +# Dependencies + +requires "nim >= 0.12.1" diff --git a/tests/tester.nim b/tests/tester.nim index 372900e..b57ab18 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -36,9 +36,13 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = quotedArgs.add("--nimbleDir:" & installDir) quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\"")) - let path = getCurrentDir().parentDir() / "src" + let path {.used.} = getCurrentDir().parentDir() / "src" - var cmd = "PATH=" & path & ":$PATH " & quotedArgs.join(" ") + var cmd = + when not defined(windows): + "PATH=" & path & ":$PATH " & quotedArgs.join(" ") + else: + quotedArgs.join(" ") when defined(macosx): # TODO: Yeah, this is really specific to my machine but for my own sanity... cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib " & cmd @@ -67,6 +71,17 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +test "caching works": + cd "caching": + var (output, exitCode) = execNimble("dump") + check output.contains("0.1.0") + let + nfile = "caching.nimble" + writeFile(nfile, readFile(nfile).replace("0.1.0", "0.2.0")) + (output, exitCode) = execNimble("dump") + check output.contains("0.2.0") + writeFile(nfile, readFile(nfile).replace("0.2.0", "0.1.0")) + test "picks #head when looking for packages": cd "versionClashes" / "aporiaScenario": let (output, exitCode) = execNimble("install", "-y", "--verbose") @@ -213,7 +228,7 @@ test "can refresh with local package list": [PackageList] name = "local" path = "$1" - """.unindent % (getCurrentDir() / "issue368" / "packages.json")) + """.unindent % (getCurrentDir() / "issue368" / "packages.json").replace("\\", "\\\\")) let (output, exitCode) = execNimble(["refresh", "--verbose"]) let lines = output.strip.processOutput() check inLines(lines, "config file at") @@ -258,9 +273,9 @@ suite "nimscript": check exitCode == QuitSuccess let lines = output.strip.processOutput() check lines[0].startsWith("Before PkgDir:") - check lines[0].endsWith("tests/nimscript") + check lines[0].endsWith("tests" / "nimscript") check lines[^1].startsWith("After PkgDir:") - check lines[^1].endsWith("tests/nimbleDir/pkgs/nimscript-0.1.0") + check lines[^1].endsWith("tests" / "nimbleDir" / "pkgs" / "nimscript-0.1.0") test "can execute nimscript tasks": cd "nimscript": @@ -412,6 +427,9 @@ test "issue #349": ] proc checkName(name: string) = + when defined(windows): + if name.toLowerAscii() in @["con", "nul"]: + return let (outp, code) = execNimble("init", "-y", name) let msg = outp.strip.processOutput() check code == QuitFailure @@ -526,9 +544,15 @@ suite "can handle two binary versions": cd "binaryPackage/v2": check execNimble("install", "-y").exitCode == QuitSuccess + var + cmd = installDir / "bin" / "binaryPackage" + + when defined(windows): + cmd = "cmd /c " & cmd & ".cmd" + test "can execute v2": let (output, exitCode) = - execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + execCmdEx(cmd) check exitCode == QuitSuccess check output.strip() == "v2" @@ -536,7 +560,7 @@ suite "can handle two binary versions": check execNimble("remove", "binaryPackage@2.0", "-y").exitCode==QuitSuccess let (output, exitCode) = - execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + execCmdEx(cmd) check exitCode == QuitSuccess check output.strip() == "v1" @@ -544,7 +568,7 @@ suite "can handle two binary versions": check execNimble("remove", "binaryPackage@1.0", "-y").exitCode==QuitSuccess let (output, exitCode) = - execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt)) + execCmdEx(cmd) check exitCode == QuitSuccess check output.strip() == "v2" @@ -678,9 +702,9 @@ suite "path command": test "can get correct path for srcDir (#531)": check execNimble("uninstall", "srcdirtest", "-y").exitCode == QuitSuccess cd "develop/srcdirtest": - let (output, exitCode) = execNimble("install", "-y") + let (_, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess - let (output, exitCode) = execNimble("path", "srcdirtest") + let (output, _) = execNimble("path", "srcdirtest") check output.strip() == installDir / "pkgs" / "srcdirtest-1.0" suite "test command": From ca779afb208bfdb4d81567130ae497b4051440c5 Mon Sep 17 00:00:00 2001 From: genotrance Date: Tue, 30 Apr 2019 14:59:12 -0500 Subject: [PATCH 333/424] Fix quoted switch, multi-line description, more caching (#642) * Fix quoted switch, multi-line description, more caching * Incorporate feedback --- src/nimblepkg/nimscriptapi.nim | 6 ++++-- src/nimblepkg/nimscriptwrapper.nim | 18 ++++++------------ tests/nimscript/nimscript.nimble | 6 +++++- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 813c5d3..eba18cd 100755 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -75,7 +75,7 @@ template `--`*(key: untyped) = template printIfLen(varName) = if varName.len != 0: - iniOut &= astToStr(varName) & ": \"" & varName & "\"\n" + iniOut &= astToStr(varName) & ": \"\"\"" & varName & "\"\"\"\n" template printSeqIfLen(varName) = if varName.len != 0: @@ -128,7 +128,9 @@ proc onExit*() = for key, val in flags.pairs: output &= "\"" & key & "\": [" for v in val: - output &= "\"" & v & "\", " + let v = if v.len > 0 and v[0] == '"': strutils.unescape(v) + else: v + output &= v.escape & ", " output = output[0 .. ^3] & "], " output = output[0 .. ^3] & "}, " diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 44d6b81..4002361 100755 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -57,22 +57,19 @@ proc getNimsFile(scriptName: string, options: Options): string = cacheDir = getTempDir() / "nimblecache" shash = $scriptName.parentDir().hash().abs() prjCacheDir = cacheDir / scriptName.splitFile().name & "_" & shash + nimscriptApiFile = cacheDir / "nimscriptapi.nim" result = prjCacheDir / scriptName.extractFilename().changeFileExt ".nims" -proc setupNimscript(scriptName: string, options: Options) = let - cacheDir = getTempDir() / "nimblecache" - nimscriptApiFile = cacheDir / "nimscriptapi.nim" - nimsFile = getNimsFile(scriptName, options) + iniFile = result.changeFileExt(".ini") - let isNimscriptApiCached = nimscriptApiFile.fileExists() and nimscriptApiFile.getLastModificationTime() > getAppFilename().getLastModificationTime() isScriptResultCached = - nimsFile.fileExists() and nimsFile.getLastModificationTime() > + isNimscriptApiCached and result.fileExists() and result.getLastModificationTime() > scriptName.getLastModificationTime() if not isNimscriptApiCached: @@ -80,14 +77,15 @@ proc setupNimscript(scriptName: string, options: Options) = writeFile(nimscriptApiFile, nimscriptApi) if not isScriptResultCached: - createDir(nimsFile.parentDir()) - writeFile(nimsFile, """ + createDir(result.parentDir()) + writeFile(result, """ import system except getCommand, setCommand, switch, `--`, packageName, version, author, description, license, srcDir, binDir, backend, skipDirs, skipFiles, skipExt, installDirs, installFiles, installExt, bin, foreignDeps, requires, task, packageName """ & "import nimscriptapi, strutils\n" & scriptName.readFile() & "\nonExit()\n") + discard tryRemoveFile(iniFile) proc getIniFile*(scriptName: string, options: Options): string = let @@ -101,7 +99,6 @@ proc getIniFile*(scriptName: string, options: Options): string = scriptName.getLastModificationTime() if not isIniResultCached: - setupNimscript(scriptName, options) let (output, exitCode) = execNimscript(nimsFile, scriptName.parentDir(), "printPkgInfo", options, live=false) @@ -116,9 +113,6 @@ proc execScript(scriptName, actionName: string, options: Options): let nimsFile = getNimsFile(scriptName, options) - if not nimsFile.fileExists(): - setupNimScript(scriptName, options) - let (output, exitCode) = execNimscript(nimsFile, scriptName.parentDir(), actionName, options) diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index 4625abb..f27631a 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -2,7 +2,9 @@ version = "0.1.0" author = "Dominik Picheta" -description = "Test package" +description = """Test package +with multi-line description +""" license = "BSD" bin = @["nimscript"] @@ -24,6 +26,8 @@ task cr, "Testing `nimble c -r nimscript.nim` via setCommand": task repeated, "Testing `nimble c nimscript.nim` with repeated flags": --define: foo --define: bar + --define: "quoted" + --define: "quoted\\\"with\\\"quotes" setCommand "c", "nimscript.nim" task api, "Testing nimscriptapi module functionality": From deb20ee57a71476610a3cc6e149c04d1b8c0a74f Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 30 Apr 2019 21:29:04 -0500 Subject: [PATCH 334/424] Print nimscript errors --- src/nimblepkg/nimscriptwrapper.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 4002361..f0b2f86 100755 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -50,7 +50,7 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, result.output = outFile.readFile() discard outFile.tryRemoveFile() else: - result = execCmdEx(cmd, options = {poUsePath}) + result = execCmdEx(cmd, options = {poUsePath, poStdErrToStdOut}) proc getNimsFile(scriptName: string, options: Options): string = let From 83a1cceb4eaa473560a356b911d8ac1866587512 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Thu, 2 May 2019 13:42:59 -0500 Subject: [PATCH 335/424] Fix for recursive nimble calls --- src/nimblepkg/nimscriptwrapper.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index f0b2f86..0956b79 100755 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -36,7 +36,9 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, nimsFile.copyFile(nimsFileCopied) defer: - nimsFileCopied.removeFile() + # Only if copied in this invocation, allows recursive calls of nimble + if not isScriptResultCopied: + nimsFileCopied.removeFile() let cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & From dcf99adf91c57cd218eec372eeee49a5242ce4b1 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 3 May 2019 13:06:42 -0500 Subject: [PATCH 336/424] Test case for #645 - recursive --- tests/recursive/recursive.nimble | 21 +++++++++++++++++++++ tests/tester.nim | 4 ++++ 2 files changed, 25 insertions(+) create mode 100644 tests/recursive/recursive.nimble diff --git a/tests/recursive/recursive.nimble b/tests/recursive/recursive.nimble new file mode 100644 index 0000000..ec09ab9 --- /dev/null +++ b/tests/recursive/recursive.nimble @@ -0,0 +1,21 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "Test package" +license = "BSD" + +# Dependencies + +requires "nim >= 0.12.1" + +task recurse, "Level 1": + echo 1 + exec "nimble recurse2" + +task recurse2, "Level 2": + echo 2 + exec "nimble recurse3" + +task recurse3, "Level 3": + echo 3 diff --git a/tests/tester.nim b/tests/tester.nim index b57ab18..1106998 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -82,6 +82,10 @@ test "caching works": check output.contains("0.2.0") writeFile(nfile, readFile(nfile).replace("0.2.0", "0.1.0")) +test "recursion works": + cd "recursive": + check execNimble("recurse").exitCode == QuitSuccess + test "picks #head when looking for packages": cd "versionClashes" / "aporiaScenario": let (output, exitCode) = execNimble("install", "-y", "--verbose") From 5b94a1b70cf0666cc6b21a3c504b98e6146ea818 Mon Sep 17 00:00:00 2001 From: Julian Fondren Date: Sat, 4 May 2019 18:58:12 -0500 Subject: [PATCH 337/424] test -c,--continue option to continue tests on error --- src/nimble.nim | 19 ++++++++++++++++--- src/nimblepkg/options.nim | 5 +++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e0b10f3..f1034df 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -992,7 +992,9 @@ proc develop(options: Options) = proc test(options: Options) = ## Executes all tests starting with 't' in the ``tests`` directory. ## Subdirectories are not walked. - var files = toSeq(walkDir(getCurrentDir() / "tests")) + var + files = toSeq(walkDir(getCurrentDir() / "tests")) + tests, failures: int if files.len < 1: display("Warning:", "No tests found!", Warning, HighPriority) @@ -1014,7 +1016,14 @@ proc test(options: Options) = binFileName = file.path.changeFileExt(ExeExt) existsBefore = existsFile(binFileName) - execBackend(optsCopy) + if options.continueTestsOnFailure: + inc tests + try: + execBackend(optsCopy) + except NimbleError: + inc failures + else: + execBackend(optsCopy) let existsAfter = existsFile(binFileName) @@ -1022,7 +1031,11 @@ proc test(options: Options) = if canRemove: removeFile(binFileName) - display("Success:", "All tests passed", Success, HighPriority) + if failures == 0: + display("Success:", "All tests passed", Success, HighPriority) + else: + let error = "Only " & $(tests - failures) & "/" & $tests & " tests passed" + display("Error:", error, Error, HighPriority) proc check(options: Options) = ## Validates a package a in the current working directory. diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 749a4ed..70924bd 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -23,6 +23,7 @@ type showVersion*: bool noColor*: bool disableValidation*: bool + continueTestsOnFailure*: bool ## Whether packages' repos should always be downloaded with their history. forceFullClone*: bool @@ -77,6 +78,7 @@ Commands: c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. test Compiles and executes tests + [-c, --continue] Don't stop execution on a failed test. doc, doc2 [opts, ...] f.nim Builds documentation for a file inside a package. Passes options to the Nim compiler. refresh [url] Refreshes the package list. A package list URL @@ -316,6 +318,9 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = else: result.action.compileOptions.add(prefix & flag & ":" & val) of actionCustom: + if result.action.command.normalize == "test": + if f == "continue" or f == "c": + result.continueTestsOnFailure = true result.action.flags[flag] = val else: wasFlagHandled = false From b2e31fb012458ef7e2a0dab86dfc869329504b29 Mon Sep 17 00:00:00 2001 From: Julian Fondren Date: Sat, 4 May 2019 19:30:55 -0500 Subject: [PATCH 338/424] use displayLine rather than display with displayCategory prompt --- src/nimblepkg/cli.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index d8d52d5..8d96015 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -140,7 +140,7 @@ proc prompt*(forcePrompts: ForcePrompt, question: string): bool = display("Prompt:", question & " -> [forced no]", Warning, HighPriority) return false of dontForcePrompt: - display("Prompt:", question & " [y/N]", Warning, HighPriority) + displayLine("Prompt:", question & " [y/N]", Warning, HighPriority) displayCategory("Answer:", Warning, HighPriority) let yn = stdin.readLine() case yn.normalize From cf7c1471217323893059f750da5ac82b096addda Mon Sep 17 00:00:00 2001 From: Christopher Dunn Date: Sat, 25 May 2019 16:59:53 -0500 Subject: [PATCH 339/424] Choose USER-specific tmpdir re: #80 --- src/nimblepkg/nimscriptsupport.nim | 4 ++-- src/nimblepkg/publish.nim | 2 +- src/nimblepkg/tools.nim | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 2806251..4c8747b 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -15,7 +15,7 @@ from compiler/scriptconfig import setupVM from compiler/astalgo import strTableGet import compiler/options as compiler_options -import common, version, options, packageinfo, cli +import common, version, options, packageinfo, cli, tools import os, strutils, strtabs, tables, times, osproc, sets, pegs when not declared(resetAllModulesHard): @@ -382,7 +382,7 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = # Ensure that "nimblepkg/nimscriptapi" is in the PATH. block: - let t = getTempDir() / "nimblecache" + let t = getNimbleUserTempDir() / "nimblecache" let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim" createDir(tmpNimscriptApiPath.splitFile.dir) writeFile(tmpNimscriptApiPath, nimscriptApi) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 2d73478..333bbbd 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -155,7 +155,7 @@ proc editJson(p: PackageInfo; url, tags, downloadMethod: string) = proc publish*(p: PackageInfo, o: Options) = ## Publishes the package p. let auth = getGithubAuth(o) - var pkgsDir = getTempDir() / "nimble-packages-fork" + var pkgsDir = getNimbleUserTempDir() / "nimble-packages-fork" if not forkExists(auth): createFork(auth) display("Info:", "Waiting 10s to let Github create a fork", diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 8dc71e2..2073154 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -162,3 +162,17 @@ proc getNimbleTempDir*(): string = result.add($GetCurrentProcessId()) else: result.add($getpid()) + +proc getNimbleUserTempDir*(): string = + ## Returns a path to a temporary directory. + ## + ## The returned path will be the same for the duration of the process but + ## different for different runs of it. You have to make sure to create it + ## first. In release builds the directory will be removed when nimble finishes + ## its work. + var tmpdir: string + if existsEnv("TMPDIR") and existsEnv("USER"): + tmpdir = joinPath(getEnv("TMPDIR"), getEnv("USER")) + else: + tmpdir = getTempDir() + return tmpdir From 06b9b494496a622cd444e992142af4cdbcfca416 Mon Sep 17 00:00:00 2001 From: genotrance Date: Mon, 27 May 2019 13:29:19 -0500 Subject: [PATCH 340/424] Update to 0.10.0 (#657) * Update changelog for 0.10.0 * Multi-user systems * Minor fixes * Update changelog.markdown --- changelog.markdown | 33 +++++++++++++++++++++++++++++++++ nimble.nimble | 2 +- src/nimblepkg/common.nim | 2 +- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/changelog.markdown b/changelog.markdown index 2b1e385..1f417e6 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,39 @@ # Nimble changelog +## 0.10.0 - 27/05/2019 + +Nimble now uses the Nim compiler directly via `nim e` to execute nimble +scripts rather than embedding the Nim VM. This has multiple benefits: +- Evolve independently from Nim enabling new versions of Nimble to work + with multiple versions of Nim. +- Inherit all nimscript enhancements and bug fixes rather than having to + duplicate functionality. +- Fast build time and smaller binary. +- No dependency on the compiler package which could cause dependency issues + when nimble is used as a package. + +Several other features and fixes have been implemented to improve general +development and test workflows. +- `nimble test` now sports a `-continue` or `-c` flag that allows tests + to continue on failure, removes all created test binaries on completion + and warns if no tests found. +- The `--inclDeps` or `-i` flag enables `nimble uninstall` to remove all + dependent packages during uninstall. +- Added documentation on the usage of a custom `nimbleDir`. +- Package type interactive prompt is more readable. +- Save temporary files in a per-user temp dir to enable Nimble on multi-user + systems. +- CTRL-C is now handled correctly in interactive prompts. +- Fixed issue where empty package list led to error. +- Fixed issue where file:// was prepended incorrectly. +- Fixed miscellaneous issues in version parsing, Github auth and briefClone. +- Miscellaneous cleanup of deprecated procs. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.9.0...v0.10.0 + ## 0.9.0 - 19/09/2018 This is a major new release which contains at least one breaking change. diff --git a/nimble.nimble b/nimble.nimble index 66c1b63..8de754f 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,6 @@ # Package -version = "0.9.0" +version = "0.10.0" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 19faed5..676a2ff 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.9.0" + nimbleVersion* = "0.10.0" From 9beb6e1529546f82d50c1b1bfdc20ca79cc41174 Mon Sep 17 00:00:00 2001 From: Taylor Rose <3nki.nam.shub@gmail.com> Date: Wed, 29 May 2019 19:38:53 -0400 Subject: [PATCH 341/424] Add backend selection to nimble init --- src/nimble.nim | 9 +++++++++ src/nimblepkg/init.nim | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 94e677a..2eda5c5 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -802,6 +802,14 @@ This should ideally be a valid SPDX identifier. See https://spdx.org/licenses/. Please specify a valid SPDX identifier.""", "MIT" ) + var pkgBackend = options.promptList( + """Package Backend? +c - Compile using C backend. +cpp - Compile using C++ backend. +objc - Compile using Objective-C backend. +js - Compile using JavaScript backend.""", + ["c", "cpp", "objc", "js"] + ) # Ask for Nim dependency let nimDepDef = getNimrodVersion() @@ -816,6 +824,7 @@ Please specify a valid SPDX identifier.""", pkgAuthor, pkgDesc, pkgLicense, + pkgBackend, pkgSrcDir, pkgNimDep, pkgType diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 42c7f4e..0617d97 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -9,6 +9,7 @@ type pkgAuthor: string pkgDesc: string pkgLicense: string + pkgBackend: string pkgSrcDir: string pkgNimDep: string pkgType: string @@ -149,6 +150,10 @@ test "correct welcome": # Write the nimble file let nimbleFile = pkgRoot / info.pkgName.changeFileExt("nimble") + # Only write backend if it isn't "c" + var pkgBackend = "" + if (info.pkgBackend != "c"): + pkgBackend = "backend = " & info.pkgbackend.escape() writeFile(nimbleFile, """# Package version = $# @@ -157,6 +162,7 @@ description = $# license = $# srcDir = $# $# +$# # Dependencies @@ -164,8 +170,8 @@ requires "nim >= $#" """ % [ info.pkgVersion.escape(), info.pkgAuthor.escape(), info.pkgDesc.escape(), info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions, - info.pkgNimDep + pkgBackend, info.pkgNimDep ] ) - display("Info:", "Nimble file created successfully", priority=MediumPriority) \ No newline at end of file + display("Info:", "Nimble file created successfully", priority=MediumPriority) From d800fb452564912fa3245caedf1ef1df3331d2b8 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 31 May 2019 16:58:54 -0500 Subject: [PATCH 342/424] Fix object variants - nim issue 1286 --- src/nimble.nim | 2 +- src/nimblepkg/options.nim | 4 ++-- src/nimblepkg/version.nim | 31 +++++++++++++------------------ 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2eda5c5..1b01502 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1015,7 +1015,7 @@ proc test(options: Options) = let (_, name, ext) = file.path.splitFile() if ext == ".nim" and name[0] == 't' and file.kind in {pcFile, pcLinkToFile}: var optsCopy = options.briefClone() - optsCopy.action.typ = actionCompile + optsCopy.action = Action(typ: actionCompile) optsCopy.action.file = file.path optsCopy.action.backend = "c" optsCopy.action.compileOptions = @[] diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 70924bd..f49ed04 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -238,7 +238,7 @@ proc getBinDir*(options: Options): string = options.getNimbleDir() / "bin" proc parseCommand*(key: string, result: var Options) = - result.action.typ = parseActionType(key) + result.action = Action(typ: parseActionType(key)) initAction(result, key) proc parseArgument*(key: string, result: var Options) = @@ -329,7 +329,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = raise newException(NimbleError, "Unknown option: --" & flag) proc initOptions*(): Options = - result.action.typ = actionNil + result.action = Action(typ: actionNil) result.pkgInfoCache = newTable[string, PackageInfo]() result.nimbleDir = "" result.verbosity = HighPriority diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index ae85e99..a3e7c4a 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -130,34 +130,32 @@ proc contains*(ran: VersionRange, ver: Version): bool = return withinRange(ver, ran) proc makeRange*(version: string, op: string): VersionRange = - new(result) if version == "": raise newException(ParseVersionError, "A version needs to accompany the operator.") case op of ">": - result.kind = verLater + result = VersionRange(kind: verLater) of "<": - result.kind = verEarlier + result = VersionRange(kind: verEarlier) of ">=": - result.kind = verEqLater + result = VersionRange(kind: verEqLater) of "<=": - result.kind = verEqEarlier + result = VersionRange(kind: verEqEarlier) of "": - result.kind = verEq + result = VersionRange(kind: verEq) else: raise newException(ParseVersionError, "Invalid operator: " & op) result.ver = Version(version) proc parseVersionRange*(s: string): VersionRange = # >= 1.5 & <= 1.8 - new(result) if s.len == 0: - result.kind = verAny + result = VersionRange(kind: verAny) return if s[0] == '#': - result.kind = verSpecial + result = VersionRange(kind: verSpecial) result.spe = s.Version return @@ -169,7 +167,7 @@ proc parseVersionRange*(s: string): VersionRange = of '>', '<', '=': op.add(s[i]) of '&': - result.kind = verIntersect + result = VersionRange(kind: verIntersect) result.verILeft = makeRange(version, op) # Parse everything after & @@ -204,10 +202,10 @@ proc toVersionRange*(ver: Version): VersionRange = ## Converts a version to either a verEq or verSpecial VersionRange. new(result) if ver.isSpecial: - result.kind = verSpecial + result = VersionRange(kind: verSpecial) result.spe = ver else: - result.kind = verEq + result = VersionRange(kind: verEq) result.ver = ver proc parseRequires*(req: string): PkgTuple = @@ -263,17 +261,14 @@ proc getSimpleString*(verRange: VersionRange): string = result = "" proc newVRAny*(): VersionRange = - new(result) - result.kind = verAny + result = VersionRange(kind: verAny) proc newVREarlier*(ver: string): VersionRange = - new(result) - result.kind = verEarlier + result = VersionRange(kind: verEarlier) result.ver = newVersion(ver) proc newVREq*(ver: string): VersionRange = - new(result) - result.kind = verEq + result = VersionRange(kind: verEq) result.ver = newVersion(ver) proc findLatest*(verRange: VersionRange, From cbd63e61dec2360a17a640987298ca702d69d4c3 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 31 May 2019 12:49:15 -0500 Subject: [PATCH 343/424] Fix outfile issue when binary exists --- src/nimblepkg/nimscriptapi.nim | 17 ++++++++++++----- src/nimblepkg/nimscriptwrapper.nim | 9 +++++---- 2 files changed, 17 insertions(+), 9 deletions(-) mode change 100755 => 100644 src/nimblepkg/nimscriptapi.nim mode change 100755 => 100644 src/nimblepkg/nimscriptwrapper.nim diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim old mode 100755 new mode 100644 index eba18cd..0ace797 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -35,6 +35,7 @@ var success = false retVal = true projectFile = "" + outFile = "" proc requires*(deps: varargs[string]) = ## Call this to set the list of requirements of your Nimble @@ -42,13 +43,18 @@ proc requires*(deps: varargs[string]) = for d in deps: requiresData.add(d) proc getParams() = + # Called by nimscriptwrapper.nim:execNimscript() + # nim e --flags /full/path/to/file.nims /full/path/to/file.out action for i in 2 .. paramCount(): let param = paramStr(i) - if param.fileExists(): - projectFile = param - elif param[0] != '-': - commandLineParams.add paramStr(i).normalize + if param[0] != '-': + if projectFile.len == 0: + projectFile = param + elif outFile.len == 0: + outFile = param + else: + commandLineParams.add param.normalize proc getCommand*(): string = return command @@ -136,7 +142,8 @@ proc onExit*() = output &= "\"retVal\": " & $retVal - writeFile(projectFile & ".out", "{" & output & "}") + if outFile.len != 0: + writeFile(outFile, "{" & output & "}") # TODO: New release of Nim will move this `task` template under a # `when not defined(nimble)`. This will allow us to override it in the future. diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim old mode 100755 new mode 100644 index 0956b79..ff28e8e --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -4,7 +4,7 @@ ## Implements the new configuration system for Nimble. Uses Nim as a ## scripting language. -import common, version, options, packageinfo, cli +import common, version, options, packageinfo, cli, tools import hashes, json, os, streams, strutils, strtabs, tables, times, osproc, sets, pegs @@ -26,6 +26,7 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, let shash = $projectDir.hash().abs() nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & shash & ".nims" + outFile = getNimbleTempDir() & ".out" let isScriptResultCopied = @@ -42,12 +43,12 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, let cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & - " " & nimsFileCopied.quoteShell & " " & actionName).strip() + " " & nimsFileCopied.quoteShell & " " & outFile.quoteShell & " " & actionName).strip() + + displayDebug("Executing " & cmd) if live: result.exitCode = execCmd(cmd) - let - outFile = nimsFileCopied & ".out" if outFile.fileExists(): result.output = outFile.readFile() discard outFile.tryRemoveFile() From 8dc036c8961975a117e42f4ebde97bb08845e0f6 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 31 May 2019 14:33:31 -0500 Subject: [PATCH 344/424] Update Nim versions, fix recursive test --- .travis.yml | 6 +++--- tests/recursive/recursive.nimble | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0e5d3a5..95b29c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ os: language: c env: - - BRANCH=0.19.4 - - BRANCH=#4f9366975441be889a8cd4fbfb4e41f6830dc542 + - BRANCH=0.19.6 + - BRANCH=#44cc5f6360c7ccc96c296948b2524bd2cdebf1f0 cache: directories: - - "$HOME/.choosenim/toolchains/nim-0.19.4" + - "$HOME/.choosenim/toolchains/nim-0.19.6" install: - export CHOOSENIM_CHOOSE_VERSION=$BRANCH diff --git a/tests/recursive/recursive.nimble b/tests/recursive/recursive.nimble index ec09ab9..a188170 100644 --- a/tests/recursive/recursive.nimble +++ b/tests/recursive/recursive.nimble @@ -11,11 +11,11 @@ requires "nim >= 0.12.1" task recurse, "Level 1": echo 1 - exec "nimble recurse2" + exec "../../src/nimble recurse2" task recurse2, "Level 2": echo 2 - exec "nimble recurse3" + exec "../../src/nimble recurse3" task recurse3, "Level 3": echo 3 From 374f62614a67f6f6701213366c0b112857d66e18 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 31 May 2019 14:49:58 -0500 Subject: [PATCH 345/424] Improved test naming --- tests/tester.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 1106998..1448869 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -71,7 +71,7 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true -test "caching works": +test "caching of nims and ini detects changes": cd "caching": var (output, exitCode) = execNimble("dump") check output.contains("0.1.0") @@ -82,7 +82,7 @@ test "caching works": check output.contains("0.2.0") writeFile(nfile, readFile(nfile).replace("0.2.0", "0.1.0")) -test "recursion works": +test "tasks can be called recursively": cd "recursive": check execNimble("recurse").exitCode == QuitSuccess From be83dcdca9385a2818fec096096c75db230c8d15 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Fri, 31 May 2019 22:36:53 -0500 Subject: [PATCH 346/424] Unique nims filename to enable parallelism --- src/nimblepkg/nimscriptwrapper.nim | 3 +-- src/nimblepkg/tools.nim | 17 ++++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index ff28e8e..473fdad 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -24,8 +24,7 @@ const proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, live = true): tuple[output: string, exitCode: int] = let - shash = $projectDir.hash().abs() - nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & shash & ".nims" + nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & getProcessId() & ".nims" outFile = getNimbleTempDir() & ".out" let diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index 2073154..acfa9a9 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -148,6 +148,15 @@ proc contains*(j: JsonNode, elem: tuple[key: string, val: JsonNode]): bool = when not defined(windows): from posix import getpid + +proc getProcessId*(): string = + when defined(windows): + proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32", + importc: "GetCurrentProcessId".} + result = $GetCurrentProcessId() + else: + result = $getpid() + proc getNimbleTempDir*(): string = ## Returns a path to a temporary directory. ## @@ -155,13 +164,7 @@ proc getNimbleTempDir*(): string = ## different for different runs of it. You have to make sure to create it ## first. In release builds the directory will be removed when nimble finishes ## its work. - result = getTempDir() / "nimble_" - when defined(windows): - proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32", - importc: "GetCurrentProcessId".} - result.add($GetCurrentProcessId()) - else: - result.add($getpid()) + result = getTempDir() / "nimble_" & getProcessId() proc getNimbleUserTempDir*(): string = ## Returns a path to a temporary directory. From 016f42c34a2bd2c8921045b453038d68b55928fc Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Sun, 2 Jun 2019 00:42:41 -0500 Subject: [PATCH 347/424] Fix issue #597 - error if bin is a source file --- src/nimblepkg/packageparser.nim | 2 ++ tests/issue597/dummy.nimble | 12 ++++++++++++ tests/issue597/test.nim | 0 tests/tester.nim | 6 ++++++ 4 files changed, 20 insertions(+) mode change 100755 => 100644 src/nimblepkg/packageparser.nim create mode 100644 tests/issue597/dummy.nimble create mode 100644 tests/issue597/test.nim diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim old mode 100755 new mode 100644 index 5c034eb..4a6d5db --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -253,6 +253,8 @@ proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = result.installExt.add(ev.value.multiSplit) of "bin": for i in ev.value.multiSplit: + if i.splitFile().ext == ".nim": + raise newException(NimbleError, "`bin` entry should not be a source file: " & i) result.bin.add(i.addFileExt(ExeExt)) of "backend": result.backend = ev.value.toLowerAscii() diff --git a/tests/issue597/dummy.nimble b/tests/issue597/dummy.nimble new file mode 100644 index 0000000..13bf4be --- /dev/null +++ b/tests/issue597/dummy.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "Author" +description = "dummy" +license = "MIT" + +# Dependencies + +requires "nim >= 0.17.0" + +bin = @["test.nim"] diff --git a/tests/issue597/test.nim b/tests/issue597/test.nim new file mode 100644 index 0000000..e69de29 diff --git a/tests/tester.nim b/tests/tester.nim index 1448869..bd7a306 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -585,6 +585,12 @@ test "can pass args with spaces to Nim (#351)": checkpoint output check exitCode == QuitSuccess +test "error if `bin` is a source file (#597)": + cd "issue597": + var (output, exitCode) = execNimble("build") + check exitCode != QuitSuccess + check output.contains("entry should not be a source file: test.nim") + suite "reverse dependencies": test "basic test": cd "revdep/mydep": From 21616e35a78594a7335005d81efe2c91eec6824f Mon Sep 17 00:00:00 2001 From: genotrance Date: Sun, 2 Jun 2019 06:12:20 -0500 Subject: [PATCH 348/424] Fix issue #655 (#661) * Fix issue #655 * Update nimscriptwrapper.nim --- src/nimblepkg/nimscriptwrapper.nim | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 473fdad..39df926 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -119,7 +119,12 @@ proc execScript(scriptName, actionName: string, options: Options): (output, exitCode) = execNimscript(nimsFile, scriptName.parentDir(), actionName, options) if exitCode != 0: - raise newException(NimbleError, output) + let errMsg = + if output.len != 0: + output + else: + "Exception raised during nimble script execution" + raise newException(NimbleError, errMsg) let j = From d15c8530cb7480ce39ffa85a2dd9819d2d4fc645 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Mon, 3 Jun 2019 13:56:49 -0500 Subject: [PATCH 349/424] Version 0.10.2 --- changelog.markdown | 18 ++++++++++++++++++ nimble.nimble | 2 +- src/nimblepkg/common.nim | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/changelog.markdown b/changelog.markdown index 1f417e6..c8ae9cf 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,24 @@ # Nimble changelog +## 0.10.2 - 03/06/2019 + +This is a small release which avoids object variant changes that are now +treated as runtime errors (Nim #1286). It also adds support for `backend` +selection during `nimble init`. + +Multiple bug fixes are also included: +- Fixed an issue where failing tasks were not returning a non-zero return + value (#655). +- Error out if `bin` is a Nim source file (#597). +- Fixed an issue where nimble task would not run if file of same name exists. +- Fixed an issue that prevented multiple instances of nimble from running on + the same package. + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.10.0...v0.10.2 + ## 0.10.0 - 27/05/2019 Nimble now uses the Nim compiler directly via `nim e` to execute nimble diff --git a/nimble.nimble b/nimble.nimble index 8de754f..5344094 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,6 @@ # Package -version = "0.10.0" +version = "0.10.2" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 676a2ff..abb8094 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,4 +63,4 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.10.0" + nimbleVersion* = "0.10.2" From 2c87a7fe5ec2c07db8596195b1db297c48a4f232 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 11 Jun 2019 11:39:32 -0500 Subject: [PATCH 350/424] Add 0.20.0 to test matrix, latest nightlies --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 95b29c0..2a17224 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,13 @@ language: c env: - BRANCH=0.19.6 - - BRANCH=#44cc5f6360c7ccc96c296948b2524bd2cdebf1f0 + - BRANCH=0.20.0 + - BRANCH=#ced0527ae334439a10e1719d1eccb727c19dc781 cache: directories: - "$HOME/.choosenim/toolchains/nim-0.19.6" + - "$HOME/.choosenim/toolchains/nim-0.20.0" install: - export CHOOSENIM_CHOOSE_VERSION=$BRANCH From 513780a38249d27adab2a120eacd63762dba5960 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 11 Jun 2019 10:54:00 -0500 Subject: [PATCH 351/424] Fix #665 - avoid stdout in printPkgInfo --- src/nimblepkg/nimscriptapi.nim | 20 +++++++++----------- src/nimblepkg/nimscriptwrapper.nim | 17 +++++++---------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index 0ace797..fffad4d 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -81,20 +81,19 @@ template `--`*(key: untyped) = template printIfLen(varName) = if varName.len != 0: - iniOut &= astToStr(varName) & ": \"\"\"" & varName & "\"\"\"\n" + result &= astToStr(varName) & ": \"\"\"" & varName & "\"\"\"\n" template printSeqIfLen(varName) = if varName.len != 0: - iniOut &= astToStr(varName) & ": \"" & varName.join(", ") & "\"\n" + result &= astToStr(varName) & ": \"" & varName.join(", ") & "\"\n" -proc printPkgInfo() = +proc printPkgInfo(): string = if backend.len == 0: backend = "c" - var - iniOut = "[Package]\n" + result = "[Package]\n" if packageName.len != 0: - iniOut &= "name: \"" & packageName & "\"\n" + result &= "name: \"" & packageName & "\"\n" printIfLen version printIfLen author printIfLen description @@ -114,14 +113,13 @@ proc printPkgInfo() = printSeqIfLen afterHooks if requiresData.len != 0: - iniOut &= "\n[Deps]\n" - iniOut &= &"requires: \"{requiresData.join(\", \")}\"\n" - - echo iniOut + result &= "\n[Deps]\n" + result &= &"requires: \"{requiresData.join(\", \")}\"\n" proc onExit*() = if "printPkgInfo".normalize in commandLineParams: - printPkgInfo() + if outFile.len != 0: + writeFile(outFile, printPkgInfo()) else: var output = "" diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 39df926..10cfae8 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -21,8 +21,8 @@ const internalCmd = "e" nimscriptApi = staticRead("nimscriptapi.nim") -proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, - live = true): tuple[output: string, exitCode: int] = +proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): + tuple[output: string, exitCode: int] = let nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & getProcessId() & ".nims" outFile = getNimbleTempDir() & ".out" @@ -46,13 +46,10 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options, displayDebug("Executing " & cmd) - if live: - result.exitCode = execCmd(cmd) - if outFile.fileExists(): - result.output = outFile.readFile() - discard outFile.tryRemoveFile() - else: - result = execCmdEx(cmd, options = {poUsePath, poStdErrToStdOut}) + result.exitCode = execCmd(cmd) + if outFile.fileExists(): + result.output = outFile.readFile() + discard outFile.tryRemoveFile() proc getNimsFile(scriptName: string, options: Options): string = let @@ -103,7 +100,7 @@ proc getIniFile*(scriptName: string, options: Options): string = if not isIniResultCached: let (output, exitCode) = - execNimscript(nimsFile, scriptName.parentDir(), "printPkgInfo", options, live=false) + execNimscript(nimsFile, scriptName.parentDir(), "printPkgInfo", options) if exitCode == 0 and output.len != 0: result.writeFile(output) From 98e566adab85e5e1b6226a5e69418d925894fb89 Mon Sep 17 00:00:00 2001 From: Hitesh Jasani Date: Wed, 12 Jun 2019 16:16:52 -0400 Subject: [PATCH 352/424] Add example dependency with git commit [docs] (#669) * Add example dependency with git commit [docs] * Update readme.markdown --- readme.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.markdown b/readme.markdown index f246c7e..5f3ef52 100644 --- a/readme.markdown +++ b/readme.markdown @@ -401,6 +401,7 @@ You can also specify multiple dependencies like so: requires "nim >= 0.10.0", "foobar >= 0.1.0" requires "fizzbuzz >= 1.0" +requires "https://github.com/user/pkg#5a54b5e" ``` Nimble currently supports installation of packages from a local directory, a From df8317585f5ee99de68cdda38df2a5b1a2d6027f Mon Sep 17 00:00:00 2001 From: liquid600pgm Date: Sat, 22 Jun 2019 00:10:41 +0200 Subject: [PATCH 353/424] fixed #581 nimble init does not overwrite existing files with its templates anymore --- src/nimblepkg/init.nim | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 0617d97..e8c1000 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -14,6 +14,10 @@ type pkgNimDep: string pkgType: string +proc writeFileIfNonExistent(file: string, content: string) = + if not existsFile(file): + writeFile(file, content) + proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = # Create source directory createDirD(pkgRoot / info.pkgSrcDir) @@ -23,7 +27,7 @@ proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = case info.pkgType of "binary": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFile(mainFile, + writeFileIfNonExistent(mainFile, """ # This is just an example to get you started. A typical binary package # uses this file as the main entry point of the application. @@ -35,7 +39,7 @@ when isMainModule: nimbleFileOptions.add("bin = @[\"$1\"]\n" % info.pkgName) of "library": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFile(mainFile, + writeFileIfNonExistent(mainFile, """ # This is just an example to get you started. A typical library package # exports the main API in this file. Note that you cannot rename this file @@ -50,7 +54,7 @@ proc add*(x, y: int): int = createDirD(pkgRoot / info.pkgSrcDir / info.pkgName) let submodule = pkgRoot / info.pkgSrcDir / info.pkgName / "submodule".addFileExt("nim") - writeFile(submodule, + writeFileIfNonExistent(submodule, """ # This is just an example to get you started. Users of your library will # import this file by writing ``import $1/submodule``. Feel free to rename or @@ -68,7 +72,7 @@ proc initSubmodule*(): Submodule = ) of "hybrid": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFile(mainFile, + writeFileIfNonExistent(mainFile, """ # This is just an example to get you started. A typical hybrid package # uses this file as the main entry point of the application. @@ -83,7 +87,7 @@ when isMainModule: let pkgSubDir = pkgRoot / info.pkgSrcDir / info.pkgName & "pkg" createDirD(pkgSubDir) let submodule = pkgSubDir / "submodule".addFileExt("nim") - writeFile(submodule, + writeFileIfNonExistent(submodule, """ # This is just an example to get you started. Users of your hybrid library will # import this file by writing ``import $1pkg/submodule``. Feel free to rename or @@ -112,7 +116,7 @@ proc getWelcomeMessage*(): string = "Hello, World!" ) if info.pkgType == "library": - writeFile(pkgTestPath / "test1".addFileExt("nim"), + writeFileIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), """ # This is just an example to get you started. You may wish to put all of your # tests into a single file, or separate them into multiple `test1`, `test2` @@ -129,7 +133,7 @@ test "can add": """ % info.pkgName ) else: - writeFile(pkgTestPath / "test1".addFileExt("nim"), + writeFileIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), """ # This is just an example to get you started. You may wish to put all of your # tests into a single file, or separate them into multiple `test1`, `test2` From 192ea12ab9cd66a1f38d643b0258f508fc3a94a0 Mon Sep 17 00:00:00 2001 From: liquid600pgm Date: Sat, 22 Jun 2019 00:32:48 +0200 Subject: [PATCH 354/424] Output message when file already exists --- src/nimblepkg/init.nim | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index e8c1000..97c5589 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -14,9 +14,12 @@ type pkgNimDep: string pkgType: string -proc writeFileIfNonExistent(file: string, content: string) = +proc writeExampleIfNonExistent(file: string, content: string) = if not existsFile(file): writeFile(file, content) + else: + display("Info:", "File " & file & " already exists, did not write " & + "example code", Message, LowPriority) proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = # Create source directory @@ -27,7 +30,7 @@ proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = case info.pkgType of "binary": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFileIfNonExistent(mainFile, + writeExampleIfNonExistent(mainFile, """ # This is just an example to get you started. A typical binary package # uses this file as the main entry point of the application. @@ -39,7 +42,7 @@ when isMainModule: nimbleFileOptions.add("bin = @[\"$1\"]\n" % info.pkgName) of "library": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFileIfNonExistent(mainFile, + writeExampleIfNonExistent(mainFile, """ # This is just an example to get you started. A typical library package # exports the main API in this file. Note that you cannot rename this file @@ -54,7 +57,7 @@ proc add*(x, y: int): int = createDirD(pkgRoot / info.pkgSrcDir / info.pkgName) let submodule = pkgRoot / info.pkgSrcDir / info.pkgName / "submodule".addFileExt("nim") - writeFileIfNonExistent(submodule, + writeExampleIfNonExistent(submodule, """ # This is just an example to get you started. Users of your library will # import this file by writing ``import $1/submodule``. Feel free to rename or @@ -72,7 +75,7 @@ proc initSubmodule*(): Submodule = ) of "hybrid": let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim") - writeFileIfNonExistent(mainFile, + writeExampleIfNonExistent(mainFile, """ # This is just an example to get you started. A typical hybrid package # uses this file as the main entry point of the application. @@ -87,7 +90,7 @@ when isMainModule: let pkgSubDir = pkgRoot / info.pkgSrcDir / info.pkgName & "pkg" createDirD(pkgSubDir) let submodule = pkgSubDir / "submodule".addFileExt("nim") - writeFileIfNonExistent(submodule, + writeExampleIfNonExistent(submodule, """ # This is just an example to get you started. Users of your hybrid library will # import this file by writing ``import $1pkg/submodule``. Feel free to rename or @@ -116,7 +119,7 @@ proc getWelcomeMessage*(): string = "Hello, World!" ) if info.pkgType == "library": - writeFileIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), + writeExampleIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), """ # This is just an example to get you started. You may wish to put all of your # tests into a single file, or separate them into multiple `test1`, `test2` @@ -133,7 +136,7 @@ test "can add": """ % info.pkgName ) else: - writeFileIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), + writeExampleIfNonExistent(pkgTestPath / "test1".addFileExt("nim"), """ # This is just an example to get you started. You may wish to put all of your # tests into a single file, or separate them into multiple `test1`, `test2` From 153866252d8606d6f77d6a1747e6ad6674ba3741 Mon Sep 17 00:00:00 2001 From: liquid600pgm Date: Sat, 22 Jun 2019 01:17:03 +0200 Subject: [PATCH 355/424] File not overwritten by example code message --- src/nimblepkg/init.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 97c5589..085c616 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -19,7 +19,7 @@ proc writeExampleIfNonExistent(file: string, content: string) = writeFile(file, content) else: display("Info:", "File " & file & " already exists, did not write " & - "example code", Message, LowPriority) + "example code", priority = HighPriority) proc createPkgStructure*(info: PkgInitInfo, pkgRoot: string) = # Create source directory From 5e72840336c03ef66557f96623fedddece53083d Mon Sep 17 00:00:00 2001 From: liquid600pgm Date: Sat, 22 Jun 2019 01:17:41 +0200 Subject: [PATCH 356/424] Test for the #581 fix --- tests/tester.nim | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/tester.nim b/tests/tester.nim index bd7a306..fcd4752 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -818,3 +818,12 @@ suite "Module tests": test "cli": cd "..": check execCmdEx("nim c -r src/nimblepkg/cli").exitCode == QuitSuccess + +test "init does not overwrite existing files (#581)": + createDir("issue581/src") + cd "issue581": + const Src = "echo \"OK\"" + writeFile("src/issue581.nim", Src) + check execNimbleYes("init").exitCode == QuitSuccess + check readFile("src/issue581.nim") == Src + removeDir("issue581") From 7c2b9f612e6a42609f28f8f51de4ab6949ced4a0 Mon Sep 17 00:00:00 2001 From: Leonardo Mariscal Date: Tue, 16 Jul 2019 10:32:17 -0500 Subject: [PATCH 357/424] Update submodules at checkout time to fix #675 --- src/nimblepkg/download.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index f8954e9..b504b61 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -24,6 +24,7 @@ proc doCheckout(meth: DownloadMethod, downloadDir, branch: string) = # clone has happened. Like in the case of git on Windows where it # messes up the damn line endings. doCmd("git checkout --force " & branch) + doCmd("git submodule update --recursive") of DownloadMethod.hg: cd downloadDir: doCmd("hg checkout " & branch) From added89acc9437946b0fba7dfdc07021da564196 Mon Sep 17 00:00:00 2001 From: genotrance Date: Sat, 27 Jul 2019 08:37:56 -0500 Subject: [PATCH 358/424] Fixes #504 (#683) * Improve messaging for uninstall * Uninstall if in right order * Fix CI - cannot looks better * Raise exception when nothing to remove * Test case, minor test fix * 0.19.6 fixes * Fix Nim devel hash * Feedback --- .travis.yml | 6 +++--- src/nimble.nim | 37 ++++++++++++++++------------------- src/nimblepkg/packageinfo.nim | 7 ++++++- src/nimblepkg/reversedeps.nim | 17 +++++++++++----- tests/tester.nim | 17 ++++++++++++++-- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2a17224..13b8678 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,13 @@ language: c env: - BRANCH=0.19.6 - - BRANCH=0.20.0 - - BRANCH=#ced0527ae334439a10e1719d1eccb727c19dc781 + - BRANCH=0.20.2 + - BRANCH=#44aadd50cfa647a759610a15967960632bf597ce cache: directories: - "$HOME/.choosenim/toolchains/nim-0.19.6" - - "$HOME/.choosenim/toolchains/nim-0.20.0" + - "$HOME/.choosenim/toolchains/nim-0.20.2" install: - export CHOOSENIM_CHOOSE_VERSION=$BRANCH diff --git a/src/nimble.nim b/src/nimble.nim index 1b01502..32b8833 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -840,7 +840,8 @@ proc uninstall(options: Options) = raise newException(NimbleError, "Please specify the package(s) to uninstall.") - var pkgsToDelete: seq[PackageInfo] = @[] + var pkgsToDelete: HashSet[PackageInfo] + pkgsToDelete.init() # Do some verification. for pkgTup in options.action.packages: display("Looking", "for $1 ($2)" % [pkgTup.name, $pkgTup.ver], @@ -851,37 +852,33 @@ proc uninstall(options: Options) = raise newException(NimbleError, "Package not found") display("Checking", "reverse dependencies", priority = HighPriority) - var errors: seq[string] = @[] for pkg in pkgList: # Check whether any packages depend on the ones the user is trying to # uninstall. if options.uninstallRevDeps: getAllRevDeps(options, pkg, pkgsToDelete) else: - let revDeps = getRevDeps(options, pkg) + let + revDeps = getRevDeps(options, pkg) var reason = "" - if revDeps.len == 1: - reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver] - else: - for i in 0 ..< revDeps.len: - reason.add("$1 ($2)" % [revDeps[i].name, $revDeps[i].ver]) - if i != revDeps.len-1: - reason.add ", " - reason.add " depend on it" + for revDep in revDeps: + if reason.len != 0: reason.add ", " + reason.add("$1 ($2)" % [revDep.name, revDep.version]) + if reason.len != 0: + reason &= " depend" & (if revDeps.len == 1: "s" else: "") & " on it" - if revDeps.len > 0: - errors.add("Cannot uninstall $1 ($2) because $3" % - [pkgTup.name, pkg.specialVersion, reason]) + if len(revDeps - pkgsToDelete) > 0: + display("Cannot", "uninstall $1 ($2) because $3" % + [pkgTup.name, pkg.specialVersion, reason], Warning, HighPriority) else: - pkgsToDelete.add pkg + pkgsToDelete.incl pkg - if pkgsToDelete.len == 0: - raise newException(NimbleError, "\n " & errors.join("\n ")) + if pkgsToDelete.len == 0: + raise newException(NimbleError, "Failed uninstall - no packages selected") var pkgNames = "" - for i in 0 ..< pkgsToDelete.len: - if i != 0: pkgNames.add ", " - let pkg = pkgsToDelete[i] + for pkg in pkgsToDelete.items: + if pkgNames.len != 0: pkgNames.add ", " pkgNames.add("$1 ($2)" % [pkg.name, pkg.specialVersion]) # Let's confirm that the user wants these packages removed. diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index c54b97d..ec7daf0 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -3,7 +3,7 @@ # Stdlib imports import system except TResult -import parsecfg, json, streams, strutils, parseutils, os, sets, tables +import hashes, parsecfg, json, streams, strutils, parseutils, os, sets, tables import httpclient # Local imports @@ -542,6 +542,11 @@ proc `==`*(pkg1: PackageInfo, pkg2: PackageInfo): bool = if pkg1.name == pkg2.name and pkg1.myPath == pkg2.myPath: return true +proc hash*(x: PackageInfo): Hash = + var h: Hash = 0 + h = h !& hash(x.myPath) + result = !$h + when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == ("packagea", "0.1") diff --git a/src/nimblepkg/reversedeps.nim b/src/nimblepkg/reversedeps.nim index 0da2a84..45d9940 100644 --- a/src/nimblepkg/reversedeps.nim +++ b/src/nimblepkg/reversedeps.nim @@ -1,7 +1,7 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import os, json +import os, json, sets import options, common, version, download, packageinfo @@ -58,7 +58,7 @@ proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) = newData[key] = newVal nimbleData["reverseDeps"] = newData -proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] = +proc getRevDepTups*(options: Options, pkg: PackageInfo): seq[PkgTuple] = ## Returns a list of *currently installed* reverse dependencies for `pkg`. result = @[] let thisPkgsDep = @@ -76,18 +76,25 @@ proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] = result.add(pkgTup) -proc getAllRevDeps*(options: Options, pkg: PackageInfo, result: var seq[PackageInfo]) = +proc getRevDeps*(options: Options, pkg: PackageInfo): HashSet[PackageInfo] = + result.init() + let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) + for rdepTup in getRevDepTups(options, pkg): + for rdepInfo in findAllPkgs(installedPkgs, rdepTup): + result.incl rdepInfo + +proc getAllRevDeps*(options: Options, pkg: PackageInfo, result: var HashSet[PackageInfo]) = if pkg in result: return let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options) - for rdepTup in getRevDeps(options, pkg): + for rdepTup in getRevDepTups(options, pkg): for rdepInfo in findAllPkgs(installedPkgs, rdepTup): if rdepInfo in result: continue getAllRevDeps(options, rdepInfo, result) - result.add pkg + result.incl pkg when isMainModule: var nimbleData = %{"reverseDeps": newJObject()} diff --git a/tests/tester.nim b/tests/tester.nim index fcd4752..99f7c64 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -465,8 +465,7 @@ test "can uninstall": let ls = outp.strip.processOutput() check exitCode != QuitSuccess - check "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends" & - " on it" in ls[ls.len-1] + check inLines(ls, "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends") check execNimble("uninstall", "-y", "issue27").exitCode == QuitSuccess check execNimble("uninstall", "-y", "issue27a").exitCode == QuitSuccess @@ -827,3 +826,17 @@ test "init does not overwrite existing files (#581)": check execNimbleYes("init").exitCode == QuitSuccess check readFile("src/issue581.nim") == Src removeDir("issue581") + +test "remove skips packages with revDeps (#504)": + check execNimble("install", "nimboost@0.5.5", "nimfp@0.4.4", "-y").exitCode == QuitSuccess + + var (output, exitCode) = execNimble("uninstall", "nimboost", "nimfp", "-n") + var lines = output.strip.processOutput() + check inLines(lines, "Cannot uninstall nimboost") + + (output, exitCode) = execNimble("uninstall", "nimfp", "nimboost", "-y") + lines = output.strip.processOutput() + check (not inLines(lines, "Cannot uninstall nimboost")) + + check execNimble("path", "nimboost").exitCode != QuitSuccess + check execNimble("path", "nimfp").exitCode != QuitSuccess From 5ec2ecea77434798133e5a1ec5f1a437d3947128 Mon Sep 17 00:00:00 2001 From: SolitudeSF Date: Fri, 26 Jul 2019 17:49:04 +0300 Subject: [PATCH 359/424] Add `passNim/p` flag to pass compiler flags explicitly. Remove redundant buildFromDir overload. --- src/nimble.nim | 14 +++----------- src/nimblepkg/options.nim | 5 +++++ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 32b8833..69086be 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -213,13 +213,13 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = for i in reverseDeps: addRevDep(options.nimbleData, i, pkginfo) -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], - args: var seq[string]) = +proc buildFromDir(pkgInfo: PackageInfo, paths, args: seq[string]) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") + var args = args let realDir = pkgInfo.getRealDir() for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: @@ -244,14 +244,6 @@ proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], exc.hint = hint raise exc -proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) = - var args: seq[string] - if forRelease: - args = @["-d:release"] - else: - args = @[] - buildFromDir(pkgInfo, paths, args) - proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. try: @@ -356,7 +348,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: let paths = result.deps.map(dep => dep.getRealDir()) - buildFromDir(pkgInfo, paths, true) + buildFromDir(pkgInfo, paths, options.action.passNimFlags & "-d:release") let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index f49ed04..e345121 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -41,6 +41,7 @@ type of actionInstall, actionPath, actionUninstall, actionDevelop: packages*: seq[PkgTuple] # Optional only for actionInstall # and actionDevelop. + passNimFlags*: seq[string] of actionSearch: search*: seq[string] # Search string. of actionInit, actionDump: @@ -61,6 +62,7 @@ Usage: nimble COMMAND [opts] Commands: install [pkgname, ...] Installs a list of packages. [-d, --depsOnly] Install only dependencies. + [-p, --passNim] Forward specified flag to compiler. develop [pkgname, ...] Clones a list of packages for development. Symlinks the cloned packages or any package in the current working directory. @@ -175,6 +177,7 @@ proc initAction*(options: var Options, key: string) = case options.action.typ of actionInstall, actionPath, actionDevelop, actionUninstall: options.action.packages = @[] + options.action.passNimFlags = @[] of actionCompile, actionDoc, actionBuild: options.action.compileOptions = @[] options.action.file = "" @@ -303,6 +306,8 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = case f of "depsonly", "d": result.depsOnly = true + of "passnim", "p": + result.action.passNimFlags.add(val) else: wasFlagHandled = false of actionUninstall: From b5b85489fab710d2a77182030ac6ef98352328ec Mon Sep 17 00:00:00 2001 From: SolitudeSF Date: Sat, 27 Jul 2019 19:38:50 +0300 Subject: [PATCH 360/424] Add tests for passNim feature. --- tests/passNimFlags/passNimFlags.nim | 1 + tests/passNimFlags/passNimFlags.nimble | 11 +++++++++++ tests/tester.nim | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 tests/passNimFlags/passNimFlags.nim create mode 100644 tests/passNimFlags/passNimFlags.nimble diff --git a/tests/passNimFlags/passNimFlags.nim b/tests/passNimFlags/passNimFlags.nim new file mode 100644 index 0000000..b4c0b97 --- /dev/null +++ b/tests/passNimFlags/passNimFlags.nim @@ -0,0 +1 @@ +when not defined(passNimIsWorking): {.error: "-d:passNimIsWorking wasn't passed to the compiler"} diff --git a/tests/passNimFlags/passNimFlags.nimble b/tests/passNimFlags/passNimFlags.nimble new file mode 100644 index 0000000..8530524 --- /dev/null +++ b/tests/passNimFlags/passNimFlags.nimble @@ -0,0 +1,11 @@ +# Package + +version = "0.1.0" +author = "SolitudeSF" +description = "Test nimble install flag forwarding" +license = "BSD" +bin = @["passNimFlags"] + +# Dependencies + +requires "nim >= 0.13.0" diff --git a/tests/tester.nim b/tests/tester.nim index 99f7c64..2a1bb00 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -840,3 +840,7 @@ test "remove skips packages with revDeps (#504)": check execNimble("path", "nimboost").exitCode != QuitSuccess check execNimble("path", "nimfp").exitCode != QuitSuccess + +test "pass options to the compiler with `nimble install`": + cd "passNimFlags": + check execNimble("install", "--passNim:-d:passNimIsWorking").exitCode == QuitSuccess From 5b7b061465d77f4798816d7b813a4fe888fa87ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ois=C3=ADn=20Mac=20Fheara=C3=AD?= Date: Sat, 27 Jul 2019 17:55:59 +0100 Subject: [PATCH 361/424] Remove escaping of author name and package description in `nimble init`, since it replaces characters used in many names and languages with escape sequences. Slightly refactor the code for determining author name, to make it easier to add other version control systems in future (right now it's just git and hg). Also, add some binary test artifacts to .gitignore so they don't accidentally get committed in future. --- .gitignore | 11 ++++++++++- src/nimble.nim | 22 +++++++++++----------- src/nimblepkg/init.nim | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 5744c47..76ef2d8 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,14 @@ nimcache/ /nimble /tests/nimscript/nimscript /tests/issue27/issue27 +src/nimblepkg/cli +src/nimblepkg/packageinfo +src/nimblepkg/packageparser +src/nimblepkg/reversedeps +src/nimblepkg/version +tests/nimble-test/ +tests/packageStructure/validBinary/y +tests/testCommand/testsFail/tests/t2 # Windows executables *.exe @@ -19,4 +27,5 @@ nimcache/ # VCC compiler and linker artifacts *.ilk -*.pdb \ No newline at end of file +*.pdb + diff --git a/src/nimble.nim b/src/nimble.nim index 69086be..f62795b 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -724,20 +724,20 @@ proc init(options: Options) = display("Using", "$# for new package name" % [pkgName.escape()], priority = HighPriority) - # Ask for package author + # Determine author by running an external command + proc getAuthorWithCmd(cmd: string): string = + let (name, exitCode) = doCmdEx(cmd) + if exitCode == QuitSuccess and name.len > 0: + result = name.strip() + display("Using", "$# for new package author" % [result], + priority = HighPriority) + + # Determine package author via git/hg or asking proc getAuthor(): string = if findExe("git") != "": - let (name, exitCode) = doCmdEx("git config --global user.name") - if exitCode == QuitSuccess and name.len > 0: - result = name.strip() - display("Using", "$# for new package author" % [result.escape()], - priority = HighPriority) + result = getAuthorWithCmd("git config --global user.name") elif findExe("hg") != "": - let (name, exitCode) = doCmdEx("hg config ui.username") - if exitCode == QuitSuccess and name.len > 0: - result = name.strip() - display("Using", "$# for new package author" % [result.escape()], - priority = HighPriority) + result = getAuthorWithCmd("hg config ui.username") if result.len == 0: result = promptCustom(options, "Your name?", "Anonymous") let pkgAuthor = getAuthor() diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 085c616..2378b5f 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -175,7 +175,7 @@ $# requires "nim >= $#" """ % [ - info.pkgVersion.escape(), info.pkgAuthor.escape(), info.pkgDesc.escape(), + info.pkgVersion.escape(), info.pkgAuthor, info.pkgDesc.escape(), info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions, pkgBackend, info.pkgNimDep ] From 522ef4cf129b20faf8071c25074e03141eb9d92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ois=C3=ADn=20Mac=20Fheara=C3=AD?= Date: Sat, 27 Jul 2019 19:53:07 +0100 Subject: [PATCH 362/424] Unescape package description in nimble init --- src/nimblepkg/init.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 2378b5f..6648877 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -175,7 +175,7 @@ $# requires "nim >= $#" """ % [ - info.pkgVersion.escape(), info.pkgAuthor, info.pkgDesc.escape(), + info.pkgVersion.escape(), info.pkgAuthor, info.pkgDesc, info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions, pkgBackend, info.pkgNimDep ] From 871e5c65d19eb3b5f69dca136edd92a2dfab1586 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sat, 27 Jul 2019 21:39:38 +0300 Subject: [PATCH 363/424] Add additional files and folders to .gitignore Several additional file and folder types are added to .gitignore: - VSCode directory for for user and workspace settings. - *.orig files created by Git on merge conflicts. - Some artifacts related to the test procedure. --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 76ef2d8..5c629ae 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,12 @@ tests/testCommand/testsFail/tests/t2 *.ilk *.pdb +# Editors and IDEs project files and folders +.vscode + +# VCS artifacts +*.orig + +# Test procedure artifacts +tests/nimble-test/ +nimble_*.nims From 8cf97e0e0682f72181d8c2f2b142dcb582584a50 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 28 Jul 2019 00:12:46 +0300 Subject: [PATCH 364/424] Add an unit test for #678 This is an unit test for the issue with multiple downloads and installs of the same dependency package. Related to #678 --- tests/issue678/issue678.nimble | 12 ++++++++++++ tests/issue678/packages.json | 19 +++++++++++++++++++ tests/tester.nim | 16 ++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/issue678/issue678.nimble create mode 100644 tests/issue678/packages.json diff --git a/tests/issue678/issue678.nimble b/tests/issue678/issue678.nimble new file mode 100644 index 0000000..20239e7 --- /dev/null +++ b/tests/issue678/issue678.nimble @@ -0,0 +1,12 @@ +# Package + +version = "0.1.0" +author = "Ivan Bobev" +description = "Package for ensuring that issue #678 is resolved." +license = "MIT" + +# Dependencies + +requires "nim >= 0.19.6" +# to reproduce dependency 2 must be before 1 +requires "issue678_dependency_2", "issue678_dependency_1" diff --git a/tests/issue678/packages.json b/tests/issue678/packages.json new file mode 100644 index 0000000..25338c9 --- /dev/null +++ b/tests/issue678/packages.json @@ -0,0 +1,19 @@ +[ + { + "name": "issue678_dependency_1", + "url": "https://github.com/bobeff/issue678?subdir=dependency_1", + "method": "git", + "tags": [ "test" ], + "description": + "Both first and second level dependency of the issue678 package.", + "license": "MIT" + }, + { + "name": "issue678_dependency_2", + "url": "https://github.com/bobeff/issue678?subdir=dependency_2", + "method": "git", + "tags": [ "test" ], + "description": "First level dependency of the issue678 package.", + "license": "MIT" + } +] diff --git a/tests/tester.nim b/tests/tester.nim index 2a1bb00..b08d0cf 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -844,3 +844,19 @@ test "remove skips packages with revDeps (#504)": test "pass options to the compiler with `nimble install`": cd "passNimFlags": check execNimble("install", "--passNim:-d:passNimIsWorking").exitCode == QuitSuccess + +test "do not install single dependency multiple times (#678)": + # for the test to be correct, the tested package and its dependencies must not + # exist in the local cache + removeDir("nimbleDir") + cd "issue678": + testRefresh(): + writeFile(configFile, """ + [PackageList] + name = "local" + path = "$1" + """.unindent % (getCurrentDir() / "packages.json").replace("\\", "\\\\")) + check execNimble(["refresh"]).exitCode == QuitSuccess + let (output, exitCode) = execNimble("install", "-y") + check exitCode == QuitSuccess + check output.find("issue678_dependency_1@0.1.0 already exists") == -1 From f46179268655a3177fec7d1b60b2c701c859ce7e Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sat, 27 Jul 2019 22:01:16 +0300 Subject: [PATCH 365/424] Fix multiple installs of the same package When one package is dependency both of some other package and some other dependency of the other package it has been downloaded and installed multiple times. Resolves #678 --- src/nimble.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index f62795b..999595e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -156,7 +156,8 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = "dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion], priority = HighPriority) - var pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) + var pkgList {.global.}: seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @[] + once: pkgList = getInstalledPkgsMin(options.getPkgsDir(), options) var reverseDeps: seq[tuple[name, version: string]] = @[] for dep in pkginfo.requires: if dep.name == "nimrod" or dep.name == "nim": From 8e3af03e4699a56e2321dfa90a0dfafd527ab51e Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 28 Jul 2019 00:29:48 +0300 Subject: [PATCH 366/424] Add a changelog entry for the issue #678 fix Related to #678 --- changelog.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index c8ae9cf..a011485 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,6 +3,8 @@ # Nimble changelog +- Fixed multiple downloads and installs of the same package (#678). + ## 0.10.2 - 03/06/2019 This is a small release which avoids object variant changes that are now From da82e3111e662fc1b12f96b3cddd66c749c0f686 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 4 Aug 2019 19:31:40 +0300 Subject: [PATCH 367/424] Fix issue678 test repository links After the ownership of the issue678 test repository was transferred to the nimble-test account, the links to the repository required for performing the test had to be updated in order to avoid possible confusion, despite the fact that GitHub does automatic link redirection for transferred repositories. Related to #687 --- tests/issue678/packages.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/issue678/packages.json b/tests/issue678/packages.json index 25338c9..972eb70 100644 --- a/tests/issue678/packages.json +++ b/tests/issue678/packages.json @@ -1,7 +1,7 @@ [ { "name": "issue678_dependency_1", - "url": "https://github.com/bobeff/issue678?subdir=dependency_1", + "url": "https://github.com/nimble-test/issue678?subdir=dependency_1", "method": "git", "tags": [ "test" ], "description": @@ -10,7 +10,7 @@ }, { "name": "issue678_dependency_2", - "url": "https://github.com/bobeff/issue678?subdir=dependency_2", + "url": "https://github.com/nimble-test/issue678?subdir=dependency_2", "method": "git", "tags": [ "test" ], "description": "First level dependency of the issue678 package.", From 2243e3fbc2dd277ad81df5d795307bf8389b9240 Mon Sep 17 00:00:00 2001 From: Hitesh Jasani Date: Sat, 24 Aug 2019 05:15:29 -0400 Subject: [PATCH 368/424] Fix #567: Display package versions in sorted order (#688) * Fix #567: Display package versions in sorted order * Add docs * Fix docs to focus on git tags * Refactor to use version module * Streamline docs * Refactor to make things work in nim <= 0.19.6 * Improve code readability --- readme.markdown | 13 ++++++++++ src/nimblepkg/download.nim | 52 +++++++++++++++++++++++++------------- src/nimblepkg/version.nim | 14 +++++++--- tests/tester.nim | 4 +++ 4 files changed, 63 insertions(+), 20 deletions(-) diff --git a/readme.markdown b/readme.markdown index 5f3ef52..9470aa8 100644 --- a/readme.markdown +++ b/readme.markdown @@ -786,6 +786,19 @@ To summarise, the steps for release are: Once the new tag is in the remote repository, Nimble will be able to detect the new version. +##### Git Version Tagging + +Use dot separated numbers to represent the release version in the git +tag label. Nimble will parse these git tag labels to know which +versions of a package are published. + +``` text +v0.2.0 # 0.2.0 +v1 # 1 +v1.2.3-zuzu # 1.2.3 +foo-1.2.3.4 # 1.2.3.4 +``` + ## Publishing packages Publishing packages isn't a requirement. But doing so allows people to associate diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index b504b61..639354f 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -2,8 +2,9 @@ # BSD License. Look at license.txt for more info. import parseutils, os, osproc, strutils, tables, pegs, uri - import packageinfo, packageparser, version, tools, common, options, cli +from algorithm import SortOrder, sorted +from sequtils import toSeq, filterIt, map type DownloadMethod* {.pure.} = enum @@ -103,14 +104,21 @@ proc getTagsListRemote*(url: string, meth: DownloadMethod): seq[string] = # http://stackoverflow.com/questions/2039150/show-tags-for-remote-hg-repository raise newException(ValueError, "Hg doesn't support remote tag querying.") -proc getVersionList*(tags: seq[string]): Table[Version, string] = - # Returns: TTable of version -> git tag name - result = initTable[Version, string]() - for tag in tags: - if tag != "": - let i = skipUntil(tag, Digits) # skip any chars before the version - # TODO: Better checking, tags can have any names. Add warnings and such. - result[newVersion(tag[i .. tag.len-1])] = tag +proc getVersionList*(tags: seq[string]): OrderedTable[Version, string] = + ## Return an ordered table of Version -> git tag label. Ordering is + ## in descending order with the most recent version first. + let taggedVers: seq[tuple[ver: Version, tag: string]] = + tags + .filterIt(it != "") + .map(proc(s: string): tuple[ver: Version, tag: string] = + # skip any chars before the version + let i = skipUntil(s, Digits) + # TODO: Better checking, tags can have any + # names. Add warnings and such. + result = (newVersion(s[i .. s.len-1]), s)) + .sorted(proc(a, b: (Version, string)): int = cmp(a[0], b[0]), + SortOrder.Descending) + result = toOrderedTable[Version, string](taggedVers) proc getDownloadMethod*(meth: string): DownloadMethod = case meth @@ -268,14 +276,8 @@ proc echoPackageVersions*(pkg: Package) = try: let versions = getTagsListRemote(pkg.url, downMethod).getVersionList() if versions.len > 0: - var vstr = "" - var i = 0 - for v in values(versions): - if i != 0: - vstr.add(", ") - vstr.add(v) - i.inc - echo(" versions: " & vstr) + let sortedVersions = toSeq(values(versions)) + echo(" versions: " & join(sortedVersions, ", ")) else: echo(" versions: (No versions tagged in the remote repository)") except OSError: @@ -283,3 +285,19 @@ proc echoPackageVersions*(pkg: Package) = of DownloadMethod.hg: echo(" versions: (Remote tag retrieval not supported by " & pkg.downloadMethod & ")") + +when isMainModule: + # Test version sorting + block: + let data = @["v9.0.0-taeyeon", "v9.0.1-jessica", "v9.2.0-sunny", + "v9.4.0-tiffany", "v9.4.2-hyoyeon"] + let expected = toOrderedTable[Version, string]({ + newVersion("9.4.2-hyoyeon"): "v9.4.2-hyoyeon", + newVersion("9.4.0-tiffany"): "v9.4.0-tiffany", + newVersion("9.2.0-sunny"): "v9.2.0-sunny", + newVersion("9.0.1-jessica"): "v9.0.1-jessica", + newVersion("9.0.0-taeyeon"): "v9.0.0-taeyeon" + }) + doAssert expected == getVersionList(data) + + echo("Everything works!") diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index a3e7c4a..4834b6d 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -93,6 +93,11 @@ proc `==`*(ver: Version, ver2: Version): bool = else: return false +proc cmp*(a, b: Version): int = + if a < b: -1 + elif a > b: 1 + else: 0 + proc `<=`*(ver: Version, ver2: Version): bool = return (ver == ver2) or (ver < ver2) @@ -272,7 +277,7 @@ proc newVREq*(ver: string): VersionRange = result.ver = newVersion(ver) proc findLatest*(verRange: VersionRange, - versions: Table[Version, string]): tuple[ver: Version, tag: string] = + versions: OrderedTable[Version, string]): tuple[ver: Version, tag: string] = result = (newVersion(""), "") for ver, tag in versions: if not withinRange(ver, verRange): continue @@ -309,8 +314,11 @@ when isMainModule: doAssert(newVersion("") < newVersion("1.0.0")) doAssert(newVersion("") < newVersion("0.1.0")) - var versions = toTable[Version, string]({newVersion("0.1.1"): "v0.1.1", - newVersion("0.2.3"): "v0.2.3", newVersion("0.5"): "v0.5"}) + var versions = toOrderedTable[Version, string]({ + newVersion("0.1.1"): "v0.1.1", + newVersion("0.2.3"): "v0.2.3", + newVersion("0.5"): "v0.5" + }) doAssert findLatest(parseVersionRange(">= 0.1 & <= 0.4"), versions) == (newVersion("0.2.3"), "v0.2.3") diff --git a/tests/tester.nim b/tests/tester.nim index b08d0cf..09427e8 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -818,6 +818,10 @@ suite "Module tests": cd "..": check execCmdEx("nim c -r src/nimblepkg/cli").exitCode == QuitSuccess + test "download": + cd "..": + check execCmdEx("nim c -r src/nimblepkg/download").exitCode == QuitSuccess + test "init does not overwrite existing files (#581)": createDir("issue581/src") cd "issue581": From e39c57482a156fb98e530c85a77766f67929ef29 Mon Sep 17 00:00:00 2001 From: genotrance Date: Mon, 2 Sep 2019 16:54:48 -0500 Subject: [PATCH 369/424] Fix #633 - pass CLI to tasks (#686) * Fix #633 - pass CLI to tasks * Add test case --- src/nimblepkg/nimscriptwrapper.nim | 10 +++++++++- tests/issue633/issue633.nimble | 16 ++++++++++++++++ tests/tester.nim | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/issue633/issue633.nimble diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 10cfae8..fa8f8f0 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -40,10 +40,18 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): if not isScriptResultCopied: nimsFileCopied.removeFile() - let + var cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & " " & nimsFileCopied.quoteShell & " " & outFile.quoteShell & " " & actionName).strip() + if options.action.typ == actionCustom and actionName != "printPkgInfo": + for i in options.action.arguments: + cmd &= " " & i.quoteShell() + for key, val in options.action.flags.pairs(): + cmd &= " $#$#" % [if key.len == 1: "-" else: "--", key] + if val.len != 0: + cmd &= ":" & val.quoteShell() + displayDebug("Executing " & cmd) result.exitCode = execCmd(cmd) diff --git a/tests/issue633/issue633.nimble b/tests/issue633/issue633.nimble new file mode 100644 index 0000000..cb786eb --- /dev/null +++ b/tests/issue633/issue633.nimble @@ -0,0 +1,16 @@ +# Package + +version = "0.1.0" +author = "GT" +description = "Package for ensuring that issue #633 is resolved." +license = "MIT" + +# Dependencies + +requires "nim >= 0.19.6" +# to reproduce dependency 2 must be before 1 + +task testTask, "Test": + for i in 0 .. paramCount(): + if paramStr(i) == "--testTask": + echo "Got it" diff --git a/tests/tester.nim b/tests/tester.nim index 09427e8..c2aefc3 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -864,3 +864,8 @@ test "do not install single dependency multiple times (#678)": let (output, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess check output.find("issue678_dependency_1@0.1.0 already exists") == -1 + +test "Passing command line arguments to a task (#633)": + cd "issue633": + var (output, exitCode) = execNimble("testTask --testTask") + check output.contains("Got it") From fb57d47421cae847d67e3c1c1281fec6312227fd Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Wed, 4 Sep 2019 13:17:17 -0500 Subject: [PATCH 370/424] Fix #640 - strip out blank spaces --- src/nimblepkg/packageparser.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 4a6d5db..ddae76d 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -212,7 +212,10 @@ proc multiSplit(s: string): seq[string] = result.del(i) # Huh, nothing to return? Return given input. if len(result) < 1: - return @[s] + if s.strip().len != 0: + return @[s] + else: + return @[] proc readPackageInfoFromNimble(path: string; result: var PackageInfo) = var fs = newFileStream(path, fmRead) From 38cd55e71af3df66c26d02d127c454d5b0a31e58 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 3 Sep 2019 18:39:06 -0500 Subject: [PATCH 371/424] Fix #689 - don't lookup versions for aliases --- src/nimble.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 999595e..20d81ed 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -551,7 +551,7 @@ proc search(options: Options) = var found = false template onFound {.dirty.} = echoPackage(pkg) - if options.queryVersions: + if pkg.alias.len == 0 and options.queryVersions: echoPackageVersions(pkg) echo(" ") found = true @@ -577,7 +577,7 @@ proc list(options: Options) = let pkgList = getPackageList(options) for pkg in pkgList: echoPackage(pkg) - if options.queryVersions: + if pkg.alias.len == 0 and options.queryVersions: echoPackageVersions(pkg) echo(" ") From 2ec470d2875a3d9d5d06f23c780f82281826c779 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sat, 3 Aug 2019 18:38:41 +0300 Subject: [PATCH 372/424] Clear unused imports Related to #680 --- src/nimble.nim | 3 +-- src/nimblepkg/cli.nim | 7 ++----- src/nimblepkg/common.nim | 1 - src/nimblepkg/config.nim | 2 +- src/nimblepkg/nimscriptexecutor.nim | 5 +++-- src/nimblepkg/nimscriptsupport.nim | 11 ++++------- src/nimblepkg/nimscriptwrapper.nim | 5 ++--- src/nimblepkg/options.nim | 2 +- src/nimblepkg/packageinfo.nim | 3 +-- src/nimblepkg/packageinstaller.nim | 2 +- src/nimblepkg/packageparser.nim | 2 +- src/nimblepkg/publish.nim | 4 ++-- src/nimblepkg/tools.nim | 2 +- tests/tester.nim | 2 +- 14 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 20d81ed..a35f262 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -3,8 +3,7 @@ import system except TResult -import httpclient, parseopt, os, osproc, pegs, tables, parseutils, - strtabs, json, algorithm, sets, uri, sugar, sequtils +import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils import strutils except toLower from unicode import toLower diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 8d96015..9544373 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -12,11 +12,8 @@ # - Bright for HighPriority. # - Normal for MediumPriority. -import logging, terminal, sets, strutils, os -import ./common - -when defined(windows): - import winlean +import terminal, sets, strutils +import version type CLI* = ref object diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index abb8094..5cacb86 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -8,7 +8,6 @@ when not defined(nimscript): import sets import version - export version.NimbleError # TODO: Surely there is a better way? type BuildFailed* = object of NimbleError diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index 5706485..ca8dcf2 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -2,7 +2,7 @@ # BSD License. Look at license.txt for more info. import parsecfg, streams, strutils, os, tables, Uri -import tools, version, common, cli +import version, cli type Config* = object diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim index fad0d1e..bf8afd1 100644 --- a/src/nimblepkg/nimscriptexecutor.nim +++ b/src/nimblepkg/nimscriptexecutor.nim @@ -1,9 +1,10 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import os, tables, strutils, sets +import os, strutils, sets -import packageparser, common, packageinfo, options, nimscriptwrapper, cli +import packageparser, common, packageinfo, options, nimscriptwrapper, cli, + version proc execHook*(options: Options, before: bool): bool = ## Returns whether to continue. diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index 4c8747b..cbe83d3 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -5,18 +5,15 @@ ## scripting language. import - compiler/ast, compiler/modules, compiler/passes, compiler/passaux, - compiler/condsyms, compiler/sem, compiler/semdata, - compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands, - compiler/msgs, compiler/magicsys, compiler/idents, + compiler/ast, compiler/modules, compiler/passes, compiler/condsyms, + compiler/sem, compiler/llstream, compiler/vm, compiler/vmdef, compiler/idents, compiler/nimconf, compiler/nversion -from compiler/scriptconfig import setupVM from compiler/astalgo import strTableGet import compiler/options as compiler_options -import common, version, options, packageinfo, cli, tools -import os, strutils, strtabs, tables, times, osproc, sets, pegs +import common, version, options, cli, tools +import os, strutils, tables, times, osproc, sets, pegs when not declared(resetAllModulesHard): import compiler/modulegraphs diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index fa8f8f0..3f7ba51 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -4,9 +4,8 @@ ## Implements the new configuration system for Nimble. Uses Nim as a ## scripting language. -import common, version, options, packageinfo, cli, tools -import hashes, json, os, streams, strutils, strtabs, - tables, times, osproc, sets, pegs +import version, options, cli, tools +import hashes, json, os, strutils, tables, times, osproc type Flags = TableRef[string, seq[string]] diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index e345121..6ef2f95 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -4,7 +4,7 @@ import json, strutils, os, parseopt, strtabs, uri, tables, terminal from httpclient import Proxy, newProxy -import config, version, tools, common, cli +import config, version, common, cli type Options* = object diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index ec7daf0..6b2d6ae 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -3,8 +3,7 @@ # Stdlib imports import system except TResult -import hashes, parsecfg, json, streams, strutils, parseutils, os, sets, tables -import httpclient +import hashes, json, strutils, os, sets, tables, httpclient # Local imports import version, tools, common, options, cli, config diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index 125db93..f131942 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -3,7 +3,7 @@ import os, strutils, sets, json # Local imports -import cli, common, options, tools +import version, cli, options, tools when defined(windows): # This is just for Win XP support. diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index ddae76d..59c2ca8 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, json, sets, streams, strutils, parseutils, os, tables, sugar +import parsecfg, sets, streams, strutils, os, tables, sugar from sequtils import apply, map import version, tools, common, nimscriptwrapper, options, packageinfo, cli diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 333bbbd..186a3a5 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -5,8 +5,8 @@ ## nim-lang/packages automatically. import system except TResult -import httpclient, base64, strutils, rdstdin, json, os, browsers, times, uri -import tools, common, cli, config, options +import httpclient, strutils, json, os, browsers, times, uri +import version, tools, common, cli, config, options type Auth = object diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index acfa9a9..b39fea7 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -3,7 +3,7 @@ # # Various miscellaneous utility functions reside here. import osproc, pegs, strutils, os, uri, sets, json, parseutils -import version, common, cli +import version, cli proc extractBin(cmd: string): string = if cmd[0] == '"': diff --git a/tests/tester.nim b/tests/tester.nim index c2aefc3..2629817 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import osproc, streams, unittest, strutils, os, sequtils, sugar +import osproc, unittest, strutils, os, sequtils, sugar # TODO: Each test should start off with a clean slate. Currently installed # packages are shared between each test which causes a multitude of issues From db018f235babd5b6e64d9524fafd02e110499dcd Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Tue, 6 Aug 2019 16:34:53 +0300 Subject: [PATCH 373/424] Clear deprecation warnings This fix clears deprecation warnings related to Nim's HashSet procedures. There were two types of warnings which have been fixed: - Warning: Deprecated since v0.20, use 'initHashSet'; initSet is deprecated [Deprecated] - Warning: Deprecated since v0.20, use 'toHashSet'; toSet is deprecated [Deprecated] Backward compatibility with older Nim versions is also implemented. Related to #680 --- src/nimble.nim | 6 +++--- src/nimblepkg/cli.nim | 5 ++++- src/nimblepkg/common.nim | 12 ++++++++++++ src/nimblepkg/packageinfo.nim | 2 +- src/nimblepkg/packageinstaller.nim | 5 ++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index a35f262..6c13ca9 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -94,7 +94,7 @@ proc copyFilesRec(origDir, currentDir, dest: string, ## Copies all the required files, skips files specified in the .nimble file ## (PackageInfo). ## Returns a list of filepaths to files which have been installed. - result = initSet[string]() + result = initHashSet[string]() let whitelistMode = pkgInfo.installDirs.len != 0 or pkgInfo.installFiles.len != 0 or @@ -373,7 +373,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, createDir(pkgDestDir) # Copy this package's files based on the preferences specified in PkgInfo. - var filesInstalled = initSet[string]() + var filesInstalled = initHashSet[string]() iterInstallFiles(realDir, pkgInfo, options, proc (file: string) = createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir)) @@ -386,7 +386,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, pkgInfo.myPath) filesInstalled.incl copyFileD(pkgInfo.myPath, dest) - var binariesInstalled = initSet[string]() + var binariesInstalled = initHashSet[string]() if pkgInfo.bin.len > 0: # Make sure ~/.nimble/bin directory is created. createDir(binDir) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index 9544373..a3ac714 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -15,6 +15,9 @@ import terminal, sets, strutils import version +when not declared(initHashSet): + import common + type CLI* = ref object level: Priority @@ -46,7 +49,7 @@ const proc newCLI(): CLI = result = CLI( level: HighPriority, - warnings: initSet[(string, string)](), + warnings: initHashSet[(string, string)](), suppressionCount: 0, showColor: true, suppressMessages: false diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index 5cacb86..f015d24 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -63,3 +63,15 @@ when not defined(nimscript): const nimbleVersion* = "0.10.2" + +when not declared(initHashSet): + import sets + + template initHashSet*[A](initialSize = 64): HashSet[A] = + initSet[A](initialSize) + +when not declared(toHashSet): + import sets + + template toHashSet*[A](keys: openArray[A]): HashSet[A] = + toSet(keys) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index 6b2d6ae..e3cac25 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -277,7 +277,7 @@ proc getPackage*(pkg: string, options: Options, resPkg: var Package): bool = proc getPackageList*(options: Options): seq[Package] = ## Returns the list of packages found in the downloaded packages.json files. result = @[] - var namesAdded = initSet[string]() + var namesAdded = initHashSet[string]() for name, list in options.config.packageLists: let packages = readPackageList(name, options) for p in packages: diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index f131942..71f305f 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -5,6 +5,9 @@ import os, strutils, sets, json # Local imports import version, cli, options, tools +when not declared(initHashSet) or not declared(toHashSet): + import common + when defined(windows): # This is just for Win XP support. # TODO: Drop XP support? @@ -103,4 +106,4 @@ proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision, nimbleLinkPath: string) = ## pkgDir - The directory where the original package files are. ## For example: ~/projects/jester/ saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision, - toSet[string]([nimbleLinkPath]), initSet[string](), true) \ No newline at end of file + toHashSet[string]([nimbleLinkPath]), initHashSet[string](), true) \ No newline at end of file From 6e5761b1923ce213c2b956900591d7a6f50cde84 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Tue, 6 Aug 2019 17:25:08 +0300 Subject: [PATCH 374/424] Clear unused symbols warnings Unused functions and variables are removed from the Nimble's source code. Resolves #680 --- src/nimblepkg/download.nim | 20 -------------------- src/nimblepkg/nimscriptsupport.nim | 7 ------- src/nimblepkg/packageinfo.nim | 1 - 3 files changed, 28 deletions(-) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 639354f..d2e0074 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -10,13 +10,6 @@ type DownloadMethod* {.pure.} = enum git = "git", hg = "hg" -proc getSpecificDir(meth: DownloadMethod): string = - case meth - of DownloadMethod.git: - ".git" - of DownloadMethod.hg: - ".hg" - proc doCheckout(meth: DownloadMethod, downloadDir, branch: string) = case meth of DownloadMethod.git: @@ -30,19 +23,6 @@ proc doCheckout(meth: DownloadMethod, downloadDir, branch: string) = cd downloadDir: doCmd("hg checkout " & branch) -proc doPull(meth: DownloadMethod, downloadDir: string) = - case meth - of DownloadMethod.git: - doCheckout(meth, downloadDir, "") - cd downloadDir: - doCmd("git pull") - if existsFile(".gitmodules"): - doCmd("git submodule update") - of DownloadMethod.hg: - doCheckout(meth, downloadDir, "default") - cd downloadDir: - doCmd("hg pull") - proc doClone(meth: DownloadMethod, url, downloadDir: string, branch = "", onlyTip = true) = case meth diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim index cbe83d3..fd45364 100644 --- a/src/nimblepkg/nimscriptsupport.nim +++ b/src/nimblepkg/nimscriptsupport.nim @@ -375,8 +375,6 @@ proc execScript(scriptName: string, flags: Flags, options: Options): PSym = "more info." raiseNimbleError(msg, hint) - let pkgName = scriptName.splitFile.name - # Ensure that "nimblepkg/nimscriptapi" is in the PATH. block: let t = getNimbleUserTempDir() / "nimblecache" @@ -692,11 +690,6 @@ proc execHook*(scriptName, actionName: string, before: bool, cleanup() -proc getNimScriptCommand(): string = - when declared(NimCompilerApiVersion): - let conf = graph.config - nimCommand() - proc setNimScriptCommand(command: string) = when declared(NimCompilerApiVersion): let conf = graph.config diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index e3cac25..f00c59f 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -310,7 +310,6 @@ proc findNimbleFile*(dir: string; error: bool): string = if result.splitFile.ext == ".nimble-link": # Return the path of the real .nimble file. - let nimbleLinkPath = result result = readNimbleLink(result).nimbleFilePath if not fileExists(result): let msg = "The .nimble-link file is pointing to a missing file: " & result From bfc4f255489801f248fed1d14ae558d207a49fb6 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Tue, 6 Aug 2019 18:08:51 +0300 Subject: [PATCH 375/424] Fix compilation of nimscriptapi.nim To compile the nimscriptapi.nim file, it is needed to import the os module, but if so the getParams procedure cannot be executed from nimscript any more. The problem is resolved by conditionally importing the module. Related to #680 --- src/nimblepkg/nimscriptapi.nim | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index fffad4d..a8b4ba3 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -6,6 +6,9 @@ import system except getCommand, setCommand, switch, `--` import strformat, strutils, tables +when not defined(nimscript): + import os + var packageName* = "" ## Set this to the package name. It ## is usually not required to do that, nims' filename is From 1eb9f0f01cc8228e44635217658a9356b06dd2fe Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Wed, 7 Aug 2019 17:01:05 +0300 Subject: [PATCH 376/424] Remove unused file The file nimscriptsupport.nim is no longer used in favor of the newer version nimscriptwrapper.nim. Related to #680 --- src/nimblepkg/nimscriptsupport.nim | 708 ----------------------------- 1 file changed, 708 deletions(-) delete mode 100644 src/nimblepkg/nimscriptsupport.nim diff --git a/src/nimblepkg/nimscriptsupport.nim b/src/nimblepkg/nimscriptsupport.nim deleted file mode 100644 index fd45364..0000000 --- a/src/nimblepkg/nimscriptsupport.nim +++ /dev/null @@ -1,708 +0,0 @@ -# Copyright (C) Andreas Rumpf. All rights reserved. -# BSD License. Look at license.txt for more info. - -## Implements the new configuration system for Nimble. Uses Nim as a -## scripting language. - -import - compiler/ast, compiler/modules, compiler/passes, compiler/condsyms, - compiler/sem, compiler/llstream, compiler/vm, compiler/vmdef, compiler/idents, - compiler/nimconf, compiler/nversion - -from compiler/astalgo import strTableGet -import compiler/options as compiler_options - -import common, version, options, cli, tools -import os, strutils, tables, times, osproc, sets, pegs - -when not declared(resetAllModulesHard): - import compiler/modulegraphs - -type - Flags = TableRef[string, seq[string]] - ExecutionResult*[T] = object - success*: bool - command*: string - arguments*: seq[string] - flags*: Flags - retVal*: T - -const - internalCmd = "NimbleInternal" - nimscriptApi = staticRead("nimscriptapi.nim") - -proc raiseVariableError(ident, typ: string) {.noinline.} = - raise newException(NimbleError, - "NimScript's variable '" & ident & "' needs a value of type '" & typ & "'.") - -proc isStrLit(n: PNode): bool = n.kind in {nkStrLit..nkTripleStrLit} - -when declared(NimCompilerApiVersion): - const finalApi = NimCompilerApiVersion >= 2 - - when NimCompilerApiVersion >= 3: - import compiler / pathutils -else: - const finalApi = false - -proc getGlobal(g: ModuleGraph; ident: PSym): string = - when finalApi: - let n = vm.getGlobalValue(PCtx g.vm, ident) - else: - let n = vm.globalCtx.getGlobalValue(ident) - if n.isStrLit: - result = n.strVal - else: - raiseVariableError(ident.name.s, "string") - -proc getGlobalAsSeq(g: ModuleGraph; ident: PSym): seq[string] = - when finalApi: - let n = vm.getGlobalValue(PCtx g.vm, ident) - else: - let n = vm.globalCtx.getGlobalValue(ident) - result = @[] - if n.kind == nkBracket: - for x in n: - if x.isStrLit: - result.add x.strVal - else: - raiseVariableError(ident.name.s, "seq[string]") - else: - raiseVariableError(ident.name.s, "seq[string]") - -proc extractRequires(g: ModuleGraph; ident: PSym, result: var seq[PkgTuple]) = - when finalApi: - let n = vm.getGlobalValue(PCtx g.vm, ident) - else: - let n = vm.globalCtx.getGlobalValue(ident) - if n.kind == nkBracket: - for x in n: - if x.kind == nkPar and x.len == 2 and x[0].isStrLit and x[1].isStrLit: - result.add(parseRequires(x[0].strVal & x[1].strVal)) - elif x.isStrLit: - result.add(parseRequires(x.strVal)) - else: - raiseVariableError("requiresData", "seq[(string, VersionReq)]") - else: - raiseVariableError("requiresData", "seq[(string, VersionReq)]") - -when declared(newIdentCache): - var identCache = newIdentCache() - -proc setupVM(graph: ModuleGraph; module: PSym; scriptName: string, flags: Flags): PEvalContext = - ## This procedure is exported in the compiler sources, but its implementation - ## is too Nim-specific to be used by Nimble. - ## Specifically, the implementation of ``switch`` is problematic. Sooo - ## I simply copied it here and edited it :) - when declared(NimCompilerApiVersion): - result = newCtx(module, identCache, graph) - elif declared(newIdentCache): - result = newCtx(module, identCache) - else: - result = newCtx(module) - result.mode = emRepl - registerAdditionalOps(result) - - # captured vars: - let conf = graph.config - var errorMsg: string - var vthisDir = scriptName.splitFile.dir - - proc listDirs(a: VmArgs, filter: set[PathComponent]) = - let dir = getString(a, 0) - var res: seq[string] = @[] - for kind, path in walkDir(dir): - if kind in filter: res.add path - setResult(a, res) - - template cbconf(name, body) {.dirty.} = - result.registerCallback "stdlib.system." & astToStr(name), - proc (a: VmArgs) = - body - - template cbos(name, body) {.dirty.} = - result.registerCallback "stdlib.system." & astToStr(name), - proc (a: VmArgs) = - try: - body - except OSError: - errorMsg = getCurrentExceptionMsg() - - # Idea: Treat link to file as a file, but ignore link to directory to prevent - # endless recursions out of the box. - cbos listFiles: - listDirs(a, {pcFile, pcLinkToFile}) - cbos listDirs: - listDirs(a, {pcDir}) - cbos removeDir: - os.removeDir getString(a, 0) - cbos removeFile: - os.removeFile getString(a, 0) - cbos createDir: - os.createDir getString(a, 0) - cbos getOsError: - setResult(a, errorMsg) - cbos setCurrentDir: - os.setCurrentDir getString(a, 0) - cbos getCurrentDir: - setResult(a, os.getCurrentDir()) - cbos moveFile: - os.moveFile(getString(a, 0), getString(a, 1)) - cbos copyFile: - os.copyFile(getString(a, 0), getString(a, 1)) - cbos getLastModificationTime: - setResult(a, toUnix(getLastModificationTime(getString(a, 0)))) - cbos findExe: - setResult(a, os.findExe(getString(a, 0))) - - cbos rawExec: - setResult(a, osproc.execCmd getString(a, 0)) - - cbconf getEnv: - setResult(a, os.getEnv(a.getString 0)) - cbconf existsEnv: - setResult(a, os.existsEnv(a.getString 0)) - cbconf dirExists: - setResult(a, os.dirExists(a.getString 0)) - cbconf fileExists: - setResult(a, os.fileExists(a.getString 0)) - - cbconf thisDir: - setResult(a, vthisDir) - cbconf put: - when declared(NimCompilerApiVersion): - compiler_options.setConfigVar(conf, getString(a, 0), getString(a, 1)) - else: - compiler_options.setConfigVar(getString(a, 0), getString(a, 1)) - cbconf get: - when declared(NimCompilerApiVersion): - setResult(a, compiler_options.getConfigVar(conf, a.getString 0)) - else: - setResult(a, compiler_options.getConfigVar(a.getString 0)) - cbconf exists: - when declared(NimCompilerApiVersion): - setResult(a, compiler_options.existsConfigVar(conf, a.getString 0)) - else: - setResult(a, compiler_options.existsConfigVar(a.getString 0)) - cbconf nimcacheDir: - when declared(NimCompilerApiVersion): - setResult(a, compiler_options.getNimcacheDir(conf)) - else: - setResult(a, compiler_options.getNimcacheDir()) - cbconf paramStr: - setResult(a, os.paramStr(int a.getInt 0)) - cbconf paramCount: - setResult(a, os.paramCount()) - cbconf cmpIgnoreStyle: - setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1)) - cbconf cmpIgnoreCase: - setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1)) - cbconf setCommand: - when declared(NimCompilerApiVersion): - conf.command = a.getString 0 - let arg = a.getString 1 - if arg.len > 0: - conf.projectName = arg - when NimCompilerApiVersion >= 3: - try: - conf.projectFull = canonicalizePath(conf, - conf.projectPath / RelativeFile(conf.projectName)) - except OSError: - conf.projectFull = AbsoluteFile conf.projectName - else: - try: - conf.projectFull = canonicalizePath(conf, conf.projectPath / conf.projectName) - except OSError: - conf.projectFull = conf.projectName - else: - compiler_options.command = a.getString 0 - let arg = a.getString 1 - if arg.len > 0: - gProjectName = arg - try: - gProjectFull = canonicalizePath(gProjectPath / gProjectName) - except OSError: - gProjectFull = gProjectName - cbconf getCommand: - when declared(NimCompilerApiVersion): - setResult(a, conf.command) - else: - setResult(a, compiler_options.command) - cbconf switch: - if not flags.isNil: - let - key = a.getString 0 - value = a.getString 1 - if flags.hasKey(key): - flags[key].add(value) - else: - flags[key] = @[value] - -proc isValidLibPath(lib: string): bool = - return fileExists(lib / "system.nim") - -proc getNimPrefixDir(options: Options): string = - let env = getEnv("NIM_LIB_PREFIX") - if env != "": - let msg = "Using env var NIM_LIB_PREFIX: " & env - display("Warning:", msg, Warning, HighPriority) - return env - - if options.config.nimLibPrefix != "": - result = options.config.nimLibPrefix - let msg = "Using Nim stdlib prefix from Nimble config file: " & result - display("Warning:", msg, Warning, HighPriority) - return - - result = splitPath(findExe("nim")).head.parentDir - # The above heuristic doesn't work for 'choosenim' proxies. Thankfully in - # that case the `nimble` binary is beside the `nim` binary so things should - # just work. - if not dirExists(result / "lib"): - # By specifying an empty string we instruct the Nim compiler to use - # getAppDir().head as the prefix dir. See compiler/options module for - # the code responsible for this. - result = "" - -proc getLibVersion(lib: string): Version = - ## This is quite a hacky procedure, but there is no other way to extract - ## this out of the ``system`` module. We could evaluate it, but that would - ## cause an error if the stdlib is out of date. The purpose of this - ## proc is to give a nice error message to the user instead of a confusing - ## Nim compile error. - let systemPath = lib / "system.nim" - if not fileExists(systemPath): - raiseNimbleError("system module not found in stdlib path: " & lib) - - let systemFile = readFile(systemPath) - let majorPeg = peg"'NimMajor' @ '=' \s* {\d*}" - let minorPeg = peg"'NimMinor' @ '=' \s* {\d*}" - let patchPeg = peg"'NimPatch' @ '=' \s* {\d*}" - - var majorMatches: array[1, string] - let major = find(systemFile, majorPeg, majorMatches) - var minorMatches: array[1, string] - let minor = find(systemFile, minorPeg, minorMatches) - var patchMatches: array[1, string] - let patch = find(systemFile, patchPeg, patchMatches) - - if major != -1 and minor != -1 and patch != -1: - return newVersion(majorMatches[0] & "." & minorMatches[0] & "." & patchMatches[0]) - else: - return system.NimVersion.newVersion() - -when finalApi: - var graph = newModuleGraph(identCache, newConfigRef()) - -elif declared(ModuleGraph): - var graph = newModuleGraph() - -proc execScript(scriptName: string, flags: Flags, options: Options): PSym = - ## Executes the specified script. Returns the script's module symbol. - ## - ## No clean up is performed and must be done manually! - when finalApi: - graph = newModuleGraph(graph.cache, graph.config) - else: - graph = newModuleGraph(graph.config) - - let conf = graph.config - when declared(NimCompilerApiVersion): - if "nimblepkg/nimscriptapi" notin conf.implicitImports: - conf.implicitImports.add("nimblepkg/nimscriptapi") - elif declared(resetAllModulesHard): - # for compatibility with older Nim versions: - if "nimblepkg/nimscriptapi" notin compiler_options.implicitIncludes: - compiler_options.implicitIncludes.add("nimblepkg/nimscriptapi") - else: - if "nimblepkg/nimscriptapi" notin compiler_options.implicitImports: - compiler_options.implicitImports.add("nimblepkg/nimscriptapi") - - # Ensure the compiler can find its standard library #220. - when declared(NimCompilerApiVersion): - when NimCompilerApiVersion >= 3: - conf.prefixDir = AbsoluteDir getNimPrefixDir(options) - display("Setting", "Nim stdlib prefix to " & conf.prefixDir.string, - priority=LowPriority) - - template myLibPath(): untyped = conf.libpath.string - - else: - conf.prefixDir = getNimPrefixDir(options) - display("Setting", "Nim stdlib prefix to " & conf.prefixDir, - priority=LowPriority) - - template myLibPath(): untyped = conf.libpath - - # Verify that lib path points to existing stdlib. - setDefaultLibpath(conf) - else: - compiler_options.gPrefixDir = getNimPrefixDir(options) - display("Setting", "Nim stdlib prefix to " & compiler_options.gPrefixDir, - priority=LowPriority) - - template myLibPath(): untyped = compiler_options.libpath - - # Verify that lib path points to existing stdlib. - compiler_options.setDefaultLibpath() - - display("Setting", "Nim stdlib path to " & myLibPath(), - priority=LowPriority) - if not isValidLibPath(myLibPath()): - let msg = "Nimble cannot find Nim's standard library.\nLast try in:\n - $1" % - myLibPath() - let hint = "Nimble does its best to find Nim's standard library, " & - "sometimes this fails. You can set the environment variable " & - "NIM_LIB_PREFIX to where Nim's `lib` directory is located as " & - "a workaround. " & - "See https://github.com/nim-lang/nimble#troubleshooting for " & - "more info." - raiseNimbleError(msg, hint) - - # Verify that the stdlib that was found isn't older than the stdlib that Nimble - # was compiled with. - let libVersion = getLibVersion(myLibPath()) - if NimVersion.newVersion() > libVersion: - let msg = ("Nimble cannot use an older stdlib than the one it was compiled " & - "with.\n Stdlib in '$#' has version: $#.\n Nimble needs at least: $#.") % - [myLibPath(), $libVersion, NimVersion] - let hint = "You may be running a newer version of Nimble than you intended " & - "to. Run an older version of Nimble that is compatible with " & - "the stdlib that Nimble is attempting to use or set the environment variable " & - "NIM_LIB_PREFIX to where a different stdlib's `lib` directory is located as " & - "a workaround." & - "See https://github.com/nim-lang/nimble#troubleshooting for " & - "more info." - raiseNimbleError(msg, hint) - - # Ensure that "nimblepkg/nimscriptapi" is in the PATH. - block: - let t = getNimbleUserTempDir() / "nimblecache" - let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim" - createDir(tmpNimscriptApiPath.splitFile.dir) - writeFile(tmpNimscriptApiPath, nimscriptApi) - when declared(NimCompilerApiVersion): - when NimCompilerApiVersion >= 3: - conf.searchPaths.add(AbsoluteDir t) - else: - conf.searchPaths.add(t) - else: - searchPaths.add(t) - - when declared(NimCompilerApiVersion): - initDefines(conf.symbols) - when NimCompilerApiVersion >= 2: - loadConfigs(DefaultConfig, graph.cache, conf) - else: - loadConfigs(DefaultConfig, conf) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule - - defineSymbol(conf.symbols, "nimscript") - defineSymbol(conf.symbols, "nimconfig") - defineSymbol(conf.symbols, "nimble") - when NimCompilerApiVersion >= 2: - registerPass(graph, semPass) - registerPass(graph, evalPass) - else: - registerPass(semPass) - registerPass(evalPass) - - conf.searchPaths.add(conf.libpath) - else: - initDefines() - loadConfigs(DefaultConfig) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule - - defineSymbol("nimscript") - defineSymbol("nimconfig") - defineSymbol("nimble") - registerPass(semPass) - registerPass(evalPass) - - searchPaths.add(compiler_options.libpath) - - when declared(resetAllModulesHard): - result = makeModule(scriptName) - else: - result = graph.makeModule(scriptName) - - incl(result.flags, sfMainModule) - when finalApi: - graph.vm = setupVM(graph, result, scriptName, flags) - - # Setup builtins defined in nimscriptapi.nim - template cbApi(name, body) {.dirty.} = - PCtx(graph.vm).registerCallback "nimscriptapi." & astToStr(name), - proc (a: VmArgs) = - body - - else: - vm.globalCtx = setupVM(graph, result, scriptName, flags) - - # Setup builtins defined in nimscriptapi.nim - template cbApi(name, body) {.dirty.} = - vm.globalCtx.registerCallback "nimscriptapi." & astToStr(name), - proc (a: VmArgs) = - body - - cbApi getPkgDir: - setResult(a, scriptName.splitFile.dir) - - when finalApi: - graph.compileSystemModule() - when NimCompilerApiVersion >= 3: - graph.processModule(result, llStreamOpen(AbsoluteFile scriptName, fmRead)) - else: - graph.processModule(result, llStreamOpen(scriptName, fmRead)) - elif declared(newIdentCache): - graph.compileSystemModule(identCache) - graph.processModule(result, llStreamOpen(scriptName, fmRead), nil, identCache) - else: - compileSystemModule() - processModule(result, llStreamOpen(scriptName, fmRead), nil) - -proc cleanup() = - # ensure everything can be called again: - when declared(NimCompilerApiVersion): - let conf = graph.config - conf.projectName = "" - conf.command = "" - else: - compiler_options.gProjectName = "" - compiler_options.command = "" - when declared(NimCompilerApiVersion): - resetSystemArtifacts(graph) - elif declared(resetAllModulesHard): - resetAllModulesHard() - else: - resetSystemArtifacts() - when finalApi: - clearPasses(graph) - else: - clearPasses() - when declared(NimCompilerApiVersion): - conf.errorMax = 1 - when NimCompilerApiVersion >= 2: - conf.writeLnHook = nil - graph.vm = nil - else: - msgs.writeLnHook = nil - vm.globalCtx = nil - initDefines(conf.symbols) - else: - msgs.gErrorMax = 1 - msgs.writeLnHook = nil - vm.globalCtx = nil - initDefines() - -proc readPackageInfoFromNims*(scriptName: string, options: Options, - result: var PackageInfo) = - ## Executes the `scriptName` nimscript file. Reads the package information - ## that it populates. - - # Setup custom error handling. - when declared(NimCompilerApiVersion): - let conf = graph.config - conf.errorMax = high(int) - else: - msgs.gErrorMax = high(int) - - template errCounter(): int = - when declared(NimCompilerApiVersion): conf.errorCounter - else: msgs.gErrorCounter - - var previousMsg = "" - - proc writelnHook(output: string) = - # The error counter is incremented after the writeLnHook is invoked. - if errCounter() > 0: - raise newException(NimbleError, previousMsg) - elif previousMsg.len > 0: - display("Info", previousMsg, priority = MediumPriority) - if output.normalize.startsWith("error"): - raise newException(NimbleError, output) - previousMsg = output - - when finalApi: - conf.writelnHook = writelnHook - else: - msgs.writeLnHook = writelnHook - - when declared(NimCompilerApiVersion): - conf.command = internalCmd - else: - compiler_options.command = internalCmd - - # Execute the nimscript file. - let thisModule = execScript(scriptName, nil, options) - - when declared(resetAllModulesHard): - let apiModule = thisModule - else: - var apiModule: PSym - for i in 0.. 0: - raise newException(NimbleError, previousMsg) - - # Extract all the necessary fields populated by the nimscript file. - proc getSym(apiModule: PSym, ident: string): PSym = - result = apiModule.tab.strTableGet(getIdent(identCache, ident)) - if result.isNil: - raise newException(NimbleError, "Ident not found: " & ident) - - template trivialField(field) = - result.field = getGlobal(graph, getSym(apiModule, astToStr field)) - - template trivialFieldSeq(field) = - result.field.add getGlobalAsSeq(graph, getSym(apiModule, astToStr field)) - - # keep reasonable default: - let name = getGlobal(graph, apiModule.tab.strTableGet(getIdent(identCache, "packageName"))) - if name.len > 0: result.name = name - - trivialField version - trivialField author - trivialField description - trivialField license - trivialField srcdir - trivialField bindir - trivialFieldSeq skipDirs - trivialFieldSeq skipFiles - trivialFieldSeq skipExt - trivialFieldSeq installDirs - trivialFieldSeq installFiles - trivialFieldSeq installExt - trivialFieldSeq foreignDeps - - extractRequires(graph, getSym(apiModule, "requiresData"), result.requires) - - let binSeq = getGlobalAsSeq(graph, getSym(apiModule, "bin")) - for i in binSeq: - result.bin.add(i.addFileExt(ExeExt)) - - let backend = getGlobal(graph, getSym(apiModule, "backend")) - if backend.len == 0: - result.backend = "c" - elif cmpIgnoreStyle(backend, "javascript") == 0: - result.backend = "js" - else: - result.backend = backend.toLowerAscii() - - # Grab all the global procs - for i in thisModule.tab.data: - if not i.isNil(): - let name = i.name.s.normalize() - if name.endsWith("before"): - result.preHooks.incl(name[0 .. ^7]) - if name.endsWith("after"): - result.postHooks.incl(name[0 .. ^6]) - - cleanup() - -when declared(NimCompilerApiVersion): - template nimCommand(): untyped = conf.command - template nimProjectName(): untyped = conf.projectName -else: - template nimCommand(): untyped = compiler_options.command - template nimProjectName(): untyped = compiler_options.gProjectName - -proc execTask*(scriptName, taskName: string, - options: Options): ExecutionResult[void] = - ## Executes the specified task in the specified script. - ## - ## `scriptName` should be a filename pointing to the nimscript file. - result.success = true - result.flags = newTable[string, seq[string]]() - when declared(NimCompilerApiVersion): - let conf = graph.config - nimCommand() = internalCmd - display("Executing", "task $# in $#" % [taskName, scriptName], - priority = HighPriority) - - let thisModule = execScript(scriptName, result.flags, options) - let prc = thisModule.tab.strTableGet(getIdent(identCache, taskName & "Task")) - if prc.isNil: - # Procedure not defined in the NimScript module. - result.success = false - cleanup() - return - when finalApi: - discard vm.execProc(PCtx(graph.vm), prc, []) - else: - discard vm.globalCtx.execProc(prc, []) - - # Read the command, arguments and flags set by the executed task. - result.command = nimCommand() - result.arguments = @[] - for arg in nimProjectName().split(): - result.arguments.add(arg) - - cleanup() - -proc execHook*(scriptName, actionName: string, before: bool, - options: Options): ExecutionResult[bool] = - ## Executes the specified action's hook. Depending on ``before``, either - ## the "before" or the "after" hook. - ## - ## `scriptName` should be a filename pointing to the nimscript file. - when declared(NimCompilerApiVersion): - let conf = graph.config - result.success = true - result.flags = newTable[string, seq[string]]() - nimCommand() = internalCmd - let hookName = - if before: actionName.toLowerAscii & "Before" - else: actionName.toLowerAscii & "After" - display("Attempting", "to execute hook $# in $#" % [hookName, scriptName], - priority = MediumPriority) - - let thisModule = execScript(scriptName, result.flags, options) - # Explicitly execute the task procedure, instead of relying on hack. - let prc = thisModule.tab.strTableGet(getIdent(identCache, hookName)) - if prc.isNil: - # Procedure not defined in the NimScript module. - result.success = false - cleanup() - return - when finalApi: - let returnVal = vm.execProc(PCtx(graph.vm), prc, []) - else: - let returnVal = vm.globalCtx.execProc(prc, []) - case returnVal.kind - of nkCharLit..nkUInt64Lit: - result.retVal = returnVal.intVal == 1 - else: assert false - - # Read the command, arguments and flags set by the executed task. - result.command = nimCommand() - result.arguments = @[] - for arg in nimProjectName().split(): - result.arguments.add(arg) - - cleanup() - -proc setNimScriptCommand(command: string) = - when declared(NimCompilerApiVersion): - let conf = graph.config - nimCommand() = command - -proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = - ## Determines whether the last executed task used ``setCommand`` - return execResult.command != internalCmd - -proc listTasks*(scriptName: string, options: Options) = - setNimScriptCommand("help") - - discard execScript(scriptName, nil, options) - # TODO (#402): Make the 'task' template generate explicit data structure - # containing all the task names + descriptions. - cleanup() From bb1dd212247a98fdf007f883de77ba7200a20e2b Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Wed, 7 Aug 2019 19:24:07 +0300 Subject: [PATCH 377/424] Add an unit test for compilation without warnings An unit test which checks whether Nimble compiles without warnings is added. Checking for three warning types cleaned in previous commits is implemented: - [UnusedImport] cleaned in e8c7d5c - [Deprecated] cleaned in 3d6172e - [XDeclaredButNotUsed] cleaned in 7df2ef3 Other types of warnings easily can be added to the test by extending the warnings list. Related to #680 --- src/nimblepkg/nimscriptwrapper.nim | 2 +- tests/tester.nim | 39 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 3f7ba51..d1f8d7a 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -5,7 +5,7 @@ ## scripting language. import version, options, cli, tools -import hashes, json, os, strutils, tables, times, osproc +import hashes, json, os, strutils, tables, times, osproc, strtabs type Flags = TableRef[string, seq[string]] diff --git a/tests/tester.nim b/tests/tester.nim index 2629817..079d9f5 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import osproc, unittest, strutils, os, sequtils, sugar +import osproc, unittest, strutils, os, sequtils, sugar, strformat # TODO: Each test should start off with a clean slate. Currently installed # packages are shared between each test which causes a multitude of issues @@ -10,6 +10,7 @@ var rootDir = getCurrentDir().parentDir() var nimblePath = rootDir / "src" / addFileExt("nimble", ExeExt) var installDir = rootDir / "tests" / "nimbleDir" const path = "../src/nimble" +const stringNotFound = -1 # Clear nimble dir. removeDir(installDir) @@ -863,9 +864,43 @@ test "do not install single dependency multiple times (#678)": check execNimble(["refresh"]).exitCode == QuitSuccess let (output, exitCode) = execNimble("install", "-y") check exitCode == QuitSuccess - check output.find("issue678_dependency_1@0.1.0 already exists") == -1 + let index = output.find("issue678_dependency_1@0.1.0 already exists") + check index == stringNotFound test "Passing command line arguments to a task (#633)": cd "issue633": var (output, exitCode) = execNimble("testTask --testTask") + check exitCode == QuitSuccess check output.contains("Got it") + +test "compilation without warnings": + const buildDir = "./buildDir/" + const filesToBuild = [ + "../src/nimble.nim", + "../src/nimblepkg/nimscriptapi.nim", + "./tester.nim", + ] + + proc execBuild(fileName: string): tuple[output: string, exitCode: int] = + result = execCmdEx(fmt"nim c -o:{buildDir} {fileName}") + + proc checkOutput(output: string): uint = + const warningsToCheck = [ + "[UnusedImport]", + "[Deprecated]", + "[XDeclaredButNotUsed]", + ] + + for line in output.splitLines(): + for warning in warningsToCheck: + if line.find(warning) != stringNotFound: + once: checkpoint("Detected warnings:") + checkpoint(line) + inc(result) + + var linesWithWarningsCount: uint = 0 + for file in filesToBuild: + let (output, exitCode) = execBuild(file) + check exitCode == QuitSuccess + linesWithWarningsCount += checkOutput(output) + check linesWithWarningsCount == 0 From 427b412ff9e6bb72f447b2886b7ff5cfec9393cc Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Wed, 7 Aug 2019 23:03:14 +0300 Subject: [PATCH 378/424] Fix unused import warning on Unix systems The NimbleError exception from the version module is being used only on Windows platforms in the packageinstaller.nim file. Conditional import of the module is used to fix the warning. Related to #680 --- src/nimblepkg/packageinstaller.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim index 71f305f..4bdc921 100644 --- a/src/nimblepkg/packageinstaller.nim +++ b/src/nimblepkg/packageinstaller.nim @@ -3,7 +3,10 @@ import os, strutils, sets, json # Local imports -import version, cli, options, tools +import cli, options, tools + +when defined(windows): + import version when not declared(initHashSet) or not declared(toHashSet): import common From f0c454a3995b92ae50ecb3f511168e2bef21019b Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Thu, 8 Aug 2019 16:34:48 +0300 Subject: [PATCH 379/424] Fix compilation without warnings test case Compilation without warnings test case on Unix systems with older Nim version 0.19.6 had been failing before the fix, because the compiler expects full file name to be passed after the '-o' switch, but not only an output directory name. Related to #680 --- tests/tester.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/tester.nim b/tests/tester.nim index 079d9f5..2c39a83 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -882,7 +882,8 @@ test "compilation without warnings": ] proc execBuild(fileName: string): tuple[output: string, exitCode: int] = - result = execCmdEx(fmt"nim c -o:{buildDir} {fileName}") + result = execCmdEx( + fmt"nim c -o:{buildDir/fileName.splitFile.name} {fileName}") proc checkOutput(output: string): uint = const warningsToCheck = [ @@ -898,6 +899,8 @@ test "compilation without warnings": checkpoint(line) inc(result) + removeDir(buildDir) + var linesWithWarningsCount: uint = 0 for file in filesToBuild: let (output, exitCode) = execBuild(file) From 9d8cc0672455d5cf34adc32c2562ffc68b92c226 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Thu, 8 Aug 2019 17:11:25 +0300 Subject: [PATCH 380/424] Add additional directory to .gitignore The directory "tests/buildDir/" where the build artifacts from the "compilation without warnings" unit test execution are being written is added to the .gitignore file. Related to #680 --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5c629ae..3388f5f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,5 @@ tests/testCommand/testsFail/tests/t2 # Test procedure artifacts tests/nimble-test/ +tests/buildDir/ nimble_*.nims From df11a6f6cf253b2433e37b90dab2967c86afc810 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 11 Aug 2019 15:48:14 +0300 Subject: [PATCH 381/424] Fix tests to pass with the latest Nim There are two issues fixed: - With the latest Nim version sometimes the files `_.nims`' generated on `nim install` contain warning for unused imports which causes the test "can validate package structure (#144)" to fail, because it was searching for the word "warning" in the output. - On Windows Subsystem for Linux, when an import starts sometimes with a lowercase, and sometimes with an uppercase, for example `import uri` and `import Uri`, this causes Nim to create and compile both `stdlib_uri.nim.c` and `stdlib_Uri.nim.c` and to fail on the linking step, because of the same symbols are being redefined. Also the Travis CI build script is changed to test against currently the latest working Nim version 212ae2f. Related to #680 --- .travis.yml | 3 ++- src/nimblepkg/config.nim | 2 +- tests/tester.nim | 33 +++++++++++++++++++++------------ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 13b8678..8cfa912 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ language: c env: - BRANCH=0.19.6 - BRANCH=0.20.2 - - BRANCH=#44aadd50cfa647a759610a15967960632bf597ce + # This is the latest working Nim version against which Nimble is being tested + - BRANCH=#212ae2f1257628bd5d1760593ce0a1bad768831a cache: directories: diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim index ca8dcf2..c4a48fc 100644 --- a/src/nimblepkg/config.nim +++ b/src/nimblepkg/config.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, streams, strutils, os, tables, Uri +import parsecfg, streams, strutils, os, tables, uri import version, cli diff --git a/tests/tester.nim b/tests/tester.nim index 2c39a83..bc9722e 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -72,6 +72,12 @@ proc inLines(lines: seq[string], line: string): bool = for i in lines: if line.normalize in i.normalize: return true +proc hasLineStartingWith(lines: seq[string], prefix: string): bool = + for line in lines: + if line.strip(trailing = false).startsWith(prefix): + return true + return false + test "caching of nims and ini detects changes": cd "caching": var (output, exitCode) = execNimble("dump") @@ -117,7 +123,7 @@ test "can validate package structure (#144)": let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess let lines = output.strip.processOutput() - check(not inLines(lines, "warning")) + check(not lines.hasLineStartingWith("Warning:")) # Test that warnings are produced for the incorrectly structured packages. for package in ["x", "y", "z"]: @@ -128,19 +134,22 @@ test "can validate package structure (#144)": checkpoint(output) case package of "x": - check inLines(lines, "Package 'x' has an incorrect structure. It should" & - " contain a single directory hierarchy for source files," & - " named 'x', but file 'foobar.nim' is in a directory named" & - " 'incorrect' instead.") + check lines.hasLineStartingWith( + "Warning: Package 'x' has an incorrect structure. It should" & + " contain a single directory hierarchy for source files," & + " named 'x', but file 'foobar.nim' is in a directory named" & + " 'incorrect' instead.") of "y": - check inLines(lines, "Package 'y' has an incorrect structure. It should" & - " contain a single directory hierarchy for source files," & - " named 'ypkg', but file 'foobar.nim' is in a directory named" & - " 'yWrong' instead.") + check lines.hasLineStartingWith( + "Warning: Package 'y' has an incorrect structure. It should" & + " contain a single directory hierarchy for source files," & + " named 'ypkg', but file 'foobar.nim' is in a directory named" & + " 'yWrong' instead.") of "z": - check inLines(lines, "Package 'z' has an incorrect structure. The top level" & - " of the package source directory should contain at most one module," & - " named 'z.nim', but a file named 'incorrect.nim' was found.") + check lines.hasLineStartingWith( + "Warning: Package 'z' has an incorrect structure. The top level" & + " of the package source directory should contain at most one module," & + " named 'z.nim', but a file named 'incorrect.nim' was found.") else: assert false From 62699afaa8b63888b6d719b4d877d79291bcafe9 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Tue, 27 Aug 2019 15:17:08 +0300 Subject: [PATCH 382/424] Revert deletion of two not used procedures The two currently not used procedures `getSpecificDir` and `doPull` from `download.nim` file are reverted according to dom96's suggestion in the code review of pull request #692. Now they are marked with used pragma to disable the warning. Related to #680 --- src/nimblepkg/download.nim | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index d2e0074..85bf54f 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -10,6 +10,13 @@ type DownloadMethod* {.pure.} = enum git = "git", hg = "hg" +proc getSpecificDir(meth: DownloadMethod): string {.used.} = + case meth + of DownloadMethod.git: + ".git" + of DownloadMethod.hg: + ".hg" + proc doCheckout(meth: DownloadMethod, downloadDir, branch: string) = case meth of DownloadMethod.git: @@ -23,6 +30,19 @@ proc doCheckout(meth: DownloadMethod, downloadDir, branch: string) = cd downloadDir: doCmd("hg checkout " & branch) +proc doPull(meth: DownloadMethod, downloadDir: string) {.used.} = + case meth + of DownloadMethod.git: + doCheckout(meth, downloadDir, "") + cd downloadDir: + doCmd("git pull") + if existsFile(".gitmodules"): + doCmd("git submodule update") + of DownloadMethod.hg: + doCheckout(meth, downloadDir, "default") + cd downloadDir: + doCmd("hg pull") + proc doClone(meth: DownloadMethod, url, downloadDir: string, branch = "", onlyTip = true) = case meth From 1880730762d298af883d633be5c86ec33bcd8e7a Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Sun, 1 Sep 2019 21:19:06 +0300 Subject: [PATCH 383/424] Fix the test for recursive calling of Nimble tasks The test case for recursive calling of Nimble tasks was not working properly on Windows so far. Related to #680 --- tests/recursive/recursive.nimble | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/recursive/recursive.nimble b/tests/recursive/recursive.nimble index a188170..972dd0b 100644 --- a/tests/recursive/recursive.nimble +++ b/tests/recursive/recursive.nimble @@ -9,13 +9,18 @@ license = "BSD" requires "nim >= 0.12.1" +when defined(windows): + let callNimble = "..\\..\\src\\nimble.exe" +else: + let callNimble = "../../src/nimble" + task recurse, "Level 1": echo 1 - exec "../../src/nimble recurse2" + exec callNimble & " recurse2" task recurse2, "Level 2": echo 2 - exec "../../src/nimble recurse3" + exec callNimble & " recurse3" task recurse3, "Level 3": echo 3 From 46f26e1d4a05ff447d80cce4edd7d9549d45ba80 Mon Sep 17 00:00:00 2001 From: Ivan Bobev Date: Fri, 6 Sep 2019 18:57:58 +0300 Subject: [PATCH 384/424] Move ignored from tests dir to its .gitignore Related to #680 --- .gitignore | 9 +-------- tests/.gitignore | 8 ++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 3388f5f..bac71d6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,20 +6,15 @@ nimcache/ # Absolute paths /src/babel /src/nimble -/tests/tester # executables from test and build /nimble -/tests/nimscript/nimscript -/tests/issue27/issue27 src/nimblepkg/cli src/nimblepkg/packageinfo src/nimblepkg/packageparser src/nimblepkg/reversedeps src/nimblepkg/version -tests/nimble-test/ -tests/packageStructure/validBinary/y -tests/testCommand/testsFail/tests/t2 +src/nimblepkg/download # Windows executables *.exe @@ -36,6 +31,4 @@ tests/testCommand/testsFail/tests/t2 *.orig # Test procedure artifacts -tests/nimble-test/ -tests/buildDir/ nimble_*.nims diff --git a/tests/.gitignore b/tests/.gitignore index 8258bb3..42549a0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,6 +1,10 @@ +tester +/nimble-test +/buildDir /binaryPackage/v1/binaryPackage /binaryPackage/v2/binaryPackage /develop/dependent/src/dependent +/issue27/issue27 /issue206/issue/issue206bin /issue289/issue289 /issue428/nimbleDir/ @@ -13,3 +17,7 @@ /testCommand/testsPass/tests/one /testCommand/testsPass/tests/three /testCommand/testsPass/tests/two +/nimscript/nimscript +/packageStructure/validBinary/y +/testCommand/testsFail/tests/t2 +/passNimFlags/passNimFlags From d6a6a47dd9c4bca64fc06f1362929c377e2262af Mon Sep 17 00:00:00 2001 From: Neelesh Chandola Date: Mon, 16 Sep 2019 15:30:01 +0530 Subject: [PATCH 385/424] Fix https://github.com/nim-lang/nimble/issues/700 --- src/nimblepkg/init.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim index 6648877..8e7c33b 100644 --- a/src/nimblepkg/init.nim +++ b/src/nimblepkg/init.nim @@ -164,8 +164,8 @@ test "correct welcome": writeFile(nimbleFile, """# Package version = $# -author = $# -description = $# +author = "$#" +description = "$#" license = $# srcDir = $# $# @@ -175,7 +175,7 @@ $# requires "nim >= $#" """ % [ - info.pkgVersion.escape(), info.pkgAuthor, info.pkgDesc, + info.pkgVersion.escape(), info.pkgAuthor.replace("\"", "\\\""), info.pkgDesc.replace("\"", "\\\""), info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions, pkgBackend, info.pkgNimDep ] From 8bdc0548175ac3feba968a89625143bacc005d4a Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 20 Sep 2019 09:44:50 +0200 Subject: [PATCH 386/424] fixes #703 --- src/nimble.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6c13ca9..4685eb0 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -348,7 +348,11 @@ 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: let paths = result.deps.map(dep => dep.getRealDir()) - buildFromDir(pkgInfo, paths, options.action.passNimFlags & "-d:release") + let flags = if options.action.typ in {actionInstall, actionPath, actionUninstall, actionDevelop}: + options.action.passNimFlags + else: + @[] + buildFromDir(pkgInfo, paths, flags & "-d:release") let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): From bc8856632a39e201b01bb98a43c97d26bd24ff78 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 20 Sep 2019 09:49:30 +0200 Subject: [PATCH 387/424] version bump to 0.11.0 --- nimble.nimble | 2 +- src/nimblepkg/common.nim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nimble.nimble b/nimble.nimble index 5344094..6cd7e9e 100644 --- a/nimble.nimble +++ b/nimble.nimble @@ -1,6 +1,6 @@ # Package -version = "0.10.2" +version = "0.11.0" author = "Dominik Picheta" description = "Nim package manager." license = "BSD" diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index f015d24..c40a82d 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -62,7 +62,7 @@ when not defined(nimscript): return (error, hint) const - nimbleVersion* = "0.10.2" + nimbleVersion* = "0.11.0" when not declared(initHashSet): import sets From 3eae8d7d616e84cfa4bf9c4264e9513050a780d9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Sep 2019 12:46:42 +0100 Subject: [PATCH 388/424] Add examples to tag prompt in `nimble publish`. --- src/nimblepkg/publish.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim index 186a3a5..f11b979 100644 --- a/src/nimblepkg/publish.nim +++ b/src/nimblepkg/publish.nim @@ -213,7 +213,10 @@ proc publish*(p: PackageInfo, o: Options) = url = promptCustom("Github URL of " & p.name & "?", "") if url.len == 0: userAborted() - let tags = promptCustom("Whitespace separated list of tags?", "") + let tags = promptCustom( + "Whitespace separated list of tags? (For example: web library wrapper)", + "" + ) cd pkgsDir: editJson(p, url, tags, downloadMethod) From 445ecfe9461029184c1e710902262e2149a3564b Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Sep 2019 13:02:04 +0100 Subject: [PATCH 389/424] Fixes #649. The `dump` command now has implicit `-y`. --- src/nimblepkg/cli.nim | 19 +++++++++++++------ src/nimblepkg/options.nim | 6 ++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim index a3ac714..3afda35 100644 --- a/src/nimblepkg/cli.nim +++ b/src/nimblepkg/cli.nim @@ -62,8 +62,18 @@ proc calculateCategoryOffset(category: string): int = assert category.len <= longestCategory return longestCategory - category.len +proc isSuppressed(displayType: DisplayType): bool = + # Don't print any Warning, Message or Success messages when suppression of + # warnings is enabled. That is, unless the user asked for --verbose output. + if globalCLI.suppressMessages and displayType >= Warning and + globalCLI.level == HighPriority: + return true + proc displayCategory(category: string, displayType: DisplayType, priority: Priority) = + if isSuppressed(displayType): + return + # Calculate how much the `category` must be offset to align along a center # line. let offset = calculateCategoryOffset(category) @@ -80,6 +90,9 @@ proc displayCategory(category: string, displayType: DisplayType, proc displayLine(category, line: string, displayType: DisplayType, priority: Priority) = + if isSuppressed(displayType): + return + displayCategory(category, displayType, priority) # Display the message. @@ -87,12 +100,6 @@ proc displayLine(category, line: string, displayType: DisplayType, proc display*(category, msg: string, displayType = Message, priority = MediumPriority) = - # Don't print any Warning, Message or Success messages when suppression of - # warnings is enabled. That is, unless the user asked for --verbose output. - if globalCLI.suppressMessages and displayType >= Warning and - globalCLI.level == HighPriority: - return - # Multiple warnings containing the same messages should not be shown. let warningPair = (category, msg) if displayType == Warning: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 6ef2f95..3482f34 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -187,6 +187,7 @@ proc initAction*(options: var Options, key: string) = options.action.projName = "" of actionDump: options.action.projName = "" + options.forcePrompts = forcePromptYes of actionRefresh: options.action.optionalURL = "" of actionSearch: @@ -264,8 +265,9 @@ proc parseArgument*(key: string, result: var Options) = result.action.search.add(key) of actionInit, actionDump: if result.action.projName != "": - raise newException(NimbleError, - "Can only initialize one package at a time.") + raise newException( + NimbleError, "Can only perform this action on one package at a time." + ) result.action.projName = key of actionCompile, actionDoc: result.action.file = key From 36c4a39674c0f81baa87d930265f5903d7a32fed Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Sep 2019 22:54:08 +0100 Subject: [PATCH 390/424] Temp files are no longer removed when --debug is present. --- src/nimble.nim | 10 +++++++--- src/nimblepkg/nimscriptwrapper.nim | 7 ++++--- src/nimblepkg/options.nim | 7 +++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 4685eb0..666a60f 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1040,7 +1040,7 @@ proc test(options: Options) = display("Error:", error, Error, HighPriority) proc check(options: Options) = - ## Validates a package a in the current working directory. + ## Validates a package in the current working directory. let nimbleFile = findNimbleFile(getCurrentDir(), true) var error: ValidationError var pkgInfo: PackageInfo @@ -1134,8 +1134,10 @@ when isMainModule: var error = "" var hint = "" + var opt: Options try: - parseCmdLine().doAction() + opt = parseCmdLine() + opt.doAction() except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) (error, hint) = getOutputInfo(currentExc) @@ -1143,7 +1145,9 @@ when isMainModule: discard finally: try: - removeDir(getNimbleTempDir()) + let folder = getNimbleTempDir() + if opt.shouldRemoveTmp(folder): + removeDir(folder) except OSError: let msg = "Couldn't remove Nimble's temp dir" display("Warning:", msg, Warning, MediumPriority) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index d1f8d7a..d7b7a3b 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -36,8 +36,8 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): defer: # Only if copied in this invocation, allows recursive calls of nimble - if not isScriptResultCopied: - nimsFileCopied.removeFile() + if not isScriptResultCopied and options.shouldRemoveTmp(nimsFileCopied): + nimsFileCopied.removeFile() var cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & @@ -56,7 +56,8 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): result.exitCode = execCmd(cmd) if outFile.fileExists(): result.output = outFile.readFile() - discard outFile.tryRemoveFile() + if options.shouldRemoveTmp(outFile): + discard outFile.tryRemoveFile() proc getNimsFile(scriptName: string, options: Options): string = let diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 3482f34..80a649d 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -425,3 +425,10 @@ proc briefClone*(options: Options): Options = newOptions.forcePrompts = options.forcePrompts newOptions.pkgInfoCache = options.pkgInfoCache return newOptions + +proc shouldRemoveTmp*(options: Options, file: string): bool = + result = true + if options.verbosity <= DebugPriority: + let msg = "Not removing temporary path because of debug verbosity: " & file + display("Warning:", msg, Warning, MediumPriority) + return false \ No newline at end of file From c834faf60e1dbdd8ae46456e1fb2dc2db05e4e91 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Sep 2019 23:34:02 +0100 Subject: [PATCH 391/424] Implements `nimble run`. Fixes #614. --- src/nimble.nim | 50 +++++++++-- src/nimblepkg/options.nim | 180 +++++++++++++++++++++++++++----------- tests/run/run.nimble | 14 +++ tests/run/src/run.nim | 4 + tests/tester.nim | 27 +++++- 5 files changed, 216 insertions(+), 59 deletions(-) create mode 100644 tests/run/run.nimble create mode 100644 tests/run/src/run.nim diff --git a/src/nimble.nim b/src/nimble.nim index 666a60f..7eb5ee4 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -4,6 +4,7 @@ import system except TResult import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils +import std/options as std_opt import strutils except toLower from unicode import toLower @@ -213,7 +214,10 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = for i in reverseDeps: addRevDep(options.nimbleData, i, pkginfo) -proc buildFromDir(pkgInfo: PackageInfo, paths, args: seq[string]) = +proc buildFromDir( + pkgInfo: PackageInfo, paths, args: seq[string], + binToBuild: Option[string] = none[string]() +) = ## Builds a package as specified by ``pkgInfo``. if pkgInfo.bin.len == 0: raise newException(NimbleError, @@ -223,6 +227,12 @@ proc buildFromDir(pkgInfo: PackageInfo, paths, args: seq[string]) = let realDir = pkgInfo.getRealDir() for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: + # Check if this is the only binary that we want to build. + if binToBuild.isSome() and binToBuild.get() != bin: + let binToBuild = binToBuild.get() + if bin.extractFilename().changeFileExt("") != binToBuild: + continue + let outputOpt = "-o:\"" & pkgInfo.getOutputDir(bin) & "\"" display("Building", "$1/$2 using $3 backend" % [pkginfo.name, bin, pkgInfo.backend], priority = HighPriority) @@ -502,12 +512,12 @@ proc build(options: Options) = nimScriptHint(pkgInfo) let deps = processDeps(pkginfo, options) let paths = deps.map(dep => dep.getRealDir()) - var args = options.action.compileOptions - buildFromDir(pkgInfo, paths, args) + var args = options.getCompilationFlags() + buildFromDir(pkgInfo, paths, args, options.getCompilationBinary()) proc execBackend(options: Options) = let - bin = options.action.file + bin = options.getCompilationBinary().get() binDotNim = bin.addFileExt("nim") if bin == "": raise newException(NimbleError, "You need to specify a file.") @@ -522,7 +532,7 @@ proc execBackend(options: Options) = var args = "" for dep in deps: args.add("--path:\"" & dep.getRealDir() & "\" ") - for option in options.action.compileOptions: + for option in options.getCompilationFlags(): args.add("\"" & option & "\" ") let backend = @@ -1011,9 +1021,9 @@ proc test(options: Options) = optsCopy.action = Action(typ: actionCompile) optsCopy.action.file = file.path optsCopy.action.backend = "c" - optsCopy.action.compileOptions = @[] - optsCopy.action.compileOptions.add("-r") - optsCopy.action.compileOptions.add("--path:.") + optsCopy.getCompilationFlags() = @[] + optsCopy.getCompilationFlags().add("-r") + optsCopy.getCompilationFlags().add("--path:.") let binFileName = file.path.changeFileExt(ExeExt) existsBefore = existsFile(binFileName) @@ -1058,6 +1068,28 @@ proc check(options: Options) = display("Failure:", "Validation failed", Error, HighPriority) quit(QuitFailure) +proc run(options: Options) = + # Verify parameters. + let binary = options.getCompilationBinary().get() + if binary.len == 0: + raiseNimbleError("Please specify a binary to run") + + var pkgInfo = getPkgInfo(getCurrentDir(), options) + if binary notin pkgInfo.bin: + raiseNimbleError( + "Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.name] + ) + + let binaryPath = pkgInfo.getOutputDir(binary) + + # Build the binary. + build(options) + + # Now run it. + let args = options.action.runFlags.join(" ") + + doCmd("$# $#" % [binaryPath, args], showOutput = true) + proc doAction(options: Options) = if options.showHelp: writeHelp() @@ -1094,6 +1126,8 @@ proc doAction(options: Options) = listPaths(options) of actionBuild: build(options) + of actionRun: + run(options) of actionCompile, actionDoc: execBackend(options) of actionInit: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 80a649d..28560e7 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -2,6 +2,8 @@ # BSD License. Look at license.txt for more info. import json, strutils, os, parseopt, strtabs, uri, tables, terminal +import sequtils, sugar +import std/options as std_opt from httpclient import Proxy, newProxy import config, version, common, cli @@ -26,12 +28,15 @@ type continueTestsOnFailure*: bool ## Whether packages' repos should always be downloaded with their history. forceFullClone*: bool + # Temporary storage of flags that have not been captured by any specific Action. + unknownFlags*: seq[(CmdLineKind, string, string)] ActionType* = enum actionNil, actionRefresh, actionInit, actionDump, actionPublish, actionInstall, actionSearch, actionList, actionBuild, actionPath, actionUninstall, actionCompile, - actionDoc, actionCustom, actionTasks, actionDevelop, actionCheck + actionDoc, actionCustom, actionTasks, actionDevelop, actionCheck, + actionRun Action* = object case typ*: ActionType @@ -49,7 +54,11 @@ type of actionCompile, actionDoc, actionBuild: file*: string backend*: string - compileOptions*: seq[string] + compileOptions: seq[string] + of actionRun: + runFile: string + compileFlags: seq[string] + runFlags*: seq[string] of actionCustom: command*: string arguments*: seq[string] @@ -76,7 +85,8 @@ Commands: toplevel directory of the Nimble package. uninstall [pkgname, ...] Uninstalls a list of packages. [-i, --inclDeps] Uninstall package and dependent package(s). - build Builds a package. + build [opts, ...] Builds a package. + run [opts, ...] bin Builds and runs a package. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. test Compiles and executes tests @@ -143,6 +153,8 @@ proc parseActionType*(action: string): ActionType = result = actionPath of "build": result = actionBuild + of "run": + result = actionRun of "c", "compile", "js", "cpp", "cc": result = actionCompile of "doc", "doc2": @@ -196,7 +208,7 @@ proc initAction*(options: var Options, key: string) = options.action.command = key options.action.arguments = @[] options.action.flags = newStringTable() - of actionPublish, actionList, actionTasks, actionCheck, + of actionPublish, actionList, actionTasks, actionCheck, actionRun, actionNil: discard proc prompt*(options: Options, question: string): bool = @@ -271,18 +283,37 @@ proc parseArgument*(key: string, result: var Options) = result.action.projName = key of actionCompile, actionDoc: result.action.file = key - of actionList, actionBuild, actionPublish: + of actionList, actionPublish: result.showHelp = true + of actionBuild: + result.action.file = key + of actionRun: + if result.action.runFile.len == 0: + result.action.runFile = key + else: + result.action.runFlags.add(key) of actionCustom: result.action.arguments.add(key) else: discard +proc getFlagString(kind: CmdLineKind, flag, val: string): string = + let prefix = + case kind + of cmdShortOption: "-" + of cmdLongOption: "--" + else: "" + if val == "": + return prefix & flag + else: + return prefix & flag & ":" & val + proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = - var wasFlagHandled = true + let f = flag.normalize() # Global flags. + var isGlobalFlag = true case f of "help", "h": result.showHelp = true of "version", "v": result.showVersion = true @@ -293,54 +324,56 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = of "debug": result.verbosity = DebugPriority of "nocolor": result.noColor = true of "disablevalidation": result.disableValidation = true + else: isGlobalFlag = false + + var wasFlagHandled = true # Action-specific flags. - else: - case result.action.typ - of actionSearch, actionList: - case f - of "installed", "i": - result.queryInstalled = true - of "ver": - result.queryVersions = true - else: - wasFlagHandled = false - of actionInstall: - case f - of "depsonly", "d": - result.depsOnly = true - of "passnim", "p": - result.action.passNimFlags.add(val) - else: - wasFlagHandled = false - of actionUninstall: - case f - of "incldeps", "i": - result.uninstallRevDeps = true - else: - wasFlagHandled = false - of actionCompile, actionDoc, actionBuild: - let prefix = if kind == cmdShortOption: "-" else: "--" - if val == "": - result.action.compileOptions.add(prefix & flag) - else: - result.action.compileOptions.add(prefix & flag & ":" & val) - of actionCustom: - if result.action.command.normalize == "test": - if f == "continue" or f == "c": - result.continueTestsOnFailure = true - result.action.flags[flag] = val + case result.action.typ + of actionSearch, actionList: + case f + of "installed", "i": + result.queryInstalled = true + of "ver": + result.queryVersions = true else: wasFlagHandled = false + of actionInstall: + case f + of "depsonly", "d": + result.depsOnly = true + of "passnim", "p": + result.action.passNimFlags.add(val) + else: + wasFlagHandled = false + of actionUninstall: + case f + of "incldeps", "i": + result.uninstallRevDeps = true + else: + wasFlagHandled = false + of actionCompile, actionDoc, actionBuild: + if not isGlobalFlag: + result.action.compileOptions.add(getFlagString(kind, flag, val)) + of actionRun: + result.action.runFlags.add(getFlagString(kind, flag, val)) + of actionCustom: + if result.action.command.normalize == "test": + if f == "continue" or f == "c": + result.continueTestsOnFailure = true + result.action.flags[flag] = val + else: + wasFlagHandled = false - if not wasFlagHandled: - raise newException(NimbleError, "Unknown option: --" & flag) + if not wasFlagHandled and not isGlobalFlag: + result.unknownFlags.add((kind, flag, val)) -proc initOptions*(): Options = - result.action = Action(typ: actionNil) - result.pkgInfoCache = newTable[string, PackageInfo]() - result.nimbleDir = "" - result.verbosity = HighPriority - result.noColor = not isatty(stdout) +proc initOptions(): Options = + Options( + action: Action(typ: actionNil), + pkgInfoCache: newTable[string, PackageInfo](), + verbosity: HighPriority, + noColor: not isatty(stdout) + ) proc parseMisc(options: var Options) = # Load nimbledata.json @@ -355,6 +388,20 @@ proc parseMisc(options: var Options) = else: options.nimbleData = %{"reverseDeps": newJObject()} +proc handleUnknownFlags(options: var Options) = + if options.action.typ == actionRun: + options.action.compileFlags = + map(options.unknownFlags, x => getFlagString(x[0], x[1], x[2])) + options.unknownFlags = @[] + + # Any unhandled flags? + if options.unknownFlags.len > 0: + let flag = options.unknownFlags[0] + raise newException( + NimbleError, + "Unknown option: " & getFlagString(flag[0], flag[1], flag[2]) + ) + proc parseCmdLine*(): Options = result = initOptions() @@ -371,6 +418,8 @@ proc parseCmdLine*(): Options = parseFlag(key, val, result, kind) of cmdEnd: assert(false) # cannot happen + handleUnknownFlags(result) + # Set verbosity level. setVerbosity(result.verbosity) @@ -386,6 +435,11 @@ proc parseCmdLine*(): Options = if result.action.typ == actionNil and not result.showVersion: result.showHelp = true + if result.action.typ != actionNil and result.showVersion: + # We've got another command that should be handled. For example: + # nimble run foobar -v + result.showVersion = false + proc getProxy*(options: Options): Proxy = ## Returns ``nil`` if no proxy is specified. var url = "" @@ -431,4 +485,30 @@ proc shouldRemoveTmp*(options: Options, file: string): bool = if options.verbosity <= DebugPriority: let msg = "Not removing temporary path because of debug verbosity: " & file display("Warning:", msg, Warning, MediumPriority) - return false \ No newline at end of file + return false + +proc getCompilationFlags*(options: var Options): var seq[string] = + case options.action.typ + of actionBuild, actionDoc, actionCompile: + return options.action.compileOptions + of actionRun: + return options.action.compileFlags + else: + assert false + +proc getCompilationFlags*(options: Options): seq[string] = + var opt = options + return opt.getCompilationFlags() + +proc getCompilationBinary*(options: Options): Option[string] = + case options.action.typ + of actionBuild, actionDoc, actionCompile: + let file = options.action.file.changeFileExt("") + if file.len > 0: + return some(file) + of actionRun: + let runFile = options.action.runFile.changeFileExt("") + if runFile.len > 0: + return some(runFile) + else: + discard \ No newline at end of file diff --git a/tests/run/run.nimble b/tests/run/run.nimble new file mode 100644 index 0000000..4b09bdd --- /dev/null +++ b/tests/run/run.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" +bin = @["run"] + + + +# Dependencies + +requires "nim >= 0.20.0" diff --git a/tests/run/src/run.nim b/tests/run/src/run.nim new file mode 100644 index 0000000..af98995 --- /dev/null +++ b/tests/run/src/run.nim @@ -0,0 +1,4 @@ +import os + +when isMainModule: + echo("Testing `nimble run`: ", commandLineParams()) diff --git a/tests/tester.nim b/tests/tester.nim index bc9722e..c70c5b7 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -33,8 +33,8 @@ template cd*(dir: string, body: untyped) = proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = var quotedArgs = @args + quotedArgs.insert("--nimbleDir:" & installDir) quotedArgs.insert(nimblePath) - quotedArgs.add("--nimbleDir:" & installDir) quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\"")) let path {.used.} = getCurrentDir().parentDir() / "src" @@ -49,6 +49,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = cmd = "DYLD_LIBRARY_PATH=/usr/local/opt/openssl@1.1/lib " & cmd result = execCmdEx(cmd) + checkpoint(cmd) checkpoint(result.output) proc execNimbleYes(args: varargs[string]): tuple[output: string, exitCode: int]= @@ -882,6 +883,30 @@ test "Passing command line arguments to a task (#633)": check exitCode == QuitSuccess check output.contains("Got it") +suite "nimble run": + test "Invalid binary": + cd "run": + var (output, exitCode) = execNimble( + "--debug", # Flag to enable debug verbosity in Nimble + "run", # Run command invokation + "blahblah", # The command to run + ) + check exitCode == QuitFailure + check output.contains("Binary 'blahblah' is not defined in 'run' package.") + + test "Parameters passed to executable": + cd "run": + var (output, exitCode) = execNimble( + "--debug", # Flag to enable debug verbosity in Nimble + "run", # Run command invokation + "run", # The command to run + "--debug", # First argument passed to the executed command + "check" # Second argument passed to the executed command. + ) + check exitCode == QuitSuccess + check output.contains("tests/run/run --debug check") + check output.contains("""Testing `nimble run`: @["--debug", "check"]""") + test "compilation without warnings": const buildDir = "./buildDir/" const filesToBuild = [ From 55dd892aab3caeba73709f4ac45e93411a5d3846 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 00:11:28 +0100 Subject: [PATCH 392/424] Fixes #631. Test command now respects backend. --- src/nimble.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 7eb5ee4..402601a 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1004,6 +1004,8 @@ proc develop(options: Options) = proc test(options: Options) = ## Executes all tests starting with 't' in the ``tests`` directory. ## Subdirectories are not walked. + var pkgInfo = getPkgInfo(getCurrentDir(), options) + var files = toSeq(walkDir(getCurrentDir() / "tests")) tests, failures: int @@ -1020,7 +1022,7 @@ proc test(options: Options) = var optsCopy = options.briefClone() optsCopy.action = Action(typ: actionCompile) optsCopy.action.file = file.path - optsCopy.action.backend = "c" + optsCopy.action.backend = pkgInfo.backend optsCopy.getCompilationFlags() = @[] optsCopy.getCompilationFlags().add("-r") optsCopy.getCompilationFlags().add("--path:.") From 28ff2e04a7f76c4ed0c305a7138f67a10b00ea4d Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 00:15:37 +0100 Subject: [PATCH 393/424] Fixes tests on 0.19.6. --- tests/run/run.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run/run.nimble b/tests/run/run.nimble index 4b09bdd..055bc1e 100644 --- a/tests/run/run.nimble +++ b/tests/run/run.nimble @@ -11,4 +11,4 @@ bin = @["run"] # Dependencies -requires "nim >= 0.20.0" +requires "nim >= 0.19.0" From 4a2aaa07dc6b52247bc0b7d40fac30a1f7eabac0 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 00:53:52 +0100 Subject: [PATCH 394/424] Implements NimblePkgVersion define. Fixes #625. --- src/nimble.nim | 10 ++++++---- .../nimbleVersionDefine.nimble | 14 ++++++++++++++ .../nimbleVersionDefine/src/nimbleVersionDefine | Bin 0 -> 86500 bytes .../src/nimbleVersionDefine.nim | 3 +++ tests/tester.nim | 10 ++++++++++ 5 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tests/nimbleVersionDefine/nimbleVersionDefine.nimble create mode 100755 tests/nimbleVersionDefine/src/nimbleVersionDefine create mode 100644 tests/nimbleVersionDefine/src/nimbleVersionDefine.nim diff --git a/src/nimble.nim b/src/nimble.nim index 402601a..5cf9652 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -225,6 +225,7 @@ proc buildFromDir( " `bin` key in your .nimble file?") var args = args let realDir = pkgInfo.getRealDir() + let nimblePkgVersion = "-d:NimblePkgVersion=" & pkgInfo.version for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: # Check if this is the only binary that we want to build. @@ -242,8 +243,8 @@ proc buildFromDir( createDir(outputDir) try: - doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# $# \"$#\"" % - [pkgInfo.backend, join(args, " "), outputOpt, + doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# $# \"$#\"" % + [pkgInfo.backend, nimblePkgVersion, join(args, " "), outputOpt, realDir / bin.changeFileExt("nim")]) except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) @@ -530,6 +531,7 @@ proc execBackend(options: Options) = nimScriptHint(pkgInfo) let deps = processDeps(pkginfo, options) + let nimblePkgVersion = "-d:NimblePkgVersion=" & pkgInfo.version var args = "" for dep in deps: args.add("--path:\"" & dep.getRealDir() & "\" ") for option in options.getCompilationFlags(): @@ -547,8 +549,8 @@ proc execBackend(options: Options) = else: display("Generating", ("documentation for $1 (from package $2) using $3 " & "backend") % [bin, pkgInfo.name, backend], priority = HighPriority) - doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# \"$#\"" % - [backend, args, bin], showOutput = true) + doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# \"$#\"" % + [backend, nimblePkgVersion, args, bin], showOutput = true) display("Success:", "Execution finished", Success, HighPriority) proc search(options: Options) = diff --git a/tests/nimbleVersionDefine/nimbleVersionDefine.nimble b/tests/nimbleVersionDefine/nimbleVersionDefine.nimble new file mode 100644 index 0000000..b47b049 --- /dev/null +++ b/tests/nimbleVersionDefine/nimbleVersionDefine.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" +bin = @["nimbleVersionDefine"] + + + +# Dependencies + +requires "nim >= 0.16.0" diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine b/tests/nimbleVersionDefine/src/nimbleVersionDefine new file mode 100755 index 0000000000000000000000000000000000000000..3b089c01cfe8bed84e2cacb812590f1b97d73f10 GIT binary patch literal 86500 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 PpazRKkMYRB4(R+}iPK7{ literal 0 HcmV?d00001 diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim b/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim new file mode 100644 index 0000000..572dab8 --- /dev/null +++ b/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim @@ -0,0 +1,3 @@ +when isMainModule: + const NimblePkgVersion {.strdefine.} = "Unknown" + echo(NimblePkgVersion) diff --git a/tests/tester.nim b/tests/tester.nim index c70c5b7..19c52cf 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -907,6 +907,16 @@ suite "nimble run": check output.contains("tests/run/run --debug check") check output.contains("""Testing `nimble run`: @["--debug", "check"]""") +test "NimbleVersion is defined": + cd "nimbleVersionDefine": + var (output, exitCode) = execNimble("c", "-r", "src/nimbleVersionDefine.nim") + check output.contains("0.1.0") + check exitCode == QuitSuccess + + var (output2, exitCode2) = execNimble("run", "nimbleVersionDefine") + check output2.contains("0.1.0") + check exitCode2 == QuitSuccess + test "compilation without warnings": const buildDir = "./buildDir/" const filesToBuild = [ From 137bb1ed075708da3807c9e4b89f5c6e8d103210 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 10:45:26 +0100 Subject: [PATCH 395/424] Fixes #606. Build before/after hook executed every time package is built. --- src/nimble.nim | 30 +++++++++++++++++++---------- src/nimblepkg/nimscriptexecutor.nim | 10 +++++----- tests/nimscript/nimscript.nimble | 6 ++++++ tests/tester.nim | 9 +++++++++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 5cf9652..2185211 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -216,15 +216,21 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = proc buildFromDir( pkgInfo: PackageInfo, paths, args: seq[string], - binToBuild: Option[string] = none[string]() + options: Options ) = ## Builds a package as specified by ``pkgInfo``. + let binToBuild = options.getCompilationBinary() + # Handle pre-`build` hook. + let realDir = pkgInfo.getRealDir() + cd realDir: # Make sure `execHook` executes the correct .nimble file. + if not execHook(options, actionBuild, true): + raise newException(NimbleError, "Pre-hook prevented further execution.") + if pkgInfo.bin.len == 0: raise newException(NimbleError, "Nothing to build. Did you specify a module to build using the" & " `bin` key in your .nimble file?") var args = args - let realDir = pkgInfo.getRealDir() let nimblePkgVersion = "-d:NimblePkgVersion=" & pkgInfo.version for path in paths: args.add("--path:\"" & path & "\" ") for bin in pkgInfo.bin: @@ -255,6 +261,10 @@ proc buildFromDir( exc.hint = hint raise exc + # Handle post-`build` hook. + cd realDir: # Make sure `execHook` executes the correct .nimble file. + discard execHook(options, actionBuild, false) + proc removePkgDir(dir: string, options: Options) = ## Removes files belonging to the package in ``dir``. try: @@ -332,7 +342,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # Handle pre-`install` hook. if not options.depsOnly: cd dir: # Make sure `execHook` executes the correct .nimble file. - if not execHook(options, true): + if not execHook(options, actionInstall, true): raise newException(NimbleError, "Pre-hook prevented further execution.") var pkgInfo = getPkgInfo(dir, options) @@ -363,7 +373,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, options.action.passNimFlags else: @[] - buildFromDir(pkgInfo, paths, flags & "-d:release") + buildFromDir(pkgInfo, paths, flags & "-d:release", options) let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): @@ -446,7 +456,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, # executes the hook defined in the CWD, so we set it to where the package # has been installed. cd dest.splitFile.dir: - discard execHook(options, false) + discard execHook(options, actionInstall, false) proc getDownloadInfo*(pv: PkgTuple, options: Options, doPrompt: bool): (DownloadMethod, string, @@ -514,7 +524,7 @@ proc build(options: Options) = let deps = processDeps(pkginfo, options) let paths = deps.map(dep => dep.getRealDir()) var args = options.getCompilationFlags() - buildFromDir(pkgInfo, paths, args, options.getCompilationBinary()) + buildFromDir(pkgInfo, paths, args, options) proc execBackend(options: Options) = let @@ -917,7 +927,7 @@ proc developFromDir(dir: string, options: Options) = raiseNimbleError("Cannot develop dependencies only.") cd dir: # Make sure `execHook` executes the correct .nimble file. - if not execHook(options, true): + if not execHook(options, actionDevelop, true): raise newException(NimbleError, "Pre-hook prevented further execution.") var pkgInfo = getPkgInfo(dir, options) @@ -970,7 +980,7 @@ proc developFromDir(dir: string, options: Options) = # Execute the post-develop hook. cd dir: - discard execHook(options, false) + discard execHook(options, actionDevelop, false) proc develop(options: Options) = if options.action.packages == @[]: @@ -1150,7 +1160,7 @@ proc doAction(options: Options) = of actionNil: assert false of actionCustom: - if not execHook(options, true): + if not execHook(options, actionCustom, true): display("Warning", "Pre-hook prevented further execution.", Warning, HighPriority) return @@ -1166,7 +1176,7 @@ proc doAction(options: Options) = if isPreDefined: test(options) # Run the post hook for `test` in case it exists. - discard execHook(options, false) + discard execHook(options, actionCustom, false) when isMainModule: var error = "" diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim index bf8afd1..122c41c 100644 --- a/src/nimblepkg/nimscriptexecutor.nim +++ b/src/nimblepkg/nimscriptexecutor.nim @@ -6,12 +6,12 @@ import os, strutils, sets import packageparser, common, packageinfo, options, nimscriptwrapper, cli, version -proc execHook*(options: Options, before: bool): bool = +proc execHook*(options: Options, hookAction: ActionType, before: bool): bool = ## Returns whether to continue. result = true # For certain commands hooks should not be evaluated. - if options.action.typ in noHookActions: + if hookAction in noHookActions: return var nimbleFile = "" @@ -21,8 +21,8 @@ proc execHook*(options: Options, before: bool): bool = # PackageInfos are cached so we can read them as many times as we want. let pkgInfo = getPkgInfoFromFile(nimbleFile, options) let actionName = - if options.action.typ == actionCustom: options.action.command - else: ($options.action.typ)[6 .. ^1] + if hookAction == actionCustom: options.action.command + else: ($hookAction)[6 .. ^1] let hookExists = if before: actionName.normalize in pkgInfo.preHooks else: actionName.normalize in pkgInfo.postHooks @@ -58,7 +58,7 @@ proc execCustom*(options: Options, HighPriority) return - if not execHook(options, false): + if not execHook(options, actionCustom, false): return return true diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble index f27631a..39f3710 100644 --- a/tests/nimscript/nimscript.nimble +++ b/tests/nimscript/nimscript.nimble @@ -54,3 +54,9 @@ before install: after install: echo("After PkgDir: ", getPkgDir()) + +before build: + echo("Before build") + +after build: + echo("After build") \ No newline at end of file diff --git a/tests/tester.nim b/tests/tester.nim index 19c52cf..21c7011 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -286,12 +286,21 @@ suite "nimscript": cd "nimscript": let (output, exitCode) = execNimble(["install", "-y"]) check exitCode == QuitSuccess + check output.contains("Before build") + check output.contains("After build") let lines = output.strip.processOutput() check lines[0].startsWith("Before PkgDir:") check lines[0].endsWith("tests" / "nimscript") check lines[^1].startsWith("After PkgDir:") check lines[^1].endsWith("tests" / "nimbleDir" / "pkgs" / "nimscript-0.1.0") + test "before/after on build": + cd "nimscript": + let (output, exitCode) = execNimble(["build"]) + check exitCode == QuitSuccess + check output.contains("Before build") + check output.contains("After build") + test "can execute nimscript tasks": cd "nimscript": let (output, exitCode) = execNimble("--verbose", "work") From 419eba036b439ca4a07c201c1969ddbe475719ac Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 11:15:00 +0100 Subject: [PATCH 396/424] Improve error message when there are no packages to uninstall. --- src/nimble.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index 2185211..6b879ac 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -892,7 +892,7 @@ proc uninstall(options: Options) = pkgsToDelete.incl pkg if pkgsToDelete.len == 0: - raise newException(NimbleError, "Failed uninstall - no packages selected") + raise newException(NimbleError, "Failed uninstall - no packages to delete") var pkgNames = "" for pkg in pkgsToDelete.items: From da3f70cb98ef60598583eb889aeadfd63f96c135 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 11:46:29 +0100 Subject: [PATCH 397/424] Fixes #713 and adds test for --depsOnly. --- src/nimblepkg/options.nim | 9 +++++++++ tests/tester.nim | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 28560e7..72f4a3a 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -390,9 +390,18 @@ proc parseMisc(options: var Options) = proc handleUnknownFlags(options: var Options) = if options.action.typ == actionRun: + # ActionRun uses flags that come before the command as compilation flags + # and flags that come after as run flags. options.action.compileFlags = map(options.unknownFlags, x => getFlagString(x[0], x[1], x[2])) options.unknownFlags = @[] + else: + # For everything else, handle the flags that came before the command + # normally. + let unknownFlags = options.unknownFlags + options.unknownFlags = @[] + for flag in unknownFlags: + parseFlag(flag[1], flag[2], options, flag[0]) # Any unhandled flags? if options.unknownFlags.len > 0: diff --git a/tests/tester.nim b/tests/tester.nim index 21c7011..efa0107 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -79,6 +79,13 @@ proc hasLineStartingWith(lines: seq[string], prefix: string): bool = return true return false +test "depsOnly + flag order test": + var (output, exitCode) = execNimble( + "--depsOnly", "install", "-y", "https://github.com/nimble-test/packagebin2" + ) + check(not output.contains("Success: packagebin2 installed successfully.")) + check exitCode == QuitSuccess + test "caching of nims and ini detects changes": cd "caching": var (output, exitCode) = execNimble("dump") From 5ea2ac34fefa9339945db4c473b3f7dd6ba77e0c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 11:53:03 +0100 Subject: [PATCH 398/424] Update CI to test against latest Nim HEAD commit. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8cfa912..3f824f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: - BRANCH=0.19.6 - BRANCH=0.20.2 # This is the latest working Nim version against which Nimble is being tested - - BRANCH=#212ae2f1257628bd5d1760593ce0a1bad768831a + - BRANCH=#2565d3d102efd21ba02ed1f3b96d892fe2637d2b cache: directories: From c85cdfd8144461757e4d83e0df4a1ae88e16cd12 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 12:00:15 +0100 Subject: [PATCH 399/424] Fixes #706. No more unused import warnings. --- src/nimblepkg/nimscriptwrapper.nim | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index d7b7a3b..23c23c9 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -39,9 +39,15 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): if not isScriptResultCopied and options.shouldRemoveTmp(nimsFileCopied): nimsFileCopied.removeFile() - var - cmd = ("nim e --hints:off --verbosity:0 -p:" & (getTempDir() / "nimblecache").quoteShell & - " " & nimsFileCopied.quoteShell & " " & outFile.quoteShell & " " & actionName).strip() + var cmd = ( + "nim e $# -p:$# $# $# $#" % [ + "--hints:off --warning[UnusedImport]:off --verbosity:0", + (getTempDir() / "nimblecache").quoteShell, + nimsFileCopied.quoteShell, + outFile.quoteShell, + actionName + ] + ).strip() if options.action.typ == actionCustom and actionName != "printPkgInfo": for i in options.action.arguments: From 46dc98bb62d8250af9f13f2f3628d67a462f50d3 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sat, 21 Sep 2019 23:52:28 +0100 Subject: [PATCH 400/424] Fixes #710. --- src/nimblepkg/nimscriptwrapper.nim | 61 ++++++++++++++-------- tests/invalidPackage/invalidPackage.nimble | 13 +++++ tests/tester.nim | 7 +++ 3 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 tests/invalidPackage/invalidPackage.nimble diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index 23c23c9..baad4e7 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -4,9 +4,10 @@ ## Implements the new configuration system for Nimble. Uses Nim as a ## scripting language. -import version, options, cli, tools import hashes, json, os, strutils, tables, times, osproc, strtabs +import version, options, cli, tools + type Flags = TableRef[string, seq[string]] ExecutionResult*[T] = object @@ -15,13 +16,23 @@ type arguments*: seq[string] flags*: Flags retVal*: T + stdout*: string const internalCmd = "e" nimscriptApi = staticRead("nimscriptapi.nim") + printPkgInfo = "printPkgInfo" -proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): - tuple[output: string, exitCode: int] = +proc isCustomTask(actionName: string, options: Options): bool = + options.action.typ == actionCustom and actionName != printPkgInfo + +proc needsLiveOutput(actionName: string, options: Options, isHook: bool): bool = + let isCustomTask = isCustomTask(actionName, options) + return isCustomTask or isHook or actionName == "" + +proc execNimscript( + nimsFile, projectDir, actionName: string, options: Options, isHook: bool +): tuple[output: string, exitCode: int, stdout: string] = let nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & getProcessId() & ".nims" outFile = getNimbleTempDir() & ".out" @@ -41,7 +52,7 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): var cmd = ( "nim e $# -p:$# $# $# $#" % [ - "--hints:off --warning[UnusedImport]:off --verbosity:0", + "--hints:off --verbosity:0", (getTempDir() / "nimblecache").quoteShell, nimsFileCopied.quoteShell, outFile.quoteShell, @@ -49,7 +60,8 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): ] ).strip() - if options.action.typ == actionCustom and actionName != "printPkgInfo": + let isCustomTask = isCustomTask(actionName, options) + if isCustomTask: for i in options.action.arguments: cmd &= " " & i.quoteShell() for key, val in options.action.flags.pairs(): @@ -59,7 +71,12 @@ proc execNimscript(nimsFile, projectDir, actionName: string, options: Options): displayDebug("Executing " & cmd) - result.exitCode = execCmd(cmd) + if needsLiveOutput(actionName, options, isHook): + result.exitCode = execCmd(cmd) + else: + # We want to capture any possible errors when parsing a .nimble + # file's metadata. See #710. + (result.stdout, result.exitCode) = execCmdEx(cmd) if outFile.fileExists(): result.output = outFile.readFile() if options.shouldRemoveTmp(outFile): @@ -112,27 +129,29 @@ proc getIniFile*(scriptName: string, options: Options): string = scriptName.getLastModificationTime() if not isIniResultCached: - let - (output, exitCode) = - execNimscript(nimsFile, scriptName.parentDir(), "printPkgInfo", options) + let (output, exitCode, stdout) = execNimscript( + nimsFile, scriptName.parentDir(), printPkgInfo, options, isHook=false + ) if exitCode == 0 and output.len != 0: result.writeFile(output) else: - raise newException(NimbleError, output & "\nprintPkgInfo() failed") + raise newException(NimbleError, stdout & "\nprintPkgInfo() failed") -proc execScript(scriptName, actionName: string, options: Options): - ExecutionResult[bool] = - let - nimsFile = getNimsFile(scriptName, options) +proc execScript( + scriptName, actionName: string, options: Options, isHook: bool +): ExecutionResult[bool] = + let nimsFile = getNimsFile(scriptName, options) - let - (output, exitCode) = execNimscript(nimsFile, scriptName.parentDir(), actionName, options) + let (output, exitCode, stdout) = + execNimscript( + nimsFile, scriptName.parentDir(), actionName, options, isHook + ) if exitCode != 0: let errMsg = - if output.len != 0: - output + if stdout.len != 0: + stdout else: "Exception raised during nimble script execution" raise newException(NimbleError, errMsg) @@ -164,7 +183,7 @@ proc execTask*(scriptName, taskName: string, display("Executing", "task $# in $#" % [taskName, scriptName], priority = HighPriority) - result = execScript(scriptName, taskName, options) + result = execScript(scriptName, taskName, options, isHook=false) proc execHook*(scriptName, actionName: string, before: bool, options: Options): ExecutionResult[bool] = @@ -178,11 +197,11 @@ proc execHook*(scriptName, actionName: string, before: bool, display("Attempting", "to execute hook $# in $#" % [hookName, scriptName], priority = MediumPriority) - result = execScript(scriptName, hookName, options) + result = execScript(scriptName, hookName, options, isHook=true) proc hasTaskRequestedCommand*(execResult: ExecutionResult): bool = ## Determines whether the last executed task used ``setCommand`` return execResult.command != internalCmd proc listTasks*(scriptName: string, options: Options) = - discard execScript(scriptName, "", options) + discard execScript(scriptName, "", options, isHook=false) diff --git a/tests/invalidPackage/invalidPackage.nimble b/tests/invalidPackage/invalidPackage.nimble new file mode 100644 index 0000000..08fcfcb --- /dev/null +++ b/tests/invalidPackage/invalidPackage.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + +thisFieldDoesNotExist = "hello" + +# Dependencies + +requires "nim >= 0.20.0" diff --git a/tests/tester.nim b/tests/tester.nim index efa0107..32d16a0 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -86,6 +86,13 @@ test "depsOnly + flag order test": check(not output.contains("Success: packagebin2 installed successfully.")) check exitCode == QuitSuccess +test "nimscript evaluation error message": + cd "invalidPackage": + var (output, exitCode) = execNimble("check") + let lines = output.strip.processOutput() + check(lines[^2].endsWith("Error: undeclared identifier: 'thisFieldDoesNotExist'")) + check exitCode == QuitFailure + test "caching of nims and ini detects changes": cd "caching": var (output, exitCode) = execNimble("dump") From a703de5dbd94e7c150f002edbe866576c4165868 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 13:55:40 +0100 Subject: [PATCH 401/424] Attempt to reproduce #564. --- tests/issue564/issue564.nimble | 14 ++++++++++++++ tests/issue564/src/issue564/issue564build.nim | 5 +++++ tests/tester.nim | 5 +++++ 3 files changed, 24 insertions(+) create mode 100644 tests/issue564/issue564.nimble create mode 100644 tests/issue564/src/issue564/issue564build.nim diff --git a/tests/issue564/issue564.nimble b/tests/issue564/issue564.nimble new file mode 100644 index 0000000..7dc0013 --- /dev/null +++ b/tests/issue564/issue564.nimble @@ -0,0 +1,14 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" +bin = @["issue564/issue564build"] + + + +# Dependencies + +requires "nim >= 0.16.0" diff --git a/tests/issue564/src/issue564/issue564build.nim b/tests/issue564/src/issue564/issue564build.nim new file mode 100644 index 0000000..862d40c --- /dev/null +++ b/tests/issue564/src/issue564/issue564build.nim @@ -0,0 +1,5 @@ +# This is just an example to get you started. A typical binary package +# uses this file as the main entry point of the application. + +when isMainModule: + echo("Hello, World!") diff --git a/tests/tester.nim b/tests/tester.nim index 32d16a0..5065606 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -79,6 +79,11 @@ proc hasLineStartingWith(lines: seq[string], prefix: string): bool = return true return false +test "issue 564": + cd "issue564": + var (output, exitCode) = execNimble("build") + check exitCode == QuitSuccess + test "depsOnly + flag order test": var (output, exitCode) = execNimble( "--depsOnly", "install", "-y", "https://github.com/nimble-test/packagebin2" From 281a1d129afad7acc0226cdd28d3e3d5cd104d34 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 14:39:22 +0100 Subject: [PATCH 402/424] Fixes #708. Refs #571. Output from Nimble scripts' top-level statements is now only visible with --verbose. --- src/nimblepkg/nimscriptwrapper.nim | 9 +++++++++ tests/issue708/issue708.nimble | 17 +++++++++++++++++ tests/issue708/src/issue708.nim | 7 +++++++ tests/tester.nim | 12 +++++++++++- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/issue708/issue708.nimble create mode 100644 tests/issue708/src/issue708.nim diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim index baad4e7..4cfe6ec 100644 --- a/src/nimblepkg/nimscriptwrapper.nim +++ b/src/nimblepkg/nimscriptwrapper.nim @@ -30,6 +30,12 @@ proc needsLiveOutput(actionName: string, options: Options, isHook: bool): bool = let isCustomTask = isCustomTask(actionName, options) return isCustomTask or isHook or actionName == "" +proc writeExecutionOutput(data: string) = + # TODO: in the future we will likely want this to be live, users will + # undoubtedly be doing loops and other crazy things in their top-level + # Nimble files. + display("Info", data) + proc execNimscript( nimsFile, projectDir, actionName: string, options: Options, isHook: bool ): tuple[output: string, exitCode: int, stdout: string] = @@ -135,6 +141,7 @@ proc getIniFile*(scriptName: string, options: Options): string = if exitCode == 0 and output.len != 0: result.writeFile(output) + stdout.writeExecutionOutput() else: raise newException(NimbleError, stdout & "\nprintPkgInfo() failed") @@ -175,6 +182,8 @@ proc execScript( result.flags[flag].add val.getStr() result.retVal = j{"retVal"}.getBool() + stdout.writeExecutionOutput() + proc execTask*(scriptName, taskName: string, options: Options): ExecutionResult[bool] = ## Executes the specified task in the specified script. diff --git a/tests/issue708/issue708.nimble b/tests/issue708/issue708.nimble new file mode 100644 index 0000000..ebb079d --- /dev/null +++ b/tests/issue708/issue708.nimble @@ -0,0 +1,17 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + + + +# Dependencies + +requires "nim >= 0.16.0" + + +echo "hello" +echo "hello2" diff --git a/tests/issue708/src/issue708.nim b/tests/issue708/src/issue708.nim new file mode 100644 index 0000000..4b2a270 --- /dev/null +++ b/tests/issue708/src/issue708.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two files together. + return x + y diff --git a/tests/tester.nim b/tests/tester.nim index 5065606..c2d2a59 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -79,9 +79,19 @@ proc hasLineStartingWith(lines: seq[string], prefix: string): bool = return true return false +test "issue 708": + cd "issue708": + # TODO: We need a way to filter out compiler messages from the messages + # written by our nimble scripts. + var (output, exitCode) = execNimble("install", "-y", "--verbose") + check exitCode == QuitSuccess + let lines = output.strip.processOutput() + check(inLines(lines, "hello")) + check(inLines(lines, "hello2")) + test "issue 564": cd "issue564": - var (output, exitCode) = execNimble("build") + var (_, exitCode) = execNimble("build") check exitCode == QuitSuccess test "depsOnly + flag order test": From fe252c6ed6e05910f0ca23c1203522f5fa1e60ca Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 16:37:47 +0100 Subject: [PATCH 403/424] Fixes #432. Fixes #672. --- src/nimble.nim | 2 +- src/nimblepkg/common.nim | 3 ++- src/nimblepkg/packageparser.nim | 9 +++++++++ tests/issue432/issue432.nimble | 15 +++++++++++++++ tests/issue432/src/issue432.nim | 7 +++++++ tests/tester.nim | 5 +++++ 6 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/issue432/issue432.nimble create mode 100644 tests/issue432/src/issue432.nim diff --git a/src/nimble.nim b/src/nimble.nim index 6b879ac..79f8768 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -205,7 +205,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % [pkgInfo.name, pkgInfo.version, pkgsInPath[pkgInfo.name]]) - pkgsInPath[pkgInfo.name] = pkgInfo.version + pkgsInPath[pkgInfo.name] = pkgInfo.getConcreteVersion(options) # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim index c40a82d..ab83175 100644 --- a/src/nimblepkg/common.nim +++ b/src/nimblepkg/common.nim @@ -22,7 +22,8 @@ when not defined(nimscript): preHooks*: HashSet[string] name*: string ## The version specified in the .nimble file.Assuming info is non-minimal, - ## it will always be a non-special version such as '0.1.4' + ## it will always be a non-special version such as '0.1.4'. + ## If in doubt, use `getConcreteVersion` instead. version*: string specialVersion*: string ## Either `myVersion` or a special version such as #head. author*: string diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim index 59c2ca8..9458074 100644 --- a/src/nimblepkg/packageparser.nim +++ b/src/nimblepkg/packageparser.nim @@ -487,6 +487,15 @@ proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo = else: return pkg +proc getConcreteVersion*(pkgInfo: PackageInfo, options: Options): string = + ## Returns a non-special version from the specified ``pkgInfo``. If the + ## ``pkgInfo`` is minimal it looks it up and retrieves the concrete version. + result = pkgInfo.version + if pkgInfo.isMinimal: + let pkgInfo = pkgInfo.toFullInfo(options) + result = pkgInfo.version + assert(not newVersion(result).isSpecial) + when isMainModule: validatePackageName("foo_bar") validatePackageName("f_oo_b_a_r") diff --git a/tests/issue432/issue432.nimble b/tests/issue432/issue432.nimble new file mode 100644 index 0000000..92937c5 --- /dev/null +++ b/tests/issue432/issue432.nimble @@ -0,0 +1,15 @@ +# Package + +version = "0.1.0" +author = "Dominik Picheta" +description = "A new awesome nimble package" +license = "MIT" +srcDir = "src" + + + +# Dependencies + +requires "nim >= 0.16.0" +requires "https://github.com/nimble-test/packagea#head", + "https://github.com/nimble-test/packagebin2" diff --git a/tests/issue432/src/issue432.nim b/tests/issue432/src/issue432.nim new file mode 100644 index 0000000..4b2a270 --- /dev/null +++ b/tests/issue432/src/issue432.nim @@ -0,0 +1,7 @@ +# This is just an example to get you started. A typical library package +# exports the main API in this file. Note that you cannot rename this file +# but you can remove it if you wish. + +proc add*(x, y: int): int = + ## Adds two files together. + return x + y diff --git a/tests/tester.nim b/tests/tester.nim index c2d2a59..1bf9caa 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -79,6 +79,11 @@ proc hasLineStartingWith(lines: seq[string], prefix: string): bool = return true return false +test "issue 432": + cd "issue432": + check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess + check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess + test "issue 708": cd "issue708": # TODO: We need a way to filter out compiler messages from the messages From 10e22fec98c2a74109e2cc52deb1875a761f9e49 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 17:58:51 +0100 Subject: [PATCH 404/424] Move issue 432 test to the bottom of tester to fix broken uninstall test. --- tests/tester.nim | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/tester.nim b/tests/tester.nim index 1bf9caa..ceb1fc6 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -79,11 +79,6 @@ proc hasLineStartingWith(lines: seq[string], prefix: string): bool = return true return false -test "issue 432": - cd "issue432": - check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess - check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess - test "issue 708": cd "issue708": # TODO: We need a way to filter out compiler messages from the messages @@ -960,6 +955,11 @@ test "NimbleVersion is defined": check output2.contains("0.1.0") check exitCode2 == QuitSuccess +test "issue 432": + cd "issue432": + check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess + check execNimble("install", "-y", "--depsOnly").exitCode == QuitSuccess + test "compilation without warnings": const buildDir = "./buildDir/" const filesToBuild = [ From 1db54cc736c25b1c1def6e969c80bd0f2356f99a Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 18:11:28 +0100 Subject: [PATCH 405/424] Fixes some small input validation errors and help text. --- src/nimble.nim | 9 ++++++++- src/nimblepkg/options.nim | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 79f8768..27e4774 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -233,6 +233,7 @@ proc buildFromDir( var args = args let nimblePkgVersion = "-d:NimblePkgVersion=" & pkgInfo.version for path in paths: args.add("--path:\"" & path & "\" ") + var binariesBuilt = 0 for bin in pkgInfo.bin: # Check if this is the only binary that we want to build. if binToBuild.isSome() and binToBuild.get() != bin: @@ -252,6 +253,7 @@ proc buildFromDir( doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# $# \"$#\"" % [pkgInfo.backend, nimblePkgVersion, join(args, " "), outputOpt, realDir / bin.changeFileExt("nim")]) + binariesBuilt.inc() except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) let exc = newException(BuildFailed, "Build failed for package: " & @@ -261,6 +263,11 @@ proc buildFromDir( exc.hint = hint raise exc + if binariesBuilt == 0: + raiseNimbleError( + "No binaries built, did you specify a valid binary name?" + ) + # Handle post-`build` hook. cd realDir: # Make sure `execHook` executes the correct .nimble file. discard execHook(options, actionBuild, false) @@ -1084,7 +1091,7 @@ proc check(options: Options) = proc run(options: Options) = # Verify parameters. - let binary = options.getCompilationBinary().get() + let binary = options.getCompilationBinary().get("") if binary.len == 0: raiseNimbleError("Please specify a binary to run") diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 72f4a3a..a162a0f 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -85,8 +85,12 @@ Commands: toplevel directory of the Nimble package. uninstall [pkgname, ...] Uninstalls a list of packages. [-i, --inclDeps] Uninstall package and dependent package(s). - build [opts, ...] Builds a package. + build [opts, ...] [bin] Builds a package. run [opts, ...] bin Builds and runs a package. + A binary name needs + to be specified after any compilation options, + any flags after the binary name are passed to + the binary when it is run. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. test Compiles and executes tests From b68f7849e6eaf1c17aaf85af634fa9105d259537 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 21:21:26 +0100 Subject: [PATCH 406/424] Add 0.11.0 changelog. --- changelog.markdown | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/changelog.markdown b/changelog.markdown index a011485..92f1d31 100644 --- a/changelog.markdown +++ b/changelog.markdown @@ -3,7 +3,33 @@ # Nimble changelog +## 0.11.0 - 22/09/2019 + +This is a major release containing nearly 60 commits. Most changes are +bug fixes, but this release also includes a couple new features: + +- Binaries can now be built and run using the new ``run`` command. +- The ``NimblePkgVersion`` is now defined so you can easily get the package + version in your source code + ([example](https://github.com/nim-lang/nimble/blob/4a2aaa07d/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim)). + +Some other highlights: + +- Temporary files are now kept when the ``--debug`` flag is used. +- Fixed dependency resolution issues with "#head" packages (#432 and #672). +- The `install` command can now take Nim compiler flags via the new + ``--passNim`` flag. +- Command line arguments are now passed properly to tasks (#633). +- The ``test`` command now respects the specified backend (#631). +- The ``dump`` command will no longer prompt and now has an implicit ``-y``. +- Fixed bugs with the new nimscript executor (#665). - Fixed multiple downloads and installs of the same package (#678). +- Nimble init no longer overwrites existing files (#581). +- Fixed incorrect submodule version being pulled when in a non-master branch (#675). + +---- + +Full changelog: https://github.com/nim-lang/nimble/compare/v0.10.2...v0.11.0 ## 0.10.2 - 03/06/2019 From 3625c1f861fd0573d271f700bc69e676fd911f97 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 21:34:05 +0100 Subject: [PATCH 407/424] Expand Nimble readme slightly (installation/nimble-run). --- readme.markdown | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index 9470aa8..e047e1b 100644 --- a/readme.markdown +++ b/readme.markdown @@ -15,6 +15,7 @@ Interested in learning **how to create a package**? Skip directly to that sectio - [nimble install](#nimble-install) - [nimble uninstall](#nimble-uninstall) - [nimble build](#nimble-build) + - [nimble run](#nimble-run) - [nimble c](#nimble-c) - [nimble list](#nimble-list) - [nimble search](#nimble-search) @@ -74,10 +75,15 @@ not need to install Nimble manually**. But in case you still want to install Nimble manually, you can follow the following instructions. -There are two ways to install Nimble manually. The first is using the -``koch`` tool included in the Nim distribution and +There are two ways to install Nimble manually. Using ``koch`` and using Nimble +itself. + +### Using koch + +The ``koch`` tool is included in the Nim distribution and [repository](https://github.com/nim-lang/Nim/blob/devel/koch.nim). -Simply execute the following command to compile and install Nimble. +Simply navigate to the location of your Nim installation and execute the +following command to compile and install Nimble. ``` ./koch nimble @@ -86,6 +92,19 @@ Simply execute the following command to compile and install Nimble. This will clone the Nimble repository, compile Nimble and copy it into Nim's bin directory. +### Using Nimble + +In most cases you will already have Nimble installed, you can install a newer +version of Nimble by simply running the following command: + +``` +nimble install nimble +``` + +This will download the latest release of Nimble and install it on your system. + +Note that you must have `~/.nimble/bin` in your PATH for this to work, if you're +using choosenim then you likely already have this set up correctly. ## Nimble usage @@ -219,6 +238,13 @@ flags, i.e. a debug build which includes stack traces but no GDB debug information. The ``install`` command will build the package in release mode instead. +### nimble run + +The ``run`` command can be used to build and run any binary specified in your +package's ``bin`` list. You can pass any compilation flags you wish by specifying +them before the ``run`` command, and you can specify arguments for your binary +by specifying them after the ``run`` command. + ### nimble c The ``c`` (or ``compile``, ``js``, ``cc``, ``cpp``) command can be used by From 901afa8c71505ad8f6aa1118e59d8c876fee84bb Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 22:13:31 +0100 Subject: [PATCH 408/424] Further fix for #432. --- src/nimble.nim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 27e4774..634d191 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -200,12 +200,13 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] = # in the path. var pkgsInPath: StringTableRef = newStringTable(modeCaseSensitive) for pkgInfo in result: + let currentVer = pkgInfo.getConcreteVersion(options) if pkgsInPath.hasKey(pkgInfo.name) and - pkgsInPath[pkgInfo.name] != pkgInfo.version: + pkgsInPath[pkgInfo.name] != currentVer: raise newException(NimbleError, "Cannot satisfy the dependency on $1 $2 and $1 $3" % - [pkgInfo.name, pkgInfo.version, pkgsInPath[pkgInfo.name]]) - pkgsInPath[pkgInfo.name] = pkgInfo.getConcreteVersion(options) + [pkgInfo.name, currentVer, pkgsInPath[pkgInfo.name]]) + pkgsInPath[pkgInfo.name] = currentVer # We add the reverse deps to the JSON file here because we don't want # them added if the above errorenous condition occurs From 0ed8e6403c8a826e776f36484e2e6ae0e9df9c4f Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 22 Sep 2019 22:22:21 +0100 Subject: [PATCH 409/424] Implicitly disable package validation for run/build/compile. --- src/nimble.nim | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 634d191..bb74ac0 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1112,7 +1112,7 @@ proc run(options: Options) = doCmd("$# $#" % [binaryPath, args], showOutput = true) -proc doAction(options: Options) = +proc doAction(options: var Options) = if options.showHelp: writeHelp() if options.showVersion: @@ -1123,6 +1123,10 @@ proc doAction(options: Options) = if not existsDir(options.getPkgsDir): createDir(options.getPkgsDir) + if options.action.typ in {actionTasks, actionRun, actionBuild, actionCompile}: + # Implicitly disable package validation for these commands. + options.disableValidation = true + case options.action.typ of actionRefresh: refresh(options) @@ -1177,7 +1181,8 @@ proc doAction(options: Options) = var execResult: ExecutionResult[bool] if execCustom(options, execResult, failFast=not isPreDefined): if execResult.hasTaskRequestedCommand(): - doAction(execResult.getOptionsForCommand(options)) + var options = execResult.getOptionsForCommand(options) + doAction(options) else: # If there is no task defined for the `test` task, we run the pre-defined # fallback logic. From 4007b2a778429a978e12307bf13a038029b4c4d9 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Mon, 23 Sep 2019 00:09:26 +0100 Subject: [PATCH 410/424] Fixes `nimble run` on Windows. Cherry picked from https://github.com/nim-lang/nimble/commit/331a33711dc0610a426941e441e6d4630e023371 --- src/nimblepkg/options.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index a162a0f..bf050fe 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -520,7 +520,7 @@ proc getCompilationBinary*(options: Options): Option[string] = if file.len > 0: return some(file) of actionRun: - let runFile = options.action.runFile.changeFileExt("") + let runFile = options.action.runFile.changeFileExt(ExeExt) if runFile.len > 0: return some(runFile) else: From a2ec2db8f261c5fd3f2d977a969babeda2a91fb0 Mon Sep 17 00:00:00 2001 From: genotrance Date: Thu, 3 Oct 2019 18:38:51 -0500 Subject: [PATCH 411/424] Enable Windows CI (#714) Also fix #676 --- .travis.yml | 33 +++++++++++++----- src/nimble.nim | 6 +++- .../src/nimbleVersionDefine | Bin 86500 -> 93432 bytes tests/recursive/recursive.nimble | 7 ++-- tests/tester.nim | 21 ++++++----- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f824f3..a8b511b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ os: + - windows - linux - osx @@ -7,23 +8,37 @@ language: c env: - BRANCH=0.19.6 - BRANCH=0.20.2 + - BRANCH=1.0.0 # This is the latest working Nim version against which Nimble is being tested - - BRANCH=#2565d3d102efd21ba02ed1f3b96d892fe2637d2b + - BRANCH=#16c39f9b2edc963655889cfd33e165bfae91c96d cache: directories: - - "$HOME/.choosenim/toolchains/nim-0.19.6" - - "$HOME/.choosenim/toolchains/nim-0.20.2" + - "$HOME/.nimble/bin" + - "$HOME/.choosenim" install: - - export CHOOSENIM_CHOOSE_VERSION=$BRANCH - - | - curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh - sh init.sh -y - -before_script: - export CHOOSENIM_NO_ANALYTICS=1 - export PATH=$HOME/.nimble/bin:$PATH + - | + if ! type -P choosenim &> /dev/null; then + if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then + # Latest choosenim binary doesn't have + # https://github.com/dom96/choosenim/pull/117 + # https://github.com/dom96/choosenim/pull/135 + # + # Using custom build with these PRs for Windows + curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=choosenim.exe" -o choosenim.exe + curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=libeay32.dll" -o libeay32.dll + curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=ssleay32.dll" -o ssleay32.dll + ./choosenim.exe $BRANCH -y + cp ./choosenim.exe $HOME/.nimble/bin/. + else + export CHOOSENIM_CHOOSE_VERSION=$BRANCH + curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh + sh init.sh -y + fi + fi script: - cd tests diff --git a/src/nimble.nim b/src/nimble.nim index bb74ac0..e214538 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1063,7 +1063,11 @@ proc test(options: Options) = existsAfter = existsFile(binFileName) canRemove = not existsBefore and existsAfter if canRemove: - removeFile(binFileName) + try: + removeFile(binFileName) + except OSError as exc: + display("Warning:", "Failed to delete " & binFileName & ": " & + exc.msg, Warning, MediumPriority) if failures == 0: display("Success:", "All tests passed", Success, HighPriority) diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine b/tests/nimbleVersionDefine/src/nimbleVersionDefine index 3b089c01cfe8bed84e2cacb812590f1b97d73f10..7aa3ee894aae8f7caa3ef0731bd0ee9452010a3f 100755 GIT binary patch literal 93432 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

QzGccFt5JNK)G;L?5C|Peqf%X%M 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

t`PuWKkA=4TL(qpjXbJj| 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 literal 86500 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 PpazRKkMYRB4(R+}iPK7{ diff --git a/tests/recursive/recursive.nimble b/tests/recursive/recursive.nimble index 972dd0b..d6b155d 100644 --- a/tests/recursive/recursive.nimble +++ b/tests/recursive/recursive.nimble @@ -9,10 +9,9 @@ license = "BSD" requires "nim >= 0.12.1" -when defined(windows): - let callNimble = "..\\..\\src\\nimble.exe" -else: - let callNimble = "../../src/nimble" +let + callNimble = getEnv("NIMBLE_TEST_BINARY_PATH") +doAssert callNimble.len != 0, "NIMBLE_TEST_BINARY_PATH not set" task recurse, "Level 1": echo 1 diff --git a/tests/tester.nim b/tests/tester.nim index ceb1fc6..f969f66 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -12,6 +12,9 @@ var installDir = rootDir / "tests" / "nimbleDir" const path = "../src/nimble" const stringNotFound = -1 +# Set env var to propagate nimble binary path +putEnv("NIMBLE_TEST_BINARY_PATH", nimblePath) + # Clear nimble dir. removeDir(installDir) createDir(installDir) @@ -480,17 +483,17 @@ test "issue #349": ] proc checkName(name: string) = - when defined(windows): - if name.toLowerAscii() in @["con", "nul"]: - return let (outp, code) = execNimble("init", "-y", name) let msg = outp.strip.processOutput() check code == QuitFailure check inLines(msg, "\"$1\" is an invalid package name: reserved name" % name) - removeFile(name.changeFileExt("nimble")) - removeDir("src") - removeDir("tests") + try: + removeFile(name.changeFileExt("nimble")) + removeDir("src") + removeDir("tests") + except OSError: + discard for reserved in reservedNames: checkName(reserved.toUpperAscii()) @@ -930,7 +933,8 @@ suite "nimble run": "blahblah", # The command to run ) check exitCode == QuitFailure - check output.contains("Binary 'blahblah' is not defined in 'run' package.") + check output.contains("Binary '$1' is not defined in 'run' package." % + "blahblah".changeFileExt(ExeExt)) test "Parameters passed to executable": cd "run": @@ -942,7 +946,8 @@ suite "nimble run": "check" # Second argument passed to the executed command. ) check exitCode == QuitSuccess - check output.contains("tests/run/run --debug check") + check output.contains("tests$1run$1$2 --debug check" % + [$DirSep, "run".changeFileExt(ExeExt)]) check output.contains("""Testing `nimble run`: @["--debug", "check"]""") test "NimbleVersion is defined": From 5bb795a364a431f897c3864186dbe1aa138c85b9 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Wed, 23 Oct 2019 16:20:59 -0500 Subject: [PATCH 412/424] Export initOptions for choosenim --- src/nimblepkg/options.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index bf050fe..42fffb1 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -371,7 +371,8 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = if not wasFlagHandled and not isGlobalFlag: result.unknownFlags.add((kind, flag, val)) -proc initOptions(): Options = +proc initOptions*(): Options = + # Exported for choosenim Options( action: Action(typ: actionNil), pkgInfoCache: newTable[string, PackageInfo](), @@ -524,4 +525,4 @@ proc getCompilationBinary*(options: Options): Option[string] = if runFile.len > 0: return some(runFile) else: - discard \ No newline at end of file + discard From 703abe3d41fb60ad03957d78bf73df48360d67f7 Mon Sep 17 00:00:00 2001 From: yuchunzhou Date: Wed, 23 Oct 2019 16:43:59 +0800 Subject: [PATCH 413/424] fix #725 --- src/nimblepkg/options.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 42fffb1..9deb357 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -359,6 +359,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = if not isGlobalFlag: result.action.compileOptions.add(getFlagString(kind, flag, val)) of actionRun: + result.showHelp = false result.action.runFlags.add(getFlagString(kind, flag, val)) of actionCustom: if result.action.command.normalize == "test": From b3abee937dad1012493a195c6c3531693caf8f7c Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Thu, 24 Oct 2019 23:24:06 +0100 Subject: [PATCH 414/424] Add tests for #666. --- src/nimblepkg/download.nim | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim index 85bf54f..3bbfa25 100644 --- a/src/nimblepkg/download.nim +++ b/src/nimblepkg/download.nim @@ -300,4 +300,17 @@ when isMainModule: }) doAssert expected == getVersionList(data) + + block: + let data2 = @["v0.1.0", "v0.1.1", "v0.2.0", + "0.4.0", "v0.4.2"] + let expected2 = toOrderedTable[Version, string]({ + newVersion("0.4.2"): "v0.4.2", + newVersion("0.4.0"): "0.4.0", + newVersion("0.2.0"): "v0.2.0", + newVersion("0.1.1"): "v0.1.1", + newVersion("0.1.0"): "v0.1.0", + }) + doAssert expected2 == getVersionList(data2) + echo("Everything works!") From bbb586dbfc0b5c3cd8e7684223b88f150cc3fa3f Mon Sep 17 00:00:00 2001 From: yuchunzhou Date: Tue, 29 Oct 2019 05:28:46 +0800 Subject: [PATCH 415/424] add vcs to the new created project (#729) * add git vcs and a default .nim.cfg file to the new created project * remove the gitapi dependency * add vcs support for new nimble project * add vcs support for new nimble project * update pull request #729 * add --git/hg flag instead of --vcs flag for nimble init command --- src/nimble.nim | 19 ++++++++++++++++++- src/nimblepkg/options.nim | 11 +++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/nimble.nim b/src/nimble.nim index e214538..412c987 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -3,12 +3,13 @@ import system except TResult -import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils +import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils, osproc import std/options as std_opt import strutils except toLower from unicode import toLower from sequtils import toSeq +from strformat import fmt import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools, nimblepkg/download, nimblepkg/config, nimblepkg/common, @@ -724,6 +725,11 @@ proc dump(options: Options) = echo "backend: ", p.backend.escape proc init(options: Options) = + # Check whether the vcs is installed. + let vcsBin = options.action.vcsOption + if vcsBin != "" and findExe(vcsBin, true) == "": + raise newException(NimbleError, "Please install git or mercurial first") + # Determine the package name. let pkgName = if options.action.projName != "": @@ -858,6 +864,17 @@ js - Compile using JavaScript backend.""", pkgRoot ) + # Create a git or hg repo in the new nimble project. + if vcsBin != "": + let cmd = fmt"cd {pkgRoot} && {vcsBin} init" + let ret: tuple[output: string, exitCode: int] = execCmdEx(cmd) + if ret.exitCode != 0: quit ret.output + + var ignoreFile = if vcsBin == "git": ".gitignore" else: ".hgignore" + var fd = open(joinPath(pkgRoot, ignoreFile), fmWrite) + fd.write(pkgName & "\n") + fd.close() + display("Success:", "Package $# created successfully" % [pkgName], Success, HighPriority) diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index 9deb357..a338978 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -51,6 +51,7 @@ type search*: seq[string] # Search string. of actionInit, actionDump: projName*: string + vcsOption*: string of actionCompile, actionDoc, actionBuild: file*: string backend*: string @@ -80,6 +81,8 @@ Commands: init [pkgname] Initializes a new Nimble project in the current directory or if a name is provided a new directory of the same name. + --git + --hg Create a git or hg repo in the new nimble project. publish Publishes a package on nim-lang/packages. The current working directory needs to be the toplevel directory of the Nimble package. @@ -201,8 +204,10 @@ proc initAction*(options: var Options, key: string) = else: options.action.backend = keyNorm of actionInit: options.action.projName = "" + options.action.vcsOption = "" of actionDump: options.action.projName = "" + options.action.vcsOption = "" options.forcePrompts = forcePromptYes of actionRefresh: options.action.optionalURL = "" @@ -349,6 +354,12 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.action.passNimFlags.add(val) else: wasFlagHandled = false + of actionInit: + case f + of "git", "hg": + result.action.vcsOption = f + else: + wasFlagHandled = false of actionUninstall: case f of "incldeps", "i": From a8a5bdd863ab311f39c242c705207b937695e270 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Tue, 29 Oct 2019 22:43:04 +0000 Subject: [PATCH 416/424] Fixes #734 --- readme.markdown | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/readme.markdown b/readme.markdown index e047e1b..d40fded 100644 --- a/readme.markdown +++ b/readme.markdown @@ -172,12 +172,13 @@ example: This is of course Git-specific, for Mercurial, use ``tip`` instead of ``head``. A branch, tag, or commit hash may also be specified in the place of ``head``. -Instead of specifying a VCS branch, you may also specify a version range, for -example: +Instead of specifying a VCS branch, you may also specify a concrete version or a +version range, for example: + $ nimble install nimgame@0.5 $ nimble install nimgame@"> 0.5" -In this case a version which is greater than ``0.5`` will be installed. +The latter command will install a version which is greater than ``0.5``. If you don't specify a parameter and there is a ``package.nimble`` file in your current working directory then Nimble will install the package residing in From 051cfa6cd34539db32b3a4d77ca87e4c59cf6fdf Mon Sep 17 00:00:00 2001 From: itmuckel Date: Sun, 3 Nov 2019 12:22:57 +0100 Subject: [PATCH 417/424] Add '==' as operator for pinning versions. --- src/nimblepkg/version.nim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim index 4834b6d..e4114f1 100644 --- a/src/nimblepkg/version.nim +++ b/src/nimblepkg/version.nim @@ -147,7 +147,7 @@ proc makeRange*(version: string, op: string): VersionRange = result = VersionRange(kind: verEqLater) of "<=": result = VersionRange(kind: verEqEarlier) - of "": + of "", "==": result = VersionRange(kind: verEq) else: raise newException(ParseVersionError, "Invalid operator: " & op) @@ -298,9 +298,10 @@ when isMainModule: doAssert(newVersion("0.1.0") <= newVersion("0.1")) var inter1 = parseVersionRange(">= 1.0 & <= 1.5") - doAssert inter1.kind == verIntersect + doAssert(inter1.kind == verIntersect) var inter2 = parseVersionRange("1.0") doAssert(inter2.kind == verEq) + doAssert(parseVersionRange("== 3.4.2") == parseVersionRange("3.4.2")) doAssert(not withinRange(newVersion("1.5.1"), inter1)) doAssert(withinRange(newVersion("1.0.2.3.4.5.6.7.8.9.10.11.12"), inter1)) From 16ba5db44e0a9132f966a2082012cc3520bfec06 Mon Sep 17 00:00:00 2001 From: Xie Yanbo Date: Sun, 10 Nov 2019 11:37:11 +0800 Subject: [PATCH 418/424] tests' config file should be config.nims which is created by `nimble init`. --- readme.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.markdown b/readme.markdown index d40fded..89f7a22 100644 --- a/readme.markdown +++ b/readme.markdown @@ -505,7 +505,7 @@ For a package named "foobar", the recommended project structure is the following └── src └── foobar.nim # Imported via `import foobar` └── tests # Contains the tests - ├── nim.cfg + ├── config.nims ├── tfoo1.nim # First test └── tfoo2.nim # Second test From e9d45ca6830c3e9af6b15c0efd252b7c59170854 Mon Sep 17 00:00:00 2001 From: Taylor Hoff Date: Tue, 19 Nov 2019 09:41:26 -0500 Subject: [PATCH 419/424] Capitalize the "D" in srcDir to avoid errors when using styleChecks Fixes #740 --- src/nimblepkg/nimscriptapi.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim index a8b4ba3..ec2f46c 100644 --- a/src/nimblepkg/nimscriptapi.nim +++ b/src/nimblepkg/nimscriptapi.nim @@ -17,7 +17,7 @@ var author*: string ## The package's author. description*: string ## The package's description. license*: string ## The package's license. - srcdir*: string ## The package's source directory. + srcDir*: string ## The package's source directory. binDir*: string ## The package's binary directory. backend*: string ## The package's backend. @@ -101,7 +101,7 @@ proc printPkgInfo(): string = printIfLen author printIfLen description printIfLen license - printIfLen srcdir + printIfLen srcDir printIfLen binDir printIfLen backend From 9391fbc56d9e4d3080c10583268f243b8b78edd5 Mon Sep 17 00:00:00 2001 From: inv2004 Date: Sat, 18 Jan 2020 01:15:34 +0300 Subject: [PATCH 420/424] Run can work without additional option if only one bin in .nimble (#761) * nimble run can work if only one binary in config * usage changed * runFile is option now * usage updated * small refactoring to reduce condition * setRunOptions fix * some code optimisation --- src/nimble.nim | 18 +++++++++-------- src/nimblepkg/options.nim | 41 +++++++++++++++++++++++++-------------- tests/tester.nim | 26 +++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 412c987..6d233f6 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -221,7 +221,7 @@ proc buildFromDir( options: Options ) = ## Builds a package as specified by ``pkgInfo``. - let binToBuild = options.getCompilationBinary() + let binToBuild = options.getCompilationBinary(pkgInfo) # Handle pre-`build` hook. let realDir = pkgInfo.getRealDir() cd realDir: # Make sure `execHook` executes the correct .nimble file. @@ -535,9 +535,9 @@ proc build(options: Options) = var args = options.getCompilationFlags() buildFromDir(pkgInfo, paths, args, options) -proc execBackend(options: Options) = +proc execBackend(pkgInfo: PackageInfo, options: Options) = let - bin = options.getCompilationBinary().get() + bin = options.getCompilationBinary(pkgInfo).get() binDotNim = bin.addFileExt("nim") if bin == "": raise newException(NimbleError, "You need to specify a file.") @@ -1070,11 +1070,11 @@ proc test(options: Options) = if options.continueTestsOnFailure: inc tests try: - execBackend(optsCopy) + execBackend(pkgInfo, optsCopy) except NimbleError: inc failures else: - execBackend(optsCopy) + execBackend(pkgInfo, optsCopy) let existsAfter = existsFile(binFileName) @@ -1113,11 +1113,12 @@ proc check(options: Options) = proc run(options: Options) = # Verify parameters. - let binary = options.getCompilationBinary().get("") + var pkgInfo = getPkgInfo(getCurrentDir(), options) + + let binary = options.getCompilationBinary(pkgInfo).get("") if binary.len == 0: raiseNimbleError("Please specify a binary to run") - var pkgInfo = getPkgInfo(getCurrentDir(), options) if binary notin pkgInfo.bin: raiseNimbleError( "Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.name] @@ -1176,7 +1177,8 @@ proc doAction(options: var Options) = of actionRun: run(options) of actionCompile, actionDoc: - execBackend(options) + var pkgInfo = getPkgInfo(getCurrentDir(), options) + execBackend(pkgInfo, options) of actionInit: init(options) of actionPublish: diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim index a338978..14d1c31 100644 --- a/src/nimblepkg/options.nim +++ b/src/nimblepkg/options.nim @@ -57,7 +57,7 @@ type backend*: string compileOptions: seq[string] of actionRun: - runFile: string + runFile: Option[string] compileFlags: seq[string] runFlags*: seq[string] of actionCustom: @@ -89,11 +89,11 @@ Commands: uninstall [pkgname, ...] Uninstalls a list of packages. [-i, --inclDeps] Uninstall package and dependent package(s). build [opts, ...] [bin] Builds a package. - run [opts, ...] bin Builds and runs a package. - A binary name needs - to be specified after any compilation options, - any flags after the binary name are passed to - the binary when it is run. + run [opts, ...] [bin] Builds and runs a package. + Binary needs to be specified after any + compilation options if there are several + binaries defined, any flags after the binary + or -- arg are passed to the binary when it is run. c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options to the Nim compiler. test Compiles and executes tests @@ -266,6 +266,12 @@ proc parseCommand*(key: string, result: var Options) = result.action = Action(typ: parseActionType(key)) initAction(result, key) +proc setRunOptions(result: var Options, key, val: string, isArg: bool) = + if result.action.runFile.isNone() and (isArg or val == "--"): + result.action.runFile = some(key) + else: + result.action.runFlags.add(val) + proc parseArgument*(key: string, result: var Options) = case result.action.typ of actionNil: @@ -297,10 +303,7 @@ proc parseArgument*(key: string, result: var Options) = of actionBuild: result.action.file = key of actionRun: - if result.action.runFile.len == 0: - result.action.runFile = key - else: - result.action.runFlags.add(key) + result.setRunOptions(key, key, true) of actionCustom: result.action.arguments.add(key) else: @@ -371,7 +374,7 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) = result.action.compileOptions.add(getFlagString(kind, flag, val)) of actionRun: result.showHelp = false - result.action.runFlags.add(getFlagString(kind, flag, val)) + result.setRunOptions(flag, getFlagString(kind, flag, val), false) of actionCustom: if result.action.command.normalize == "test": if f == "continue" or f == "c": @@ -441,7 +444,7 @@ proc parseCmdLine*(): Options = else: parseArgument(key, result) of cmdLongOption, cmdShortOption: - parseFlag(key, val, result, kind) + parseFlag(key, val, result, kind) of cmdEnd: assert(false) # cannot happen handleUnknownFlags(result) @@ -526,15 +529,23 @@ proc getCompilationFlags*(options: Options): seq[string] = var opt = options return opt.getCompilationFlags() -proc getCompilationBinary*(options: Options): Option[string] = +proc getCompilationBinary*(options: Options, pkgInfo: PackageInfo): Option[string] = case options.action.typ of actionBuild, actionDoc, actionCompile: let file = options.action.file.changeFileExt("") if file.len > 0: return some(file) of actionRun: - let runFile = options.action.runFile.changeFileExt(ExeExt) + let optRunFile = options.action.runFile + let runFile = + if optRunFile.get("").len > 0: + optRunFile.get() + elif pkgInfo.bin.len == 1: + pkgInfo.bin[0] + else: + "" + if runFile.len > 0: - return some(runFile) + return some(runFile.changeFileExt(ExeExt)) else: discard diff --git a/tests/tester.nim b/tests/tester.nim index f969f66..c5d9925 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -950,6 +950,32 @@ suite "nimble run": [$DirSep, "run".changeFileExt(ExeExt)]) check output.contains("""Testing `nimble run`: @["--debug", "check"]""") + test "Parameters not passed to single executable": + cd "run": + var (output, exitCode) = execNimble( + "--debug", # Flag to enable debug verbosity in Nimble + "run", # Run command invokation + "--debug" # First argument passed to the executed command + ) + check exitCode == QuitSuccess + check output.contains("tests$1run$1$2 --debug" % + [$DirSep, "run".changeFileExt(ExeExt)]) + check output.contains("""Testing `nimble run`: @["--debug"]""") + + test "Parameters passed to single executable": + cd "run": + var (output, exitCode) = execNimble( + "--debug", # Flag to enable debug verbosity in Nimble + "run", # Run command invokation + "--", # Flag to set run file to "" before next argument + "--debug", # First argument passed to the executed command + "check" # Second argument passed to the executed command. + ) + check exitCode == QuitSuccess + check output.contains("tests$1run$1$2 --debug check" % + [$DirSep, "run".changeFileExt(ExeExt)]) + check output.contains("""Testing `nimble run`: @["--debug", "check"]""") + test "NimbleVersion is defined": cd "nimbleVersionDefine": var (output, exitCode) = execNimble("c", "-r", "src/nimbleVersionDefine.nim") From 85e5bc7c375caf07977c58481dfbac58e326dde8 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Wed, 5 Feb 2020 12:31:05 -0600 Subject: [PATCH 421/424] Use travis gist --- .travis.yml | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index a8b511b..d132ced 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,9 @@ language: c env: - BRANCH=0.19.6 - BRANCH=0.20.2 - - BRANCH=1.0.0 + - BRANCH=1.0.6 # This is the latest working Nim version against which Nimble is being tested - - BRANCH=#16c39f9b2edc963655889cfd33e165bfae91c96d + - BRANCH=#ab525cc48abdbbbed1f772e58e9fe21474f70f07 cache: directories: @@ -18,27 +18,8 @@ cache: - "$HOME/.choosenim" install: - - export CHOOSENIM_NO_ANALYTICS=1 - - export PATH=$HOME/.nimble/bin:$PATH - - | - if ! type -P choosenim &> /dev/null; then - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then - # Latest choosenim binary doesn't have - # https://github.com/dom96/choosenim/pull/117 - # https://github.com/dom96/choosenim/pull/135 - # - # Using custom build with these PRs for Windows - curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=choosenim.exe" -o choosenim.exe - curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=libeay32.dll" -o libeay32.dll - curl -L -s "https://bintray.com/genotrance/binaries/download_file?file_path=ssleay32.dll" -o ssleay32.dll - ./choosenim.exe $BRANCH -y - cp ./choosenim.exe $HOME/.nimble/bin/. - else - export CHOOSENIM_CHOOSE_VERSION=$BRANCH - curl https://nim-lang.org/choosenim/init.sh -sSf > init.sh - sh init.sh -y - fi - fi + - curl https://gist.github.com/genotrance/fb53504a4fba88bc5201d3783df5c522/raw/travis.sh -LsSf -o travis.sh + - source travis.sh script: - cd tests From 27d56f8e9f6d7cee207e66c5a4d3766e73975f15 Mon Sep 17 00:00:00 2001 From: Ganesh Viswanathan Date: Tue, 11 Feb 2020 18:58:31 +0000 Subject: [PATCH 422/424] Remove ~/.nimble from cache --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d132ced..f1ff69e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ env: cache: directories: - - "$HOME/.nimble/bin" - "$HOME/.choosenim" install: From 68a9c4c955c6abc501a7b5d2f197081a79347d57 Mon Sep 17 00:00:00 2001 From: Daniel M Date: Wed, 19 Feb 2020 15:20:59 -0800 Subject: [PATCH 423/424] fix and improve the behavior of `nimble run` quote arguments appropriately: - whitespace in arguments is preserved; previously arguments with whitespace were split - quotes are now escaped the exit code of the command that has been "run" is re-used when nimble exits show the output of the "run" command regardless of whether nimble is debugging --- src/nimble.nim | 9 ++++----- tests/tester.nim | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index 6d233f6..e923eec 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -1124,15 +1124,14 @@ proc run(options: Options) = "Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.name] ) - let binaryPath = pkgInfo.getOutputDir(binary) - # Build the binary. build(options) - # Now run it. - let args = options.action.runFlags.join(" ") + let binaryPath = pkgInfo.getOutputDir(binary) + let cmd = quoteShellCommand(binaryPath & options.action.runFlags) + displayDebug("Executing", cmd) + cmd.execCmd.quit - doCmd("$# $#" % [binaryPath, args], showOutput = true) proc doAction(options: var Options) = if options.showHelp: diff --git a/tests/tester.nim b/tests/tester.nim index c5d9925..446fecb 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -38,7 +38,7 @@ proc execNimble(args: varargs[string]): tuple[output: string, exitCode: int] = var quotedArgs = @args quotedArgs.insert("--nimbleDir:" & installDir) quotedArgs.insert(nimblePath) - quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\"")) + quotedArgs = quotedArgs.map((x: string) => x.quoteShell) let path {.used.} = getCurrentDir().parentDir() / "src" @@ -976,6 +976,24 @@ suite "nimble run": [$DirSep, "run".changeFileExt(ExeExt)]) check output.contains("""Testing `nimble run`: @["--debug", "check"]""") + test "Executable output is shown even when not debugging": + cd "run": + var (output, exitCode) = + execNimble("run", "run", "--option1", "arg1") + check exitCode == QuitSuccess + check output.contains("""Testing `nimble run`: @["--option1", "arg1"]""") + + test "Quotes and whitespace are well handled": + cd "run": + var (output, exitCode) = execNimble( + "run", "run", "\"", "\'", "\t", "arg with spaces" + ) + check exitCode == QuitSuccess + check output.contains( + """Testing `nimble run`: @["\"", "\'", "\t", "arg with spaces"]""" + ) + + test "NimbleVersion is defined": cd "nimbleVersionDefine": var (output, exitCode) = execNimble("c", "-r", "src/nimbleVersionDefine.nim") From a10691bdf23cde83d87c8b7df947fa625fe96c7d Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 26 Mar 2020 16:14:09 -0700 Subject: [PATCH 424/424] show cmd used with --verbose (even on success); fix #783 (#781) * show cmd used with --verbose (even on success) * honor -p:-u:release * address comment * remove --showCmds flag * remove quoteShell * fix #783 * Revert "fix #783" This reverts commit af0ac004c00f17e9983c63ab99e40cd38ba6aaa4. * fix #783 by fixing the gist instead * Revert "fix #783 by fixing the gist instead" now that upstream gist was updated with my patch This reverts commit 8bec86039d8335af152acf238ab14d0268e003e5. --- src/nimble.nim | 12 ++++++++---- src/nimblepkg/tools.nim | 7 +++++-- .../src/nimbleVersionDefine | Bin 93432 -> 89112 bytes 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/nimble.nim b/src/nimble.nim index e923eec..d7e011e 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -251,10 +251,14 @@ proc buildFromDir( if not existsDir(outputDir): createDir(outputDir) + let input = realDir / bin.changeFileExt("nim") + # `quoteShell` would be more robust than `\"` (and avoid quoting when + # un-necessary) but would require changing `extractBin` + let cmd = "\"$#\" $# --noNimblePath $# $# $# \"$#\"" % + [getNimBin(), pkgInfo.backend, nimblePkgVersion, + join(args, " "), outputOpt, input] try: - doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# $# \"$#\"" % - [pkgInfo.backend, nimblePkgVersion, join(args, " "), outputOpt, - realDir / bin.changeFileExt("nim")]) + doCmd(cmd, showCmd = true) binariesBuilt.inc() except NimbleError: let currentExc = (ref NimbleError)(getCurrentException()) @@ -382,7 +386,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options, options.action.passNimFlags else: @[] - buildFromDir(pkgInfo, paths, flags & "-d:release", options) + buildFromDir(pkgInfo, paths, "-d:release" & flags, options) let pkgDestDir = pkgInfo.getPkgDest(options) if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"): diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim index b39fea7..a0e6a0e 100644 --- a/src/nimblepkg/tools.nim +++ b/src/nimblepkg/tools.nim @@ -11,7 +11,7 @@ proc extractBin(cmd: string): string = else: return cmd.split(' ')[0] -proc doCmd*(cmd: string, showOutput = false) = +proc doCmd*(cmd: string, showOutput = false, showCmd = false) = let bin = extractBin(cmd) if findExe(bin) == "": raise newException(NimbleError, "'" & bin & "' not in PATH.") @@ -20,7 +20,10 @@ proc doCmd*(cmd: string, showOutput = false) = stdout.flushFile() stderr.flushFile() - displayDebug("Executing", cmd) + if showCmd: + display("Executing", cmd, priority = MediumPriority) + else: + displayDebug("Executing", cmd) if showOutput: let exitCode = execCmd(cmd) displayDebug("Finished", "with exit code " & $exitCode) diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine b/tests/nimbleVersionDefine/src/nimbleVersionDefine index 7aa3ee894aae8f7caa3ef0731bd0ee9452010a3f..af3cc22a318be8838339bcde68bf318266324d06 100755 GIT binary patch literal 89112 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

QzGccFt5JNK)G;L?5C|Peqf%X%M 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

t`PuWKkA=4TL(qpjXbJj| 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