diff --git a/.gitignore b/.gitignore
index bac71d6..bd1ebed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,29 +6,4 @@ nimcache/
# Absolute paths
/src/babel
/src/nimble
-
-# executables from test and build
-/nimble
-src/nimblepkg/cli
-src/nimblepkg/packageinfo
-src/nimblepkg/packageparser
-src/nimblepkg/reversedeps
-src/nimblepkg/version
-src/nimblepkg/download
-
-# Windows executables
-*.exe
-*.dll
-
-# VCC compiler and linker artifacts
-*.ilk
-*.pdb
-
-# Editors and IDEs project files and folders
-.vscode
-
-# VCS artifacts
-*.orig
-
-# Test procedure artifacts
-nimble_*.nims
+/tests/tester
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index f1ff69e..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-os:
- - windows
- - linux
- - osx
-
-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/.choosenim"
-
-install:
- - curl https://gist.github.com/genotrance/fb53504a4fba88bc5201d3783df5c522/raw/travis.sh -LsSf -o travis.sh
- - source travis.sh
-
-script:
- - cd tests
- - nim c -r tester
- - cd ..
- - ./src/nimble install -y
-
-notifications:
- irc: "chat.freenode.net#nimbuild"
diff --git a/changelog.markdown b/changelog.markdown
index 92f1d31..f4262b1 100644
--- a/changelog.markdown
+++ b/changelog.markdown
@@ -1,383 +1,4 @@
-
-[comment]: # (Before releasing, make sure to follow the steps in https://github.com/nim-lang/nimble/wiki/Releasing-a-new-version)
-
-# 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.
-This release fixes many
-issues, with most being fixed by our brilliant contributors. Thanks a lot
-everyone!
-
-One big new feature is the new support for multiple Nimble packages in a single
-Git/Hg repository. You can now specify ``?subdir=
`` at the end of your
-repo's URL and Nimble will know to look in ```` for your package.
-
-* **Implemented support for multi-package repos.** See
- [#421](https://github.com/nim-lang/nimble/issues/421) for the relevant issue.
-* **Better error message when the user has an outdated stdlib version that confuses Nimble**
-* **The validity of a Nimble package can now be checked using the new ``check`` command**
-* Nimble no longer silently ignores an erroneous '@' in for example
- ``nimble install compiler@``.
-* Issues with the ``nimble path`` command have been fixed.
-* The ``nimble publish`` command has been improved and stabilised.
-* Messages for the ``NIM_LIB_PREFIX`` env var have been improved.
-* ``before install`` is now called when packages are installed by their name.
- See [#280](https://github.com/nim-lang/nimble/issues/280).
-* Fixed issue with ``nimble init``. See [#446](https://github.com/nim-lang/nimble/issues/446).
-* Nimble now rejects [reserved names on Windows](https://github.com/nim-lang/nimble/commit/74856a87084b73451254555b2c20ad932cf84270).
-* The ``NIMBLE_DIR`` environment variable is now supported, in addition to the
- command line flag and config setting.
-* The ``init`` command has been improved significantly.
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.8...v0.8.10
-
-## 0.8.8 - 03/09/2017
-
-This is a relatively big release containing 57 commits, with multiple new
-features and many bug fixes.
-
-* **Implemented the `develop` command.** See
- [readme](https://github.com/nim-lang/nimble#nimble-develop) for details.
-* **Implemented a default `test` task** for packages that don't define it.
-* **Lowered the memory consumption** in cases where a package contained many files.
-* Nimble now accepts .nimble symlinks.
-* Locally stored package list files can now be specified in the Nimble config.
-* Fixed branch checkout and handling of branch names with dashes.
-* Improved URL detection in ``publish`` feature.
-* Fixed many issues related to binary management. Packages are now resymlinked
- when an newer version is removed.
- ([#331](https://github.com/nim-lang/nimble/issues/331))
-* Fixed issues with CLI arg passing to the Nim compiler.
- ([#351](https://github.com/nim-lang/nimble/issues/351))
-* Improved performance of ``list -i`` command.
-* Fixed issue where warnings weren't suppressed for some commands.
- ([#290](https://github.com/nim-lang/nimble/issues/290))
-* Special versions other than `#head` are no longer considered to be newest.
-* Improves the reverse dependency lookup by cross checking it with the
- installed list of packages.
- ([#287](https://github.com/nim-lang/nimble/issues/287))
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.6...v0.8.8
-
-## 0.8.6 - 05/05/2017
-
-Yet another point release which includes various bug fixes and improvements.
-
-* Improves heuristic for finding Nim standard library to support choosenim
- installations and adds ability to override it via ``NIM_LIB_PREFIX``
- environment variable.
-* Implement ``--noColor`` option to remove color from the output.
-* Fixes bug when ``srcDir`` contains trailing slash.
-* Fixes failure when ``-d`` flag is passed to ``c`` command.
-* Show raw output for certain commands.
-* GitHub API token can now be specified via the ``NIMBLE_GITHUB_API_TOKEN``
- environment variable.
-* GitHub API token is now stored in ``~/.nimble/api_token`` so that it
- doesn't need to be specified each time.
-* Fixes multiple flags not being passed in Nimble task.
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.4...v0.8.6
-
-## 0.8.4 - 29/01/2017
-
-Another bug fix release which resolves problems related to stale nimscriptapi
-files in /tmp/, no compilation output when ``nimble build`` fails, and issues
-with the new package validation on Windows.
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.8.2...v0.8.4
-
-## 0.8.2 - 08/01/2017
-
-This is a small bug fix release which resolves problems with the installation
-of Aporia (and likely other Nimble packages).
-
-## 0.8.0 - 05/01/2017
-
-This is a large release containing multiple new features and many bug fixes.
-
-* Implemented a completely new output system.
- * Supports different message types and priorities. Each is differently
- encoded using a color and a brightness.
- * The amount of messages shown can be changed by using the new ``--verbose``
- and ``--debug`` flags, by default only high priority messages are shown.
- * Duplicate warnings are filtered out to prevent too much noise.
-* Package namespaces are now validated. You will see a warning whenever an
- incorrectly namespaced package is read by Nimble, this can occur either
- during installation or when the installed package database is being loaded.
- The namespacing rules are described in Nimble's
- [readme](https://github.com/nim-lang/nimble#libraries).
- **Consider these warnings to be unstable, if you see something that you
- think is incorrect please report it**.
-* Special version dependencies are now installed into a directory with that
- special version in its name. For example, ``compiler@#head`` will be installed
- into ``~/.nimble/pkgs/compiler-#head``. This reduces the amount of redundant
- installs. See [#88](https://github.com/nim-lang/nimble/issues/88) for
- more information.
-* External dependencies can now be specified in .nimble files. Nimble doesn't
- install these, but does instruct the user on how they can be installed.
- More information about this feature can be found in the
- [readme](https://github.com/nim-lang/nimble#external-dependencies).
-* Nimble now supports package aliases in the packages.json files.
-* Fixed regression that caused transitive dependencies to not be installed.
-* Fixed problem with ``install`` command when a ``src`` directory is present
- in the current directory.
-* Improved quoting of process execution arguments.
-* Many improvements to custom ``--nimbleDir`` handling. All commands should now
- support it correctly.
-* Running ``nimble -v`` will no longer read the Nimble config before displaying
- the version.
-* Refresh command now supports a package list name as argument.
-* Fixes issues with symlinks not being removed correctly.
-* Changed the way the ``dump`` command locates the .nimble file.
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.10...v0.8.0
-
-Full list of issues which have been closed: https://github.com/nim-lang/nimble/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-10-09+..+2017-01-05%22+
-
-## 0.7.10 - 09/10/2016
-
-This release includes multiple bug fixes.
-
-* Reverted patch that breaks binary stubs in Git Bash on Windows.
-* The ``nimscriptapi.nim`` file is now statically compiled into the binary.
- This should fix the "could not find nimscriptapi.nim" errors. The file can
- still be overriden by placing a file named ``nimscriptapi.nim`` inside a
- ``nimblepkg`` directory that is placed alongside the Nimble binary, or
- by a ``nimscriptapi.nim`` file inside ``~/.nimble/pkgs/nimble-ver/nimblepkg/``.
- For more information see the
- [code that looks for this file](https://github.com/nim-lang/nimble/blob/v0.7.10/src/nimblepkg/nimscriptsupport.nim#L176).
-* Nim files can now be imported in .nimble nimscript files. (Issue [#186](https://github.com/nim-lang/nimble/issues/186))
-* Requiring a specific git commit hash no longer fails. (Issue [#129](https://github.com/nim-lang/nimble/issues/129))
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.8...v0.7.10
-
-## 0.7.8 - 28/09/2016
-
-This is a hotfix release which fixes crashes when Nimble (or Nim) is installed
-to ``C:\Program Files`` or other paths with spaces in them.
-
-## 0.7.6 - 26/09/2016
-
-This is a small release designed to coincide with the release of Nim 0.15.0.
-
-* Fixes ``--depsOnly`` flag ([commit](https://github.com/nim-lang/nimble/commit/f6a19b54e47c7c99f2b473fc02915277273f8c41))
-* Fixes compilation on 0.15.0.
-* Fixes #239.
-* Fixes #215.
-* VCS information is now stored in the Nimble package metadata.
-
-## 0.7.4 - 06/06/2016
-
-This release is mainly a bug fix release. The installation problems
-introduced by v0.7.0 should now be fixed.
-
-* Fixed symlink install issue
- (Thank you [@yglukhov](https://github.com/yglukhov)).
-* Fixed permission issue when installing packages
- (Thank you [@SSPkrolik](https://github.com/SSPkrolik)).
-* Work around for issue #204.
- (Thank you [@Jeff-Ciesielski](https://github.com/Jeff-Ciesielski)).
-* Fixed FD leak.
- (Thank you [@yglukhov](https://github.com/yglukhov)).
-* Implemented the ``--depsOnly`` option for the ``install`` command.
-* Various fixes to installation/nimscript support problems introduced by
-v0.7.0.
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.7.2...v0.7.4
-
-## 0.7.2 - 11/02/2016
-
-This is a hotfix release which alleviates problems when building Nimble.
-
-See Issue [#203](https://github.com/nim-lang/nimble/issues/203) for more
-information.
-
-## 0.7.0 - 30/12/2015
-
-This is a major release.
-Significant changes include NimScript support, configurable package list
-URLs, a new ``publish`` command, the removal of the dependency on
-OpenSSL, and proxy support. More detailed list of changes follows:
-
-* Fixed ``chcp`` on Windows XP and Windows Vista
- (Thank you [@vegansk](https://github.com/vegansk)).
-* Fixed incorrect command line processing
- (Issue [#151](https://github.com/nim-lang/nimble/issues/151))
-* Merged ``developers.markdown`` back into ``readme.markdown``
- (Issue [#132](https://github.com/nim-lang/nimble/issues/132))
-* Removed advertising clause from license
- (Issue [#153](https://github.com/nim-lang/nimble/issues/153))
-* Implemented ``publish`` command
- (Thank you for taking the initiative [@Araq](https://github.com/Araq))
-* Implemented NimScript support. Nimble now import a portion of the Nim
- compiler source code for this.
- (Thank you for taking the initiative [@Araq](https://github.com/Araq))
-* Fixes incorrect logic for finding the Nim executable
- (Issue [#125](https://github.com/nim-lang/nimble/issues/125)).
-* Renamed the ``update`` command to ``refresh``. **The ``update`` command will
- mean something else soon!**
- (Issue [#158](https://github.com/nim-lang/nimble/issues/158))
-* Improvements to the ``init`` command.
- (Issue [#96](https://github.com/nim-lang/nimble/issues/96))
-* Package names must now officially be valid Nim identifiers. Package's
- with dashes in particular will become invalid in the next version.
- Warnings are shown now but the **next version will show an error**.
- (Issue [#126](https://github.com/nim-lang/nimble/issues/126))
-* Added error message when no build targets are present.
- (Issue [#108](https://github.com/nim-lang/nimble/issues/108))
-* Implemented configurable package lists. Including fallback URLs
- (Issue [#75](https://github.com/nim-lang/nimble/issues/75)).
-* Removed the OpenSSL dependency
- (Commit [ec96ee7](https://github.com/nim-lang/nimble/commit/ec96ee7709f0f8bd323aa1ac5ed4c491c4bf23be))
-* Implemented proxy support. This can be configured using the ``http_proxy``/
- ``https_proxy`` environment variables or Nimble's configuration
- (Issue [#86](https://github.com/nim-lang/nimble/issues/86)).
-* Fixed issues with reverse dependency storage
- (Issue [#113](https://github.com/nim-lang/nimble/issues/113) and
- [#168](https://github.com/nim-lang/nimble/issues/168)).
-
-----
-
-Full changelog: https://github.com/nim-lang/nimble/compare/v0.6.2...v0.7.0
-
-## 0.6.4 - 30/12/2015
-
-This is a hotfix release fixing compilation with Nim 0.12.0.
-
-See Issue [#180](https://github.com/nim-lang/nimble/issues/180) for more
-info.
+# Babel changelog
## 0.6.2 - 19/06/2015
diff --git a/developers.markdown b/developers.markdown
new file mode 100644
index 0000000..95e6fa0
--- /dev/null
+++ b/developers.markdown
@@ -0,0 +1,236 @@
+# How to Create and Publish Packages
+
+This file contains information mostly meant for developers willing to produce
+[Nim](http://nim-lang.org) modules and submit them to the
+[nim-lang/packages repository](https://github.com/nim-lang/packages). End
+user documentation is provided in the [readme.markdown file](readme.markdown).
+
+## Packages
+
+A Nimble package is defined by an ini-like formatted file with the ``.nimble``
+extension (this document uses the term ".nimble file" to refer to them). The
+.nimble file should be named after the package it describes, i.e. a package
+named "foobar" should have a corresponding ``foobar.nimble`` file.
+
+These files specify information about the package including its name, author,
+license, dependencies and more. Without one Nimble is not able to install
+a package. A bare minimum .nimble file follows:
+
+```ini
+[Package]
+name = "ProjectName"
+version = "0.1.0"
+author = "Your Name"
+description = "Example .nimble file."
+license = "MIT"
+
+[Deps]
+Requires: "nim >= 0.10.0"
+```
+
+You may omit the dependencies entirely, but specifying the lowest version
+of the Nim compiler required is recommended.
+
+Nimble currently supports installation of packages from a local directory, a
+git repository and a mercurial repository. The .nimble file must be present in
+the root of the directory or repository being installed.
+
+### Libraries
+
+Library packages are likely the most popular form of Nimble packages. They are
+meant to be used by other library packages or the ultimate binary packages.
+
+When nimble installs a library it will copy all the files in the package
+into ``$nimbleDir/pkgs/pkgname-ver``. It's up to the package creator to make sure
+that the package directory layout is correct, this is so that users of the
+package can correctly import the package.
+
+By convention, it is suggested that the layout be as follows. The directory
+layout is determined by the nature of your package, that is, whether your
+package exposes only one module or multiple modules.
+
+If your package exposes only a single module, then that module should be
+present in the root directory (the directory with the .nimble file) of your git
+repository, it is recommended that in this case you name that module whatever
+your package's name is. A good example of this is the
+[jester](https://github.com/dom96/jester) package which exposes the ``jester``
+module. In this case the jester package is imported with ``import jester``.
+
+If your package exposes multiple modules then the modules should be in a
+``PackageName`` directory. This will allow for a certain measure of isolation
+from other packages which expose modules with the same names. In this case
+the package's modules will be imported with ``import PackageName/module``.
+
+You are free to combine the two approaches described.
+
+In regards to modules which you do **not** wish to be exposed. You should place
+them in a ``PackageName/private`` directory. Your modules may then import these
+private modules with ``import PackageName/private/module``. This directory
+structure may be enforced in the future.
+
+All files and folders in the directory of where the .nimble file resides will be
+copied as-is, you can however skip some directories or files by setting
+the ``SkipDirs``, ``SkipFiles`` or ``SkipExt`` options in your .nimble file.
+Directories and files can also be specified on a *whitelist* basis, if you
+specify either of ``InstallDirs``, ``InstallFiles`` or ``InstallExt`` then
+Nimble will **only** install the files specified.
+
+### Binary packages
+
+These are application packages which require building prior to installation.
+A package is automatically a binary package as soon as it sets at least one
+``bin`` value, like so:
+
+```ini
+bin = "main"
+```
+
+In this case when ``nimble install`` is invoked, nimble will build the ``main.nim``
+file, copy it into ``$nimbleDir/pkgs/pkgname-ver/`` and subsequently create a
+symlink to the binary in ``$nimbleDir/bin/``. On Windows a stub .bat file is
+created instead.
+
+Other files will be copied in the same way as they are for library packages.
+
+Binary packages should not install .nim files so you should include
+``SkipExt = "nim"`` in your .nimble file, unless you intend for your package to
+be a binary/library combo which is fine.
+
+Dependencies are automatically installed before building. Before publishing your
+package you should ensure that the dependencies you specified are correct.
+You can do this by running ``nimble build`` or ``nimble install`` in the directory
+of your package.
+
+### Hybrids
+
+One thing to note about library and binary package hybrids is that your binary
+will most likely share the name of the package. This will mean that you will
+not be able to put your .nim files in a ``pkgname`` directory. The current
+convention to get around this problem is to append ``pkg`` to the name as is
+done for nimble.
+
+## Dependencies
+
+Dependencies are specified under the ``[Deps]`` section in a nimble file.
+The ``requires`` key field is used to specify them. For example:
+
+```ini
+[Deps]
+Requires: "nim >= 0.10.0, jester > 0.1 & <= 0.5"
+```
+
+Dependency lists support version ranges. These versions may either be a concrete
+version like ``0.1``, or they may contain any of the less-than (``<``),
+greater-than (``>``), less-than-or-equal-to (``<=``) and greater-than-or-equal-to
+(``>=``). Two version ranges may be combined using the ``&`` operator for example:
+``> 0.2 & < 1.0`` which will install a package with the version greater than 0.2
+and less than 1.0.
+
+Specifying a concrete version as a dependency is not a good idea because your
+package may end up depending on two different versions of the same package.
+If this happens Nimble will refuse to install the package. Similarly you should
+not specify an upper-bound as this can lead to a similar issue.
+
+In addition to versions you may also specify git/hg tags, branches and commits.
+These have to be concrete however. This is done with the ``#`` character,
+for example: ``jester#head``. Which will make your package depend on the
+latest commit of Jester.
+
+### Nim compiler
+
+The Nim compiler cannot read .nimble files. Its knowledge of Nimble is
+limited to the ``nimblePaths`` feature which allows it to use packages installed
+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.
+
+When Nimble builds your package it actually executes the Nim compiler.
+It resolves the dependencies and feeds the path of each package to
+the compiler so that it knows precisely which version to use.
+
+This means that you can safely compile using the compiler when developing your
+software, but you should use nimble to build the package before publishing it
+to ensure that the dependencies you specified are correct.
+
+## Versions
+
+Versions of cloned packages via git or mercurial are determined through the
+repository's *tags*.
+
+When installing a package which needs to be downloaded, after the download is
+complete and if the package is distributed through a VCS, nimble will check the
+cloned repository's tags list. If no tags exist, nimble will simply install the
+HEAD (or tip in mercurial) of the repository. If tags exist, nimble will attempt
+to look for tags which resemble versions (e.g. v0.1) and will then find the
+latest version out of the available tags, once it does so it will install the
+package after checking out the latest version.
+
+You can force the installation of the HEAD of the repository by specifying
+``#head`` after the package name in your dependency list.
+
+# Submitting your package to the package list.
+
+Nimble's packages list is stored on github and everyone is encouraged to add
+their own packages to it! Take a look at
+[nim-lang/packages](https://github.com/nim-lang/packages) to learn more.
+
+# .nimble reference
+
+## [Package]
+
+### Required
+
+* ``name`` - The name of the package.
+* ``version`` - The *current* version of this package. This should be incremented
+ **after** tagging the current version using ``git tag`` or ``hg tag``.
+* ``author`` - The name of the author of this package.
+* ``description`` - A string describing the package.
+* ``license`` - The name of the license in which this package is licensed under.
+
+### Optional
+
+* ``SkipDirs`` - A list of directory names which should be skipped during
+ installation, separated by commas.
+* ``SkipFiles`` - A list of file names which should be skipped during
+ installation, separated by commas.
+* ``SkipExt`` - A list of file extensions which should be skipped during
+ installation, the extensions should be specified without a leading ``.`` and
+ should be separated by commas.
+* ``InstallDirs`` - A list of directories which should exclusively be installed,
+ if this option is specified nothing else will be installed except the dirs
+ listed here, the files listed in ``InstallFiles``, the files which share the
+ extensions listed in ``InstallExt``, the .nimble file and the binary
+ (if ``bin`` is specified). Separated by commas.
+* ``InstallFiles`` - A list of files which should be exclusively installed,
+ this complements ``InstallDirs`` and ``InstallExt``. Only the files listed
+ here, directories listed in ``InstallDirs``, files which share the extension
+ listed in ``InstallExt``, the .nimble file and the binary (if ``bin`` is
+ specified) will be installed. Separated by commas.
+* ``InstallExt`` - A list of file extensions which should be exclusively
+ installed, this complements ``InstallDirs`` and ``InstallFiles``.
+ Separated by commas.
+* ``srcDir`` - Specifies the directory which contains the .nim source files.
+ **Default**: The directory in which the .nimble file resides; i.e. root dir of
+ the package.
+* ``binDir`` - Specifies the directory where ``nimble build`` will output
+ binaries.
+ **Default**: The directory in which the .nimble file resides; i.e.
+ root dir of the package.
+* ``bin`` - A list of files which should be built separated by commas with
+ no file extension required. This option turns your package into a *binary
+ package*, nimble will build the files specified and install them appropriately.
+* ``backend`` - Specifies the backend which will be used to build the files
+ listed in ``bin``. Possible values include: ``c``, ``cc``, ``cpp``, ``objc``,
+ ``js``.
+ **Default**: c
+
+## [Deps]/[Dependencies]
+
+### Optional
+
+* ``requires`` - Specified a list of package names with an optional version
+ range separated by commas.
+ **Example**: ``nim >= 0.10.0, jester``; with this value your package will
+ depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``.
+
+
diff --git a/license.txt b/license.txt
index be6ce3c..7767636 100644
--- a/license.txt
+++ b/license.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2015, Dominik Picheta
+Copyright (c) 2013, Dominik Picheta
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -8,7 +8,10 @@ modification, are permitted provided that the following conditions are met:
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
-3. Neither the name of Nimble nor the
+3. All advertising materials mentioning features or use of this software
+ must display the following acknowledgement:
+ This product includes software developed by Dominik Picheta.
+4. Neither the name of Babel nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
@@ -21,4 +24,4 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/nimble.bash-completion b/nimble.bash-completion
deleted file mode 100644
index 45eef01..0000000
--- a/nimble.bash-completion
+++ /dev/null
@@ -1,46 +0,0 @@
-# vim: filetype=sh
-
-_nimble()
-{
- local cur=${COMP_WORDS[COMP_CWORD]}
- local prev=${COMP_WORDS[COMP_CWORD-1]}
- COMPREPLY=()
-
- if declare -F _init_completions >/dev/null 2>&1; then
- _init_completion || return
- fi
-
- case "$prev" in
- init|update|refresh|publish|search|build)
- # no needed or available completion
- ;;
- c|cc|js)
- _filedir '@(nim)'
- ;;
- install)
- COMPREPLY=( $( nimble list 2> /dev/null | grep "^$cur" | grep -v '^ ' | tr -d ':') )
- ;;
- path)
- COMPREPLY=( $( nimble list -i 2> /dev/null | cut -d' ' -f1 | grep "^$cur" ) )
- ;;
- uninstall)
- COMPREPLY=( $( nimble list -i 2> /dev/null | awk -F'( |\\[|\\])' '{ f=4; while($f) { l=length($f); if(substr($f, l, l)==",") { $f=substr($f, 0, l-1) }; print $1 "@" $f; f++; }}' | sort -f | grep "^$cur" ) )
- ;;
- list)
- COMPREPLY=( $( compgen -W '--ver -i --installed' -- $cur ) )
- ;;
- *)
- # no $prev: suggest commands or flags
- if [[ "$cur" == -* ]]; then
- kw="-h -v -y -n --reject --version --accept --ver --help"
- else
- kw="install init publish uninstall build c cc js refresh search list path"
- fi
- COMPREPLY=( $( compgen -W "${kw}" -- $cur ) )
- ;;
- esac;
-
- return 0
-}
-
-complete -F _nimble nimble
diff --git a/nimble.nimble b/nimble.nimble
index 6cd7e9e..60a6fcf 100644
--- a/nimble.nimble
+++ b/nimble.nimble
@@ -1,25 +1,12 @@
-# Package
-
-version = "0.11.0"
+[Package]
+name = "nimble"
+version = "0.6.2"
author = "Dominik Picheta"
description = "Nim package manager."
license = "BSD"
-bin = @["nimble"]
+bin = "nimble"
srcDir = "src"
-installExt = @["nim"]
-# Dependencies
-
-requires "nim >= 0.13.0"
-
-when defined(nimdistros):
- import distros
- if detectOs(Ubuntu):
- foreignDep "libssl-dev"
- else:
- foreignDep "openssl"
-
-task test, "Run the Nimble tester!":
- withDir "tests":
- exec "nim c -r tester"
+[Deps]
+Requires: "nim >= 0.11.2"
diff --git a/nimble.zsh-completion b/nimble.zsh-completion
deleted file mode 100644
index 0d59b59..0000000
--- a/nimble.zsh-completion
+++ /dev/null
@@ -1,51 +0,0 @@
-#compdef nimble
-
-_nimble() {
- local line
-
- _arguments -C \
- '1: :(install init publish uninstall build c cc js doc doc2 refresh search list tasks path dump develop)' \
- '*::options:->options' \
- '(--version)--version[show version]' \
- '(--help)--help[show help]' \
- '(-)--help[display help information]' \
- '(-)--version[display version information]' \
- '(-y --accept)'{-y,--accept}'[accept all interactive prompts]' \
- {-n,--reject}'[reject all interactive prompts]' \
- '--ver[Query remote server for package version information when searching or listing packages]' \
- '--nimbleDir dirname[Set the Nimble directory]' \
- '(-d --depsOnly)'{-d,--depsOnly}'[Install only dependencies]'
-
- if [ $#line -eq 0 ]; then
- # if the command line is empty and "nimble tasks" is successfull, add custom tasks
- tasks=$(nimble tasks)
- if [ $? -eq 0 ]; then
- compadd - $(echo $tasks | cut -f1 -d" " | tr '\n' ' ')
- fi
- fi
-
- case $line[1] in
- install)
- _nimble_installable_packages
- ;;
- uninstall|path|dump)
- _nimble_installed_packages
- ;;
- init|publish|build|refresh|search|tasks)
- (( ret )) && _message 'no more arguments'
- ;;
- *)
- (( ret )) && _message 'no more arguments'
- ;;
- esac
-}
-
-function _nimble_installable_packages {
- compadd - $(nimble list 2> /dev/null | grep -v '^ ' | tr -d ':')
-}
-
-function _nimble_installed_packages {
- compadd - $(nimble list -i 2> /dev/null | grep ']$' | cut -d' ' -f1)
-}
-
-_nimble "$@"
diff --git a/readme.markdown b/readme.markdown
index 89f7a22..ec2c155 100644
--- a/readme.markdown
+++ b/readme.markdown
@@ -1,150 +1,107 @@
-# Nimble [](https://travis-ci.org/nim-lang/nimble)
+# Nimble
Nimble is a *beta*-grade *package manager* for the [Nim programming
-language](https://nim-lang.org).
+language](http://nim-lang.org).
-Interested in learning **how to create a package**? Skip directly to that section
-[here](#creating-packages).
-
-## Contents
-
-- [Requirements](#requirements)
-- [Installation](#installation)
-- [Nimble usage](#nimble-usage)
- - [nimble refresh](#nimble-refresh)
- - [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)
- - [nimble path](#nimble-path)
- - [nimble init](#nimble-init)
- - [nimble publish](#nimble-publish)
- - [nimble tasks](#nimble-tasks)
- - [nimble dump](#nimble-dump)
-- [Configuration](#configuration)
-- [Creating Packages](#creating-packages)
- - [Project structure](#project-structure)
- - [Tests](#tests)
- - [Libraries](#libraries)
- - [Binary packages](#binary-packages)
- - [Hybrids](#hybrids)
- - [Dependencies](#dependencies)
- - [External dependencies](#external-dependencies)
- - [Nim compiler](#nim-compiler)
- - [Versions](#versions)
- - [Releasing a new version](#releasing-a-new-version)
-- [Publishing packages](#publishing-packages)
-- [.nimble reference](#nimble-reference)
- - [[Package]](#package)
- - [Required](#required)
- - [Optional](#optional)
- - [[Deps]/[Dependencies]](#depsdependencies)
- - [Optional](#optional)
-- [Troubleshooting](#troubleshooting)
-- [Nimble's folder structure and packages](#nimbles-folder-structure-and-packages)
-- [Repository information](#repository-information)
-- [Contribution](#contribution)
-- [About](#about)
-
-## Requirements
-
-Nimble has some runtime dependencies on external tools, these tools are used to
-download Nimble packages. For instance, if a package is hosted on
-[GitHub](https://github.com), you need to have [git](https://www.git-scm.com)
-installed and added to your environment ``PATH``. Same goes for
-[Mercurial](http://mercurial.selenic.com) repositories on
-[Bitbucket](https://bitbucket.org). Nimble packages are typically hosted in Git
-repositories so you may be able to get away without installing Mercurial.
-
-**Warning:** Ensure that you have a fairly recent version of Git installed.
-If the version is older than 1.9.0, then Nimble may have trouble using it.
-See [this issue](https://github.com/nim-lang/nimble/issues/105) for more
-information.
+**Note:** This readme explains how to install and use nimble. It does not
+explain how to create nimble packages. Take a look at the
+[developers.markdown file](developers.markdown) for information regarding
+package creation.
## Installation
-Nimble is now bundled with [Nim](https://nim-lang.org)
-(since Nim version 0.15.0).
-This means that you should have Nimble installed already, as long as you have
-the latest version of Nim installed as well. Because of this **you likely do
-not need to install Nimble manually**.
+You will need version 0.9.6 or better (OSX users **have** to use the developer
+version 0.10.1 or better) of the [Nim
+compiler](http://nim-lang.org/download.html). To run nimble you will need to
+have installed some of the tools it depends on to check out source code. For
+instance, if a package is hosted on [Github](https://github.com) you require to
+have [git](http://www.git-scm.com) installed and added to your environment
+``PATH``. Same goes for [Mercurial](http://mercurial.selenic.com) repositories
+on [Bitbucket](https://bitbucket.org). On Windows you will also need [OpenSSL
+DLLs](https://www.openssl.org) for secure network connections.
-But in case you still want to install Nimble manually, you can follow the
-following instructions.
+### Unix
-There are two ways to install Nimble manually. Using ``koch`` and using Nimble
-itself.
+On Unix operating systems Nimble can be compiled and installed with two simple
+commands. After successfully grabbing the latest Nim compiler simply execute
+the following commands to clone nimble, compile it and then install it.
-### Using koch
+ git clone https://github.com/nim-lang/nimble.git
+ cd nimble
+ nim c -r src/nimble install
-The ``koch`` tool is 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.
+After these steps nimble should be compiled and installed. You should then add
+``~/.nimble/bin`` to your ``$PATH``. Updating nimble can then be done by
+executing ``nimble install nimble``.
-```
-./koch nimble
-```
+### Windows
-This will clone the Nimble repository, compile Nimble and copy it into
-Nim's bin directory.
+You can install via a pre-built installation archive which is
+available on the [releases](https://github.com/nim-lang/nimble/releases) page
+or from source.
-### Using Nimble
+#### Using the pre-built archives
-In most cases you will already have Nimble installed, you can install a newer
-version of Nimble by simply running the following command:
+Download the latest release archive from the
+[releases](https://github.com/nim-lang/nimble/releases) page. These archives
+will have a filename of the form ``nimble-x_win32`` where ``x`` is the
+current version.
-```
-nimble install nimble
-```
+Once you download that archive unzip it and execute the ``install.bat`` file.
+One important thing to note is that this installation requires you have
+the Nim compiler in your PATH. Once the installation completes you should
+add ``C:\Users\YourName\.nimble\bin`` to your PATH.
-This will download the latest release of Nimble and install it on your system.
+#### From source
-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.
+On Windows installing Nimble from source is slightly more complex:
+
+ git clone https://github.com/nim-lang/nimble.git
+ cd nimble
+ nim c src\nimble
+ cp src\nimble.exe src\nimble1.exe
+ src\nimble1.exe install
+
+This is required because Windows will lock the process which is being run and
+during installation Nimble will recompile itself.
+Once the installation completes you should
+add ``C:\Users\YourName\.nimble\bin`` to your PATH.
+
+## Nimble's folder structure and packages
+
+Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems
+and in your ``$home/.nimble`` on Windows. Libraries are stored in
+``$nimbleDir/pkgs``, and binaries are stored in ``$nimbleDir/bin``. Most Nimble
+packages will provide ``.nim`` files and some documentation. The Nim
+compiler is aware of Nimble and will automatically find the modules so you can
+``import modulename`` and have that working without additional setup.
+
+However, some Nimble packages can provide additional tools or commands. If you
+don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not
+work properly and you won't be able to run them.
## Nimble usage
Once you have Nimble installed on your system you can run the ``nimble`` command
to obtain a list of available commands.
-### nimble refresh
+### nimble update
-The ``refresh`` command is used to fetch and update the list of Nimble packages
+The ``update`` command is used to fetch and update the list of Nimble packages
(see below). There is no automatic update mechanism, so you need to run this
yourself if you need to *refresh* your local list of known available Nimble
packages. Example:
- $ nimble refresh
+ $ nimble update
Downloading package list from https://.../packages.json
Done.
-Some commands may remind you to run ``nimble refresh`` or will run it for you if
+Some commands may remind you to run ``nimble update`` or will run it for you if
they fail.
You can also optionally supply this command with a URL if you would like to use
a third-party package list.
-Package lists can be specified in Nimble's config. Take a look at the
-config section below to see how to do this.
-
-### nimble check
-
-The ``check`` command will read your package's .nimble file. It will then
-verify that the package's structure is valid.
-
-Example:
-
- $ nimble check
- Error: Package 'x' has an incorrect structure. It should contain a single directory hierarchy for source files, named 'x', but file 'foobar.nim' is in a directory named 'incorrect' instead. This will be an error in the future.
- Hint: If 'incorrect' contains source files for building 'x', rename it to 'x'. Otherwise, prevent its installation by adding `skipDirs = @["incorrect"]` to the .nimble file.
- Failure: Validation failed
-
-
-
### nimble install
The ``install`` command will download and install a package. You need to pass
@@ -159,9 +116,9 @@ Example:
nake installed successfully
Nimble always fetches and installs the latest version of a package. Note that
-latest version is defined as the latest tagged version in the Git (or Mercurial)
+latest version is defined as the latest tagged version in the git (or hg)
repository, if the package has no tagged versions then the latest commit in the
-remote repository will be installed. If you already have that version installed,
+remote repository will be installed. If you already have that version installed
Nimble will ask you whether you wish it to overwrite your local copy.
You can force Nimble to download the latest commit from the package's repo, for
@@ -169,63 +126,30 @@ example:
$ nimble install nimgame@#head
-This is of course Git-specific, for Mercurial, use ``tip`` instead of ``head``. A
+This is of course git specific, for hg 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
the current working directory. This can be useful for developers who are testing
locally their ``.nimble`` files before submitting them to the official package
-list. See the [Creating Packages](#creating-packages) section for more info on this.
+list. See [developers.markdown](developers.markdown) for more info on this.
-#### Package URLs
-
-A valid URL to a Git or Merurial repository can also be specified, Nimble will
-automatically detect the type of the repository that the url points to and
-install it.
-
-For repositories containing the Nimble package in a subdirectory, you can
-instruct Nimble about the location of your package using the ``?subdir=``
-query parameter. For example:
-
- $ nimble install https://github.com/nimble-test/multi?subdir=alpha
-
-### nimble develop
-
-The ``develop`` command allows you to link an existing copy of a package into
-your installation directory. This is so that when developing a package you
-don't need to keep reinstalling it for every single change.
-
- $ cd ~/projects/jester
- $ nimble develop
-
-Any packages depending on ``jester`` will now use the code in
-``~/projects/jester``.
-
-If you specify a package name to this command, Nimble will clone it into the
-current working directory.
-
- $ nimble develop jester
-
-The ``jester`` package will be cloned into ``./jester`` and it will be linked
-to your installation directory.
-
-Just as with the ``install`` command, a package URL may also be specified
-instead of a name.
+A URL to a repository can also be specified, Nimble will automatically detect
+the type of the repository that the url points to and install it.
### nimble uninstall
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:
@@ -234,17 +158,12 @@ Similar to the ``install`` command you can specify a version range, for example:
### nimble build
The ``build`` command is mostly used by developers who want to test building
-their ``.nimble`` package. This command will build the package with default
-flags, i.e. a debug build which includes stack traces but no GDB debug
-information. The ``install`` command will build the package in release mode
-instead.
+their ``.nimble`` package. This command will build the package in debug mode,
+without installing anything. The ``install`` command will build the package
+in release mode instead.
-### nimble 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.
+If you are a developer willing to produce new Nimble packages please read the
+[developers.markdown file](developers.markdown) for detailed information.
### nimble c
@@ -260,7 +179,7 @@ the command ``c`` or ``compile`` is specified. The more specific ``js``, ``cc``,
The ``list`` command will display the known list of packages available for
Nimble. An optional ``--ver`` parameter can be specified to tell Nimble to
-query remote Git repositories for the list of versions of the packages and to
+query remote git repositories for the list of versions of the packages and to
then print the versions. Please note however that this can be slow as each
package must be queried separately.
@@ -288,8 +207,8 @@ substrings). Example:
Searches are case insensitive.
An optional ``--ver`` parameter can be specified to tell Nimble to
-query remote Git repositories for the list of versions of the packages and
-then print the versions. However, please note that this can be slow as each
+query remote git repositories for the list of versions of the packages and to
+then print the versions. Please note however that this can be slow as each
package must be queried separately.
### nimble path
@@ -313,685 +232,54 @@ which can be useful to read the bundled documentation. Example:
### nimble init
The nimble ``init`` command will start a simple wizard which will create
-a quick ``.nimble`` file for your project in the current directory.
-
-As of version 0.7.0, the ``.nimble`` file that this command creates will
-use the new NimScript format.
-Check out the [Creating Packages](#creating-packages) section for more info.
-
-### nimble publish
-
-Publishes your Nimble package to the official Nimble package repository.
-
-**Note:** Requires a valid GitHub account with an SSH key attached to it. To upload your public key onto your GitHub account, follow [this link](https://github.com/settings/keys).
-
-### nimble tasks
-
-For a Nimble package in the current working directory, list the tasks which that
-package defines. This is only supported for packages utilising the new
-nimscript .nimble files.
-
-### nimble dump
-
-Outputs information about the package in the current working directory in
-an ini-compatible format. Useful for tools wishing to read metadata about
-Nimble packages who do not want to use the NimScript evaluator.
+a quick ``.nimble`` file for your project.
## Configuration
-At startup Nimble will attempt to read ``~/.config/nimble/nimble.ini`` on Linux
-(on Windows it will attempt to read
-``C:\Users\\AppData\Roaming\nimble\nimble.ini``).
+At startup Nimble will attempt to read ``$AppDir/nimble/nimble.ini``,
+where ``$AppDir`` is ``~/.config/`` on Linux and
+``C:\Users\\AppData\Roaming\`` on Windows.
The format of this file corresponds to the ini format with some Nim
enhancements. For example:
```ini
nimbleDir = r"C:\Nimble\"
-
-[PackageList]
-name = "CustomPackages"
-url = "http://mydomain.org/packages.json"
-
-[PackageList]
-name = "Local project packages"
-path = r"C:\Projects\Nim\packages.json"
```
You can currently configure the following in this file:
-* ``nimbleDir`` - The directory which Nimble uses for package installation.
+* ``nimbleDir`` - The directory which nimble uses for package installation.
**Default:** ``~/.nimble/``
* ``chcp`` - Whether to change the current code page when executing Nim
application packages. If ``true`` this will add ``chcp 65001`` to the
.cmd stubs generated in ``~/.nimble/bin/``.
**Default:** ``true``
-* ``[PackageList]`` + ``name`` + (``url``|``path``) - You can use this section to specify
- a new custom package list. Multiple package lists can be specified. Nimble
- defaults to the "Official" package list, you can override it by specifying
- a ``[PackageList]`` section named "official". Multiple URLs can be specified
- under each section, Nimble will try each in succession if
- downloading from the first fails. Alternately, ``path`` can specify a
- local file path to copy a package list .json file from.
-* ``cloneUsingHttps`` - Whether to replace any ``git://`` inside URLs with
- ``https://``.
- **Default: true**
-* ``httpProxy`` - The URL of the proxy to use when downloading package listings.
- Nimble will also attempt to read the ``http_proxy`` and ``https_proxy``
- environment variables.
- **Default: ""**
-* ``nimLibPrefix`` - Specifies the Nim standard library prefix to help Nimble
- find the Nim standard library.
- **Default: ""**
-## Creating Packages
+## Packages
-Nimble works on Git repositories as its primary source of packages. Its list of
+Nimble works on git repositories as its primary source of packages. Its list of
packages is stored in a JSON file which is freely accessible in the
[nim-lang/packages repository](https://github.com/nim-lang/packages).
-This JSON file provides Nimble with the required Git URL to clone the package
+This JSON file provides nimble with the required Git URL to clone the package
and install it. Installation and build instructions are contained inside a
-file with the ``.nimble`` file extension. The Nimble file shares the
-package's name, i.e. a package
-named "foobar" should have a corresponding ``foobar.nimble`` file.
-
-These files specify information about the package including its author,
-license, dependencies and more. Without one, Nimble is not able to install
-a package.
-
-A .nimble file can be created easily using Nimble's ``init`` command. This
-command will ask you a bunch of questions about your package, then generate a
-.nimble file for you in the current directory.
-
-A bare minimum .nimble file follows:
-
-```ini
-# Package
-
-version = "0.1.0"
-author = "Your Name"
-description = "Example .nimble file."
-license = "MIT"
-
-# Deps
-
-requires "nim >= 0.10.0"
-```
-
-You may omit the dependencies entirely, but specifying the lowest version
-of the Nim compiler required is recommended.
-
-You can also specify multiple dependencies like so:
-
-```
-# Deps
-
-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
-Git repository and a mercurial repository. The .nimble file must be present in
-the root of the directory or repository being installed.
-
-The .nimble file is very flexible because it is interpreted using NimScript.
-Because of Nim's flexibility the definitions remain declarative. With the added
-ability of using the Nim language to enrich your package specification.
-For example, you can define dependencies for specific platforms using Nim's
-``when`` statement.
-
-Another great feature
-is the ability to define custom Nimble package-specific commands. These are
-defined in the .nimble files of course.
-
-```nim
-task hello, "This is a hello task":
- echo("Hello World!")
-```
-
-You can then execute ``nimble hello``, which will result in the following
-output:
-
-```
-Executing task hello in /Users/user/projects/pkg/pkg.nimble
-Hello World!
-```
-
-You can place any Nim code inside these tasks. As long as that code does not
-access the FFI. The ``nimscript``
-[module](https://nim-lang.org/docs/nimscript.html) in Nim's standard library defines
-additional functionality such as the ability to execute external processes
-which makes this feature very powerful.
-
-You can also check what tasks are supported by the package in the current
-directory by using the ``tasks`` command.
-
-Nimble provides an API which adds even more functionality. For example,
-you can specify
-pre and post hooks for any Nimble command (including commands that
-you define yourself). To do this you can add something like the following:
-
-```nim
-before hello:
- echo("About to call hello!")
-```
-
-That will result in the following output when ``nimble hello`` is executed (you
-must also specify the ``task`` shown above).
-
-```
-Executing task hello in /Users/user/projects/pkg/pkg.nimble
-About to call hello!
-Hello World!
-```
-
-Similar to this an ``after`` block is also available for post hooks,
-which are executed after Nimble finished executing a command. You can
-also return ``false`` from these blocks to stop further execution.
-
-The ``nimscriptapi.nim`` module specifies this and includes other definitions
-which are also useful. Take a look at it for more information.
-
-### Project structure
-
-For a package named "foobar", the recommended project structure is the following:
-
-```
-. # The root directory of the project
-├── LICENSE
-├── README.md
-├── foobar.nimble # The project .nimble file
-└── src
- └── foobar.nim # Imported via `import foobar`
-└── tests # Contains the tests
- ├── config.nims
- ├── tfoo1.nim # First test
- └── tfoo2.nim # Second test
-
-```
-
-Note that the .nimble file needs to be in the project's root directory. This
-directory structure will be created if you run ``nimble init`` inside a
-``foobar`` directory.
-
-**Warning:** When source files are placed in a ``src`` directory, the
-.nimble file must contain a ``srcDir = "src"`` directive. The ``nimble init``
-command takes care of that for you.
-
-When introducing more modules into your package, you should place them in a
-separate directory named ``foobar`` (i.e. your package's name). For example:
-
-```
-. # The root directory of the project
-├── ...
-├── foobar.nimble # The project .nimble file
-├── src
-│ ├── foobar
-│ │ ├── utils.nim # Imported via `import foobar/utils`
-│ │ └── common.nim # Imported via `import foobar/common`
-│ └── foobar.nim # Imported via `import foobar`
-└── ...
-```
-
-#### Private modules
-
-You may wish to hide certain modules in your package from the users. Create a
-``private`` directory for that purpose. For example:
-
-```
-. # The root directory of the project
-├── ...
-├── foobar.nimble # The project .nimble file
-├── src
-│ ├── foobar
-│ │ ├── private
-│ │ │ └── hidden.nim # Imported via `import foobar/private/hidden`
-│ │ ├── utils.nim # Imported via `import foobar/utils`
-│ │ └── common.nim # Imported via `import foobar/common`
-│ └── foobar.nim # Imported via `import foobar`
-└── ...
-```
-
-#### Tests
-
-A common problem that arises with tests is the fact that they need to import
-the associated package. But the package is in the parent directory. This can
-be solved in a few different ways:
-
-* Expect that the package has been installed locally into your
- ``~/.nimble`` directory.
-* Use a simple path modification to resolve the package properly.
-
-The latter is highly recommended. Reinstalling the package to test an actively
-changing code base is a massive pain.
-
-To modify the path for your tests only, simply add a ``nim.cfg`` file into
-your ``tests`` directory with the following contents:
-
-```
---path:"../src/"
-```
-
-Nimble offers a pre-defined ``test`` task which compiles and runs all files
-in the ``tests`` directory beginning with 't' in their filename.
-
-You may wish to override this ``test`` task in your ``.nimble`` file. This
-is particularly useful when you have a single test suite program. Just add
-the following to your ``.nimble`` file to override the default ``test`` task.
-
-```nim
-task test, "Runs the test suite":
- exec "nim c -r tests/tester"
-```
-
-Running ``nimble test`` will now use the ``test`` task you have defined.
-
-### Libraries
-
-Library packages are likely the most popular form of Nimble packages. They are
-meant to be used by other library or binary packages.
-
-When Nimble installs a library, it will copy all of its files
-into ``$nimbleDir/pkgs/pkgname-ver``. It's up to the package creator to make sure
-that the package directory layout is correct, this is so that users of the
-package can correctly import the package.
-
-It is suggested that the layout be as follows. The directory layout is
-determined by the nature of your package, that is, whether your package exposes
-only one module or multiple modules.
-
-If your package exposes only a single module, then that module should be
-present in the root directory (the directory with the .nimble file) of your Git
-repository, and should be named whatever your package's name is. A good example
-of this is the [jester](https://github.com/dom96/jester) package which exposes
-the ``jester`` module. In this case the jester package is imported with
-``import jester``.
-
-If your package exposes multiple modules then the modules should be in a
-``PackageName`` directory. This will allow for a certain measure of isolation
-from other packages which expose modules with the same names. In this case
-the package's modules will be imported with ``import PackageName/module``.
-
-Here's a simple example multi-module library package called `kool`:
-
-```
-.
-├── kool
-│ ├── useful.nim
-│ └── also_useful.nim
-└── kool.nimble
-```
-
-In regards to modules which you do **not** wish to be exposed. You should place
-them in a ``PackageName/private`` directory. Your modules may then import these
-private modules with ``import PackageName/private/module``. This directory
-structure may be enforced in the future.
-
-All files and folders in the directory of where the .nimble file resides will be
-copied as-is, you can however skip some directories or files by setting
-the ``skipDirs``, ``skipFiles`` or ``skipExt`` options in your .nimble file.
-Directories and files can also be specified on a *whitelist* basis, if you
-specify either of ``installDirs``, ``installFiles`` or ``installExt`` then
-Nimble will **only** install the files specified.
-
-### Binary packages
-
-These are application packages which require building prior to installation.
-A package is automatically a binary package as soon as it sets at least one
-``bin`` value, like so:
-
-```ini
-bin = @["main"]
-```
-
-In this case when ``nimble install`` is invoked, Nimble will build the ``main.nim``
-file, copy it into ``$nimbleDir/pkgs/pkgname-ver/`` and subsequently create a
-symlink to the binary in ``$nimbleDir/bin/``. On Windows a stub .cmd file is
-created instead.
-
-Other files will be copied in the same way as they are for library packages.
-
-Binary packages should not install .nim files so include ``skipExt = @["nim"]``
-in your .nimble file, unless you intend for your package to be a binary/library
-combo.
-
-Dependencies are automatically installed before building.
-It's a good idea to test that the dependencies you specified are correct by
-running ``nimble build`` or ``nimble install`` in the directory
-of your package.
-
-### Hybrids
-
-One thing to note about binary packages that contain source files aside from
-the one(s) specified in `bin` (or that also expose multiple library modules, as
-above) is that a binary may share the name of the package: this will mean
-that you will not be able to put your additional .nim files in a ``pkgname``
-directory. The reason for this is that binaries on some operating systems do
-not have an extension, so they will clash with a directory of the same name.
-
-If this is the case, you should place your additional .nim files in a directory
-with `pkg` appended after the name of the project. For instance, if you were
-building a binary named `project`, you would put any additional source files in
-a directory called `projectpkg`. From within project.nim you would then import
-those modules namespaced with `projectpkg/`.
-
-### Dependencies
-
-Dependencies are specified using the ``requires`` function. For example:
-
-```
-# Dependencies
-requires "nim >= 0.10.0", "jester > 0.1 & <= 0.5"
-```
-
-Dependency lists support version ranges. These versions may either be a concrete
-version like ``0.1``, or they may contain any of the less-than (``<``),
-greater-than (``>``), less-than-or-equal-to (``<=``) and greater-than-or-equal-to
-(``>=``) operators.
-Two version ranges may be combined using the ``&`` operator, for example
-``> 0.2 & < 1.0``, which will install a package with the version greater than 0.2
-and less than 1.0.
-
-Specifying a concrete version as a dependency is not a good idea because your
-package may end up depending on two different versions of the same package.
-If this happens, Nimble will refuse to install the package.
-
-In addition to versions you may also specify Git/Mercurial tags, branches and commits.
-Although these have to be specific; ranges of commits are not supported.
-This is done with the ``#`` character,
-for example: ``jester#head``. Which will make your package depend on the
-latest commit of Jester.
-
-#### External dependencies
-
-**Warning:** This feature is brand new in Nimble v0.8.0. Breaking changes
-related to it are more likely to be introduced than for any other Nimble
-features.
-
-Starting with Nimble v0.8.0, you can now specify external dependencies. These
-are dependencies which are not managed by Nimble and can only be installed via
-your system's package manager or downloaded manually via the internet.
-
-As an example, to specify a dependency on openssl you may put this in your
-.nimble file:
-
-```nim
-when defined(nimdistros):
- import distros
- if detectOs(Ubuntu):
- foreignDep "libssl-dev"
- else:
- foreignDep "openssl"
-```
-
-The ``when`` branch is important to support installation using older versions
-of Nimble.
-
-The [distros module](https://nim-lang.org/docs/distros.html) in Nim's
-standard library contains a list of all the supported Operating Systems and
-Linux distributions.
-
-With this inside your .nimble file, Nimble will output the following after
-installing your package (on macOS):
-
-```
- Hint: This package requires some external dependencies.
- Hint: To install them you may be able to run:
- Hint: 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
-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.
-
-When Nimble builds your package it actually executes the Nim compiler.
-It resolves the dependencies and feeds the path of each package to
-the compiler so that it knows precisely which version to use.
-
-This means that you can safely compile using the compiler when developing your
-software, but you should use Nimble to build the package before publishing it
-to ensure that the dependencies you specified are correct.
-
-### Compile with `nim` after changing the nimble directory
-
-The Nim compiler has been preconfigured to look at the default nimble directory while compiling,
-so no extra step is required to use nimble managed packages in your code.
-However, if you are using a custom `nimbleDir`, you need to specify the
-`--nimblePath:PATH` option. For example,
-if your `nimble` directory is located at `/some/custom/path/nimble`, this should work:
-
-```
-nim c --nimblePath:/some/custom/path/nimble/pkgs main.nim
-```
-
-Some code editors rely on `nim check` to check for errors under the hood (e.g. VScode),
-and the editor extension may not allow users to pass custom option to `nim check`, which
-will cause `nim check` to scream `Error: cannot open file:`. In this case,
-you will have to use [Nim compiler's configuration files](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files). Simply add the line:
-```
-nimblePath = "/some/custom/path/nimble/pkgs"
-```
-to the `nim.cfg` located in any directory listed in the [documentation](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files), this should resolve the problem.
-
-### Versions
-
-Versions of cloned packages via Git or Mercurial are determined through the
-repository's *tags*.
-
-When installing a package which needs to be downloaded, after the download is
-complete and if the package is distributed through a VCS, Nimble will check the
-cloned repository's tags list. If no tags exist, Nimble will simply install the
-HEAD (or tip in Mercurial) of the repository. If tags exist, Nimble will attempt
-to look for tags which resemble versions (e.g. v0.1) and will then find the
-latest version out of the available tags, once it does so it will install the
-package after checking out the latest version.
-
-You can force the installation of the HEAD of the repository by specifying
-``#head`` after the package name in your dependency list.
-
-#### Releasing a new version
-
-Version releases are done by creating a tag in your Git or Mercurial
-repository.
-
-Whenever you want to release a new version, you should remember to first
-increment the version in your ``.nimble`` file and commit your changes. Only
-after that is done should you tag the release.
-
-To summarise, the steps for release are:
-
-* Increment the version in your ``.nimble`` file.
-* Commit your changes.
-* Tag your release, by for example running ``git tag v0.2.0``.
-* Push your tags and commits.
-
-Once the new tag is in the remote repository, Nimble will be able to detect
-the new version.
-
-##### 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
-a specific name to a URL pointing to your package. This mapping is stored
-in an official packages repository located
-[here](https://github.com/nim-lang/packages).
-
-This repository contains a ``packages.json`` file which lists all the published
-packages. It contains a set of package names with associated metadata. You
-can read more about this metadata in the
-[readme for the packages repository](https://github.com/nim-lang/packages#readme).
-
-To publish your package you need to fork that repository, and add an entry
-into the ``packages.json`` file for your package. Then create a pull request
-with your changes. **You only need to do this
-once**.
-
-Nimble includes a ``publish`` command which does this for you automatically.
-
-## .nimble reference
-
-### [Package]
-
-#### Required
-
-* ``name`` - The name of the package. *(This is not required in the new NimScript format)*
-* ``version`` - The *current* version of this package. This should be incremented
- **before** tagging the current version using ``git tag`` or ``hg tag``.
-* ``author`` - The name of the author of this package.
-* ``description`` - A string describing the package.
-* ``license`` - The name of the license in which this package is licensed under.
-
-#### Optional
-
-* ``skipDirs`` - A list of directory names which should be skipped during
- installation, separated by commas.
-* ``skipFiles`` - A list of file names which should be skipped during
- installation, separated by commas.
-* ``skipExt`` - A list of file extensions which should be skipped during
- installation, the extensions should be specified without a leading ``.`` and
- should be separated by commas.
-* ``installDirs`` - A list of directories which should exclusively be installed,
- if this option is specified nothing else will be installed except the dirs
- listed here, the files listed in ``installFiles``, the files which share the
- extensions listed in ``installExt``, the .nimble file and the binary
- (if ``bin`` is specified). Separated by commas.
-* ``installFiles`` - A list of files which should be exclusively installed,
- this complements ``installDirs`` and ``installExt``. Only the files listed
- here, directories listed in ``installDirs``, files which share the extension
- listed in ``installExt``, the .nimble file and the binary (if ``bin`` is
- specified) will be installed. Separated by commas.
-* ``installExt`` - A list of file extensions which should be exclusively
- installed, this complements ``installDirs`` and ``installFiles``.
- Separated by commas.
-* ``srcDir`` - Specifies the directory which contains the .nim source files.
- **Default**: The directory in which the .nimble file resides; i.e. root dir of
- the package.
-* ``binDir`` - Specifies the directory where ``nimble build`` will output
- binaries.
- **Default**: The directory in which the .nimble file resides; i.e.
- root dir of the package.
-* ``bin`` - A list of files which should be built separated by commas with
- no file extension required. This option turns your package into a *binary
- package*, Nimble will build the files specified and install them appropriately.
-* ``backend`` - Specifies the backend which will be used to build the files
- listed in ``bin``. Possible values include: ``c``, ``cc``, ``cpp``, ``objc``,
- ``js``.
- **Default**: c
-
-### [Deps]/[Dependencies]
-
-#### Optional
-
-* ``requires`` - Specified a list of package names with an optional version
- range separated by commas.
- **Example**: ``nim >= 0.10.0, jester``; with this value your package will
- depend on ``nim`` version 0.10.0 or greater and on any version of ``jester``.
-
-## Nimble's folder structure and packages
-
-Nimble stores everything that has been installed in ``~/.nimble`` on Unix systems
-and in your ``$home/.nimble`` on Windows. Libraries are stored in
-``$nimbleDir/pkgs``, and binaries are stored in ``$nimbleDir/bin``. Most Nimble
-packages will provide ``.nim`` files and some documentation. The Nim
-compiler is aware of Nimble and will automatically find the modules so you can
-``import modulename`` and have that working without additional setup.
-
-However, some Nimble packages can provide additional tools or commands. If you
-don't add their location (``$nimbleDir/bin``) to your ``$PATH`` they will not
-work properly and you won't be able to run them.
-
-## Troubleshooting
-
-* ```SSL support is not available. Cannot connect over SSL. [HttpRequestError]```
-
-Make sure that Nimble is configured to run with SSL, adding a ```-d:ssl```
-flag to the file ```src/nimble.nim.cfg```.
-After that, you can run ```src/nimble install``` and overwrite the existing
-installation.
-
-* ``Could not download: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure``
-
-If you are on macOS, you need to set and export the ```DYLD_LIBRARY_PATH``` environment variable to the directory where your OpenSSL libraries are. For example, if you use OpenSSL, you have to set ```export DYLD_LIBRARY_PATH=/usr/local/opt/openssl/lib``` in your ```$HOME/.bashrc``` file.
-
-* ``Error: ambiguous identifier: 'version' --use nimscriptapi.version or system.version``
-
-Make sure that you are running at least version 0.16.0 of Nim (or the latest nightly).
-
-* ``Error: cannot open '/home/user/.nimble/lib/system.nim'.``
-
-Nimble cannot find the Nim standard library. This is considered a bug so
-please report it. As a workaround you can set the ``NIM_LIB_PREFIX`` environment
-variable to the directory where ``lib/system.nim`` (and other standard library
-files) are found. Alternatively you can also configure this in Nimble's
-config file.
-
-## Repository information
-
-This repository has two main branches: ``master`` and ``stable``.
-
-The ``master`` branch is...
-
-* default
-* bleeding edge
-* tested to compile with a pinned (close to HEAD) commit of Nim
-
-The ``stable`` branch is...
-
-* installed by ``koch tools``/``koch nimble``
-* relatively stable
-* should compile with Nim HEAD as well as the latest Nim version
-
-Note: The travis build only tests whether Nimble works with the latest Nim
-version.
-
-A new Nim release (via ``koch xz``) will always bundle the ``stable`` branch.
+ini-style file with the ``.nimble`` file extension. The nimble file shares the
+package's name.
## Contribution
If you would like to help, feel free to fork and make any additions you see fit
-and then send a pull request.
+and then send a pull request. If you are a developer willing to produce new
+Nimble packages please read the [developers.markdown file](developers.markdown)
+for detailed information.
-If you have any questions about the project, you can ask me directly on GitHub,
-ask on the Nim [forum](https://forum.nim-lang.org), or ask on Freenode in
+If you have any questions about the project you can ask me directly on github,
+ask on the Nim [forum](http://forum.nim-lang.org), or ask on Freenode in
the #nim channel.
-## Implementation details
-
-### .nimble-link
-
-These files are created by Nimble when using the ``develop`` command. They
-are very simple and contain two lines.
-
-**The first line:** Always a path to the `.nimble` file.
-
-**The second line:** Always a path to the Nimble package's source code. Usually
-``$pkgDir/src``, depending on what ``srcDir`` is set to.
-
-The paths written by Nimble are **always** absolute. But Nimble (and the
-Nim compiler) also supports relative paths, which will be read relative to
-the `.nimble-link` file.
-
## About
-Nimble has been written by [Dominik Picheta](https://picheta.me/) with help from
+Nimble has been written by [Dominik Picheta](http://picheta.me/) with help from
a number of
[contributors](https://github.com/nim-lang/nimble/graphs/contributors).
-It is licensed under the 3-clause BSD license, see [license.txt](license.txt)
-for more information.
+It is licensed under the BSD license (Look at license.txt for more info).
diff --git a/src/nimble.nim b/src/nimble.nim
index d7e011e..ab6a233 100644
--- a/src/nimble.nim
+++ b/src/nimble.nim
@@ -1,48 +1,259 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
-import system except TResult
+import httpclient, parseopt, os, strutils, osproc, pegs, tables, parseutils,
+ strtabs, json, algorithm, sets
-import os, tables, strtabs, json, algorithm, sets, uri, sugar, sequtils, osproc
-import std/options as std_opt
-
-import strutils except toLower
-from unicode import toLower
from sequtils import toSeq
-from strformat import fmt
import nimblepkg/packageinfo, nimblepkg/version, nimblepkg/tools,
- nimblepkg/download, nimblepkg/config, nimblepkg/common,
- nimblepkg/publish, nimblepkg/options, nimblepkg/packageparser,
- nimblepkg/cli, nimblepkg/packageinstaller, nimblepkg/reversedeps,
- nimblepkg/nimscriptexecutor, nimblepkg/init
+ nimblepkg/download, nimblepkg/config, nimblepkg/nimbletypes
-import nimblepkg/nimscriptwrapper
+when not defined(windows):
+ from posix import getpid
-proc refresh(options: Options) =
+type
+ Options = object
+ forcePrompts: ForcePrompt
+ queryVersions: bool
+ queryInstalled: bool
+ action: Action
+ config: Config
+ nimbleData: JsonNode ## Nimbledata.json
+
+ ActionType = enum
+ actionNil, actionUpdate, actionInit, actionInstall, actionSearch,
+ actionList, actionBuild, actionPath, actionUninstall, actionCompile
+
+ Action = object
+ case typ: ActionType
+ of actionNil, actionList, actionBuild: nil
+ of actionUpdate:
+ optionalURL: string # Overrides default package list.
+ of actionInstall, actionPath, actionUninstall:
+ optionalName: seq[string] # \
+ # When this is @[], installs package from current dir.
+ packages: seq[PkgTuple] # Optional only for actionInstall.
+ of actionSearch:
+ search: seq[string] # Search string.
+ of actionInit:
+ projName: string
+ of actionCompile:
+ file: string
+ backend: string
+ compileOptions: seq[string]
+ else: nil
+
+ ForcePrompt = enum
+ dontForcePrompt, forcePromptYes, forcePromptNo
+
+const
+ help = """
+Usage: nimble COMMAND [opts]
+
+Commands:
+ install [pkgname, ...] Installs a list of packages.
+ init [pkgname] Initializes a new Nimble project.
+ uninstall [pkgname, ...] Uninstalls a list of packages.
+ build Builds a package.
+ c, cc, js [opts, ...] f.nim Builds a file inside a package. Passes options
+ to the Nim compiler.
+ update [url] Updates package list. A package list URL can
+ be optionally specified.
+ search [--ver] pkg/tag Searches for a specified package. Search is
+ performed by tag and by name.
+ list [--ver] Lists all packages.
+ [-i, --installed] Lists all installed packages.
+ path pkgname ... Shows absolute path to the installed packages
+ specified.
+
+Options:
+ -h, --help Print this help message.
+ -v, --version Print version information.
+ -y, --accept Accept all interactive prompts.
+ -n, --reject Reject all interactive prompts.
+ --ver Query remote server for package version
+ information when searching or listing packages
+ --nimbledir dirname Set the Nimble directory.
+
+For more information read the Github readme:
+ https://github.com/nim-lang/nimble#readme
+"""
+ nimbleVersion = "0.6.2"
+ defaultPackageURL =
+ "https://github.com/nim-lang/packages/raw/master/packages.json"
+
+proc writeHelp() =
+ echo(help)
+ quit(QuitSuccess)
+
+proc writeVersion() =
+ echo("nimble v$# compiled at $# $#" %
+ [nimbleVersion, CompileDate, CompileTime])
+ quit(QuitSuccess)
+
+proc getNimbleDir(options: Options): string =
+ options.config.nimbleDir
+
+proc getPkgsDir(options: Options): string =
+ options.config.nimbleDir / "pkgs"
+
+proc getBinDir(options: Options): string =
+ options.config.nimbleDir / "bin"
+
+proc prompt(options: Options, question: string): bool =
+ ## Asks an interactive question and returns the result.
+ ##
+ ## The proc will return immediately without asking the user if the global
+ ## forcePrompts has a value different than dontForcePrompt.
+ case options.forcePrompts
+ of forcePromptYes:
+ echo(question & " -> [forced yes]")
+ return true
+ of forcePromptNo:
+ echo(question & " -> [forced no]")
+ return false
+ of dontForcePrompt:
+ echo(question & " [y/N]")
+ let yn = stdin.readLine()
+ case yn.normalize
+ of "y", "yes":
+ return true
+ of "n", "no":
+ return false
+ else:
+ return false
+
+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 parseCmdLine(): Options =
+ result.action.typ = actionNil
+ result.config = parseConfig()
+ for kind, key, val in getOpt():
+ case kind
+ of cmdArgument:
+ if result.action.typ == actionNil:
+ case key
+ of "install", "path":
+ case key
+ of "install":
+ result.action.typ = actionInstall
+ of "path":
+ result.action.typ = actionPath
+ else:
+ discard
+ result.action.packages = @[]
+ of "build":
+ result.action.typ = actionBuild
+ of "c", "compile", "js", "cpp", "cc":
+ result.action.typ = actionCompile
+ result.action.compileOptions = @[]
+ result.action.file = ""
+ if key == "c" or key == "compile": result.action.backend = ""
+ else: result.action.backend = key
+ of "init":
+ result.action.typ = actionInit
+ result.action.projName = ""
+ of "update":
+ result.action.typ = actionUpdate
+ result.action.optionalURL = ""
+ of "search":
+ result.action.typ = actionSearch
+ result.action.search = @[]
+ of "list":
+ result.action.typ = actionList
+ of "uninstall", "remove", "delete", "del", "rm":
+ result.action.typ = actionUninstall
+ result.action.packages = @[]
+ else: writeHelp()
+ else:
+ case result.action.typ
+ of actionNil:
+ assert false
+ of actionInstall, actionPath, actionUninstall:
+ # Parse pkg@verRange
+ if '@' in key:
+ let i = find(key, '@')
+ let pkgTup = (key[0 .. i-1],
+ key[i+1 .. key.len-1].parseVersionRange())
+ result.action.packages.add(pkgTup)
+ else:
+ result.action.packages.add((key, VersionRange(kind: verAny)))
+ of actionUpdate:
+ result.action.optionalURL = key
+ of actionSearch:
+ result.action.search.add(key)
+ of actionInit:
+ if result.action.projName != "":
+ raise newException(NimbleError,
+ "Can only initialize one package at a time.")
+ result.action.projName = key
+ of actionCompile:
+ result.action.file = key
+ of actionList, actionBuild:
+ writeHelp()
+ else:
+ discard
+ of cmdLongOption, cmdShortOption:
+ case result.action.typ
+ of actionCompile:
+ if val == "":
+ result.action.compileOptions.add("--" & key)
+ else:
+ result.action.compileOptions.add("--" & key & ":" & val)
+ else:
+ case key
+ of "help", "h": writeHelp()
+ of "version", "v": writeVersion()
+ of "accept", "y": result.forcePrompts = forcePromptYes
+ of "reject", "n": result.forcePrompts = forcePromptNo
+ of "ver": result.queryVersions = true
+ of "nimbleDir": result.config.nimbleDir = val # overrides option from file
+ of "installed", "i": result.queryInstalled = true
+ else: discard
+ of cmdEnd: assert(false) # cannot happen
+ if result.action.typ == actionNil:
+ writeHelp()
+
+ # TODO: Remove this after a couple of versions.
+ if getNimrodVersion() > newVersion("0.9.6"):
+ # Rename deprecated babel dir.
+ renameBabelToNimble(result)
+
+ # Load nimbledata.json
+ let nimbledataFilename = result.getNimbleDir() / "nimbledata.json"
+ if fileExists(nimbledataFilename):
+ try:
+ result.nimbleData = parseFile(nimbledataFilename)
+ except:
+ raise newException(NimbleError, "Couldn't parse nimbledata.json file " &
+ "located at " & nimbledataFilename)
+ else:
+ result.nimbleData = %{"reverseDeps": newJObject()}
+
+proc update(options: Options) =
## Downloads the package list from the specified URL.
##
- ## If the download is not successful, an exception is raised.
- let parameter =
- if options.action.typ == actionRefresh:
+ ## If the download is successful, the global didUpdatePackages is set to
+ ## true. Otherwise an exception is raised on error.
+ let url =
+ if options.action.typ == actionUpdate and options.action.optionalURL != "":
options.action.optionalURL
else:
- ""
-
- if parameter.len > 0:
- if parameter.isUrl:
- let cmdLine = PackageList(name: "commandline", urls: @[parameter])
- fetchList(cmdLine, options)
- else:
- if parameter notin options.config.packageLists:
- let msg = "Package list with the specified name not found."
- raise newException(NimbleError, msg)
-
- fetchList(options.config.packageLists[parameter], options)
- else:
- # Try each package list in config
- for name, list in options.config.packageLists:
- fetchList(list, options)
+ defaultPackageURL
+ echo("Downloading package list from " & url)
+ downloadFile(url, options.getNimbleDir() / "packages.json")
+ echo("Done.")
proc checkInstallFile(pkgInfo: PackageInfo,
origDir, file: string): bool =
@@ -96,7 +307,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
@@ -108,7 +319,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
if options.prompt("Missing file " & src & ". Continue?"):
continue
else:
- raise NimbleQuit(msg: "")
+ quit(QuitSuccess)
createDir(dest / file.splitFile.dir)
result.incl copyFileD(src, dest / file)
@@ -119,7 +330,7 @@ proc copyFilesRec(origDir, currentDir, dest: string,
if options.prompt("Missing directory " & src & ". Continue?"):
continue
else:
- raise NimbleQuit(msg: "")
+ quit(QuitSuccess)
result.incl copyDirD(origDir / dir, dest / dir)
result.incl copyWithExt(origDir, currentDir, dest, pkgInfo)
@@ -143,140 +354,133 @@ proc copyFilesRec(origDir, currentDir, dest: string,
result.incl copyFileD(pkgInfo.mypath,
changeRoot(pkgInfo.mypath.splitFile.dir, dest, pkgInfo.mypath))
+proc saveNimbleData(options: Options) =
+ # TODO: This file should probably be locked.
+ writeFile(options.getNimbleDir() / "nimbledata.json",
+ pretty(options.nimbleData))
+
+proc addRevDep(options: Options, dep: tuple[name, version: string],
+ pkg: PackageInfo) =
+ # let depNameVer = dep.name & '-' & dep.version
+ if not options.nimbleData["reverseDeps"].hasKey(dep.name):
+ options.nimbleData["reverseDeps"][dep.name] = newJObject()
+ if not options.nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
+ options.nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
+ let revDep = %{ "name": %pkg.name, "version": %pkg.version}
+ let thisDep = options.nimbleData["reverseDeps"][dep.name][dep.version]
+ if revDep notin thisDep:
+ thisDep.add revDep
+
+proc removeRevDep(options: Options, pkg: PackageInfo) =
+ ## Removes ``pkg`` from the reverse dependencies of every package.
+ proc remove(options: Options, pkg: PackageInfo, depTup: PkgTuple,
+ thisDep: JsonNode) =
+ for ver, val in thisDep:
+ if ver.newVersion in depTup.ver:
+ var newVal = newJArray()
+ for revDep in val:
+ if not (revDep["name"].str == pkg.name and
+ revDep["version"].str == pkg.version):
+ newVal.add revDep
+ thisDep[ver] = newVal
+
+ for depTup in pkg.requires:
+ if depTup.name.isURL():
+ # We sadly must go through everything in this case...
+ for key, val in options.nimbleData["reverseDeps"]:
+ options.remove(pkg, depTup, val)
+ else:
+ let thisDep = options.nimbleData["reverseDeps"][depTup.name]
+ if thisDep.isNil: continue
+ options.remove(pkg, depTup, thisDep)
+
+ # Clean up empty objects/arrays
+ var newData = newJObject()
+ for key, val in options.nimbleData["reverseDeps"]:
+ if val.len != 0:
+ var newVal = newJObject()
+ for ver, elem in val:
+ if elem.len != 0:
+ newVal[ver] = elem
+ if newVal.len != 0:
+ newData[key] = newVal
+ options.nimbleData["reverseDeps"] = newData
+
+ saveNimbleData(options)
+
proc install(packages: seq[PkgTuple],
options: Options,
- doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo]
-proc processDeps(pkginfo: PackageInfo, options: Options): seq[PackageInfo] =
+ doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo]
+proc processDeps(pkginfo: PackageInfo, options: Options): seq[string] =
## Verifies and installs dependencies.
##
- ## Returns the list of PackageInfo (for paths) to pass to the compiler
- ## during build phase.
+ ## Returns the list of paths to pass to the compiler during build phase.
result = @[]
- assert(not pkginfo.isMinimal, "processDeps needs pkginfo.requires")
- display("Verifying",
- "dependencies for $1@$2" % [pkginfo.name, pkginfo.specialVersion],
- priority = HighPriority)
-
- var pkgList {.global.}: seq[tuple[pkginfo: PackageInfo, meta: MetaData]] = @[]
- once: pkgList = getInstalledPkgsMin(options.getPkgsDir(), options)
+ let pkglist = getInstalledPkgs(options.getPkgsDir())
var reverseDeps: seq[tuple[name, version: string]] = @[]
for dep in pkginfo.requires:
if dep.name == "nimrod" or dep.name == "nim":
let nimVer = getNimrodVersion()
if not withinRange(nimVer, dep.ver):
- let msg = "Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")"
- raise newException(NimbleError, msg)
+ quit("Unsatisfied dependency: " & dep.name & " (" & $dep.ver & ")")
else:
- let resolvedDep = dep.resolveAlias(options)
- display("Checking", "for $1" % $resolvedDep, priority = MediumPriority)
+ echo("Looking for ", dep.name, " (", $dep.ver, ")...")
var pkg: PackageInfo
- var found = findPkg(pkgList, resolvedDep, pkg)
- # Check if the original name exists.
- if not found and resolvedDep.name != dep.name:
- display("Checking", "for $1" % $dep, priority = MediumPriority)
- found = findPkg(pkgList, dep, pkg)
- if found:
- display("Warning:", "Installed package $1 should be renamed to $2" %
- [dep.name, resolvedDep.name], Warning, HighPriority)
-
- if not found:
- display("Installing", $resolvedDep, priority = HighPriority)
- let toInstall = @[(resolvedDep.name, resolvedDep.ver)]
- let (pkgs, installedPkg) = install(toInstall, options)
- result.add(pkgs)
+ if not findPkg(pkglist, dep, pkg):
+ echo("None found, installing...")
+ let (paths, installedPkg) = install(@[(dep.name, dep.ver)], options)
+ result.add(paths)
pkg = installedPkg # For addRevDep
-
- # This package has been installed so we add it to our pkgList.
- pkgList.add((pkg, readMetaData(pkg.getRealDir())))
else:
- display("Info:", "Dependency on $1 already satisfied" % $dep,
- priority = HighPriority)
- result.add(pkg)
+ echo("Dependency already satisfied.")
+ result.add(pkg.mypath.splitFile.dir)
# Process the dependencies of this dependency.
- result.add(processDeps(pkg.toFullInfo(options), options))
- reverseDeps.add((pkg.name, pkg.specialVersion))
+ result.add(processDeps(pkg, options))
+ reverseDeps.add((pkg.name, pkg.version))
# Check if two packages of the same name (but different version) are listed
# 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:
+ for p in result:
+ let (name, version) = getNameVersion(p)
+ if pkgsInPath.hasKey(name) and pkgsInPath[name] != version:
raise newException(NimbleError,
"Cannot satisfy the dependency on $1 $2 and $1 $3" %
- [pkgInfo.name, currentVer, pkgsInPath[pkgInfo.name]])
- pkgsInPath[pkgInfo.name] = currentVer
+ [name, version, pkgsInPath[name]])
+ pkgsInPath[name] = version
# We add the reverse deps to the JSON file here because we don't want
# them added if the above errorenous condition occurs
# (unsatisfiable dependendencies).
- # N.B. NimbleData is saved in installFromDir.
for i in reverseDeps:
- addRevDep(options.nimbleData, i, pkginfo)
+ addRevDep(options, i, pkginfo)
+ saveNimbleData(options)
-proc buildFromDir(
- pkgInfo: PackageInfo, paths, args: seq[string],
- options: Options
-) =
+proc buildFromDir(pkgInfo: PackageInfo, paths: seq[string], forRelease: bool) =
## 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 releaseOpt = if forRelease: "-d:release" else: ""
+ var args = ""
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)
-
- let outputDir = pkgInfo.getOutputDir("")
- 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]
+ echo("Building ", pkginfo.name, "/", bin, " using ", pkgInfo.backend,
+ " backend...")
try:
- doCmd(cmd, showCmd = true)
- binariesBuilt.inc()
+ doCmd(getNimBin() & " $# $# --noBabelPath $# $# \"$#\"" %
+ [pkgInfo.backend, releaseOpt, args, outputOpt,
+ realDir / bin.changeFileExt("nim")])
except NimbleError:
- let currentExc = (ref NimbleError)(getCurrentException())
- let exc = newException(BuildFailed, "Build failed for package: " &
- pkgInfo.name)
- let (error, hint) = getOutputInfo(currentExc)
- exc.msg.add("\nDetails:\n" & error)
- exc.hint = hint
- raise exc
+ raise newException(BuildFailed, "Build failed for package: " &
+ pkgInfo.name)
- 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 saveNimbleMeta(pkgDestDir, url: string, filesInstalled: HashSet[string]) =
+ var nimblemeta = %{"url": %url}
+ nimblemeta["files"] = newJArray()
+ for file in filesInstalled:
+ nimblemeta["files"].add(%changeRoot(pkgDestDir, "", file))
+ writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta)
proc removePkgDir(dir: string, options: Options) =
## Removes files belonging to the package in ``dir``.
@@ -294,111 +498,40 @@ proc removePkgDir(dir: string, options: Options) =
if toSeq(walkDirRec(dir)).len == 0:
removeDir(dir)
else:
- display("Warning:", ("Cannot completely remove $1. Files not installed " &
- "by nimble are present.") % dir, Warning, HighPriority)
-
- if nimblemeta.hasKey("binaries"):
- # Remove binaries.
- for binary in nimblemeta["binaries"]:
- removeFile(options.getBinDir() / binary.str)
-
- # Search for an older version of the package we are removing.
- # So that we can reinstate its symlink.
- let (pkgName, _) = getNameVersion(dir)
- let pkgList = getInstalledPkgsMin(options.getPkgsDir(), options)
- var pkgInfo: PackageInfo
- if pkgList.findPkg((pkgName, newVRAny()), pkgInfo):
- pkgInfo = pkgInfo.toFullInfo(options)
- for bin in pkgInfo.bin:
- let symlinkDest = pkgInfo.getRealDir() / bin
- let symlinkFilename = options.getBinDir() / bin.extractFilename
- discard setupBinSymlink(symlinkDest, symlinkFilename, options)
- else:
- display("Warning:", ("Cannot completely remove $1. Binary symlinks may " &
- "have been left over in $2.") %
- [dir, options.getBinDir()])
+ echo("WARNING: Cannot completely remove " & dir &
+ ". Files not installed by nimble are present.")
except OSError, JsonParsingError:
- display("Warning", "Unable to read nimblemeta.json: " &
- getCurrentExceptionMsg(), Warning, HighPriority)
+ echo("Error: Unable to read nimblemeta.json: ", getCurrentExceptionMsg())
if not options.prompt("Would you like to COMPLETELY remove ALL files " &
"in " & dir & "?"):
- raise NimbleQuit(msg: "")
+ quit(QuitSuccess)
removeDir(dir)
-proc vcsRevisionInDir(dir: string): string =
- ## Returns current revision number of HEAD if dir is inside VCS, or nil in
- ## case of failure.
- var cmd = ""
- if dirExists(dir / ".git"):
- cmd = "git -C " & quoteShell(dir) & " rev-parse HEAD"
- elif dirExists(dir / ".hg"):
- cmd = "hg --cwd " & quoteShell(dir) & " id -i"
-
- if cmd.len > 0:
- try:
- let res = doCmdEx(cmd)
- if res.exitCode == 0:
- result = string(res.output).strip()
- except:
- discard
-
-proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
- url: string): tuple[
- deps: seq[PackageInfo],
- pkg: PackageInfo
- ] =
+proc installFromDir(dir: string, latest: bool, options: Options,
+ url: string): tuple[paths: seq[string], pkg: PackageInfo] =
## Returns where package has been installed to, together with paths
## to the packages this package depends on.
## The return value of this function is used by
## ``processDeps`` to gather a list of paths to pass to the nim compiler.
-
- # Handle pre-`install` hook.
- if not options.depsOnly:
- cd dir: # Make sure `execHook` executes the correct .nimble file.
- if not execHook(options, actionInstall, true):
- raise newException(NimbleError, "Pre-hook prevented further execution.")
-
- var pkgInfo = getPkgInfo(dir, options)
+ var pkgInfo = getPkgInfo(dir)
let realDir = pkgInfo.getRealDir()
let binDir = options.getBinDir()
- var depsOptions = options
- depsOptions.depsOnly = false
-
- # Overwrite the version if the requested version is "#head" or similar.
- if requestedVer.kind == verSpecial:
- pkgInfo.specialVersion = $requestedVer.spe
-
+ let pkgsDir = options.getPkgsDir()
# Dependencies need to be processed before the creation of the pkg dir.
- result.deps = processDeps(pkgInfo, depsOptions)
+ result.paths = processDeps(pkginfo, options)
- if options.depsOnly:
- result.pkg = pkgInfo
- return result
-
- display("Installing", "$1@$2" % [pkginfo.name, pkginfo.specialVersion],
- priority = HighPriority)
+ echo("Installing ", pkginfo.name, "-", pkginfo.version)
# Build before removing an existing package (if one exists). This way
# if the build fails then the old package will still be installed.
- if pkgInfo.bin.len > 0:
- 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)
+ if pkgInfo.bin.len > 0: buildFromDir(pkgInfo, result.paths, true)
- let pkgDestDir = pkgInfo.getPkgDest(options)
+ let versionStr = (if latest: "" else: '-' & pkgInfo.version)
+ let pkgDestDir = pkgsDir / (pkgInfo.name & versionStr)
if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
- let msg = "$1@$2 already exists. Overwrite?" %
- [pkgInfo.name, pkgInfo.specialVersion]
- if not options.prompt(msg):
- raise NimbleQuit(msg: "")
-
- # Remove reverse deps.
- let pkgInfo = getPkgInfo(pkgDestDir, options)
- options.nimbleData.removeRevDep(pkgInfo)
-
+ if not options.prompt(pkgInfo.name & versionStr &
+ " already exists. Overwrite?"):
+ quit(QuitSuccess)
removePkgDir(pkgDestDir, options)
# Remove any symlinked binaries
for bin in pkgInfo.bin:
@@ -406,115 +539,135 @@ proc installFromDir(dir: string, requestedVer: VersionRange, options: Options,
when defined(windows):
removeFile(binDir / bin.changeFileExt("cmd"))
removeFile(binDir / bin.changeFileExt(""))
+ # TODO: Remove this later.
+ # Remove .bat file too from previous installs.
+ removeFile(binDir / bin.changeFileExt("bat"))
else:
removeFile(binDir / bin)
+ ## Will contain a list of files which have been installed.
+ var filesInstalled: HashSet[string]
+
createDir(pkgDestDir)
- # Copy this package's files based on the preferences specified in PkgInfo.
- var filesInstalled = initHashSet[string]()
- iterInstallFiles(realDir, pkgInfo, options,
- proc (file: string) =
- createDir(changeRoot(realDir, pkgDestDir, file.splitFile.dir))
- let dest = changeRoot(realDir, pkgDestDir, file)
- filesInstalled.incl copyFileD(file, dest)
- )
-
- # Copy the .nimble file.
- let dest = changeRoot(pkgInfo.myPath.splitFile.dir, pkgDestDir,
- pkgInfo.myPath)
- filesInstalled.incl copyFileD(pkgInfo.myPath, dest)
-
- var binariesInstalled = initHashSet[string]()
if pkgInfo.bin.len > 0:
- # Make sure ~/.nimble/bin directory is created.
createDir(binDir)
+ # Copy all binaries and files that are not skipped
+ filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
+ pkgInfo)
# Set file permissions to +x for all binaries built,
# and symlink them on *nix OS' to $nimbleDir/bin/
for bin in pkgInfo.bin:
- if existsFile(pkgDestDir / bin):
- display("Warning:", ("Binary '$1' was already installed from source" &
- " directory. Will be overwritten.") % bin, Warning,
- MediumPriority)
+ if not existsFile(pkgDestDir / bin):
+ filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin),
+ pkgDestDir / bin)
- # Copy the binary file.
- filesInstalled.incl copyFileD(pkgInfo.getOutputDir(bin),
- pkgDestDir / bin)
-
- # Set up a symlink.
- let symlinkDest = pkgDestDir / bin
- let symlinkFilename = binDir / bin.extractFilename
- for filename in setupBinSymlink(symlinkDest, symlinkFilename, options):
- binariesInstalled.incl(filename)
-
- let vcsRevision = vcsRevisionInDir(realDir)
+ let currentPerms = getFilePermissions(pkgDestDir / bin)
+ setFilePermissions(pkgDestDir / bin, currentPerms + {fpUserExec})
+ let cleanBin = bin.extractFilename
+ when defined(unix):
+ # TODO: Verify that we are removing an old bin of this package, not
+ # some other package's binary!
+ if existsFile(binDir / bin): removeFile(binDir / cleanBin)
+ echo("Creating symlink: ", pkgDestDir / bin, " -> ", binDir / cleanBin)
+ createSymlink(pkgDestDir / bin, binDir / cleanBin)
+ elif defined(windows):
+ let dest = binDir / cleanBin.changeFileExt("cmd")
+ echo("Creating stub: ", pkgDestDir / bin, " -> ", dest)
+ var contents = ""
+ if options.config.chcp:
+ contents.add "chcp 65001\n"
+ contents.add "\"" & pkgDestDir / bin & "\" %*\n"
+ writeFile(dest, contents)
+ # For bash on Windows (Cygwin/Git bash).
+ let bashDest = dest.changeFileExt("")
+ echo("Creating Cygwin stub: ", pkgDestDir / bin, " -> ", bashDest)
+ writeFile(bashDest, "\"" & pkgDestDir / bin & "\" \"$@\"\n")
+ else:
+ {.error: "Sorry, your platform is not supported.".}
+ else:
+ filesInstalled = copyFilesRec(realDir, realDir, pkgDestDir, options,
+ pkgInfo)
# Save a nimblemeta.json file.
- saveNimbleMeta(pkgDestDir, url, vcsRevision, filesInstalled,
- binariesInstalled)
+ saveNimbleMeta(pkgDestDir, url, filesInstalled)
- # Save the nimble data (which might now contain reverse deps added in
- # processDeps).
- saveNimbleData(options)
-
- # Return the dependencies of this package (mainly for paths).
- result.deps.add pkgInfo
+ # Return the paths to the dependencies of this package.
+ result.paths.add pkgDestDir
result.pkg = pkgInfo
- result.pkg.isInstalled = true
- result.pkg.myPath = dest
- display("Success:", pkgInfo.name & " installed successfully.",
- Success, HighPriority)
+ echo(pkgInfo.name & " installed successfully.")
- # Run post-install hook now that package is installed. The `execHook` proc
- # executes the hook defined in the CWD, so we set it to where the package
- # has been installed.
- cd dest.splitFile.dir:
- discard execHook(options, actionInstall, false)
+proc getNimbleTempDir(): string =
+ ## Returns a path to a temporary directory.
+ ##
+ ## The returned path will be the same for the duration of the process but
+ ## different for different runs of it. You have to make sure to create it
+ ## first. In release builds the directory will be removed when nimble finishes
+ ## its work.
+ result = getTempDir() / "nimble_"
+ when defined(windows):
+ proc GetCurrentProcessId(): int32 {.stdcall, dynlib: "kernel32",
+ importc: "GetCurrentProcessId".}
+ result.add($GetCurrentProcessId())
+ else:
+ result.add($getpid())
+
+proc downloadPkg(url: string, verRange: VersionRange,
+ downMethod: DownloadMethod): (string, VersionRange) =
+ ## Downloads the repository as specified by ``url`` and ``verRange`` using
+ ## the download method specified.
+ ##
+ ## Returns the directory where it was downloaded and the concrete version
+ ## which was downloaded.
+ let downloadDir = (getNimbleTempDir() / getDownloadDirName(url, verRange))
+ createDir(downloadDir)
+ echo("Downloading ", url, " into ", downloadDir, " using ", downMethod, "...")
+ result = (downloadDir, doDownload(url, downloadDir, verRange, downMethod))
proc getDownloadInfo*(pv: PkgTuple, options: Options,
- doPrompt: bool): (DownloadMethod, string,
- Table[string, string]) =
+ doPrompt: bool): (DownloadMethod, string) =
if pv.name.isURL:
- let (url, metadata) = getUrlData(pv.name)
- return (checkUrlType(url), url, metadata)
+ return (checkUrlType(pv.name), pv.name)
else:
var pkg: Package
- if getPackage(pv.name, options, pkg):
- let (url, metadata) = getUrlData(pkg.url)
- return (pkg.downloadMethod.getDownloadMethod(), url, metadata)
+ if getPackage(pv.name, options.getNimbleDir() / "packages.json", pkg):
+ return (pkg.downloadMethod.getDownloadMethod(), pkg.url)
else:
- # If package is not found give the user a chance to refresh
+ # If package is not found give the user a chance to update
# package.json
if doPrompt and
- options.prompt(pv.name & " not found in any local packages.json, " &
+ options.prompt(pv.name & " not found in local packages.json, " &
"check internet for updated packages?"):
- refresh(options)
-
- # Once we've refreshed, try again, but don't prompt if not found
- # (as we've already refreshed and a failure means it really
- # isn't there)
- return getDownloadInfo(pv, options, false)
+ update(options)
+ return getDownloadInfo(pv, options, doPrompt)
else:
raise newException(NimbleError, "Package not found.")
proc install(packages: seq[PkgTuple],
options: Options,
- doPrompt = true): tuple[deps: seq[PackageInfo], pkg: PackageInfo] =
+ doPrompt = true): tuple[paths: seq[string], pkg: PackageInfo] =
if packages == @[]:
- result = installFromDir(getCurrentDir(), newVRAny(), options, "")
+ result = installFromDir(getCurrentDir(), false, options, "")
else:
+ # If packages.json is not present ask the user if they want to download it.
+ if not existsFile(options.getNimbleDir / "packages.json"):
+ if doPrompt and
+ options.prompt("Local packages.json not found, download it from " &
+ "internet?"):
+ update(options)
+ else:
+ quit("Please run nimble update.", QuitFailure)
+
# Install each package.
for pv in packages:
- let (meth, url, metadata) = getDownloadInfo(pv, options, doPrompt)
- let subdir = metadata.getOrDefault("subdir")
- let (downloadDir, downloadVersion) =
- downloadPkg(url, pv.ver, meth, subdir, options)
+ let (meth, url) = getDownloadInfo(pv, options, doPrompt)
+ let (downloadDir, downloadVersion) = downloadPkg(url, pv.ver, meth)
try:
- result = installFromDir(downloadDir, pv.ver, options, url)
+ result = installFromDir(downloadDir, false, options, url)
except BuildFailed:
# The package failed to build.
# Check if we tried building a tagged version of the package.
- let headVer = getHeadName(meth)
+ let headVer = parseVersionRange("#" & getHeadName(meth))
if pv.ver.kind != verSpecial and downloadVersion != headVer:
# If we tried building a tagged version of the package then
# ask the user whether they want to try building #head.
@@ -523,8 +676,8 @@ proc install(packages: seq[PkgTuple],
" like to try installing '$1@#head' (latest unstable)?") %
[pv.name, $downloadVersion])
if promptResult:
- let toInstall = @[(pv.name, headVer.toVersionRange())]
- result = install(toInstall, options, doPrompt)
+
+ result = install(@[(pv.name, headVer)], options, doPrompt)
else:
raise newException(BuildFailed,
"Aborting installation due to build failure")
@@ -532,49 +685,34 @@ proc install(packages: seq[PkgTuple],
raise
proc build(options: Options) =
- var pkgInfo = getPkgInfo(getCurrentDir(), 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 pkgInfo = getPkgInfo(getCurrentDir())
+ let paths = processDeps(pkginfo, options)
+ buildFromDir(pkgInfo, paths, false)
-proc execBackend(pkgInfo: PackageInfo, options: Options) =
- let
- bin = options.getCompilationBinary(pkgInfo).get()
- binDotNim = bin.addFileExt("nim")
- if bin == "":
- raise newException(NimbleError, "You need to specify a file.")
+proc compile(options: Options) =
+ var pkgInfo = getPkgInfo(getCurrentDir())
+ let paths = processDeps(pkginfo, options)
+ let realDir = pkgInfo.getRealDir()
- if not (fileExists(bin) or fileExists(binDotNim)):
- raise newException(NimbleError,
- "Specified file, " & bin & " or " & binDotNim & ", does not exist.")
-
- var pkgInfo = getPkgInfo(getCurrentDir(), options)
- nimScriptHint(pkgInfo)
- 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():
- args.add("\"" & option & "\" ")
+ for path in paths: args.add("--path:\"" & path & "\" ")
+ for option in options.action.compileOptions:
+ args.add(option & " ")
+ let bin = options.action.file
let backend =
if options.action.backend.len > 0:
options.action.backend
else:
pkgInfo.backend
- if options.action.typ == actionCompile:
- display("Compiling", "$1 (from package $2) using $3 backend" %
- [bin, pkgInfo.name, backend], priority = HighPriority)
- else:
- display("Generating", ("documentation for $1 (from package $2) using $3 " &
- "backend") % [bin, pkgInfo.name, backend], priority = HighPriority)
- doCmd("\"" & getNimBin() & "\" $# --noNimblePath $# $# \"$#\"" %
- [backend, nimblePkgVersion, args, bin], showOutput = true)
- display("Success:", "Execution finished", Success, HighPriority)
+ if bin == "":
+ raise newException(NimbleError, "You need to specify a file to compile.")
+
+ echo("Compiling ", bin, " (", pkgInfo.name, ") using ", backend,
+ " backend...")
+ doCmd(getNimBin() & " $# --noBabelPath $# \"$#\"" %
+ [backend, args, bin])
proc search(options: Options) =
## Searches for matches in ``options.action.search``.
@@ -583,62 +721,59 @@ proc search(options: Options) =
assert options.action.typ == actionSearch
if options.action.search == @[]:
raise newException(NimbleError, "Please specify a search string.")
- if needsRefresh(options):
- raise newException(NimbleError, "Please run nimble refresh.")
- let pkgList = getPackageList(options)
+ if not existsFile(options.getNimbleDir() / "packages.json"):
+ raise newException(NimbleError, "Please run nimble update.")
+ let pkgList = getPackageList(options.getNimbleDir() / "packages.json")
var found = false
- template onFound {.dirty.} =
+ template onFound: stmt =
echoPackage(pkg)
- if pkg.alias.len == 0 and options.queryVersions:
+ if options.queryVersions:
echoPackageVersions(pkg)
echo(" ")
found = true
- break forPkg
+ break
for pkg in pkgList:
- block forPkg:
- for word in options.action.search:
- # Search by name.
- if word.toLower() in pkg.name.toLower():
+ for word in options.action.search:
+ # Search by name.
+ if word.toLower() in pkg.name.toLower():
+ onFound()
+ # Search by tag.
+ for tag in pkg.tags:
+ if word.toLower() in tag.toLower():
onFound()
- # Search by tag.
- for tag in pkg.tags:
- if word.toLower() in tag.toLower():
- onFound()
if not found:
- display("Error", "No package found.", Error, HighPriority)
+ echo("No package found.")
proc list(options: Options) =
- if needsRefresh(options):
- raise newException(NimbleError, "Please run nimble refresh.")
- let pkgList = getPackageList(options)
+ if not existsFile(options.getNimbleDir() / "packages.json"):
+ raise newException(NimbleError, "Please run nimble update.")
+ let pkgList = getPackageList(options.getNimbleDir() / "packages.json")
for pkg in pkgList:
echoPackage(pkg)
- if pkg.alias.len == 0 and options.queryVersions:
+ if options.queryVersions:
echoPackageVersions(pkg)
echo(" ")
proc listInstalled(options: Options) =
- var h = initOrderedTable[string, seq[string]]()
- let pkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
+ var h = initTable[string, seq[string]]()
+ let pkgs = getInstalledPkgs(options.getPkgsDir())
for x in pkgs.items():
let
pName = x.pkginfo.name
- pVer = x.pkginfo.specialVersion
+ pVer = x.pkginfo.version
if not h.hasKey(pName): h[pName] = @[]
var s = h[pName]
add(s, pVer)
h[pName] = s
-
- h.sort(proc (a, b: (string, seq[string])): int = cmpIgnoreCase(a[0], b[0]))
for k in keys(h):
echo k & " [" & h[k].join(", ") & "]"
type VersionAndPath = tuple[version: Version, path: string]
proc listPaths(options: Options) =
- ## Loops over the specified packages displaying their installed paths.
+ ## Loops over installing packages displaying their installed paths.
##
## If there are several packages installed, only the last one (the version
## listed in the packages.json) will be displayed. If any package name is not
@@ -646,526 +781,147 @@ proc listPaths(options: Options) =
## but at the end quits with a non zero exit error.
##
## On success the proc returns normally.
- cli.setSuppressMessages(true)
assert options.action.typ == actionPath
-
- if options.action.packages.len == 0:
- raise newException(NimbleError, "A package name needs to be specified")
-
+ assert(not options.action.packages.isNil)
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():
+ for kind, path in walkDir(options.getPkgsDir):
+ if kind != pcDir or not path.startsWith(options.getPkgsDir / name):
+ continue
+
let
- pName = x.pkginfo.name
- pVer = x.pkginfo.specialVersion
- if name == pName:
+ babelFile = path / name.addFileExt("babel")
+ nimbleFile = path / name.addFileExt("nimble")
+ hasSpec = nimbleFile.existsFile or babelFile.existsFile
+ if hasSpec:
+ var pkgInfo = getPkgInfo(path)
var v: VersionAndPath
- v.version = newVersion(pVer)
- v.path = x.pkginfo.getRealDir()
+ v.version = newVersion(pkgInfo.version)
+ v.path = options.getPkgsDir / (pkgInfo.name & '-' & pkgInfo.version)
installed.add(v)
+ else:
+ echo "Warning: No .nimble file found for ", path
if installed.len > 0:
- sort(installed, cmp[VersionAndPath], Descending)
- # The output for this command is used by tools so we do not use display().
+ sort(installed, system.cmp[VersionAndPath], Descending)
echo installed[0].path
else:
- display("Warning:", "Package '$1' is not installed" % name, Warning,
- MediumPriority)
+ echo "Warning: Package '" & name & "' not installed"
errors += 1
if errors > 0:
raise newException(NimbleError,
"At least one of the specified packages was not found")
-proc join(x: seq[PkgTuple]; y: string): string =
- if x.len == 0: return ""
- result = x[0][0] & " " & $x[0][1]
- for i in 1 ..< x.len:
- result.add y
- result.add x[i][0] & " " & $x[i][1]
-
-proc getPackageByPattern(pattern: string, options: Options): PackageInfo =
- ## Search for a package file using multiple strategies.
- if pattern == "":
- # Not specified - using current directory
- result = getPkgInfo(os.getCurrentDir(), options)
- elif pattern.splitFile.ext == ".nimble" and pattern.existsFile:
- # project file specified
- result = getPkgInfoFromFile(pattern, options)
- elif pattern.existsDir:
- # project directory specified
- result = getPkgInfo(pattern, options)
- else:
- # Last resort - attempt to read as package identifier
- let packages = getInstalledPkgsMin(options.getPkgsDir(), options)
- let identTuple = parseRequires(pattern)
- var skeletonInfo: PackageInfo
- if not findPkg(packages, identTuple, skeletonInfo):
- raise newException(NimbleError,
- "Specified package not found"
- )
- result = getPkgInfoFromFile(skeletonInfo.myPath, options)
-
-proc dump(options: Options) =
- cli.setSuppressMessages(true)
- let p = getPackageByPattern(options.action.projName, options)
- echo "name: ", p.name.escape
- echo "version: ", p.version.escape
- echo "author: ", p.author.escape
- echo "desc: ", p.description.escape
- echo "license: ", p.license.escape
- echo "skipDirs: ", p.skipDirs.join(", ").escape
- echo "skipFiles: ", p.skipFiles.join(", ").escape
- echo "skipExt: ", p.skipExt.join(", ").escape
- echo "installDirs: ", p.installDirs.join(", ").escape
- echo "installFiles: ", p.installFiles.join(", ").escape
- echo "installExt: ", p.installExt.join(", ").escape
- echo "requires: ", p.requires.join(", ").escape
- echo "bin: ", p.bin.join(", ").escape
- echo "binDir: ", p.binDir.escape
- echo "srcDir: ", p.srcDir.escape
- 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")
+ echo("Initializing new Nimble project!")
+ var
+ pkgName, fName: string = ""
+ outFile: File
- # Determine the package name.
- let pkgName =
- if options.action.projName != "":
- options.action.projName
- else:
- os.getCurrentDir().splitPath.tail.toValidPackageName()
+ if (options.action.projName != ""):
+ pkgName = options.action.projName
+ fName = pkgName & ".nimble"
+ if (existsFile(os.getCurrentDir() / fName)):
+ raise newException(NimbleError, "Already have a nimble file.")
+ else:
+ echo("Enter a project name for this (blank to use working directory), " &
+ "Ctrl-C to abort:")
+ pkgName = readline(stdin)
+ if (pkgName == ""):
+ pkgName = os.getCurrentDir().splitPath.tail
+ if (pkgName == ""):
+ raise newException(NimbleError, "Could not get default file path.")
+ fName = pkgName & ".nimble"
- # Validate the package name.
- validatePackageName(pkgName)
+ # Now need to write out .nimble file with projName and other details
- # Determine the package root.
- let pkgRoot =
- if pkgName == os.getCurrentDir().splitPath.tail:
- os.getCurrentDir()
- else:
- os.getCurrentDir() / pkgName
+ if (not existsFile(os.getCurrentDir() / fName) and
+ open(f=outFile, filename = fName, mode = fmWrite)):
+ outFile.writeln("[Package]")
+ outFile.writeln("name = \"" & pkgName & "\"")
+ outFile.writeln("version = \"0.1.0\"")
+ outFile.writeln("author = \"Anonymous\"")
+ outFile.writeln("description = \"New Nimble project for Nim\"")
+ outFile.writeln("license = \"MIT\"")
+ outFile.writeln("")
+ outFile.writeln("[Deps]")
+ outFile.writeln("Requires: \"nim >= 0.10.0\"")
+ close(outFile)
- let nimbleFile = (pkgRoot / pkgName).changeFileExt("nimble")
-
- if existsFile(nimbleFile):
- let errMsg = "Nimble file already exists: $#" % nimbleFile
- raise newException(NimbleError, errMsg)
-
- if options.forcePrompts != forcePromptYes:
- display(
- "Info:",
- "Package initialisation requires info which could not be inferred.\n" &
- "Default values are shown in square brackets, press\n" &
- "enter to use them.",
- priority = HighPriority
- )
- display("Using", "$# for new package name" % [pkgName.escape()],
- priority = HighPriority)
-
- # Determine author by running an external command
- proc getAuthorWithCmd(cmd: string): string =
- let (name, exitCode) = doCmdEx(cmd)
- if exitCode == QuitSuccess and name.len > 0:
- result = name.strip()
- display("Using", "$# for new package author" % [result],
- priority = HighPriority)
-
- # Determine package author via git/hg or asking
- proc getAuthor(): string =
- if findExe("git") != "":
- result = getAuthorWithCmd("git config --global user.name")
- elif findExe("hg") != "":
- result = getAuthorWithCmd("hg config ui.username")
- if result.len == 0:
- result = promptCustom(options, "Your name?", "Anonymous")
- let pkgAuthor = getAuthor()
-
- # Declare the src/ directory
- let pkgSrcDir = "src"
- display("Using", "$# for new package source directory" % [pkgSrcDir.escape()],
- priority = HighPriority)
-
- # Determine the type of package
- let pkgType = promptList(
- options,
- """Package type?
-Library - provides functionality for other packages.
-Binary - produces an executable for the end-user.
-Hybrid - combination of library and binary
-
-For more information see https://goo.gl/cm2RX5""",
- ["library", "binary", "hybrid"]
- )
-
- # Ask for package version.
- let pkgVersion = promptCustom(options, "Initial version of package?", "0.1.0")
- validateVersion(pkgVersion)
-
- # Ask for description
- let pkgDesc = promptCustom(options, "Package description?",
- "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/.
-""", [
- "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"
- ])
-
- 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
- )
-
- # Create a git or hg repo in the new nimble project.
- if vcsBin != "":
- let cmd = fmt"cd {pkgRoot} && {vcsBin} init"
- let ret: tuple[output: string, exitCode: int] = execCmdEx(cmd)
- if ret.exitCode != 0: quit ret.output
-
- var ignoreFile = if vcsBin == "git": ".gitignore" else: ".hgignore"
- var fd = open(joinPath(pkgRoot, ignoreFile), fmWrite)
- fd.write(pkgName & "\n")
- fd.close()
-
- display("Success:", "Package $# created successfully" % [pkgName], Success,
- HighPriority)
+ else:
+ raise newException(NimbleError, "Unable to open file " & fName &
+ " for writing: " & osErrorMsg(osLastError()))
proc uninstall(options: Options) =
if options.action.packages.len == 0:
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],
- priority = HighPriority)
- let installedPkgs = getInstalledPkgsMin(options.getPkgsDir(), options)
+ echo("Looking for ", pkgTup.name, " (", $pkgTup.ver, ")...")
+ let installedPkgs = getInstalledPkgs(options.getPkgsDir())
var pkgList = findAllPkgs(installedPkgs, pkgTup)
if pkgList.len == 0:
raise newException(NimbleError, "Package not found")
- display("Checking", "reverse dependencies", priority = HighPriority)
+ echo("Checking reverse dependencies...")
+ var errors: seq[string] = @[]
for pkg in pkgList:
# Check whether any packages depend on the ones the user is trying to
# uninstall.
- if options.uninstallRevDeps:
- getAllRevDeps(options, pkg, pkgsToDelete)
- else:
- let
- revDeps = getRevDeps(options, pkg)
+ let thisPkgsDep = options.nimbleData["reverseDeps"]{pkg.name}{pkg.version}
+ if not thisPkgsDep.isNil:
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"
-
- if len(revDeps - pkgsToDelete) > 0:
- display("Cannot", "uninstall $1 ($2) because $3" %
- [pkgTup.name, pkg.specialVersion, reason], Warning, HighPriority)
+ if thisPkgsDep.len == 1:
+ reason = thisPkgsDep[0]["name"].str &
+ " (" & thisPkgsDep[0]["version"].str & ") depends on it"
else:
- pkgsToDelete.incl pkg
+ for i in 0 .. 0:
- if "nim" in pkgInfo.skipExt:
- raiseNimbleError("Cannot develop packages that are binaries only.")
-
- display("Warning:", "This package's binaries will not be compiled " &
- "nor symlinked for development.", Warning, HighPriority)
-
- # Overwrite the version to #head always.
- pkgInfo.specialVersion = "#head"
-
- # Dependencies need to be processed before the creation of the pkg dir.
- discard processDeps(pkgInfo, options)
-
- # This is similar to the code in `installFromDir`, except that we
- # *consciously* not worry about the package's binaries.
- let pkgDestDir = pkgInfo.getPkgDest(options)
- if existsDir(pkgDestDir) and existsFile(pkgDestDir / "nimblemeta.json"):
- let msg = "$1@$2 already exists. Overwrite?" %
- [pkgInfo.name, pkgInfo.specialVersion]
- if not options.prompt(msg):
- raise NimbleQuit(msg: "")
- removePkgDir(pkgDestDir, options)
-
- createDir(pkgDestDir)
- # The .nimble-link file contains the path to the real .nimble file,
- # and a secondary path to the source directory of the package.
- # The secondary path is necessary so that the package's .nimble file doesn't
- # need to be read. This will mean that users will need to re-run
- # `nimble develop` if they change their `srcDir` but I think it's a worthy
- # compromise.
- let nimbleLinkPath = pkgDestDir / pkgInfo.name.addFileExt("nimble-link")
- let nimbleLink = NimbleLink(
- nimbleFilePath: pkgInfo.myPath,
- packageDir: pkgInfo.getRealDir()
- )
- writeNimbleLink(nimbleLinkPath, nimbleLink)
-
- # Save a nimblemeta.json file.
- saveNimbleMeta(pkgDestDir, dir, vcsRevisionInDir(dir), nimbleLinkPath)
-
- # Save the nimble data (which might now contain reverse deps added in
- # processDeps).
- saveNimbleData(options)
-
- display("Success:", (pkgInfo.name & " linked successfully to '$1'.") %
- dir, Success, HighPriority)
-
- # Execute the post-develop hook.
- cd dir:
- discard execHook(options, actionDevelop, false)
-
-proc develop(options: Options) =
- if options.action.packages == @[]:
- developFromDir(getCurrentDir(), options)
- else:
- # Install each package.
- for pv in options.action.packages:
- let name =
- if isURL(pv.name):
- parseUri(pv.name).path
- else:
- pv.name
- let downloadDir = getCurrentDir() / name
- if dirExists(downloadDir):
- let msg = "Cannot clone into '$1': directory exists." % downloadDir
- let hint = "Remove the directory, or run this command somewhere else."
- raiseNimbleError(msg, hint)
-
- 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)
- 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
-
- 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}:
- var optsCopy = options.briefClone()
- optsCopy.action = 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)
-
- 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)
-
-proc check(options: Options) =
- ## Validates a package in the current working directory.
- let nimbleFile = findNimbleFile(getCurrentDir(), true)
- var error: ValidationError
- var pkgInfo: PackageInfo
- var validationResult = false
- try:
- validationResult = validate(nimbleFile, options, error, pkgInfo)
- except:
- raiseNimbleError("Could not validate package:\n" & getCurrentExceptionMsg())
-
- if validationResult:
- display("Success:", pkgInfo.name & " is valid!", Success, HighPriority)
- else:
- display("Error:", error.msg, Error, HighPriority)
- display("Hint:", error.hint, Warning, HighPriority)
- display("Failure:", "Validation failed", Error, HighPriority)
- quit(QuitFailure)
-
-proc 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) =
- if options.showHelp:
- writeHelp()
- if options.showVersion:
- writeVersion()
-
+proc doAction(options: Options) =
if not existsDir(options.getNimbleDir()):
createDir(options.getNimbleDir())
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)
+ of actionUpdate:
+ update(options)
of actionInstall:
- let (_, pkgInfo) = install(options.action.packages, options)
- if options.action.packages.len == 0:
- nimScriptHint(pkgInfo)
- if pkgInfo.foreignDeps.len > 0:
- display("Hint:", "This package requires some external dependencies.",
- Warning, HighPriority)
- display("Hint:", "To install them you may be able to run:",
- Warning, HighPriority)
- for i in 0.. 0:
- displayTip()
- display("Error:", error, Error, HighPriority)
- if hint.len > 0:
- display("Hint:", hint, Warning, HighPriority)
- quit(1)
+ parseCmdLine().doAction()
+ except NimbleError:
+ quit("FAILURE: " & getCurrentExceptionMsg())
+ finally:
+ removeDir(getNimbleTempDir())
+ else:
+ parseCmdLine().doAction()
diff --git a/src/nimble.nim.cfg b/src/nimble.nim.cfg
deleted file mode 100644
index e459055..0000000
--- a/src/nimble.nim.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
---path:"$lib/packages/docutils"
-#--noNimblePath
---path:"$nim/"
---path:"./vendor/nim"
--d:ssl
--d:nimcore # Enable 'gorge' in Nim's VM. See https://github.com/nim-lang/Nim/issues/8096
diff --git a/src/nimble.nimrod.cfg b/src/nimble.nimrod.cfg
new file mode 100644
index 0000000..521e21d
--- /dev/null
+++ b/src/nimble.nimrod.cfg
@@ -0,0 +1 @@
+-d:ssl
diff --git a/src/nimblepkg/cli.nim b/src/nimblepkg/cli.nim
deleted file mode 100644
index 3afda35..0000000
--- a/src/nimblepkg/cli.nim
+++ /dev/null
@@ -1,293 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-#
-# Rough rules/philosophy for the messages that Nimble displays are the following:
-# - Green is only shown when the requested operation is successful.
-# - Blue can be used to emphasise certain keywords, for example actions such
-# as "Downloading" or "Reading".
-# - Red is used when the requested operation fails with an error.
-# - Yellow is used for warnings.
-#
-# - Dim for LowPriority.
-# - Bright for HighPriority.
-# - Normal for MediumPriority.
-
-import terminal, sets, strutils
-import version
-
-when not declared(initHashSet):
- import common
-
-type
- CLI* = ref object
- level: Priority
- warnings: HashSet[(string, string)]
- suppressionCount: int ## Amount of messages which were not shown.
- showColor: bool ## Whether messages should be colored.
- suppressMessages: bool ## Whether Warning, Message and Success messages
- ## should be suppressed, useful for
- ## commands like `dump` whose output should be
- ## machine readable.
-
- Priority* = enum
- DebugPriority, LowPriority, MediumPriority, HighPriority
-
- DisplayType* = enum
- Error, Warning, Message, Success
-
- ForcePrompt* = enum
- dontForcePrompt, forcePromptYes, forcePromptNo
-
-const
- longestCategory = len("Downloading")
- foregrounds: array[Error .. Success, ForegroundColor] =
- [fgRed, fgYellow, fgCyan, fgGreen]
- styles: array[DebugPriority .. HighPriority, set[Style]] =
- [{styleDim}, {styleDim}, {}, {styleBright}]
-
-
-proc newCLI(): CLI =
- result = CLI(
- level: HighPriority,
- warnings: initHashSet[(string, string)](),
- suppressionCount: 0,
- showColor: true,
- suppressMessages: false
- )
-
-var globalCLI = newCLI()
-
-
-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)
-
- # Display the category.
- let text = "$1$2 " % [spaces(offset), category]
- if globalCLI.showColor:
- if priority != DebugPriority:
- setForegroundColor(stdout, foregrounds[displayType])
- writeStyled(text, styles[priority])
- resetAttributes()
- else:
- stdout.write(text)
-
-proc displayLine(category, line: string, displayType: DisplayType,
- priority: Priority) =
- if isSuppressed(displayType):
- return
-
- displayCategory(category, displayType, priority)
-
- # Display the message.
- echo(line)
-
-proc display*(category, msg: string, displayType = Message,
- priority = MediumPriority) =
- # Multiple warnings containing the same messages should not be shown.
- let warningPair = (category, msg)
- if displayType == Warning:
- if warningPair in globalCLI.warnings:
- return
- else:
- globalCLI.warnings.incl(warningPair)
-
- # Suppress this message if its priority isn't high enough.
- # TODO: Per-priority suppression counts?
- if priority < globalCLI.level:
- if priority != DebugPriority:
- globalCLI.suppressionCount.inc
- return
-
- # Display each line in the message.
- var i = 0
- for line in msg.splitLines():
- if len(line) == 0: continue
- displayLine(if i == 0: category else: "...", line, displayType, priority)
- i.inc
-
-proc displayDebug*(category, msg: string) =
- ## Convenience for displaying debug messages.
- display(category, msg, priority = DebugPriority)
-
-proc displayDebug*(msg: string) =
- ## Convenience for displaying debug messages with a default category.
- displayDebug("Debug:", msg)
-
-proc displayTip*() =
- ## Called just before Nimble exits. Shows some tips for the user, for example
- ## the amount of messages that were suppressed and how to show them.
- if globalCLI.suppressionCount > 0:
- let msg = "$1 messages have been suppressed, use --verbose to show them." %
- $globalCLI.suppressionCount
- display("Tip:", msg, Warning, HighPriority)
-
-proc prompt*(forcePrompts: ForcePrompt, question: string): bool =
- case forcePrompts
- of forcePromptYes:
- display("Prompt:", question & " -> [forced yes]", Warning, HighPriority)
- return true
- of forcePromptNo:
- display("Prompt:", question & " -> [forced no]", Warning, HighPriority)
- return false
- of dontForcePrompt:
- displayLine("Prompt:", question & " [y/N]", Warning, HighPriority)
- displayCategory("Answer:", Warning, HighPriority)
- let yn = stdin.readLine()
- case yn.normalize
- of "y", "yes":
- return true
- of "n", "no":
- return false
- else:
- return false
-
-proc promptCustom*(forcePrompts: ForcePrompt, question, default: string): string =
- case forcePrompts:
- of forcePromptYes:
- display("Prompt:", question & " -> [forced " & default & "]", Warning,
- HighPriority)
- return default
- else:
- if default == "":
- display("Prompt:", question, Warning, HighPriority)
- displayCategory("Answer:", Warning, HighPriority)
- let user = stdin.readLine()
- if user.len == 0: return promptCustom(forcePrompts, question, default)
- else: return user
- else:
- display("Prompt:", question & " [" & default & "]", Warning, HighPriority)
- displayCategory("Answer:", Warning, HighPriority)
- let user = stdin.readLine()
- if user == "": return default
- else: return user
-
-proc promptCustom*(question, default: string): string =
- return promptCustom(dontForcePrompt, question, default)
-
-proc 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.. [forced " & result & "]", Warning,
- HighPriority)
- else:
- if isatty(stdout):
- return promptListInteractive(question, args)
- else:
- return promptListFallback(question, args)
-
-proc setVerbosity*(level: Priority) =
- globalCLI.level = level
-
-proc setShowColor*(val: bool) =
- globalCLI.showColor = val
-
-proc setSuppressMessages*(val: bool) =
- globalCLI.suppressMessages = val
-
-when isMainModule:
- display("Reading", "config file at /Users/dom/.config/nimble/nimble.ini",
- priority = LowPriority)
-
- display("Reading", "official package list",
- priority = LowPriority)
-
- display("Downloading", "daemonize v0.0.2 using Git",
- priority = HighPriority)
-
- display("Warning", "dashes in package names will be deprecated", Warning,
- priority = HighPriority)
-
- display("Error", """Unable to read package info for /Users/dom/.nimble/pkgs/nimble-0.7.11
-Reading as ini file failed with:
- Invalid section: .
-Evaluating as NimScript file failed with:
- Users/dom/.nimble/pkgs/nimble-0.7.11/nimble.nimble(3, 23) Error: cannot open 'src/nimblepkg/common'.
-""", Error, HighPriority)
diff --git a/src/nimblepkg/common.nim b/src/nimblepkg/common.nim
deleted file mode 100644
index ab83175..0000000
--- a/src/nimblepkg/common.nim
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-#
-# Various miscellaneous common types reside here, to avoid problems with
-# recursive imports
-
-when not defined(nimscript):
- import sets
-
- import version
-
- type
- BuildFailed* = object of NimbleError
-
- PackageInfo* = object
- myPath*: string ## The path of this .nimble file
- isNimScript*: bool ## Determines if this pkg info was read from a nims file
- isMinimal*: bool
- isInstalled*: bool ## Determines if the pkg this info belongs to is installed
- isLinked*: bool ## Determines if the pkg this info belongs to has been linked via `develop`
- postHooks*: HashSet[string] ## Useful to know so that Nimble doesn't execHook unnecessarily
- preHooks*: HashSet[string]
- name*: string
- ## 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.
- version*: string
- specialVersion*: string ## Either `myVersion` or a special version such as #head.
- author*: string
- description*: string
- license*: string
- skipDirs*: seq[string]
- skipFiles*: seq[string]
- skipExt*: seq[string]
- installDirs*: seq[string]
- installFiles*: seq[string]
- installExt*: seq[string]
- requires*: seq[PkgTuple]
- bin*: seq[string]
- binDir*: string
- srcDir*: string
- backend*: string
- foreignDeps*: seq[string]
-
- ## Same as quit(QuitSuccess), but allows cleanup.
- NimbleQuit* = ref object of Exception
-
- proc raiseNimbleError*(msg: string, hint = "") =
- var exc = newException(NimbleError, msg)
- exc.hint = hint
- raise exc
-
- proc getOutputInfo*(err: ref NimbleError): (string, string) =
- var error = ""
- var hint = ""
- error = err.msg
- when not defined(release):
- let stackTrace = getStackTrace(err)
- error = stackTrace & "\n\n" & error
- if not err.isNil:
- hint = err.hint
-
- return (error, hint)
-
-const
- nimbleVersion* = "0.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)
diff --git a/src/nimblepkg/config.nim b/src/nimblepkg/config.nim
index c4a48fc..244509c 100644
--- a/src/nimblepkg/config.nim
+++ b/src/nimblepkg/config.nim
@@ -1,49 +1,22 @@
# 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
-import version, cli
+import tools, version, nimbletypes
type
Config* = object
nimbleDir*: string
chcp*: bool # Whether to change the code page in .cmd files on Win.
- packageLists*: Table[string, PackageList] ## Names -> packages.json files
- cloneUsingHttps*: bool # Whether to replace git:// for https://
- httpProxy*: Uri # Proxy for package list downloads.
- nimLibPrefix*: string # Nim stdlib prefix.
-
- PackageList* = object
- name*: string
- urls*: seq[string]
- path*: string
+
proc initConfig(): Config =
- result.nimbleDir = getHomeDir() / ".nimble"
-
- result.httpProxy = initUri()
+ if getNimrodVersion() > newVersion("0.9.6"):
+ result.nimbleDir = getHomeDir() / ".nimble"
+ else:
+ result.nimbleDir = getHomeDir() / ".babel"
result.chcp = true
- result.cloneUsingHttps = true
-
- result.packageLists = initTable[string, PackageList]()
- let defaultPkgList = PackageList(name: "Official", urls: @[
- "https://github.com/nim-lang/packages/raw/master/packages.json",
- "http://irclogs.nim-lang.org/packages.json",
- "http://nim-lang.org/nimble/packages.json"
- ])
- result.packageLists["official"] = defaultPkgList
-
- result.nimLibPrefix = ""
-
-proc initPackageList(): PackageList =
- result.name = ""
- result.urls = @[]
- result.path = ""
-
-proc addCurrentPkgList(config: var Config, currentPackageList: PackageList) =
- if currentPackageList.name.len > 0:
- config.packageLists[currentPackageList.name.normalize] = currentPackageList
proc parseConfig*(): Config =
result = initConfig()
@@ -52,38 +25,21 @@ proc parseConfig*(): Config =
var f = newFileStream(confFile, fmRead)
if f == nil:
# Try the old deprecated babel.ini
- # TODO: This can be removed.
confFile = getConfigDir() / "babel" / "babel.ini"
f = newFileStream(confFile, fmRead)
if f != nil:
- display("Warning", "Using deprecated config file at " & confFile,
- Warning, HighPriority)
+ echo("[Warning] Using deprecated config file at ", confFile)
+
if f != nil:
- display("Reading", "config file at " & confFile, priority = LowPriority)
+ echo("Reading from config file at ", confFile)
var p: CfgParser
open(p, f, confFile)
- var currentSection = ""
- var currentPackageList = initPackageList()
while true:
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)
break
- of cfgSectionStart:
- addCurrentPkgList(result, currentPackageList)
- currentSection = e.section
- case currentSection.normalize
- of "packagelist":
- currentPackageList = initPackageList()
- else:
- raise newException(NimbleError, "Unable to parse config file:" &
- " Unknown section: " & e.key)
+ of cfgSectionStart: discard
of cfgKeyValuePair, cfgOption:
case e.key.normalize
of "nimbledir":
@@ -92,30 +48,6 @@ proc parseConfig*(): Config =
result.nimbleDir = e.value
of "chcp":
result.chcp = parseBool(e.value)
- of "cloneusinghttps":
- result.cloneUsingHttps = parseBool(e.value)
- of "httpproxy":
- result.httpProxy = parseUri(e.value)
- of "name":
- case currentSection.normalize
- of "packagelist":
- currentPackageList.name = e.value
- else: assert false
- of "url":
- case currentSection.normalize
- of "packagelist":
- currentPackageList.urls.add(e.value)
- else: assert false
- of "path":
- case currentSection.normalize
- of "packagelist":
- if currentPackageList.path != "":
- raise newException(NimbleError, "Attempted to specify more than one `path` for the same package list.")
- else:
- currentPackageList.path = e.value
- else: assert false
- of "nimlibprefix":
- result.nimLibPrefix = e.value
else:
raise newException(NimbleError, "Unable to parse config file:" &
" Unknown key: " & e.key)
diff --git a/src/nimblepkg/download.nim b/src/nimblepkg/download.nim
index 3bbfa25..a7ebd34 100644
--- a/src/nimblepkg/download.nim
+++ b/src/nimblepkg/download.nim
@@ -1,16 +1,15 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# 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
+import parseutils, os, osproc, strutils, tables, pegs
+
+import packageinfo, version, tools, nimbletypes
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)
@@ -93,10 +91,8 @@ proc getTagsListRemote*(url: string, meth: DownloadMethod): seq[string] =
raise newException(OSError, "Unable to query remote tags for " & url &
". Git returned: " & output)
for i in output.splitLines():
- let refStart = i.find("refs/tags/")
- # git outputs warnings, empty lines, etc
- if refStart == -1: continue
- let start = refStart+"refs/tags/".len
+ if i == "": continue
+ let start = i.find("refs/tags/")+"refs/tags/".len
let tag = i[start .. i.len-1]
if not tag.endswith("^{}"): result.add(tag)
@@ -104,21 +100,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
@@ -127,12 +116,12 @@ proc getDownloadMethod*(meth: string): DownloadMethod =
else:
raise newException(NimbleError, "Invalid download method: " & meth)
-proc getHeadName*(meth: DownloadMethod): Version =
+proc getHeadName*(meth: DownloadMethod): string =
## Returns the name of the download method specific head. i.e. for git
## it's ``head`` for hg it's ``tip``.
case meth
- of DownloadMethod.git: newVersion("#head")
- of DownloadMethod.hg: newVersion("#tip")
+ of DownloadMethod.git: "head"
+ of DownloadMethod.hg: "tip"
proc checkUrlType*(url: string): DownloadMethod =
## Determines the download method based on the URL.
@@ -141,29 +130,19 @@ proc checkUrlType*(url: string): DownloadMethod =
elif doCmdEx("hg identify " & url).exitCode == QuitSuccess:
return DownloadMethod.hg
else:
- raise newException(NimbleError, "Unable to identify url: " & url)
-
-proc getUrlData*(url: string): (string, Table[string, string]) =
- var uri = parseUri(url)
- # TODO: use uri.parseQuery once it lands... this code is quick and dirty.
- var subdir = ""
- if uri.query.startsWith("subdir="):
- subdir = uri.query[7 .. ^1]
-
- uri.query = ""
- return ($uri, {"subdir": subdir}.toTable())
+ raise newException(NimbleError, "Unable to identify url.")
proc isURL*(name: string): bool =
name.startsWith(peg" @'://' ")
-proc doDownload(url: string, downloadDir: string, verRange: VersionRange,
- downMethod: DownloadMethod,
- options: Options): Version =
+proc doDownload*(url: string, downloadDir: string, verRange: VersionRange,
+ downMethod: DownloadMethod): VersionRange =
## Downloads the repository specified by ``url`` using the specified download
## method.
##
## Returns the version of the repository which has been downloaded.
- template getLatestByTag(meth: untyped) {.dirty.} =
+ template getLatestByTag(meth: stmt): stmt {.dirty, immediate.} =
+ echo("Found tags...")
# Find latest version that fits our ``verRange``.
var latest = findLatest(verRange, versions)
## Note: HEAD is not used when verRange.kind is verAny. This is
@@ -171,104 +150,66 @@ proc doDownload(url: string, downloadDir: string, verRange: VersionRange,
# If no tagged versions satisfy our range latest.tag will be "".
# We still clone in that scenario because we want to try HEAD in that case.
- # https://github.com/nim-lang/nimble/issues/22
+ # https://github.com/nimrod-code/nimble/issues/22
meth
if $latest.ver != "":
- result = latest.ver
-
- removeDir(downloadDir)
- 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)
+ result = parseVersionRange($latest.ver)
else:
- # Grab the full repo.
- doClone(downMethod, url, downloadDir, onlyTip = false)
- # Then perform a checkout operation to get the specified branch/commit.
- # `spe` starts with '#', trim it.
- doAssert(($verRange.spe)[0] == '#')
- doCheckout(downMethod, downloadDir, substr($verRange.spe, 1))
- result = verRange.spe
- else:
- case downMethod
- of DownloadMethod.git:
- # For Git we have to query the repo remotely for its tags. This is
- # necessary as cloning with a --depth of 1 removes all tag info.
- result = getHeadName(downMethod)
- let versions = getTagsListRemote(url, downMethod).getVersionList()
- if versions.len > 0:
- getLatestByTag:
- display("Cloning", "latest tagged version: " & latest.tag,
- priority = MediumPriority)
- doClone(downMethod, url, downloadDir, latest.tag,
- onlyTip = not options.forceFullClone)
- else:
- # If no commits have been tagged on the repo we just clone HEAD.
- doClone(downMethod, url, downloadDir) # Grab HEAD.
- of DownloadMethod.hg:
- doClone(downMethod, url, downloadDir, onlyTip = not options.forceFullClone)
- result = getHeadName(downMethod)
- let versions = getTagsList(downloadDir, downMethod).getVersionList()
+ # Result should already be set to #head here.
+ assert(not result.isNil)
- if versions.len > 0:
- getLatestByTag:
- display("Switching", "to latest tagged version: " & latest.tag,
- priority = MediumPriority)
- doCheckout(downMethod, downloadDir, latest.tag)
-
-proc downloadPkg*(url: string, verRange: VersionRange,
- downMethod: DownloadMethod,
- subdir: string,
- options: Options,
- downloadPath = ""): (string, Version) =
- ## Downloads the repository as specified by ``url`` and ``verRange`` using
- ## the download method specified.
- ##
- ## If `downloadPath` isn't specified a location in /tmp/ will be used.
- ##
- ## Returns the directory where it was downloaded (subdir is appended) and
- ## the concrete version which was downloaded.
- let downloadDir =
- if downloadPath == "":
- (getNimbleTempDir() / getDownloadDirName(url, verRange))
- else:
- downloadPath
-
- createDir(downloadDir)
- var modUrl =
- if url.startsWith("git://") and options.config.cloneUsingHttps:
- "https://" & url[6 .. ^1]
- else: url
-
- # Fixes issue #204
- # github + https + trailing url slash causes a
- # checkout/ls-remote to fail with Repository not found
- if modUrl.contains("github.com") and modUrl.endswith("/"):
- modUrl = modUrl[0 .. ^2]
-
- if subdir.len > 0:
- display("Downloading", "$1 using $2 (subdir is '$3')" %
- [modUrl, $downMethod, subdir],
- priority = HighPriority)
- else:
- display("Downloading", "$1 using $2" % [modUrl, $downMethod],
- priority = HighPriority)
- result = (
- downloadDir / subdir,
- doDownload(modUrl, downloadDir, verRange, downMethod, options)
- )
-
- if verRange.kind != verSpecial:
+ proc verifyClone() =
## Makes sure that the downloaded package's version satisfies the requested
## version range.
- let pkginfo = getPkgInfo(result[0], options)
+ let pkginfo = getPkgInfo(downloadDir)
if pkginfo.version.newVersion notin verRange:
raise newException(NimbleError,
"Downloaded package's version does not satisfy requested version " &
"range: wanted $1 got $2." %
[$verRange, $pkginfo.version])
+ removeDir(downloadDir)
+ if verRange.kind == verSpecial:
+ # We want a specific commit/branch/tag here.
+ if verRange.spe == newSpecial(getHeadName(downMethod)):
+ doClone(downMethod, url, downloadDir) # Grab HEAD.
+ else:
+ # Mercurial requies a clone and checkout. The git clone operation is
+ # already fragmented into multiple steps so we just call doClone().
+ if downMethod == DownloadMethod.git:
+ doClone(downMethod, url, downloadDir, $verRange.spe)
+ else:
+ doClone(downMethod, url, downloadDir, tip = false)
+ doCheckout(downMethod, downloadDir, $verRange.spe)
+ result = verRange
+ else:
+ case downMethod
+ of DownloadMethod.git:
+ # For Git we have to query the repo remotely for its tags. This is
+ # necessary as cloning with a --depth of 1 removes all tag info.
+ result = parseVersionRange("#head")
+ let versions = getTagsListRemote(url, downMethod).getVersionList()
+ if versions.len > 0:
+ getLatestByTag:
+ echo("Cloning latest tagged version: ", latest.tag)
+ 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.
+
+ verifyClone()
+ of DownloadMethod.hg:
+ doClone(downMethod, url, downloadDir)
+ result = parseVersionRange("#tip")
+ let versions = getTagsList(downloadDir, downMethod).getVersionList()
+
+ if versions.len > 0:
+ getLatestByTag:
+ echo("Switching to latest tagged version: ", latest.tag)
+ doCheckout(downMethod, downloadDir, latest.tag)
+
+ verifyClone()
+
proc echoPackageVersions*(pkg: Package) =
let downMethod = pkg.downloadMethod.getDownloadMethod()
case downMethod
@@ -276,8 +217,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 +232,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!")
diff --git a/src/nimblepkg/init.nim b/src/nimblepkg/init.nim
deleted file mode 100644
index 8e7c33b..0000000
--- a/src/nimblepkg/init.nim
+++ /dev/null
@@ -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)
diff --git a/src/nimblepkg/nim.cfg b/src/nimblepkg/nim.cfg
deleted file mode 100644
index d7edcd3..0000000
--- a/src/nimblepkg/nim.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
---path:"$nim/"
---path:"$lib/packages/docutils"
\ No newline at end of file
diff --git a/src/nimblepkg/nimbletypes.nim b/src/nimblepkg/nimbletypes.nim
new file mode 100644
index 0000000..3ee3fc8
--- /dev/null
+++ b/src/nimblepkg/nimbletypes.nim
@@ -0,0 +1,8 @@
+# BSD License. Look at license.txt for more info.
+#
+# Various miscellaneous common types reside here, to avoid problems with
+# recursive imports
+
+type
+ NimbleError* = object of Exception
+ BuildFailed* = object of NimbleError
diff --git a/src/nimblepkg/nimscriptapi.nim b/src/nimblepkg/nimscriptapi.nim
deleted file mode 100644
index ec2f46c..0000000
--- a/src/nimblepkg/nimscriptapi.nim
+++ /dev/null
@@ -1,196 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-
-## This module is implicitly imported in NimScript .nimble files.
-
-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
- ## the default.
- version*: string ## The package's version.
- 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.
- binDir*: string ## The package's binary directory.
- backend*: string ## The package's backend.
-
- skipDirs*, skipFiles*, skipExt*, installDirs*, installFiles*,
- installExt*, bin*: seq[string] = @[] ## Nimble metadata.
- requiresData*: seq[string] = @[] ## The package's dependencies.
-
- 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
-
- if commandLineParams.len == 0 or "help" in commandLineParams:
- success = true
- echo(astToStr(name), " ", description)
- elif astToStr(name).normalize in commandLineParams:
- success = true
- `name Task`()
-
-template before*(action: untyped, body: untyped): untyped =
- ## Defines a block of code which is evaluated before ``action`` is executed.
- proc `action Before`*(): bool =
- 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`()
-
-proc getPkgDir*(): string =
- ## Returns the package directory containing the .nimble file currently
- ## being evaluated.
- result = projectFile.rsplit(seps={'/', '\\', ':'}, maxsplit=1)[0]
-
-getParams()
diff --git a/src/nimblepkg/nimscriptexecutor.nim b/src/nimblepkg/nimscriptexecutor.nim
deleted file mode 100644
index 122c41c..0000000
--- a/src/nimblepkg/nimscriptexecutor.nim
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-
-import os, strutils, sets
-
-import packageparser, common, packageinfo, options, nimscriptwrapper, cli,
- version
-
-proc execHook*(options: Options, hookAction: ActionType, before: bool): bool =
- ## Returns whether to continue.
- result = true
-
- # For certain commands hooks should not be evaluated.
- if hookAction in noHookActions:
- return
-
- var nimbleFile = ""
- try:
- nimbleFile = findNimbleFile(getCurrentDir(), true)
- except NimbleError: return true
- # PackageInfos are cached so we can read them as many times as we want.
- let pkgInfo = getPkgInfoFromFile(nimbleFile, options)
- let actionName =
- if hookAction == actionCustom: options.action.command
- else: ($hookAction)[6 .. ^1]
- let hookExists =
- if before: actionName.normalize in pkgInfo.preHooks
- else: actionName.normalize in pkgInfo.postHooks
- if pkgInfo.isNimScript and hookExists:
- let res = execHook(nimbleFile, actionName, before, options)
- if res.success:
- result = res.retVal
-
-proc execCustom*(options: Options,
- execResult: var ExecutionResult[bool],
- failFast = true): bool =
- ## Executes the custom command using the nimscript backend.
- ##
- ## If failFast is true then exceptions will be raised when something is wrong.
- ## Otherwise this function will just return false.
-
- # Custom command. Attempt to call a NimScript task.
- let nimbleFile = findNimbleFile(getCurrentDir(), true)
- if not nimbleFile.isNimScript(options) and failFast:
- writeHelp()
-
- execResult = execTask(nimbleFile, options.action.command, options)
- if not execResult.success:
- if not failFast:
- return
- raiseNimbleError(msg = "Could not find task $1 in $2" %
- [options.action.command, nimbleFile],
- hint = "Run `nimble --help` and/or `nimble tasks` for" &
- " a list of possible commands.")
-
- if execResult.command.normalize == "nop":
- display("Warning:", "Using `setCommand 'nop'` is not necessary.", Warning,
- HighPriority)
- return
-
- if not execHook(options, actionCustom, false):
- return
-
- return true
-
-proc getOptionsForCommand*(execResult: ExecutionResult,
- options: Options): Options =
- ## Creates an Options object for the requested command.
- var newOptions = options.briefClone()
- parseCommand(execResult.command, newOptions)
- for arg in execResult.arguments:
- parseArgument(arg, newOptions)
- for flag, vals in execResult.flags:
- for val in vals:
- parseFlag(flag, val, newOptions)
- return newOptions
diff --git a/src/nimblepkg/nimscriptwrapper.nim b/src/nimblepkg/nimscriptwrapper.nim
deleted file mode 100644
index 4cfe6ec..0000000
--- a/src/nimblepkg/nimscriptwrapper.nim
+++ /dev/null
@@ -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)
diff --git a/src/nimblepkg/options.nim b/src/nimblepkg/options.nim
deleted file mode 100644
index 14d1c31..0000000
--- a/src/nimblepkg/options.nim
+++ /dev/null
@@ -1,551 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# 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
-
-type
- Options* = object
- forcePrompts*: ForcePrompt
- depsOnly*: bool
- uninstallRevDeps*: bool
- queryVersions*: bool
- queryInstalled*: bool
- nimbleDir*: string
- verbosity*: cli.Priority
- action*: Action
- config*: Config
- nimbleData*: JsonNode ## Nimbledata.json
- pkgInfoCache*: TableRef[string, PackageInfo]
- showHelp*: bool
- 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
-
- Action* = object
- case typ*: ActionType
- of actionNil, actionList, actionPublish, actionTasks, actionCheck: nil
- of actionRefresh:
- optionalURL*: string # Overrides default package list.
- 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]
- of actionCustom:
- command*: string
- arguments*: seq[string]
- flags*: StringTableRef
-
-const
- help* = """
-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.
- 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.
- 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
- can be optionally specified.
- search pkg/tag Searches for a specified package. Search is
- performed by tag and by name.
- [--ver] Query remote server for package version.
- list Lists all packages.
- [--ver] Query remote server for package version.
- [-i, --installed] Lists all installed packages.
- tasks Lists the tasks specified in the Nimble
- package's Nimble file.
- path pkgname ... Shows absolute path to the installed packages
- specified.
- dump [pkgname] Outputs Nimble package information for
- external tools. The argument can be a
- .nimble file, a project directory or
- the name of an installed package.
-
-
-Options:
- -h, --help Print this help message.
- -v, --version Print version information.
- -y, --accept Accept all interactive prompts.
- -n, --reject Reject all interactive prompts.
- --ver Query remote server for package version
- information when searching or listing packages
- --nimbleDir:dirname Set the Nimble directory.
- --verbose Show all non-debug output.
- --debug Show all output including debug messages.
- --noColor Don't colorise output.
-
-For more information read the Github readme:
- https://github.com/nim-lang/nimble#readme
-"""
-
-const noHookActions* = {actionCheck}
-
-proc writeHelp*(quit=true) =
- echo(help)
- if quit:
- raise NimbleQuit(msg: "")
-
-proc writeVersion*() =
- echo("nimble v$# compiled at $# $#" %
- [nimbleVersion, CompileDate, CompileTime])
- const execResult = gorgeEx("git rev-parse HEAD")
- when execResult[0].len > 0 and execResult[1] == QuitSuccess:
- echo "git hash: ", execResult[0]
- else:
- {.warning: "Couldn't determine GIT hash: " & execResult[0].}
- echo "git hash: couldn't determine git hash"
- raise NimbleQuit(msg: "")
-
-proc parseActionType*(action: string): ActionType =
- case action.normalize()
- of "install":
- result = actionInstall
- of "path":
- result = actionPath
- of "build":
- result = actionBuild
- of "run":
- result = actionRun
- of "c", "compile", "js", "cpp", "cc":
- result = actionCompile
- of "doc", "doc2":
- result = actionDoc
- of "init":
- result = actionInit
- of "dump":
- result = actionDump
- of "update", "refresh":
- result = actionRefresh
- of "search":
- result = actionSearch
- of "list":
- result = actionList
- of "uninstall", "remove", "delete", "del", "rm":
- result = actionUninstall
- of "publish":
- result = actionPublish
- of "tasks":
- result = actionTasks
- of "develop":
- result = actionDevelop
- of "check":
- result = actionCheck
- else:
- result = actionCustom
-
-proc initAction*(options: var Options, key: string) =
- ## Intialises `options.actions` fields based on `options.actions.typ` and
- ## `key`.
- let keyNorm = key.normalize()
- 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 = ""
- if keyNorm == "c" or keyNorm == "compile": options.action.backend = ""
- 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:
- options.action.search = @[]
- of actionCustom:
- options.action.command = key
- options.action.arguments = @[]
- options.action.flags = newStringTable()
- of actionPublish, actionList, actionTasks, actionCheck, actionRun,
- actionNil: discard
-
-proc prompt*(options: Options, question: string): bool =
- ## Asks an interactive question and returns the result.
- ##
- ## The proc will return immediately without asking the user if the global
- ## forcePrompts has a value different than dontForcePrompt.
- return prompt(options.forcePrompts, question)
-
-proc promptCustom*(options: Options, question, default: string): string =
- ## Asks an interactive question and returns the result.
- ##
- ## The proc will return "default" without asking the user if the global
- ## forcePrompts is forcePromptYes.
- return promptCustom(options.forcePrompts, question, default)
-
-proc promptList*(options: Options, question: string, args: openarray[string]): string =
- ## Asks an interactive question and returns the result.
- ##
- ## The proc will return one of the provided args. If not prompting the first
- ## options is selected.
- return promptList(options.forcePrompts, question, args)
-
-proc getNimbleDir*(options: Options): string =
- result = options.config.nimbleDir
- if options.nimbleDir.len != 0:
- # --nimbleDir: takes priority...
- result = options.nimbleDir
- else:
- # ...followed by the environment variable.
- let env = getEnv("NIMBLE_DIR")
- if env.len != 0:
- display("Warning:", "Using the environment variable: NIMBLE_DIR='" &
- env & "'", Warning)
- result = env
-
- return expandTilde(result)
-
-proc getPkgsDir*(options: Options): string =
- options.getNimbleDir() / "pkgs"
-
-proc getBinDir*(options: Options): string =
- options.getNimbleDir() / "bin"
-
-proc parseCommand*(key: string, result: var Options) =
- result.action = Action(typ: parseActionType(key))
- initAction(result, key)
-
-proc setRunOptions(result: var Options, key, val: string, isArg: bool) =
- if result.action.runFile.isNone() and (isArg or val == "--"):
- result.action.runFile = some(key)
- else:
- result.action.runFlags.add(val)
-
-proc parseArgument*(key: string, result: var Options) =
- case result.action.typ
- of actionNil:
- assert false
- of actionInstall, actionPath, actionDevelop, actionUninstall:
- # Parse pkg@verRange
- if '@' in key:
- let i = find(key, '@')
- let (pkgName, pkgVer) = (key[0 .. i-1], key[i+1 .. key.len-1])
- if pkgVer.len == 0:
- raise newException(NimbleError, "Version range expected after '@'.")
- result.action.packages.add((pkgName, pkgVer.parseVersionRange()))
- else:
- result.action.packages.add((key, VersionRange(kind: verAny)))
- of actionRefresh:
- result.action.optionalURL = key
- of actionSearch:
- 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."
- )
- result.action.projName = key
- of actionCompile, actionDoc:
- result.action.file = key
- of actionList, 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) =
-
- let f = flag.normalize()
-
- # Global flags.
- var isGlobalFlag = true
- case f
- of "help", "h": result.showHelp = true
- of "version", "v": result.showVersion = true
- of "accept", "y": result.forcePrompts = forcePromptYes
- of "reject", "n": result.forcePrompts = forcePromptNo
- of "nimbledir": result.nimbleDir = val
- of "verbose": result.verbosity = LowPriority
- 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
-
- if not wasFlagHandled and not isGlobalFlag:
- result.unknownFlags.add((kind, flag, val))
-
-proc initOptions*(): Options =
- # Exported for choosenim
- Options(
- action: Action(typ: actionNil),
- pkgInfoCache: newTable[string, PackageInfo](),
- verbosity: HighPriority,
- noColor: not isatty(stdout)
- )
-
-proc parseMisc(options: var Options) =
- # Load nimbledata.json
- let nimbledataFilename = options.getNimbleDir() / "nimbledata.json"
-
- if fileExists(nimbledataFilename):
- try:
- options.nimbleData = parseFile(nimbledataFilename)
- except:
- raise newException(NimbleError, "Couldn't parse nimbledata.json file " &
- "located at " & nimbledataFilename)
- 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()
-
- # Parse command line params first. A simple `--version` shouldn't require
- # a config to be parsed.
- for kind, key, val in getOpt():
- case kind
- of cmdArgument:
- if result.action.typ == actionNil:
- parseCommand(key, result)
- else:
- parseArgument(key, result)
- of cmdLongOption, cmdShortOption:
- parseFlag(key, val, result, kind)
- of cmdEnd: assert(false) # cannot happen
-
- handleUnknownFlags(result)
-
- # Set verbosity level.
- setVerbosity(result.verbosity)
-
- # Set whether color should be shown.
- setShowColor(not result.noColor)
-
- # Parse config.
- result.config = parseConfig()
-
- # Parse other things, for example the nimbledata.json file.
- parseMisc(result)
-
- 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 = ""
- if ($options.config.httpProxy).len > 0:
- url = $options.config.httpProxy
- else:
- try:
- if existsEnv("http_proxy"):
- url = getEnv("http_proxy")
- elif existsEnv("https_proxy"):
- url = getEnv("https_proxy")
- elif existsEnv("HTTP_PROXY"):
- url = getEnv("HTTP_PROXY")
- elif existsEnv("HTTPS_PROXY"):
- url = getEnv("HTTPS_PROXY")
- except ValueError:
- display("Warning:", "Unable to parse proxy from environment: " &
- getCurrentExceptionMsg(), Warning, HighPriority)
-
- if url.len > 0:
- var parsed = parseUri(url)
- if parsed.scheme.len == 0 or parsed.hostname.len == 0:
- parsed = parseUri("http://" & url)
- let auth =
- if parsed.username.len > 0: parsed.username & ":" & parsed.password
- else: ""
- return newProxy($parsed, auth)
- else:
- return nil
-
-proc briefClone*(options: Options): Options =
- ## Clones the few important fields and creates a new Options object.
- var newOptions = initOptions()
- newOptions.config = options.config
- newOptions.nimbleData = options.nimbleData
- 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
diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim
index f00c59f..c58e32d 100644
--- a/src/nimblepkg/packageinfo.nim
+++ b/src/nimblepkg/packageinfo.nim
@@ -1,15 +1,31 @@
# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
-
-# Stdlib imports
-import system except TResult
-import hashes, json, strutils, os, sets, tables, httpclient
-
-# Local imports
-import version, tools, common, options, cli, config
-
+import parsecfg, json, streams, strutils, parseutils, os
+import version, tools, nimbletypes
type
- Package* = object ## Definition of package from packages.json.
+ ## Tuple containing package name and version range.
+ PkgTuple* = tuple[name: string, ver: VersionRange]
+
+ PackageInfo* = object
+ mypath*: string ## The path of this .nimble file
+ name*: string
+ version*: string
+ author*: string
+ description*: string
+ license*: string
+ skipDirs*: seq[string]
+ skipFiles*: seq[string]
+ skipExt*: seq[string]
+ installDirs*: seq[string]
+ installFiles*: seq[string]
+ installExt*: seq[string]
+ requires*: seq[PkgTuple]
+ bin*: seq[string]
+ binDir*: string
+ srcDir*: string
+ backend*: string
+
+ Package* = object
# Required fields in a package.
name*: string
url*: string # Download location.
@@ -17,26 +33,17 @@ type
downloadMethod*: string
description*: string
tags*: seq[string] # Even if empty, always a valid non nil seq. \
- # From here on, optional fields set to the empty string if not available.
+ # From here on, optional fields set to the emtpy string if not available.
version*: string
dvcsTag*: string
web*: string # Info url for humans.
- alias*: string ## A name of another package, that this package aliases.
MetaData* = object
url*: string
- NimbleLink* = object
- nimbleFilePath*: string
- packageDir*: string
-
-proc initPackageInfo*(path: string): PackageInfo =
- result.myPath = path
- result.specialVersion = ""
- result.preHooks.init()
- result.postHooks.init()
- # reasonable default:
- result.name = path.splitFile.name
+proc initPackageInfo(): PackageInfo =
+ result.mypath = ""
+ result.name = ""
result.version = ""
result.author = ""
result.description = ""
@@ -48,45 +55,134 @@ proc initPackageInfo*(path: string): PackageInfo =
result.installFiles = @[]
result.installExt = @[]
result.requires = @[]
- result.foreignDeps = @[]
result.bin = @[]
result.srcDir = ""
result.binDir = ""
result.backend = "c"
-proc toValidPackageName*(name: string): string =
- result = ""
- for c in name:
- case c
- of '_', '-':
- if result[^1] != '_': result.add('_')
- of AllChars - IdentChars - {'-'}: discard
- else: result.add(c)
+proc validatePackageInfo(pkgInfo: PackageInfo, path: string) =
+ if pkgInfo.name == "":
+ raise newException(NimbleError, "Incorrect .nimble file: " & path &
+ " does not contain a name field.")
+ if pkgInfo.version == "":
+ raise newException(NimbleError, "Incorrect .nimble file: " & path &
+ " does not contain a version field.")
+ if pkgInfo.author == "":
+ raise newException(NimbleError, "Incorrect .nimble file: " & path &
+ " does not contain an author field.")
+ if pkgInfo.description == "":
+ raise newException(NimbleError, "Incorrect .nimble file: " & path &
+ " does not contain a description field.")
+ if pkgInfo.license == "":
+ raise newException(NimbleError, "Incorrect .nimble file: " & path &
+ " does not contain a license field.")
+ if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
+ raise newException(NimbleError, "'" & pkgInfo.backend &
+ "' is an invalid backend.")
+ for c in pkgInfo.version:
+ if c notin ({'.'} + Digits):
+ raise newException(NimbleError,
+ "Version may only consist of numbers and the '.' character " &
+ "but found '" & c & "'.")
-proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
- ## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1``
- ## into ``(packagea, 0.1)``
+proc parseRequires(req: string): PkgTuple =
+ try:
+ if ' ' in req:
+ var i = skipUntil(req, Whitespace)
+ result.name = req[0 .. i].strip
+ result.ver = parseVersionRange(req[i .. req.len-1])
+ elif '#' in req:
+ var i = skipUntil(req, {'#'})
+ result.name = req[0 .. i-1]
+ result.ver = parseVersionRange(req[i .. req.len-1])
+ else:
+ result.name = req.strip
+ result.ver = VersionRange(kind: verAny)
+ except ParseVersionError:
+ raise newException(NimbleError,
+ "Unable to parse dependency version range: " & getCurrentExceptionMsg())
+
+proc multiSplit(s: string): seq[string] =
+ ## Returns ``s`` split by newline and comma characters.
##
- ## Also works for file paths like:
- ## ``/home/user/.nimble/pkgs/package-0.1/package.nimble``
- if pkgPath.splitFile.ext in [".nimble", ".nimble-link", ".babel"]:
- return getNameVersion(pkgPath.splitPath.head)
+ ## Before returning, all individual entries are stripped of whitespace and
+ ## also empty entries are purged from the list. If after all the cleanups are
+ ## done no entries are found in the list, the proc returns a sequence with
+ ## the original string as the only entry.
+ result = split(s, {char(0x0A), char(0x0D), ','})
+ map(result, proc(x: var string) = x = x.strip())
+ for i in countdown(result.len()-1, 0):
+ if len(result[i]) < 1:
+ result.del(i)
+ # Huh, nothing to return? Return given input.
+ if len(result) < 1:
+ return @[s]
- result.name = ""
- result.version = ""
- let tail = pkgpath.splitPath.tail
-
- const specialSeparator = "-#"
- var sepIdx = tail.find(specialSeparator)
- if sepIdx == -1:
- sepIdx = tail.rfind('-')
-
- if sepIdx == -1:
- result.name = tail
- return
-
- result.name = tail[0 .. sepIdx - 1]
- result.version = tail.substr(sepIdx + 1)
+proc readPackageInfo*(path: string): PackageInfo =
+ result = initPackageInfo()
+ result.mypath = path
+ var fs = newFileStream(path, fmRead)
+ if fs != nil:
+ var p: CfgParser
+ open(p, fs, path)
+ var currentSection = ""
+ while true:
+ var ev = next(p)
+ case ev.kind
+ of cfgEof:
+ break
+ of cfgSectionStart:
+ currentSection = ev.section
+ of cfgKeyValuePair:
+ case currentSection.normalize
+ of "package":
+ case ev.key.normalize
+ of "name": result.name = ev.value
+ of "version": result.version = ev.value
+ of "author": result.author = ev.value
+ of "description": result.description = ev.value
+ of "license": result.license = ev.value
+ of "srcdir": result.srcDir = ev.value
+ of "bindir": result.binDir = ev.value
+ of "skipdirs":
+ result.skipDirs.add(ev.value.multiSplit)
+ of "skipfiles":
+ result.skipFiles.add(ev.value.multiSplit)
+ of "skipext":
+ result.skipExt.add(ev.value.multiSplit)
+ of "installdirs":
+ result.installDirs.add(ev.value.multiSplit)
+ of "installfiles":
+ result.installFiles.add(ev.value.multiSplit)
+ of "installext":
+ result.installExt.add(ev.value.multiSplit)
+ of "bin":
+ for i in ev.value.multiSplit:
+ result.bin.add(i.addFileExt(ExeExt))
+ of "backend":
+ result.backend = ev.value.toLower()
+ case result.backend.normalize
+ of "javascript": result.backend = "js"
+ else: discard
+ else:
+ raise newException(NimbleError, "Invalid field: " & ev.key)
+ of "deps", "dependencies":
+ case ev.key.normalize
+ of "requires":
+ for v in ev.value.multiSplit:
+ result.requires.add(parseRequires(v.strip))
+ else:
+ raise newException(NimbleError, "Invalid field: " & ev.key)
+ else: raise newException(NimbleError,
+ "Invalid section: " & currentSection)
+ of cfgOption: raise newException(NimbleError,
+ "Invalid package info, should not contain --" & ev.value)
+ of cfgError:
+ raise newException(NimbleError, "Error parsing .nimble file: " & ev.msg)
+ close(p)
+ else:
+ raise newException(ValueError, "Cannot open package info: " & path)
+ validatePackageInfo(result, path)
proc optionalField(obj: JsonNode, name: string, default = ""): string =
## Queries ``obj`` for the optional ``name`` string.
@@ -106,8 +202,8 @@ proc requiredField(obj: JsonNode, name: string): string =
## Queries ``obj`` for the required ``name`` string.
##
## Aborts execution if the field does not exist or is of invalid json type.
- result = optionalField(obj, name)
- if result.len == 0:
+ result = optionalField(obj, name, nil)
+ if result == nil:
raise newException(NimbleError,
"Package in packages.json file does not contain a " & name & " field.")
@@ -116,260 +212,87 @@ proc fromJson(obj: JSonNode): Package =
##
## Aborts execution if the JSON node doesn't contain the required fields.
result.name = obj.requiredField("name")
- if obj.hasKey("alias"):
- result.alias = obj.requiredField("alias")
- else:
- result.alias = ""
- result.version = obj.optionalField("version")
- result.url = obj.requiredField("url")
- result.downloadMethod = obj.requiredField("method")
- result.dvcsTag = obj.optionalField("dvcs-tag")
- result.license = obj.requiredField("license")
- result.tags = @[]
- for t in obj["tags"]:
- result.tags.add(t.str)
- result.description = obj.requiredField("description")
- result.web = obj.optionalField("web")
+ result.version = obj.optionalField("version")
+ result.url = obj.requiredField("url")
+ result.downloadMethod = obj.requiredField("method")
+ result.dvcsTag = obj.optionalField("dvcs-tag")
+ result.license = obj.requiredField("license")
+ result.tags = @[]
+ for t in obj["tags"]:
+ result.tags.add(t.str)
+ result.description = obj.requiredField("description")
+ result.web = obj.optionalField("web")
proc readMetaData*(path: string): MetaData =
## Reads the metadata present in ``~/.nimble/pkgs/pkg-0.1/nimblemeta.json``
var bmeta = path / "nimblemeta.json"
+ if not existsFile(bmeta):
+ bmeta = path / "babelmeta.json"
+ if existsFile(bmeta):
+ echo("WARNING: using deprecated babelmeta.json file in " & path)
if not existsFile(bmeta):
result.url = ""
- display("Warning:", "No nimblemeta.json file found in " & path,
- Warning, HighPriority)
+ echo("WARNING: No nimblemeta.json file found in " & path)
return
# TODO: Make this an error.
let cont = readFile(bmeta)
let jsonmeta = parseJson(cont)
result.url = jsonmeta["url"].str
-proc readNimbleLink*(nimbleLinkPath: string): NimbleLink =
- let s = readFile(nimbleLinkPath).splitLines()
- result.nimbleFilePath = s[0]
- result.packageDir = s[1]
-
-proc writeNimbleLink*(nimbleLinkPath: string, contents: NimbleLink) =
- let c = contents.nimbleFilePath & "\n" & contents.packageDir
- writeFile(nimbleLinkPath, c)
-
-proc needsRefresh*(options: Options): bool =
- ## Determines whether a ``nimble refresh`` is needed.
- ##
- ## In the future this will check a stored time stamp to determine how long
- ## ago the package list was refreshed.
- result = true
- for name, list in options.config.packageLists:
- if fileExists(options.getNimbleDir() / "packages_" & name & ".json"):
- result = false
-
-proc validatePackagesList(path: string): bool =
- ## Determines whether package list at ``path`` is valid.
- try:
- let pkgList = parseFile(path)
- if pkgList.kind == JArray:
- if pkgList.len == 0:
- display("Warning:", path & " contains no packages.", Warning,
- HighPriority)
- return true
- except ValueError, JsonParsingError:
- return false
-
-proc fetchList*(list: PackageList, options: Options) =
- ## Downloads or copies the specified package list and saves it in $nimbleDir.
- let verb = if list.urls.len > 0: "Downloading" else: "Copying"
- display(verb, list.name & " package list", priority = HighPriority)
-
- var
- lastError = ""
- copyFromPath = ""
- if list.urls.len > 0:
- for i in 0 ..< list.urls.len:
- let url = list.urls[i]
- display("Trying", url)
- let tempPath = options.getNimbleDir() / "packages_temp.json"
-
- # Grab the proxy
- let proxy = getProxy(options)
- if not proxy.isNil:
- var maskedUrl = proxy.url
- if maskedUrl.password.len > 0: maskedUrl.password = "***"
- display("Connecting", "to proxy at " & $maskedUrl,
- priority = LowPriority)
-
- try:
- let client = newHttpClient(proxy = proxy)
- client.downloadFile(url, tempPath)
- except:
- let message = "Could not download: " & getCurrentExceptionMsg()
- display("Warning:", message, Warning)
- lastError = message
- continue
-
- if not validatePackagesList(tempPath):
- lastError = "Downloaded packages.json file is invalid"
- display("Warning:", lastError & ", discarding.", Warning)
- continue
-
- copyFromPath = tempPath
- display("Success", "Package list downloaded.", Success, HighPriority)
- lastError = ""
- break
-
- elif list.path != "":
- if not validatePackagesList(list.path):
- lastError = "Copied packages.json file is invalid"
- display("Warning:", lastError & ", discarding.", Warning)
- else:
- copyFromPath = list.path
- display("Success", "Package list copied.", Success, HighPriority)
-
- if lastError.len != 0:
- raise newException(NimbleError, "Refresh failed\n" & lastError)
-
- if copyFromPath.len > 0:
- copyFile(copyFromPath,
- options.getNimbleDir() / "packages_$1.json" % list.name.toLowerAscii())
-
-proc readPackageList(name: string, options: Options): JsonNode =
- # If packages.json is not present ask the user if they want to download it.
- if needsRefresh(options):
- if options.prompt("No local packages.json found, download it from " &
- "internet?"):
- for name, list in options.config.packageLists:
- fetchList(list, options)
- else:
- # The user might not need a package list for now. So let's try
- # going further.
- return newJArray()
- return parseFile(options.getNimbleDir() / "packages_" &
- name.toLowerAscii() & ".json")
-
-proc getPackage*(pkg: string, options: Options, resPkg: var Package): bool
-proc resolveAlias(pkg: Package, options: Options): Package =
- result = pkg
- # Resolve alias.
- if pkg.alias.len > 0:
- display("Warning:", "The $1 package has been renamed to $2" %
- [pkg.name, pkg.alias], Warning, HighPriority)
- if not getPackage(pkg.alias, options, result):
- raise newException(NimbleError, "Alias for package not found: " &
- pkg.alias)
-
-proc getPackage*(pkg: string, options: Options, resPkg: var Package): bool =
- ## Searches any packages.json files defined in ``options.config.packageLists``
- ## Saves the found package into ``resPkg``.
+proc getPackage*(pkg: string, packagesPath: string, resPkg: var Package): bool =
+ ## Searches ``packagesPath`` file saving into ``resPkg`` the found package.
##
## Pass in ``pkg`` the name of the package you are searching for. As
## convenience the proc returns a boolean specifying if the ``resPkg`` was
## successfully filled with good data.
- ##
- ## Aliases are handled and resolved.
- for name, list in options.config.packageLists:
- display("Reading", "$1 package list" % name, priority = LowPriority)
- let packages = readPackageList(name, options)
- for p in packages:
- if normalize(p["name"].str) == normalize(pkg):
- resPkg = p.fromJson()
- resPkg = resolveAlias(resPkg, options)
- return true
+ let packages = parseFile(packagesPath)
+ for p in packages:
+ if p["name"].str == pkg:
+ resPkg = p.fromJson()
+ return true
-proc getPackageList*(options: Options): seq[Package] =
- ## Returns the list of packages found in the downloaded packages.json files.
+proc getPackageList*(packagesPath: string): seq[Package] =
+ ## Returns the list of packages found at the specified path.
result = @[]
- var namesAdded = initHashSet[string]()
- for name, list in options.config.packageLists:
- let packages = readPackageList(name, options)
- for p in packages:
- let pkg: Package = p.fromJson()
- if pkg.name notin namesAdded:
- result.add(pkg)
- namesAdded.incl(pkg.name)
+ let packages = parseFile(packagesPath)
+ for p in packages:
+ let pkg: Package = p.fromJson()
+ result.add(pkg)
-proc findNimbleFile*(dir: string; error: bool): string =
+proc findNimbleFile*(dir: string): string =
result = ""
- var hits = 0
for kind, path in walkDir(dir):
- if kind in {pcFile, pcLinkToFile}:
- let ext = path.splitFile.ext
- case ext
- of ".babel", ".nimble", ".nimble-link":
- result = path
- inc hits
- else: discard
- if hits >= 2:
+ if kind == pcFile and path.splitFile.ext in [".babel", ".nimble"]:
+ if result != "":
+ raise newException(NimbleError,
+ "Only one .nimble file should be present in " & dir)
+ result = path
+
+proc getPkgInfo*(dir: string): PackageInfo =
+ ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
+ let nimbleFile = findNimbleFile(dir)
+ if nimbleFile == "":
raise newException(NimbleError,
- "Only one .nimble file should be present in " & dir)
- elif hits == 0:
- if error:
- raise newException(NimbleError,
- "Specified directory ($1) does not contain a .nimble file." % dir)
- else:
- display("Warning:", "No .nimble or .nimble-link file found for " &
- dir, Warning, HighPriority)
+ "Specified directory does not contain a .nimble file.")
+ result = readPackageInfo(nimbleFile)
- if result.splitFile.ext == ".nimble-link":
- # 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)
-
-proc getInstalledPkgsMin*(libsDir: string, options: Options):
+proc getInstalledPkgs*(libsDir: string):
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``.
+ ## Gets a list of installed packages.
##
- ## ``libsDir`` is in most cases: ~/.nimble/pkgs/ (options.getPkgsDir)
+ ## ``libsDir`` is in most cases: ~/.nimble/pkgs/
result = @[]
for kind, path in walkDir(libsDir):
if kind == pcDir:
- let nimbleFile = findNimbleFile(path, false)
+ let nimbleFile = findNimbleFile(path)
if nimbleFile != "":
let meta = readMetaData(path)
- let (name, version) = getNameVersion(path)
- var pkg = initPackageInfo(nimbleFile)
- pkg.name = name
- pkg.version = version
- pkg.specialVersion = version
- pkg.isMinimal = true
- pkg.isInstalled = true
- let nimbleFileDir = nimbleFile.splitFile().dir
- pkg.isLinked = cmpPaths(nimbleFileDir, path) != 0
+ result.add((readPackageInfo(nimbleFile), meta))
+ else:
+ # TODO: Abstract logging.
+ echo("WARNING: No .nimble file found for ", path)
- # Read the package's 'srcDir' (this is stored in the .nimble-link so
- # we can easily grab it)
- if pkg.isLinked:
- let nimbleLinkPath = path / name.addFileExt("nimble-link")
- let realSrcPath = readNimbleLink(nimbleLinkPath).packageDir
- assert realSrcPath.startsWith(nimbleFileDir)
- pkg.srcDir = realSrcPath.replace(nimbleFileDir)
- pkg.srcDir.removePrefix(DirSep)
- result.add((pkg, meta))
-
-proc withinRange*(pkgInfo: PackageInfo, verRange: VersionRange): bool =
- ## Determines whether the specified package's version is within the
- ## specified range. The check works with ordinary versions as well as
- ## special ones.
- return withinRange(newVersion(pkgInfo.version), verRange) or
- withinRange(newVersion(pkgInfo.specialVersion), verRange)
-
-proc resolveAlias*(dep: PkgTuple, options: Options): PkgTuple =
- ## Looks up the specified ``dep.name`` in the packages.json files to resolve
- ## a potential alias into the package's real name.
- result = dep
- var pkg: Package
- # TODO: This needs better caching.
- if getPackage(dep.name, options, pkg):
- # The resulting ``pkg`` will contain the resolved name or the original if
- # no alias is present.
- result.name = pkg.name
-
-proc findPkg*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]],
+proc findPkg*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
dep: PkgTuple,
r: var PackageInfo): bool =
## Searches ``pkglist`` for a package of which version is within the range
@@ -379,29 +302,29 @@ proc findPkg*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]],
##
## **Note**: dep.name here could be a URL, hence the need for pkglist.meta.
for pkg in pkglist:
- if cmpIgnoreStyle(pkg.pkginfo.name, dep.name) != 0 and
- cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
- if withinRange(pkg.pkgInfo, dep.ver):
- let isNewer = newVersion(r.version) < newVersion(pkg.pkginfo.version)
- if not result or isNewer:
+ if pkg.pkginfo.name.normalize != dep.name.normalize and
+ pkg.meta.url.normalize != dep.name.normalize: continue
+ if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
+ if not result or newVersion(r.version) < newVersion(pkg.pkginfo.version):
r = pkg.pkginfo
result = true
-proc findAllPkgs*(pkglist: seq[tuple[pkgInfo: PackageInfo, meta: MetaData]],
+proc findAllPkgs*(pkglist: seq[tuple[pkginfo: PackageInfo, meta: MetaData]],
dep: PkgTuple): seq[PackageInfo] =
## Searches ``pkglist`` for packages of which version is within the range
## of ``dep.ver``. This is similar to ``findPkg`` but returns multiple
## packages if multiple are found.
result = @[]
for pkg in pkglist:
- if cmpIgnoreStyle(pkg.pkgInfo.name, dep.name) != 0 and
- cmpIgnoreStyle(pkg.meta.url, dep.name) != 0: continue
- if withinRange(pkg.pkgInfo, dep.ver):
+ if pkg.pkginfo.name.normalize != dep.name.normalize and
+ pkg.meta.url.normalize != dep.name.normalize: continue
+ if withinRange(newVersion(pkg.pkginfo.version), dep.ver):
result.add pkg.pkginfo
proc getRealDir*(pkgInfo: PackageInfo): string =
- ## Returns the directory containing the package source files.
- if pkgInfo.srcDir != "" and (not pkgInfo.isInstalled or pkgInfo.isLinked):
+ ## Returns the ``pkgInfo.srcDir`` or the .mypath directory if package does
+ ## not specify the src dir.
+ if pkgInfo.srcDir != "":
result = pkgInfo.mypath.splitFile.dir / pkgInfo.srcDir
else:
result = pkgInfo.mypath.splitFile.dir
@@ -413,17 +336,30 @@ proc getOutputDir*(pkgInfo: PackageInfo, bin: string): string =
else:
result = pkgInfo.mypath.splitFile.dir / bin
+proc getNameVersion*(pkgpath: string): tuple[name, version: string] =
+ ## Splits ``pkgpath`` in the format ``/home/user/.nimble/pkgs/package-0.1``
+ ## into ``(packagea, 0.1)``
+ result.name = ""
+ result.version = ""
+ let tail = pkgpath.splitPath.tail
+ if '-' notin tail:
+ result.name = tail
+ return
+
+ for i in countdown(tail.len-1, 0):
+ if tail[i] == '-':
+ result.name = tail[0 .. i-1]
+ result.version = tail[i+1 .. tail.len-1]
+ break
+
proc echoPackage*(pkg: Package) =
echo(pkg.name & ":")
- if pkg.alias.len > 0:
- echo(" Alias for ", pkg.alias)
- else:
- echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
- echo(" tags: " & pkg.tags.join(", "))
- echo(" description: " & pkg.description)
- echo(" license: " & pkg.license)
- if pkg.web.len > 0:
- echo(" website: " & pkg.web)
+ echo(" url: " & pkg.url & " (" & pkg.downloadMethod & ")")
+ echo(" tags: " & pkg.tags.join(", "))
+ echo(" description: " & pkg.description)
+ echo(" license: " & pkg.license)
+ if pkg.web.len > 0:
+ echo(" website: " & pkg.web)
proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string =
result = pkg.name
@@ -432,134 +368,8 @@ proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string =
result.add "_"
result.add verSimple
-proc checkInstallFile(pkgInfo: PackageInfo,
- origDir, file: string): bool =
- ## Checks whether ``file`` should be installed.
- ## ``True`` means file should be skipped.
-
- for ignoreFile in pkgInfo.skipFiles:
- if ignoreFile.endswith("nimble"):
- raise newException(NimbleError, ignoreFile & " must be installed.")
- if samePaths(file, origDir / ignoreFile):
- result = true
- break
-
- for ignoreExt in pkgInfo.skipExt:
- if file.splitFile.ext == ('.' & ignoreExt):
- result = true
- break
-
- if file.splitFile().name[0] == '.': result = true
-
-proc checkInstallDir(pkgInfo: PackageInfo,
- origDir, dir: string): bool =
- ## Determines whether ``dir`` should be installed.
- ## ``True`` means dir should be skipped.
- for ignoreDir in pkgInfo.skipDirs:
- if samePaths(dir, origDir / ignoreDir):
- result = true
- break
-
- let thisDir = splitPath(dir).tail
- assert thisDir != ""
- if thisDir[0] == '.': result = true
- if thisDir == "nimcache": result = true
-
-proc iterFilesWithExt(dir: string, pkgInfo: PackageInfo,
- action: proc (f: string)) =
- ## Runs `action` for each filename of the files that have a whitelisted
- ## file extension.
- for kind, path in walkDir(dir):
- if kind == pcDir:
- iterFilesWithExt(path, pkgInfo, action)
- else:
- if path.splitFile.ext.substr(1) in pkgInfo.installExt:
- action(path)
-
-proc iterFilesInDir(dir: string, action: proc (f: string)) =
- ## Runs `action` for each file in ``dir`` and any
- ## subdirectories that are in it.
- for kind, path in walkDir(dir):
- if kind == pcDir:
- iterFilesInDir(path, action)
- else:
- action(path)
-
-proc iterInstallFiles*(realDir: string, pkgInfo: PackageInfo,
- options: Options, action: proc (f: string)) =
- ## Runs `action` for each file within the ``realDir`` that should be
- ## installed.
- let whitelistMode =
- pkgInfo.installDirs.len != 0 or
- pkgInfo.installFiles.len != 0 or
- pkgInfo.installExt.len != 0
- if whitelistMode:
- for file in pkgInfo.installFiles:
- let src = realDir / file
- if not src.existsFile():
- if options.prompt("Missing file " & src & ". Continue?"):
- continue
- else:
- raise NimbleQuit(msg: "")
-
- action(src)
-
- for dir in pkgInfo.installDirs:
- # TODO: Allow skipping files inside dirs?
- let src = realDir / dir
- if not src.existsDir():
- if options.prompt("Missing directory " & src & ". Continue?"):
- continue
- else:
- raise NimbleQuit(msg: "")
-
- iterFilesInDir(src, action)
-
- iterFilesWithExt(realDir, pkgInfo, action)
- else:
- for kind, file in walkDir(realDir):
- if kind == pcDir:
- let skip = pkgInfo.checkInstallDir(realDir, file)
- if skip: continue
- # we also have to stop recursing if we reach an in-place nimbleDir
- if file == options.getNimbleDir().expandFilename(): continue
-
- iterInstallFiles(file, pkgInfo, options, action)
- else:
- let skip = pkgInfo.checkInstallFile(realDir, file)
- if skip: continue
-
- action(file)
-
-proc getPkgDest*(pkgInfo: PackageInfo, options: Options): string =
- let versionStr = '-' & pkgInfo.specialVersion
- 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")
doAssert getNameVersion("/home/user/.nimble/libs/package-a-0.1") ==
("package-a", "0.1")
- doAssert getNameVersion("/home/user/.nimble/libs/package-a-0.1/package.nimble") ==
- ("package-a", "0.1")
- doAssert getNameVersion("/home/user/.nimble/libs/package-#head") ==
- ("package", "#head")
- doAssert getNameVersion("/home/user/.nimble/libs/package-#branch-with-dashes") ==
- ("package", "#branch-with-dashes")
- # readPackageInfo (and possibly more) depends on this not raising.
- doAssert getNameVersion("/home/user/.nimble/libs/package") == ("package", "")
-
- doAssert toValidPackageName("foo__bar") == "foo_bar"
- doAssert toValidPackageName("jhbasdh!£$@%#^_&*_()qwe") == "jhbasdh_qwe"
-
- echo("All tests passed!")
diff --git a/src/nimblepkg/packageinstaller.nim b/src/nimblepkg/packageinstaller.nim
deleted file mode 100644
index 4bdc921..0000000
--- a/src/nimblepkg/packageinstaller.nim
+++ /dev/null
@@ -1,112 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-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
-
-when defined(windows):
- # This is just for Win XP support.
- # TODO: Drop XP support?
- from winlean import WINBOOL, DWORD
- type
- OSVERSIONINFO* {.final, pure.} = object
- dwOSVersionInfoSize*: DWORD
- dwMajorVersion*: DWORD
- dwMinorVersion*: DWORD
- dwBuildNumber*: DWORD
- dwPlatformId*: DWORD
- szCSDVersion*: array[0..127, char]
-
- proc GetVersionExA*(VersionInformation: var OSVERSIONINFO): WINBOOL{.stdcall,
- dynlib: "kernel32", importc: "GetVersionExA".}
-
-proc setupBinSymlink*(symlinkDest, symlinkFilename: string,
- options: Options): seq[string] =
- result = @[]
- let currentPerms = getFilePermissions(symlinkDest)
- setFilePermissions(symlinkDest, currentPerms + {fpUserExec})
- when defined(unix):
- display("Creating", "symlink: $1 -> $2" %
- [symlinkDest, symlinkFilename], priority = MediumPriority)
- if existsFile(symlinkFilename):
- let msg = "Symlink already exists in $1. Replacing." % symlinkFilename
- display("Warning:", msg, Warning, HighPriority)
- removeFile(symlinkFilename)
-
- createSymlink(symlinkDest, symlinkFilename)
- result.add symlinkFilename.extractFilename
- elif defined(windows):
- # There is a bug on XP, described here:
- # http://stackoverflow.com/questions/2182568/batch-script-is-not-executed-if-chcp-was-called
- # But this workaround brakes code page on newer systems, so we need to detect OS version
- var osver = OSVERSIONINFO()
- osver.dwOSVersionInfoSize = cast[DWORD](sizeof(OSVERSIONINFO))
- if GetVersionExA(osver) == WINBOOL(0):
- raise newException(NimbleError,
- "Can't detect OS version: GetVersionExA call failed")
- let fixChcp = osver.dwMajorVersion <= 5
-
- # Create cmd.exe/powershell stub.
- let dest = symlinkFilename.changeFileExt("cmd")
- display("Creating", "stub: $1 -> $2" % [symlinkDest, dest],
- priority = MediumPriority)
- var contents = "@"
- if options.config.chcp:
- if fixChcp:
- contents.add "chcp 65001 > nul && "
- else: contents.add "chcp 65001 > nul\n@"
- contents.add "\"" & symlinkDest & "\" %*\n"
- writeFile(dest, contents)
- result.add dest.extractFilename
- # For bash on Windows (Cygwin/Git bash).
- let bashDest = dest.changeFileExt("")
- display("Creating", "Cygwin stub: $1 -> $2" %
- [symlinkDest, bashDest], priority = MediumPriority)
- writeFile(bashDest, "\"" & symlinkDest & "\" \"$@\"\n")
- result.add bashDest.extractFilename
- else:
- {.error: "Sorry, your platform is not supported.".}
-
-proc saveNimbleMeta*(pkgDestDir, url, vcsRevision: string,
- filesInstalled, bins: HashSet[string],
- isLink: bool = false) =
- ## Saves the specified data into a ``nimblemeta.json`` file inside
- ## ``pkgDestDir``.
- ##
- ## filesInstalled - A list of absolute paths to files which have been
- ## installed.
- ## bins - A list of binary filenames which have been installed for this
- ## package.
- ##
- ## isLink - Determines whether the installed package is a .nimble-link.
- var nimblemeta = %{"url": %url}
- if vcsRevision.len > 0:
- nimblemeta["vcsRevision"] = %vcsRevision
- let files = newJArray()
- nimblemeta["files"] = files
- for file in filesInstalled:
- files.add(%changeRoot(pkgDestDir, "", file))
- let binaries = newJArray()
- nimblemeta["binaries"] = binaries
- for bin in bins:
- binaries.add(%bin)
- nimblemeta["isLink"] = %isLink
- writeFile(pkgDestDir / "nimblemeta.json", $nimblemeta)
-
-proc saveNimbleMeta*(pkgDestDir, pkgDir, vcsRevision, nimbleLinkPath: string) =
- ## Overload of saveNimbleMeta for linked (.nimble-link) packages.
- ##
- ## pkgDestDir - The directory where the package has been installed.
- ## For example: ~/.nimble/pkgs/jester-#head/
- ##
- ## pkgDir - The directory where the original package files are.
- ## For example: ~/projects/jester/
- saveNimbleMeta(pkgDestDir, "file://" & pkgDir, vcsRevision,
- toHashSet[string]([nimbleLinkPath]), initHashSet[string](), true)
\ No newline at end of file
diff --git a/src/nimblepkg/packageparser.nim b/src/nimblepkg/packageparser.nim
deleted file mode 100644
index 9458074..0000000
--- a/src/nimblepkg/packageparser.nim
+++ /dev/null
@@ -1,508 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-import parsecfg, sets, streams, strutils, os, tables, sugar
-from sequtils import apply, map
-
-import version, tools, common, nimscriptwrapper, options, packageinfo, cli
-
-## Contains procedures for parsing .nimble files. Moved here from ``packageinfo``
-## because it depends on ``nimscriptwrapper`` (``nimscriptwrapper`` also
-## depends on other procedures in ``packageinfo``.
-
-type
- NimbleFile* = string
-
- ValidationError* = object of NimbleError
- warnInstalled*: bool # Determines whether to show a warning for installed pkgs
- warnAll*: bool
-
-const reservedNames = [
- "CON",
- "PRN",
- "AUX",
- "NUL",
- "COM1",
- "COM2",
- "COM3",
- "COM4",
- "COM5",
- "COM6",
- "COM7",
- "COM8",
- "COM9",
- "LPT1",
- "LPT2",
- "LPT3",
- "LPT4",
- "LPT5",
- "LPT6",
- "LPT7",
- "LPT8",
- "LPT9",
-]
-
-proc newValidationError(msg: string, warnInstalled: bool,
- hint: string, warnAll: bool): ref ValidationError =
- result = newException(ValidationError, msg)
- result.warnInstalled = warnInstalled
- result.warnAll = warnAll
- result.hint = hint
-
-proc raiseNewValidationError(msg: string, warnInstalled: bool,
- hint: string = "", warnAll = false) =
- raise newValidationError(msg, warnInstalled, hint, warnAll)
-
-proc validatePackageName*(name: string) =
- ## Raises an error if specified package name contains invalid characters.
- ##
- ## A valid package name is one which is a valid nim module name. So only
- ## underscores, letters and numbers allowed.
- if name.len == 0: return
-
- if name[0] in {'0'..'9'}:
- raiseNewValidationError(name &
- "\"$1\" is an invalid package name: cannot begin with $2" %
- [name, $name[0]], true)
-
- var prevWasUnderscore = false
- for c in name:
- case c
- of '_':
- if prevWasUnderscore:
- raiseNewValidationError(
- "$1 is an invalid package name: cannot contain \"__\"" % name, true)
- prevWasUnderscore = true
- of AllChars - IdentChars:
- raiseNewValidationError(
- "$1 is an invalid package name: cannot contain '$2'" % [name, $c],
- true)
- else:
- prevWasUnderscore = false
-
- if name.endsWith("pkg"):
- raiseNewValidationError("\"$1\" is an invalid package name: cannot end" &
- " with \"pkg\"" % name, false)
- if name.toUpperAscii() in reservedNames:
- raiseNewValidationError(
- "\"$1\" is an invalid package name: reserved name" % name, false)
-
-proc validateVersion*(ver: string) =
- for c in ver:
- if c notin ({'.'} + Digits):
- raiseNewValidationError(
- "Version may only consist of numbers and the '.' character " &
- "but found '" & c & "'.", false)
-
-proc validatePackageStructure(pkgInfo: PackageInfo, options: Options) =
- ## This ensures that a package's source code does not leak into
- ## another package's namespace.
- ## https://github.com/nim-lang/nimble/issues/144
- let
- realDir = pkgInfo.getRealDir()
- normalizedBinNames = pkgInfo.bin.map(
- (x) => x.changeFileExt("").toLowerAscii()
- )
- correctDir =
- if pkgInfo.name.toLowerAscii() in normalizedBinNames:
- pkgInfo.name & "pkg"
- else:
- pkgInfo.name
-
- proc onFile(path: string) =
- # Remove the root to leave only the package subdirectories.
- # ~/package-0.1/package/utils.nim -> package/utils.nim.
- var trailPath = changeRoot(realDir, "", path)
- if trailPath.startsWith(DirSep): trailPath = trailPath[1 .. ^1]
- let (dir, file, ext) = trailPath.splitFile
- # We're only interested in nim files, because only they can pollute our
- # namespace.
- if ext != (ExtSep & "nim"):
- return
-
- if dir.len == 0:
- if file != pkgInfo.name:
- # A source file was found in the top level of srcDir that doesn't share
- # a name with the package.
- let
- msg = ("Package '$1' has an incorrect structure. " &
- "The top level of the package source directory " &
- "should contain at most one module, " &
- "named '$2', but a file named '$3' was found. This " &
- "will be an error in the future.") %
- [pkgInfo.name, pkgInfo.name & ext, file & ext]
- hint = ("If this is the primary source file in the package, " &
- "rename it to '$1'. If it's a source file required by " &
- "the main module, or if it is one of several " &
- "modules exposed by '$4', then move it into a '$2' subdirectory. " &
- "If it's a test file or otherwise not required " &
- "to build the the package '$1', prevent its installation " &
- "by adding `skipFiles = @[\"$3\"]` to the .nimble file. See " &
- "https://github.com/nim-lang/nimble#libraries for more info.") %
- [pkgInfo.name & ext, correctDir & DirSep, file & ext, pkgInfo.name]
- raiseNewValidationError(msg, true, hint, true)
- else:
- assert(not pkgInfo.isMinimal)
- # On Windows `pkgInfo.bin` has a .exe extension, so we need to normalize.
- if not (dir.startsWith(correctDir & DirSep) or dir == correctDir):
- let
- msg = ("Package '$2' has an incorrect structure. " &
- "It should contain a single directory hierarchy " &
- "for source files, named '$3', but file '$1' " &
- "is in a directory named '$4' instead. " &
- "This will be an error in the future.") %
- [file & ext, pkgInfo.name, correctDir, dir]
- hint = ("If '$1' contains source files for building '$2', rename it " &
- "to '$3'. Otherwise, prevent its installation " &
- "by adding `skipDirs = @[\"$1\"]` to the .nimble file.") %
- [dir, pkgInfo.name, correctDir]
- raiseNewValidationError(msg, true, hint, true)
-
- iterInstallFiles(realDir, pkgInfo, options, onFile)
-
-proc validatePackageInfo(pkgInfo: PackageInfo, options: Options) =
- let path = pkgInfo.myPath
- if pkgInfo.name == "":
- raiseNewValidationError("Incorrect .nimble file: " & path &
- " does not contain a name field.", false)
-
- if pkgInfo.name.normalize != path.splitFile.name.normalize:
- raiseNewValidationError(
- "The .nimble file name must match name specified inside " & path, true)
-
- if pkgInfo.version == "":
- raiseNewValidationError("Incorrect .nimble file: " & path &
- " does not contain a version field.", false)
-
- if not pkgInfo.isMinimal:
- if pkgInfo.author == "":
- raiseNewValidationError("Incorrect .nimble file: " & path &
- " does not contain an author field.", false)
- if pkgInfo.description == "":
- raiseNewValidationError("Incorrect .nimble file: " & path &
- " does not contain a description field.", false)
- if pkgInfo.license == "":
- raiseNewValidationError("Incorrect .nimble file: " & path &
- " does not contain a license field.", false)
- if pkgInfo.backend notin ["c", "cc", "objc", "cpp", "js"]:
- raiseNewValidationError("'" & pkgInfo.backend &
- "' is an invalid backend.", false)
-
- validatePackageStructure(pkginfo, options)
-
-
-proc nimScriptHint*(pkgInfo: PackageInfo) =
- if not pkgInfo.isNimScript:
- display("Warning:", "The .nimble file for this project could make use of " &
- "additional features, if converted into the new NimScript format." &
- "\nFor more details see:" &
- "https://github.com/nim-lang/nimble#creating-packages",
- Warning, HighPriority)
-
-proc multiSplit(s: string): seq[string] =
- ## Returns ``s`` split by newline and comma characters.
- ##
- ## Before returning, all individual entries are stripped of whitespace and
- ## also empty entries are purged from the list. If after all the cleanups are
- ## done no entries are found in the list, the proc returns a sequence with
- ## the original string as the only entry.
- result = split(s, {char(0x0A), char(0x0D), ','})
- apply(result, proc(x: var string) = x = x.strip())
- for i in countdown(result.len()-1, 0):
- if len(result[i]) < 1:
- result.del(i)
- # Huh, nothing to return? Return given input.
- if len(result) < 1:
- if s.strip().len != 0:
- return @[s]
- else:
- return @[]
-
-proc readPackageInfoFromNimble(path: string; result: var PackageInfo) =
- var fs = newFileStream(path, fmRead)
- if fs != nil:
- var p: CfgParser
- open(p, fs, path)
- defer: close(p)
- var currentSection = ""
- while true:
- var ev = next(p)
- case ev.kind
- of cfgEof:
- break
- of cfgSectionStart:
- currentSection = ev.section
- of cfgKeyValuePair:
- case currentSection.normalize
- of "package":
- case ev.key.normalize
- of "name": result.name = ev.value
- of "version": result.version = ev.value
- of "author": result.author = ev.value
- of "description": result.description = ev.value
- of "license": result.license = ev.value
- of "srcdir": result.srcDir = ev.value
- of "bindir": result.binDir = ev.value
- of "skipdirs":
- result.skipDirs.add(ev.value.multiSplit)
- of "skipfiles":
- result.skipFiles.add(ev.value.multiSplit)
- of "skipext":
- result.skipExt.add(ev.value.multiSplit)
- of "installdirs":
- result.installDirs.add(ev.value.multiSplit)
- of "installfiles":
- result.installFiles.add(ev.value.multiSplit)
- of "installext":
- 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":
- case ev.key.normalize
- of "requires":
- for v in ev.value.multiSplit:
- result.requires.add(parseRequires(v.strip))
- else:
- raise newException(NimbleError, "Invalid field: " & ev.key)
- else: raise newException(NimbleError,
- "Invalid section: " & currentSection)
- of cfgOption: raise newException(NimbleError,
- "Invalid package info, should not contain --" & ev.value)
- of cfgError:
- raise newException(NimbleError, "Error parsing .nimble file: " & ev.msg)
- 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.
- ##
- ## Attempts to read it using the "old" Nimble ini format first, if that
- ## fails attempts to evaluate it as a nimscript file.
- ##
- ## If both fail then returns an error.
- ##
- ## When ``onlyMinimalInfo`` is true, only the `name` and `version` fields are
- ## populated. The ``isNimScript`` field can also be relied on.
- ##
- ## This version uses a cache stored in ``options``, so calling it multiple
- ## times on the same ``nf`` shouldn't require re-evaluation of the Nimble
- ## file.
-
- assert fileExists(nf)
-
- # Check the cache.
- if options.pkgInfoCache.hasKey(nf):
- return options.pkgInfoCache[nf]
-
- result = initPackageInfo(nf)
- let minimalInfo = getNameVersion(nf)
-
- validatePackageName(nf.splitFile.name)
-
- var success = false
- var iniError: ref NimbleError
- # Attempt ini-format first.
- try:
- readPackageInfoFromNimble(nf, result)
- success = true
- result.isNimScript = false
- except NimbleError:
- iniError = (ref NimbleError)(getCurrentException())
-
- if not success:
- if onlyMinimalInfo:
- result.name = minimalInfo.name
- result.version = minimalInfo.version
- result.isNimScript = true
- result.isMinimal = true
-
- # It's possible this proc will receive a .nimble-link file eventually,
- # I added this assert to hopefully make this error clear for everyone.
- let msg = "No version detected. Received nimble-link?"
- assert result.version.len > 0, msg
- else:
- try:
- readPackageInfoFromNims(nf, options, result)
- result.isNimScript = true
- except NimbleError as exc:
- if exc.hint.len > 0:
- raise
- let msg = "Could not read package info file in " & nf & ";\n" &
- " Reading as ini file failed with: \n" &
- " " & iniError.msg & ".\n" &
- " Evaluating as NimScript file failed with: \n" &
- " " & exc.msg & "."
- raise newException(NimbleError, msg)
-
- # By default specialVersion is the same as version.
- result.specialVersion = result.version
-
- # Only attempt to read a special version if `nf` is inside the $nimbleDir.
- if nf.startsWith(options.getNimbleDir()):
- # The package directory name may include a "special" version
- # (example #head). If so, it is given higher priority and therefore
- # overwrites the .nimble file's version.
- let version = parseVersionRange(minimalInfo.version)
- if version.kind == verSpecial:
- result.specialVersion = minimalInfo.version
-
- # Apply rules to infer which files should/shouldn't be installed. See #469.
- inferInstallRules(result, options)
-
- if not result.isMinimal:
- options.pkgInfoCache[nf] = result
-
- # Validate the rest of the package info last.
- if not options.disableValidation:
- validateVersion(result.version)
- validatePackageInfo(result, options)
-
-proc validate*(file: NimbleFile, options: Options,
- error: var ValidationError, pkgInfo: var PackageInfo): bool =
- try:
- pkgInfo = readPackageInfo(file, options)
- except ValidationError as exc:
- error = exc[]
- return false
-
- return true
-
-proc getPkgInfoFromFile*(file: NimbleFile, options: Options): PackageInfo =
- ## Reads the specified .nimble file and returns its data as a PackageInfo
- ## object. Any validation errors are handled and displayed as warnings.
- try:
- result = readPackageInfo(file, options)
- except ValidationError:
- let exc = (ref ValidationError)(getCurrentException())
- if exc.warnAll:
- display("Warning:", exc.msg, Warning, HighPriority)
- display("Hint:", exc.hint, Warning, HighPriority)
- else:
- raise
-
-proc getPkgInfo*(dir: string, options: Options): PackageInfo =
- ## Find the .nimble file in ``dir`` and parses it, returning a PackageInfo.
- let nimbleFile = findNimbleFile(dir, true)
- return getPkgInfoFromFile(nimbleFile, options)
-
-proc getInstalledPkgs*(libsDir: string, options: Options):
- seq[tuple[pkginfo: PackageInfo, meta: MetaData]] =
- ## Gets a list of installed packages.
- ##
- ## ``libsDir`` is in most cases: ~/.nimble/pkgs/
- const
- readErrorMsg = "Installed package '$1@$2' is outdated or corrupt."
- validationErrorMsg = readErrorMsg & "\nPackage did not pass validation: $3"
- hintMsg = "The corrupted package will need to be removed manually. To fix" &
- " this error message, remove $1."
-
- proc createErrorMsg(tmplt, path, msg: string): string =
- let (name, version) = getNameVersion(path)
- return tmplt % [name, version, msg]
-
- display("Loading", "list of installed packages", priority = MediumPriority)
-
- result = @[]
- for kind, path in walkDir(libsDir):
- if kind == pcDir:
- let nimbleFile = findNimbleFile(path, false)
- if nimbleFile != "":
- let meta = readMetaData(path)
- var pkg: PackageInfo
- try:
- pkg = readPackageInfo(nimbleFile, options, onlyMinimalInfo=false)
- except ValidationError:
- let exc = (ref ValidationError)(getCurrentException())
- exc.msg = createErrorMsg(validationErrorMsg, path, exc.msg)
- exc.hint = hintMsg % path
- if exc.warnInstalled or exc.warnAll:
- display("Warning:", exc.msg, Warning, HighPriority)
- # Don't show hints here because they are only useful for package
- # owners.
- else:
- raise exc
- except:
- let tmplt = readErrorMsg & "\nMore info: $3"
- let msg = createErrorMsg(tmplt, path, getCurrentException().msg)
- var exc = newException(NimbleError, msg)
- exc.hint = hintMsg % path
- raise exc
-
- pkg.isInstalled = true
- pkg.isLinked =
- cmpPaths(nimbleFile.splitFile().dir, path) != 0
- result.add((pkg, meta))
-
-proc isNimScript*(nf: string, options: Options): bool =
- result = readPackageInfo(nf, options).isNimScript
-
-proc toFullInfo*(pkg: PackageInfo, options: Options): PackageInfo =
- if pkg.isMinimal:
- result = getPkgInfoFromFile(pkg.mypath, options)
- result.isInstalled = pkg.isInstalled
- result.isLinked = pkg.isLinked
- 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")
- try:
- validatePackageName("foo__bar")
- assert false
- except NimbleError:
- assert true
-
- echo("Everything passed!")
diff --git a/src/nimblepkg/publish.nim b/src/nimblepkg/publish.nim
deleted file mode 100644
index f11b979..0000000
--- a/src/nimblepkg/publish.nim
+++ /dev/null
@@ -1,229 +0,0 @@
-# Copyright (C) Andreas Rumpf. All rights reserved.
-# BSD License. Look at license.txt for more info.
-
-## Implements 'nimble publish' to create a pull request against
-## nim-lang/packages automatically.
-
-import system except TResult
-import httpclient, strutils, json, os, browsers, times, uri
-import version, tools, common, cli, config, options
-
-type
- Auth = object
- user: string
- token: string ## Github access token
- http: HttpClient ## http client for doing API requests
-
-const
- ApiKeyFile = "github_api_token"
- ApiTokenEnvironmentVariable = "NIMBLE_GITHUB_API_TOKEN"
- ReposUrl = "https://api.github.com/repos/"
-
-proc userAborted() =
- raise newException(NimbleError, "User aborted the process.")
-
-proc createHeaders(a: Auth) =
- a.http.headers = newHttpHeaders({
- "Authorization": "token $1" % a.token,
- "Content-Type": "application/x-www-form-urlencoded",
- "Accept": "*/*"
- })
-
-proc requestNewToken(cfg: Config): string =
- display("Info:", "Please create a new personal access token on Github in" &
- " order to allow Nimble to fork the packages repository.",
- priority = HighPriority)
- display("Hint:", "Make sure to give the access token access to public repos" &
- " (public_repo scope)!", Warning, HighPriority)
- sleep(5000)
- display("Info:", "Your default browser should open with the following URL: " &
- "https://github.com/settings/tokens/new", priority = HighPriority)
- sleep(3000)
- openDefaultBrowser("https://github.com/settings/tokens/new")
- let token = promptCustom("Personal access token?", "").strip()
- # inform the user that their token will be written to disk
- let tokenWritePath = cfg.nimbleDir / ApiKeyFile
- display("Info:", "Writing access token to file:" & tokenWritePath,
- priority = HighPriority)
- writeFile(tokenWritePath, token)
- sleep(3000)
- return token
-
-proc getGithubAuth(o: Options): Auth =
- let cfg = o.config
- result.http = newHttpClient(proxy = getProxy(o))
- # always prefer the environment variable to asking for a new one
- if existsEnv(ApiTokenEnvironmentVariable):
- result.token = getEnv(ApiTokenEnvironmentVariable)
- display("Info:", "Using the '" & ApiTokenEnvironmentVariable &
- "' environment variable for the GitHub API Token.",
- priority = HighPriority)
- else:
- # try to read from disk, if it cannot be found write a new one
- try:
- let apiTokenFilePath = cfg.nimbleDir / ApiKeyFile
- result.token = readFile(apiTokenFilePath).strip()
- display("Info:", "Using GitHub API Token in file: " & apiTokenFilePath,
- priority = HighPriority)
- except IOError:
- result.token = requestNewToken(cfg)
- createHeaders(result)
- let resp = result.http.getContent("https://api.github.com/user").parseJson()
-
- result.user = resp["login"].str
- display("Success:", "Verified as " & result.user, Success, HighPriority)
-
-proc isCorrectFork(j: JsonNode): bool =
- # Check whether this is a fork of the nimble packages repo.
- result = false
- if j{"fork"}.getBool():
- result = j{"parent"}{"full_name"}.getStr() == "nim-lang/packages"
-
-proc forkExists(a: Auth): bool =
- try:
- let x = a.http.getContent(ReposUrl & a.user & "/packages")
- let j = parseJson(x)
- result = isCorrectFork(j)
- except JsonParsingError, IOError:
- result = false
-
-proc createFork(a: Auth) =
- try:
- discard a.http.postContent(ReposUrl & "nim-lang/packages/forks")
- except HttpRequestError:
- raise newException(NimbleError, "Unable to create fork. Access token" &
- " might not have enough permissions.")
-
-proc createPullRequest(a: Auth, packageName, branch: string): string =
- display("Info", "Creating PR", priority = HighPriority)
- var body = a.http.postContent(ReposUrl & "nim-lang/packages/pulls",
- body="""{"title": "Add package $1", "head": "$2:$3",
- "base": "master"}""" % [packageName, a.user, branch])
- var pr = parseJson(body)
- return pr{"html_url"}.getStr()
-
-proc `%`(s: openArray[string]): JsonNode =
- result = newJArray()
- for x in s: result.add(%x)
-
-proc cleanupWhitespace(s: string): string =
- ## Removes trailing whitespace and normalizes line endings to LF.
- result = newStringOfCap(s.len)
- var i = 0
- while i < s.len:
- if s[i] == ' ':
- var j = i+1
- while s[j] == ' ': inc j
- if s[j] == '\c':
- inc j
- if s[j] == '\L': inc j
- result.add '\L'
- i = j
- elif s[j] == '\L':
- result.add '\L'
- i = j+1
- else:
- result.add ' '
- inc i
- elif s[i] == '\c':
- inc i
- if s[i] == '\L': inc i
- result.add '\L'
- elif s[i] == '\L':
- result.add '\L'
- inc i
- else:
- result.add s[i]
- inc i
- if result[^1] != '\L':
- result.add '\L'
-
-proc editJson(p: PackageInfo; url, tags, downloadMethod: string) =
- var contents = parseFile("packages.json")
- doAssert contents.kind == JArray
- contents.add(%*{
- "name": p.name,
- "url": url,
- "method": downloadMethod,
- "tags": tags.split(),
- "description": p.description,
- "license": p.license,
- "web": url
- })
- writeFile("packages.json", contents.pretty.cleanupWhitespace)
-
-proc publish*(p: PackageInfo, o: Options) =
- ## Publishes the package p.
- let auth = getGithubAuth(o)
- var pkgsDir = getNimbleUserTempDir() / "nimble-packages-fork"
- if not forkExists(auth):
- createFork(auth)
- display("Info:", "Waiting 10s to let Github create a fork",
- priority = HighPriority)
- os.sleep(10_000)
-
- display("Info:", "Finished waiting", priority = LowPriority)
- if dirExists(pkgsDir):
- display("Removing", "old packages fork git directory.",
- priority = LowPriority)
- removeDir(pkgsDir)
- createDir(pkgsDir)
- cd pkgsDir:
- # Avoid git clone to prevent token from being stored in repo
- # https://github.com/blog/1270-easier-builds-and-deployments-using-git-over-https-and-oauth
- display("Copying", "packages fork into: " & pkgsDir, priority = HighPriority)
- doCmd("git init")
- doCmd("git pull https://github.com/" & auth.user & "/packages")
- # Make sure to update the fork
- display("Updating", "the fork", priority = HighPriority)
- doCmd("git pull https://github.com/nim-lang/packages.git master")
- doCmd("git push https://" & auth.token & "@github.com/" & auth.user & "/packages master")
-
- if not dirExists(pkgsDir):
- raise newException(NimbleError,
- "Cannot find nimble-packages-fork git repository. Cloning failed.")
-
- if not fileExists(pkgsDir / "packages.json"):
- raise newException(NimbleError,
- "No packages file found in cloned fork.")
-
- # We need to do this **before** the cd:
- # Determine what type of repo this is.
- var url = ""
- var downloadMethod = ""
- if dirExists(os.getCurrentDir() / ".git"):
- let (output, exitCode) = doCmdEx("git ls-remote --get-url")
- if exitCode == 0:
- url = output.string.strip
- if url.endsWith(".git"): url.setLen(url.len - 4)
- downloadMethod = "git"
- let parsed = parseUri(url)
- if parsed.scheme == "":
- # Assuming that we got an ssh write/read URL.
- let sshUrl = parseUri("ssh://" & url)
- url = "https://" & sshUrl.hostname & "/" & sshUrl.port & sshUrl.path
- elif dirExists(os.getCurrentDir() / ".hg"):
- downloadMethod = "hg"
- # TODO: Retrieve URL from hg.
- else:
- raise newException(NimbleError,
- "No .git nor .hg directory found. Stopping.")
-
- if url.len == 0:
- 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)",
- ""
- )
-
- cd pkgsDir:
- editJson(p, url, tags, downloadMethod)
- let branchName = "add-" & p.name & getTime().utc.format("HHmm")
- doCmd("git checkout -B " & branchName)
- doCmd("git commit packages.json -m \"Added package " & p.name & "\"")
- display("Pushing", "to remote of fork.", priority = HighPriority)
- doCmd("git push https://" & auth.token & "@github.com/" & auth.user & "/packages " & branchName)
- let prUrl = createPullRequest(auth, p.name, branchName)
- display("Success:", "Pull request successful, check at " & prUrl , Success, HighPriority)
diff --git a/src/nimblepkg/reversedeps.nim b/src/nimblepkg/reversedeps.nim
deleted file mode 100644
index 45d9940..0000000
--- a/src/nimblepkg/reversedeps.nim
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright (C) Dominik Picheta. All rights reserved.
-# BSD License. Look at license.txt for more info.
-
-import os, json, sets
-
-import options, common, version, download, packageinfo
-
-proc saveNimbleData*(options: Options) =
- # TODO: This file should probably be locked.
- writeFile(options.getNimbleDir() / "nimbledata.json",
- pretty(options.nimbleData))
-
-proc addRevDep*(nimbleData: JsonNode, dep: tuple[name, version: string],
- pkg: PackageInfo) =
- # Add a record which specifies that `pkg` has a dependency on `dep`, i.e.
- # the reverse dependency of `dep` is `pkg`.
- if not nimbleData["reverseDeps"].hasKey(dep.name):
- nimbleData["reverseDeps"][dep.name] = newJObject()
- if not nimbleData["reverseDeps"][dep.name].hasKey(dep.version):
- nimbleData["reverseDeps"][dep.name][dep.version] = newJArray()
- let revDep = %{ "name": %pkg.name, "version": %pkg.specialVersion}
- let thisDep = nimbleData["reverseDeps"][dep.name][dep.version]
- if revDep notin thisDep:
- thisDep.add revDep
-
-proc removeRevDep*(nimbleData: JsonNode, pkg: PackageInfo) =
- ## Removes ``pkg`` from the reverse dependencies of every package.
- assert(not pkg.isMinimal)
- proc remove(pkg: PackageInfo, depTup: PkgTuple, thisDep: JsonNode) =
- for ver, val in thisDep:
- if ver.newVersion in depTup.ver:
- var newVal = newJArray()
- for revDep in val:
- if not (revDep["name"].str == pkg.name and
- revDep["version"].str == pkg.specialVersion):
- newVal.add revDep
- thisDep[ver] = newVal
-
- for depTup in pkg.requires:
- if depTup.name.isURL():
- # We sadly must go through everything in this case...
- for key, val in nimbleData["reverseDeps"]:
- remove(pkg, depTup, val)
- else:
- let thisDep = nimbleData{"reverseDeps", depTup.name}
- if thisDep.isNil: continue
- remove(pkg, depTup, thisDep)
-
- # Clean up empty objects/arrays
- var newData = newJObject()
- for key, val in nimbleData["reverseDeps"]:
- if val.len != 0:
- var newVal = newJObject()
- for ver, elem in val:
- if elem.len != 0:
- newVal[ver] = elem
- if newVal.len != 0:
- newData[key] = newVal
- nimbleData["reverseDeps"] = newData
-
-proc getRevDepTups*(options: Options, pkg: PackageInfo): seq[PkgTuple] =
- ## Returns a list of *currently installed* reverse dependencies for `pkg`.
- result = @[]
- let thisPkgsDep =
- options.nimbleData["reverseDeps"]{pkg.name}{pkg.specialVersion}
- if not thisPkgsDep.isNil:
- let pkgList = getInstalledPkgsMin(options.getPkgsDir(), options)
- for pkg in thisPkgsDep:
- let pkgTup = (
- name: pkg["name"].getStr(),
- ver: parseVersionRange(pkg["version"].getStr())
- )
- var pkgInfo: PackageInfo
- if not findPkg(pkgList, pkgTup, pkgInfo):
- continue
-
- result.add(pkgTup)
-
-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()}
-
- let nimforum1 = PackageInfo(
- isMinimal: false,
- name: "nimforum",
- specialVersion: "0.1.0",
- requires: @[("jester", parseVersionRange("0.1.0")),
- ("captcha", parseVersionRange("1.0.0")),
- ("auth", parseVersionRange("#head"))]
- )
- let nimforum2 = PackageInfo(isMinimal: false, name: "nimforum", specialVersion: "0.2.0")
- let play = PackageInfo(isMinimal: false, name: "play", specialVersion: "#head")
-
- nimbleData.addRevDep(("jester", "0.1.0"), nimforum1)
- nimbleData.addRevDep(("jester", "0.1.0"), play)
- nimbleData.addRevDep(("captcha", "1.0.0"), nimforum1)
- nimbleData.addRevDep(("auth", "#head"), nimforum1)
- nimbleData.addRevDep(("captcha", "1.0.0"), nimforum2)
- nimbleData.addRevDep(("auth", "#head"), nimforum2)
-
- doAssert nimbleData["reverseDeps"]["jester"]["0.1.0"].len == 2
- doAssert nimbleData["reverseDeps"]["captcha"]["1.0.0"].len == 2
- doAssert nimbleData["reverseDeps"]["auth"]["#head"].len == 2
-
- block:
- nimbleData.removeRevDep(nimforum1)
- let jester = nimbleData["reverseDeps"]["jester"]["0.1.0"][0]
- doAssert jester["name"].getStr() == play.name
- doAssert jester["version"].getStr() == play.specialVersion
-
- let captcha = nimbleData["reverseDeps"]["captcha"]["1.0.0"][0]
- doAssert captcha["name"].getStr() == nimforum2.name
- doAssert captcha["version"].getStr() == nimforum2.specialVersion
-
- echo("Everything works!")
-
diff --git a/src/nimblepkg/tools.nim b/src/nimblepkg/tools.nim
index a0e6a0e..ac2f76f 100644
--- a/src/nimblepkg/tools.nim
+++ b/src/nimblepkg/tools.nim
@@ -2,52 +2,31 @@
# BSD License. Look at license.txt for more info.
#
# Various miscellaneous utility functions reside here.
-import osproc, pegs, strutils, os, uri, sets, json, parseutils
-import version, cli
+import osproc, pegs, strutils, os, uri, sets, json
+import version, packageinfo, nimbletypes
-proc extractBin(cmd: string): string =
- if cmd[0] == '"':
- return cmd.captureBetween('"')
- else:
- return cmd.split(' ')[0]
-
-proc doCmd*(cmd: string, showOutput = false, showCmd = false) =
- let bin = extractBin(cmd)
+proc doCmd*(cmd: string) =
+ let bin = cmd.split(' ')[0]
if findExe(bin) == "":
raise newException(NimbleError, "'" & bin & "' not in PATH.")
-
+
# To keep output in sequence
stdout.flushFile()
stderr.flushFile()
- if showCmd:
- display("Executing", cmd, priority = MediumPriority)
- else:
- displayDebug("Executing", cmd)
- if showOutput:
- let exitCode = execCmd(cmd)
- displayDebug("Finished", "with exit code " & $exitCode)
- if exitCode != QuitSuccess:
- raise newException(NimbleError,
- "Execution failed with exit code $1\nCommand: $2" %
- [$exitCode, cmd])
- else:
- let (output, exitCode) = execCmdEx(cmd)
- displayDebug("Finished", "with exit code " & $exitCode)
- displayDebug("Output", output)
+ let exitCode = execCmd(cmd)
- if exitCode != QuitSuccess:
- raise newException(NimbleError,
- "Execution failed with exit code $1\nCommand: $2\nOutput: $3" %
- [$exitCode, cmd, output])
+ if exitCode != QuitSuccess:
+ raise newException(NimbleError,
+ "Execution failed with exit code " & $exitCode)
proc doCmdEx*(cmd: string): tuple[output: TaintedString, exitCode: int] =
- let bin = extractBin(cmd)
+ let bin = cmd.split(' ')[0]
if findExe(bin) == "":
raise newException(NimbleError, "'" & bin & "' not in PATH.")
return execCmdEx(cmd)
-template cd*(dir: string, body: untyped) =
+template cd*(dir: string, body: stmt) =
## Sets the current dir to ``dir``, executes ``body`` and restores the
## previous working dir.
let lastDir = getCurrentDir()
@@ -57,15 +36,15 @@ template cd*(dir: string, body: untyped) =
proc getNimBin*: string =
result = "nim"
- if findExe("nim") != "": result = findExe("nim")
- elif findExe("nimrod") != "": result = findExe("nimrod")
+ if findExe("nim") != "": result = "nim"
+ elif findExe("nimrod") != "": result = "nimrod"
proc getNimrodVersion*: Version =
let nimBin = getNimBin()
- let vOutput = doCmdEx('"' & nimBin & "\" -v").output
+ let vOutput = doCmdEx(nimBin & " -v").output
var matches: array[0..MaxSubpatterns, string]
if vOutput.find(peg"'Version'\s{(\d+\.)+\d}", matches) == -1:
- raise newException(NimbleError, "Couldn't find Nim version.")
+ quit("Couldn't find Nim version.", QuitFailure)
newVersion(matches[0])
proc samePaths*(p1, p2: string): bool =
@@ -74,7 +53,7 @@ proc samePaths*(p1, p2: string): bool =
var cp2 = if not p2.endsWith("/"): p2 & "/" else: p2
cp1 = cp1.replace('/', DirSep).replace('\\', DirSep)
cp2 = cp2.replace('/', DirSep).replace('\\', DirSep)
-
+
return cmpPaths(cp1, cp2) == 0
proc changeRoot*(origRoot, newRoot, path: string): string =
@@ -82,37 +61,26 @@ proc changeRoot*(origRoot, newRoot, path: string): string =
## newRoot: /home/test/
## path: /home/dom/bar/blah/2/foo.txt
## Return value -> /home/test/bar/blah/2/foo.txt
-
- ## The additional check of `path.samePaths(origRoot)` is necessary to prevent
- ## a regression, where by ending the `srcDir` defintion in a nimble file in a
- ## trailing separator would cause the `path.startsWith(origRoot)` evaluation to
- ## fail because of the value of `origRoot` would be longer than `path` due to
- ## the trailing separator. This would cause this method to throw during package
- ## installation.
- if path.startsWith(origRoot) or path.samePaths(origRoot):
- return newRoot / path.substr(origRoot.len, path.len-1)
+ if path.startsWith(origRoot):
+ return newRoot / path[origRoot.len .. path.len-1]
else:
raise newException(ValueError,
"Cannot change root of path: Path does not begin with original root.")
proc copyFileD*(fro, to: string): string =
## Returns the destination (``to``).
- display("Copying", "file $# to $#" % [fro, to], priority = LowPriority)
- copyFileWithPermissions(fro, to)
+ echo(fro, " -> ", to)
+ copyFile(fro, to)
result = to
proc copyDirD*(fro, to: string): seq[string] =
## Returns the filenames of the files in the directory that were copied.
result = @[]
- display("Copying", "directory $# to $#" % [fro, to], priority = LowPriority)
+ echo("Copying directory: ", fro, " -> ", to)
for path in walkDirRec(fro):
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 = ""
@@ -128,7 +96,7 @@ proc getDownloadDirName*(uri: string, verRange: VersionRange): string =
of strutils.Letters, strutils.Digits:
result.add i
else: discard
-
+
let verSimple = getSimpleString(verRange)
if verSimple != "":
result.add "_"
@@ -138,47 +106,12 @@ proc incl*(s: var HashSet[string], v: seq[string] | HashSet[string]) =
for i in v:
s.incl i
-when not declared(json.contains):
- proc contains*(j: JsonNode, elem: JsonNode): bool =
- for i in j:
- if i == elem:
- return true
+proc contains*(j: JsonNode, elem: JsonNode): bool =
+ for i in j:
+ if i == elem:
+ return true
proc contains*(j: JsonNode, elem: tuple[key: string, val: JsonNode]): bool =
for key, val in pairs(j):
if key == elem.key and val == elem.val:
return true
-
-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.
- ##
- ## The returned path will be the same for the duration of the process but
- ## different for different runs of it. You have to make sure to create it
- ## first. In release builds the directory will be removed when nimble finishes
- ## its work.
- result = getTempDir() / "nimble_" & 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"))
- else:
- tmpdir = getTempDir()
- return tmpdir
diff --git a/src/nimblepkg/version.nim b/src/nimblepkg/version.nim
index e4114f1..1960882 100644
--- a/src/nimblepkg/version.nim
+++ b/src/nimblepkg/version.nim
@@ -5,6 +5,7 @@
import strutils, tables, hashes, parseutils
type
Version* = distinct string
+ Special* = distinct string
VersionRangeEnum* = enum
verLater, # > V
@@ -22,43 +23,26 @@ type
of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
ver*: Version
of verSpecial:
- spe*: Version
+ spe*: Special
of verIntersect:
verILeft, verIRight: VersionRange
of verAny:
nil
- ## Tuple containing package name and version range.
- PkgTuple* = tuple[name: string, ver: VersionRange]
-
ParseVersionError* = object of ValueError
- NimbleError* = object of Exception
- hint*: string
+
+proc newVersion*(ver: string): Version = return Version(ver)
+proc newSpecial*(spe: string): Special = return Special(spe)
proc `$`*(ver: Version): string {.borrow.}
-proc hash*(ver: Version): Hash {.borrow.}
+proc hash*(ver: Version): THash {.borrow.}
-proc newVersion*(ver: string): Version =
- doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits,
- "Wrong version: " & ver)
- return Version(ver)
+proc `$`*(ver: Special): string {.borrow.}
-proc isSpecial*(ver: Version): bool =
- return ($ver).len > 0 and ($ver)[0] == '#'
+proc hash*(ver: Special): THash {.borrow.}
proc `<`*(ver: Version, ver2: Version): bool =
- # Handling for special versions such as "#head" or "#branch".
- if ver.isSpecial or ver2.isSpecial:
- # TODO: This may need to be reverted. See #311.
- if ver2.isSpecial and ($ver2).normalize == "#head":
- return ($ver).normalize != "#head"
-
- if not ver2.isSpecial:
- # `#aa111 < 1.1`
- return ($ver).normalize != "#head"
-
- # Handling for normal versions such as "0.1.0" or "1.0".
var sVer = string(ver).split('.')
var sVer2 = string(ver2).split('.')
for i in 0..max(sVer.len, sVer2.len)-1:
@@ -76,9 +60,6 @@ proc `<`*(ver: Version, ver2: Version): bool =
return false
proc `==`*(ver: Version, ver2: Version): bool =
- if ver.isSpecial or ver2.isSpecial:
- return ($ver).toLowerAscii() == ($ver2).toLowerAscii()
-
var sVer = string(ver).split('.')
var sVer2 = string(ver2).split('.')
for i in 0..max(sVer.len, sVer2.len)-1:
@@ -93,10 +74,8 @@ 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 `==`*(spe: Special, spe2: Special): bool =
+ return ($spe).toLower() == ($spe2).toLower()
proc `<=`*(ver: Version, ver2: Version): bool =
return (ver == ver2) or (ver < ver2)
@@ -125,54 +104,64 @@ proc withinRange*(ver: Version, ran: VersionRange): bool =
of verEq:
return ver == ran.ver
of verSpecial:
- return ver == ran.spe
+ return false
of verIntersect:
return withinRange(ver, ran.verILeft) and withinRange(ver, ran.verIRight)
of verAny:
return true
+proc withinRange*(spe: Special, ran: VersionRange): bool =
+ case ran.kind
+ of verLater, verEarlier, verEqLater, verEqEarlier, verEq, verIntersect:
+ return false
+ of verSpecial:
+ return spe == ran.spe
+ of verAny:
+ return true
+
proc contains*(ran: VersionRange, ver: Version): bool =
return withinRange(ver, ran)
+proc contains*(ran: VersionRange, spe: Special): bool =
+ return withinRange(spe, ran)
+
proc makeRange*(version: string, op: string): VersionRange =
+ new(result)
if version == "":
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
- if s.len == 0:
- result = VersionRange(kind: verAny)
- return
-
+ new(result)
if s[0] == '#':
- result = VersionRange(kind: verSpecial)
- result.spe = s.Version
+ result.kind = verSpecial
+ result.spe = s[1 .. s.len-1].Special
return
var i = 0
var op = ""
var version = ""
- while i < s.len:
+ while true:
case s[i]
of '>', '<', '=':
op.add(s[i])
of '&':
- result = VersionRange(kind: verIntersect)
+ result.kind = verIntersect
result.verILeft = makeRange(version, op)
# Parse everything after &
@@ -185,50 +174,26 @@ 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 '\0':
+ result = makeRange(version, op)
+ break
+
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.")
else:
raise newException(ParseVersionError,
- "Unexpected char in version range '" & s & "': " & s[i])
+ "Unexpected char in version range: " & s[i])
inc(i)
- result = makeRange(version, op)
-
-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.spe = ver
- else:
- result = VersionRange(kind: verEq)
- result.ver = ver
-
-proc parseRequires*(req: string): PkgTuple =
- try:
- if ' ' in req:
- var i = skipUntil(req, Whitespace)
- result.name = req[0 .. i].strip
- result.ver = parseVersionRange(req[i .. req.len-1])
- elif '#' in req:
- var i = skipUntil(req, {'#'})
- result.name = req[0 .. i-1]
- result.ver = parseVersionRange(req[i .. req.len-1])
- else:
- result.name = req.strip
- result.ver = VersionRange(kind: verAny)
- except ParseVersionError:
- raise newException(NimbleError,
- "Unable to parse dependency version range: " & getCurrentExceptionMsg())
proc `$`*(verRange: VersionRange): string =
case verRange.kind
@@ -243,7 +208,7 @@ proc `$`*(verRange: VersionRange): string =
of verEq:
result = ""
of verSpecial:
- return $verRange.spe
+ return "#" & $verRange.spe
of verIntersect:
return $verRange.verILeft & " & " & $verRange.verIRight
of verAny:
@@ -266,42 +231,41 @@ 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
if ver > result.ver:
result = (ver, tag)
-proc `$`*(dep: PkgTuple): string =
- return dep.name & "@" & $dep.ver
-
when isMainModule:
doAssert(newVersion("1.0") < newVersion("1.4"))
doAssert(newVersion("1.0.1") > newVersion("1.0"))
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 +279,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")
@@ -328,34 +289,13 @@ when isMainModule:
#doAssert newVersion("0.1-rc1") < newVersion("0.1")
# Special tests
- doAssert newVersion("#ab26sgdt362") != newVersion("#qwersaggdt362")
- doAssert newVersion("#ab26saggdt362") == newVersion("#ab26saggdt362")
- doAssert newVersion("#head") == newVersion("#HEAD")
- doAssert newVersion("#head") == newVersion("#head")
+ doAssert newSpecial("ab26sgdt362") != newSpecial("ab26saggdt362")
+ doAssert newSpecial("ab26saggdt362") == newSpecial("ab26saggdt362")
+ doAssert newSpecial("head") == newSpecial("HEAD")
+ doAssert newSpecial("head") == newSpecial("head")
var sp = parseVersionRange("#ab26sgdt362")
- doAssert newVersion("#ab26sgdt362") in sp
- doAssert newVersion("#ab26saggdt362") notin sp
-
- doAssert newVersion("#head") in parseVersionRange("#head")
-
- # We assume that #head > 0.1.0, in practice this shouldn't be a problem.
- doAssert(newVersion("#head") > newVersion("0.1.0"))
- doAssert(not(newVersion("#head") > newVersion("#head")))
- doAssert(withinRange(newVersion("#head"), parseVersionRange(">= 0.5.0")))
- doAssert newVersion("#a111") < newVersion("#head")
- # We assume that all other special versions are not higher than a normal
- # version.
- doAssert newVersion("#a111") < newVersion("1.1")
-
- # An empty version range should give verAny
- doAssert parseVersionRange("").kind == verAny
-
- # toVersionRange tests
- doAssert toVersionRange(newVersion("#head")).kind == verSpecial
- doAssert toVersionRange(newVersion("0.2.0")).kind == verEq
-
- # Something raised on IRC
- doAssert newVersion("1") == newVersion("1.0")
+ doAssert newSpecial("ab26sgdt362") in sp
+ doAssert newSpecial("ab26saggdt362") notin sp
echo("Everything works!")
diff --git a/tests/.gitignore b/tests/.gitignore
deleted file mode 100644
index 42549a0..0000000
--- a/tests/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-tester
-/nimble-test
-/buildDir
-/binaryPackage/v1/binaryPackage
-/binaryPackage/v2/binaryPackage
-/develop/dependent/src/dependent
-/issue27/issue27
-/issue206/issue/issue206bin
-/issue289/issue289
-/issue428/nimbleDir/
-/nimbleDir/
-/packageStructure/c/c
-/packageStructure/y/y
-/testCommand/testOverride/myTester
-/testCommand/testsFail/tests/a
-/testCommand/testsFail/tests/b
-/testCommand/testsPass/tests/one
-/testCommand/testsPass/tests/three
-/testCommand/testsPass/tests/two
-/nimscript/nimscript
-/packageStructure/validBinary/y
-/testCommand/testsFail/tests/t2
-/passNimFlags/passNimFlags
diff --git a/tests/binaryPackage/v1/binaryPackage.nim b/tests/binaryPackage/v1/binaryPackage.nim
deleted file mode 100644
index e094d7c..0000000
--- a/tests/binaryPackage/v1/binaryPackage.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("v1")
\ No newline at end of file
diff --git a/tests/binaryPackage/v1/binaryPackage.nimble b/tests/binaryPackage/v1/binaryPackage.nimble
deleted file mode 100644
index 6031ae9..0000000
--- a/tests/binaryPackage/v1/binaryPackage.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-version = "1.0"
-author = "Dominik Picheta"
-description = "binary"
-license = "MIT"
-
-bin = @["binaryPackage"]
-
-# Dependencies
-
-requires "nim >= 0.15.3"
diff --git a/tests/binaryPackage/v2/binaryPackage.nim b/tests/binaryPackage/v2/binaryPackage.nim
deleted file mode 100644
index 1168967..0000000
--- a/tests/binaryPackage/v2/binaryPackage.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("v2")
\ No newline at end of file
diff --git a/tests/binaryPackage/v2/binaryPackage.nimble b/tests/binaryPackage/v2/binaryPackage.nimble
deleted file mode 100644
index cfe2a9e..0000000
--- a/tests/binaryPackage/v2/binaryPackage.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-version = "2.0"
-author = "Dominik Picheta"
-description = "binary"
-license = "MIT"
-
-bin = @["binaryPackage"]
-
-# Dependencies
-
-requires "nim >= 0.15.3"
diff --git a/tests/caching/caching.nimble b/tests/caching/caching.nimble
deleted file mode 100644
index d3035a9..0000000
--- a/tests/caching/caching.nimble
+++ /dev/null
@@ -1,10 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Test package"
-license = "BSD"
-
-# Dependencies
-
-requires "nim >= 0.12.1"
diff --git a/tests/develop/binary/binary.nim b/tests/develop/binary/binary.nim
deleted file mode 100644
index 53c687a..0000000
--- a/tests/develop/binary/binary.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("hello")
\ No newline at end of file
diff --git a/tests/develop/binary/binary.nimble b/tests/develop/binary/binary.nimble
deleted file mode 100644
index b80a50e..0000000
--- a/tests/develop/binary/binary.nimble
+++ /dev/null
@@ -1,14 +0,0 @@
-# Package
-
-version = "1.0"
-author = "Dominik Picheta"
-description = "binary"
-license = "MIT"
-
-bin = @["binary"]
-
-skipExt = @["nim"]
-
-# Dependencies
-
-requires "nim >= 0.16.0"
diff --git a/tests/develop/dependent/dependent.nimble b/tests/develop/dependent/dependent.nimble
deleted file mode 100644
index 7bab4b7..0000000
--- a/tests/develop/dependent/dependent.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-version = "1.0"
-author = "Dominik Picheta"
-description = "dependent"
-license = "MIT"
-
-srcDir = "src"
-
-# Dependencies
-
-requires "nim >= 0.16.0", "srcdirtest"
diff --git a/tests/develop/dependent/src/dependent.nim b/tests/develop/dependent/src/dependent.nim
deleted file mode 100644
index 37231ba..0000000
--- a/tests/develop/dependent/src/dependent.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-import srcdirtest
-
-doAssert foo() == "correct"
\ No newline at end of file
diff --git a/tests/develop/hybrid/hybrid.nim b/tests/develop/hybrid/hybrid.nim
deleted file mode 100644
index 53c687a..0000000
--- a/tests/develop/hybrid/hybrid.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("hello")
\ No newline at end of file
diff --git a/tests/develop/hybrid/hybrid.nimble b/tests/develop/hybrid/hybrid.nimble
deleted file mode 100644
index ae478e1..0000000
--- a/tests/develop/hybrid/hybrid.nimble
+++ /dev/null
@@ -1,13 +0,0 @@
-# Package
-
-version = "1.0"
-author = "Dominik Picheta"
-description = "hybrid"
-license = "MIT"
-
-bin = @["hybrid"]
-installExt = @["nim"]
-
-# Dependencies
-
-requires "nim >= 0.16.0"
diff --git a/tests/develop/srcdirtest/src/srcdirtest.nim b/tests/develop/srcdirtest/src/srcdirtest.nim
deleted file mode 100644
index 54b5b46..0000000
--- a/tests/develop/srcdirtest/src/srcdirtest.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-proc foo*(): string =
- return "correct"
-
-echo("hello")
\ No newline at end of file
diff --git a/tests/develop/srcdirtest/srcdirtest.nimble b/tests/develop/srcdirtest/srcdirtest.nimble
deleted file mode 100644
index c0f8136..0000000
--- a/tests/develop/srcdirtest/srcdirtest.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-version = "1.0"
-author = "Dominik Picheta"
-description = "srcdir"
-license = "MIT"
-
-srcDir = "src"
-
-# Dependencies
-
-requires "nim >= 0.16.0"
diff --git a/tests/diamond_deps/a/a.nimble b/tests/diamond_deps/a/a.nimble
deleted file mode 100644
index a140030..0000000
--- a/tests/diamond_deps/a/a.nimble
+++ /dev/null
@@ -1,14 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "a"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.3", "b", "c"
-
-
-task test, "test":
- echo("hello")
diff --git a/tests/diamond_deps/b/b.nimble b/tests/diamond_deps/b/b.nimble
deleted file mode 100644
index 2d64846..0000000
--- a/tests/diamond_deps/b/b.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "b"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.3", "d"
-
diff --git a/tests/diamond_deps/c/c.nimble b/tests/diamond_deps/c/c.nimble
deleted file mode 100644
index 2062240..0000000
--- a/tests/diamond_deps/c/c.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "c"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.3", "d"
-
diff --git a/tests/diamond_deps/d/d.nimble b/tests/diamond_deps/d/d.nimble
deleted file mode 100644
index 763e7db..0000000
--- a/tests/diamond_deps/d/d.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "d"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.3"
-
diff --git a/tests/invalidPackage/invalidPackage.nimble b/tests/invalidPackage/invalidPackage.nimble
deleted file mode 100644
index 08fcfcb..0000000
--- a/tests/invalidPackage/invalidPackage.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue108/issue108.nimble b/tests/issue108/issue108.nimble
deleted file mode 100644
index 8b2fa29..0000000
--- a/tests/issue108/issue108.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Test for issue 108."
-license = "BSD"
-
-# Dependencies
-
-requires "nim >= 0.12.1"
-
diff --git a/tests/issue113/a/a.nimble b/tests/issue113/a/a.nimble
deleted file mode 100644
index 2f22f38..0000000
--- a/tests/issue113/a/a.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Root package, depends on b."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.12.1", "b"
-
diff --git a/tests/issue113/b/b.nimble b/tests/issue113/b/b.nimble
deleted file mode 100644
index f5ce98d..0000000
--- a/tests/issue113/b/b.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Second dep. Depended by a and depends on c."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.12.1", "c"
-
diff --git a/tests/issue113/buildfail/buildfail.nim b/tests/issue113/buildfail/buildfail.nim
deleted file mode 100644
index 3820449..0000000
--- a/tests/issue113/buildfail/buildfail.nim
+++ /dev/null
@@ -1 +0,0 @@
-var x: string = 42
diff --git a/tests/issue113/buildfail/buildfail.nimble b/tests/issue113/buildfail/buildfail.nimble
deleted file mode 100644
index e60f126..0000000
--- a/tests/issue113/buildfail/buildfail.nimble
+++ /dev/null
@@ -1,13 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Testing issue 113."
-license = "MIT"
-
-bin = @["buildfail"]
-
-# Dependencies
-
-requires "nim >= 0.12.1", "c"
-
diff --git a/tests/issue113/c/c.nimble b/tests/issue113/c/c.nimble
deleted file mode 100644
index 6ed1e7d..0000000
--- a/tests/issue113/c/c.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Third dep. Depended by b."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.12.1"
-
diff --git a/tests/issue126/a/issue-126.nimble b/tests/issue126/a/issue-126.nimble
deleted file mode 100644
index 1b27a24..0000000
--- a/tests/issue126/a/issue-126.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Test to see if certain characters are disallowed in pkg names."
-license = "BSD"
-
-# Dependencies
-
-requires "nim >= 0.12.1"
-
diff --git a/tests/issue126/b/issue126.nimble b/tests/issue126/b/issue126.nimble
deleted file mode 100644
index 255bac2..0000000
--- a/tests/issue126/b/issue126.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-packageName = "foobar"
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Test to see if certain characters are disallowed in pkg names."
-license = "BSD"
-
-# Dependencies
-
-requires "nim >= 0.12.1"
-
diff --git a/tests/issue206/issue/issue206bin.nim b/tests/issue206/issue/issue206bin.nim
deleted file mode 100644
index 1726a88..0000000
--- a/tests/issue206/issue/issue206bin.nim
+++ /dev/null
@@ -1,2 +0,0 @@
-
-echo "Hello"
diff --git a/tests/issue206/issue206.nimble b/tests/issue206/issue206.nimble
deleted file mode 100644
index 1daea5c..0000000
--- a/tests/issue206/issue206.nimble
+++ /dev/null
@@ -1,10 +0,0 @@
-# Package
-version = "0.1.0"
-author = "Yuriy Glukhov"
-description = "Test package for Issue 206"
-license = "BSD"
-
-bin = @["issue/issue206bin"]
-
-# Dependencies
-requires "nimrod >= 0.9.3"
diff --git a/tests/issue289/issue289.nim b/tests/issue289/issue289.nim
deleted file mode 100644
index 10c5f66..0000000
--- a/tests/issue289/issue289.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo 42
diff --git a/tests/issue289/issue289.nimble b/tests/issue289/issue289.nimble
deleted file mode 100644
index bd90b3b..0000000
--- a/tests/issue289/issue289.nimble
+++ /dev/null
@@ -1,14 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Package reproducing issues depending on #head and concrete version of the same package."
-license = "MIT"
-
-bin = @["issue289"]
-
-# Dependencies
-
-requires "nim >= 0.15.0", "https://github.com/nimble-test/packagea.git 0.6.0"
-requires "https://github.com/nimble-test/packagea.git#head"
-
diff --git a/tests/issue304/package-test/package_test.nimble b/tests/issue304/package-test/package_test.nimble
deleted file mode 100644
index 9886d31..0000000
--- a/tests/issue304/package-test/package_test.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Package for ensuring that issue #304 is resolved."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.3"
-
diff --git a/tests/issue338/issue338.nimble b/tests/issue338/issue338.nimble
deleted file mode 100644
index fae4ae5..0000000
--- a/tests/issue338/issue338.nimble
+++ /dev/null
@@ -1,7 +0,0 @@
-# Package
-version = "0.1.0"
-author = "Samantha Marshall"
-description = "test case to validate successful install when `srcDir` value ends in a directory separator"
-license = "MIT"
-
-srcDir = "src/"
diff --git a/tests/issue338/src/issue338.nim b/tests/issue338/src/issue338.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/issue368/packages.json b/tests/issue368/packages.json
deleted file mode 100644
index 5cc425e..0000000
--- a/tests/issue368/packages.json
+++ /dev/null
@@ -1,14 +0,0 @@
-[
- {
- "name": "discordnim",
- "url": "https://github.com/Krognol/discordnim",
- "method": "git",
- "tags": [
- "library",
- "discord"
- ],
- "description": "Discord library for Nim",
- "license": "MIT",
- "web": "https://github.com/Krognol/discordnim"
- }
-]
diff --git a/tests/issue428/dummy.nimble b/tests/issue428/dummy.nimble
deleted file mode 100644
index a249eab..0000000
--- a/tests/issue428/dummy.nimble
+++ /dev/null
@@ -1,10 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Author"
-description = "dummy"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.17.0"
\ No newline at end of file
diff --git a/tests/issue432/issue432.nimble b/tests/issue432/issue432.nimble
deleted file mode 100644
index 92937c5..0000000
--- a/tests/issue432/issue432.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue432/src/issue432.nim b/tests/issue432/src/issue432.nim
deleted file mode 100644
index 4b2a270..0000000
--- a/tests/issue432/src/issue432.nim
+++ /dev/null
@@ -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
diff --git a/tests/issue564/issue564.nimble b/tests/issue564/issue564.nimble
deleted file mode 100644
index 7dc0013..0000000
--- a/tests/issue564/issue564.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue564/src/issue564/issue564build.nim b/tests/issue564/src/issue564/issue564build.nim
deleted file mode 100644
index 862d40c..0000000
--- a/tests/issue564/src/issue564/issue564build.nim
+++ /dev/null
@@ -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!")
diff --git a/tests/issue597/dummy.nimble b/tests/issue597/dummy.nimble
deleted file mode 100644
index 13bf4be..0000000
--- a/tests/issue597/dummy.nimble
+++ /dev/null
@@ -1,12 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Author"
-description = "dummy"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.17.0"
-
-bin = @["test.nim"]
diff --git a/tests/issue597/test.nim b/tests/issue597/test.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/issue633/issue633.nimble b/tests/issue633/issue633.nimble
deleted file mode 100644
index cb786eb..0000000
--- a/tests/issue633/issue633.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue678/issue678.nimble b/tests/issue678/issue678.nimble
deleted file mode 100644
index 20239e7..0000000
--- a/tests/issue678/issue678.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue678/packages.json b/tests/issue678/packages.json
deleted file mode 100644
index 972eb70..0000000
--- a/tests/issue678/packages.json
+++ /dev/null
@@ -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"
- }
-]
diff --git a/tests/issue708/issue708.nimble b/tests/issue708/issue708.nimble
deleted file mode 100644
index ebb079d..0000000
--- a/tests/issue708/issue708.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/issue708/src/issue708.nim b/tests/issue708/src/issue708.nim
deleted file mode 100644
index 4b2a270..0000000
--- a/tests/issue708/src/issue708.nim
+++ /dev/null
@@ -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
diff --git a/tests/nimbleVersionDefine/nimbleVersionDefine.nimble b/tests/nimbleVersionDefine/nimbleVersionDefine.nimble
deleted file mode 100644
index b47b049..0000000
--- a/tests/nimbleVersionDefine/nimbleVersionDefine.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine b/tests/nimbleVersionDefine/src/nimbleVersionDefine
deleted file mode 100755
index af3cc22..0000000
Binary files a/tests/nimbleVersionDefine/src/nimbleVersionDefine and /dev/null differ
diff --git a/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim b/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim
deleted file mode 100644
index 572dab8..0000000
--- a/tests/nimbleVersionDefine/src/nimbleVersionDefine.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-when isMainModule:
- const NimblePkgVersion {.strdefine.} = "Unknown"
- echo(NimblePkgVersion)
diff --git a/tests/nimscript/nimscript.nim b/tests/nimscript/nimscript.nim
deleted file mode 100644
index f3a3789..0000000
--- a/tests/nimscript/nimscript.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("Hello World")
diff --git a/tests/nimscript/nimscript.nimble b/tests/nimscript/nimscript.nimble
deleted file mode 100644
index 39f3710..0000000
--- a/tests/nimscript/nimscript.nimble
+++ /dev/null
@@ -1,62 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = """Test package
-with multi-line description
-"""
-license = "BSD"
-
-bin = @["nimscript"]
-
-# Dependencies
-
-requires "nim >= 0.12.1"
-
-task work, "test description":
- echo(5+5)
-
-task c_test, "Testing `setCommand \"c\", \"nimscript.nim\"`":
- setCommand "c", "nimscript.nim"
-
-task cr, "Testing `nimble c -r nimscript.nim` via setCommand":
- --r
- setCommand "c", "nimscript.nim"
-
-task repeated, "Testing `nimble c nimscript.nim` with repeated flags":
- --define: foo
- --define: bar
- --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:
- echo("First")
-
-task hooks, "Testing the hooks":
- echo("Middle")
-
-after hooks:
- echo("last")
-
-before hooks2:
- return false
-
-task hooks2, "Testing the hooks again":
- echo("Shouldn't happen")
-
-before install:
- echo("Before PkgDir: ", getPkgDir())
-
-after install:
- echo("After PkgDir: ", getPkgDir())
-
-before build:
- echo("Before build")
-
-after build:
- echo("After build")
\ No newline at end of file
diff --git a/tests/packageStructure/a/a.nim b/tests/packageStructure/a/a.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/a/a.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/a/a.nimble b/tests/packageStructure/a/a.nimble
deleted file mode 100644
index fd6878a..0000000
--- a/tests/packageStructure/a/a.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Correctly structured package A"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/packageStructure/b/b.nim b/tests/packageStructure/b/b.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/b/b.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/b/b.nimble b/tests/packageStructure/b/b.nimble
deleted file mode 100644
index ce659ef..0000000
--- a/tests/packageStructure/b/b.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Correctly structured package B"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/packageStructure/b/b/foobar.nim b/tests/packageStructure/b/b/foobar.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/b/b/foobar.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/c/c.nim b/tests/packageStructure/c/c.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/c/c.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/c/c.nimble b/tests/packageStructure/c/c.nimble
deleted file mode 100644
index 88cfb84..0000000
--- a/tests/packageStructure/c/c.nimble
+++ /dev/null
@@ -1,13 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Correctly structured package C"
-license = "MIT"
-
-bin = @["c"]
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/packageStructure/c/cpkg/foobar.nim b/tests/packageStructure/c/cpkg/foobar.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/c/cpkg/foobar.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/softened/myPkg.nim b/tests/packageStructure/softened/myPkg.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/softened/myPkg.nimble b/tests/packageStructure/softened/myPkg.nimble
deleted file mode 100644
index 525080d..0000000
--- a/tests/packageStructure/softened/myPkg.nimble
+++ /dev/null
@@ -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"
-
diff --git a/tests/packageStructure/softened/myPkg/submodule.nim b/tests/packageStructure/softened/myPkg/submodule.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/softened/tests/mytest.nim b/tests/packageStructure/softened/tests/mytest.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/validBinary/y.nim b/tests/packageStructure/validBinary/y.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/validBinary/y.nimble b/tests/packageStructure/validBinary/y.nimble
deleted file mode 100644
index 087141b..0000000
--- a/tests/packageStructure/validBinary/y.nimble
+++ /dev/null
@@ -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"
-
diff --git a/tests/packageStructure/validBinary/yWrong/foobar.nim b/tests/packageStructure/validBinary/yWrong/foobar.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/validBinary/yWrong/foobar.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/x/incorrect/foobar.nim b/tests/packageStructure/x/incorrect/foobar.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/x/x.nimble b/tests/packageStructure/x/x.nimble
deleted file mode 100644
index 51ebde2..0000000
--- a/tests/packageStructure/x/x.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Incorrectly structured package X."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/packageStructure/y/y.nim b/tests/packageStructure/y/y.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/y/y.nimble b/tests/packageStructure/y/y.nimble
deleted file mode 100644
index 4eb3ba5..0000000
--- a/tests/packageStructure/y/y.nimble
+++ /dev/null
@@ -1,14 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Incorrectly structured package Y"
-license = "MIT"
-
-installExt = @["nim"]
-bin = @["y"]
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/packageStructure/y/yWrong/foobar.nim b/tests/packageStructure/y/yWrong/foobar.nim
deleted file mode 100644
index 8b13789..0000000
--- a/tests/packageStructure/y/yWrong/foobar.nim
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/packageStructure/z/incorrect.nim b/tests/packageStructure/z/incorrect.nim
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/packageStructure/z/z.nimble b/tests/packageStructure/z/z.nimble
deleted file mode 100644
index f872d3c..0000000
--- a/tests/packageStructure/z/z.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Incorrect package structure Z."
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/passNimFlags/passNimFlags.nim b/tests/passNimFlags/passNimFlags.nim
deleted file mode 100644
index b4c0b97..0000000
--- a/tests/passNimFlags/passNimFlags.nim
+++ /dev/null
@@ -1 +0,0 @@
-when not defined(passNimIsWorking): {.error: "-d:passNimIsWorking wasn't passed to the compiler"}
diff --git a/tests/passNimFlags/passNimFlags.nimble b/tests/passNimFlags/passNimFlags.nimble
deleted file mode 100644
index 8530524..0000000
--- a/tests/passNimFlags/passNimFlags.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/recursive/recursive.nimble b/tests/recursive/recursive.nimble
deleted file mode 100644
index d6b155d..0000000
--- a/tests/recursive/recursive.nimble
+++ /dev/null
@@ -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
diff --git a/tests/revdep/mydep/mydep.nimble b/tests/revdep/mydep/mydep.nimble
deleted file mode 100644
index 1d5f3a9..0000000
--- a/tests/revdep/mydep/mydep.nimble
+++ /dev/null
@@ -1,10 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Random dep"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
\ No newline at end of file
diff --git a/tests/revdep/pkgNoDep/pkgA.nimble b/tests/revdep/pkgNoDep/pkgA.nimble
deleted file mode 100644
index fd6878a..0000000
--- a/tests/revdep/pkgNoDep/pkgA.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Correctly structured package A"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0"
-
diff --git a/tests/revdep/pkgWithDep/pkgA.nimble b/tests/revdep/pkgWithDep/pkgA.nimble
deleted file mode 100644
index 842af28..0000000
--- a/tests/revdep/pkgWithDep/pkgA.nimble
+++ /dev/null
@@ -1,11 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = "Correctly structured package A"
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.0", "mydep"
-
diff --git a/tests/run/run.nimble b/tests/run/run.nimble
deleted file mode 100644
index 055bc1e..0000000
--- a/tests/run/run.nimble
+++ /dev/null
@@ -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"
diff --git a/tests/run/src/run.nim b/tests/run/src/run.nim
deleted file mode 100644
index af98995..0000000
--- a/tests/run/src/run.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-import os
-
-when isMainModule:
- echo("Testing `nimble run`: ", commandLineParams())
diff --git a/tests/testCommand/testOverride/myTester.nim b/tests/testCommand/testOverride/myTester.nim
deleted file mode 100644
index 0e1a8f3..0000000
--- a/tests/testCommand/testOverride/myTester.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo("overriden")
\ No newline at end of file
diff --git a/tests/testCommand/testOverride/pkga.nimble b/tests/testCommand/testOverride/pkga.nimble
deleted file mode 100644
index 74bef6c..0000000
--- a/tests/testCommand/testOverride/pkga.nimble
+++ /dev/null
@@ -1,9 +0,0 @@
-version = "0.1.0"
-author = "John Doe"
-description = "Nimble Test"
-license = "BSD"
-
-skipFiles = @["myTester.nim"]
-
-task test, "Custom tester":
- exec "nim c -r myTester.nim"
\ No newline at end of file
diff --git a/tests/testCommand/testsCWD/testing123.nimble b/tests/testCommand/testsCWD/testing123.nimble
deleted file mode 100644
index 00e43bf..0000000
--- a/tests/testCommand/testsCWD/testing123.nimble
+++ /dev/null
@@ -1,4 +0,0 @@
-version = "0.1.0"
-author = "John Doe"
-description = "Nimble Test"
-license = "BSD"
diff --git a/tests/testCommand/testsCWD/tests/tcwd.nim b/tests/testCommand/testsCWD/tests/tcwd.nim
deleted file mode 100644
index 444a862..0000000
--- a/tests/testCommand/testsCWD/tests/tcwd.nim
+++ /dev/null
@@ -1,2 +0,0 @@
-import os
-echo(getCurrentDir())
\ No newline at end of file
diff --git a/tests/testCommand/testsFail/testing123.nim b/tests/testCommand/testsFail/testing123.nim
deleted file mode 100644
index 2c96a26..0000000
--- a/tests/testCommand/testsFail/testing123.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-proc myFunc*() =
- echo "Executing my func"
-
diff --git a/tests/testCommand/testsFail/testing123.nimble b/tests/testCommand/testsFail/testing123.nimble
deleted file mode 100644
index 00e43bf..0000000
--- a/tests/testCommand/testsFail/testing123.nimble
+++ /dev/null
@@ -1,4 +0,0 @@
-version = "0.1.0"
-author = "John Doe"
-description = "Nimble Test"
-license = "BSD"
diff --git a/tests/testCommand/testsFail/tests/t1.nim b/tests/testCommand/testsFail/tests/t1.nim
deleted file mode 100644
index 09f3215..0000000
--- a/tests/testCommand/testsFail/tests/t1.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "First test"
- myFunc()
-
diff --git a/tests/testCommand/testsFail/tests/t2.nim b/tests/testCommand/testsFail/tests/t2.nim
deleted file mode 100644
index da5ab05..0000000
--- a/tests/testCommand/testsFail/tests/t2.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "Failing Second test"
- assert(false)
-
diff --git a/tests/testCommand/testsFail/tests/t3.nim b/tests/testCommand/testsFail/tests/t3.nim
deleted file mode 100644
index 0aae686..0000000
--- a/tests/testCommand/testsFail/tests/t3.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "Third test"
- myFunc()
-
-
diff --git a/tests/testCommand/testsIgnore/testing123.nim b/tests/testCommand/testsIgnore/testing123.nim
deleted file mode 100644
index 2c96a26..0000000
--- a/tests/testCommand/testsIgnore/testing123.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-proc myFunc*() =
- echo "Executing my func"
-
diff --git a/tests/testCommand/testsIgnore/testing123.nimble b/tests/testCommand/testsIgnore/testing123.nimble
deleted file mode 100644
index 00e43bf..0000000
--- a/tests/testCommand/testsIgnore/testing123.nimble
+++ /dev/null
@@ -1,4 +0,0 @@
-version = "0.1.0"
-author = "John Doe"
-description = "Nimble Test"
-license = "BSD"
diff --git a/tests/testCommand/testsIgnore/tests/foobar/tignored.nim b/tests/testCommand/testsIgnore/tests/foobar/tignored.nim
deleted file mode 100644
index 9d61174..0000000
--- a/tests/testCommand/testsIgnore/tests/foobar/tignored.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo "Should be ignored"
diff --git a/tests/testCommand/testsIgnore/tests/ignore.nim b/tests/testCommand/testsIgnore/tests/ignore.nim
deleted file mode 100644
index b63fe4d..0000000
--- a/tests/testCommand/testsIgnore/tests/ignore.nim
+++ /dev/null
@@ -1 +0,0 @@
-echo "Should be ignored"
\ No newline at end of file
diff --git a/tests/testCommand/testsIgnore/tests/taccept.nim b/tests/testCommand/testsIgnore/tests/taccept.nim
deleted file mode 100644
index e020a08..0000000
--- a/tests/testCommand/testsIgnore/tests/taccept.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import testing123, unittest
-
-test "can accept":
- echo "First test"
- myFunc()
-
-
diff --git a/tests/testCommand/testsPass/testing123.nim b/tests/testCommand/testsPass/testing123.nim
deleted file mode 100644
index 2c96a26..0000000
--- a/tests/testCommand/testsPass/testing123.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-proc myFunc*() =
- echo "Executing my func"
-
diff --git a/tests/testCommand/testsPass/testing123.nimble b/tests/testCommand/testsPass/testing123.nimble
deleted file mode 100644
index 00e43bf..0000000
--- a/tests/testCommand/testsPass/testing123.nimble
+++ /dev/null
@@ -1,4 +0,0 @@
-version = "0.1.0"
-author = "John Doe"
-description = "Nimble Test"
-license = "BSD"
diff --git a/tests/testCommand/testsPass/tests/t1.nim b/tests/testCommand/testsPass/tests/t1.nim
deleted file mode 100644
index 09f3215..0000000
--- a/tests/testCommand/testsPass/tests/t1.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "First test"
- myFunc()
-
diff --git a/tests/testCommand/testsPass/tests/t2.nim b/tests/testCommand/testsPass/tests/t2.nim
deleted file mode 100644
index 91413e1..0000000
--- a/tests/testCommand/testsPass/tests/t2.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "Second test"
- myFunc()
-
-
diff --git a/tests/testCommand/testsPass/tests/t3.nim b/tests/testCommand/testsPass/tests/t3.nim
deleted file mode 100644
index 0aae686..0000000
--- a/tests/testCommand/testsPass/tests/t3.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import testing123, unittest
-
-test "can compile nimble":
- echo "Third test"
- myFunc()
-
-
diff --git a/tests/testdump/testdump.nimble b/tests/testdump/testdump.nimble
deleted file mode 100644
index 630b52a..0000000
--- a/tests/testdump/testdump.nimble
+++ /dev/null
@@ -1,4 +0,0 @@
-description = "Test package for dump command"
-version = "0.1.0"
-author = "nigredo-tori"
-license = "BSD"
diff --git a/tests/tester.nim b/tests/tester.nim
index 446fecb..42864ad 100644
--- a/tests/tester.nim
+++ b/tests/tester.nim
@@ -1,1045 +1,82 @@
# 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
-# and is really fragile.
-
-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)
+test "can compile nimble":
+ check execCmdEx("nim c " & path).exitCode == QuitSuccess
-# Clear nimble dir.
-removeDir(installDir)
-createDir(installDir)
-
-# Always recompile.
-doAssert execCmdEx("nim c " & path).exitCode == QuitSuccess
-
-test "can compile with --os:windows":
- check execCmdEx("nim check --os:windows " & path).exitCode == QuitSuccess
-
-template cd*(dir: string, body: untyped) =
+template cd*(dir: string, body: stmt) =
## Sets the current dir to ``dir``, executes ``body`` and restores the
## previous working dir.
- block:
- let lastDir = getCurrentDir()
- setCurrentDir(dir)
- body
- setCurrentDir(lastDir)
-
-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)
-
- 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
-
- result = execCmdEx(cmd)
- checkpoint(cmd)
- checkpoint(result.output)
-
-proc execNimbleYes(args: varargs[string]): tuple[output: string, exitCode: int]=
- # issue #6314
- execNimble(@args & "-y")
-
-template verify(res: (string, int)) =
- let r = res
- checkpoint r[0]
- check r[1] == QuitSuccess
+ let lastDir = getCurrentDir()
+ setCurrentDir(dir)
+ body
+ setCurrentDir(lastDir)
proc processOutput(output: string): seq[string] =
- output.strip.splitLines().filter(
- (x: string) => (
- x.len > 0 and
- "Using env var NIM_LIB_PREFIX" notin x
- )
- )
-
-proc inLines(lines: seq[string], line: string): bool =
- for i in lines:
- 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")
- checkpoint output
- check exitCode == QuitSuccess
- check execNimble("remove", "aporiascenario", "-y").exitCode == QuitSuccess
- check execNimble("remove", "packagea", "-y").exitCode == QuitSuccess
-
-test "can distinguish package reading in nimbleDir vs. other dirs (#304)":
- cd "issue304" / "package-test":
- check execNimble("tasks").exitCode == QuitSuccess
-
-test "can accept short flags (#329)":
- cd "nimscript":
- check execNimble("c", "-d:release", "nimscript.nim").exitCode == QuitSuccess
-
-test "can build with #head and versioned package (#289)":
- cd "issue289":
- check execNimble(["install", "-y"]).exitCode == QuitSuccess
-
- check execNimble(["uninstall", "issue289", "-y"]).exitCode == QuitSuccess
- check execNimble(["uninstall", "packagea", "-y"]).exitCode == QuitSuccess
-
-test "can validate package structure (#144)":
- # Test that no warnings are produced for correctly structured packages.
- for package in ["a", "b", "c", "validBinary", "softened"]:
- cd "packageStructure/" & package:
- let (output, exitCode) = execNimble(["install", "-y"])
- check exitCode == QuitSuccess
- let lines = output.strip.processOutput()
- check(not lines.hasLineStartingWith("Warning:"))
-
- # Test that warnings are produced for the incorrectly structured packages.
- for package in ["x", "y", "z"]:
- cd "packageStructure/" & package:
- let (output, exitCode) = execNimble(["install", "-y"])
- check exitCode == QuitSuccess
- let lines = output.strip.processOutput()
- 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.")
- 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.")
- 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.")
- else:
- assert false
-
-test "issue 129 (installing commit hash)":
- let arguments = @["install", "-y",
- "https://github.com/nimble-test/packagea.git@#1f9cb289c89"]
- check execNimble(arguments).exitCode == QuitSuccess
- # Verify that it was installed correctly.
- check dirExists(installDir / "pkgs" / "PackageA-#1f9cb289c89")
- # Remove it so that it doesn't interfere with the uninstall tests.
- check execNimble("uninstall", "-y", "packagea@#1f9cb289c89").exitCode ==
- QuitSuccess
-
-test "issue 113 (uninstallation problems)":
- cd "issue113/c":
- check execNimble(["install", "-y"]).exitCode == QuitSuccess
- cd "issue113/b":
- check execNimble(["install", "-y"]).exitCode == QuitSuccess
- cd "issue113/a":
- check execNimble(["install", "-y"]).exitCode == QuitSuccess
-
- # Try to remove c.
- let (output, exitCode) = execNimble(["remove", "-y", "c"])
- let lines = output.strip.processOutput()
- check exitCode != QuitSuccess
- check inLines(lines, "cannot uninstall c (0.1.0) because b (0.1.0) depends on it")
-
- check execNimble(["remove", "-y", "a"]).exitCode == QuitSuccess
- check execNimble(["remove", "-y", "b"]).exitCode == QuitSuccess
-
- cd "issue113/buildfail":
- check execNimble(["install", "-y"]).exitCode != QuitSuccess
-
- check execNimble(["remove", "-y", "c"]).exitCode == QuitSuccess
-
-test "can refresh with default urls":
- let (output, exitCode) = execNimble(["refresh"])
- checkpoint(output)
- check exitCode == QuitSuccess
-
-proc safeMoveFile(src, dest: string) =
- try:
- moveFile(src, dest)
- except OSError:
- copyFile(src, dest)
- removeFile(src)
-
-template testRefresh(body: untyped) =
- # Backup current config
- let configFile {.inject.} = getConfigDir() / "nimble" / "nimble.ini"
- let configBakFile = getConfigDir() / "nimble" / "nimble.ini.bak"
- if fileExists(configFile):
- safeMoveFile(configFile, configBakFile)
-
- # Ensure config dir exists
- createDir(getConfigDir() / "nimble")
-
- body
-
- # Restore config
- if fileExists(configBakFile):
- safeMoveFile(configBakFile, configFile)
-
-test "can refresh with custom urls":
- testRefresh():
- writeFile(configFile, """
- [PackageList]
- name = "official"
- url = "http://google.com"
- url = "http://google.com/404"
- url = "http://irclogs.nim-lang.org/packages.json"
- url = "http://nim-lang.org/nimble/packages.json"
- url = "https://github.com/nim-lang/packages/raw/master/packages.json"
- """.unindent)
-
- let (output, exitCode) = execNimble(["refresh", "--verbose"])
- checkpoint(output)
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check inLines(lines, "config file at")
- check inLines(lines, "official package list")
- check inLines(lines, "http://google.com")
- check inLines(lines, "packages.json file is invalid")
- check inLines(lines, "404 not found")
- check inLines(lines, "Package list downloaded.")
-
-test "can refresh with local package list":
- testRefresh():
- writeFile(configFile, """
- [PackageList]
- name = "local"
- path = "$1"
- """.unindent % (getCurrentDir() / "issue368" / "packages.json").replace("\\", "\\\\"))
- let (output, exitCode) = execNimble(["refresh", "--verbose"])
- let lines = output.strip.processOutput()
- check inLines(lines, "config file at")
- check inLines(lines, "Copying")
- check inLines(lines, "Package list copied.")
- check exitCode == QuitSuccess
-
-test "package list source required":
- testRefresh():
- writeFile(configFile, """
- [PackageList]
- name = "local"
- """)
- let (output, exitCode) = execNimble(["refresh", "--verbose"])
- let lines = output.strip.processOutput()
- check inLines(lines, "config file at")
- check inLines(lines, "Package list 'local' requires either url or path")
- check exitCode == QuitFailure
-
-test "package list can only have one source":
- testRefresh():
- writeFile(configFile, """
- [PackageList]
- name = "local"
- path = "$1"
- url = "http://nim-lang.org/nimble/packages.json"
- """)
- let (output, exitCode) = execNimble(["refresh", "--verbose"])
- let lines = output.strip.processOutput()
- check inLines(lines, "config file at")
- check inLines(lines, "Attempted to specify `url` and `path` for the same package list 'local'")
- check exitCode == QuitFailure
-
-suite "nimscript":
- test "can install nimscript package":
- cd "nimscript":
- check execNimble(["install", "-y"]).exitCode == QuitSuccess
-
- test "before/after install pkg dirs are correct":
- cd "nimscript":
- let (output, exitCode) = execNimble(["install", "-y"])
- check exitCode == QuitSuccess
- check output.contains("Before build")
- check output.contains("After build")
- let lines = output.strip.processOutput()
- check lines[0].startsWith("Before PkgDir:")
- check lines[0].endsWith("tests" / "nimscript")
- check lines[^1].startsWith("After PkgDir:")
- check lines[^1].endsWith("tests" / "nimbleDir" / "pkgs" / "nimscript-0.1.0")
-
- test "before/after on build":
- cd "nimscript":
- let (output, exitCode) = execNimble(["build"])
- check exitCode == QuitSuccess
- check output.contains("Before build")
- check output.contains("After build")
-
- test "can execute nimscript tasks":
- cd "nimscript":
- let (output, exitCode) = execNimble("--verbose", "work")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check lines[^1] == "10"
-
- test "can use nimscript's setCommand":
- cd "nimscript":
- let (output, exitCode) = execNimble("--verbose", "cTest")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check "Execution finished".normalize in lines[^1].normalize
-
- test "can use nimscript's setCommand with flags":
- cd "nimscript":
- let (output, exitCode) = execNimble("--debug", "cr")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check inLines(lines, "Hello World")
-
- test "can use nimscript with repeated flags (issue #329)":
- cd "nimscript":
- let (output, exitCode) = execNimble("--debug", "repeated")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- var found = false
- for line in lines:
- if line.contains("--define:foo"):
- found = true
- check found == true
-
- test "can list nimscript tasks":
- cd "nimscript":
- let (output, exitCode) = execNimble("tasks")
- check "work".normalize in output.normalize
- check "test description".normalize in output.normalize
- check exitCode == QuitSuccess
-
- test "can use pre/post hooks":
- cd "nimscript":
- let (output, exitCode) = execNimble("hooks")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check inLines(lines, "First")
- check inLines(lines, "middle")
- check inLines(lines, "last")
-
- test "pre hook can prevent action":
- cd "nimscript":
- let (output, exitCode) = execNimble("hooks2")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check(not inLines(lines, "Shouldn't happen"))
- check inLines(lines, "Hook prevented further execution")
-
- test "nimble script api":
- cd "nimscript":
- let (output, exitCode) = execNimble("api")
- let lines = output.strip.processOutput()
- check exitCode == QuitSuccess
- check inLines(lines, "PKG_DIR: " & getCurrentDir())
+ output.strip.splitLines().filter((x: string) => (x.len > 0))
test "can install packagebin2":
- let args = ["install", "-y", "https://github.com/nimble-test/packagebin2.git"]
- check execNimble(args).exitCode == QuitSuccess
+ check execCmdEx(path &
+ " install -y https://github.com/nimble-test/packagebin2.git").exitCode ==
+ QuitSuccess
test "can reject same version dependencies":
- let (outp, exitCode) = execNimble(
- "install", "-y", "https://github.com/nimble-test/packagebin.git")
+ let (outp, exitCode) = execCmdEx(path &
+ " install -y https://github.com/nimble-test/packagebin.git")
# We look at the error output here to avoid out-of-order problems caused by
# stderr output being generated and flushed without first flushing stdout
- let ls = outp.strip.processOutput()
+ let ls = outp.strip.splitLines()
check exitCode != QuitSuccess
- check "Cannot satisfy the dependency on PackageA 0.2.0 and PackageA 0.5.0" in
- ls[ls.len-1]
+ check ls[ls.len-1] == "Error: unhandled exception: Cannot satisfy the " &
+ "dependency on PackageA 0.2.0 and PackageA 0.5.0 [NimbleError]"
test "can update":
- check execNimble("update").exitCode == QuitSuccess
+ check execCmdEx(path & " update").exitCode == QuitSuccess
test "issue #27":
# Install b
cd "issue27/b":
- check execNimble("install", "-y").exitCode == QuitSuccess
+ check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess
# Install a
cd "issue27/a":
- check execNimble("install", "-y").exitCode == QuitSuccess
+ check execCmdEx("../../" & path & " install -y").exitCode == QuitSuccess
cd "issue27":
- check execNimble("install", "-y").exitCode == QuitSuccess
-
-test "issue #126":
- cd "issue126/a":
- let (output, exitCode) = execNimble("install", "-y")
- let lines = output.strip.processOutput()
- check exitCode != QuitSuccess # TODO
- check inLines(lines, "issue-126 is an invalid package name: cannot contain '-'")
-
- cd "issue126/b":
- let (output1, exitCode1) = execNimble("install", "-y")
- let lines1 = output1.strip.processOutput()
- check exitCode1 != QuitSuccess
- check inLines(lines1, "The .nimble file name must match name specified inside")
-
-test "issue #108":
- cd "issue108":
- let (output, exitCode) = execNimble("build")
- let lines = output.strip.processOutput()
- check exitCode != QuitSuccess
- check inLines(lines, "Nothing to build")
-
-test "issue #206":
- cd "issue206":
- var (output, exitCode) = execNimble("install", "-y")
- check exitCode == QuitSuccess
- (output, exitCode) = execNimble("install", "-y")
- check exitCode == QuitSuccess
-
-test "issue #338":
- cd "issue338":
- check execNimble("install", "-y").exitCode == QuitSuccess
-
-test "issue #349":
- let reservedNames = [
- "CON",
- "PRN",
- "AUX",
- "NUL",
- "COM1",
- "COM2",
- "COM3",
- "COM4",
- "COM5",
- "COM6",
- "COM7",
- "COM8",
- "COM9",
- "LPT1",
- "LPT2",
- "LPT3",
- "LPT4",
- "LPT5",
- "LPT6",
- "LPT7",
- "LPT8",
- "LPT9",
- ]
-
- proc checkName(name: string) =
- let (outp, code) = execNimble("init", "-y", name)
- let msg = outp.strip.processOutput()
- 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
-
- for reserved in reservedNames:
- checkName(reserved.toUpperAscii())
- checkName(reserved.toLowerAscii())
-
-test "issue #428":
- cd "issue428":
- # Note: Can't use execNimble because it patches nimbleDir
- check execCmdEx(nimblePath & " -y --nimbleDir=./nimbleDir install").exitCode == QuitSuccess
- check dirExists("nimbleDir/pkgs/dummy-0.1.0")
- check(not dirExists("nimbleDir/pkgs/dummy-0.1.0/nimbleDir"))
-
-test "can list":
- check execNimble("list").exitCode == QuitSuccess
-
- check execNimble("list", "-i").exitCode == QuitSuccess
+ check execCmdEx("../" & path & " install -y").exitCode == QuitSuccess
test "can uninstall":
block:
- let (outp, exitCode) = execNimble("uninstall", "-y", "issue27b")
-
- let ls = outp.strip.processOutput()
+ let (outp, exitCode) = execCmdEx(path & " uninstall -y issue27b")
+ # let ls = outp.processOutput()
+ let ls = outp.strip.splitLines()
check exitCode != QuitSuccess
- check inLines(ls, "Cannot uninstall issue27b (0.1.0) because issue27a (0.1.0) depends")
+ check ls[ls.len-1] == " Cannot uninstall issue27b (0.1.0) because " &
+ "issue27a (0.1.0) depends on it [NimbleError]"
- check execNimble("uninstall", "-y", "issue27").exitCode == QuitSuccess
- check execNimble("uninstall", "-y", "issue27a").exitCode == QuitSuccess
+ check execCmdEx(path & " uninstall -y issue27").exitCode == QuitSuccess
+ check execCmdEx(path & " uninstall -y issue27a").exitCode == QuitSuccess
# Remove Package*
- check execNimble("uninstall", "-y", "PackageA@0.5").exitCode == QuitSuccess
+ check execCmdEx(path & " uninstall -y PackageA@0.5").exitCode == QuitSuccess
- let (outp, exitCode) = execNimble("uninstall", "-y", "PackageA")
+ let (outp, exitCode) = execCmdEx(path & " uninstall -y PackageA")
check exitCode != QuitSuccess
let ls = outp.processOutput()
- check inLines(ls, "Cannot uninstall PackageA (0.2.0)")
- check inLines(ls, "Cannot uninstall PackageA (0.6.0)")
- check execNimble("uninstall", "-y", "PackageBin2").exitCode == QuitSuccess
+ check ls[ls.len-2].startsWith(" Cannot uninstall PackageA ")
+ check ls[ls.len-1].startsWith(" Cannot uninstall PackageA ")
+ check execCmdEx(path & " uninstall -y PackageBin2").exitCode == QuitSuccess
# Case insensitive
- check execNimble("uninstall", "-y", "packagea").exitCode == QuitSuccess
- check execNimble("uninstall", "-y", "PackageA").exitCode != QuitSuccess
+ check execCmdEx(path & " uninstall -y packagea").exitCode == QuitSuccess
+ check execCmdEx(path & " uninstall -y PackageA").exitCode != QuitSuccess
# Remove the rest of the installed packages.
- check execNimble("uninstall", "-y", "PackageB").exitCode == QuitSuccess
+ check execCmdEx(path & " uninstall -y PackageB").exitCode == QuitSuccess
- check execNimble("uninstall", "-y", "PackageA@0.2", "issue27b").exitCode ==
+ check execCmdEx(path & " uninstall -y PackageA@0.2 issue27b").exitCode ==
QuitSuccess
- check(not dirExists(installDir / "pkgs" / "PackageA-0.2.0"))
-
- check execNimble("uninstall", "-y", "nimscript").exitCode == QuitSuccess
-
-test "can dump for current project":
- cd "testdump":
- let (outp, exitCode) = execNimble("dump")
- check: exitCode == 0
- check: outp.processOutput.inLines("desc: \"Test package for dump command\"")
-
-test "can dump for project directory":
- let (outp, exitCode) = execNimble("dump", "testdump")
- check: exitCode == 0
- check: outp.processOutput.inLines("desc: \"Test package for dump command\"")
-
-test "can dump for project file":
- let (outp, exitCode) = execNimble("dump", "testdump" / "testdump.nimble")
- check: exitCode == 0
- check: outp.processOutput.inLines("desc: \"Test package for dump command\"")
-
-test "can dump for installed package":
- cd "testdump":
- check: execNimble("install", "-y").exitCode == 0
- defer:
- discard execNimble("remove", "-y", "testdump")
-
- # Otherwise we might find subdirectory instead
- cd "..":
- let (outp, exitCode) = execNimble("dump", "testdump")
- check: exitCode == 0
- check: outp.processOutput.inLines("desc: \"Test package for dump command\"")
-
-test "can install diamond deps (#184)":
- cd "diamond_deps":
- cd "d":
- check execNimble("install", "-y").exitCode == 0
- cd "c":
- check execNimble("install", "-y").exitCode == 0
- cd "b":
- check execNimble("install", "-y").exitCode == 0
- cd "a":
- # TODO: This doesn't really test anything. But I couldn't quite
- # reproduce #184.
- let (output, exitCode) = execNimble("install", "-y")
- checkpoint(output)
- check exitCode == 0
-
-test "issues #280 and #524":
- check execNimble("install", "-y", "https://github.com/nimble-test/issue280and524.git").exitCode == 0
-
-suite "can handle two binary versions":
- setup:
- cd "binaryPackage/v1":
- check execNimble("install", "-y").exitCode == QuitSuccess
-
- 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)
- check exitCode == QuitSuccess
- check output.strip() == "v2"
-
- test "can update symlink to earlier version after removal":
- check execNimble("remove", "binaryPackage@2.0", "-y").exitCode==QuitSuccess
-
- let (output, exitCode) =
- execCmdEx(cmd)
- check exitCode == QuitSuccess
- check output.strip() == "v1"
-
- test "can keep symlink version after earlier version removal":
- check execNimble("remove", "binaryPackage@1.0", "-y").exitCode==QuitSuccess
-
- let (output, exitCode) =
- execCmdEx(cmd)
- check exitCode == QuitSuccess
- check output.strip() == "v2"
-
-test "can pass args with spaces to Nim (#351)":
- cd "binaryPackage/v2":
- let (output, exitCode) = execCmdEx(nimblePath &
- " c -r" &
- " -d:myVar=\"string with spaces\"" &
- " binaryPackage")
- checkpoint output
- check exitCode == QuitSuccess
-
-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":
- verify execNimbleYes("install")
-
- cd "revdep/pkgWithDep":
- verify execNimbleYes("install")
-
- 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")
-
- cd "revdep/pkgWithDep":
- verify execNimbleYes("install")
-
- cd "revdep/pkgNoDep":
- verify execNimbleYes("install")
-
- verify execNimbleYes("remove", "mydep")
-
-suite "develop feature":
- test "can reject binary packages":
- cd "develop/binary":
- let (output, exitCode) = execNimble("develop")
- checkpoint output
- check output.processOutput.inLines("cannot develop packages")
- check exitCode == QuitFailure
-
- test "can develop hybrid":
- cd "develop/hybrid":
- let (output, exitCode) = execNimble("develop")
- checkpoint output
- check output.processOutput.inLines("will not be compiled")
- check exitCode == QuitSuccess
-
- let path = installDir / "pkgs" / "hybrid-#head" / "hybrid.nimble-link"
- check fileExists(path)
- let split = readFile(path).processOutput()
- check split.len == 2
- check split[0].endsWith("develop" / "hybrid" / "hybrid.nimble")
- check split[1].endsWith("develop" / "hybrid")
-
- test "can develop with srcDir":
- cd "develop/srcdirtest":
- let (output, exitCode) = execNimble("develop")
- checkpoint output
- check(not output.processOutput.inLines("will not be compiled"))
- check exitCode == QuitSuccess
-
- let path = installDir / "pkgs" / "srcdirtest-#head" /
- "srcdirtest.nimble-link"
- check fileExists(path)
- let split = readFile(path).processOutput()
- check split.len == 2
- 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")
- checkpoint output
- check(output.processOutput.inLines("hello"))
- check exitCode == QuitSuccess
-
- test "can uninstall linked package":
- cd "develop/srcdirtest":
- let (_, exitCode) = execNimble("develop", "-y")
- check exitCode == QuitSuccess
-
- let (output, exitCode) = execNimble("uninstall", "-y", "srcdirtest")
- checkpoint(output)
- check exitCode == QuitSuccess
- check(not output.processOutput.inLines("warning"))
-
- test "can git clone for develop":
- let cloneDir = installDir / "developTmp"
- createDir(cloneDir)
- cd cloneDir:
- let url = "https://github.com/nimble-test/packagea.git"
- let (_, exitCode) = execNimble("develop", "-y", url)
- check exitCode == QuitSuccess
-
- test "nimble path points to develop":
- cd "develop/srcdirtest":
- var (output, exitCode) = execNimble("develop")
- checkpoint output
- check exitCode == QuitSuccess
-
- (output, exitCode) = execNimble("path", "srcdirtest")
-
- checkpoint output
- check exitCode == QuitSuccess
- check output.strip() == getCurrentDir() / "src"
-
-suite "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":
- let (outp, exitCode) = execNimble("test")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("First test")
- check outp.processOutput.inLines("Second test")
- check outp.processOutput.inLines("Third test")
- check outp.processOutput.inLines("Executing my func")
-
- test "Runs failing unit tests":
- cd "testCommand/testsFail":
- let (outp, exitCode) = execNimble("test")
- check exitCode == QuitFailure
- check outp.processOutput.inLines("First test")
- check outp.processOutput.inLines("Failing Second test")
- check(not outp.processOutput.inLines("Third test"))
-
- test "test command can be overriden":
- cd "testCommand/testOverride":
- let (outp, exitCode) = execNimble("test")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("overriden")
-
- 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":
- let (outp, exitCode) = execNimble("check")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("success")
- check outp.processOutput.inLines("binaryPackage is valid")
-
- cd "packageStructure/a":
- let (outp, exitCode) = execNimble("check")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("success")
- check outp.processOutput.inLines("a is valid")
-
- cd "packageStructure/b":
- let (outp, exitCode) = execNimble("check")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("success")
- check outp.processOutput.inLines("b is valid")
-
- cd "packageStructure/c":
- let (outp, exitCode) = execNimble("check")
- check exitCode == QuitSuccess
- check outp.processOutput.inLines("success")
- check outp.processOutput.inLines("c is valid")
-
- test "can fail package":
- cd "packageStructure/x":
- let (outp, exitCode) = execNimble("check")
- check exitCode == QuitFailure
- check outp.processOutput.inLines("failure")
- check outp.processOutput.inLines("validation failed")
- check outp.processOutput.inLines("package 'x' has an incorrect structure")
-
-suite "multi":
- test "can install package from git subdir":
- let args = ["install", "-y", "https://github.com/nimble-test/multi?subdir=alpha"]
- check execNimble(args).exitCode == QuitSuccess
-
- test "can develop package from git subdir":
- removeDir("nimble-test/multi")
- let args = ["develop", "-y", "https://github.com/nimble-test/multi?subdir=beta"]
- check execNimble(args).exitCode == QuitSuccess
-
-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 (not dirExists(getHomeDir() / ".nimble" / "pkgs" / "PackageA-0.2.0"))
diff --git a/tests/versionClashes/aporiaScenario/aporiaScenario.nimble b/tests/versionClashes/aporiaScenario/aporiaScenario.nimble
deleted file mode 100644
index 3be5bbc..0000000
--- a/tests/versionClashes/aporiaScenario/aporiaScenario.nimble
+++ /dev/null
@@ -1,13 +0,0 @@
-# Package
-
-version = "0.1.0"
-author = "Dominik Picheta"
-description = " "
-license = "MIT"
-
-# Dependencies
-
-requires "nim >= 0.15.2"
-requires "https://github.com/nimble-test/packagea.git#head"
-requires "https://github.com/nimble-test/packagea.git >= 0.5"
-
diff --git a/tests/versionClashes/readme.md b/tests/versionClashes/readme.md
deleted file mode 100644
index 374f2b6..0000000
--- a/tests/versionClashes/readme.md
+++ /dev/null
@@ -1,5 +0,0 @@
-Tests to ensure that the following errors are correct.
-
-```
-Cannot satisfy dependency on gtk2 1.0 and gtk2 1.1
-```
\ No newline at end of file