Compare commits
2 commits
master
...
travis-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f8a7e178d | ||
|
|
f566e8bcd1 |
69 changed files with 1190 additions and 2294 deletions
20
.gitignore
vendored
20
.gitignore
vendored
|
|
@ -6,15 +6,12 @@ nimcache/
|
|||
# Absolute paths
|
||||
/src/babel
|
||||
/src/nimble
|
||||
/tests/tester
|
||||
|
||||
# executables from test and build
|
||||
/nimble
|
||||
src/nimblepkg/cli
|
||||
src/nimblepkg/packageinfo
|
||||
src/nimblepkg/packageparser
|
||||
src/nimblepkg/reversedeps
|
||||
src/nimblepkg/version
|
||||
src/nimblepkg/download
|
||||
/tests/nimscript/nimscript
|
||||
/tests/issue27/issue27
|
||||
|
||||
# Windows executables
|
||||
*.exe
|
||||
|
|
@ -22,13 +19,4 @@ src/nimblepkg/download
|
|||
|
||||
# VCC compiler and linker artifacts
|
||||
*.ilk
|
||||
*.pdb
|
||||
|
||||
# Editors and IDEs project files and folders
|
||||
.vscode
|
||||
|
||||
# VCS artifacts
|
||||
*.orig
|
||||
|
||||
# Test procedure artifacts
|
||||
nimble_*.nims
|
||||
*.pdb
|
||||
24
.travis.yml
24
.travis.yml
|
|
@ -1,24 +1,26 @@
|
|||
os:
|
||||
- windows
|
||||
- linux
|
||||
- osx
|
||||
dist: trusty
|
||||
|
||||
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=#ab525cc48abdbbbed1f772e58e9fe21474f70f07
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- "$HOME/.nimble"
|
||||
- "$HOME/.choosenim"
|
||||
|
||||
install:
|
||||
- curl https://gist.github.com/genotrance/fb53504a4fba88bc5201d3783df5c522/raw/travis.sh -LsSf -o travis.sh
|
||||
- source travis.sh
|
||||
- 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
|
||||
|
||||
before_script:
|
||||
- set -e
|
||||
- set -x
|
||||
- export CHOOSENIM_NO_ANALYTICS=1
|
||||
- export PATH=$HOME/.nimble/bin:$PATH
|
||||
|
||||
script:
|
||||
- cd tests
|
||||
|
|
|
|||
|
|
@ -3,122 +3,6 @@
|
|||
|
||||
# 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
|
||||
|
||||
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
|
||||
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.
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,17 +1,26 @@
|
|||
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 = "0.11.0"
|
||||
version = nimbleVersion
|
||||
author = "Dominik Picheta"
|
||||
description = "Nim package manager."
|
||||
license = "BSD"
|
||||
|
||||
bin = @["nimble"]
|
||||
srcDir = "src"
|
||||
installExt = @["nim"]
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.13.0"
|
||||
requires "nim >= 0.13.0", "compiler#head"
|
||||
|
||||
when defined(nimdistros):
|
||||
import distros
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ 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)
|
||||
|
|
@ -75,15 +74,10 @@ 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. Using ``koch`` and using Nimble
|
||||
itself.
|
||||
|
||||
### Using koch
|
||||
|
||||
The ``koch`` tool is included in the Nim distribution and
|
||||
There are two ways to install Nimble manually. The first is using the
|
||||
``koch`` tool included in the Nim distribution and
|
||||
[repository](https://github.com/nim-lang/Nim/blob/devel/koch.nim).
|
||||
Simply navigate to the location of your Nim installation and execute the
|
||||
following command to compile and install Nimble.
|
||||
Simply execute the following command to compile and install Nimble.
|
||||
|
||||
```
|
||||
./koch nimble
|
||||
|
|
@ -92,19 +86,23 @@ 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:
|
||||
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.
|
||||
|
||||
```
|
||||
nimble install nimble
|
||||
git clone https://github.com/nim-lang/nimble.git
|
||||
cd nimble
|
||||
nim c src/nimble
|
||||
src/nimble install
|
||||
```
|
||||
|
||||
This will download the latest release of Nimble and install it on your system.
|
||||
**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``.
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
|
|
@ -172,13 +170,12 @@ 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 concrete version or a
|
||||
version range, for example:
|
||||
Instead of specifying a VCS branch, you may also specify a version range, for
|
||||
example:
|
||||
|
||||
$ nimble install nimgame@0.5
|
||||
$ nimble install nimgame@"> 0.5"
|
||||
|
||||
The latter command will install a version which is greater than ``0.5``.
|
||||
In this case a version which is greater than ``0.5`` will be installed.
|
||||
|
||||
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
|
||||
|
|
@ -224,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 will result in an error. You can use the
|
||||
``--inclDeps`` or ``-i`` flag to remove all dependent packages along with the package.
|
||||
a package which other packages depend on is disallowed and will result in an
|
||||
error. You must currently manually remove the reverse dependencies first.
|
||||
|
||||
Similar to the ``install`` command you can specify a version range, for example:
|
||||
|
||||
|
|
@ -239,13 +236,6 @@ 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
|
||||
|
|
@ -428,7 +418,6 @@ 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
|
||||
|
|
@ -505,7 +494,7 @@ For a package named "foobar", the recommended project structure is the following
|
|||
└── src
|
||||
└── foobar.nim # Imported via `import foobar`
|
||||
└── tests # Contains the tests
|
||||
├── config.nims
|
||||
├── nim.cfg
|
||||
├── tfoo1.nim # First test
|
||||
└── tfoo2.nim # Second test
|
||||
|
||||
|
|
@ -658,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 ``nimble build`` or ``nimble install`` in the directory
|
||||
running by running ``nimble build`` or ``nimble install`` in the directory
|
||||
of your package.
|
||||
|
||||
### Hybrids
|
||||
|
|
@ -738,13 +727,13 @@ installing your package (on macOS):
|
|||
```
|
||||
Hint: This package requires some external dependencies.
|
||||
Hint: To install them you may be able to run:
|
||||
Hint: brew install openssl
|
||||
Hint: sudo brew install openssl
|
||||
```
|
||||
|
||||
### Nim compiler
|
||||
|
||||
The Nim compiler cannot read .nimble files. Its knowledge of Nimble is
|
||||
limited to the ``nimblePath`` feature which allows it to use packages installed
|
||||
limited to the ``nimblePaths`` 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.
|
||||
|
|
@ -757,27 +746,6 @@ 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:<the_package>`. 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
|
||||
|
|
@ -813,19 +781,6 @@ 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
|
||||
|
|
|
|||
520
src/nimble.nim
520
src/nimble.nim
|
|
@ -3,21 +3,20 @@
|
|||
|
||||
import system except TResult
|
||||
|
||||
import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils, osproc
|
||||
import std/options as std_opt
|
||||
import httpclient, parseopt, os, osproc, pegs, tables, parseutils,
|
||||
strtabs, json, algorithm, sets, uri, future, sequtils
|
||||
|
||||
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,
|
||||
nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser,
|
||||
nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps,
|
||||
nimblepkg/nimscriptexecutor, nimblepkg/init
|
||||
nimblepkg/nimscriptexecutor
|
||||
|
||||
import nimblepkg/nimscriptwrapper
|
||||
import nimblepkg/nimscriptsupport
|
||||
|
||||
proc refresh(options: Options) =
|
||||
## Downloads the package list from the specified URL.
|
||||
|
|
@ -96,7 +95,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 = initHashSet[string]()
|
||||
result = initSet[string]()
|
||||
let whitelistMode =
|
||||
pkgInfo.installDirs.len != 0 or
|
||||
pkgInfo.installFiles.len != 0 or
|
||||
|
|
@ -157,8 +156,7 @@ proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] =
|
|||
"dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion],
|
||||
priority = HighPriority)
|
||||
|
||||
var pkgList {.global.}: seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @[]
|
||||
once: 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":
|
||||
|
|
@ -192,6 +190,11 @@ 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))
|
||||
|
|
@ -201,13 +204,12 @@ 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] != currentVer:
|
||||
pkgsInPath[pkgInfo.name] != pkgInfo.version:
|
||||
raise newException(NimbleError,
|
||||
"Cannot satisfy the dependency on $1 $2 and $1 $3" %
|
||||
[pkgInfo.name, currentVer, pkgsInPath[pkgInfo.name]])
|
||||
pkgsInPath[pkgInfo.name] = currentVer
|
||||
[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
|
||||
|
|
@ -216,33 +218,16 @@ 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],
|
||||
options: Options
|
||||
) =
|
||||
proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string],
|
||||
args: var seq[string]) =
|
||||
## 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 nimblePkgVersion = "-d:NimblePkgVersion=" & pkgInfo.version
|
||||
let realDir = pkgInfo.getRealDir()
|
||||
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:
|
||||
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)
|
||||
|
|
@ -251,15 +236,10 @@ 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(cmd, showCmd = true)
|
||||
binariesBuilt.inc()
|
||||
doCmd("\"" & getNimBin() & "\" $# --noBabelPath $# $# \"$#\"" %
|
||||
[pkgInfo.backend, join(args, " "), outputOpt,
|
||||
realDir / bin.changeFileExt("nim")])
|
||||
except NimbleError:
|
||||
let currentExc = (ref NimbleError)(getCurrentException())
|
||||
let exc = newException(BuildFailed, "Build failed for package: " &
|
||||
|
|
@ -269,14 +249,13 @@ 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 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``.
|
||||
|
|
@ -355,7 +334,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, actionInstall, true):
|
||||
if not execHook(options, true):
|
||||
raise newException(NimbleError, "Pre-hook prevented further execution.")
|
||||
|
||||
var pkgInfo = getPkgInfo(dir, options)
|
||||
|
|
@ -382,11 +361,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 flags = if options.action.typ in {actionInstall, actionPath, actionUninstall, actionDevelop}:
|
||||
options.action.passNimFlags
|
||||
else:
|
||||
@[]
|
||||
buildFromDir(pkgInfo, paths, "-d:release" & flags, options)
|
||||
buildFromDir(pkgInfo, paths, true)
|
||||
|
||||
let pkgDestDir = pkgInfo.getPkgDest(options)
|
||||
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
|
||||
|
|
@ -411,7 +386,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 = initHashSet[string]()
|
||||
var filesInstalled = initSet[string]()
|
||||
iterInstallFiles(realDir, pkgInfo, options,
|
||||
proc (file: string) =
|
||||
createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir))
|
||||
|
|
@ -424,7 +399,7 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
|
|||
pkgInfo.myPath)
|
||||
filesInstalled.incl copyFileD(pkgInfo.myPath, dest)
|
||||
|
||||
var binariesInstalled = initHashSet[string]()
|
||||
var binariesInstalled = initSet[string]()
|
||||
if pkgInfo.bin.len > 0:
|
||||
# Make sure ~/.nimble/bin directory is created.
|
||||
createDir(binDir)
|
||||
|
|
@ -469,7 +444,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, actionInstall, false)
|
||||
discard execHook(options, false)
|
||||
|
||||
proc getDownloadInfo*(pv: PkgTuple, options: Options,
|
||||
doPrompt: bool): (DownloadMethod, string,
|
||||
|
|
@ -536,12 +511,12 @@ proc build(options: Options) =
|
|||
nimScriptHint(pkgInfo)
|
||||
let deps = processDeps(pkginfo, options)
|
||||
let paths = deps.map(dep => dep.getRealDir())
|
||||
var args = options.getCompilationFlags()
|
||||
buildFromDir(pkgInfo, paths, args, options)
|
||||
var args = options.action.compileOptions
|
||||
buildFromDir(pkgInfo, paths, args)
|
||||
|
||||
proc execBackend(pkgInfo: PackageInfo, options: Options) =
|
||||
proc execBackend(options: Options) =
|
||||
let
|
||||
bin = options.getCompilationBinary(pkgInfo).get()
|
||||
bin = options.action.file
|
||||
binDotNim = bin.addFileExt("nim")
|
||||
if bin == "":
|
||||
raise newException(NimbleError, "You need to specify a file.")
|
||||
|
|
@ -554,10 +529,9 @@ proc execBackend(pkgInfo: PackageInfo, 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():
|
||||
for option in options.action.compileOptions:
|
||||
args.add("\"" & option & "\" ")
|
||||
|
||||
let backend =
|
||||
|
|
@ -572,8 +546,8 @@ proc execBackend(pkgInfo: PackageInfo, options: Options) =
|
|||
else:
|
||||
display("Generating", ("documentation for $1 (from package $2) using $3 " &
|
||||
"backend") % [bin, pkgInfo.name, backend], priority = HighPriority)
|
||||
doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# \"$#\"" %
|
||||
[backend, nimblePkgVersion, args, bin], showOutput = true)
|
||||
doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# \"$#\"" %
|
||||
[backend, args, bin], showOutput = true)
|
||||
display("Success:", "Execution finished", Success, HighPriority)
|
||||
|
||||
proc search(options: Options) =
|
||||
|
|
@ -589,7 +563,7 @@ proc search(options: Options) =
|
|||
var found = false
|
||||
template onFound {.dirty.} =
|
||||
echoPackage(pkg)
|
||||
if pkg.alias.len == 0 and options.queryVersions:
|
||||
if options.queryVersions:
|
||||
echoPackageVersions(pkg)
|
||||
echo(" ")
|
||||
found = true
|
||||
|
|
@ -615,7 +589,7 @@ proc list(options: Options) =
|
|||
let pkgList = getPackageList(options)
|
||||
for pkg in pkgList:
|
||||
echoPackage(pkg)
|
||||
if pkg.alias.len == 0 and options.queryVersions:
|
||||
if options.queryVersions:
|
||||
echoPackageVersions(pkg)
|
||||
echo(" ")
|
||||
|
||||
|
|
@ -653,19 +627,23 @@ 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 x in pkgs.items():
|
||||
let
|
||||
pName = x.pkginfo.name
|
||||
pVer = x.pkginfo.specialVersion
|
||||
if name == pName:
|
||||
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)
|
||||
var v: VersionAndPath
|
||||
v.version = newVersion(pVer)
|
||||
v.path = x.pkginfo.getRealDir()
|
||||
v.version = newVersion(pkgInfo.specialVersion)
|
||||
v.path = 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)
|
||||
|
|
@ -729,59 +707,46 @@ 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")
|
||||
var nimbleFile: string = ""
|
||||
|
||||
# Determine the package name.
|
||||
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.
|
||||
let pkgName =
|
||||
if options.action.projName != "":
|
||||
options.action.projName
|
||||
else:
|
||||
os.getCurrentDir().splitPath.tail.toValidPackageName()
|
||||
|
||||
# Validate the package name.
|
||||
validatePackageName(pkgName)
|
||||
nimbleFile = pkgName.changeFileExt("nimble")
|
||||
validatePackageName(nimbleFile.changeFileExt(""))
|
||||
|
||||
# Determine the package root.
|
||||
let pkgRoot =
|
||||
if pkgName == os.getCurrentDir().splitPath.tail:
|
||||
os.getCurrentDir()
|
||||
else:
|
||||
os.getCurrentDir() / pkgName
|
||||
|
||||
let nimbleFile = (pkgRoot / pkgName).changeFileExt("nimble")
|
||||
|
||||
if existsFile(nimbleFile):
|
||||
let errMsg = "Nimble file already exists: $#" % nimbleFile
|
||||
let nimbleFilePath = os.getCurrentDir() / nimbleFile
|
||||
if existsFile(nimbleFilePath):
|
||||
let errMsg = "Nimble file already exists: $#" % nimbleFilePath
|
||||
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)
|
||||
|
||||
# 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
|
||||
# Ask for package author
|
||||
proc getAuthor(): string =
|
||||
if findExe("git") != "":
|
||||
result = getAuthorWithCmd("git config --global user.name")
|
||||
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") != "":
|
||||
result = getAuthorWithCmd("hg config ui.username")
|
||||
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)
|
||||
if result.len == 0:
|
||||
result = promptCustom(options, "Your name?", "Anonymous")
|
||||
let pkgAuthor = getAuthor()
|
||||
|
|
@ -792,16 +757,10 @@ proc init(options: Options) =
|
|||
priority = HighPriority)
|
||||
|
||||
# Determine the type of package
|
||||
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"]
|
||||
)
|
||||
let pkgType = promptList(options, "Package type?", [
|
||||
"lib",
|
||||
"bin",
|
||||
])
|
||||
|
||||
# Ask for package version.
|
||||
let pkgVersion = promptCustom(options, "Initial version of package?", "0.1.0")
|
||||
|
|
@ -812,72 +771,105 @@ For more information see https://goo.gl/cm2RX5""",
|
|||
"A new awesome nimble package")
|
||||
|
||||
# Ask for 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/.
|
||||
""", [
|
||||
let pkgLicense = options.promptList("Package License?", [
|
||||
"MIT",
|
||||
"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"
|
||||
"BSD2",
|
||||
"GPLv3",
|
||||
"LGPLv3",
|
||||
"Apache2",
|
||||
])
|
||||
|
||||
if pkgLicense.toLower == "other":
|
||||
pkgLicense = promptCustom(options,
|
||||
"""Package license?
|
||||
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()
|
||||
let pkgNimDep = promptCustom(options, "Lowest supported Nim version?",
|
||||
$nimDepDef)
|
||||
validateVersion(pkgNimDep)
|
||||
|
||||
createPkgStructure(
|
||||
(
|
||||
pkgName,
|
||||
pkgVersion,
|
||||
pkgAuthor,
|
||||
pkgDesc,
|
||||
pkgLicense,
|
||||
pkgBackend,
|
||||
pkgSrcDir,
|
||||
pkgNimDep,
|
||||
pkgType
|
||||
),
|
||||
pkgRoot
|
||||
)
|
||||
let pkgTestDir = "tests"
|
||||
|
||||
# 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
|
||||
# Create source directory
|
||||
os.createDir(pkgSrcDir)
|
||||
|
||||
var ignoreFile = if vcsBin == "git": ".gitignore" else: ".hgignore"
|
||||
var fd = open(joinPath(pkgRoot, ignoreFile), fmWrite)
|
||||
fd.write(pkgName & "\n")
|
||||
fd.close()
|
||||
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(), 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,
|
||||
MediumPriority)
|
||||
|
||||
display("Success:", "Package $# created successfully" % [pkgName], Success,
|
||||
HighPriority)
|
||||
|
|
@ -887,8 +879,7 @@ proc uninstall(options: Options) =
|
|||
raise newException(NimbleError,
|
||||
"Please specify the package(s) to uninstall.")
|
||||
|
||||
var pkgsToDelete: HashSet[PackageInfo]
|
||||
pkgsToDelete.init()
|
||||
var pkgsToDelete: seq[PackageInfo] = @[]
|
||||
# Do some verification.
|
||||
for pkgTup in options.action.packages:
|
||||
display("Looking", "for $1 ($2)" % [pkgTup.name, $pkgTup.ver],
|
||||
|
|
@ -899,33 +890,34 @@ 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)
|
||||
let revDeps = getRevDeps(options, pkg)
|
||||
var reason = ""
|
||||
if revDeps.len == 1:
|
||||
reason = "$1 ($2) depends on it" % [revDeps[0].name, $revDeps[0].ver]
|
||||
else:
|
||||
let
|
||||
revDeps = getRevDeps(options, pkg)
|
||||
var reason = ""
|
||||
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"
|
||||
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 len(revDeps - pkgsToDelete) > 0:
|
||||
display("Cannot", "uninstall $1 ($2) because $3" %
|
||||
[pkgTup.name, pkg.specialVersion, reason], Warning, HighPriority)
|
||||
else:
|
||||
pkgsToDelete.incl 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, "Failed uninstall - no packages to delete")
|
||||
if pkgsToDelete.len == 0:
|
||||
raise newException(NimbleError, "\n " & errors.join("\n "))
|
||||
|
||||
var pkgNames = ""
|
||||
for pkg in pkgsToDelete.items:
|
||||
if pkgNames.len != 0: pkgNames.add ", "
|
||||
for i in 0 ..< pkgsToDelete.len:
|
||||
if i != 0: pkgNames.add ", "
|
||||
let pkg = pkgsToDelete[i]
|
||||
pkgNames.add("$1 ($2)" % [pkg.name, pkg.specialVersion])
|
||||
|
||||
# Let's confirm that the user wants these packages removed.
|
||||
|
|
@ -949,14 +941,14 @@ proc uninstall(options: Options) =
|
|||
|
||||
proc listTasks(options: Options) =
|
||||
let nimbleFile = findNimbleFile(getCurrentDir(), true)
|
||||
nimscriptwrapper.listTasks(nimbleFile, options)
|
||||
nimscriptsupport.listTasks(nimbleFile, options)
|
||||
|
||||
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, actionDevelop, true):
|
||||
if not execHook(options, true):
|
||||
raise newException(NimbleError, "Pre-hook prevented further execution.")
|
||||
|
||||
var pkgInfo = getPkgInfo(dir, options)
|
||||
|
|
@ -998,7 +990,8 @@ proc developFromDir(dir: string, options: Options) =
|
|||
writeNimbleLink(nimbleLinkPath, nimbleLink)
|
||||
|
||||
# Save a nimblemeta.json file.
|
||||
saveNimbleMeta(pkgDestDir, dir, vcsRevisionInDir(dir), nimbleLinkPath)
|
||||
saveNimbleMeta(pkgDestDir, "file://" & dir, vcsRevisionInDir(dir),
|
||||
nimbleLinkPath)
|
||||
|
||||
# Save the nimble data (which might now contain reverse deps added in
|
||||
# processDeps).
|
||||
|
|
@ -1009,7 +1002,7 @@ proc developFromDir(dir: string, options: Options) =
|
|||
|
||||
# Execute the post-develop hook.
|
||||
cd dir:
|
||||
discard execHook(options, actionDevelop, false)
|
||||
discard execHook(options, false)
|
||||
|
||||
proc develop(options: Options) =
|
||||
if options.action.packages == @[]:
|
||||
|
|
@ -1030,74 +1023,29 @@ proc develop(options: Options) =
|
|||
|
||||
let (meth, url, metadata) = getDownloadInfo(pv, options, true)
|
||||
let subdir = metadata.getOrDefault("subdir")
|
||||
|
||||
# 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)
|
||||
discard downloadPkg(url, pv.ver, meth, subdir, options, downloadDir)
|
||||
developFromDir(downloadDir / subdir, 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
|
||||
|
||||
if files.len < 1:
|
||||
display("Warning:", "No tests found!", Warning, HighPriority)
|
||||
return
|
||||
|
||||
## Executes all tests.
|
||||
var files = toSeq(walkDir(getCurrentDir() / "tests"))
|
||||
files.sort((a, b) => cmp(a.path, b.path))
|
||||
|
||||
for file in files:
|
||||
let (_, name, ext) = file.path.splitFile()
|
||||
if ext == ".nim" and name[0] == 't' and file.kind in {pcFile, pcLinkToFile}:
|
||||
if file.path.endsWith(".nim") and file.kind in {pcFile, pcLinkToFile}:
|
||||
var optsCopy = options.briefClone()
|
||||
optsCopy.action = Action(typ: actionCompile)
|
||||
optsCopy.action.typ = actionCompile
|
||||
optsCopy.action.file = file.path
|
||||
optsCopy.action.backend = pkgInfo.backend
|
||||
optsCopy.getCompilationFlags() = @[]
|
||||
optsCopy.getCompilationFlags().add("-r")
|
||||
optsCopy.getCompilationFlags().add("--path:.")
|
||||
let
|
||||
binFileName = file.path.changeFileExt(ExeExt)
|
||||
existsBefore = existsFile(binFileName)
|
||||
optsCopy.action.backend = "c"
|
||||
optsCopy.action.compileOptions = @[]
|
||||
optsCopy.action.compileOptions.add("-r")
|
||||
optsCopy.action.compileOptions.add("--path:.")
|
||||
execBackend(optsCopy)
|
||||
|
||||
if options.continueTestsOnFailure:
|
||||
inc tests
|
||||
try:
|
||||
execBackend(pkgInfo, optsCopy)
|
||||
except NimbleError:
|
||||
inc failures
|
||||
else:
|
||||
execBackend(pkgInfo, optsCopy)
|
||||
|
||||
let
|
||||
existsAfter = existsFile(binFileName)
|
||||
canRemove = not existsBefore and existsAfter
|
||||
if canRemove:
|
||||
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)
|
||||
else:
|
||||
let error = "Only " & $(tests - failures) & "/" & $tests & " tests passed"
|
||||
display("Error:", error, Error, HighPriority)
|
||||
display("Success:", "All tests passed", Success, HighPriority)
|
||||
|
||||
proc check(options: Options) =
|
||||
## Validates a package in the current working directory.
|
||||
## Validates a package a in the current working directory.
|
||||
let nimbleFile = findNimbleFile(getCurrentDir(), true)
|
||||
var error: ValidationError
|
||||
var pkgInfo: PackageInfo
|
||||
|
|
@ -1115,29 +1063,7 @@ proc check(options: Options) =
|
|||
display("Failure:", "Validation failed", Error, HighPriority)
|
||||
quit(QuitFailure)
|
||||
|
||||
proc run(options: Options) =
|
||||
# Verify parameters.
|
||||
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
||||
|
||||
let binary = options.getCompilationBinary(pkgInfo).get("")
|
||||
if binary.len == 0:
|
||||
raiseNimbleError("Please specify a binary to run")
|
||||
|
||||
if binary notin pkgInfo.bin:
|
||||
raiseNimbleError(
|
||||
"Binary '$#' is not defined in '$#' package." % [binary, pkgInfo.name]
|
||||
)
|
||||
|
||||
# Build the binary.
|
||||
build(options)
|
||||
|
||||
let binaryPath = pkgInfo.getOutputDir(binary)
|
||||
let cmd = quoteShellCommand(binaryPath & options.action.runFlags)
|
||||
displayDebug("Executing", cmd)
|
||||
cmd.execCmd.quit
|
||||
|
||||
|
||||
proc doAction(options: var Options) =
|
||||
proc doAction(options: Options) =
|
||||
if options.showHelp:
|
||||
writeHelp()
|
||||
if options.showVersion:
|
||||
|
|
@ -1148,10 +1074,6 @@ proc doAction(options: var 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,11 +1099,8 @@ proc doAction(options: var Options) =
|
|||
listPaths(options)
|
||||
of actionBuild:
|
||||
build(options)
|
||||
of actionRun:
|
||||
run(options)
|
||||
of actionCompile, actionDoc:
|
||||
var pkgInfo = getPkgInfo(getCurrentDir(), options)
|
||||
execBackend(pkgInfo, options)
|
||||
execBackend(options)
|
||||
of actionInit:
|
||||
init(options)
|
||||
of actionPublish:
|
||||
|
|
@ -1198,46 +1117,37 @@ proc doAction(options: var Options) =
|
|||
of actionNil:
|
||||
assert false
|
||||
of actionCustom:
|
||||
if not execHook(options, actionCustom, true):
|
||||
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[bool]
|
||||
var execResult: ExecutionResult[void]
|
||||
if execCustom(options, execResult, failFast=not isPreDefined):
|
||||
if execResult.hasTaskRequestedCommand():
|
||||
var options = execResult.getOptionsForCommand(options)
|
||||
doAction(options)
|
||||
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, actionCustom, false)
|
||||
discard execHook(options, false)
|
||||
|
||||
when isMainModule:
|
||||
var error = ""
|
||||
var hint = ""
|
||||
|
||||
var opt: Options
|
||||
try:
|
||||
opt = parseCmdLine()
|
||||
opt.doAction()
|
||||
parseCmdLine().doAction()
|
||||
except NimbleError:
|
||||
let currentExc = (ref NimbleError)(getCurrentException())
|
||||
(error, hint) = getOutputInfo(currentExc)
|
||||
except NimbleQuit:
|
||||
discard
|
||||
finally:
|
||||
try:
|
||||
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)
|
||||
removeDir(getNimbleTempDir())
|
||||
|
||||
if error.len > 0:
|
||||
displayTip()
|
||||
|
|
|
|||
|
|
@ -12,11 +12,7 @@
|
|||
# - Bright for HighPriority.
|
||||
# - Normal for MediumPriority.
|
||||
|
||||
import terminal, sets, strutils
|
||||
import version
|
||||
|
||||
when not declared(initHashSet):
|
||||
import common
|
||||
import logging, terminal, sets, strutils
|
||||
|
||||
type
|
||||
CLI* = ref object
|
||||
|
|
@ -45,11 +41,10 @@ const
|
|||
styles: array[DebugPriority .. HighPriority, set[Style]] =
|
||||
[{styleDim}, {styleDim}, {}, {styleBright}]
|
||||
|
||||
|
||||
proc newCLI(): CLI =
|
||||
result = CLI(
|
||||
level: HighPriority,
|
||||
warnings: initHashSet[(string, string)](),
|
||||
warnings: initSet[(string, string)](),
|
||||
suppressionCount: 0,
|
||||
showColor: true,
|
||||
suppressMessages: false
|
||||
|
|
@ -62,18 +57,8 @@ 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)
|
||||
|
|
@ -90,9 +75,6 @@ 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.
|
||||
|
|
@ -100,6 +82,12 @@ 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:
|
||||
|
|
@ -147,7 +135,7 @@ proc prompt*(forcePrompts: ForcePrompt, question: string): bool =
|
|||
display("Prompt:", question & " -> [forced no]", Warning, HighPriority)
|
||||
return false
|
||||
of dontForcePrompt:
|
||||
displayLine("Prompt:", question & " [y/N]", Warning, HighPriority)
|
||||
display("Prompt:", question & " [y/N]", Warning, HighPriority)
|
||||
displayCategory("Answer:", Warning, HighPriority)
|
||||
let yn = stdin.readLine()
|
||||
case yn.normalize
|
||||
|
|
@ -181,76 +169,6 @@ 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:
|
||||
setForegroundColor(fgDefault)
|
||||
# Loop through the options
|
||||
for i, arg in args:
|
||||
# Check if the option is the current
|
||||
if i == current:
|
||||
writeStyled("> " & arg & " <", {styleBright})
|
||||
else:
|
||||
writeStyled(" " & arg & " ", {styleDim})
|
||||
# Move the cursor back to the start
|
||||
for s in 0..<(arg.len + 4):
|
||||
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
|
||||
of '\3':
|
||||
showCursor(stdout)
|
||||
raise newException(NimbleError, "Keyboard interrupt")
|
||||
else: discard
|
||||
|
||||
# Erase all lines of the selection
|
||||
for i in 0..<args.len:
|
||||
eraseLine(stdout)
|
||||
cursorDown(stdout)
|
||||
# Move the cursor back up to the initial selection line
|
||||
for i in 0..<args.len():
|
||||
cursorUp(stdout)
|
||||
showCursor(stdout)
|
||||
display("Answer:", args[current], Warning,HighPriority)
|
||||
return args[current]
|
||||
|
||||
proc promptListFallback(question: string, args: openarray[string]): string =
|
||||
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
|
||||
|
||||
proc promptList*(forcePrompts: ForcePrompt, question: string, args: openarray[string]): string =
|
||||
case forcePrompts:
|
||||
of forcePromptYes:
|
||||
|
|
@ -258,10 +176,13 @@ proc promptList*(forcePrompts: ForcePrompt, question: string, args: openarray[st
|
|||
display("Prompt:", question & " -> [forced " & result & "]", Warning,
|
||||
HighPriority)
|
||||
else:
|
||||
if isatty(stdout):
|
||||
return promptListInteractive(question, args)
|
||||
else:
|
||||
return promptListFallback(question, args)
|
||||
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)
|
||||
|
||||
proc setVerbosity*(level: Priority) =
|
||||
globalCLI.level = level
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ when not defined(nimscript):
|
|||
import sets
|
||||
|
||||
import version
|
||||
export version.NimbleError # TODO: Surely there is a better way?
|
||||
|
||||
type
|
||||
BuildFailed* = object of NimbleError
|
||||
|
|
@ -22,8 +23,7 @@ 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'.
|
||||
## If in doubt, use `getConcreteVersion` instead.
|
||||
## it will always be a non-special version such as '0.1.4'
|
||||
version*: string
|
||||
specialVersion*: string ## Either `myVersion` or a special version such as #head.
|
||||
author*: string
|
||||
|
|
@ -63,16 +63,4 @@ when not defined(nimscript):
|
|||
return (error, hint)
|
||||
|
||||
const
|
||||
nimbleVersion* = "0.11.0"
|
||||
|
||||
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)
|
||||
nimbleVersion* = "0.8.11"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# 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
|
||||
import tools, version, common, cli
|
||||
|
||||
type
|
||||
Config* = object
|
||||
|
|
@ -68,12 +68,11 @@ proc parseConfig*(): Config =
|
|||
var e = next(p)
|
||||
case e.kind
|
||||
of cfgEof:
|
||||
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)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -2,15 +2,14 @@
|
|||
# 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
|
||||
git = "git", hg = "hg"
|
||||
|
||||
proc getSpecificDir(meth: DownloadMethod): string {.used.} =
|
||||
proc getSpecificDir(meth: DownloadMethod): string =
|
||||
case meth
|
||||
of DownloadMethod.git:
|
||||
".git"
|
||||
|
|
@ -25,12 +24,11 @@ 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)
|
||||
|
||||
proc doPull(meth: DownloadMethod, downloadDir: string) {.used.} =
|
||||
proc doPull(meth: DownloadMethod, downloadDir: string) =
|
||||
case meth
|
||||
of DownloadMethod.git:
|
||||
doCheckout(meth, downloadDir, "")
|
||||
|
|
@ -44,17 +42,17 @@ proc doPull(meth: DownloadMethod, downloadDir: string) {.used.} =
|
|||
doCmd("hg pull")
|
||||
|
||||
proc doClone(meth: DownloadMethod, url, downloadDir: string, branch = "",
|
||||
onlyTip = true) =
|
||||
tip = true) =
|
||||
case meth
|
||||
of DownloadMethod.git:
|
||||
let
|
||||
depthArg = if onlyTip: "--depth 1 " else: ""
|
||||
depthArg = if tip: "--depth 1 " else: ""
|
||||
branchArg = if branch == "": "" else: "-b " & branch & " "
|
||||
doCmd("git clone --recursive " & depthArg & branchArg & url &
|
||||
" " & downloadDir)
|
||||
of DownloadMethod.hg:
|
||||
let
|
||||
tipArg = if onlyTip: "-r tip " else: ""
|
||||
tipArg = if tip: "-r tip " else: ""
|
||||
branchArg = if branch == "": "" else: "-b " & branch & " "
|
||||
doCmd("hg clone " & tipArg & branchArg & url & " " & downloadDir)
|
||||
|
||||
|
|
@ -104,21 +102,14 @@ 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]): 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 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 getDownloadMethod*(meth: string): DownloadMethod =
|
||||
case meth
|
||||
|
|
@ -180,11 +171,10 @@ 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):
|
||||
# Grab HEAD.
|
||||
doClone(downMethod, url, downloadDir, onlyTip = not options.forceFullClone)
|
||||
doClone(downMethod, url, downloadDir) # Grab HEAD.
|
||||
else:
|
||||
# Grab the full repo.
|
||||
doClone(downMethod, url, downloadDir, onlyTip = false)
|
||||
doClone(downMethod, url, downloadDir, tip = false)
|
||||
# Then perform a checkout operation to get the specified branch/commit.
|
||||
# `spe` starts with '#', trim it.
|
||||
doAssert(($verRange.spe)[0] == '#')
|
||||
|
|
@ -201,13 +191,12 @@ proc doDownload(url: string, downloadDir: string, verRange: VersionRange,
|
|||
getLatestByTag:
|
||||
display("Cloning", "latest tagged version: " & latest.tag,
|
||||
priority = MediumPriority)
|
||||
doClone(downMethod, url, downloadDir, latest.tag,
|
||||
onlyTip = not options.forceFullClone)
|
||||
doClone(downMethod, url, downloadDir, latest.tag)
|
||||
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, onlyTip = not options.forceFullClone)
|
||||
doClone(downMethod, url, downloadDir)
|
||||
result = getHeadName(downMethod)
|
||||
let versions = getTagsList(downloadDir, downMethod).getVersionList()
|
||||
|
||||
|
|
@ -276,8 +265,14 @@ proc echoPackageVersions*(pkg: Package) =
|
|||
try:
|
||||
let versions = getTagsListRemote(pkg.url, downMethod).getVersionList()
|
||||
if versions.len > 0:
|
||||
let sortedVersions = toSeq(values(versions))
|
||||
echo(" versions: " & join(sortedVersions, ", "))
|
||||
var vstr = ""
|
||||
var i = 0
|
||||
for v in values(versions):
|
||||
if i != 0:
|
||||
vstr.add(", ")
|
||||
vstr.add(v)
|
||||
i.inc
|
||||
echo(" versions: " & vstr)
|
||||
else:
|
||||
echo(" versions: (No versions tagged in the remote repository)")
|
||||
except OSError:
|
||||
|
|
@ -285,32 +280,3 @@ 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)
|
||||
|
||||
|
||||
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!")
|
||||
|
|
|
|||
|
|
@ -1,184 +0,0 @@
|
|||
import os, strutils
|
||||
|
||||
import ./cli, ./tools
|
||||
|
||||
type
|
||||
PkgInitInfo* = tuple
|
||||
pkgName: string
|
||||
pkgVersion: string
|
||||
pkgAuthor: string
|
||||
pkgDesc: string
|
||||
pkgLicense: string
|
||||
pkgBackend: string
|
||||
pkgSrcDir: string
|
||||
pkgNimDep: string
|
||||
pkgType: 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", priority = HighPriority)
|
||||
|
||||
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")
|
||||
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.
|
||||
|
||||
when isMainModule:
|
||||
echo("Hello, World!")
|
||||
"""
|
||||
)
|
||||
nimbleFileOptions.add("bin = @[\"$1\"]\n" % info.pkgName)
|
||||
of "library":
|
||||
let mainFile = pkgRoot / info.pkgSrcDir / info.pkgName.changeFileExt("nim")
|
||||
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
|
||||
# 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")
|
||||
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
|
||||
# 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")
|
||||
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.
|
||||
|
||||
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")
|
||||
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
|
||||
# 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":
|
||||
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`
|
||||
# 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:
|
||||
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`
|
||||
# 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")
|
||||
# Only write backend if it isn't "c"
|
||||
var pkgBackend = ""
|
||||
if (info.pkgBackend != "c"):
|
||||
pkgBackend = "backend = " & info.pkgbackend.escape()
|
||||
writeFile(nimbleFile, """# Package
|
||||
|
||||
version = $#
|
||||
author = "$#"
|
||||
description = "$#"
|
||||
license = $#
|
||||
srcDir = $#
|
||||
$#
|
||||
$#
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= $#"
|
||||
""" % [
|
||||
info.pkgVersion.escape(), info.pkgAuthor.replace("\"", "\\\""), info.pkgDesc.replace("\"", "\\\""),
|
||||
info.pkgLicense.escape(), info.pkgSrcDir.escape(), nimbleFileOptions,
|
||||
pkgBackend, info.pkgNimDep
|
||||
]
|
||||
)
|
||||
|
||||
display("Info:", "Nimble file created successfully", priority=MediumPriority)
|
||||
|
|
@ -3,12 +3,6 @@
|
|||
|
||||
## This module is implicitly imported in NimScript .nimble files.
|
||||
|
||||
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
|
||||
|
|
@ -17,7 +11,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.
|
||||
|
||||
|
|
@ -28,140 +22,29 @@ 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 = ""
|
||||
outFile = ""
|
||||
|
||||
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() =
|
||||
# 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[0] != '-':
|
||||
if projectFile.len == 0:
|
||||
projectFile = param
|
||||
elif outFile.len == 0:
|
||||
outFile = param
|
||||
else:
|
||||
commandLineParams.add param.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:
|
||||
result &= astToStr(varName) & ": \"\"\"" & varName & "\"\"\"\n"
|
||||
|
||||
template printSeqIfLen(varName) =
|
||||
if varName.len != 0:
|
||||
result &= astToStr(varName) & ": \"" & varName.join(", ") & "\"\n"
|
||||
|
||||
proc printPkgInfo(): string =
|
||||
if backend.len == 0:
|
||||
backend = "c"
|
||||
|
||||
result = "[Package]\n"
|
||||
if packageName.len != 0:
|
||||
result &= "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:
|
||||
result &= "\n[Deps]\n"
|
||||
result &= &"requires: \"{requiresData.join(\", \")}\"\n"
|
||||
|
||||
proc onExit*() =
|
||||
if "printPkgInfo".normalize in commandLineParams:
|
||||
if outFile.len != 0:
|
||||
writeFile(outFile, 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:
|
||||
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] & "}, "
|
||||
|
||||
output &= "\"retVal\": " & $retVal
|
||||
|
||||
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.
|
||||
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
|
||||
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
|
||||
|
||||
if commandLineParams.len == 0 or "help" in commandLineParams:
|
||||
success = true
|
||||
echo(astToStr(name), " ", description)
|
||||
elif astToStr(name).normalize in commandLineParams:
|
||||
success = true
|
||||
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 =
|
||||
|
|
@ -170,27 +53,15 @@ 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
|
||||
|
||||
afterHooks.add astToStr(action)
|
||||
|
||||
if (astToStr(action) & "After").normalize in commandLineParams:
|
||||
success = true
|
||||
retVal = `action After`()
|
||||
template builtin = discard
|
||||
|
||||
proc getPkgDir*(): string =
|
||||
## Returns the package directory containing the .nimble file currently
|
||||
## being evaluated.
|
||||
result = projectFile.rsplit(seps={'/', '\\', ':'}, maxsplit=1)[0]
|
||||
|
||||
getParams()
|
||||
builtin
|
||||
|
|
|
|||
|
|
@ -1,17 +1,16 @@
|
|||
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
|
||||
import os, strutils, sets
|
||||
import os, tables, strutils, sets
|
||||
|
||||
import packageparser, common, packageinfo, options, nimscriptwrapper, cli,
|
||||
version
|
||||
import packageparser, common, packageinfo, options, nimscriptsupport, cli
|
||||
|
||||
proc execHook*(options: Options, hookAction: ActionType, before: bool): bool =
|
||||
proc execHook*(options: Options, before: bool): bool =
|
||||
## Returns whether to continue.
|
||||
result = true
|
||||
|
||||
# For certain commands hooks should not be evaluated.
|
||||
if hookAction in noHookActions:
|
||||
if options.action.typ in noHookActions:
|
||||
return
|
||||
|
||||
var nimbleFile = ""
|
||||
|
|
@ -21,8 +20,8 @@ proc execHook*(options: Options, hookAction: ActionType, 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 hookAction == actionCustom: options.action.command
|
||||
else: ($hookAction)[6 .. ^1]
|
||||
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
|
||||
|
|
@ -32,7 +31,7 @@ proc execHook*(options: Options, hookAction: ActionType, before: bool): bool =
|
|||
result = res.retVal
|
||||
|
||||
proc execCustom*(options: Options,
|
||||
execResult: var ExecutionResult[bool],
|
||||
execResult: var ExecutionResult[void],
|
||||
failFast = true): bool =
|
||||
## Executes the custom command using the nimscript backend.
|
||||
##
|
||||
|
|
@ -58,7 +57,7 @@ proc execCustom*(options: Options,
|
|||
HighPriority)
|
||||
return
|
||||
|
||||
if not execHook(options, actionCustom, false):
|
||||
if not execHook(options, false):
|
||||
return
|
||||
|
||||
return true
|
||||
|
|
|
|||
692
src/nimblepkg/nimscriptsupport.nim
Normal file
692
src/nimblepkg/nimscriptsupport.nim
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
# 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/passaux,
|
||||
compiler/condsyms, compiler/sem, compiler/semdata,
|
||||
compiler/llstream, compiler/vm, compiler/vmdef, compiler/commands,
|
||||
compiler/msgs, compiler/magicsys, 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
|
||||
import os, strutils, strtabs, 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
|
||||
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, toSeconds(getLastModificationTime(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
|
||||
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):
|
||||
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)
|
||||
|
||||
let pkgName = scriptName.splitFile.name
|
||||
|
||||
# Ensure that "nimblepkg/nimscriptapi" is in the PATH.
|
||||
block:
|
||||
let t = getTempDir() / "nimblecache"
|
||||
let tmpNimscriptApiPath = t / "nimblepkg" / "nimscriptapi.nim"
|
||||
createDir(tmpNimscriptApiPath.splitFile.dir)
|
||||
writeFile(tmpNimscriptApiPath, nimscriptApi)
|
||||
when declared(NimCompilerApiVersion):
|
||||
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()
|
||||
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..<graph.modules.len:
|
||||
if graph.modules[i] != nil and
|
||||
graph.modules[i].name.s == "nimscriptapi":
|
||||
apiModule = graph.modules[i]
|
||||
break
|
||||
doAssert apiModule != nil
|
||||
|
||||
# Check whether an error has occurred.
|
||||
if errCounter() > 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 getNimScriptCommand(): string =
|
||||
when declared(NimCompilerApiVersion):
|
||||
let conf = graph.config
|
||||
nimCommand()
|
||||
|
||||
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()
|
||||
|
|
@ -1,216 +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 hashes, json, os, strutils, tables, times, osproc, strtabs
|
||||
|
||||
import version, options, cli, tools
|
||||
|
||||
type
|
||||
Flags = TableRef[string, seq[string]]
|
||||
ExecutionResult*[T] = object
|
||||
success*: bool
|
||||
command*: string
|
||||
arguments*: seq[string]
|
||||
flags*: Flags
|
||||
retVal*: T
|
||||
stdout*: string
|
||||
|
||||
const
|
||||
internalCmd = "e"
|
||||
nimscriptApi = staticRead("nimscriptapi.nim")
|
||||
printPkgInfo = "printPkgInfo"
|
||||
|
||||
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"
|
||||
|
||||
let
|
||||
isScriptResultCopied =
|
||||
nimsFileCopied.fileExists() and
|
||||
nimsFileCopied.getLastModificationTime() >= nimsFile.getLastModificationTime()
|
||||
|
||||
if not isScriptResultCopied:
|
||||
nimsFile.copyFile(nimsFileCopied)
|
||||
|
||||
defer:
|
||||
# Only if copied in this invocation, allows recursive calls of nimble
|
||||
if not isScriptResultCopied and options.shouldRemoveTmp(nimsFileCopied):
|
||||
nimsFileCopied.removeFile()
|
||||
|
||||
var cmd = (
|
||||
"nim e $# -p:$# $# $# $#" % [
|
||||
"--hints:off --verbosity:0",
|
||||
(getTempDir() / "nimblecache").quoteShell,
|
||||
nimsFileCopied.quoteShell,
|
||||
outFile.quoteShell,
|
||||
actionName
|
||||
]
|
||||
).strip()
|
||||
|
||||
let isCustomTask = isCustomTask(actionName, options)
|
||||
if isCustomTask:
|
||||
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)
|
||||
|
||||
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):
|
||||
discard outFile.tryRemoveFile()
|
||||
|
||||
proc getNimsFile(scriptName: string, options: Options): string =
|
||||
let
|
||||
cacheDir = getTempDir() / "nimblecache"
|
||||
shash = $scriptName.parentDir().hash().abs()
|
||||
prjCacheDir = cacheDir / scriptName.splitFile().name & "_" & shash
|
||||
nimscriptApiFile = cacheDir / "nimscriptapi.nim"
|
||||
|
||||
result = prjCacheDir / scriptName.extractFilename().changeFileExt ".nims"
|
||||
|
||||
let
|
||||
iniFile = result.changeFileExt(".ini")
|
||||
|
||||
isNimscriptApiCached =
|
||||
nimscriptApiFile.fileExists() and nimscriptApiFile.getLastModificationTime() >
|
||||
getAppFilename().getLastModificationTime()
|
||||
|
||||
isScriptResultCached =
|
||||
isNimscriptApiCached and result.fileExists() and result.getLastModificationTime() >
|
||||
scriptName.getLastModificationTime()
|
||||
|
||||
if not isNimscriptApiCached:
|
||||
createDir(cacheDir)
|
||||
writeFile(nimscriptApiFile, nimscriptApi)
|
||||
|
||||
if not isScriptResultCached:
|
||||
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
|
||||
nimsFile = getNimsFile(scriptName, options)
|
||||
|
||||
result = nimsFile.changeFileExt(".ini")
|
||||
|
||||
let
|
||||
isIniResultCached =
|
||||
result.fileExists() and result.getLastModificationTime() >
|
||||
scriptName.getLastModificationTime()
|
||||
|
||||
if not isIniResultCached:
|
||||
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, stdout & "\nprintPkgInfo() failed")
|
||||
|
||||
proc execScript(
|
||||
scriptName, actionName: string, options: Options, isHook: bool
|
||||
): ExecutionResult[bool] =
|
||||
let nimsFile = getNimsFile(scriptName, options)
|
||||
|
||||
let (output, exitCode, stdout) =
|
||||
execNimscript(
|
||||
nimsFile, scriptName.parentDir(), actionName, options, isHook
|
||||
)
|
||||
|
||||
if exitCode != 0:
|
||||
let errMsg =
|
||||
if stdout.len != 0:
|
||||
stdout
|
||||
else:
|
||||
"Exception raised during nimble script execution"
|
||||
raise newException(NimbleError, errMsg)
|
||||
|
||||
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()
|
||||
|
||||
stdout.writeExecutionOutput()
|
||||
|
||||
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, isHook=false)
|
||||
|
||||
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, 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, isHook=false)
|
||||
|
|
@ -2,17 +2,14 @@
|
|||
# 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
|
||||
import config, version, tools, common, cli
|
||||
|
||||
type
|
||||
Options* = object
|
||||
forcePrompts*: ForcePrompt
|
||||
depsOnly*: bool
|
||||
uninstallRevDeps*: bool
|
||||
queryVersions*: bool
|
||||
queryInstalled*: bool
|
||||
nimbleDir*: string
|
||||
|
|
@ -25,18 +22,12 @@ type
|
|||
showVersion*: bool
|
||||
noColor*: bool
|
||||
disableValidation*: bool
|
||||
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,
|
||||
actionRun
|
||||
actionDoc, actionCustom, actionTasks, actionDevelop, actionCheck
|
||||
|
||||
Action* = object
|
||||
case typ*: ActionType
|
||||
|
|
@ -46,20 +37,14 @@ 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:
|
||||
projName*: string
|
||||
vcsOption*: string
|
||||
of actionCompile, actionDoc, actionBuild:
|
||||
file*: string
|
||||
backend*: string
|
||||
compileOptions: seq[string]
|
||||
of actionRun:
|
||||
runFile: Option[string]
|
||||
compileFlags: seq[string]
|
||||
runFlags*: seq[string]
|
||||
compileOptions*: seq[string]
|
||||
of actionCustom:
|
||||
command*: string
|
||||
arguments*: seq[string]
|
||||
|
|
@ -72,32 +57,21 @@ 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.
|
||||
check Verifies the validity of a package in the
|
||||
current working directory.
|
||||
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.
|
||||
current directory.
|
||||
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, ...] [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.
|
||||
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
|
||||
[-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
|
||||
|
|
@ -160,8 +134,6 @@ 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 +168,6 @@ 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 = ""
|
||||
|
|
@ -204,11 +175,8 @@ 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 = ""
|
||||
of actionSearch:
|
||||
|
|
@ -217,7 +185,7 @@ proc initAction*(options: var Options, key: string) =
|
|||
options.action.command = key
|
||||
options.action.arguments = @[]
|
||||
options.action.flags = newStringTable()
|
||||
of actionPublish, actionList, actionTasks, actionCheck, actionRun,
|
||||
of actionPublish, actionList, actionTasks, actionCheck,
|
||||
actionNil: discard
|
||||
|
||||
proc prompt*(options: Options, question: string): bool =
|
||||
|
|
@ -241,6 +209,18 @@ 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:
|
||||
|
|
@ -263,15 +243,9 @@ proc getBinDir*(options: Options): string =
|
|||
options.getNimbleDir() / "bin"
|
||||
|
||||
proc parseCommand*(key: string, result: var Options) =
|
||||
result.action = Action(typ: parseActionType(key))
|
||||
result.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:
|
||||
|
|
@ -292,40 +266,23 @@ proc parseArgument*(key: string, result: var Options) =
|
|||
result.action.search.add(key)
|
||||
of actionInit, actionDump:
|
||||
if result.action.projName != "":
|
||||
raise newException(
|
||||
NimbleError, "Can only perform this action on one package at a time."
|
||||
)
|
||||
raise newException(NimbleError,
|
||||
"Can only initialize one package at a time.")
|
||||
result.action.projName = key
|
||||
of actionCompile, actionDoc:
|
||||
result.action.file = key
|
||||
of actionList, actionPublish:
|
||||
of actionList, actionBuild, actionPublish:
|
||||
result.showHelp = true
|
||||
of actionBuild:
|
||||
result.action.file = key
|
||||
of actionRun:
|
||||
result.setRunOptions(key, key, true)
|
||||
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
|
||||
|
|
@ -336,64 +293,43 @@ 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.
|
||||
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 actionInit:
|
||||
case f
|
||||
of "git", "hg":
|
||||
result.action.vcsOption = f
|
||||
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.showHelp = false
|
||||
result.setRunOptions(flag, getFlagString(kind, flag, val), false)
|
||||
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
|
||||
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
|
||||
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:
|
||||
result.action.flags[flag] = val
|
||||
else:
|
||||
wasFlagHandled = false
|
||||
|
||||
if not wasFlagHandled and not isGlobalFlag:
|
||||
result.unknownFlags.add((kind, flag, val))
|
||||
if not wasFlagHandled:
|
||||
raise newException(NimbleError, "Unknown option: --" & flag)
|
||||
|
||||
proc initOptions*(): Options =
|
||||
# Exported for choosenim
|
||||
Options(
|
||||
action: Action(typ: actionNil),
|
||||
pkgInfoCache: newTable[string, PackageInfo](),
|
||||
verbosity: HighPriority,
|
||||
noColor: not isatty(stdout)
|
||||
)
|
||||
result.action.typ = actionNil
|
||||
result.pkgInfoCache = newTable[string, PackageInfo]()
|
||||
result.nimbleDir = ""
|
||||
result.verbosity = HighPriority
|
||||
result.noColor = not isatty(stdout)
|
||||
|
||||
proc parseMisc(options: var Options) =
|
||||
# Load nimbledata.json
|
||||
|
|
@ -408,29 +344,6 @@ proc parseMisc(options: var Options) =
|
|||
else:
|
||||
options.nimbleData = %{"reverseDeps": newJObject()}
|
||||
|
||||
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:
|
||||
let flag = options.unknownFlags[0]
|
||||
raise newException(
|
||||
NimbleError,
|
||||
"Unknown option: " & getFlagString(flag[0], flag[1], flag[2])
|
||||
)
|
||||
|
||||
proc parseCmdLine*(): Options =
|
||||
result = initOptions()
|
||||
|
||||
|
|
@ -444,11 +357,9 @@ 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)
|
||||
|
||||
# Set verbosity level.
|
||||
setVerbosity(result.verbosity)
|
||||
|
||||
|
|
@ -464,11 +375,6 @@ 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 = ""
|
||||
|
|
@ -504,48 +410,5 @@ 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
|
||||
|
||||
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
|
||||
|
||||
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, 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 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.changeFileExt(ExeExt))
|
||||
else:
|
||||
discard
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
# Stdlib imports
|
||||
import system except TResult
|
||||
import hashes, json, strutils, os, sets, tables, httpclient
|
||||
import parsecfg, json, streams, strutils, parseutils, os, sets, tables
|
||||
import httpclient
|
||||
|
||||
# Local imports
|
||||
import version, tools, common, options, cli, config
|
||||
|
|
@ -277,7 +278,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 = initHashSet[string]()
|
||||
var namesAdded = initSet[string]()
|
||||
for name, list in options.config.packageLists:
|
||||
let packages = readPackageList(name, options)
|
||||
for p in packages:
|
||||
|
|
@ -312,17 +313,14 @@ proc findNimbleFile*(dir: string; error: bool): string =
|
|||
# Return the path of the real .nimble file.
|
||||
result = readNimbleLink(result).nimbleFilePath
|
||||
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." % dir
|
||||
display("Warning:", msg, Warning, HighPriority)
|
||||
display("Hint:", hintMsg, Warning, HighPriority)
|
||||
raiseNimbleError("The .nimble-link file is pointing to a missing" &
|
||||
" file: " & result)
|
||||
|
||||
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 ``nimscriptwrapper``.
|
||||
## ``packageparser`` module, and so can be used by ``nimscriptsupport``.
|
||||
##
|
||||
## ``libsDir`` is in most cases: ~/.nimble/pkgs/ (options.getPkgsDir)
|
||||
result = @[]
|
||||
|
|
@ -338,17 +336,8 @@ proc getInstalledPkgsMin*(libsDir: string, options: Options):
|
|||
pkg.specialVersion = version
|
||||
pkg.isMinimal = true
|
||||
pkg.isInstalled = true
|
||||
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)
|
||||
pkg.isLinked =
|
||||
cmpPaths(nimbleFile.splitFile().dir, path) != 0
|
||||
result.add((pkg, meta))
|
||||
|
||||
proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool =
|
||||
|
|
@ -536,15 +525,6 @@ 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
|
||||
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -3,13 +3,7 @@
|
|||
import os, strutils, sets, json
|
||||
|
||||
# Local imports
|
||||
import cli, options, tools
|
||||
|
||||
when defined(windows):
|
||||
import version
|
||||
|
||||
when not declared(initHashSet) or not declared(toHashSet):
|
||||
import common
|
||||
import cli, common, options, tools
|
||||
|
||||
when defined(windows):
|
||||
# This is just for Win XP support.
|
||||
|
|
@ -109,4 +103,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,
|
||||
toHashSet[string]([nimbleLinkPath]), initHashSet[string](), true)
|
||||
toSet[string]([nimbleLinkPath]), initSet[string](), true)
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
import parsecfg, sets, streams, strutils, os, tables, sugar
|
||||
import parsecfg, json, streams, strutils, parseutils, os, tables, future
|
||||
from sequtils import apply, map
|
||||
|
||||
import version, tools, common, nimscriptwrapper, options, packageinfo, cli
|
||||
import version, tools, common, nimscriptsupport, options, packageinfo, cli
|
||||
|
||||
## Contains procedures for parsing .nimble files. Moved here from ``packageinfo``
|
||||
## because it depends on ``nimscriptwrapper`` (``nimscriptwrapper`` also
|
||||
## because it depends on ``nimscriptsupport`` (``nimscriptsupport`` also
|
||||
## depends on other procedures in ``packageinfo``.
|
||||
|
||||
type
|
||||
|
|
@ -212,10 +212,7 @@ proc multiSplit(s: string): seq[string] =
|
|||
result.del(i)
|
||||
# Huh, nothing to return? Return given input.
|
||||
if len(result) < 1:
|
||||
if s.strip().len != 0:
|
||||
return @[s]
|
||||
else:
|
||||
return @[]
|
||||
return @[s]
|
||||
|
||||
proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
|
||||
var fs = newFileStream(path, fmRead)
|
||||
|
|
@ -256,20 +253,12 @@ 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()
|
||||
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":
|
||||
|
|
@ -288,33 +277,6 @@ 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
|
||||
# installed.)
|
||||
let installInstructions =
|
||||
pkgInfo.installDirs.len + pkgInfo.installExt.len + pkgInfo.installFiles.len
|
||||
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.
|
||||
|
|
@ -389,9 +351,6 @@ proc readPackageInfo(nf: NimbleFile, options: Options,
|
|||
if version.kind == verSpecial:
|
||||
result.specialVersion = minimalInfo.version
|
||||
|
||||
# Apply rules to infer which files should/shouldn't be installed. See #469.
|
||||
inferInstallRules(result, options)
|
||||
|
||||
if not result.isMinimal:
|
||||
options.pkgInfoCache[nf] = result
|
||||
|
||||
|
|
@ -487,15 +446,6 @@ 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")
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
## nim-lang/packages automatically.
|
||||
|
||||
import system except TResult
|
||||
import httpclient, strutils, json, os, browsers, times, uri
|
||||
import version, tools, common, cli, config, options
|
||||
import httpclient, base64, strutils, rdstdin, json, os, browsers, times, uri
|
||||
import tools, common, cli, config, options
|
||||
|
||||
type
|
||||
Auth = object
|
||||
|
|
@ -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).strip()
|
||||
result.token = readFile(apiTokenFilePath)
|
||||
display("Info:", "Using GitHub API Token in file: " & apiTokenFilePath,
|
||||
priority = HighPriority)
|
||||
except IOError:
|
||||
|
|
@ -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"}.getBool():
|
||||
if j{"fork"}.getBVal():
|
||||
result = j{"parent"}{"full_name"}.getStr() == "nim-lang/packages"
|
||||
|
||||
proc forkExists(a: Auth): bool =
|
||||
|
|
@ -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 = getNimbleUserTempDir() / "nimble-packages-fork"
|
||||
var pkgsDir = getTempDir() / "nimble-packages-fork"
|
||||
if not forkExists(auth):
|
||||
createFork(auth)
|
||||
display("Info:", "Waiting 10s to let Github create a fork",
|
||||
|
|
@ -213,14 +213,11 @@ 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? (For example: web library wrapper)",
|
||||
""
|
||||
)
|
||||
let tags = promptCustom("Whitespace separated list of tags?", "")
|
||||
|
||||
cd pkgsDir:
|
||||
editJson(p, url, tags, downloadMethod)
|
||||
let branchName = "add-" & p.name & getTime().utc.format("HHmm")
|
||||
let branchName = "add-" & p.name & getTime().getGMTime().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)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) Dominik Picheta. All rights reserved.
|
||||
# BSD License. Look at license.txt for more info.
|
||||
|
||||
import os, json, sets
|
||||
import os, json
|
||||
|
||||
import options, common, version, download, packageinfo
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) =
|
|||
newData[key] = newVal
|
||||
nimbleData["reverseDeps"] = newData
|
||||
|
||||
proc getRevDepTups*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
|
||||
proc getRevDeps*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
|
||||
## Returns a list of *currently installed* reverse dependencies for `pkg`.
|
||||
result = @[]
|
||||
let thisPkgsDep =
|
||||
|
|
@ -76,26 +76,6 @@ proc getRevDepTups*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
|
|||
|
||||
result.add(pkgTup)
|
||||
|
||||
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 getRevDepTups(options, pkg):
|
||||
for rdepInfo in findAllPkgs(installedPkgs, rdepTup):
|
||||
if rdepInfo in result:
|
||||
continue
|
||||
|
||||
getAllRevDeps(options, rdepInfo, result)
|
||||
result.incl pkg
|
||||
|
||||
when isMainModule:
|
||||
var nimbleData = %{"reverseDeps": newJObject()}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
# Various miscellaneous utility functions reside here.
|
||||
import osproc, pegs, strutils, os, uri, sets, json, parseutils
|
||||
import version, cli
|
||||
import version, common, cli
|
||||
|
||||
proc extractBin(cmd: string): string =
|
||||
if cmd[0] == '"':
|
||||
|
|
@ -11,7 +11,7 @@ proc extractBin(cmd: string): string =
|
|||
else:
|
||||
return cmd.split(' ')[0]
|
||||
|
||||
proc doCmd*(cmd: string, showOutput = false, showCmd = false) =
|
||||
proc doCmd*(cmd: string, showOutput = false) =
|
||||
let bin = extractBin(cmd)
|
||||
if findExe(bin) == "":
|
||||
raise newException(NimbleError, "'" & bin & "' not in PATH.")
|
||||
|
|
@ -20,10 +20,7 @@ proc doCmd*(cmd: string, showOutput = false, showCmd = false) =
|
|||
stdout.flushFile()
|
||||
stderr.flushFile()
|
||||
|
||||
if showCmd:
|
||||
display("Executing", cmd, priority = MediumPriority)
|
||||
else:
|
||||
displayDebug("Executing", cmd)
|
||||
displayDebug("Executing", cmd)
|
||||
if showOutput:
|
||||
let exitCode = execCmd(cmd)
|
||||
displayDebug("Finished", "with exit code " & $exitCode)
|
||||
|
|
@ -109,10 +106,6 @@ 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 = ""
|
||||
|
|
@ -151,15 +144,6 @@ 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.
|
||||
##
|
||||
|
|
@ -167,18 +151,10 @@ 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_" & getProcessId()
|
||||
|
||||
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"))
|
||||
result = getTempDir() / "nimble_"
|
||||
when defined(windows):
|
||||
proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32",
|
||||
importc: "GetCurrentProcessId".}
|
||||
result.add($GetCurrentProcessId())
|
||||
else:
|
||||
tmpdir = getTempDir()
|
||||
return tmpdir
|
||||
result.add($getpid())
|
||||
|
|
|
|||
|
|
@ -93,11 +93,6 @@ 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)
|
||||
|
||||
|
|
@ -135,32 +130,34 @@ 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 = VersionRange(kind: verLater)
|
||||
result.kind = verLater
|
||||
of "<":
|
||||
result = VersionRange(kind: verEarlier)
|
||||
result.kind = verEarlier
|
||||
of ">=":
|
||||
result = VersionRange(kind: verEqLater)
|
||||
result.kind = verEqLater
|
||||
of "<=":
|
||||
result = VersionRange(kind: verEqEarlier)
|
||||
of "", "==":
|
||||
result = VersionRange(kind: verEq)
|
||||
result.kind = verEqEarlier
|
||||
of "":
|
||||
result.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 = VersionRange(kind: verAny)
|
||||
result.kind = verAny
|
||||
return
|
||||
|
||||
if s[0] == '#':
|
||||
result = VersionRange(kind: verSpecial)
|
||||
result.kind = verSpecial
|
||||
result.spe = s.Version
|
||||
return
|
||||
|
||||
|
|
@ -172,7 +169,7 @@ proc parseVersionRange*(s: string): VersionRange =
|
|||
of '>', '<', '=':
|
||||
op.add(s[i])
|
||||
of '&':
|
||||
result = VersionRange(kind: verIntersect)
|
||||
result.kind = verIntersect
|
||||
result.verILeft = makeRange(version, op)
|
||||
|
||||
# Parse everything after &
|
||||
|
|
@ -185,14 +182,14 @@ proc parseVersionRange*(s: string): VersionRange =
|
|||
raise newException(ParseVersionError,
|
||||
"Having more than one `&` in a version range is pointless")
|
||||
|
||||
return
|
||||
break
|
||||
|
||||
of '0'..'9', '.':
|
||||
version.add(s[i])
|
||||
|
||||
of ' ':
|
||||
# Make sure '0.9 8.03' is not allowed.
|
||||
if version != "" and i < s.len - 1:
|
||||
if version != "" and i < s.len:
|
||||
if s[i+1] in {'0'..'9', '.'}:
|
||||
raise newException(ParseVersionError,
|
||||
"Whitespace is not allowed in a version literal.")
|
||||
|
|
@ -207,10 +204,10 @@ proc toVersionRange*(ver: Version): VersionRange =
|
|||
## Converts a version to either a verEq or verSpecial VersionRange.
|
||||
new(result)
|
||||
if ver.isSpecial:
|
||||
result = VersionRange(kind: verSpecial)
|
||||
result.kind = verSpecial
|
||||
result.spe = ver
|
||||
else:
|
||||
result = VersionRange(kind: verEq)
|
||||
result.kind = verEq
|
||||
result.ver = ver
|
||||
|
||||
proc parseRequires*(req: string): PkgTuple =
|
||||
|
|
@ -266,18 +263,21 @@ proc getSimpleString*(verRange: VersionRange): string =
|
|||
result = ""
|
||||
|
||||
proc newVRAny*(): VersionRange =
|
||||
result = VersionRange(kind: verAny)
|
||||
new(result)
|
||||
result.kind = verAny
|
||||
|
||||
proc newVREarlier*(ver: string): VersionRange =
|
||||
result = VersionRange(kind: verEarlier)
|
||||
new(result)
|
||||
result.kind = verEarlier
|
||||
result.ver = newVersion(ver)
|
||||
|
||||
proc newVREq*(ver: string): VersionRange =
|
||||
result = VersionRange(kind: verEq)
|
||||
new(result)
|
||||
result.kind = verEq
|
||||
result.ver = newVersion(ver)
|
||||
|
||||
proc findLatest*(verRange: VersionRange,
|
||||
versions: OrderedTable[Version, string]): tuple[ver: Version, tag: string] =
|
||||
versions: Table[Version, string]): tuple[ver: Version, tag: string] =
|
||||
result = (newVersion(""), "")
|
||||
for ver, tag in versions:
|
||||
if not withinRange(ver, verRange): continue
|
||||
|
|
@ -291,17 +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)
|
||||
doAssert(parseVersionRange("== 3.4.2") == parseVersionRange("3.4.2"))
|
||||
#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))
|
||||
|
|
@ -315,11 +314,8 @@ when isMainModule:
|
|||
doAssert(newVersion("") < newVersion("1.0.0"))
|
||||
doAssert(newVersion("") < newVersion("0.1.0"))
|
||||
|
||||
var versions = toOrderedTable[Version, string]({
|
||||
newVersion("0.1.1"): "v0.1.1",
|
||||
newVersion("0.2.3"): "v0.2.3",
|
||||
newVersion("0.5"): "v0.5"
|
||||
})
|
||||
var versions = toTable[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")
|
||||
|
||||
|
|
@ -355,7 +351,4 @@ 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!")
|
||||
|
|
|
|||
8
tests/.gitignore
vendored
8
tests/.gitignore
vendored
|
|
@ -1,10 +1,6 @@
|
|||
tester
|
||||
/nimble-test
|
||||
/buildDir
|
||||
/binaryPackage/v1/binaryPackage
|
||||
/binaryPackage/v2/binaryPackage
|
||||
/develop/dependent/src/dependent
|
||||
/issue27/issue27
|
||||
/issue206/issue/issue206bin
|
||||
/issue289/issue289
|
||||
/issue428/nimbleDir/
|
||||
|
|
@ -17,7 +13,3 @@ tester
|
|||
/testCommand/testsPass/tests/one
|
||||
/testCommand/testsPass/tests/three
|
||||
/testCommand/testsPass/tests/two
|
||||
/nimscript/nimscript
|
||||
/packageStructure/validBinary/y
|
||||
/testCommand/testsFail/tests/t2
|
||||
/passNimFlags/passNimFlags
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Dominik Picheta"
|
||||
description = "Test package"
|
||||
license = "BSD"
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.12.1"
|
||||
|
|
@ -6,7 +6,6 @@ description = "hybrid"
|
|||
license = "MIT"
|
||||
|
||||
bin = @["hybrid"]
|
||||
installExt = @["nim"]
|
||||
|
||||
# Dependencies
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# 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
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# 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!")
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Author"
|
||||
description = "dummy"
|
||||
license = "MIT"
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.17.0"
|
||||
|
||||
bin = @["test.nim"]
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "issue678_dependency_1",
|
||||
"url": "https://github.com/nimble-test/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/nimble-test/issue678?subdir=dependency_2",
|
||||
"method": "git",
|
||||
"tags": [ "test" ],
|
||||
"description": "First level dependency of the issue678 package.",
|
||||
"license": "MIT"
|
||||
}
|
||||
]
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# 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"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# 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
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# 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"
|
||||
Binary file not shown.
|
|
@ -1,3 +0,0 @@
|
|||
when isMainModule:
|
||||
const NimblePkgVersion {.strdefine.} = "Unknown"
|
||||
echo(NimblePkgVersion)
|
||||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
version = "0.1.0"
|
||||
author = "Dominik Picheta"
|
||||
description = """Test package
|
||||
with multi-line description
|
||||
"""
|
||||
description = "Test package"
|
||||
license = "BSD"
|
||||
|
||||
bin = @["nimscript"]
|
||||
|
|
@ -26,12 +24,9 @@ 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":
|
||||
doAssert(findExe("nim").len != 0)
|
||||
echo("PKG_DIR: ", getPkgDir())
|
||||
|
||||
before hooks:
|
||||
|
|
@ -53,10 +48,4 @@ before install:
|
|||
echo("Before PkgDir: ", getPkgDir())
|
||||
|
||||
after install:
|
||||
echo("After PkgDir: ", getPkgDir())
|
||||
|
||||
before build:
|
||||
echo("Before build")
|
||||
|
||||
after build:
|
||||
echo("After build")
|
||||
echo("After PkgDir: ", getPkgDir())
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# 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"
|
||||
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Dominik Picheta"
|
||||
description = "Correctly structured package Y"
|
||||
license = "MIT"
|
||||
|
||||
bin = @["y"]
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.15.0"
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -5,7 +5,6 @@ author = "Dominik Picheta"
|
|||
description = "Incorrectly structured package Y"
|
||||
license = "MIT"
|
||||
|
||||
installExt = @["nim"]
|
||||
bin = @["y"]
|
||||
|
||||
# Dependencies
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
when not defined(passNimIsWorking): {.error: "-d:passNimIsWorking wasn't passed to the compiler"}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "SolitudeSF"
|
||||
description = "Test nimble install flag forwarding"
|
||||
license = "BSD"
|
||||
bin = @["passNimFlags"]
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.13.0"
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Dominik Picheta"
|
||||
description = "Test package"
|
||||
license = "BSD"
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.12.1"
|
||||
|
||||
let
|
||||
callNimble = getEnv("NIMBLE_TEST_BINARY_PATH")
|
||||
doAssert callNimble.len != 0, "NIMBLE_TEST_BINARY_PATH not set"
|
||||
|
||||
task recurse, "Level 1":
|
||||
echo 1
|
||||
exec callNimble & " recurse2"
|
||||
|
||||
task recurse2, "Level 2":
|
||||
echo 2
|
||||
exec callNimble & " recurse3"
|
||||
|
||||
task recurse3, "Level 3":
|
||||
echo 3
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Dominik Picheta"
|
||||
description = "A new awesome nimble package"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["run"]
|
||||
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 0.19.0"
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import os
|
||||
|
||||
when isMainModule:
|
||||
echo("Testing `nimble run`: ", commandLineParams())
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
version = "0.1.0"
|
||||
author = "John Doe"
|
||||
description = "Nimble Test"
|
||||
license = "BSD"
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
import os
|
||||
echo(getCurrentDir())
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
proc myFunc*() =
|
||||
echo "Executing my func"
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
version = "0.1.0"
|
||||
author = "John Doe"
|
||||
description = "Nimble Test"
|
||||
license = "BSD"
|
||||
|
|
@ -1 +0,0 @@
|
|||
echo "Should be ignored"
|
||||
|
|
@ -1 +0,0 @@
|
|||
echo "Should be ignored"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import testing123, unittest
|
||||
|
||||
test "can accept":
|
||||
echo "First test"
|
||||
myFunc()
|
||||
|
||||
|
||||
401
tests/tester.nim
401
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, strformat
|
||||
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
|
||||
|
|
@ -10,10 +10,6 @@ var rootDir = getCurrentDir().parentDir()
|
|||
var nimblePath = rootDir / "src" / addFileExt("nimble", ExeExt)
|
||||
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)
|
||||
|
|
@ -36,23 +32,14 @@ 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 = quotedArgs.map((x: string) => x.quoteShell)
|
||||
quotedArgs.add("--nimbleDir:" & installDir)
|
||||
quotedArgs = quotedArgs.map((x: string) => ("\"" & x & "\""))
|
||||
|
||||
let path {.used.} = getCurrentDir().parentDir() / "src"
|
||||
|
||||
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
|
||||
let path = getCurrentDir().parentDir() / "src"
|
||||
|
||||
let cmd = "PATH=" & path & ":$PATH " & quotedArgs.join(" ")
|
||||
result = execCmdEx(cmd)
|
||||
checkpoint(cmd)
|
||||
checkpoint(result.output)
|
||||
|
||||
proc execNimbleYes(args: varargs[string]): tuple[output: string, exitCode: int]=
|
||||
|
|
@ -76,56 +63,6 @@ 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 "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")
|
||||
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 "tasks can be called recursively":
|
||||
cd "recursive":
|
||||
check execNimble("recurse").exitCode == QuitSuccess
|
||||
|
||||
test "picks #head when looking for packages":
|
||||
cd "versionClashes" / "aporiaScenario":
|
||||
let (output, exitCode) = execNimble("install", "-y", "--verbose")
|
||||
|
|
@ -151,12 +88,12 @@ 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", "softened"]:
|
||||
for package in ["a", "b", "c"]:
|
||||
cd "packageStructure/" & package:
|
||||
let (output, exitCode) = execNimble(["install", "-y"])
|
||||
check exitCode == QuitSuccess
|
||||
let lines = output.strip.processOutput()
|
||||
check(not lines.hasLineStartingWith("Warning:"))
|
||||
check(not inLines(lines, "warning"))
|
||||
|
||||
# Test that warnings are produced for the incorrectly structured packages.
|
||||
for package in ["x", "y", "z"]:
|
||||
|
|
@ -167,22 +104,19 @@ test "can validate package structure (#144)":
|
|||
checkpoint(output)
|
||||
case package
|
||||
of "x":
|
||||
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.")
|
||||
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 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.")
|
||||
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 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.")
|
||||
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
|
||||
|
||||
|
|
@ -275,7 +209,7 @@ test "can refresh with local package list":
|
|||
[PackageList]
|
||||
name = "local"
|
||||
path = "$1"
|
||||
""".unindent % (getCurrentDir() / "issue368" / "packages.json").replace("\\", "\\\\"))
|
||||
""".unindent % (getCurrentDir() / "issue368" / "packages.json"))
|
||||
let (output, exitCode) = execNimble(["refresh", "--verbose"])
|
||||
let lines = output.strip.processOutput()
|
||||
check inLines(lines, "config file at")
|
||||
|
|
@ -318,20 +252,11 @@ 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[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")
|
||||
check lines[^1].endsWith("tests/nimbleDir/pkgs/nimscript-0.1.0")
|
||||
|
||||
test "can execute nimscript tasks":
|
||||
cd "nimscript":
|
||||
|
|
@ -368,8 +293,7 @@ suite "nimscript":
|
|||
test "can list nimscript tasks":
|
||||
cd "nimscript":
|
||||
let (output, exitCode) = execNimble("tasks")
|
||||
check "work".normalize in output.normalize
|
||||
check "test description".normalize in output.normalize
|
||||
check "work test description".normalize in output.normalize
|
||||
check exitCode == QuitSuccess
|
||||
|
||||
test "can use pre/post hooks":
|
||||
|
|
@ -488,12 +412,9 @@ test "issue #349":
|
|||
check code == QuitFailure
|
||||
check inLines(msg,
|
||||
"\"$1\" is an invalid package name: reserved name" % name)
|
||||
try:
|
||||
removeFile(name.changeFileExt("nimble"))
|
||||
removeDir("src")
|
||||
removeDir("tests")
|
||||
except OSError:
|
||||
discard
|
||||
removeFile(name.changeFileExt("nimble"))
|
||||
removeDir("src")
|
||||
removeDir("tests")
|
||||
|
||||
for reserved in reservedNames:
|
||||
checkName(reserved.toUpperAscii())
|
||||
|
|
@ -517,7 +438,8 @@ test "can uninstall":
|
|||
|
||||
let ls = outp.strip.processOutput()
|
||||
check exitCode != QuitSuccess
|
||||
check inLines(ls, "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends")
|
||||
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
|
||||
|
|
@ -599,15 +521,9 @@ 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(cmd)
|
||||
execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt))
|
||||
check exitCode == QuitSuccess
|
||||
check output.strip() == "v2"
|
||||
|
||||
|
|
@ -615,7 +531,7 @@ suite "can handle two binary versions":
|
|||
check execNimble("remove", "binaryPackage@2.0", "-y").exitCode==QuitSuccess
|
||||
|
||||
let (output, exitCode) =
|
||||
execCmdEx(cmd)
|
||||
execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt))
|
||||
check exitCode == QuitSuccess
|
||||
check output.strip() == "v1"
|
||||
|
||||
|
|
@ -623,7 +539,7 @@ suite "can handle two binary versions":
|
|||
check execNimble("remove", "binaryPackage@1.0", "-y").exitCode==QuitSuccess
|
||||
|
||||
let (output, exitCode) =
|
||||
execCmdEx(cmd)
|
||||
execCmdEx(installDir / "bin" / "binaryPackage".addFileExt(ExeExt))
|
||||
check exitCode == QuitSuccess
|
||||
check output.strip() == "v2"
|
||||
|
||||
|
|
@ -636,12 +552,6 @@ 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":
|
||||
|
|
@ -653,27 +563,6 @@ 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")
|
||||
|
|
@ -705,8 +594,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":
|
||||
|
|
@ -720,11 +609,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
|
||||
|
|
@ -754,20 +643,10 @@ 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 (_, exitCode) = execNimble("install", "-y")
|
||||
check exitCode == QuitSuccess
|
||||
let (output, _) = execNimble("path", "srcdirtest")
|
||||
check output.strip() == installDir / "pkgs" / "srcdirtest-1.0"
|
||||
|
||||
suite "test command":
|
||||
test "Runs passing unit tests":
|
||||
cd "testCommand/testsPass":
|
||||
|
|
@ -792,19 +671,6 @@ 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")
|
||||
|
||||
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":
|
||||
|
|
@ -847,199 +713,4 @@ 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
|
||||
|
||||
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
|
||||
|
||||
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":
|
||||
const Src = "echo \"OK\""
|
||||
writeFile("src/issue581.nim", Src)
|
||||
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
|
||||
|
||||
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
|
||||
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")
|
||||
|
||||
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 '$1' is not defined in 'run' package." %
|
||||
"blahblah".changeFileExt(ExeExt))
|
||||
|
||||
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$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")
|
||||
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 "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 = [
|
||||
"../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.splitFile.name} {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)
|
||||
|
||||
removeDir(buildDir)
|
||||
|
||||
var linesWithWarningsCount: uint = 0
|
||||
for file in filesToBuild:
|
||||
let (output, exitCode) = execBuild(file)
|
||||
check exitCode == QuitSuccess
|
||||
linesWithWarningsCount += checkOutput(output)
|
||||
check linesWithWarningsCount == 0
|
||||
check execNimble(args).exitCode == QuitSuccess
|
||||
Loading…
Add table
Add a link
Reference in a new issue