Compare commits

...
Sign in to create a new pull request.

30 commits

Author SHA1 Message Date
Timothee Cour
a10691bdf2
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.
2020-03-26 23:14:09 +00:00
Daniel M
68a9c4c955 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
2020-02-23 16:01:14 +00:00
Ganesh Viswanathan
27d56f8e9f Remove ~/.nimble from cache 2020-02-11 21:43:41 +00:00
Ganesh Viswanathan
85e5bc7c37 Use travis gist 2020-02-07 00:12:25 +00:00
inv2004
9391fbc56d 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
2020-01-17 22:15:34 +00:00
Taylor Hoff
e9d45ca683 Capitalize the "D" in srcDir to avoid errors when using styleChecks
Fixes #740
2019-11-19 22:00:15 +00:00
Xie Yanbo
16ba5db44e tests' config file should be config.nims
which is created by `nimble init`.
2019-11-10 15:30:38 +00:00
itmuckel
051cfa6cd3 Add '==' as operator for pinning versions. 2019-11-09 12:48:00 +00:00
Dominik Picheta
a8a5bdd863
Fixes #734 2019-10-29 22:43:04 +00:00
yuchunzhou
bbb586dbfc 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
2019-10-28 21:28:46 +00:00
Dominik Picheta
b3abee937d Add tests for #666. 2019-10-24 23:26:21 +01:00
yuchunzhou
703abe3d41 fix #725 2019-10-24 00:20:40 +01:00
Ganesh Viswanathan
5bb795a364 Export initOptions for choosenim 2019-10-23 23:22:00 +01:00
genotrance
a2ec2db8f2
Enable Windows CI (#714)
Also fix #676
2019-10-03 18:38:51 -05:00
Dominik Picheta
4007b2a778 Fixes nimble run on Windows.
Cherry picked from 331a33711d
2019-09-23 00:09:26 +01:00
Dominik Picheta
0ed8e6403c Implicitly disable package validation for run/build/compile. 2019-09-22 22:22:21 +01:00
Dominik Picheta
901afa8c71 Further fix for #432. 2019-09-22 22:13:31 +01:00
Dominik Picheta
3625c1f861 Expand Nimble readme slightly (installation/nimble-run). 2019-09-22 21:36:50 +01:00
Dominik Picheta
b68f7849e6 Add 0.11.0 changelog. 2019-09-22 21:21:26 +01:00
Dominik Picheta
1db54cc736 Fixes some small input validation errors and help text. 2019-09-22 18:11:28 +01:00
Dominik Picheta
10e22fec98 Move issue 432 test to the bottom of tester to fix broken uninstall test. 2019-09-22 17:58:51 +01:00
Dominik Picheta
fe252c6ed6 Fixes #432. Fixes #672. 2019-09-22 16:37:47 +01:00
Dominik Picheta
281a1d129a Fixes #708. Refs #571.
Output from Nimble scripts' top-level statements is now
only visible with --verbose.
2019-09-22 14:39:22 +01:00
Dominik Picheta
a703de5dbd Attempt to reproduce #564. 2019-09-22 13:58:59 +01:00
Dominik Picheta
46dc98bb62 Fixes #710. 2019-09-22 13:34:54 +01:00
Dominik Picheta
c85cdfd814 Fixes #706. No more unused import warnings. 2019-09-22 12:00:15 +01:00
Dominik Picheta
5ea2ac34fe Update CI to test against latest Nim HEAD commit. 2019-09-22 11:53:03 +01:00
Dominik Picheta
da3f70cb98 Fixes #713 and adds test for --depsOnly. 2019-09-22 11:48:00 +01:00
Dominik Picheta
419eba036b Improve error message when there are no packages to uninstall. 2019-09-22 11:48:00 +01:00
Dominik Picheta
137bb1ed07 Fixes #606. Build before/after hook executed every time package is built. 2019-09-22 11:26:57 +01:00
24 changed files with 483 additions and 113 deletions

View file

@ -1,4 +1,5 @@
os:
- windows
- linux
- osx
@ -7,23 +8,17 @@ language: c
env:
- BRANCH=0.19.6
- BRANCH=0.20.2
- BRANCH=1.0.6
# This is the latest working Nim version against which Nimble is being tested
- BRANCH=#212ae2f1257628bd5d1760593ce0a1bad768831a
- BRANCH=#ab525cc48abdbbbed1f772e58e9fe21474f70f07
cache:
directories:
- "$HOME/.choosenim/toolchains/nim-0.19.6"
- "$HOME/.choosenim/toolchains/nim-0.20.2"
- "$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
- curl https://gist.github.com/genotrance/fb53504a4fba88bc5201d3783df5c522/raw/travis.sh -LsSf -o travis.sh
- source travis.sh
script:
- cd tests

View file

@ -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

View file

@ -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
@ -153,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
@ -219,6 +239,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
@ -478,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

View file

@ -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,
@ -200,12 +201,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.version
[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
@ -216,17 +218,24 @@ 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(pkgInfo)
# 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 & "\" ")
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:
@ -242,10 +251,15 @@ 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())
let exc = newException(BuildFailed, "Build failed for package: " &
@ -255,6 +269,15 @@ 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)
proc removePkgDir(dir: string, options: Options) =
## Removes files belonging to the package in ``dir``.
try:
@ -332,7 +355,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 +386,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
options.action.passNimFlags
else:
@[]
buildFromDir(pkgInfo, paths, flags & "-d:release")
buildFromDir(pkgInfo, paths, "-d:release" & flags, options)
let pkgDestDir = pkgInfo.getPkgDest(options)
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
@ -446,7 +469,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,11 +537,11 @@ 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) =
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.")
@ -706,6 +729,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 != "":
@ -840,6 +868,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)
@ -882,7 +921,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:
@ -917,7 +956,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 +1009,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 == @[]:
@ -1035,17 +1074,21 @@ 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)
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)
@ -1074,27 +1117,27 @@ 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]
)
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: Options) =
proc doAction(options: var Options) =
if options.showHelp:
writeHelp()
if options.showVersion:
@ -1105,6 +1148,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)
@ -1133,7 +1180,8 @@ proc doAction(options: Options) =
of actionRun:
run(options)
of actionCompile, actionDoc:
execBackend(options)
var pkgInfo = getPkgInfo(getCurrentDir(), options)
execBackend(pkgInfo, options)
of actionInit:
init(options)
of actionPublish:
@ -1150,7 +1198,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
@ -1159,14 +1207,15 @@ 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.
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 = ""

View file

@ -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

View file

@ -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!")

View file

@ -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

View file

@ -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

View file

@ -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,29 @@ 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 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] =
let
nimsFileCopied = projectDir / nimsFile.splitFile().name & "_" & getProcessId() & ".nims"
outFile = getNimbleTempDir() & ".out"
@ -39,11 +56,18 @@ 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 --verbosity:0",
(getTempDir() / "nimblecache").quoteShell,
nimsFileCopied.quoteShell,
outFile.quoteShell,
actionName
]
).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():
@ -53,7 +77,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):
@ -106,27 +135,30 @@ 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)
stdout.writeExecutionOutput()
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)
@ -150,6 +182,8 @@ proc execScript(scriptName, actionName: string, options: Options):
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.
@ -158,7 +192,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] =
@ -172,11 +206,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)

View file

@ -51,12 +51,13 @@ type
search*: seq[string] # Search string.
of actionInit, actionDump:
projName*: string
vcsOption*: string
of actionCompile, actionDoc, actionBuild:
file*: string
backend*: string
compileOptions: seq[string]
of actionRun:
runFile: string
runFile: Option[string]
compileFlags: seq[string]
runFlags*: seq[string]
of actionCustom:
@ -80,13 +81,19 @@ 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.
uninstall [pkgname, ...] Uninstalls a list of packages.
[-i, --inclDeps] Uninstall package and dependent package(s).
build [opts, ...] Builds a package.
run [opts, ...] bin Builds and runs a package.
build [opts, ...] [bin] Builds a package.
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
@ -197,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 = ""
@ -257,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:
@ -288,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:
@ -345,6 +357,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":
@ -355,7 +373,8 @@ proc parseFlag*(flag, val: string, result: var Options, kind = cmdLongOption) =
if not isGlobalFlag:
result.action.compileOptions.add(getFlagString(kind, flag, val))
of actionRun:
result.action.runFlags.add(getFlagString(kind, flag, val))
result.showHelp = false
result.setRunOptions(flag, getFlagString(kind, flag, val), false)
of actionCustom:
if result.action.command.normalize == "test":
if f == "continue" or f == "c":
@ -367,7 +386,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](),
@ -390,9 +410,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:
@ -415,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)
@ -500,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("")
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
discard

View file

@ -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")

View file

@ -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)

View file

@ -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))

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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"

View file

@ -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!")

View file

@ -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"

View file

@ -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

View file

@ -54,3 +54,9 @@ before install:
after install:
echo("After PkgDir: ", getPkgDir())
before build:
echo("Before build")
after build:
echo("After build")

View file

@ -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

View file

@ -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)
@ -35,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"
@ -79,6 +82,35 @@ 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 (_, exitCode) = execNimble("build")
check exitCode == QuitSuccess
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 "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")
@ -286,12 +318,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")
@ -442,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())
@ -892,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":
@ -904,9 +946,54 @@ 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 "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 "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")
@ -917,6 +1004,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 = [