diff --git a/.coveragerc b/.coveragerc index 7c462b3..77c2ecb 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,7 +5,6 @@ source = omit = .tox/* /usr/* - */tmp* setup.py # Don't complain if non-runnable code isn't run */__main__.py diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..e6805cf --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,22 @@ +# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes + +changelog: + categories: + - title: New Features 🎉 + labels: + - new-feature + - title: Fixed bugs 🐛 + labels: + - bug + - title: Improvements 🛠 + labels: + - enhancement + - title: Dependencies 🤖 + labels: + - deps + - title: Documentation 📄 + labels: + - docs + - title: Other Changes + labels: + - "*" \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..40d7bb1 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,82 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + workflow_dispatch: + +jobs: + tests: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + python-version: + - '3.10' + - '3.11' + - '3.12' + - '3.13' + - '3.14' + + steps: + - uses: actions/checkout@v5 + + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + # build and test dependencies + python -m pip install --upgrade pip wheel tox + # runtime dependencies + python -m pip install -e . + + - name: Run tox targets for ${{ matrix.python-version }} + run: | + ENV_SUFFIX=$(echo "${{ matrix.python-version }}" | tr -d '.') + tox -e py${ENV_SUFFIX} + + - name: Upload coverage data + if: always() + uses: actions/upload-artifact@v6 + with: + name: coverage-data-${{ matrix.python-version }} + path: .coverage.* + include-hidden-files: true + + coverage: + name: Coverage + runs-on: ubuntu-latest + needs: tests + steps: + - uses: actions/checkout@v5 + + - uses: actions/setup-python@v6 + with: + python-version: '3.14' + + - name: Install dependencies + run: python -m pip install --upgrade coverage[toml] + + - name: Download data + uses: actions/download-artifact@v7 + with: + pattern: coverage-data-* + merge-multiple: true + + - name: Combine coverage and fail if it's <100% + run: | + python -m coverage combine + python -m coverage html --skip-covered --skip-empty + python -m coverage report --fail-under=55 + + - name: Upload HTML report + uses: actions/upload-artifact@v6 + with: + name: html-report + path: coverage-html diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6b0eed8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,67 @@ +name: Tests + +on: + pull_request: + branches: + - master + - main + push: + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Run tests with tox + run: | + tox -e py$(echo ${{ matrix.python-version }} | tr -d '.') + + - name: Run flake8 + run: | + flake8 --extend-ignore=E127 nodeenv.py tests setup.py + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.14 + uses: actions/setup-python@v5 + with: + python-version: '3.14' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Run tests with coverage + run: | + coverage run -p -m pytest + coverage report -m + coverage html + + - name: Upload coverage report + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-report + path: coverage-html/ + diff --git a/.gitignore b/.gitignore index 40fddb5..26c0261 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ .coverage +.coverage.* *.pyc *.pyo *.swp *.swo env +env-dev /nodeenv /TODO /build/ @@ -16,6 +18,8 @@ env /*.egg-info/ .ropeproject/ .tox/ +.idea/ +.cache/ debian debian-upstream/files debian-upstream/nodeenv.substvars diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0306b61..0000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: python -env: # These should match the tox env list - - TOXENV=py26 - - TOXENV=py27 - - TOXENV=py33 - - TOXENV=py34 - - TOXENV=pypy - - TOXENV=pypy3 -install: pip install coveralls tox --use-mirrors -script: tox -after_success: - - coveralls -sudo: false diff --git a/AUTHORS b/AUTHORS index 17f2644..99ce636 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,43 +3,109 @@ Nodeenv is written and maintained by Eugene Kalinin. Patches and Suggestions ``````````````````````` -- jhermann -- ivan hilkov -- Vincent Bernat -- Anthony Sottile -- Kyle P Davis -- Elias Kunnas -- Doug Turnbull -- Anton Parkhomenko -- Vyacheslav Levit -- Travis Miller -- syndbg -- Spencer Rathbun -- Lispython -- Leonardo Fedalto -- Kyle P Davis -- Dennis Flanigan -- Andrzej Pragacz -- Alex Couper -- Zenobius Jiricek -- Yi-Feng Tzeng -- Vladimír Gorej -- Vincent Bernat -- Stan Seibert -- Shubhang Mani -- Rik -- Mrinal Wadhwa -- Michal Kolodziejski -- Marc Abramowitz -- Ken Struys -- Jesse Dhillon -- Jeremy Banks -- Geoffrey Huntley -- dhilipsiva -- Dennis Flanigan -- Dan North -- Dan Fuchs -- Damien Nozay -- cmehay -- Ben Davis -- Alexey Poryadin +- jhermann +- Anthony Sottile +- anatoly techtonik +- ivan hilkov +- Vincent Bernat +- Kyle P Davis +- Kefu Chai +- Elias Kunnas +- Avimitin +- Adam Johnson +- Pierre Le Marre +- Eashwar Ranganathan +- Doug Turnbull +- Anton Parkhomenko +- Vyacheslav Levit +- Travis Miller +- syndbg +- Spencer Rathbun +- Robert Schwebel +- Luis Orduz +- Lucas Cimon +- Lispython +- Leonardo Fedalto +- Kyle P Davis +- Jon Winn +- Duncan Bellamy +- Dennis Flanigan +- Christian Clauss +- Chris Beaven +- Cerem Cem ASLAN +- Bruno Oliveira +- Andrzej Pragacz +- Andrey Mishchenko +- Alex Couper +- 0Xellos +- zjeuhpiung liu +- Zenobius Jiricek +- zbw +- Yi-Feng Tzeng +- Willem Jan Withagen +- Walter dos Santos Filho +- Vladimír Gorej +- Vizonex +- Vincent Bernat +- urbandove +- Uman Shahzad +- Tomi Belan +- Tom Whitwell +- Tom Parker-Shemilt +- Tim Gates +- Thomas Bechtold +- Terseus +- Stan Seibert +- Shubhang Mani +- Sam James +- sam +- Rob Moss +- Rik +- rely10 +- rachmadaniHaryono +- proItheus +- Philipp Dieter +- Philipp A +- Mrinal Wadhwa +- Michal Kolodziejski +- Michał Górny +- michael +- Maxim Mazurok +- max0x53 +- Max R +- Max Melamed +- Max Liebkies +- Marc-Antoine Parent +- Marc Abramowitz +- Laust Rud Jacobsen +- Ken Struys +- Kai Weber +- Josh Soref +- Johnny Lim +- Joby Harding +- jiho +- Jesse Dhillon +- Jeremy Banks +- Jelle van der Waa +- Hugo van Kemenade +- Hugo +- Han Yeong-woo +- Geoffrey Huntley +- Fabricio C Zuardi +- Eashwar Ranganathan +- Duncan Bellamy +- dkgitdev +- dhilipsiva +- Dennis Flanigan +- Dan North +- Dan Fuchs +- Damien Nozay +- cmehay +- Brian Jacobel +- Ben Davis +- Ben Beasley +- Bastien Gérard +- Augusto Andreoli +- Andreas Wirooks +- Alexey Poryadin +- Aarni Koskela diff --git a/CHANGES b/CHANGES index 354928a..de03fd7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,70 @@ Nodeenv changelog ================= +Version [unreleased] +-------------------- + +- Added check for how `activate` is called. + +Version 1.3.1 +------------- +- Windows related fix `#207 `_ +- Fixed url for arm64 `#210 `_ +- Fixed fish support `#212 `_ + + +Version 1.3.0 +------------- +- Fixed symlink creation `#189 `_ +- Python3.6 support `#200 `_ +- Added `activate` for fish `#201 `_ +- Fixed cp866 `#202 `_ +- Added Conda support `#203 `_ + + +Version 1.2.0 +------------- +- Support for Cygwin `#194 `_ `#195 + `_ +- tox.ini as default configuration file `#197 + `_ + +Version 1.1.4 +------------- +- Fixed directory copy `#188 `_ + +Version 1.1.3 +------------- +- Fixed spaces in paths `#187 `_ + +Version 1.1.2 +------------- +- Fixed MANIFEST.in `#184 `_ + +Version 1.1.1 +------------- +- Improve Windows support. See `#181 + `_ +- Fix bug when downgrading using `--force`. See `#183 + `_ +- Environment creation fails with non-ASCII chars in path. See `#49 + `_ + +Version 1.1.0 +------------- +- Windows support + +Version 1.0.0 +------------- +- `--prebuilt` is default. See `# 161`_ +- Added `--source` option +- Added support for the `ARM`. See `# 171`_ +- Fixed issue with `$PATH`. See `# 86`_ + +.. _# 171: https://github.com/ekalinin/nodeenv/issues/171 +.. _# 161: https://github.com/ekalinin/nodeenv/issues/161 +.. _# 86: https://github.com/ekalinin/nodeenv/issues/86 + Version 0.13.6 -------------- - Use https for nodejs.org. See `# 129`_ diff --git a/MANIFEST.in b/MANIFEST.in index bde96b9..daa88db 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ include README LICENSE CHANGES AUTHORS include *.py *.rst setup.cfg Makefile -graft debian -prune debian/nodeenv -prune debian/sdist -recursive-exclude debian *.log *.substvars files +graft debian-upstream +prune debian-upstream/nodeenv +prune debian-upstream/sdist +recursive-exclude debian-upstream *.log *.substvars files diff --git a/Makefile b/Makefile index c7e6341..7bd20a8 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,8 @@ .PHONY: default deploy deploy-github deploy-pypi update-pypi clean tests env +PYTHON=python3 +TEST_ENV=env +DEV_TEST_ENV=env-dev +SETUP=pip install -U pip setuptools && $(PYTHON) setup.py install > /dev/null default: : do nothing when dpkg-buildpackage runs this project Makefile @@ -8,115 +12,139 @@ deploy-github: git push --tags origin master deploy-pypi: - python setup.py sdist upload + rm -rf dist + @. ${DEV_TEST_ENV}/bin/activate && \ + pip install -U setuptools wheel twine && \ + $(PYTHON) setup.py sdist bdist_wheel && \ + twine upload --repository pypi dist/* update-pypi: - python setup.py register + $(PYTHON) setup.py register -deploy: contributors deploy-github deploy-pypi +deploy: contributors ut deploy-github deploy-pypi clean: @rm -rf nodeenv.egg-info/ @rm -rf dist/ @rm -rf build/ - @rm -rf env/ + @rm -rf ${TEST_ENV}/ @rm -rf nodeenv/ -env: - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install +clean-test-env: + @rm -rf ${TEST_ENV} -test1: clean +# https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages +# https://github.com/pypa/virtualenv/issues/1681 +setup-test-env: + @virtualenv ${TEST_ENV} > /dev/null 2>&1 + +env: clean-test-env setup-test-env + @. ${TEST_ENV}/bin/activate && \ + $(PYTHON) setup.py install + +# https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages +# https://github.com/pypa/virtualenv/issues/1681 +env-dev: + @rm -rf ${DEV_TEST_ENV} && \ + $(PYTHON) -m venv ${DEV_TEST_ENV} && \ + . ${DEV_TEST_ENV}/bin/activate && \ + pip install -r requirements-dev.txt + +test1: clean clean-test-env setup-test-env @echo " =" @echo " = test1: separate nodejs's env" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ - rm -rf nodeenv && \ + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ nodeenv -j 4 nodeenv -test2: clean +test2: clean clean-test-env setup-test-env @echo " =" @echo " = test2: the same virtualenv's env, with 4 jobs" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ nodeenv -j 4 -p -test3: clean +test3: clean clean-test-env setup-test-env @echo " =" @echo " = test3: the same virtualenv's env, without any params" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ nodeenv -p # https://github.com/ekalinin/nodeenv/issues/43 -test4: clean +test4: clean clean-test-env @echo " =" - @echo " = test4: separate nodejs's env for python3.4" + @echo " = test4: system nodejs's for python3.9" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages --python=python3.4 env && \ - . env/bin/activate && \ - python setup.py install && \ - nodeenv 4 -p --prebuilt && \ + @virtualenv --python=python3.9 ${TEST_ENV} && \ + . ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ nodeenv -p --node=system -test5: clean +test5: clean clean-test-env @echo " =" @echo " = test5: prebuilt nodejs's env for python2" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages --python=python2.7 env && \ - . env/bin/activate && \ - python setup.py install && \ - nodeenv 4 -p --prebuilt && \ - nodeenv -p --node=system - -test6: clean - @echo " =" - @echo " = test6: separate iojs's env" - @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ - nodeenv -p --prebuilt --iojs + @virtualenv --python=python2.7 ${TEST_ENV} && \ + . ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ + nodeenv -p --prebuilt -test7: clean +test7: clean clean-test-env setup-test-env @echo " =" @echo " = test7: freeze for global installation" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ nodeenv -j 4 -p --prebuilt && \ - . env/bin/activate && \ + . ${TEST_ENV}/bin/activate && \ npm install -g sitemap && \ - test "`freeze | wc -l`" = "1"; + npm -v && \ + node -v && \ + test "`freeze | grep -v corepack | wc -l`" = " 1"; -test8: clean +test8: clean clean-test-env setup-test-env @echo " =" @echo " = test8: unicode paths, #49" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ rm -rf öäü && mkdir öäü && cd öäü && \ - nodeenv -j 4 --prebuilt env + nodeenv -j 4 --prebuilt env && \ + rm -rf öäü + +test9: clean clean-test-env setup-test-env + @echo " =" + @echo " = test9: unicode paths, #187" + @echo " =" + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ + rm -rf "test dir" && mkdir "test dir" && cd "test dir" && \ + nodeenv -j 4 --prebuilt env && \ + rm -rf "test dir" + +test10: clean clean-test-env setup-test-env + @echo " =" + @echo " = test10: symlink does not fail if npm already exists, #189" + @echo " =" + @. ${TEST_ENV}/bin/activate && \ + ${SETUP} && \ + nodeenv -j 4 -p --prebuilt && \ + nodeenv -j 4 -p --prebuilt + +tests: test1 test2 test3 test4 test7 test8 test9 test10 clean + +ut: env-dev + @. ${DEV_TEST_ENV}/bin/activate && tox -e py314 -tests: clean test1 test2 test3 test4 test5 test6 test7 test8 clean +coverage: env-dev + @. ${DEV_TEST_ENV}/bin/activate && \ + coverage run -p -m pytest && \ + coverage report -m && \ + coverage html contributors: @echo "Nodeenv is written and maintained by Eugene Kalinin." > AUTHORS @@ -127,4 +155,4 @@ contributors: @git log --raw | grep "^Author: " | \ sort | uniq -c | sort -n -r | \ cut -d ':' -f 2 | sed 's/^/- /' | \ - cut -d '<' -f1 | uniq | grep -v Kalinin >> AUTHORS + cut -d '<' -f1 | uniq | grep -v Kalinin | sed 's/ *$$//g' >> AUTHORS diff --git a/README.rst b/README.rst index 63c8d14..09880b8 100644 --- a/README.rst +++ b/README.rst @@ -1,10 +1,10 @@ Node.js virtual environment =========================== -``nodeenv`` (node.js virtual environment) is a tool to create +``nodeenv`` (node.js virtual environment) is a tool to create isolated node.js environments. -It creates an environment that has its own installation directories, +It creates an environment that has its own installation directories, that doesn't share libraries with other node.js virtual environments. Also the new environment can be integrated with the environment which was built @@ -14,8 +14,12 @@ If you use nodeenv feel free to add your project on wiki: `Who-Uses-Nodeenv`_. .. _Who-Uses-Nodeenv: https://github.com/ekalinin/nodeenv/wiki/Who-Uses-Nodeenv -.. image:: https://travis-ci.org/ekalinin/nodeenv.svg?branch=master - :target: https://travis-ci.org/ekalinin/nodeenv +.. image:: https://github.com/ekalinin/nodeenv/actions/workflows/main.yml/badge.svg?branch=master + :target: https://github.com/ekalinin/nodeenv/actions/workflows/main.yml + :alt: CI + +.. contents:: :local: + Install ------- @@ -51,7 +55,7 @@ pip_/easy_install_ inside any virtual environment built with virtualenv:: (env) $ nodeenv --version 0.6.5 -If you want to work with the latest version of the nodeenv you can +If you want to work with the latest version of the nodeenv you can install it from the github `repository`_:: $ git clone https://github.com/ekalinin/nodeenv.git @@ -72,7 +76,7 @@ Dependency For nodeenv ^^^^^^^^^^^ -* python (>= 2.6) +* python (2.6+, 3.5+, or pypy) * make * tail @@ -124,16 +128,21 @@ Get available node.js versions:: 0.3.2 0.3.3 0.3.4 0.3.5 0.3.6 0.3.7 0.3.8 0.4.1 0.4.2 0.4.3 0.4.4 0.4.5 0.4.6 -Install node.js "0.4.3" without ssl support with 4 parallel commands +Install node.js "0.4.3" without ssl support with 4 parallel commands for compilation and npm.js "0.3.17":: - $ nodeenv --without-ssl --node=0.4.3 --npm=0.3.17 --jobs=4 env-4.3 + $ nodeenv --without-ssl --node=0.4.3 --npm=0.3.17 --with-npm --jobs=4 env-4.3 + +Install node.js from the source:: -Install node.js from prebuilt package:: + $ nodeenv --node=0.10.25 --source env-0.10.25 - $ nodeenv --node=0.10.25 --prebuilt env-0.10.25-prebuilt +Install node.js from a mirror:: -It's much faster than installing & compiling node.js from source:: + $ nodeenv --node=10.19.0 --mirror=https://npm.taobao.org/mirrors/node + +It's much faster to install from the prebuilt package than Install & compile +node.js from source:: $ time nodeenv --node=0.10.25 --prebuilt env-0.10.25-prebuilt + Install node.js (0.10.25) ... done. @@ -142,7 +151,7 @@ It's much faster than installing & compiling node.js from source:: user 0m0.408s sys 0m1.144s - $ time nodeenv --node=0.10.25 env-0.10.25-src + $ time nodeenv --node=0.10.25 --source env-0.10.25-src + Install node.js (0.10.25) ... done. real 4m12.602s @@ -168,7 +177,7 @@ Create an environment from a requirements file:: $ nodeenv --requirements=../prod-requirements.txt --jobs=4 env-copy -Requirements files are plain text files that contain a list of packages +Requirements files are plain text files that contain a list of packages to be installed. These text files allow you to create repeatable installations. Requirements file example:: @@ -193,7 +202,7 @@ virtual environment:: and add a node virtual environment to this existing new_venv:: $ nodeenv -p - + If you need to set the path to make used to build node:: $ nodeenv -m /usr/local/bin/gmake ENV @@ -203,9 +212,13 @@ environment:: $ workon my_env $ npm install -g coffee-script - $ which coffee + $ command -v coffee /home/monty/virtualenvs/my_env/bin/coffee +Creating a virtual environment with a custom prompt: + + $ nodeenv --node=12.18.2 --prompt="(myenv)" nodeenv + If environment's directory already exists then you can use ``--force`` option:: $ nodeenv --requirements=requirements.txt --jobs=4 --force env @@ -222,17 +235,103 @@ use `shim` script:: $ ./env-4.3/bin/shim --version v0.4.3 +Command Line Options +-------------------- -If you want to install iojs instead of nodejs then use ``--iojs``:: +Basic options +^^^^^^^^^^^^^ - $ virtualenv env - $ . env/bin/activate - (env) $ nodeenv --iojs --list - 1.0.0 1.0.1 - (env) $ nodeenv --iojs -p --prebuilt - * Install iojs (1.0.1) ... done. - * Appending data to ~/tmp/env/bin/activate +``-n NODE_VER, --node=NODE_VER`` + The node.js version to use, e.g., ``--node=22.11.0``. The default is the + last stable version (``latest``). Use ``lts`` for the latest LTS release. + Use ``system`` to use system-wide node. + +``-l, --list`` + Lists available node.js versions. + +``-p, --python-virtualenv`` + Use current python virtualenv. +``-r FILENAME, --requirements=FILENAME`` + Install all the packages listed in the given requirements file. + +``--prompt=PROMPT`` + Provides an alternative prompt prefix for this environment. + +``--force`` + Force installation in a pre-existing directory. + +``--update`` + Install npm packages from file without reinstalling node. + +Installation options +^^^^^^^^^^^^^^^^^^^^ + +``--prebuilt`` + Install node.js from prebuilt package (default). + +``--source`` + Install node.js from the source (Unix only). + +``--mirror=URL`` + Set mirror server of nodejs.org to download from. + +``-c, --clean-src`` + Remove "src" directory after installation. + +NPM options +^^^^^^^^^^^ + +``--npm=NPM_VER`` + The npm version to use, e.g., ``--npm=10.0.0``. + The default is the last available version (``latest``). + +``--with-npm`` + Install npm into the new virtual environment. Required for node.js < 0.6.3. + By default, the npm included with node.js is used. + +``--no-npm-clean`` + Skip the npm 0.x cleanup. Cleanup is enabled by default. + +Compilation options (Unix only) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``-j JOBS, --jobs=JOBS`` + Sets number of parallel commands at node.js compilation. The default is 2 jobs. + +``--load-average=LOAD`` + Sets maximum load average for executing parallel commands at node.js compilation. + +``-m MAKE_PATH, --make=MAKE_PATH`` + Path to make command. + +``--without-ssl`` + Build node.js without SSL support. + +``--debug`` + Build debug variant of the node.js. + +``--profile`` + Enable profiling for node.js. + +Other options +^^^^^^^^^^^^^ + +``-v, --verbose`` + Verbose mode. + +``-q, --quiet`` + Quiet mode. + +``-C CONFIG_FILE, --config-file=CONFIG_FILE`` + Load a different config file than ``~/.nodeenvrc``. + Pass an empty string for no config (use built-in defaults). + +``--ignore_ssl_certs`` + Ignore SSL certificates for package downloads. **UNSAFE - use at your own risk**. + +``--version`` + Show program version and exit. Configuration ------------- @@ -242,15 +341,17 @@ the keys in that file are the long command-line option names. These are the available options and their defaults:: [nodeenv] - debug = False - jobs = 2 - make = make - node = latest - npm = latest - prebuilt = False - profile = False + node = 'latest' + npm = 'latest' with_npm = False + jobs = '2' without_ssl = False + debug = False + profile = False + make = 'make' + prebuilt = True + ignore_ssl_certs = False + mirror = None Alternatives ------------ @@ -261,7 +362,7 @@ There are several alternatives that create isolated environments: Nave stores all environments in one directory ``~/.nave``. Can create per node version environments using `nave use envname versionname`. Can not pass additional arguments into configure (for example --without-ssl) - Can't run on windows because it relies on bash. + Can't run on windows because it relies on a POSIX shell. * `nvm `_ - Node Version Manager. It is necessarily to do `nvm sync` for caching available node.js diff --git a/README.ru.rst b/README.ru.rst index c3eb130..2cc821e 100644 --- a/README.ru.rst +++ b/README.ru.rst @@ -155,7 +155,7 @@ python'а:: $ workon my_env $ npm install -g coffee-script - $ which coffee + $ command -v coffee /home/monty/virtualenvs/my_env/bin/coffee diff --git a/nodeenv.py b/nodeenv.py index 8772bf4..e2cf1f0 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -12,43 +12,53 @@ import contextlib import io +import json import sys import os import re +import ssl import stat import logging import operator -import optparse +import argparse import subprocess import tarfile -import pipes +if sys.version_info < (3, 3): + from pipes import quote as _quote +else: + from shlex import quote as _quote import platform +import zipfile +import shutil +import sysconfig +import glob try: # pragma: no cover (py2 only) - from ConfigParser import SafeConfigParser as ConfigParser - from HTMLParser import HTMLParser - import urllib2 + from ConfigParser import SafeConfigParser as ConfigParser # pyright: ignore[reportMissingImports] # noqa: E501 + # noinspection PyCompatibility + import urllib2 # pyright: ignore[reportMissingImports] iteritems = operator.methodcaller('iteritems') + import httplib # pyright: ignore[reportMissingImports] + IncompleteRead = httplib.IncompleteRead except ImportError: # pragma: no cover (py3 only) from configparser import ConfigParser - from html.parser import HTMLParser + # noinspection PyUnresolvedReferences import urllib.request as urllib2 iteritems = operator.methodcaller('items') + import http + IncompleteRead = http.client.IncompleteRead -from pkg_resources import parse_version - -nodeenv_version = '0.13.6' +nodeenv_version = '1.10.0' join = os.path.join abspath = os.path.abspath -src_domain = "nodejs.org" - -is_PY3 = sys.version_info[0] == 3 -if is_PY3: - from functools import cmp_to_key +src_base_url = None +is_PY3 = sys.version_info[0] >= 3 is_WIN = platform.system() == 'Windows' +is_CYGWIN = platform.system().startswith(('CYGWIN', 'MSYS')) +ignore_ssl_certs = False # --------------------------------------------------------- # Utils @@ -60,20 +70,19 @@ def to_utf8(text): if not text or is_PY3: return text - try: # unicode or pure ascii + try: # unicode or pure ascii return text.encode("utf8") except UnicodeDecodeError: - try: # successful UTF-8 decode means it's pretty sure UTF-8 + try: # successful UTF-8 decode means it's pretty sure UTF-8 text.decode("utf8") return text except UnicodeDecodeError: - try: # get desperate; and yes, - # this has a western hemisphere bias + try: # get desperate; and yes, this has a western hemisphere bias return text.decode("cp1252").encode("utf8") except UnicodeDecodeError: pass - return text # return unchanged, hope for the best + return text # return unchanged, hope for the best class Config(object): @@ -90,13 +99,16 @@ class Config(object): debug = False profile = False make = 'make' - prebuilt = False + prebuilt = True + ignore_ssl_certs = False + mirror = None @classmethod def _load(cls, configfiles, verbose=False): """ Load configuration from the given files in reverse order, if they exist and have a [nodeenv] section. + Additionally, load version from .node-version if file exists. """ for configfile in reversed(configfiles): configfile = os.path.expanduser(configfile) @@ -124,6 +136,10 @@ def _load(cls, configfiles, verbose=False): os.path.basename(configfile), attr, val)) setattr(cls, attr, val) + if os.path.exists(".node-version"): + with open(".node-version", "r") as v_file: + setattr(cls, "node", v_file.readline().strip().lstrip("v")) + @classmethod def _dump(cls): """ @@ -155,16 +171,27 @@ def remove_env_bin_from_path(env, env_bin_dir): return env.replace(env_bin_dir + ':', '') -def node_version_from_opt(opt): +def parse_version(version_str): + """ + Parse version string to a tuple of integer parts + """ + v = version_str.replace('v', '').split('.')[:3] + # remove all after '+' in the PATCH part of the version + if len(v) >= 3: + v[2] = v[2].split('+')[0] + return tuple(map(int, v)) + + +def node_version_from_args(args): """ - Parse the node version from the optparse options + Parse the node version from the argparse args """ - if opt.node == 'system': + if args.node == 'system': out, err = subprocess.Popen( ["node", "--version"], stdout=subprocess.PIPE).communicate() - return parse_version(clear_output(out).replace('v', '')) + return parse_version(clear_output(out)) - return parse_version(opt.node) + return parse_version(args.node) def create_logger(): @@ -172,8 +199,8 @@ def create_logger(): Create logger for diagnostic """ # create logger - logger = logging.getLogger("nodeenv") - logger.setLevel(logging.INFO) + loggr = logging.getLogger("nodeenv") + loggr.setLevel(logging.INFO) # monkey patch def emit(self, record): @@ -194,101 +221,116 @@ def emit(self, record): ch.setFormatter(formatter) # add ch to logger - logger.addHandler(ch) - return logger + loggr.addHandler(ch) + return loggr + + logger = create_logger() -def parse_args(check=True): +def make_parser(): """ - Parses command line arguments. - - Set `check` to False to skip validation checks. + Make a command line argument parser. """ - parser = optparse.OptionParser( - version=nodeenv_version, - usage="%prog [OPTIONS] ENV_DIR") + parser = argparse.ArgumentParser( + usage="%(prog)s [OPTIONS] DEST_DIR") + + parser.add_argument( + '--version', action='version', version=nodeenv_version) - parser.add_option( + parser.add_argument( '-n', '--node', dest='node', metavar='NODE_VER', default=Config.node, help='The node.js version to use, e.g., ' '--node=0.4.3 will use the node-v0.4.3 ' 'to create the new environment. ' 'The default is last stable version (`latest`). ' + 'Use `lts` to use the latest LTS release. ' 'Use `system` to use system-wide node.') - parser.add_option( - '-i', '--iojs', - action='store_true', dest='io', default=False, - help='Use iojs instead of nodejs.') - - parser.add_option( - '-j', '--jobs', dest='jobs', default=Config.jobs, - help='Sets number of parallel commands at node.js compilation. ' - 'The default is 2 jobs.') + parser.add_argument( + '--mirror', + action="store", dest='mirror', default=Config.mirror, + help='Set mirror server of nodejs.org to download from.') - parser.add_option( - '--load-average', dest='load_average', - help='Sets maximum load average for executing parallel commands ' - 'at node.js compilation.') - - parser.add_option( + if not is_WIN: + parser.add_argument( + '-j', '--jobs', dest='jobs', default=Config.jobs, + help='Sets number of parallel commands at node.js compilation. ' + 'The default is 2 jobs.') + + parser.add_argument( + '--load-average', dest='load_average', + help='Sets maximum load average for executing parallel commands ' + 'at node.js compilation.') + + parser.add_argument( + '--without-ssl', dest='without_ssl', + action='store_true', default=Config.without_ssl, + help='Build node.js without SSL support') + + parser.add_argument( + '--debug', dest='debug', + action='store_true', default=Config.debug, + help='Build debug variant of the node.js') + + parser.add_argument( + '--profile', dest='profile', + action='store_true', default=Config.profile, + help='Enable profiling for node.js') + + parser.add_argument( + '--make', '-m', dest='make_path', + metavar='MAKE_PATH', + help='Path to make command', + default=Config.make) + + parser.add_argument( + '--source', dest='prebuilt', + action='store_false', default=Config.prebuilt, + help='Install node.js from the source') + + parser.add_argument( '-v', '--verbose', action='store_true', dest='verbose', default=False, help="Verbose mode") - parser.add_option( + parser.add_argument( '-q', '--quiet', action='store_true', dest='quiet', default=False, help="Quiet mode") - parser.add_option( + parser.add_argument( '-C', '--config-file', dest='config_file', default=None, help="Load a different file than '~/.nodeenvrc'. " "Pass an empty string for no config (use built-in defaults).") - parser.add_option( + parser.add_argument( '-r', '--requirements', dest='requirements', default='', metavar='FILENAME', help='Install all the packages listed in the given requirements file.') - parser.add_option( + parser.add_argument( '--prompt', dest='prompt', help='Provides an alternative prompt prefix for this environment') - parser.add_option( + parser.add_argument( '-l', '--list', dest='list', action='store_true', default=False, help='Lists available node.js versions') - parser.add_option( + parser.add_argument( '--update', dest='update', action='store_true', default=False, help='Install npm packages from file without node') - parser.add_option( - '--without-ssl', dest='without_ssl', - action='store_true', default=Config.without_ssl, - help='Build node.js without SSL support') - - parser.add_option( - '--debug', dest='debug', - action='store_true', default=Config.debug, - help='Build debug variant of the node.js') - - parser.add_option( - '--profile', dest='profile', - action='store_true', default=Config.profile, - help='Enable profiling for node.js') - - parser.add_option( + parser.add_argument( '--with-npm', dest='with_npm', action='store_true', default=Config.with_npm, help='Build without installing npm into the new virtual environment. ' 'Required for node.js < 0.6.3. By default, the npm included with ' - 'node.js is used.') + 'node.js is used. Under Windows, this defaults to true.') - parser.add_option( + parser.add_argument( '--npm', dest='npm', metavar='NPM_VER', default=Config.npm, help='The npm version to use, e.g., ' @@ -296,62 +338,72 @@ def parse_args(check=True): 'tarball to install. ' 'The default is last available version (`latest`).') - parser.add_option( + parser.add_argument( '--no-npm-clean', dest='no_npm_clean', action='store_true', default=False, help='Skip the npm 0.x cleanup. Cleanup is enabled by default.') - parser.add_option( + parser.add_argument( '--python-virtualenv', '-p', dest='python_virtualenv', action='store_true', default=False, help='Use current python virtualenv') - parser.add_option( + parser.add_argument( '--clean-src', '-c', dest='clean_src', action='store_true', default=False, help='Remove "src" directory after installation') - parser.add_option( + parser.add_argument( '--force', dest='force', action='store_true', default=False, help='Force installation in a pre-existing directory') - parser.add_option( - '--make', '-m', dest='make_path', - metavar='MAKE_PATH', - help='Path to make command', - default=Config.make) - - parser.add_option( + parser.add_argument( '--prebuilt', dest='prebuilt', action='store_true', default=Config.prebuilt, - help='Install node.js from prebuilt package') + help='Install node.js from prebuilt package (default)') + + parser.add_argument( + '--ignore_ssl_certs', dest='ignore_ssl_certs', + action='store_true', default=Config.ignore_ssl_certs, + help='Ignore certificates for package downloads. - UNSAFE -') + + parser.add_argument( + metavar='DEST_DIR', dest='env_dir', nargs='?', + help='Destination directory') + + return parser + + +def parse_args(check=True): + """ + Parses command line arguments. - options, args = parser.parse_args() - if options.config_file is None: - options.config_file = ["./setup.cfg", "~/.nodeenvrc"] - elif not options.config_file: - options.config_file = [] + Set `check` to False to skip validation checks. + """ + parser = make_parser() + args = parser.parse_args() + + if args.config_file is None: + args.config_file = ["./tox.ini", "./setup.cfg", "~/.nodeenvrc"] + elif not args.config_file: + args.config_file = [] else: # Make sure that explicitly provided files exist - if not os.path.exists(options.config_file): + if not os.path.exists(args.config_file): parser.error("Config file '{0}' doesn't exist!".format( - options.config_file)) - options.config_file = [options.config_file] + args.config_file)) + args.config_file = [args.config_file] if not check: - return options, args + return args - if not options.list and not options.python_virtualenv: - if not args: + if not args.list: + if not args.python_virtualenv and not args.env_dir: parser.error('You must provide a DEST_DIR or ' 'use current python virtualenv') - if len(args) > 1: - parser.error('There must be only one argument: DEST_DIR ' - '(you gave: {0})'.format(' '.join(args))) - - return options, args + return args def mkdir(path): @@ -366,26 +418,31 @@ def mkdir(path): logger.debug(' * Directory %s already exists', path) +def make_executable(filename): + mode_0755 = (stat.S_IRWXU | stat.S_IXGRP | + stat.S_IRGRP | stat.S_IROTH | stat.S_IXOTH) + os.chmod(filename, mode_0755) + + +# noinspection PyArgumentList def writefile(dest, content, overwrite=True, append=False): """ Create file and write content in it """ - mode_0755 = (stat.S_IRWXU | stat.S_IXGRP | - stat.S_IRGRP | stat.S_IROTH | stat.S_IXOTH) content = to_utf8(content) - if is_PY3: + if is_PY3 and not isinstance(content, bytes): content = bytes(content, 'utf-8') if not os.path.exists(dest): logger.debug(' * Writing %s ... ', dest, extra=dict(continued=True)) with open(dest, 'wb') as f: f.write(content) - os.chmod(dest, mode_0755) + make_executable(dest) logger.debug('done.') return else: with open(dest, 'rb') as f: c = f.read() - if c == content: + if content in c: logger.debug(' * Content %s already in place', dest) return @@ -397,9 +454,7 @@ def writefile(dest, content, overwrite=True, append=False): if append: logger.info(' * Appending data to %s', dest) with open(dest, 'ab') as f: - f.write(DISABLE_PROMPT.encode('utf-8')) f.write(content) - f.write(ENABLE_PROMPT.encode('utf-8')) return logger.info(' * Overwriting %s with new content', dest) @@ -453,7 +508,13 @@ def callit(cmd, show_stdout=True, in_shell=False, line = stdout.readline() if not line: break - line = line.decode('utf-8').rstrip() + try: + if is_WIN: + line = line.decode('mbcs').rstrip() + else: + line = line.decode('utf8').rstrip() + except UnicodeDecodeError: + line = line.decode('cp866').rstrip() all_output.append(line) if show_stdout: logger.info(line) @@ -470,34 +531,57 @@ def callit(cmd, show_stdout=True, in_shell=False, return proc.returncode, all_output -def get_root_url(version): - if parse_version(version) > parse_version("0.5.0"): - return 'https://%s/dist/v%s/' % (src_domain, version) +def get_root_url(version_str): + if parse_version(version_str) > (0, 5): + return '%s/v%s/' % (src_base_url, version_str) else: - return 'https://%s/dist/' % (src_domain) + return src_base_url + + +def is_x86_64_musl(): + return sysconfig.get_config_var('HOST_GNU_TYPE') == 'x86_64-pc-linux-musl' + + +def is_riscv64(): + return platform.machine() == 'riscv64' def get_node_bin_url(version): archmap = { - 'x86': 'x86', # Windows Vista 32 - 'i686': 'x86', - 'x86_64': 'x64', # Linux Ubuntu 64 - 'AMD64': 'x64', # Windows Server 2012 R2 (x64) + 'x86': 'x86', # Windows Vista 32 + 'i686': 'x86', + 'x86_64': 'x64', # Linux Ubuntu 64 + 'amd64': 'x64', # FreeBSD 64bits + 'amd64': 'x64', # Windows Server 2012 R2 (x64) + 'i86pc': 'x64', # Solaris/illumos 64 + 'armv6l': 'armv6l', # arm + 'armv7l': 'armv7l', + 'armv8l': 'armv7l', + 'aarch64': 'arm64', + 'arm64': 'arm64', + 'arm64/v8': 'arm64', + 'armv8': 'arm64', + 'armv8.4': 'arm64', + 'ppc64le': 'ppc64le', # Power PC + 's390x': 's390x', # IBM S390x + 'riscv64': 'riscv64', # RISCV 64 } sysinfo = { - 'system': platform.system().lower(), - 'arch': archmap[platform.machine()], + 'system': platform.system().lower(), + 'arch': archmap[platform.machine().lower()], } - if is_WIN: - filename = 'win-%(arch)s/node.exe' % sysinfo + if is_WIN or is_CYGWIN: + postfix = '-win-%(arch)s.zip' % sysinfo + elif is_x86_64_musl(): + postfix = '-linux-x64-musl.tar.gz' else: postfix = '-%(system)s-%(arch)s.tar.gz' % sysinfo - filename = '%s-v%s%s' % (get_binary_prefix(), version, postfix) + filename = 'node-v%s%s' % (version, postfix) return get_root_url(version) + filename def get_node_src_url(version): - tar_name = '%s-v%s.tar.gz' % (get_binary_prefix(), version) + tar_name = 'node-v%s.tar.gz' % version return get_root_url(version) + tar_name @@ -511,60 +595,122 @@ def tarfile_open(*args, **kwargs): tf.close() -def download_node_bin(node_url, env_dir): - """ - Download node binaries directly into environment - """ - if is_WIN: - bin_dir = os.path.join(env_dir, 'bin') - mkdir(bin_dir) - fp = open(os.path.join(bin_dir, os.path.basename(node_url)), 'wb+') - fp.write(urlopen(node_url).read()) - else: - download_node_tar(node_url, env_dir, strip=True) +def _download_node_file(node_url, n_attempt=3): + """Do multiple attempts to avoid incomplete data in case + of unstable network""" + while n_attempt > 0: + try: + return io.BytesIO(urlopen(node_url).read()) + except IncompleteRead as e: + logger.warning( + 'Incomplete read while reading ' + 'from {} - {}'.format(node_url, e) + ) + n_attempt -= 1 + if n_attempt == 0: + raise e -def download_node_tar(node_url, src_dir, strip=False): +def download_node_src(node_url, src_dir, args): """ - Download and unpack tar contents. If strip is set, also strips - root directory and all files in it (archive with node binary). + Download source code """ - tar_contents = io.BytesIO(urlopen(node_url).read()) - with tarfile_open(fileobj=tar_contents) as tarfile_obj: - member_list = tarfile_obj.getmembers() - extract_list = [] - for member in member_list: - # skip leading dir - newstart = member.name.find('/')+1 - newname = member.name[newstart:] - if strip: - if not newstart: - continue - # members can be renamed before extraction ! - member.name = newname - regex_string = "^(README\.md|CHANGELOG\.md|LICENSE)" - if re.match(regex_string, newname) is not None: - logger.debug(' Stripping %s ', newname) - continue - extract_list.append(member) - tarfile_obj.extractall(src_dir, extract_list) + logger.info('.', extra=dict(continued=True)) + dl_contents = _download_node_file(node_url) + logger.info('.', extra=dict(continued=True)) + + if is_WIN or is_CYGWIN: + ctx = zipfile.ZipFile(dl_contents) + members = operator.methodcaller('namelist') + member_name = lambda s: s # noqa: E731 + else: + ctx = tarfile_open(fileobj=dl_contents) + members = operator.methodcaller('getmembers') + member_name = operator.attrgetter('name') + + with ctx as archive: + node_ver = re.escape(args.node) + rexp_string = r"node-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ + % node_ver + extract_list = [ + member + for member in members(archive) + if re.match(rexp_string, member_name(member)) is None + ] + if sys.version_info >= (3, 12): + archive.extractall(src_dir, extract_list, filter="data") + else: + archive.extractall(src_dir, extract_list) def urlopen(url): home_url = "https://github.com/ekalinin/nodeenv/" headers = {'User-Agent': 'nodeenv/%s (%s)' % (nodeenv_version, home_url)} req = urllib2.Request(url, None, headers) + if ignore_ssl_certs: + # py27: protocol required, py3: optional + # https://github.com/ekalinin/nodeenv/issues/296 + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + context.verify_mode = ssl.CERT_NONE + return urllib2.urlopen(req, context=context) return urllib2.urlopen(req) # --------------------------------------------------------- # Virtual environment functions -def build_node_from_src(env_dir, src_dir, node_src_dir, opt): +def copytree(src, dst, symlinks=False, ignore=None): + for item in os.listdir(src): + s = os.path.join(src, item) + d = os.path.join(dst, item) + if os.path.isdir(s): + try: + shutil.copytree(s, d, symlinks, ignore) + except OSError: + copytree(s, d, symlinks, ignore) + else: + if os.path.islink(s): + # copy link only if it not exists. #189 + if not os.path.islink(d): + os.symlink(os.readlink(s), d) + else: + shutil.copy2(s, d) + + +def copy_node_from_prebuilt(env_dir, src_dir, node_version): + """ + Copy prebuilt binaries into environment + """ + logger.info('.', extra=dict(continued=True)) + if is_WIN: + dest = join(env_dir, 'Scripts') + mkdir(dest) + elif is_CYGWIN: + dest = join(env_dir, 'bin') + mkdir(dest) + # write here to avoid https://bugs.python.org/issue35650 + writefile(join(env_dir, 'bin', 'node'), CYGWIN_NODE) + else: + dest = env_dir + + src_folder_tpl = src_dir + to_utf8('/node-v%s*' % node_version) + src_folder, = glob.glob(src_folder_tpl) + copytree(src_folder, dest, True) + + if is_CYGWIN: + for filename in ('npm', 'npx', 'node.exe'): + filename = join(env_dir, 'bin', filename) + if os.path.exists(filename): + make_executable(filename) + + logger.info('.', extra=dict(continued=True)) + + +def build_node_from_src(env_dir, src_dir, node_src_dir, args): env = {} make_param_names = ['load-average', 'jobs'] make_param_values = map( - lambda x: getattr(opt, x.replace('-', '_')), + lambda x: getattr(args, x.replace('-', '_')), make_param_names) make_opts = [ '--{0}={1}'.format(name, value) @@ -577,12 +723,8 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): # Currently, the node.js build scripts are using python2.*, # therefore we need to temporarily point python exec to the # python 2.* version in this case. - try: - _, which_python2_output = callit( - ['which', 'python2'], opt.verbose, True, node_src_dir, env - ) - python2_path = which_python2_output[0] - except (OSError, IndexError): + python2_path = shutil.which('python2') + if not python2_path: raise OSError( 'Python >=3.0 virtualenv detected, but no python2 ' 'command (required for building node.js) was found' @@ -596,77 +738,93 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): env['PATH'] = '{}:{}'.format(node_tmpbin_dir, os.environ.get('PATH', '')) - conf_cmd = [] - conf_cmd.append('./configure') - conf_cmd.append('--prefix=%s' % pipes.quote(env_dir)) - if opt.without_ssl: + conf_cmd = [ + './configure', + '--prefix=%s' % _quote(env_dir) + ] + if args.without_ssl: conf_cmd.append('--without-ssl') - if opt.debug: + if args.debug: conf_cmd.append('--debug') - if opt.profile: + if args.profile: conf_cmd.append('--profile') - make_cmd = opt.make_path + make_cmd = args.make_path - callit(conf_cmd, opt.verbose, True, node_src_dir, env) + callit(conf_cmd, args.verbose, True, node_src_dir, env) logger.info('.', extra=dict(continued=True)) - callit([make_cmd] + make_opts, opt.verbose, True, node_src_dir, env) + callit([make_cmd] + make_opts, args.verbose, True, node_src_dir, env) logger.info('.', extra=dict(continued=True)) - callit([make_cmd + ' install'], opt.verbose, True, node_src_dir, env) - + callit([make_cmd + ' install'], args.verbose, True, node_src_dir, env) -def get_binary_prefix(): - return to_utf8('node' if src_domain == 'nodejs.org' else 'iojs') - -def install_node(env_dir, src_dir, opt): +def install_node(env_dir, src_dir, args): """ Download source code for node.js, unpack it and install it in virtual environment. """ + try: + install_node_wrapped(env_dir, src_dir, args) + except BaseException: + # this restores the newline suppressed by continued=True + logger.info('') + raise + + +def install_node_wrapped(env_dir, src_dir, args): env_dir = abspath(env_dir) - prefix = get_binary_prefix() - if opt.prebuilt: - logger.info(' * Installing binary %s (%s)' % (prefix, opt.node)) - node_url = get_node_bin_url(opt.node) - - # get binary if not downloaded yet - if not os.path.exists(os.path.join(env_dir, 'bin')): - logger.info(' Downloading %s' % node_url) - download_node_bin(node_url, env_dir) + node_src_dir = join(src_dir, to_utf8('node-v%s' % args.node)) + src_type = "prebuilt" if args.prebuilt else "source" + + logger.info(' * Install %s node (%s) ' % (src_type, args.node), + extra=dict(continued=True)) + + if args.prebuilt: + node_url = get_node_bin_url(args.node) else: - logger.info(' * Installing %s (%s) from source' % (prefix, opt.node)) - node_url = get_node_src_url(opt.node) - node_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) + node_url = get_node_src_url(args.node) - # get src if not downloaded yet - if not os.path.exists(node_src_dir): - logger.info(' Downloading %s' % node_url) - download_node_tar(node_url, src_dir) + # get src if not downloaded yet + if not os.path.exists(node_src_dir): + try: + download_node_src(node_url, src_dir, args) + except urllib2.HTTPError: + if "arm64" in node_url: + # if arm64 not found, try x64 + download_node_src(node_url.replace('arm64', 'x64'), + src_dir, args) + else: + logger.warning('Failed to download from %s' % node_url) + raise - build_node_from_src(env_dir, src_dir, node_src_dir, opt) + logger.info('.', extra=dict(continued=True)) - logger.info(' Done.') + if args.prebuilt: + copy_node_from_prebuilt(env_dir, src_dir, args.node) + else: + build_node_from_src(env_dir, src_dir, node_src_dir, args) + logger.info(' done.') -def install_npm(env_dir, src_dir, opt): + +def install_npm(env_dir, _src_dir, args): """ Download source code for npm, unpack it and install it in virtual environment. """ - logger.info(' * Install npm.js (%s) ... ' % opt.npm, + logger.info(' * Install npm.js (%s) ... ' % args.npm, extra=dict(continued=True)) - npm_contents = urlopen('https://www.npmjs.org/install.sh').read() env = dict( os.environ, - clean='no' if opt.no_npm_clean else 'yes', - npm_install=opt.npm, + clean='no' if args.no_npm_clean else 'yes', + npm_install=args.npm, ) proc = subprocess.Popen( ( - 'bash', '-c', - '. {0} && exec bash'.format( - pipes.quote(join(env_dir, 'bin', 'activate')), + 'sh', '-c', + '. {0} && npm install -g npm@{1}'.format( + _quote(join(env_dir, 'bin', 'activate')), + args.npm, ) ), env=env, @@ -674,27 +832,69 @@ def install_npm(env_dir, src_dir, opt): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) - out, _ = proc.communicate(npm_contents) - if opt.verbose: + out, _ = proc.communicate() + if args.verbose: logger.info(out) logger.info('done.') -def install_packages(env_dir, opt): +def install_npm_win(env_dir, src_dir, args): + """ + Download source code for npm, unpack it + and install it in virtual environment. + """ + logger.info(' * Install npm.js (%s) ... ' % args.npm, + extra=dict(continued=True)) + npm_url = 'https://github.com/npm/cli/archive/v%s.zip' % args.npm + npm_contents = io.BytesIO(urlopen(npm_url).read()) + + bin_path = join(env_dir, 'Scripts') + node_modules_path = join(bin_path, 'node_modules', 'npm') + + if os.path.exists(node_modules_path): + shutil.rmtree(node_modules_path) + + if os.path.exists(join(bin_path, 'npm.cmd')): + os.remove(join(bin_path, 'npm.cmd')) + + if os.path.exists(join(bin_path, 'npm-cli.js')): + os.remove(join(bin_path, 'npm-cli.js')) + + with zipfile.ZipFile(npm_contents, 'r') as zipf: + zipf.extractall(src_dir) + + npm_ver = 'cli-%s' % args.npm + shutil.copytree(join(src_dir, npm_ver), node_modules_path) + shutil.copy(join(src_dir, npm_ver, 'bin', 'npm.cmd'), + join(bin_path, 'npm.cmd')) + shutil.copy(join(src_dir, npm_ver, 'bin', 'npm-cli.js'), + join(bin_path, 'npm-cli.js')) + + if is_CYGWIN: + shutil.copy(join(bin_path, 'npm-cli.js'), + join(env_dir, 'bin', 'npm-cli.js')) + shutil.copytree(join(bin_path, 'node_modules'), + join(env_dir, 'bin', 'node_modules')) + npm_gh_url = 'https://raw.githubusercontent.com/npm/cli' + npm_bin_url = '{}/{}/bin/npm'.format(npm_gh_url, args.npm) + writefile(join(env_dir, 'bin', 'npm'), urlopen(npm_bin_url).read()) + + +def install_packages(env_dir, args): """ Install node.js packages via npm """ logger.info(' * Install node.js packages ... ', extra=dict(continued=True)) packages = [package.strip() for package in - open(opt.requirements).readlines()] + open(args.requirements).readlines()] activate_path = join(env_dir, 'bin', 'activate') - real_npm_ver = opt.npm if opt.npm.count(".") == 2 else opt.npm + ".0" - if opt.npm == "latest" or real_npm_ver >= "1.0.0": - cmd = '. ' + pipes.quote(activate_path) + \ + real_npm_ver = args.npm if args.npm.count(".") == 2 else args.npm + ".0" + if args.npm == "latest" or real_npm_ver >= "1.0.0": + cmd = '. ' + _quote(activate_path) + \ ' && npm install -g %(pack)s' else: - cmd = '. ' + pipes.quote(activate_path) + \ + cmd = '. ' + _quote(activate_path) + \ ' && npm install %(pack)s' + \ ' && npm activate %(pack)s' @@ -702,36 +902,47 @@ def install_packages(env_dir, opt): if not package: continue callit(cmd=[ - cmd % {"pack": package}], show_stdout=opt.verbose, in_shell=True) + cmd % {"pack": package}], show_stdout=args.verbose, in_shell=True) logger.info('done.') -def install_activate(env_dir, opt): +def install_activate(env_dir, args): """ Install virtual environment activation script """ - if not is_WIN: - files = {'activate': ACTIVATE_SH, 'shim': SHIM} + if is_WIN: + files = { + 'activate.bat': ACTIVATE_BAT, + "deactivate.bat": DEACTIVATE_BAT, + "Activate.ps1": ACTIVATE_PS1 + } + bin_dir = join(env_dir, 'Scripts') + shim_node = join(bin_dir, "node.exe") + shim_nodejs = join(bin_dir, "nodejs.exe") else: - files = {'activate.bat': ACTIVATE_BAT} - if opt.node == "system": + files = { + 'activate': ACTIVATE_SH, + 'activate.fish': ACTIVATE_FISH, + 'shim': SHIM + } + bin_dir = join(env_dir, 'bin') + shim_node = join(bin_dir, "node") + shim_nodejs = join(bin_dir, "nodejs") + if is_CYGWIN: + mkdir(bin_dir) + + if args.node == "system": files["node"] = SHIM - bin_dir = join(env_dir, 'bin') + mod_dir = join('lib', 'node_modules') - prompt = opt.prompt or '(%s)' % os.path.basename(os.path.abspath(env_dir)) + prompt = args.prompt or '(%s)' % os.path.basename(os.path.abspath(env_dir)) - shim_node = join(bin_dir, "node") - shim_nodejs = join(bin_dir, "nodejs") - if opt.node == "system": - env = os.environ.copy() - env.update({'PATH': remove_env_bin_from_path(env['PATH'], bin_dir)}) + if args.node == "system": + path_var = remove_env_bin_from_path(os.environ['PATH'], bin_dir) for candidate in ("nodejs", "node"): - which_node_output, _ = subprocess.Popen( - ["which", candidate], - stdout=subprocess.PIPE, env=env).communicate() - shim_node = clear_output(which_node_output) - if shim_node: + shim_node = shutil.which(candidate, path=path_var) + if shim_node is not None: break assert shim_node, "Did not find nodejs or node system executable" @@ -743,34 +954,65 @@ def install_activate(env_dir, opt): content = content.replace('__SHIM_NODE__', shim_node) content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) content = content.replace('__MOD_NAME__', mod_dir) + if is_CYGWIN: + _, cyg_bin_dir = callit( + ['cygpath', '-w', os.path.abspath(bin_dir)], + show_stdout=False, in_shell=False) + content = content.replace('__NPM_CONFIG_PREFIX__', cyg_bin_dir[0]) + else: + content = content.replace('__NPM_CONFIG_PREFIX__', + '$NODE_VIRTUAL_ENV') # if we call in the same environment: # $ nodeenv -p --prebuilt # $ nodeenv -p --node=system # we should get `bin/node` not as binary+string. - # `bin/activate` should be appended if we inside + # `bin/activate` should be appended if we're inside # existing python's virtual environment - need_append = 0 if name in ('node', 'shim') else opt.python_virtualenv + need_append = False + if args.python_virtualenv: + disable_prompt = DISABLE_PROMPT.get(name, '') + enable_prompt = ENABLE_PROMPT.get(name, '') + content = disable_prompt + content + enable_prompt + need_append = bool(disable_prompt) writefile(file_path, content, append=need_append) if not os.path.exists(shim_nodejs): - if getattr(os, "symlink", None): - # ^ there is no os.symlink on Windows Python 2.x + if is_WIN: + try: + callit(['mklink', shim_nodejs, 'node.exe'], True, True) + except OSError: + logger.error('Error: Failed to create nodejs.exe link') + else: os.symlink("node", shim_nodejs) -def create_environment(env_dir, opt): +def set_predeactivate_hook(env_dir): + if is_WIN: + # Windows: create predeactivate.bat for CMD and + # predeactivate.ps1 for PowerShell + with open(join(env_dir, 'Scripts', 'predeactivate.bat'), 'a') as hook: + hook.write(PREDEACTIVATE_BAT) + with open(join(env_dir, 'Scripts', 'predeactivate.ps1'), 'a') as hook: + hook.write(PREDEACTIVATE_PS1) + else: + # Unix: create predeactivate for bash/sh + with open(join(env_dir, 'bin', 'predeactivate'), 'a') as hook: + hook.write(PREDEACTIVATE_SH) + + +def create_environment(env_dir, args): """ Creates a new environment in ``env_dir``. """ - if os.path.exists(env_dir) and not opt.python_virtualenv: + if os.path.exists(env_dir) and not args.python_virtualenv: logger.info(' * Environment already exists: %s', env_dir) - if not opt.force: + if not args.force: sys.exit(2) src_dir = to_utf8(abspath(join(env_dir, 'src'))) mkdir(src_dir) - if opt.node != "system": - install_node(env_dir, src_dir, opt) + if args.node != "system": + install_node(env_dir, src_dir, args) else: mkdir(join(env_dir, 'bin')) mkdir(join(env_dir, 'lib')) @@ -778,68 +1020,26 @@ def create_environment(env_dir, opt): # activate script install must be # before npm install, npm use activate # for install - install_activate(env_dir, opt) - if node_version_from_opt(opt) < parse_version("0.6.3") or opt.with_npm: - install_npm(env_dir, src_dir, opt) - if opt.requirements: - install_packages(env_dir, opt) + install_activate(env_dir, args) + if node_version_from_args(args) < (0, 6, 3) or args.with_npm: + instfunc = install_npm_win if is_WIN or is_CYGWIN else install_npm + instfunc(env_dir, src_dir, args) + if args.requirements: + install_packages(env_dir, args) + if args.python_virtualenv: + set_predeactivate_hook(env_dir) # Cleanup - if opt.clean_src: - callit(['rm -rf', pipes.quote(src_dir)], opt.verbose, True, env_dir) - - -class GetsAHrefs(HTMLParser): - def __init__(self): - # Old style class in py2 :( - HTMLParser.__init__(self) - self.hrefs = [] - - def handle_starttag(self, tag, attrs): - if tag == 'a': - self.hrefs.append(dict(attrs).get('href', '')) - -VERSION_RE = re.compile('\d+\.\d+\.\d+') + if args.clean_src: + shutil.rmtree(src_dir) -def _py2_cmp(a, b): - # -1 = a < b, 0 = eq, 1 = a > b - return (a > b) - (a < b) - - -def compare_versions(version, other_version): - version_tuple = version.split('.') - other_tuple = other_version.split('.') - - version_length = len(version_tuple) - other_length = len(other_tuple) - version_dots = min(version_length, other_length) - - for i in range(version_dots): - a = int(version_tuple[i]) - b = int(other_tuple[i]) - cmp_value = _py2_cmp(a, b) - if cmp_value != 0: - return cmp_value - - return _py2_cmp(version_length, other_length) +def _get_versions_json(): + response = urlopen('%s/index.json' % src_base_url) + return json.loads(response.read().decode('UTF-8')) def get_node_versions(): - response = urlopen('https://{0}/dist'.format(src_domain)) - href_parser = GetsAHrefs() - href_parser.feed(response.read().decode('UTF-8')) - - versions = set( - VERSION_RE.search(href).group() - for href in href_parser.hrefs - if VERSION_RE.search(href) - ) - if is_PY3: - key_compare = cmp_to_key(compare_versions) - versions = sorted(versions, key=key_compare) - else: - versions = sorted(versions, cmp=compare_versions) - return versions + return [dct['version'].lstrip('v') for dct in _get_versions_json()][::-1] def print_node_versions(): @@ -854,53 +1054,60 @@ def print_node_versions(): logger.info('\t'.join(chunk)) +def _get_last_node_version(lts=False): + """ + Return last node.js version matching the filter + """ + print({"x86": is_x86_64_musl(), "risc": is_riscv64(), "lts": lts}) + + def version_filter(v): + if lts and not v['lts']: + return False + + if is_x86_64_musl() and "linux-x64-musl" not in v['files']: + return False + elif is_riscv64() and "linux-riscv64" not in v['files']: + return False + + return True + + return next((v['version'].lstrip('v') + for v in _get_versions_json() if version_filter(v)), None) + + def get_last_stable_node_version(): """ Return last stable node.js version """ - response = urlopen('https://%s/dist/latest/' % (src_domain)) - href_parser = GetsAHrefs() - href_parser.feed(response.read().decode('UTF-8')) - - links = [] - pattern = re.compile(r'''%s-v([0-9]+)\.([0-9]+)\.([0-9]+)\.tar\.gz''' % ( - get_binary_prefix())) - - for href in href_parser.hrefs: - match = pattern.match(href) - if match: - version = u'.'.join(match.groups()) - major, minor, revision = map(int, match.groups()) - links.append((version, major, minor, revision)) - break + return _get_last_node_version() + - return links[-1][0] +def get_last_lts_node_version(): + """ + Return the last node.js version marked as LTS + """ + return _get_last_node_version(lts=True) -def get_env_dir(opt, args): - if opt.python_virtualenv: +def get_env_dir(args): + if args.python_virtualenv: if hasattr(sys, 'real_prefix'): res = sys.prefix elif hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix: res = sys.prefix + elif 'CONDA_PREFIX' in os.environ: + res = sys.prefix + elif 'VIRTUAL_ENV' in os.environ: + res = os.environ['VIRTUAL_ENV'] else: logger.error('No python virtualenv is available') sys.exit(2) else: - res = args[0] + res = args.env_dir return to_utf8(res) -def is_installed(name): - try: - devnull = open(os.devnull) - subprocess.Popen([name], stdout=devnull, stderr=devnull) - except OSError as e: - if e.errno == os.errno.ENOENT: - return False - return True - - +# noinspection PyProtectedMember def main(): """ Entry point @@ -910,98 +1117,195 @@ def main(): Config._dump() return - opt, args = parse_args(check=False) - Config._load(opt.config_file, opt.verbose) + args = parse_args(check=False) + # noinspection PyProtectedMember + Config._load(args.config_file, args.verbose) + + args = parse_args() - opt, args = parse_args() + if args.node.lower() == 'system' and is_WIN: + logger.error('Installing system node.js on win32 is not supported!') + exit(1) - if opt.io: - global src_domain - src_domain = "iojs.org" + global src_base_url + global ignore_ssl_certs - if not opt.node or opt.node.lower() == "latest": - opt.node = get_last_stable_node_version() + ignore_ssl_certs = args.ignore_ssl_certs - if opt.list: + src_domain = None + if args.mirror: + if '://' in args.mirror: + src_base_url = args.mirror + else: + src_domain = args.mirror + # use unofficial builds only if musl and no explicitly chosen mirror + elif is_x86_64_musl() or is_riscv64(): + src_domain = 'unofficial-builds.nodejs.org' + else: + src_domain = 'nodejs.org' + if src_base_url is None: + src_base_url = 'https://%s/download/release' % src_domain + + if not args.node or args.node.lower() == 'latest': + args.node = get_last_stable_node_version() + elif args.node.lower() == 'lts': + args.node = get_last_lts_node_version() + + if args.list: print_node_versions() - elif opt.update: - env_dir = get_env_dir(opt, args) - install_packages(env_dir, opt) + elif args.update: + env_dir = get_env_dir(args) + install_packages(env_dir, args) else: - env_dir = get_env_dir(opt, args) - create_environment(env_dir, opt) + env_dir = get_env_dir(args) + create_environment(env_dir, args) # --------------------------------------------------------- # Shell scripts content -DISABLE_PROMPT = """ +DISABLE_PROMPT = { + 'activate': """ # disable nodeenv's prompt # (prompt already changed by original virtualenv's script) # https://github.com/ekalinin/nodeenv/issues/26 NODE_VIRTUAL_ENV_DISABLE_PROMPT=1 -""" +""", + 'activate.fish': """ +# disable nodeenv's prompt +# (prompt already changed by original virtualenv's script) +# https://github.com/ekalinin/nodeenv/issues/26 +set NODE_VIRTUAL_ENV_DISABLE_PROMPT 1 +""", +} -ENABLE_PROMPT = """ +ENABLE_PROMPT = { + 'activate': """ unset NODE_VIRTUAL_ENV_DISABLE_PROMPT -""" +""", + 'activate.fish': """ +set -e NODE_VIRTUAL_ENV_DISABLE_PROMPT +""", +} -SHIM = """#!/usr/bin/env bash -export NODE_PATH=__NODE_VIRTUAL_ENV__/lib/node_modules -export NPM_CONFIG_PREFIX=__NODE_VIRTUAL_ENV__ -export npm_config_prefix=__NODE_VIRTUAL_ENV__ -exec __SHIM_NODE__ "$@" +SHIM = """#!/usr/bin/env sh +export NODE_PATH='__NODE_VIRTUAL_ENV__/lib/node_modules' +export NPM_CONFIG_PREFIX='__NODE_VIRTUAL_ENV__' +export npm_config_prefix='__NODE_VIRTUAL_ENV__' +exec '__SHIM_NODE__' "$@" """ -# virtualenv script adapted for node environment -ACTIVATE_BAT = """\ +ACTIVATE_BAT = r""" @echo off -set NODE_VIRTUAL_ENV="__NODE_VIRTUAL_ENV__" - +set "NODE_VIRTUAL_ENV=__NODE_VIRTUAL_ENV__" +if not defined PROMPT ( + set "PROMPT=$P$G" +) if defined _OLD_VIRTUAL_PROMPT ( set "PROMPT=%_OLD_VIRTUAL_PROMPT%" -) else ( - if not defined PROMPT ( - set "PROMPT=$P$G" - ) - set "_OLD_VIRTUAL_PROMPT=%PROMPT%" ) +if defined _OLD_VIRTUAL_NODE_PATH ( + set "NODE_PATH=%_OLD_VIRTUAL_NODE_PATH%" +) +set "_OLD_VIRTUAL_PROMPT=%PROMPT%" set "PROMPT=__NODE_VIRTUAL_PROMPT__ %PROMPT%" - -if not defined _OLD_VIRTUAL_NODE_PATH ( +if defined NODE_PATH ( set "_OLD_VIRTUAL_NODE_PATH=%NODE_PATH%" + set NODE_PATH= ) -set NODE_PATH=__NODE_VIRTUAL_ENV__\\lib\\node_modules - -if defined _OLD_VIRTUAL_NODE_PATH ( - set "PATH=%_OLD_VIRTUAL_NODE_PATH%" +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" ) else ( - set "_OLD_VIRTUAL_NODE_PATH=%PATH%" + set "_OLD_VIRTUAL_PATH=%PATH%" ) -set "PATH=%NODE_VIRTUAL_ENV%\\bin;%PATH%" +set "PATH=%NODE_VIRTUAL_ENV%\Scripts;%PATH%" +:END +""" + +DEACTIVATE_BAT = """\ +@echo off +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= +if defined _OLD_VIRTUAL_NODE_PATH ( + set "NODE_PATH=%_OLD_VIRTUAL_NODE_PATH%" + set _OLD_VIRTUAL_NODE_PATH= +) +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) +set _OLD_VIRTUAL_PATH= +set NODE_VIRTUAL_ENV= :END +""" + +ACTIVATE_PS1 = r""" +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + if (Test-Path function:_OLD_VIRTUAL_PROMPT) { + copy-item function:_OLD_VIRTUAL_PROMPT function:prompt + remove-item function:_OLD_VIRTUAL_PROMPT + } + if (Test-Path env:_OLD_VIRTUAL_NODE_PATH) { + copy-item env:_OLD_VIRTUAL_NODE_PATH env:NODE_PATH + remove-item env:_OLD_VIRTUAL_NODE_PATH + } + if (Test-Path env:_OLD_VIRTUAL_PATH) { + copy-item env:_OLD_VIRTUAL_PATH env:PATH + remove-item env:_OLD_VIRTUAL_PATH + } + if (Test-Path env:NODE_VIRTUAL_ENV) { + remove-item env:NODE_VIRTUAL_ENV + } + if (!$NonDestructive) { + # Self destruct! + remove-item function:deactivate + } +} + +deactivate -nondestructive +$env:NODE_VIRTUAL_ENV="__NODE_VIRTUAL_ENV__" + +# Set the prompt to include the env name +# Make sure _OLD_VIRTUAL_PROMPT is global +function global:_OLD_VIRTUAL_PROMPT {""} +copy-item function:prompt function:_OLD_VIRTUAL_PROMPT +function global:prompt { + Write-Host -NoNewline -ForegroundColor Green '__NODE_VIRTUAL_PROMPT__ ' + _OLD_VIRTUAL_PROMPT +} + +# Clear NODE_PATH +if (Test-Path env:NODE_PATH) { + copy-item env:NODE_PATH env:_OLD_VIRTUAL_NODE_PATH + remove-item env:NODE_PATH +} +# Add the venv to the PATH +copy-item env:PATH env:_OLD_VIRTUAL_PATH +$env:PATH = "$env:NODE_VIRTUAL_ENV\Scripts;$env:PATH" """ -ACTIVATE_SH = """ +ACTIVATE_SH = r""" -# This file must be used with "source bin/activate" *from bash* +# This file must be used with "source bin/activate" *from sh* # you cannot run it directly deactivate_node () { # reset old environment variables - if [ -n "$_OLD_NODE_VIRTUAL_PATH" ] ; then - PATH="$_OLD_NODE_VIRTUAL_PATH" + if [ -n "${_OLD_NODE_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_NODE_VIRTUAL_PATH:-}" export PATH unset _OLD_NODE_VIRTUAL_PATH - NODE_PATH="$_OLD_NODE_PATH" + NODE_PATH="${_OLD_NODE_PATH:-}" export NODE_PATH unset _OLD_NODE_PATH - NPM_CONFIG_PREFIX="$_OLD_NPM_CONFIG_PREFIX" - npm_config_prefix="$_OLD_npm_config_prefix" + NPM_CONFIG_PREFIX="${_OLD_NPM_CONFIG_PREFIX:-}" + npm_config_prefix="${_OLD_npm_config_prefix:-}" export NPM_CONFIG_PREFIX export npm_config_prefix unset _OLD_NPM_CONFIG_PREFIX @@ -1011,18 +1315,18 @@ def main(): # This should detect bash and zsh, which have a hash command that must # be called to get it to forget past commands. Without forgetting # past commands the $PATH changes we made may not be respected - if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then hash -r fi - if [ -n "$_OLD_NODE_VIRTUAL_PS1" ] ; then - PS1="$_OLD_NODE_VIRTUAL_PS1" + if [ -n "${_OLD_NODE_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_NODE_VIRTUAL_PS1:-}" export PS1 unset _OLD_NODE_VIRTUAL_PS1 fi unset NODE_VIRTUAL_ENV - if [ ! "$1" = "nondestructive" ] ; then + if [ ! "${1:-}" = "nondestructive" ] ; then # Self destruct! unset -f deactivate_node fi @@ -1036,7 +1340,7 @@ def main(): cut -d ' ' -f 1 | grep -v npm` else local npmls="npm ls -g" - if [ "$1" = "-l" ]; then + if [ "${1:-}" = "-l" ]; then npmls="npm ls" shift fi @@ -1051,16 +1355,26 @@ def main(): fi } -# unset irrelavent variables + +# Detect calling this file as a script +case $0 in + */bin/activate ) + echo "Do not call $0 directly. Instead source it with \`source $0\`." + exit 1 + ;; +esac + + +# unset irrelevant variables deactivate_node nondestructive # find the directory of this script # http://stackoverflow.com/a/246128 -if [ "${BASH_SOURCE}" ] ; then +if [ "${BASH_SOURCE:-}" ] ; then SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done - DIR="$( command cd -P "$( dirname "$SOURCE" )" && pwd )" + DIR="$( command cd -P "$( dirname "$SOURCE" )" > /dev/null && pwd )" NODE_VIRTUAL_ENV="$(dirname "$DIR")" else @@ -1073,31 +1387,31 @@ def main(): export NODE_VIRTUAL_ENV _OLD_NODE_VIRTUAL_PATH="$PATH" -PATH="$NODE_VIRTUAL_ENV/__BIN_NAME__:$PATH" +PATH="$NODE_VIRTUAL_ENV/lib/node_modules/.bin:$NODE_VIRTUAL_ENV/__BIN_NAME__:$PATH" export PATH -_OLD_NODE_PATH="$NODE_PATH" +_OLD_NODE_PATH="${NODE_PATH:-}" NODE_PATH="$NODE_VIRTUAL_ENV/__MOD_NAME__" export NODE_PATH -_OLD_NPM_CONFIG_PREFIX="$NPM_CONFIG_PREFIX" -_OLD_npm_config_prefix="$npm_config_prefix" -NPM_CONFIG_PREFIX="$NODE_VIRTUAL_ENV" -npm_config_prefix="$NODE_VIRTUAL_ENV" +_OLD_NPM_CONFIG_PREFIX="${NPM_CONFIG_PREFIX:-}" +_OLD_npm_config_prefix="${npm_config_prefix:-}" +NPM_CONFIG_PREFIX="__NPM_CONFIG_PREFIX__" +npm_config_prefix="__NPM_CONFIG_PREFIX__" export NPM_CONFIG_PREFIX export npm_config_prefix -if [ -z "$NODE_VIRTUAL_ENV_DISABLE_PROMPT" ] ; then - _OLD_NODE_VIRTUAL_PS1="$PS1" +if [ -z "${NODE_VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_NODE_VIRTUAL_PS1="${PS1:-}" if [ "x__NODE_VIRTUAL_PROMPT__" != x ] ; then - PS1="__NODE_VIRTUAL_PROMPT__$PS1" + PS1="__NODE_VIRTUAL_PROMPT__ ${PS1:-}" else if [ "`basename \"$NODE_VIRTUAL_ENV\"`" = "__" ] ; then # special case for Aspen magic directories # see http://www.zetadev.com/software/aspen/ - PS1="[`basename \`dirname \"$NODE_VIRTUAL_ENV\"\``] $PS1" + PS1="[`basename \`dirname \"$NODE_VIRTUAL_ENV\"\``] ${PS1:-}" else - PS1="(`basename \"$NODE_VIRTUAL_ENV\"`)$PS1" + PS1="(`basename \"$NODE_VIRTUAL_ENV\"`) ${PS1:-}" fi fi export PS1 @@ -1106,10 +1420,185 @@ def main(): # This should detect bash and zsh, which have a hash command that must # be called to get it to forget past commands. Without forgetting # past commands the $PATH changes we made may not be respected -if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then hash -r fi """ + +ACTIVATE_FISH = """ + +# This file must be used with "source bin/activate.fish" *from fish* +# you cannot run it directly + +function deactivate_node -d 'Exit nodeenv and return to normal environment.' + # reset old environment variables + if test -n "$_OLD_NODE_VIRTUAL_PATH" + set -gx PATH $_OLD_NODE_VIRTUAL_PATH + set -e _OLD_NODE_VIRTUAL_PATH + end + + if test -n "$_OLD_NODE_PATH" + set -gx NODE_PATH $_OLD_NODE_PATH + set -e _OLD_NODE_PATH + else + set -e NODE_PATH + end + + if test -n "$_OLD_NPM_CONFIG_PREFIX" + set -gx NPM_CONFIG_PREFIX $_OLD_NPM_CONFIG_PREFIX + set -e _OLD_NPM_CONFIG_PREFIX + else + set -e NPM_CONFIG_PREFIX + end + + if test -n "$_OLD_npm_config_prefix" + set -gx npm_config_prefix $_OLD_npm_config_prefix + set -e _OLD_npm_config_prefix + else + set -e npm_config_prefix + end + + if test -n "$_OLD_NODE_FISH_PROMPT_OVERRIDE" + # Set an empty local `$fish_function_path` to allow the removal of + # `fish_prompt` using `functions -e`. + set -l fish_function_path + + # Prevents error when using nested fish instances + if functions -q _node_old_fish_prompt + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _node_old_fish_prompt fish_prompt + functions -e _node_old_fish_prompt + end + set -e _OLD_NODE_FISH_PROMPT_OVERRIDE + end + + set -e NODE_VIRTUAL_ENV + + if test (count $argv) = 0 -o "$argv[1]" != "nondestructive" + # Self destruct! + functions -e deactivate_node + end +end + +function freeze -d 'Show a list of installed packages - like `pip freeze`' + set -l NPM_VER (npm -v | cut -d '.' -f 1) + set -l RE "[a-zA-Z0-9\\.\\-]+@[0-9]+\\.[0-9]+\\.[0-9]+([\\+\\-][a-zA-Z0-9\\.\\-]+)*" + + if test "$NPM_VER" = "0" + set -g NPM_LIST (npm list installed active >/dev/null ^/dev/null | \ + cut -d ' ' -f 1 | grep -v npm) + else + set -l NPM_LS "npm ls -g" + if test (count $argv) -gt 0 -a "$argv[1]" = "-l" + set NPM_LS "npm ls" + set -e argv[1] + end + set -l NPM_LIST (eval $NPM_LS | grep -E '^.{4}\\w{1}' | \ + grep -o -E "$re" | \ + grep -v npm) + end + + if test (count $argv) = 0 + echo $NPM_LIST + else + echo $NPM_LIST > $argv[1] + end +end + +# unset irrelevant variables +deactivate_node nondestructive + +# find the directory of this script +begin + set -l SOURCE (status filename) + while test -L "$SOURCE" + set SOURCE (readlink "$SOURCE") + end + set -l DIR (dirname (realpath "$SOURCE")) + + # NODE_VIRTUAL_ENV is the parent of the directory where this script is + set -gx NODE_VIRTUAL_ENV (dirname "$DIR") +end + +set -gx _OLD_NODE_VIRTUAL_PATH $PATH +# The node_modules/.bin path doesn't exists and it will print a warning, and +# that's why we redirect stderr to /dev/null :) +set -gx PATH "$NODE_VIRTUAL_ENV/lib/node_modules/.bin" "$NODE_VIRTUAL_ENV/__BIN_NAME__" $PATH ^/dev/null + +if set -q NODE_PATH + set -gx _OLD_NODE_PATH $NODE_PATH + set -gx NODE_PATH "$NODE_VIRTUAL_ENV/__MOD_NAME__" $NODE_PATH +else + set -gx NODE_PATH "$NODE_VIRTUAL_ENV/__MOD_NAME__" +end + +if set -q NPM_CONFIG_PREFIX + set -gx _OLD_NPM_CONFIG_PREFIX $NPM_CONFIG_PREFIX +end +set -gx NPM_CONFIG_PREFIX "__NPM_CONFIG_PREFIX__" + +if set -q npm_config_prefix + set -gx _OLD_npm_config_prefix $npm_config_prefix +end +set -gx npm_config_prefix "__NPM_CONFIG_PREFIX__" + +if test -z "$NODE_VIRTUAL_ENV_DISABLE_PROMPT" + # Copy the current `fish_prompt` function as `_node_old_fish_prompt`. + functions -c fish_prompt _node_old_fish_prompt + + function fish_prompt + # Save the current $status, for fish_prompts that display it. + set -l old_status $status + + # Prompt override provided? + # If not, just prepend the environment name. + if test -n "__NODE_VIRTUAL_PROMPT__" + printf '%s%s ' "__NODE_VIRTUAL_PROMPT__" (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$NODE_VIRTUAL_ENV") + end + + # Restore the original $status + echo "exit $old_status" | source + _node_old_fish_prompt + end + + set -gx _OLD_NODE_FISH_PROMPT_OVERRIDE "$NODE_VIRTUAL_ENV" +end +""" # noqa: E501 + +PREDEACTIVATE_SH = """ +if type -p deactivate_node > /dev/null; then deactivate_node;fi +""" + +PREDEACTIVATE_BAT = """\ +@echo off +REM Deactivate Node.js environment +if exist "%NODE_VIRTUAL_ENV%\\Scripts\\deactivate.bat" ( + call "%NODE_VIRTUAL_ENV%\\Scripts\\deactivate.bat" +) +""" + +PREDEACTIVATE_PS1 = """\ +# Deactivate Node.js environment +if (Get-Command deactivate -ErrorAction SilentlyContinue) { + deactivate +} +""" + +CYGWIN_NODE = """#!/bin/sh + +if [ -r "$1" ]; then + SCRIPT_PATH=$(cygpath -w "$1") + shift + set - $SCRIPT_PATH $@ + unset SCRIPT_PATH +fi + +exec $(dirname "$0")/node.exe "$@" +""" + if __name__ == '__main__': main() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8fd8d67 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "setuptools-scm"] +build-backend = "setuptools.build_meta" diff --git a/requirements-dev.txt b/requirements-dev.txt index 3e5c34e..aa38656 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,5 +2,9 @@ coverage flake8 -mock +mock; python_version < '3.3' pytest +setuptools +tox +twine +wheel diff --git a/setup.py b/setup.py index 8e0bdc9..2977546 100644 --- a/setup.py +++ b/setup.py @@ -7,10 +7,14 @@ """ import codecs import os +import sys -from nodeenv import nodeenv_version from setuptools import setup +sys.path.insert(0, '.') + +from nodeenv import nodeenv_version # noqa: E402 + def read_file(file_name): return codecs.open( @@ -21,6 +25,7 @@ def read_file(file_name): encoding='utf-8', ).read() + ldesc = read_file('README.rst') ldesc += "\n\n" + read_file('CHANGES') @@ -32,6 +37,9 @@ def read_file(file_name): author='Eugene Kalinin', author_email='e.v.kalinin@gmail.com', install_requires=[], + python_requires=( + ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" + ), description="Node.js virtual environment builder", long_description=ldesc, py_modules=['nodeenv'], @@ -41,11 +49,20 @@ def read_file(file_name): zip_safe=False, platforms='any', classifiers=[ - 'Development Status :: 4 - Beta', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' - ] + ], + options={'bdist_wheel': {'universal': True}}, ) diff --git a/tests/iojs.htm b/tests/iojs.htm deleted file mode 100644 index 2dfdf79..0000000 --- a/tests/iojs.htm +++ /dev/null @@ -1,24 +0,0 @@ - -Index of /dist/latest/ - -

Index of /dist/latest/


../
-doc/                                               14-Jan-2015 04:43                   -
-win-x64/                                           14-Jan-2015 04:48                   -
-win-x86/                                           14-Jan-2015 04:45                   -
-SHASUMS256.txt                                     14-Jan-2015 05:04                1428
-SHASUMS256.txt.asc                                 14-Jan-2015 05:04                1948
-SHASUMS256.txt.gpg                                 14-Jan-2015 05:04                2141
-iojs-v1.0.1-darwin-x64.tar.gz                      14-Jan-2015 04:38             6463647
-iojs-v1.0.1-linux-armv7l.tar.gz                    14-Jan-2015 04:59             7275326
-iojs-v1.0.1-linux-armv7l.tar.xz                    14-Jan-2015 04:59             4848364
-iojs-v1.0.1-linux-x64.tar.gz                       14-Jan-2015 04:42             7782045
-iojs-v1.0.1-linux-x64.tar.xz                       14-Jan-2015 04:42             5331880
-iojs-v1.0.1-linux-x86.tar.gz                       14-Jan-2015 04:43             7584510
-iojs-v1.0.1-linux-x86.tar.xz                       14-Jan-2015 04:43             5184944
-iojs-v1.0.1-x64.msi                                14-Jan-2015 04:49             7313864
-iojs-v1.0.1-x86.msi                                14-Jan-2015 04:46             6707654
-iojs-v1.0.1.pkg                                    14-Jan-2015 04:41             8608836
-iojs-v1.0.1.tar.gz                                 14-Jan-2015 04:43            19056750
-iojs-v1.0.1.tar.xz                                 14-Jan-2015 04:43            11892124
-

- diff --git a/tests/iojs_dist.htm b/tests/iojs_dist.htm deleted file mode 100644 index 40e1ce3..0000000 --- a/tests/iojs_dist.htm +++ /dev/null @@ -1,15 +0,0 @@ - -Index of /dist/ - -

Index of /dist/


../
-latest/                                            03-Feb-2015 23:30                   -
-v1.0.0/                                            14-Jan-2015 03:59                   -
-v1.0.1/                                            14-Jan-2015 05:03                   -
-v1.0.2/                                            16-Jan-2015 05:37                   -
-v1.0.3/                                            20-Jan-2015 07:54                   -
-v1.0.4/                                            24-Jan-2015 12:13                   -
-v1.1.0/                                            03-Feb-2015 23:30                   -
-index.json                                         03-Feb-2015 23:30                1646
-index.tab                                          03-Feb-2015 23:30                1039
-

- diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index f13b219..818c182 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -1,73 +1,29 @@ from __future__ import absolute_import from __future__ import unicode_literals -import io +import sys +if sys.version_info < (3, 3): + from pipes import quote as _quote +else: + from shlex import quote as _quote import os.path import subprocess +import sys +import sysconfig +import platform -import mock +try: + from unittest import mock +except ImportError: + import mock import pytest import nodeenv - +from nodeenv import IncompleteRead HERE = os.path.abspath(os.path.dirname(__file__)) -def test_compare_versions(): - assert nodeenv.compare_versions('1', '2') == -1 - assert nodeenv.compare_versions('1', '2') == -1 - assert nodeenv.compare_versions('0.1', '0.2') == -1 - assert nodeenv.compare_versions('0.9', '0.10') == -1 - assert nodeenv.compare_versions('0.2', '0.2.1') == -1 - assert nodeenv.compare_versions('0.2.1', '0.2.10') == -1 - assert nodeenv.compare_versions('0.2.9', '0.2.10') == -1 - assert nodeenv.compare_versions('0.2.1', '0.3') == -1 - - -def test_gets_a_hrefs_trivial(): - parser = nodeenv.GetsAHrefs() - parser.feed('') - assert parser.hrefs == [] - - -def test_gets_a_hrefs_nodejs_org(): - # Retrieved 2015-01-15 - contents = io.open(os.path.join(HERE, 'nodejs.htm')).read() - parser = nodeenv.GetsAHrefs() - parser.feed(contents) - # Smoke test - assert parser.hrefs == [ - '../', 'docs/', 'x64/', 'SHASUMS.txt', 'SHASUMS.txt.asc', - 'SHASUMS.txt.gpg', 'SHASUMS256.txt', 'SHASUMS256.txt.asc', - 'SHASUMS256.txt.gpg', 'node-v0.10.35-darwin-x64.tar.gz', - 'node-v0.10.35-darwin-x86.tar.gz', 'node-v0.10.35-linux-x64.tar.gz', - 'node-v0.10.35-linux-x86.tar.gz', 'node-v0.10.35-sunos-x64.tar.gz', - 'node-v0.10.35-sunos-x86.tar.gz', 'node-v0.10.35-x86.msi', - 'node-v0.10.35.pkg', 'node-v0.10.35.tar.gz', 'node.exe', - 'node.exp', 'node.lib', 'node.pdb', 'openssl-cli.exe', - 'openssl-cli.pdb', - ] - - -def test_gets_a_hrefs_iojs_org(): - # Retrieved 2015-01-15 - contents = io.open(os.path.join(HERE, 'iojs.htm')).read() - parser = nodeenv.GetsAHrefs() - parser.feed(contents) - # Smoke test - assert parser.hrefs == [ - '../', 'doc/', 'win-x64/', 'win-x86/', 'SHASUMS256.txt', - 'SHASUMS256.txt.asc', 'SHASUMS256.txt.gpg', - 'iojs-v1.0.1-darwin-x64.tar.gz', 'iojs-v1.0.1-linux-armv7l.tar.gz', - 'iojs-v1.0.1-linux-armv7l.tar.xz', 'iojs-v1.0.1-linux-x64.tar.gz', - 'iojs-v1.0.1-linux-x64.tar.xz', 'iojs-v1.0.1-linux-x86.tar.gz', - 'iojs-v1.0.1-linux-x86.tar.xz', 'iojs-v1.0.1-x64.msi', - 'iojs-v1.0.1-x86.msi', 'iojs-v1.0.1.pkg', 'iojs-v1.0.1.tar.gz', - 'iojs-v1.0.1.tar.xz', - ] - - @pytest.mark.integration def test_smoke(tmpdir): nenv_path = tmpdir.join('nenv').strpath @@ -77,67 +33,1526 @@ def test_smoke(tmpdir): '-m', 'nodeenv', '--prebuilt', nenv_path, ]) assert os.path.exists(nenv_path) + activate = _quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ - 'sh', '-c', '. {0}/bin/activate && nodejs --version'.format(nenv_path), + 'sh', '-c', '. {} && node --version'.format(activate), ]) -@pytest.yield_fixture -def returns_iojs_dist(): - with io.open(os.path.join(HERE, 'iojs_dist.htm'), 'rb') as iojs_dist: - with mock.patch.object(nodeenv, 'urlopen', return_value=iojs_dist): - yield +@pytest.mark.integration +@pytest.mark.skipif(sys.platform == 'win32', reason='-n system is posix only') +def test_smoke_n_system_special_chars(tmpdir): + nenv_path = tmpdir.join('nenv (production env)').strpath + subprocess.check_call(( + 'coverage', 'run', '-p', + '-m', 'nodeenv', '-n', 'system', nenv_path, + )) + assert os.path.exists(nenv_path) + activate = _quote(os.path.join(nenv_path, 'bin', 'activate')) + subprocess.check_call([ + 'sh', '-c', '. {} && node --version'.format(activate), + ]) -@pytest.yield_fixture -def returns_nodejs_dist(): - with io.open(os.path.join(HERE, 'nodejs_dist.htm'), 'rb') as node_dist: - with mock.patch.object(nodeenv, 'urlopen', return_value=node_dist): +@pytest.fixture +def mock_index_json(): + # retrieved 2019-12-31 + with open(os.path.join(HERE, 'nodejs_index.json'), 'rb') as f: + with mock.patch.object(nodeenv, 'urlopen', return_value=f): yield -@pytest.yield_fixture +@pytest.fixture def cap_logging_info(): with mock.patch.object(nodeenv.logger, 'info') as mck: yield mck -def mck_to_out(mck): - return '\n'.join(call[0][0] for call in mck.call_args_list) +@pytest.fixture +def mock_host_platform(): + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False): + with mock.patch.object(nodeenv, 'is_riscv64', return_value=False): + yield -@pytest.mark.usefixtures('returns_iojs_dist') -def test_get_node_versions_iojs(): - versions = nodeenv.get_node_versions() - assert versions == ['1.0.0', '1.0.1', '1.0.2', '1.0.3', '1.0.4', '1.1.0'] +@pytest.fixture +def mock_riscv64_platform(): + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False): + with mock.patch.object(nodeenv, 'is_riscv64', return_value=True): + yield -@pytest.mark.usefixtures('returns_nodejs_dist') -def test_get_node_versions_nodejs(): - versions = nodeenv.get_node_versions() - # There's a lot of versions here, let's just do some sanity assertions - assert len(versions) == 227 - assert versions[0:3] == ['0.0.1', '0.0.2', '0.0.3'] - assert versions[-3:] == ['0.11.15', '0.11.16', '0.12.0'] +def mck_to_out(mck): + return '\n'.join(call[0][0] for call in mck.call_args_list) -@pytest.mark.usefixtures('returns_iojs_dist') -def test_print_node_versions_iojs(cap_logging_info): - nodeenv.print_node_versions() - printed = mck_to_out(cap_logging_info) - assert printed == '1.0.0\t1.0.1\t1.0.2\t1.0.3\t1.0.4\t1.1.0' +@pytest.mark.usefixtures('mock_index_json') +def test_get_node_versions(): + versions = nodeenv.get_node_versions() + # there are a lot of versions, just some sanity checks here + assert len(versions) == 485 + assert versions[:3] == ['0.1.14', '0.1.15', '0.1.16'] + assert versions[-3:] == ['13.3.0', '13.4.0', '13.5.0'] -@pytest.mark.usefixtures('returns_nodejs_dist') -def test_print_node_versions_node(cap_logging_info): +@pytest.mark.usefixtures('mock_index_json') +def test_print_node_versions(cap_logging_info): nodeenv.print_node_versions() printed = mck_to_out(cap_logging_info) - # There's a lot of output here, let's just assert a few things assert printed.startswith( - '0.0.1\t0.0.2\t0.0.3\t0.0.4\t0.0.5\t0.0.6\t0.1.0\t0.1.1\n' + '0.1.14\t0.1.15\t0.1.16\t0.1.17\t0.1.18\t0.1.19\t0.1.20\t0.1.21\n' ) - assert printed.endswith('\n0.11.15\t0.11.16\t0.12.0') + assert printed.endswith('\n13.1.0\t13.2.0\t13.3.0\t13.4.0\t13.5.0') tabs_per_line = [line.count('\t') for line in printed.splitlines()] # 8 items per line = 7 tabs - # The last line contains the remaning 3 items - assert tabs_per_line == [7] * 28 + [2] + # The last line contains the remaining 5 items + assert tabs_per_line == [7] * 60 + [4] + + +def test_predeactivate_hook(tmpdir): + # Throw error if the environment directory is not a string + with pytest.raises((TypeError, AttributeError)): + nodeenv.set_predeactivate_hook(1) + # Throw error if environment directory has no bin path + with pytest.raises((OSError, IOError)): + nodeenv.set_predeactivate_hook(tmpdir.strpath) + + if nodeenv.is_WIN: + tmpdir.mkdir('Scripts') + nodeenv.set_predeactivate_hook(tmpdir.strpath) + # Check BAT file + p_bat = tmpdir.join('Scripts').join('predeactivate.bat') + assert p_bat.exists() + content_bat = p_bat.read() + assert 'deactivate.bat' in content_bat + # Check PS1 file + p_ps1 = tmpdir.join('Scripts').join('predeactivate.ps1') + assert p_ps1.exists() + assert 'deactivate' in p_ps1.read() + else: + tmpdir.mkdir('bin') + nodeenv.set_predeactivate_hook(tmpdir.strpath) + p = tmpdir.join('bin').join('predeactivate') + assert 'deactivate_node' in p.read() + + +def test_mirror_option(): + urls = [('https://npm.taobao.org/mirrors/node', + 'https://npm.taobao.org/mirrors/node/index.json'), + ('npm.some-mirror.com', + 'https://npm.some-mirror.com/download/release/index.json'), + ('', + 'https://nodejs.org/download/release/index.json')] + sys_type = sysconfig.get_config_var('HOST_GNU_TYPE') + musl_type = ['x86_64-pc-linux-musl', 'x86_64-unknown-linux-musl'] + # Check if running on musl system and delete last mirror if it is + if sys_type in musl_type: + urls.pop() + elif platform.machine() == "riscv64": + urls.pop() + with open(os.path.join(HERE, 'nodejs_index.json'), 'rb') as f: + def rewind(_): + f.seek(0) + return f + argv = [__file__, '--list'] + for mirror, url in urls: + if mirror: + test_argv = argv + ['--mirror=' + mirror] + else: + test_argv = argv + with mock.patch.object(sys, 'argv', test_argv), \ + mock.patch.object(nodeenv.logger, 'info') as mock_logger, \ + mock.patch.object(nodeenv, 'urlopen', + side_effect=rewind) as mock_urlopen: + nodeenv.src_base_url = None + nodeenv.main() + mock_urlopen.assert_called_with(url) + mock_logger.assert_called() + + +@pytest.mark.usefixtures('mock_index_json', 'mock_host_platform') +def test_get_latest_node_version(): + assert nodeenv.get_last_stable_node_version() == '13.5.0' + + +@pytest.mark.usefixtures('mock_index_json', 'mock_host_platform') +def test_get_lts_node_version(): + assert nodeenv.get_last_lts_node_version() == '12.14.0' + + +@pytest.mark.usefixtures('mock_index_json', 'mock_riscv64_platform') +def test_get_latest_node_version_riscv64(): + assert nodeenv.get_last_stable_node_version() == '13.4.0' + + +@pytest.mark.usefixtures('mock_index_json', 'mock_riscv64_platform') +def test_get_lts_node_version_riscv64(): + assert nodeenv.get_last_lts_node_version() == '12.13.1' + + +def test__download_node_file(): + with mock.patch.object(nodeenv, 'urlopen') as m_urlopen: + m_urlopen.side_effect = IncompleteRead("dummy") + with pytest.raises(IncompleteRead): + nodeenv._download_node_file( + "https://dummy/nodejs.tar.gz", + n_attempt=5 + ) + assert m_urlopen.call_count == 5 + + +def test_parse_version(): + assert nodeenv.parse_version("v21.7") == (21, 7) + assert nodeenv.parse_version("v21.7.3") == (21, 7, 3) + assert nodeenv.parse_version("v21.7.3+0-b20240228T18452699") == (21, 7, 3) + + +def test_clear_output(): + assert nodeenv.clear_output( + bytes('some \ntext', 'utf-8')) == 'some text' + + +def test_remove_env_bin_from_path(): + assert (nodeenv.remove_env_bin_from_path( + '//home://home/env/bin://home/bin', '//home/env/bin') + == '//home://home/bin') + + +@pytest.mark.parametrize( + "node_version_file_content, expected_node_version", + [ + ("v22.14.0", "22.14.0"), + ("22.14.0", "22.14.0"), + ("v22.14.0\n", "22.14.0"), + ("v22.14.0\r\n", "22.14.0"), + ], +) +def test_node_version_file(node_version_file_content, expected_node_version): + def custom_exists(path): + if path == ".node-version": + return True + else: + return os.path.exists(path) + + def custom_open(file_path, *args, **kwargs): + if file_path == ".node-version": + return mock.mock_open(read_data=node_version_file_content)() + else: + return open(file_path, *args, **kwargs) + + with mock.patch("os.path.exists", new=custom_exists), mock.patch( + "builtins.open", new=custom_open + ): + nodeenv.Config._load([]) + assert nodeenv.Config.node == expected_node_version + + +class TestGetNodeBinUrl: + """Tests for get_node_bin_url function""" + + @pytest.mark.parametrize( + "machine,expected_arch", + [ + ('x86', 'x86'), + ('i686', 'x86'), + ('x86_64', 'x64'), + ('amd64', 'x64'), + ('AMD64', 'x64'), + ('i86pc', 'x64'), + ('armv6l', 'armv6l'), + ('armv7l', 'armv7l'), + ('armv8l', 'armv7l'), + ('aarch64', 'arm64'), + ('arm64', 'arm64'), + ('arm64/v8', 'arm64'), + ('armv8', 'arm64'), + ('armv8.4', 'arm64'), + ('ppc64le', 'ppc64le'), + ('s390x', 's390x'), + ('riscv64', 'riscv64'), + ], + ) + def test_linux_architectures(self, machine, expected_arch): + """Test URL generation for various Linux architectures""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value=machine), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-{}.tar.gz'.format(expected_arch) + ) + assert url == expected + + @pytest.mark.parametrize( + "machine,expected_arch", + [ + ('x86', 'x86'), + ('x86_64', 'x64'), + ('AMD64', 'x64'), + ], + ) + def test_windows_architectures(self, machine, expected_arch): + """Test URL generation for Windows platforms""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object( + platform, 'system', return_value='Windows'), \ + mock.patch.object( + platform, 'machine', return_value=machine), \ + mock.patch.object(nodeenv, 'is_WIN', True), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-win-{}.zip'.format(expected_arch) + ) + assert url == expected + + def test_darwin_x64(self): + """Test URL generation for macOS x64""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Darwin'), \ + mock.patch.object( + platform, 'machine', return_value='x86_64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-darwin-x64.tar.gz' + ) + assert url == expected + + def test_darwin_arm64(self): + """Test URL generation for macOS ARM64 (Apple Silicon)""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Darwin'), \ + mock.patch.object(platform, 'machine', return_value='arm64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-darwin-arm64.tar.gz' + ) + assert url == expected + + def test_x86_64_musl(self): + """Test URL generation for x86_64 musl (Alpine Linux)""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value='x86_64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=True), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64-musl.tar.gz' + ) + assert url == expected + + def test_cygwin(self): + """Test URL generation for CYGWIN platforms""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object( + platform, 'system', return_value='CYGWIN_NT-10.0'), \ + mock.patch.object( + platform, 'machine', return_value='x86_64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', True), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-win-x64.zip' + ) + assert url == expected + + def test_old_node_version(self): + """Test URL generation for old Node.js version (< 0.5)""" + root_url = 'https://nodejs.org/download/release/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value='x86_64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('0.4.12') + expected = ( + 'https://nodejs.org/download/release/' + 'node-v0.4.12-linux-x64.tar.gz' + ) + assert url == expected + + def test_freebsd(self): + """Test URL generation for FreeBSD""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object( + platform, 'system', return_value='FreeBSD'), \ + mock.patch.object(platform, 'machine', return_value='amd64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-freebsd-x64.tar.gz' + ) + assert url == expected + + def test_uppercase_machine_x86_64(self): + """Test that uppercase X86_64 is handled correctly""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value='X86_64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64.tar.gz' + ) + assert url == expected + + def test_uppercase_machine_aarch64(self): + """Test that uppercase AARCH64 is handled correctly""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value='AARCH64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-arm64.tar.gz' + ) + assert url == expected + + def test_mixed_case_machine(self): + """Test that mixed case Aarch64 is handled correctly""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object(platform, 'system', return_value='Linux'), \ + mock.patch.object( + platform, 'machine', return_value='Aarch64'), \ + mock.patch.object(nodeenv, 'is_WIN', False), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-arm64.tar.gz' + ) + assert url == expected + + def test_uppercase_machine_amd64(self): + """Test that uppercase AMD64 (Windows style) is handled correctly""" + root_url = 'https://nodejs.org/download/release/v18.0.0/' + with mock.patch.object( + platform, 'system', return_value='Windows'), \ + mock.patch.object(platform, 'machine', return_value='AMD64'), \ + mock.patch.object(nodeenv, 'is_WIN', True), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch.object( + nodeenv, 'is_x86_64_musl', return_value=False), \ + mock.patch.object( + nodeenv, 'get_root_url', return_value=root_url): + url = nodeenv.get_node_bin_url('18.0.0') + expected = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-win-x64.zip' + ) + assert url == expected + + +class TestInstallNode: + """Tests for install_node and install_node_wrapped functions""" + + def test_install_node_wrapped_success(self, tmpdir): + """Test successful Node.js installation""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + bin_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64.tar.gz' + ) + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=bin_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src' + ) as mock_download, \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ) as mock_copy, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify download was called + mock_download.assert_called_once_with( + bin_url, + src_dir, + args + ) + + # Verify copy was called + mock_copy.assert_called_once_with(env_dir, src_dir, '18.0.0') + + def test_install_node_wrapped_from_source(self, tmpdir): + """Test Node.js installation from source""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = False + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + node_src_dir = os.path.join(src_dir, 'node-v18.0.0') + + src_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0.tar.gz' + ) + with mock.patch.object( + nodeenv, 'get_node_src_url', + return_value=src_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src' + ) as mock_download, \ + mock.patch.object( + nodeenv, 'build_node_from_src' + ) as mock_build, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify download was called with source URL + mock_download.assert_called_once_with( + src_url, + src_dir, + args + ) + + # Verify build was called instead of copy + mock_build.assert_called_once_with( + env_dir, src_dir, node_src_dir, args + ) + + def test_install_node_wrapped_arm64_fallback_to_x64(self, tmpdir): + """Test arm64 fallback to x64 when arm64 is not available""" + args = mock.Mock() + args.node = '16.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + arm64_url = ( + 'https://nodejs.org/download/release/v16.0.0/' + 'node-v16.0.0-darwin-arm64.tar.gz' + ) + + # Mock HTTPError for arm64 URL + def download_side_effect(url, src_dir, args): + if 'arm64' in url: + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + # x64 download succeeds + return None + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=arm64_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ) as mock_download, \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ) as mock_copy, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + mock.patch.object(nodeenv.logger, 'warning'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify download was called twice: first with arm64, then with x64 + assert mock_download.call_count == 2 + calls = mock_download.call_args_list + assert 'arm64' in calls[0][0][0] + assert 'x64' in calls[1][0][0] + + # Verify copy was called after successful x64 download + mock_copy.assert_called_once() + + def test_install_node_wrapped_http_error_non_arm64(self, tmpdir): + """Test that HTTPError is re-raised for non-arm64 URLs""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + x64_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64.tar.gz' + ) + + # Mock HTTPError for x64 URL (no arm64 fallback should happen) + def download_side_effect(url, src_dir, args): + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=x64_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ) as mock_download, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + mock.patch.object(nodeenv.logger, 'warning') as mock_warning, \ + pytest.raises(nodeenv.urllib2.HTTPError): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify warning was logged + mock_warning.assert_called_once() + warning_call = mock_warning.call_args[0][0] + assert 'Failed to download' in warning_call + assert x64_url in warning_call + + # Verify download was called only once (no fallback for x64) + mock_download.assert_called_once() + + def test_install_node_wrapped_skips_download_if_exists(self, tmpdir): + """Test that download is skipped if node source dir exists""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + node_src_dir = os.path.join(src_dir, 'node-v18.0.0') + os.makedirs(node_src_dir) + + bin_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64.tar.gz' + ) + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=bin_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src' + ) as mock_download, \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ) as mock_copy, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify download was NOT called + mock_download.assert_not_called() + + # Verify copy was still called + mock_copy.assert_called_once() + + def test_install_node_restores_newline_on_exception(self, tmpdir): + """Test that install_node restores newline on exception""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = True + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + + with mock.patch.object( + nodeenv, 'install_node_wrapped', + side_effect=RuntimeError('Test error') + ), \ + mock.patch.object(nodeenv.logger, 'info') as mock_logger, \ + pytest.raises(RuntimeError): + nodeenv.install_node(env_dir, src_dir, args) + + # Verify that empty string was logged to restore newline + calls = [call[0][0] for call in mock_logger.call_args_list] + assert '' in calls + + def test_install_node_wrapped_prebuilt_vs_source_urls(self, tmpdir): + """Test that correct URL getter is used for prebuilt vs source""" + args = mock.Mock() + args.node = '18.0.0' + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + # Test prebuilt + args.prebuilt = True + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value='bin_url' + ) as mock_bin_url, \ + mock.patch.object( + nodeenv, 'get_node_src_url' + ) as mock_src_url, \ + mock.patch.object( + nodeenv, 'download_node_src' + ), \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + mock_bin_url.assert_called_once() + mock_src_url.assert_not_called() + + # Test source + args.prebuilt = False + with mock.patch.object( + nodeenv, 'get_node_bin_url' + ) as mock_bin_url, \ + mock.patch.object( + nodeenv, 'get_node_src_url', + return_value='src_url' + ) as mock_src_url, \ + mock.patch.object( + nodeenv, 'download_node_src' + ), \ + mock.patch.object( + nodeenv, 'build_node_from_src' + ), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + mock_src_url.assert_called_once() + mock_bin_url.assert_not_called() + + def test_install_node_wrapped_arm64_fallback_both_fail(self, tmpdir): + """Test that both arm64 and x64 failures raise exception""" + args = mock.Mock() + args.node = '16.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + arm64_url = ( + 'https://nodejs.org/download/release/v16.0.0/' + 'node-v16.0.0-darwin-arm64.tar.gz' + ) + + # Both arm64 and x64 downloads fail + def download_side_effect(url, src_dir, args): + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=arm64_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ) as mock_download, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + pytest.raises(nodeenv.urllib2.HTTPError): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Both arm64 and x64 should have been tried + assert mock_download.call_count == 2 + + def test_install_node_wrapped_no_copy_after_download_failure( + self, tmpdir + ): + """Test copy_node_from_prebuilt not called after failure""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + x64_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0-linux-x64.tar.gz' + ) + + # Download fails + def download_side_effect(url, src_dir, args): + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=x64_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ), \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ) as mock_copy, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + mock.patch.object(nodeenv.logger, 'warning'), \ + pytest.raises(nodeenv.urllib2.HTTPError): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify copy was NOT called after download failure + mock_copy.assert_not_called() + + def test_install_node_wrapped_no_build_after_download_failure( + self, tmpdir + ): + """Test build_node_from_src not called after failure""" + args = mock.Mock() + args.node = '18.0.0' + args.prebuilt = False + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + src_url = ( + 'https://nodejs.org/download/release/v18.0.0/' + 'node-v18.0.0.tar.gz' + ) + + # Download fails + def download_side_effect(url, src_dir, args): + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + + with mock.patch.object( + nodeenv, 'get_node_src_url', + return_value=src_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ), \ + mock.patch.object( + nodeenv, 'build_node_from_src' + ) as mock_build, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + mock.patch.object(nodeenv.logger, 'warning'), \ + pytest.raises(nodeenv.urllib2.HTTPError): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify build was NOT called after download failure + mock_build.assert_not_called() + + def test_install_node_wrapped_no_copy_after_arm64_fallback_failure( + self, tmpdir + ): + """Test copy not called when both arm64 and x64 fail""" + args = mock.Mock() + args.node = '16.0.0' + args.prebuilt = True + args.verbose = False + + env_dir = tmpdir.join('env').strpath + src_dir = tmpdir.join('src').strpath + os.makedirs(src_dir) + + arm64_url = ( + 'https://nodejs.org/download/release/v16.0.0/' + 'node-v16.0.0-darwin-arm64.tar.gz' + ) + + # Both arm64 and x64 downloads fail + def download_side_effect(url, src_dir, args): + raise nodeenv.urllib2.HTTPError( + url, 404, 'Not Found', {}, None + ) + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value=arm64_url + ), \ + mock.patch.object( + nodeenv, 'download_node_src', + side_effect=download_side_effect + ) as mock_download, \ + mock.patch.object( + nodeenv, 'copy_node_from_prebuilt' + ) as mock_copy, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch.object(nodeenv.logger, 'info'), \ + pytest.raises(nodeenv.urllib2.HTTPError): + nodeenv.install_node_wrapped(env_dir, src_dir, args) + + # Verify both attempts were made + assert mock_download.call_count == 2 + + # Verify copy was NOT called after both download failures + mock_copy.assert_not_called() + + +class TestGetEnvDir: + """Tests for get_env_dir function""" + + def test_with_python_virtualenv_real_prefix(self): + """Test get_env_dir when using python virtualenv with real_prefix""" + args = mock.Mock() + args.python_virtualenv = True + test_prefix = '/path/to/virtualenv' + + with mock.patch.object(sys, 'real_prefix', test_prefix, create=True), \ + mock.patch.object(sys, 'prefix', test_prefix): + result = nodeenv.get_env_dir(args) + assert result == test_prefix + + def test_with_python_virtualenv_base_prefix(self): + """Test get_env_dir when using python virtualenv with base_prefix""" + args = mock.Mock() + args.python_virtualenv = True + test_prefix = '/path/to/virtualenv' + test_base_prefix = '/usr' + + # Remove real_prefix if it exists + if hasattr(sys, 'real_prefix'): + with mock.patch.object(sys, 'real_prefix', create=False): + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_base_prefix): + result = nodeenv.get_env_dir(args) + assert result == test_prefix + else: + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_base_prefix): + result = nodeenv.get_env_dir(args) + assert result == test_prefix + + def test_with_python_virtualenv_conda_prefix(self): + """Test get_env_dir when using conda environment""" + args = mock.Mock() + args.python_virtualenv = True + test_prefix = '/path/to/conda/env' + + # Remove real_prefix if it exists + if hasattr(sys, 'real_prefix'): + with mock.patch.object(sys, 'real_prefix', create=False): + env_dict = {'CONDA_PREFIX': test_prefix} + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, env_dict): + result = nodeenv.get_env_dir(args) + assert result == test_prefix + else: + env_dict = {'CONDA_PREFIX': test_prefix} + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, env_dict): + result = nodeenv.get_env_dir(args) + assert result == test_prefix + + def test_with_python_virtualenv_virtual_env(self): + """Test get_env_dir when using VIRTUAL_ENV variable""" + args = mock.Mock() + args.python_virtualenv = True + test_prefix = '/path/to/venv' + virtual_env = '/path/to/virtual/env' + + # Remove real_prefix if it exists + if hasattr(sys, 'real_prefix'): + with mock.patch.object(sys, 'real_prefix', create=False): + env_dict = {'VIRTUAL_ENV': virtual_env} + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, env_dict, clear=True): + result = nodeenv.get_env_dir(args) + assert result == virtual_env + else: + env_dict = {'VIRTUAL_ENV': virtual_env} + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, env_dict, clear=True): + result = nodeenv.get_env_dir(args) + assert result == virtual_env + + def test_with_python_virtualenv_no_virtualenv_exits(self): + """Test get_env_dir exits when no virtualenv is available""" + args = mock.Mock() + args.python_virtualenv = True + test_prefix = '/usr' + + # Remove real_prefix if it exists + if hasattr(sys, 'real_prefix'): + with mock.patch.object(sys, 'real_prefix', create=False): + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, {}, clear=True), \ + pytest.raises(SystemExit) as exc_info: + nodeenv.get_env_dir(args) + assert exc_info.value.code == 2 + else: + with mock.patch.object(sys, 'prefix', test_prefix), \ + mock.patch.object(sys, 'base_prefix', test_prefix), \ + mock.patch.dict(os.environ, {}, clear=True), \ + pytest.raises(SystemExit) as exc_info: + nodeenv.get_env_dir(args) + assert exc_info.value.code == 2 + + def test_without_python_virtualenv(self): + """Test get_env_dir when not using python virtualenv""" + args = mock.Mock() + args.python_virtualenv = False + args.env_dir = '/path/to/node/env' + + result = nodeenv.get_env_dir(args) + assert result == '/path/to/node/env' + + def test_returns_utf8_encoded_string(self): + """Test that get_env_dir returns UTF-8 encoded string""" + args = mock.Mock() + args.python_virtualenv = False + args.env_dir = '/path/to/env' + + result = nodeenv.get_env_dir(args) + # The to_utf8 function is applied, + # but in Python 3 it returns the same string + assert result == '/path/to/env' + + +class TestInstallNpm: + """Tests for install_npm function""" + + def test_install_npm_basic(self): + """Test basic npm installation with default settings""" + args = mock.Mock() + args.npm = '8.19.2' + args.no_npm_clean = False + args.verbose = False + + env_dir = '/path/to/env' + src_dir = '/path/to/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'npm installed', None) + + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info') as mock_logger: + nodeenv.install_npm(env_dir, src_dir, args) + + # Verify subprocess was called correctly + mock_popen.assert_called_once() + call_args = mock_popen.call_args + + # Check command + assert call_args[0][0][0] == 'sh' + assert call_args[0][0][1] == '-c' + expected_cmd = '. {0} && npm install -g npm@{1}'.format( + _quote(os.path.join(env_dir, 'bin', 'activate')), + '8.19.2' + ) + assert call_args[0][0][2] == expected_cmd + + # Check environment variables + env = call_args[1]['env'] + assert env['clean'] == 'yes' + assert env['npm_install'] == '8.19.2' + + # Check other subprocess parameters + assert call_args[1]['stdin'] == subprocess.PIPE + assert call_args[1]['stdout'] == subprocess.PIPE + assert call_args[1]['stderr'] == subprocess.STDOUT + + # Verify communicate was called + mock_proc.communicate.assert_called_once() + + # Verify logging + assert mock_logger.call_count >= 2 + log_calls = [call[0][0] for call in mock_logger.call_args_list] + assert any('8.19.2' in str(call) for call in log_calls) + assert any('done' in str(call) for call in log_calls) + + def test_install_npm_with_no_npm_clean(self): + """Test npm installation with no_npm_clean flag""" + args = mock.Mock() + args.npm = 'latest' + args.no_npm_clean = True + args.verbose = False + + env_dir = '/test/env' + src_dir = '/test/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'', None) + + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm(env_dir, src_dir, args) + + # Check that clean='no' when no_npm_clean is True + call_args = mock_popen.call_args + env = call_args[1]['env'] + assert env['clean'] == 'no' + assert env['npm_install'] == 'latest' + + def test_install_npm_verbose_output(self): + """Test npm installation with verbose output enabled""" + args = mock.Mock() + args.npm = '9.0.0' + args.no_npm_clean = False + args.verbose = True + + env_dir = '/verbose/env' + src_dir = '/verbose/src' + + test_output = b'Installing npm 9.0.0...\nDone!' + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (test_output, None) + + with mock.patch.object(subprocess, 'Popen', return_value=mock_proc), \ + mock.patch.object(nodeenv.logger, 'info') as mock_logger: + nodeenv.install_npm(env_dir, src_dir, args) + + # Verify that output was logged when verbose=True + log_calls = [call[0][0] for call in mock_logger.call_args_list] + assert test_output in log_calls + + def test_install_npm_latest_version(self): + """Test npm installation with 'latest' version""" + args = mock.Mock() + args.npm = 'latest' + args.no_npm_clean = False + args.verbose = False + + env_dir = '/latest/env' + src_dir = '/latest/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'', None) + + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm(env_dir, src_dir, args) + + # Verify the command uses 'latest' + call_args = mock_popen.call_args + command = call_args[0][0][2] + assert 'npm install -g npm@latest' in command + + def test_install_npm_with_special_chars_in_path(self): + """Test npm installation with special characters in path""" + args = mock.Mock() + args.npm = '8.0.0' + args.no_npm_clean = False + args.verbose = False + + env_dir = '/path/with spaces/and (parens)/env' + src_dir = '/path/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'', None) + + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm(env_dir, src_dir, args) + + # Verify the path is properly quoted + call_args = mock_popen.call_args + command = call_args[0][0][2] + # The path should be quoted to handle special characters + activate_path = os.path.join(env_dir, 'bin', 'activate') + quoted_path = _quote(activate_path) + assert quoted_path in command + + def test_install_npm_environment_inheritance(self): + """Test that install_npm inherits current environment variables""" + args = mock.Mock() + args.npm = '7.0.0' + args.no_npm_clean = False + args.verbose = False + + env_dir = '/env' + src_dir = '/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'', None) + + test_env = {'TEST_VAR': 'test_value', 'PATH': '/usr/bin'} + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info'), \ + mock.patch.dict(os.environ, test_env, clear=True): + nodeenv.install_npm(env_dir, src_dir, args) + + # Check that environment variables are inherited + call_args = mock_popen.call_args + env = call_args[1]['env'] + assert env['TEST_VAR'] == 'test_value' + assert env['PATH'] == '/usr/bin' + assert env['clean'] == 'yes' + assert env['npm_install'] == '7.0.0' + + def test_install_npm_specific_version_formats(self): + """Test npm installation with different version formats""" + test_versions = ['8.19.2', '10.0.0', '6.14.18', 'latest'] + + for version in test_versions: + args = mock.Mock() + args.npm = version + args.no_npm_clean = False + args.verbose = False + + env_dir = '/env' + src_dir = '/src' + + mock_proc = mock.Mock() + mock_proc.communicate.return_value = (b'', None) + + with mock.patch.object( + subprocess, 'Popen', return_value=mock_proc + ) as mock_popen, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm(env_dir, src_dir, args) + + # Verify the version is correctly used in the command + call_args = mock_popen.call_args + command = call_args[0][0][2] + assert f'npm install -g npm@{version}' in command + + # Verify version is in environment + env = call_args[1]['env'] + assert env['npm_install'] == version + + +class TestInstallNpmWin: + """Tests for install_npm_win function""" + + def test_install_npm_win_basic(self): + """Test basic Windows npm installation""" + args = mock.Mock() + args.npm = '8.19.2' + + env_dir = 'C:\\path\\to\\env' + src_dir = 'C:\\path\\to\\src' + + # Mock the zip file content + mock_zip_content = b'PK\x03\x04...' # Simplified zip header + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + + with mock.patch.object( + nodeenv, 'urlopen', return_value=mock_response + ), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch('zipfile.ZipFile', return_value=mock_zip), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch('shutil.copytree') as mock_copytree, \ + mock.patch('shutil.copy') as mock_copy, \ + mock.patch.object(nodeenv.logger, 'info') as mock_logger: + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify URL was constructed correctly + expected_url = 'https://github.com/npm/cli/archive/v8.19.2.zip' + nodeenv.urlopen.assert_called_once_with(expected_url) + + # Verify extraction happened + mock_zip.extractall.assert_called_once_with(src_dir) + + # Verify copytree and copy were called + assert mock_copytree.called + assert mock_copy.call_count == 2 + + # Verify logging + log_calls = [call[0][0] for call in mock_logger.call_args_list] + assert any('8.19.2' in str(call) for call in log_calls) + + def test_install_npm_win_removes_existing_files(self): + """Test that existing npm files are removed before installation""" + args = mock.Mock() + args.npm = '9.0.0' + + env_dir = 'C:\\env' + src_dir = 'C:\\src' + + mock_zip_content = b'PK\x03\x04...' + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + + # Simulate existing files + def exists_side_effect(path): + if ('node_modules' in path or 'npm.cmd' in path or + 'npm-cli.js' in path): + return True + return False + + with mock.patch.object( + nodeenv, 'urlopen', return_value=mock_response + ), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch('zipfile.ZipFile', return_value=mock_zip), \ + mock.patch('os.path.exists', side_effect=exists_side_effect), \ + mock.patch('shutil.rmtree') as mock_rmtree, \ + mock.patch('os.remove') as mock_remove, \ + mock.patch('shutil.copytree'), \ + mock.patch('shutil.copy'), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify cleanup happened + mock_rmtree.assert_called_once() + assert mock_remove.call_count == 2 + + def test_install_npm_win_cygwin(self): + """Test Windows npm installation on CYGWIN""" + args = mock.Mock() + args.npm = '7.24.2' + + env_dir = '/cygdrive/c/env' + src_dir = '/cygdrive/c/src' + + mock_zip_content = b'PK\x03\x04...' + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_npm_script = b'#!/bin/sh\n# npm script' + mock_npm_response = mock.Mock() + mock_npm_response.read.return_value = mock_npm_script + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + + with mock.patch.object(nodeenv, 'urlopen') as mock_urlopen, \ + mock.patch.object(nodeenv, 'is_CYGWIN', True), \ + mock.patch.object(nodeenv, 'writefile') as mock_writefile, \ + mock.patch('zipfile.ZipFile', return_value=mock_zip), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch('shutil.copytree'), \ + mock.patch('shutil.copy'), \ + mock.patch.object(nodeenv.logger, 'info'): + mock_urlopen.side_effect = [mock_response, mock_npm_response] + + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify that CYGWIN-specific operations happened + assert mock_urlopen.call_count == 2 + assert mock_writefile.called + + # Verify the raw GitHub URL was called + calls = [str(call) for call in mock_urlopen.call_args_list] + assert any( + 'raw.githubusercontent.com' in str(call) for call in calls + ) + + def test_install_npm_win_different_versions(self): + """Test Windows npm installation with different version formats""" + test_versions = ['8.0.0', '9.5.1', '10.0.0'] + + for version in test_versions: + args = mock.Mock() + args.npm = version + + env_dir = 'C:\\env' + src_dir = 'C:\\src' + + mock_zip_content = b'PK\x03\x04...' + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + + with mock.patch.object( + nodeenv, 'urlopen', return_value=mock_response + ) as mock_urlopen, \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch('zipfile.ZipFile', return_value=mock_zip), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch('shutil.copytree'), \ + mock.patch('shutil.copy'), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify correct URL for each version + expected_url = ( + f'https://github.com/npm/cli/archive/v{version}.zip' + ) + mock_urlopen.assert_called_with(expected_url) + + def test_install_npm_win_paths(self): + """Test that Windows npm installation uses correct paths""" + args = mock.Mock() + args.npm = '8.5.0' + + env_dir = 'C:\\Users\\test\\env' + src_dir = 'C:\\Users\\test\\src' + + mock_zip_content = b'PK\x03\x04...' + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + + with mock.patch.object( + nodeenv, 'urlopen', return_value=mock_response + ), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch('zipfile.ZipFile', return_value=mock_zip), \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch('shutil.copytree') as mock_copytree, \ + mock.patch('shutil.copy') as mock_copy, \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify paths + copytree_call = mock_copytree.call_args[0] + src_path = copytree_call[0] + dst_path = copytree_call[1] + + assert 'cli-8.5.0' in src_path + expected_path = os.path.join( + env_dir, 'Scripts', 'node_modules', 'npm' + ) + assert expected_path == dst_path + + # Verify copy calls use correct paths + copy_calls = mock_copy.call_args_list + assert len(copy_calls) == 2 + assert any('npm.cmd' in str(call) for call in copy_calls) + assert any('npm-cli.js' in str(call) for call in copy_calls) + + def test_install_npm_win_zip_extraction(self): + """Test that zip file is properly extracted""" + args = mock.Mock() + args.npm = '9.1.0' + + env_dir = 'C:\\test' + src_dir = 'C:\\test\\src' + + mock_zip_content = b'PK\x03\x04...' + mock_response = mock.Mock() + mock_response.read.return_value = mock_zip_content + + mock_zip = mock.Mock() + mock_zip.__enter__ = mock.Mock(return_value=mock_zip) + mock_zip.__exit__ = mock.Mock(return_value=False) + mock_zip.extractall = mock.Mock() + + with mock.patch.object( + nodeenv, 'urlopen', return_value=mock_response + ), \ + mock.patch.object(nodeenv, 'is_CYGWIN', False), \ + mock.patch( + 'zipfile.ZipFile', return_value=mock_zip + ) as mock_zipfile, \ + mock.patch('os.path.exists', return_value=False), \ + mock.patch('shutil.copytree'), \ + mock.patch('shutil.copy'), \ + mock.patch.object(nodeenv.logger, 'info'): + nodeenv.install_npm_win(env_dir, src_dir, args) + + # Verify ZipFile was created with the BytesIO content + mock_zipfile.assert_called_once() + zip_args = mock_zipfile.call_args[0] + assert hasattr(zip_args[0], 'read') # Should be BytesIO object + + # Verify extraction + mock_zip.extractall.assert_called_once_with(src_dir) diff --git a/tests/nodejs.htm b/tests/nodejs.htm deleted file mode 100644 index 5adb939..0000000 --- a/tests/nodejs.htm +++ /dev/null @@ -1,29 +0,0 @@ - -Index of /dist/latest/ - -

Index of /dist/latest/


../
-docs/                                              25-Dec-2014 16:16                   -
-x64/                                               22-Dec-2014 21:33                   -
-SHASUMS.txt                                        22-Dec-2014 21:50                1359
-SHASUMS.txt.asc                                    22-Dec-2014 21:50                1649
-SHASUMS.txt.gpg                                    22-Dec-2014 21:50                 845
-SHASUMS256.txt                                     22-Dec-2014 21:50                1887
-SHASUMS256.txt.asc                                 22-Dec-2014 21:50                2177
-SHASUMS256.txt.gpg                                 22-Dec-2014 21:50                1159
-node-v0.10.35-darwin-x64.tar.gz                    22-Dec-2014 21:32             5119135
-node-v0.10.35-darwin-x86.tar.gz                    22-Dec-2014 21:29             4944714
-node-v0.10.35-linux-x64.tar.gz                     22-Dec-2014 21:32             5674318
-node-v0.10.35-linux-x86.tar.gz                     22-Dec-2014 21:32             5476680
-node-v0.10.35-sunos-x64.tar.gz                     22-Dec-2014 21:38             6942340
-node-v0.10.35-sunos-x86.tar.gz                     22-Dec-2014 21:38             6515411
-node-v0.10.35-x86.msi                              22-Dec-2014 21:48             5808128
-node-v0.10.35.pkg                                  22-Dec-2014 21:35            10279155
-node-v0.10.35.tar.gz                               22-Dec-2014 21:28            14417025
-node.exe                                           22-Dec-2014 21:48             5832576
-node.exp                                           22-Dec-2014 21:48              186902
-node.lib                                           22-Dec-2014 21:48              304702
-node.pdb                                           22-Dec-2014 21:48            17574912
-openssl-cli.exe                                    22-Dec-2014 21:48             1829888
-openssl-cli.pdb                                    22-Dec-2014 21:48             7457792
-

- diff --git a/tests/nodejs_dist.htm b/tests/nodejs_dist.htm deleted file mode 100644 index 43dcce6..0000000 --- a/tests/nodejs_dist.htm +++ /dev/null @@ -1,255 +0,0 @@ - -Index of /dist/ - -

Index of /dist/


../
-latest/                                            06-Feb-2015 22:03                   -
-nightlies/                                         07-Aug-2014 17:11                   -
-npm/                                               23-May-2014 16:55                   -
-patch/                                             30-Jul-2014 23:02                   -
-v0.10.0/                                           19-Mar-2013 04:14                   -
-v0.10.1/                                           21-Mar-2013 19:04                   -
-v0.10.10/                                          12-Jun-2013 22:46                   -
-v0.10.11/                                          13-Jun-2013 22:11                   -
-v0.10.12/                                          19-Jun-2013 02:19                   -
-v0.10.13/                                          13-Jul-2013 20:14                   -
-v0.10.14/                                          12-Aug-2013 20:37                   -
-v0.10.15/                                          12-Aug-2013 20:52                   -
-v0.10.16/                                          16-Aug-2013 19:35                   -
-v0.10.16-isaacs-manual/                            16-Aug-2013 16:26                   -
-v0.10.17/                                          22-Aug-2013 17:23                   -
-v0.10.18/                                          09-Oct-2013 03:56                   -
-v0.10.19/                                          09-Oct-2013 17:15                   -
-v0.10.2/                                           03-Apr-2013 05:01                   -
-v0.10.20/                                          09-Oct-2013 17:25                   -
-v0.10.21/                                          21-Oct-2013 19:55                   -
-v0.10.22/                                          02-Dec-2013 16:59                   -
-v0.10.23/                                          21-Jan-2014 18:51                   -
-v0.10.24/                                          21-Jan-2014 19:01                   -
-v0.10.25/                                          11-Apr-2014 20:13                   -
-v0.10.26/                                          11-Apr-2014 20:34                   -
-v0.10.27/                                          07-Aug-2014 17:43                   -
-v0.10.28/                                          07-Aug-2014 18:35                   -
-v0.10.29/                                          09-Jun-2014 17:45                   -
-v0.10.3/                                           26-Apr-2013 23:11                   -
-v0.10.30/                                          31-Jul-2014 19:13                   -
-v0.10.31/                                          19-Aug-2014 22:12                   -
-v0.10.32/                                          16-Sep-2014 23:52                   -
-v0.10.33/                                          23-Oct-2014 19:12                   -
-v0.10.34/                                          17-Dec-2014 21:59                   -
-v0.10.35/                                          22-Dec-2014 21:51                   -
-v0.10.36/                                          26-Jan-2015 19:56                   -
-v0.10.4/                                           26-Apr-2013 23:41                   -
-v0.10.5/                                           13-May-2013 22:31                   -
-v0.10.6/                                           15-May-2013 17:35                   -
-v0.10.7/                                           24-May-2013 02:36                   -
-v0.10.8/                                           12-Jun-2013 19:42                   -
-v0.10.9/                                           12-Jun-2013 19:51                   -
-v0.11.0/                                           03-Apr-2013 18:43                   -
-v0.11.1/                                           15-May-2013 17:47                   -
-v0.11.10/                                          21-Jan-2014 19:19                   -
-v0.11.11/                                          11-Apr-2014 20:49                   -
-v0.11.12/                                          11-Apr-2014 21:06                   -
-v0.11.13/                                          02-May-2014 14:53                   -
-v0.11.14/                                          16-Jan-2015 16:37                   -
-v0.11.15/                                          20-Jan-2015 23:42                   -
-v0.11.16/                                          30-Jan-2015 17:05                   -
-v0.11.2/                                           15-May-2013 18:29                   -
-v0.11.3/                                           27-Jun-2013 00:26                   -
-v0.11.4/                                           13-Jul-2013 19:50                   -
-v0.11.5/                                           12-Aug-2013 21:07                   -
-v0.11.6/                                           22-Aug-2013 17:24                   -
-v0.11.7/                                           09-Oct-2013 17:56                   -
-v0.11.8/                                           02-Dec-2013 18:57                   -
-v0.11.9/                                           02-Dec-2013 19:16                   -
-v0.12.0/                                           06-Feb-2015 22:03                   -
-v0.5.1/                                            01-Apr-2012 01:55                   -
-v0.5.10/                                           01-Apr-2012 01:55                   -
-v0.5.2/                                            01-Apr-2012 01:55                   -
-v0.5.3/                                            01-Apr-2012 01:55                   -
-v0.5.4/                                            01-Apr-2012 01:55                   -
-v0.5.5/                                            01-Apr-2012 01:55                   -
-v0.5.6/                                            01-Apr-2012 01:55                   -
-v0.5.7/                                            01-Apr-2012 01:55                   -
-v0.5.8/                                            01-Apr-2012 01:55                   -
-v0.5.9/                                            01-Apr-2012 01:55                   -
-v0.6.0/                                            01-Apr-2012 01:55                   -
-v0.6.1/                                            01-Apr-2012 01:55                   -
-v0.6.10/                                           01-Apr-2012 01:55                   -
-v0.6.11/                                           01-Apr-2012 01:55                   -
-v0.6.12/                                           01-Apr-2012 01:55                   -
-v0.6.13/                                           01-Apr-2012 01:55                   -
-v0.6.14/                                           01-Apr-2012 01:55                   -
-v0.6.15/                                           09-Apr-2012 18:02                   -
-v0.6.16/                                           30-Apr-2012 20:25                   -
-v0.6.17/                                           04-May-2012 20:29                   -
-v0.6.18/                                           15-May-2012 17:01                   -
-v0.6.19/                                           08-Jun-2012 18:27                   -
-v0.6.2/                                            01-Apr-2012 01:55                   -
-v0.6.20/                                           11-Jul-2012 00:02                   -
-v0.6.21/                                           03-Aug-2012 21:38                   -
-v0.6.3/                                            01-Apr-2012 01:55                   -
-v0.6.4/                                            31-Mar-2012 20:17                   -
-v0.6.5/                                            01-Apr-2012 01:55                   -
-v0.6.6/                                            01-Apr-2012 01:55                   -
-v0.6.7/                                            01-Apr-2012 01:55                   -
-v0.6.8/                                            01-Apr-2012 01:55                   -
-v0.6.9/                                            01-Apr-2012 01:55                   -
-v0.7.0/                                            01-Apr-2012 01:55                   -
-v0.7.1/                                            01-Apr-2012 01:55                   -
-v0.7.10/                                           11-Jun-2012 19:34                   -
-v0.7.11/                                           15-Jun-2012 22:24                   -
-v0.7.12/                                           20-Jun-2012 00:14                   -
-v0.7.2/                                            01-Apr-2012 01:55                   -
-v0.7.3/                                            01-Apr-2012 01:55                   -
-v0.7.4/                                            01-Apr-2012 01:55                   -
-v0.7.5/                                            01-Apr-2012 01:55                   -
-v0.7.6/                                            01-Apr-2012 01:55                   -
-v0.7.7/                                            01-Apr-2012 01:55                   -
-v0.7.8/                                            18-Apr-2012 17:37                   -
-v0.7.9/                                            11-Jun-2012 15:53                   -
-v0.8.0/                                            25-Jun-2012 15:28                   -
-v0.8.1/                                            29-Jun-2012 17:07                   -
-v0.8.10/                                           25-Sep-2012 22:31                   -
-v0.8.11/                                           27-Sep-2012 17:17                   -
-v0.8.12/                                           11-Oct-2012 23:42                   -
-v0.8.13/                                           25-Oct-2012 19:50                   -
-v0.8.14/                                           25-Oct-2012 21:42                   -
-v0.8.15/                                           26-Nov-2012 17:11                   -
-v0.8.16/                                           13-Dec-2012 16:46                   -
-v0.8.17/                                           13-Jan-2013 04:59                   -
-v0.8.18/                                           24-Jan-2013 22:25                   -
-v0.8.19/                                           08-Feb-2013 00:20                   -
-v0.8.2/                                            09-Jul-2012 17:20                   -
-v0.8.20/                                           16-Feb-2013 06:22                   -
-v0.8.21/                                           26-Feb-2013 20:37                   -
-v0.8.22/                                           07-Mar-2013 07:19                   -
-v0.8.23/                                           09-Apr-2013 00:30                   -
-v0.8.24/                                           04-Jun-2013 14:12                   -
-v0.8.25/                                           13-Jun-2013 20:17                   -
-v0.8.26/                                           23-Jun-2014 17:02                   -
-v0.8.27/                                           23-Jun-2014 17:12                   -
-v0.8.28/                                           31-Jul-2014 18:36                   -
-v0.8.3/                                            19-Jul-2012 17:16                   -
-v0.8.4/                                            25-Jul-2012 22:24                   -
-v0.8.5/                                            02-Aug-2012 21:53                   -
-v0.8.6/                                            07-Aug-2012 19:00                   -
-v0.8.7/                                            15-Aug-2012 23:34                   -
-v0.8.8/                                            22-Aug-2012 20:37                   -
-v0.8.9/                                            11-Sep-2012 18:54                   -
-v0.9.0/                                            20-Jul-2012 18:49                   -
-v0.9.1/                                            13-Sep-2012 19:30                   -
-v0.9.10/                                           20-Feb-2013 20:23                   -
-v0.9.11/                                           02-Mar-2013 21:21                   -
-v0.9.12/                                           07-Mar-2013 07:54                   -
-v0.9.2/                                            18-Sep-2012 01:24                   -
-v0.9.3/                                            24-Oct-2012 17:06                   -
-v0.9.4/                                            21-Dec-2012 20:31                   -
-v0.9.5/                                            30-Dec-2012 01:22                   -
-v0.9.6/                                            11-Jan-2013 19:21                   -
-v0.9.7/                                            24-Jan-2013 20:49                   -
-v0.9.8/                                            02-Feb-2013 19:12                   -
-v0.9.9/                                            08-Feb-2013 00:21                   -
-node-0.0.1.tar.gz                                  26-Aug-2011 16:22             2846972
-node-0.0.2.tar.gz                                  26-Aug-2011 16:22             2847748
-node-0.0.3.tar.gz                                  26-Aug-2011 16:22             2891652
-node-0.0.4.tar.gz                                  26-Aug-2011 16:21             2891533
-node-0.0.5.tar.gz                                  26-Aug-2011 16:22             2926727
-node-0.0.6.tar.gz                                  26-Aug-2011 16:21             2952115
-node-0.1.0.tar.gz                                  26-Aug-2011 16:21             3331341
-node-0.1.1.tar.gz                                  26-Aug-2011 16:22             3390971
-node-0.1.10.tar.gz                                 26-Aug-2011 16:22             3674389
-node-0.1.11.tar.gz                                 26-Aug-2011 16:22             3683687
-node-0.1.12.tar.gz                                 26-Aug-2011 16:21             3699939
-node-0.1.13.tar.gz                                 26-Aug-2011 16:22             3718928
-node-0.1.2.tar.gz                                  26-Aug-2011 16:21             3516421
-node-0.1.3.tar.gz                                  26-Aug-2011 16:22             3527371
-node-0.1.4.tar.gz                                  26-Aug-2011 16:21             3567057
-node-0.1.5.tar.gz                                  26-Aug-2011 16:22             3598128
-node-0.1.6.tar.gz                                  26-Aug-2011 16:22             3598051
-node-0.1.7.tar.gz                                  26-Aug-2011 16:22             3599626
-node-0.1.8.tar.gz                                  26-Aug-2011 16:22             3639185
-node-0.1.9.tar.gz                                  26-Aug-2011 16:21             3639588
-node-latest.tar.gz                                 06-Feb-2015 20:40            19096897
-node-v0.1.100.tar.gz                               26-Aug-2011 16:21             3813493
-node-v0.1.101.tar.gz                               26-Aug-2011 16:22             3825097
-node-v0.1.102.tar.gz                               26-Aug-2011 16:21             3847409
-node-v0.1.103.tar.gz                               26-Aug-2011 16:22             3843666
-node-v0.1.104.tar.gz                               26-Aug-2011 16:21             3859322
-node-v0.1.14.tar.gz                                26-Aug-2011 16:22             3736523
-node-v0.1.15.tar.gz                                26-Aug-2011 16:21             3766716
-node-v0.1.16.tar.gz                                26-Aug-2011 16:22             3827870
-node-v0.1.17.tar.gz                                26-Aug-2011 16:21             3826866
-node-v0.1.18.tar.gz                                26-Aug-2011 16:21             3537137
-node-v0.1.19.tar.gz                                26-Aug-2011 16:22             3574916
-node-v0.1.20.tar.gz                                26-Aug-2011 16:21             3575681
-node-v0.1.21.tar.gz                                26-Aug-2011 16:22             3597096
-node-v0.1.22.tar.gz                                26-Aug-2011 16:21             3604861
-node-v0.1.23.tar.gz                                26-Aug-2011 16:22             3605321
-node-v0.1.24.tar.gz                                26-Aug-2011 16:21             3649641
-node-v0.1.25.tar.gz                                26-Aug-2011 16:22             3666675
-node-v0.1.26.tar.gz                                26-Aug-2011 16:22             3704254
-node-v0.1.27.tar.gz                                26-Aug-2011 16:22             3766114
-node-v0.1.28.tar.gz                                26-Aug-2011 16:22             3804602
-node-v0.1.29.tar.gz                                26-Aug-2011 16:21             3807335
-node-v0.1.30.tar.gz                                26-Aug-2011 16:22             3912671
-node-v0.1.31.tar.gz                                26-Aug-2011 16:22             3933441
-node-v0.1.32.tar.gz                                26-Aug-2011 16:21             3984949
-node-v0.1.33.tar.gz                                26-Aug-2011 16:22             4016600
-node-v0.1.90.tar.gz                                26-Aug-2011 16:22             6452573
-node-v0.1.91.tar.gz                                26-Aug-2011 16:21             6488023
-node-v0.1.92.tar.gz                                26-Aug-2011 16:22             6535942
-node-v0.1.93.tar.gz                                26-Aug-2011 16:21             6528767
-node-v0.1.94.tar.gz                                26-Aug-2011 16:22             6691437
-node-v0.1.95.tar.gz                                26-Aug-2011 16:21             3691396
-node-v0.1.96.tar.gz                                26-Aug-2011 16:22             3697128
-node-v0.1.97.tar.gz                                26-Aug-2011 16:21             3725213
-node-v0.1.98.tar.gz                                26-Aug-2011 16:21             3770749
-node-v0.1.99.tar.gz                                26-Aug-2011 16:22             3796156
-node-v0.10.14.tar.gz                               25-Jul-2013 19:06            13782897
-node-v0.2.0.tar.gz                                 26-Aug-2011 16:21             3869705
-node-v0.2.1.tar.gz                                 26-Aug-2011 16:22             3874229
-node-v0.2.2.tar.gz                                 26-Aug-2011 16:21             3876164
-node-v0.2.3.tar.gz                                 26-Aug-2011 16:22             3877908
-node-v0.2.4.tar.gz                                 26-Aug-2011 16:22             4002347
-node-v0.2.5.tar.gz                                 26-Aug-2011 16:22             4008314
-node-v0.2.6.tar.gz                                 26-Aug-2011 16:21             4010320
-node-v0.3.0.tar.gz                                 26-Aug-2011 16:22             4054239
-node-v0.3.1.tar.gz                                 26-Aug-2011 16:22             4147683
-node-v0.3.2.tar.gz                                 26-Aug-2011 16:21             4433878
-node-v0.3.3.tar.gz                                 26-Aug-2011 16:22             4582669
-node-v0.3.4.tar.gz                                 26-Aug-2011 16:21             4610441
-node-v0.3.5.tar.gz                                 26-Aug-2011 16:22             4655131
-node-v0.3.6.tar.gz                                 26-Aug-2011 16:21             4727071
-node-v0.3.7.tar.gz                                 26-Aug-2011 16:22             4748183
-node-v0.3.8.tar.gz                                 26-Aug-2011 16:22             4779447
-node-v0.4.0.tar.gz                                 26-Aug-2011 16:21             4827760
-node-v0.4.1.tar.gz                                 26-Aug-2011 16:22             4855576
-node-v0.4.10.tar.gz                                26-Aug-2011 16:22            12410018
-node-v0.4.11.tar.gz                                26-Aug-2011 16:21            12419274
-node-v0.4.12.tar.gz                                15-Sep-2011 23:48            12421469
-node-v0.4.2.tar.gz                                 26-Aug-2011 16:22             4922523
-node-v0.4.3.tar.gz                                 26-Aug-2011 16:22             4991966
-node-v0.4.4.tar.gz                                 26-Aug-2011 16:21             4995935
-node-v0.4.5.tar.gz                                 26-Aug-2011 16:22             5001301
-node-v0.4.6.tar.gz                                 26-Aug-2011 16:21             5008110
-node-v0.4.7.tar.gz                                 26-Aug-2011 16:22             5011520
-node-v0.4.8.tar.gz                                 26-Aug-2011 16:22             4991396
-node-v0.4.9.tar.gz                                 26-Aug-2011 16:21             4994552
-node-v0.4.tar.gz                                   26-Aug-2011 16:21             4991396
-node-v0.5.0.tar.gz                                 26-Aug-2011 16:21             5357945
-node-v0.6.1.tar.gz                                 14-Nov-2011 21:57             9276847
-node-v0.6.10.tar.gz                                15-Mar-2012 23:03            10545272
-node-v0.6.11.tar.gz                                15-Mar-2012 23:03            10555423
-node-v0.6.12.tar.gz                                15-Mar-2012 23:03            10452498
-node-v0.6.13.tar.gz                                15-Mar-2012 23:04            10757157
-node-v0.6.2.tar.gz                                 18-Nov-2011 23:29             9286655
-node-v0.6.3.tar.gz                                 15-Mar-2012 23:07            10048403
-node-v0.6.4.tar.gz                                 02-Dec-2011 02:17            10195975
-node-v0.6.5.tar.gz                                 15-Mar-2012 23:04            10195654
-node-v0.6.6.tar.gz                                 15-Mar-2012 23:04            10446671
-node-v0.6.7.tar.gz                                 15-Mar-2012 23:04            10473188
-node-v0.6.8.tar.gz                                 20-Jan-2012 02:26            10488841
-node-v0.6.9.tar.gz                                 15-Mar-2012 23:03            10544243
-npm-versions.txt                                   27-Feb-2014 00:01                1676
-

- diff --git a/tests/nodejs_index.json b/tests/nodejs_index.json new file mode 100644 index 0000000..11bb736 --- /dev/null +++ b/tests/nodejs_index.json @@ -0,0 +1,487 @@ +[ +{"version":"v13.5.0","date":"2019-12-18","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.4","v8":"7.9.317.25","uv":"1.34.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v13.4.0","date":"2019-12-17","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-riscv64","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.4","v8":"7.9.317.25","uv":"1.34.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":true}, +{"version":"v13.3.0","date":"2019-12-03","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.1","v8":"7.9.317.25","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v13.2.0","date":"2019-11-21","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.1","v8":"7.9.317.23","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v13.1.0","date":"2019-11-05","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.12.1","v8":"7.8.279.17","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v13.0.1","date":"2019-10-23","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.12.0","v8":"7.8.279.17","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v13.0.0","date":"2019-10-10","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.12.0","v8":"7.8.279.17","uv":"1.32.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"79","lts":false,"security":false}, +{"version":"v12.14.0","date":"2019-12-16","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.4","v8":"7.7.299.13","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"72","lts":"Erbium","security":true}, +{"version":"v12.13.1","date":"2019-11-19","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-riscv64","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.12.1","v8":"7.7.299.13","uv":"1.33.1","zlib":"1.2.11","openssl":"1.1.1d","modules":"72","lts":"Erbium","security":false}, +{"version":"v12.13.0","date":"2019-10-21","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.12.0","v8":"7.7.299.13","uv":"1.32.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"72","lts":"Erbium","security":false}, +{"version":"v12.12.0","date":"2019-10-11","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.11.3","v8":"7.7.299.13","uv":"1.32.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"72","lts":false,"security":false}, +{"version":"v12.11.1","date":"2019-10-01","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.11.3","v8":"7.7.299.11","uv":"1.32.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.11.0","date":"2019-09-25","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.11.3","v8":"7.7.299.11","uv":"1.32.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.10.0","date":"2019-09-04","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.3","v8":"7.6.303.29","uv":"1.31.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.9.1","date":"2019-08-26","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.2","v8":"7.6.303.29","uv":"1.31.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.9.0","date":"2019-08-20","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.2","v8":"7.6.303.29","uv":"1.31.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.8.1","date":"2019-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.2","v8":"7.5.288.22","uv":"1.30.1","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":true}, +{"version":"v12.8.0","date":"2019-08-06","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.2","v8":"7.5.288.22","uv":"1.30.1","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.7.0","date":"2019-07-23","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.10.0","v8":"7.5.288.22","uv":"1.30.1","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.6.0","date":"2019-07-03","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.5.288.22","uv":"1.30.1","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.5.0","date":"2019-06-26","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.5.288.22","uv":"1.29.1","zlib":"1.2.11","openssl":"1.1.1c","modules":"72","lts":false,"security":false}, +{"version":"v12.4.0","date":"2019-06-04","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.27","uv":"1.29.1","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v12.3.1","date":"2019-05-22","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.27","uv":"1.29.1","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v12.3.0","date":"2019-05-21","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.27","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v12.2.0","date":"2019-05-07","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.21","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v12.1.0","date":"2019-04-29","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.21","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v12.0.0","date":"2019-04-23","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"7.4.288.21","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"72","lts":false,"security":false}, +{"version":"v11.15.0","date":"2019-04-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.27.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"67","lts":false,"security":false}, +{"version":"v11.14.0","date":"2019-04-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.27.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"67","lts":false,"security":false}, +{"version":"v11.13.0","date":"2019-03-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.27.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"67","lts":false,"security":false}, +{"version":"v11.12.0","date":"2019-03-14","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.26.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"67","lts":false,"security":false}, +{"version":"v11.11.0","date":"2019-03-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.26.0","zlib":"1.2.11","openssl":"1.1.1a","modules":"67","lts":false,"security":false}, +{"version":"v11.10.1","date":"2019-02-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.26.0","zlib":"1.2.11","openssl":"1.1.1a","modules":"67","lts":false,"security":true}, +{"version":"v11.10.0","date":"2019-02-14","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.7.0","v8":"7.0.276.38","uv":"1.26.0","zlib":"1.2.11","openssl":"1.1.1a","modules":"67","lts":false,"security":false}, +{"version":"v11.9.0","date":"2019-01-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.5.0","v8":"7.0.276.38","uv":"1.25.0","zlib":"1.2.11","openssl":"1.1.1a","modules":"67","lts":false,"security":false}, +{"version":"v11.8.0","date":"2019-01-24","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.5.0","v8":"7.0.276.38","uv":"1.25.0","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":false}, +{"version":"v11.7.0","date":"2019-01-17","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.5.0","v8":"7.0.276.38","uv":"1.24.1","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":false}, +{"version":"v11.6.0","date":"2018-12-26","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.5.0-next.0","v8":"7.0.276.38","uv":"1.24.1","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":false}, +{"version":"v11.5.0","date":"2018-12-18","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.38","uv":"1.24.0","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":false}, +{"version":"v11.4.0","date":"2018-12-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.38","uv":"1.24.0","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":false}, +{"version":"v11.3.0","date":"2018-11-27","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.38","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"67","lts":false,"security":true}, +{"version":"v11.2.0","date":"2018-11-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.38","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0i","modules":"67","lts":false,"security":false}, +{"version":"v11.1.0","date":"2018-10-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0i","modules":"67","lts":false,"security":false}, +{"version":"v11.0.0","date":"2018-10-23","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"7.0.276.28","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0i","modules":"67","lts":false,"security":false}, +{"version":"v10.18.0","date":"2019-12-16","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.4","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"64","lts":"Dubnium","security":true}, +{"version":"v10.17.0","date":"2019-10-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.11.3","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1d","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.16.3","date":"2019-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"64","lts":"Dubnium","security":true}, +{"version":"v10.16.2","date":"2019-08-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.16.1","date":"2019-07-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1c","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.16.0","date":"2019-05-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.9.0","v8":"6.8.275.32","uv":"1.28.0","zlib":"1.2.11","openssl":"1.1.1b","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.15.3","date":"2019-03-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.15.2","date":"2019-02-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":true}, +{"version":"v10.15.1","date":"2019-01-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.15.0","date":"2018-12-26","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.14.2","date":"2018-12-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.14.1","date":"2018-11-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.14.0","date":"2018-11-27","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0j","modules":"64","lts":"Dubnium","security":true}, +{"version":"v10.13.0","date":"2018-10-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0i","modules":"64","lts":"Dubnium","security":false}, +{"version":"v10.12.0","date":"2018-10-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.2","zlib":"1.2.11","openssl":"1.1.0i","modules":"64","lts":false,"security":false}, +{"version":"v10.11.0","date":"2018-09-19","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.32","uv":"1.23.0","zlib":"1.2.11","openssl":"1.1.0i","modules":"64","lts":false,"security":false}, +{"version":"v10.10.0","date":"2018-09-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.8.275.30","uv":"1.23.0","zlib":"1.2.11","openssl":"1.1.0i","modules":"64","lts":false,"security":false}, +{"version":"v10.9.0","date":"2018-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.2.0","v8":"6.8.275.24","uv":"1.22.0","zlib":"1.2.11","openssl":"1.1.0i","modules":"64","lts":false,"security":false}, +{"version":"v10.8.0","date":"2018-08-01","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.2.0","v8":"6.7.288.49","uv":"1.22.0","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.7.0","date":"2018-07-18","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.7.288.49","uv":"1.22.0","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.6.0","date":"2018-07-04","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.7.288.46","uv":"1.21.0","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.5.0","date":"2018-06-20","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.7.288.46","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.4.1","date":"2018-06-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.7.288.45","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.4.0","date":"2018-06-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.7.288.43","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.3.0","date":"2018-05-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.1.0","v8":"6.6.346.32","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.2.1","date":"2018-05-24","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.6.346.32","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.2.0","date":"2018-05-23","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.6.346.32","uv":"1.20.3","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.1.0","date":"2018-05-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.6.346.27","uv":"1.20.2","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v10.0.0","date":"2018-04-24","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","osx-x64-pkg","osx-x64-tar","src","sunos-x64","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.6.346.24","uv":"1.20.2","zlib":"1.2.11","openssl":"1.1.0h","modules":"64","lts":false,"security":false}, +{"version":"v9.11.2","date":"2018-06-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2o","modules":"59","lts":false,"security":false}, +{"version":"v9.11.1","date":"2018-04-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2o","modules":"59","lts":false,"security":false}, +{"version":"v9.11.0","date":"2018-04-04","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2o","modules":"59","lts":false,"security":false}, +{"version":"v9.10.1","date":"2018-03-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2o","modules":"59","lts":false,"security":false}, +{"version":"v9.10.0","date":"2018-03-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2o","modules":"59","lts":false,"security":true}, +{"version":"v9.9.0","date":"2018-03-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.8.0","date":"2018-03-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.7.1","date":"2018-03-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.7.0","date":"2018-03-01","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.6.1","date":"2018-02-23","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.6.0","date":"2018-02-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.5.0","date":"2018-01-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.4.0","date":"2018-01-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.46","uv":"1.18.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.3.0","date":"2017-12-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.2.414.46","uv":"1.18.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.2.1","date":"2017-12-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.2.414.44","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"59","lts":false,"security":false}, +{"version":"v9.2.0","date":"2017-11-14","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.2.414.44","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2m","modules":"59","lts":false,"security":false}, +{"version":"v9.1.0","date":"2017-11-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.2.414.32","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2m","modules":"59","lts":false,"security":false}, +{"version":"v9.0.0","date":"2017-10-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.2.414.32","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"59","lts":false,"security":false}, +{"version":"v8.17.0","date":"2019-12-17","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.13.4","v8":"6.2.414.78","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2s","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.16.2","date":"2019-10-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.78","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2s","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.16.1","date":"2019-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.77","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2r","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.16.0","date":"2019-04-16","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.77","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2r","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.15.1","date":"2019-02-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.75","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2r","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.15.0","date":"2018-12-26","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.75","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2q","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.14.1","date":"2018-12-18","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.75","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2q","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.14.0","date":"2018-11-27","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.72","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2q","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.13.0","date":"2018-11-20","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.72","uv":"1.23.2","zlib":"1.2.11","openssl":"1.0.2p","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.12.0","date":"2018-09-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"6.4.1","v8":"6.2.414.66","uv":"1.19.2","zlib":"1.2.11","openssl":"1.0.2p","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.11.4","date":"2018-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.54","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2p","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.11.3","date":"2018-06-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.54","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.11.2","date":"2018-05-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.54","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.11.1","date":"2018-03-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.50","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.11.0","date":"2018-03-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.50","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.10.0","date":"2018-03-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.2.414.50","uv":"1.19.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.9.4","date":"2018-01-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.6.0","v8":"6.1.534.50","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.9.3","date":"2017-12-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.1.534.48","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"57","lts":"Carbon","security":true}, +{"version":"v8.9.2","date":"2017-12-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.1.534.48","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2m","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.9.1","date":"2017-11-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.1.534.47","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2m","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.9.0","date":"2017-10-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.5.1","v8":"6.1.534.46","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":"Carbon","security":false}, +{"version":"v8.8.1","date":"2017-10-25","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.4.2","v8":"6.1.534.42","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.8.0","date":"2017-10-24","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.4.2","v8":"6.1.534.42","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.7.0","date":"2017-10-11","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.4.2","v8":"6.1.534.42","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.6.0","date":"2017-09-26","files":["aix-ppc64","headers","linux-arm64","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"6.0.287.53","uv":"1.14.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.5.0","date":"2017-09-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"6.0.287.53","uv":"1.14.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.4.0","date":"2017-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"6.0.286.52","uv":"1.13.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.3.0","date":"2017-08-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"6.0.286.52","uv":"1.13.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.2.1","date":"2017-07-20","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"5.8.283.41","uv":"1.13.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.2.0","date":"2017-07-19","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.3.0","v8":"5.8.283.41","uv":"1.13.1","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.1.4","date":"2017-07-11","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.3","v8":"5.8.283.41","uv":"1.12.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":true}, +{"version":"v8.1.3","date":"2017-06-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.3","v8":"5.8.283.41","uv":"1.12.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.1.2","date":"2017-06-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.3","v8":"5.8.283.41","uv":"1.12.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.1.1","date":"2017-06-13","files":["aix-ppc64","headers","linux-arm64","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.3","v8":"5.8.283.41","uv":"1.12.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.1.0","date":"2017-06-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.3","v8":"5.8.283.41","uv":"1.12.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"57","lts":false,"security":false}, +{"version":"v8.0.0","date":"2017-05-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"5.0.0","v8":"5.8.283.41","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"57","lts":false,"security":false}, +{"version":"v7.10.1","date":"2017-07-11","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.2.0","v8":"5.5.372.43","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":true}, +{"version":"v7.10.0","date":"2017-05-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.2.0","v8":"5.5.372.43","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.9.0","date":"2017-04-11","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.2.0","v8":"5.5.372.43","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.8.0","date":"2017-03-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.2.0","v8":"5.5.372.43","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.7.4","date":"2017-03-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.42","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.7.3","date":"2017-03-14","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.41","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.7.2","date":"2017-03-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.41","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.7.1","date":"2017-03-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.41","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.7.0","date":"2017-02-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.41","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.6.0","date":"2017-02-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.5.372.40","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.5.0","date":"2017-01-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.1.2","v8":"5.4.500.48","uv":"1.10.2","zlib":"1.2.8","openssl":"1.0.2k","modules":"51","lts":false,"security":false}, +{"version":"v7.4.0","date":"2017-01-04","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"4.0.5","v8":"5.4.500.45","uv":"1.10.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v7.3.0","date":"2016-12-20","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.4.500.45","uv":"1.10.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v7.2.1","date":"2016-12-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.4.500.44","uv":"1.10.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v7.2.0","date":"2016-11-22","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.9","v8":"5.4.500.43","uv":"1.10.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v7.1.0","date":"2016-11-08","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.9","v8":"5.4.500.36","uv":"1.10.0","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v7.0.0","date":"2016-10-25","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.8","v8":"5.4.500.36","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"51","lts":false,"security":false}, +{"version":"v6.17.1","date":"2019-04-03","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2r","modules":"48","lts":"Boron","security":false}, +{"version":"v6.17.0","date":"2019-02-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2r","modules":"48","lts":"Boron","security":true}, +{"version":"v6.16.0","date":"2018-12-26","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2q","modules":"48","lts":"Boron","security":false}, +{"version":"v6.15.1","date":"2018-12-03","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2q","modules":"48","lts":"Boron","security":false}, +{"version":"v6.15.0","date":"2018-11-27","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2q","modules":"48","lts":"Boron","security":true}, +{"version":"v6.14.4","date":"2018-08-15","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2p","modules":"48","lts":"Boron","security":true}, +{"version":"v6.14.3","date":"2018-06-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"48","lts":"Boron","security":false}, +{"version":"v6.14.2","date":"2018-04-30","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"48","lts":"Boron","security":false}, +{"version":"v6.14.1","date":"2018-03-29","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"48","lts":"Boron","security":false}, +{"version":"v6.14.0","date":"2018-03-28","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"48","lts":"Boron","security":true}, +{"version":"v6.13.1","date":"2018-03-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"48","lts":"Boron","security":false}, +{"version":"v6.13.0","date":"2018-02-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.16.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"48","lts":"Boron","security":false}, +{"version":"v6.12.3","date":"2018-01-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.111","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"48","lts":"Boron","security":false}, +{"version":"v6.12.2","date":"2017-12-07","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.109","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2n","modules":"48","lts":"Boron","security":true}, +{"version":"v6.12.1","date":"2017-12-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.109","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2m","modules":"48","lts":"Boron","security":false}, +{"version":"v6.12.0","date":"2017-11-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.108","uv":"1.15.0","zlib":"1.2.11","openssl":"1.0.2m","modules":"48","lts":"Boron","security":false}, +{"version":"v6.11.5","date":"2017-10-24","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.108","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"48","lts":"Boron","security":true}, +{"version":"v6.11.4","date":"2017-10-03","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.108","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"48","lts":"Boron","security":false}, +{"version":"v6.11.3","date":"2017-09-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.107","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"48","lts":"Boron","security":false}, +{"version":"v6.11.2","date":"2017-08-01","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.103","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2l","modules":"48","lts":"Boron","security":false}, +{"version":"v6.11.1","date":"2017-07-10","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.103","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"48","lts":"Boron","security":true}, +{"version":"v6.11.0","date":"2017-06-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.102","uv":"1.11.0","zlib":"1.2.11","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.10.3","date":"2017-05-02","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.101","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.10.2","date":"2017-04-04","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.98","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.10.1","date":"2017-03-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.95","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.10.0","date":"2017-02-21","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.93","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.5","date":"2017-01-31","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.89","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.4","date":"2017-01-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.89","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.3","date":"2017-01-05","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.10","v8":"5.1.281.89","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.2","date":"2016-12-06","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.9","v8":"5.1.281.88","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.1","date":"2016-10-19","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.8","v8":"5.1.281.84","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":"Boron","security":false}, +{"version":"v6.9.0","date":"2016-10-18","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.8","v8":"5.1.281.84","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":"Boron","security":false}, +{"version":"v6.8.1","date":"2016-10-14","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.8","v8":"5.1.281.84","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":false,"security":false}, +{"version":"v6.8.0","date":"2016-10-12","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.8","v8":"5.1.281.84","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":false,"security":false}, +{"version":"v6.7.0","date":"2016-09-27","files":["aix-ppc64","headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.1.281.83","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"48","lts":false,"security":true}, +{"version":"v6.6.0","date":"2016-09-14","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-s390x","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.1.281.83","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.5.0","date":"2016-08-26","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.1.281.81","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.4.0","date":"2016-08-12","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.0.71.60","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.3.1","date":"2016-07-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.0.71.57","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.3.0","date":"2016-07-06","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.10.3","v8":"5.0.71.52","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.2.2","date":"2016-06-16","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.9.5","v8":"5.0.71.52","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.2.1","date":"2016-06-02","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"3.9.3","v8":"5.0.71.52","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.2.0","date":"2016-05-17","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.9","v8":"5.0.71.47","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.1.0","date":"2016-05-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.6","v8":"5.0.71.35","uv":"1.9.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"48","lts":false,"security":false}, +{"version":"v6.0.0","date":"2016-04-26","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.6","v8":"5.0.71.35","uv":"1.9.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"48","lts":false,"security":false}, +{"version":"v5.12.0","date":"2016-06-23","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.6","v8":"4.6.85.32","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"47","lts":false,"security":false}, +{"version":"v5.11.1","date":"2016-05-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.6","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"47","lts":false,"security":false}, +{"version":"v5.11.0","date":"2016-04-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.6","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.10.1","date":"2016-04-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.3","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.10.0","date":"2016-04-01","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.8.3","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.9.1","date":"2016-03-22","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.7.3","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.9.0","date":"2016-03-16","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.7.3","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.8.0","date":"2016-03-09","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.7.3","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.7.1","date":"2016-03-02","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.6.0","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"47","lts":false,"security":false}, +{"version":"v5.7.0","date":"2016-02-23","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.6.0","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2f","modules":"47","lts":false,"security":false}, +{"version":"v5.6.0","date":"2016-02-09","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.6.0","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2f","modules":"47","lts":false,"security":false}, +{"version":"v5.5.0","date":"2016-01-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.4.1","date":"2016-01-12","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.4.0","date":"2016-01-06","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.3.0","date":"2015-12-15","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.2.0","date":"2015-12-09","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.1.1","date":"2015-12-03","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2e","modules":"47","lts":false,"security":false}, +{"version":"v5.1.0","date":"2015-11-17","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.12","v8":"4.6.85.31","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"47","lts":false,"security":false}, +{"version":"v5.0.0","date":"2015-10-29","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"3.3.6","v8":"4.6.85.28","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"47","lts":false,"security":false}, +{"version":"v4.9.1","date":"2018-03-29","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.53","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"46","lts":"Argon","security":false}, +{"version":"v4.9.0","date":"2018-03-28","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.53","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2o","modules":"46","lts":"Argon","security":true}, +{"version":"v4.8.7","date":"2017-12-07","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.53","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2n","modules":"46","lts":"Argon","security":true}, +{"version":"v4.8.6","date":"2017-11-06","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.53","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2m","modules":"46","lts":"Argon","security":false}, +{"version":"v4.8.5","date":"2017-10-24","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.47","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"46","lts":"Argon","security":true}, +{"version":"v4.8.4","date":"2017-07-11","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.47","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"46","lts":"Argon","security":true}, +{"version":"v4.8.3","date":"2017-05-02","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.47","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"46","lts":"Argon","security":false}, +{"version":"v4.8.2","date":"2017-04-04","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.46","uv":"1.9.1","zlib":"1.2.11","openssl":"1.0.2k","modules":"46","lts":"Argon","security":false}, +{"version":"v4.8.1","date":"2017-03-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.46","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"46","lts":"Argon","security":false}, +{"version":"v4.8.0","date":"2017-02-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.45","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"46","lts":"Argon","security":false}, +{"version":"v4.7.3","date":"2017-01-31","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.43","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2k","modules":"46","lts":"Argon","security":false}, +{"version":"v4.7.2","date":"2017-01-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.43","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":false}, +{"version":"v4.7.1","date":"2017-01-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.43","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":false}, +{"version":"v4.7.0","date":"2016-12-06","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.43","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":false}, +{"version":"v4.6.2","date":"2016-11-08","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.11","v8":"4.5.103.42","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":false}, +{"version":"v4.6.1","date":"2016-10-18","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.9","v8":"4.5.103.37","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":true}, +{"version":"v4.6.0","date":"2016-09-27","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.9","v8":"4.5.103.37","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2j","modules":"46","lts":"Argon","security":true}, +{"version":"v4.5.0","date":"2016-08-16","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-7z","win-x64-exe","win-x64-msi","win-x64-zip","win-x86-7z","win-x86-exe","win-x86-msi","win-x86-zip"],"npm":"2.15.9","v8":"4.5.103.37","uv":"1.9.1","zlib":"1.2.8","openssl":"1.0.2h","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.7","date":"2016-06-28","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.8","v8":"4.5.103.36","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.6","date":"2016-06-23","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.5","v8":"4.5.103.36","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.5","date":"2016-05-24","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.5","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.4","date":"2016-05-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2h","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.3","date":"2016-04-12","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.2","date":"2016-04-01","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.15.0","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.1","date":"2016-03-22","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.20","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"46","lts":"Argon","security":false}, +{"version":"v4.4.0","date":"2016-03-08","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.20","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"46","lts":"Argon","security":false}, +{"version":"v4.3.2","date":"2016-03-02","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-ppc64le","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2g","modules":"46","lts":"Argon","security":false}, +{"version":"v4.3.1","date":"2016-02-16","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2f","modules":"46","lts":"Argon","security":false}, +{"version":"v4.3.0","date":"2016-02-09","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2f","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.6","date":"2016-01-21","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.5","date":"2016-01-20","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.8.0","zlib":"1.2.8","openssl":"1.0.2e","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.4","date":"2015-12-23","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.12","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2e","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.3","date":"2015-12-03","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.7","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2e","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.2","date":"2015-11-03","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.7","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.1","date":"2015-10-13","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.7","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":"Argon","security":false}, +{"version":"v4.2.0","date":"2015-10-12","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.7","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":"Argon","security":false}, +{"version":"v4.1.2","date":"2015-10-05","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.4","v8":"4.5.103.35","uv":"1.7.5","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":false,"security":false}, +{"version":"v4.1.1","date":"2015-09-23","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.4","v8":"4.5.103.33","uv":"1.7.4","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":false,"security":false}, +{"version":"v4.1.0","date":"2015-09-17","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.3","v8":"4.5.103.33","uv":"1.7.4","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":false,"security":false}, +{"version":"v4.0.0","date":"2015-09-08","files":["headers","linux-arm64","linux-armv6l","linux-armv7l","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"2.14.2","v8":"4.5.103.30","uv":"1.7.3","zlib":"1.2.8","openssl":"1.0.2d","modules":"46","lts":false,"security":false}, +{"version":"v0.12.18","date":"2017-02-22","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.11","v8":"3.28.71.20","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1u","modules":"14","lts":false,"security":false}, +{"version":"v0.12.17","date":"2016-10-18","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1u","modules":"14","lts":false,"security":true}, +{"version":"v0.12.16","date":"2016-09-27","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1u","modules":"14","lts":false,"security":true}, +{"version":"v0.12.15","date":"2016-06-23","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1t","modules":"14","lts":false,"security":true}, +{"version":"v0.12.14","date":"2016-05-06","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1t","modules":"14","lts":false,"security":false}, +{"version":"v0.12.13","date":"2016-03-31","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.0","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1s","modules":"14","lts":false,"security":false}, +{"version":"v0.12.12","date":"2016-03-08","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.14.9","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1s","modules":"14","lts":false,"security":false}, +{"version":"v0.12.11","date":"2016-03-03","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.14.9","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1s","modules":"14","lts":false,"security":false}, +{"version":"v0.12.10","date":"2016-02-09","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.14.9","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1r","modules":"14","lts":false,"security":false}, +{"version":"v0.12.9","date":"2015-12-03","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.14.9","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1q","modules":"14","lts":false,"security":false}, +{"version":"v0.12.8","date":"2015-11-24","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.14.9","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1p","modules":"14","lts":false,"security":false}, +{"version":"v0.12.7","date":"2015-07-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.11.3","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1p","modules":"14","lts":false,"security":false}, +{"version":"v0.12.6","date":"2015-07-04","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.11.2","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1o","modules":"14","lts":false,"security":false}, +{"version":"v0.12.5","date":"2015-06-22","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.11.2","v8":"3.28.71.19","uv":"1.6.1","zlib":"1.2.8","openssl":"1.0.1o","modules":"14","lts":false,"security":false}, +{"version":"v0.12.4","date":"2015-05-23","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.10.1","v8":"3.28.71.19","uv":"1.5.0","zlib":"1.2.8","openssl":"1.0.1m","modules":"14","lts":false,"security":false}, +{"version":"v0.12.3","date":"2015-05-14","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.9.1","v8":"3.28.71.19","uv":"1.5.0","zlib":"1.2.8","openssl":"1.0.1m","modules":"14","lts":false,"security":false}, +{"version":"v0.12.2","date":"2015-03-31","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.7.4","v8":"3.28.73.0","uv":"1.4.2","zlib":"1.2.8","openssl":"1.0.1m","modules":"14","lts":false,"security":false}, +{"version":"v0.12.1","date":"2015-03-24","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.5.1","v8":"3.28.73.0","uv":"1.0.2","zlib":"1.2.8","openssl":"1.0.1m","modules":"14","lts":false,"security":false}, +{"version":"v0.12.0","date":"2015-02-06","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.5.1","v8":"3.28.73.0","uv":"1.0.2","zlib":"1.2.8","openssl":"1.0.1l","modules":"14","lts":false,"security":false}, +{"version":"v0.11.16","date":"2015-01-30","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.3.0","v8":"3.28.73.0","uv":"1.0.2","zlib":"1.2.8","openssl":"1.0.1l","modules":"14","lts":false,"security":false}, +{"version":"v0.11.15","date":"2015-01-20","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.1.6","v8":"3.28.73.0","uv":"1.0.2","zlib":"1.2.8","openssl":"1.0.1j","modules":"14","lts":false,"security":false}, +{"version":"v0.11.14","date":"2014-08-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.0.0","v8":"3.26.33.0","uv":"1.0.0","zlib":"1.2.3","openssl":"1.0.1i","modules":"14","lts":false,"security":false}, +{"version":"v0.11.13","date":"2014-05-02","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.9","v8":"3.25.30.0","uv":"0.11.25","zlib":"1.2.3","openssl":"1.0.1g","modules":"14","lts":false,"security":false}, +{"version":"v0.11.12","date":"2014-03-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.3","v8":"3.22.24.19","uv":"0.11.22","zlib":"1.2.3","openssl":"1.0.1f","modules":"14","lts":false,"security":false}, +{"version":"v0.11.11","date":"2014-01-29","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.25","v8":"3.22.24.19","uv":"0.11.18","zlib":"1.2.3","openssl":"1.0.1f","modules":"14","lts":false,"security":false}, +{"version":"v0.11.10","date":"2013-12-31","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.22","v8":"3.22.24.10","uv":"0.11.17","zlib":"1.2.3","openssl":"1.0.1e","modules":"13","lts":false,"security":false}, +{"version":"v0.11.9","date":"2013-11-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.15","v8":"3.22.24.5","uv":"0.11.15","zlib":"1.2.3","openssl":"1.0.1e","modules":"13","lts":false,"security":false}, +{"version":"v0.11.8","date":"2013-10-30","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.13","v8":"3.21.18.3","uv":"0.11.14","zlib":"1.2.3","openssl":"1.0.1e","modules":"13","lts":false,"security":false}, +{"version":"v0.11.7","date":"2013-09-04","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.8","v8":"3.20.17.0","uv":"0.11.13","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.6","date":"2013-08-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x86-msi"],"npm":"1.3.8","v8":"3.20.14.1","uv":"0.11.8","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.5","date":"2013-08-07","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.6","v8":"3.20.11.0","uv":"0.11.7","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.4","date":"2013-07-12","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x86-msi"],"npm":"1.3.4","v8":"3.20.2.0","uv":"0.11.5","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.3","date":"2013-06-26","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.25","v8":"3.19.13.0","uv":"0.11.5","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.2","date":"2013-05-13","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.21","v8":"3.19.0.0","uv":"0.11.2","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.1","date":"2013-04-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.18","v8":"3.18.0.0","uv":"0.11.1","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.11.0","date":"2013-03-28","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.15","v8":"3.17.13.0","uv":"0.10.3","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000C","lts":false,"security":false}, +{"version":"v0.10.48","date":"2016-10-18","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.14.5.11","uv":"0.10.37","zlib":"1.2.8","openssl":"1.0.1u","modules":"11","lts":false,"security":true}, +{"version":"v0.10.47","date":"2016-09-27","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.14.5.11","uv":"0.10.37","zlib":"1.2.8","openssl":"1.0.1u","modules":"11","lts":false,"security":true}, +{"version":"v0.10.46","date":"2016-06-23","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.14.5.9","uv":"0.10.37","zlib":"1.2.8","openssl":"1.0.1t","modules":"11","lts":false,"security":true}, +{"version":"v0.10.45","date":"2016-05-06","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.1","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1t","modules":"11","lts":false,"security":false}, +{"version":"v0.10.44","date":"2016-03-31","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"2.15.0","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1s","modules":"11","lts":false,"security":false}, +{"version":"v0.10.43","date":"2016-03-03","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.29","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1s","modules":"11","lts":false,"security":false}, +{"version":"v0.10.42","date":"2016-02-09","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.29","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1r","modules":"11","lts":false,"security":false}, +{"version":"v0.10.41","date":"2015-12-03","files":["headers","linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.29","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1q","modules":"11","lts":false,"security":false}, +{"version":"v0.10.40","date":"2015-07-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1p","modules":"11","lts":false,"security":false}, +{"version":"v0.10.39","date":"2015-06-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1o","modules":"11","lts":false,"security":false}, +{"version":"v0.10.38","date":"2015-03-23","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1m","modules":"11","lts":false,"security":false}, +{"version":"v0.10.37","date":"2015-03-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.36","zlib":"1.2.8","openssl":"1.0.1l","modules":"11","lts":false,"security":false}, +{"version":"v0.10.36","date":"2015-01-26","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.30","zlib":"1.2.8","openssl":"1.0.1l","modules":"11","lts":false,"security":false}, +{"version":"v0.10.35","date":"2014-12-22","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.30","zlib":"1.2.8","openssl":"1.0.1j","modules":"11","lts":false,"security":false}, +{"version":"v0.10.34","date":"2014-12-17","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.30","zlib":"1.2.8","openssl":"1.0.1j","modules":"11","lts":false,"security":false}, +{"version":"v0.10.33","date":"2014-10-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.29","zlib":"1.2.3","openssl":"1.0.1j","modules":"11","lts":false,"security":false}, +{"version":"v0.10.32","date":"2014-09-16","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.28","v8":"3.14.5.9","uv":"0.10.28","zlib":"1.2.3","openssl":"1.0.1i","modules":"11","lts":false,"security":false}, +{"version":"v0.10.31","date":"2014-08-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.23","v8":"3.14.5.9","uv":"0.10.28","zlib":"1.2.3","openssl":"1.0.1i","modules":"11","lts":false,"security":false}, +{"version":"v0.10.30","date":"2014-07-31","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.21","v8":"3.14.5.9","uv":"0.10.28","zlib":"1.2.3","openssl":"1.0.1h","modules":"11","lts":false,"security":false}, +{"version":"v0.10.29","date":"2014-06-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.14","v8":"3.14.5.9","uv":"0.10.27","zlib":"1.2.3","openssl":"1.0.1h","modules":"11","lts":false,"security":false}, +{"version":"v0.10.28","date":"2014-05-02","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.9","v8":"3.14.5.9","uv":"0.10.27","zlib":"1.2.3","openssl":"1.0.1g","modules":"11","lts":false,"security":false}, +{"version":"v0.10.27","date":"2014-05-01","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.8","v8":"3.14.5.9","uv":"0.10.27","zlib":"1.2.3","openssl":"1.0.1g","modules":"11","lts":false,"security":false}, +{"version":"v0.10.26","date":"2014-02-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.4.3","v8":"3.14.5.9","uv":"0.10.25","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.25","date":"2014-01-23","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.24","v8":"3.14.5.9","uv":"0.10.23","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.24","date":"2013-12-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.21","v8":"3.14.5.9","uv":"0.10.21","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.23","date":"2013-12-12","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.17","v8":"3.14.5.9","uv":"0.10.20","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.22","date":"2013-11-12","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.14","v8":"3.14.5.9","uv":"0.10.19","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.21","date":"2013-10-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.11","v8":"3.14.5.9","uv":"0.10.18","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.20","date":"2013-09-30","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.11","v8":"3.14.5.9","uv":"0.10.17","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.19","date":"2013-09-24","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.11","v8":"3.14.5.9","uv":"0.10.17","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.18","date":"2013-09-04","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.8","v8":"3.14.5.9","uv":"0.10.15","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.17","date":"2013-08-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.8","v8":"3.14.5.9","uv":"0.10.14","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.16","date":"2013-08-16","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.8","v8":"3.14.5.9","uv":"0.10.13","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.15","date":"2013-07-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.5","v8":"3.14.5.9","uv":"0.10.13","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.14","date":"2013-07-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.5","v8":"3.14.5.9","uv":"0.10.13","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.13","date":"2013-07-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.3.2","v8":"3.14.5.9","uv":"0.10.12","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.12","date":"2013-06-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.32","v8":"3.14.5.9","uv":"0.10.11","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.11","date":"2013-06-13","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.30","v8":"3.14.5.9","uv":"0.10.11","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.10","date":"2013-06-04","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.25","v8":"3.14.5.9","uv":"0.10.10","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.9","date":"2013-05-30","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.24","v8":"3.14.5.9","uv":"0.10.9","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.8","date":"2013-05-24","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.23","v8":"3.14.5.9","uv":"0.10.8","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.7","date":"2013-05-17","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.21","v8":"3.14.5.8","uv":"0.10.7","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.6","date":"2013-05-14","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.18","v8":"3.14.5.8","uv":"0.10.5","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.5","date":"2013-04-23","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.18","v8":"3.14.5.8","uv":"0.10.5","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.4","date":"2013-04-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.18","v8":"3.14.5.8","uv":"0.10.4","zlib":"1.2.3","openssl":"1.0.1e","modules":"11","lts":false,"security":false}, +{"version":"v0.10.3","date":"2013-04-03","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.17","v8":"3.14.5.8","uv":"0.10.3","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.10.2","date":"2013-03-28","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.15","v8":"3.14.5.8","uv":"0.10.3","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.10.1","date":"2013-03-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.15","v8":"3.14.5.8","uv":"0.10","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.10.0","date":"2013-03-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.14","v8":"3.14.5.8","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.9.12","date":"2013-03-06","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.12","v8":"3.14.5.8","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.9.11","date":"2013-03-01","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.12","v8":"3.14.5.0","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1e","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.9.10","date":"2013-02-19","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.12","v8":"3.15.11.15","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.9.9","date":"2013-02-07","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.10","v8":"3.15.11.10","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000B","lts":false,"security":false}, +{"version":"v0.9.8","date":"2013-01-24","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.3","v8":"3.15.11.10","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.7","date":"2013-01-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.2","v8":"3.15.11.7","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.6","date":"2013-01-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.0","v8":"3.15.11.5","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.5","date":"2012-12-30","files":["linux-x64","linux-x86","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.70","v8":"3.13.7.4","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.4","date":"2012-12-21","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.70","v8":"3.13.7.4","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.3","date":"2012-10-24","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.64","v8":"3.13.7.4","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.2","date":"2012-09-17","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.61","v8":"3.11.10.22","uv":"0.9","zlib":"1.2.3","openssl":"1.0.1c","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.1","date":"2012-08-28","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.59","v8":"3.11.10.19","uv":"0.9","zlib":"1.2.3","openssl":"1.0.0f","modules":"0x000A","lts":false,"security":false}, +{"version":"v0.9.0","date":"2012-07-20","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.44","v8":"3.11.10.15","uv":"0.9","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.28","date":"2014-07-31","files":["linux-x64","linux-x86","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.30","v8":"3.11.10.26","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.27","date":"2014-06-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x86-msi"],"npm":"1.2.30","v8":"3.11.10.26","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.26","date":"2013-10-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.30","v8":"3.11.10.26","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.25","date":"2013-06-13","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.30","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.24","date":"2013-06-03","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.24","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.23","date":"2013-04-09","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.18","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.22","date":"2013-03-06","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.14","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.21","date":"2013-02-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.11","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.20","date":"2013-02-15","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.11","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.19","date":"2013-02-06","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.10","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.18","date":"2013-01-18","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.2","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.17","date":"2013-01-10","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.2.0","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.16","date":"2012-12-12","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.69","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.15","date":"2012-11-26","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.66","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.14","date":"2012-10-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.65","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.13","date":"2012-10-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.65","v8":"3.11.10.25","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.12","date":"2012-10-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.63","v8":"3.11.10.22","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.11","date":"2012-09-27","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.62","v8":"3.11.10.22","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.10","date":"2012-09-25","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.62","v8":"3.11.10.22","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.9","date":"2012-09-11","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.61","v8":"3.11.10.22","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.8","date":"2012-08-22","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"1.1.59","v8":"3.11.10.19","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.7","date":"2012-08-15","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.49","v8":"3.11.10.17","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.6","date":"2012-08-06","files":["linux-x64","linux-x86","osx-x64-pkg","osx-x64-tar","osx-x86-tar","src","sunos-x64","sunos-x86","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.48","v8":"3.11.10.17","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.5","date":"2012-08-02","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.46","v8":"3.11.10.17","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.4","date":"2012-07-24","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.45","v8":"3.11.10.17","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.3","date":"2012-07-17","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.43","v8":"3.11.10.15","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.2","date":"2012-07-09","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.36","v8":"3.11.10.14","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.1","date":"2012-06-29","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.33","v8":"3.11.10.12","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.8.0","date":"2012-06-22","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.32","v8":"3.11.10.10","uv":"0.8","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.12","date":"2012-06-19","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe","win-x86-msi"],"npm":"1.1.30","v8":"3.11.10.0","uv":"0.6","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.11","date":"2012-06-15","files":["osx-x64-pkg","src","win-x64-exe","win-x64-msi","win-x86-exe","win-x86-msi"],"npm":"1.1.26","v8":"3.11.10.0","uv":"0.6","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.10","date":"2012-06-11","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.25","v8":"3.9.24.31","uv":"0.6","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.9","date":"2012-05-29","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.23","v8":"3.11.1.0","uv":"0.6","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.8","date":"2012-04-18","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.18","v8":"3.9.24.9","uv":"0.6","zlib":"1.2.3","openssl":"1.0.0f","modules":"1","lts":false,"security":false}, +{"version":"v0.7.7","date":"2012-03-30","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.15","v8":"3.9.24.7","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.6","date":"2012-03-13","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.8","v8":"3.9.17.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.5","date":"2012-02-23","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.1","v8":"3.9.5.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.4","date":"2012-02-14","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.1","v8":"3.9.5.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.3","date":"2012-02-07","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-3","v8":"3.9.2.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.2","date":"2012-02-01","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-3","v8":"3.8.9.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.1","date":"2012-01-23","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-2","v8":"3.8.8.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.7.0","date":"2012-01-17","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-2","v8":"3.8.6.0","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.21","date":"2012-08-03","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.37","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.20","date":"2012-07-10","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.37","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.19","date":"2012-06-06","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.24","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.18","date":"2012-05-14","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.21","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.17","date":"2012-05-04","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.21","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.16","date":"2012-04-27","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.19","v8":"3.6.6.25","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.15","date":"2012-04-08","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.16","v8":"3.6.6.24","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.14","date":"2012-03-23","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.12","v8":"3.6.6.24","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.13","date":"2012-03-15","files":["osx-x64-pkg","src","win-x64-exe","win-x86-exe"],"npm":"1.1.9","v8":"3.6.6.24","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.12","date":"2012-03-02","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.4","v8":"3.6.6.24","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.11","date":"2012-02-08","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.1","v8":"3.6.6.20","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.10","date":"2012-02-03","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-3","v8":"3.6.6.20","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.9","date":"2012-01-27","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-3","v8":"3.6.6.19","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.8","date":"2012-01-20","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-2","v8":"3.6.6.19","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.7","date":"2012-01-07","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-beta-10","v8":"3.6.6.15","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.6","date":"2011-12-15","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-beta-4","v8":"3.6.6.14","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.5","date":"2011-12-04","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-alpha-6","v8":"3.6.6.11","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.4","date":"2011-12-02","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-alpha-6","v8":"3.6.6.8","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.3","date":"2011-11-25","files":["osx-x64-pkg","src","win-x86-exe"],"npm":"1.1.0-alpha-2","v8":"3.6.6.8","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.2","date":"2011-11-18","files":["osx-x64-pkg","src","win-x86-exe"],"v8":"3.6.6.8","uv":"0.6","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.1","date":"2011-11-11","files":["osx-x64-pkg","src","win-x86-exe"],"v8":"3.6.6.7","uv":"0.1","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.6.0","date":"2011-11-04","files":["src","win-x86-exe"],"v8":"3.6.6.6","uv":"0.1","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.10","date":"2011-10-22","files":["src","win-x86-exe"],"v8":"3.7.0.0","uv":"0.1","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.9","date":"2011-10-11","files":["src","win-x86-exe"],"v8":"3.6.4.0","uv":"0.1","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.8","date":"2011-09-30","files":["src","win-x86-exe"],"v8":"3.6.4.0","uv":"0.1","zlib":"1.2.3","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.7","date":"2011-09-16","files":["src","win-x86-exe"],"v8":"3.6.4.0","uv":"0.1","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.6","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.6.2.0","uv":"0.1","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.5","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.5.8.0","uv":"0.1","openssl":"0.9.8r","modules":"1","lts":false,"security":false}, +{"version":"v0.5.4","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.5.4.3","uv":"0.1","modules":"1","lts":false,"security":false}, +{"version":"v0.5.3","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.4.14.0","uv":"0.1","modules":"1","lts":false,"security":false}, +{"version":"v0.5.2","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.4.14.0","uv":"0.1","modules":"1","lts":false,"security":false}, +{"version":"v0.5.1","date":"2011-08-26","files":["src","win-x86-exe"],"v8":"3.4.10.0","uv":"0.1","modules":"1","lts":false,"security":false}, +{"version":"v0.5.0","date":"2011-08-26","files":["src"],"v8":"3.1.8.25","modules":"1","lts":false,"security":false}, +{"version":"v0.4.12","date":"2011-09-15","files":["src"],"v8":"3.1.8.26","modules":"1","lts":false,"security":false}, +{"version":"v0.4.11","date":"2011-08-26","files":["src"],"v8":"3.1.8.26","modules":"1","lts":false,"security":false}, +{"version":"v0.4.10","date":"2011-08-26","files":["src"],"v8":"3.1.8.26","modules":"1","lts":false,"security":false}, +{"version":"v0.4.9","date":"2011-08-26","files":["src"],"v8":"3.1.8.25","modules":"1","lts":false,"security":false}, +{"version":"v0.4.8","date":"2011-08-26","files":["src"],"v8":"3.1.8.16","modules":"1","lts":false,"security":false}, +{"version":"v0.4.7","date":"2011-08-26","files":["src"],"v8":"3.1.8.10","modules":"1","lts":false,"security":false}, +{"version":"v0.4.6","date":"2011-08-26","files":["src"],"v8":"3.1.8.10","modules":"1","lts":false,"security":false}, +{"version":"v0.4.5","date":"2011-08-26","files":["src"],"v8":"3.1.8.8","modules":"1","lts":false,"security":false}, +{"version":"v0.4.4","date":"2011-08-26","files":["src"],"v8":"3.1.8.5","modules":"1","lts":false,"security":false}, +{"version":"v0.4.3","date":"2011-08-26","files":["src"],"v8":"3.1.8.3","modules":"1","lts":false,"security":false}, +{"version":"v0.4.2","date":"2011-08-26","files":["src"],"v8":"3.1.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.4.1","date":"2011-08-26","files":["src"],"v8":"3.1.5.0","modules":"1","lts":false,"security":false}, +{"version":"v0.4.0","date":"2011-08-26","files":["src"],"v8":"3.1.2.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.8","date":"2011-08-26","files":["src"],"v8":"3.1.1.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.7","date":"2011-08-26","files":["src"],"v8":"3.0.10.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.6","date":"2011-08-26","files":["src"],"v8":"3.0.9.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.5","date":"2011-08-26","files":["src"],"v8":"3.0.4.1","modules":"1","lts":false,"security":false}, +{"version":"v0.3.4","date":"2011-08-26","files":["src"],"v8":"3.0.4.1","modules":"1","lts":false,"security":false}, +{"version":"v0.3.3","date":"2011-08-26","files":["src"],"v8":"3.0.4.1","modules":"1","lts":false,"security":false}, +{"version":"v0.3.2","date":"2011-08-26","files":["src"],"v8":"3.0.3.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.1","date":"2011-08-26","files":["src"],"v8":"2.5.3.0","modules":"1","lts":false,"security":false}, +{"version":"v0.3.0","date":"2011-08-26","files":["src"],"v8":"2.5.1.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.6","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.5","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.4","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.3","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.2","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.1","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.2.0","date":"2011-08-26","files":["src"],"v8":"2.3.8.0","modules":"1","lts":false,"security":false}, +{"version":"v0.1.104","date":"2011-08-26","files":["src"],"v8":"2.3.6.1","lts":false,"security":false}, +{"version":"v0.1.103","date":"2011-08-26","files":["src"],"v8":"2.3.5.0","lts":false,"security":false}, +{"version":"v0.1.102","date":"2011-08-26","files":["src"],"v8":"2.3.2.0","lts":false,"security":false}, +{"version":"v0.1.101","date":"2011-08-26","files":["src"],"v8":"2.3.0.0","lts":false,"security":false}, +{"version":"v0.1.100","date":"2011-08-26","files":["src"],"v8":"2.2.21.0","lts":false,"security":false}, +{"version":"v0.1.99","date":"2011-08-26","files":["src"],"v8":"2.2.18.0","lts":false,"security":false}, +{"version":"v0.1.98","date":"2011-08-26","files":["src"],"v8":"2.2.16.0","lts":false,"security":false}, +{"version":"v0.1.97","date":"2011-08-26","files":["src"],"v8":"2.2.12.0","lts":false,"security":false}, +{"version":"v0.1.96","date":"2011-08-26","files":["src"],"v8":"2.2.0","lts":false,"security":false}, +{"version":"v0.1.95","date":"2011-08-26","files":["src"],"v8":"2.2.0","lts":false,"security":false}, +{"version":"v0.1.94","date":"2011-08-26","files":["src"],"v8":"2.2.8.0","lts":false,"security":false}, +{"version":"v0.1.93","date":"2011-08-26","files":["src"],"v8":"2.2.6.0","lts":false,"security":false}, +{"version":"v0.1.92","date":"2011-08-26","files":["src"],"v8":"2.2.4.2","lts":false,"security":false}, +{"version":"v0.1.91","date":"2011-08-26","files":["src"],"v8":"2.2.3.1","lts":false,"security":false}, +{"version":"v0.1.90","date":"2011-08-26","files":["src"],"v8":"2.2.0.3","lts":false,"security":false}, +{"version":"v0.1.33","date":"2011-08-26","files":["src"],"v8":"2.1.6.0","lts":false,"security":false}, +{"version":"v0.1.32","date":"2011-08-26","files":["src"],"v8":"2.1.3.0","lts":false,"security":false}, +{"version":"v0.1.31","date":"2011-08-26","files":["src"],"v8":"2.1.2.0","lts":false,"security":false}, +{"version":"v0.1.30","date":"2011-08-26","files":["src"],"v8":"2.1.1.1","lts":false,"security":false}, +{"version":"v0.1.29","date":"2011-08-26","files":["src"],"v8":"2.1.0.0","lts":false,"security":false}, +{"version":"v0.1.28","date":"2011-08-26","files":["src"],"v8":"2.1.0.0","lts":false,"security":false}, +{"version":"v0.1.27","date":"2011-08-26","files":["src"],"v8":"2.1.0.0","lts":false,"security":false}, +{"version":"v0.1.26","date":"2011-08-26","files":["src"],"v8":"2.0.6.1","lts":false,"security":false}, +{"version":"v0.1.25","date":"2011-08-26","files":["src"],"v8":"2.0.5.4","lts":false,"security":false}, +{"version":"v0.1.24","date":"2011-08-26","files":["src"],"v8":"2.0.5.4","lts":false,"security":false}, +{"version":"v0.1.23","date":"2011-08-26","files":["src"],"v8":"2.0.0","lts":false,"security":false}, +{"version":"v0.1.22","date":"2011-08-26","files":["src"],"v8":"2.0.0","lts":false,"security":false}, +{"version":"v0.1.21","date":"2011-08-26","files":["src"],"v8":"2.0.0","lts":false,"security":false}, +{"version":"v0.1.20","date":"2011-08-26","files":["src"],"v8":"2.0.2.0","lts":false,"security":false}, +{"version":"v0.1.19","date":"2011-08-26","files":["src"],"v8":"2.0.2.0","lts":false,"security":false}, +{"version":"v0.1.18","date":"2011-08-26","files":["src"],"v8":"1.3.18.0","lts":false,"security":false}, +{"version":"v0.1.17","date":"2011-08-26","files":["src"],"v8":"1.3.18.0","lts":false,"security":false}, +{"version":"v0.1.16","date":"2011-08-26","files":["src"],"v8":"1.3.18.0","lts":false,"security":false}, +{"version":"v0.1.15","date":"2011-08-26","files":["src"],"v8":"1.3.16.0","lts":false,"security":false}, +{"version":"v0.1.14","date":"2011-08-26","files":["src"],"v8":"1.3.15.0","lts":false,"security":false} +] diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py new file mode 100644 index 0000000..6a2b82b --- /dev/null +++ b/tests/test_install_activate.py @@ -0,0 +1,298 @@ +import sys +import os + +try: + from unittest import mock +except ImportError: + import mock # pyright: ignore[reportMissingModuleSource] +import pytest + +import nodeenv + +if nodeenv.is_WIN: + FILES = { + 'activate.bat': 'ACTIVATE_BAT', + "deactivate.bat": 'DEACTIVATE_BAT', + "Activate.ps1": 'ACTIVATE_PS1', + } +else: + FILES = { + 'activate': 'ACTIVATE_SH', + 'activate.fish': 'ACTIVATE_FISH', + 'shim': 'SHIM', + } + + +def fix_content(content, tmpdir): + if nodeenv.is_WIN: + bin_name = 'Scripts' + node_name = 'node.exe' + else: + bin_name = 'bin' + node_name = 'node' + tmpdir.join('Scripts').join('node.exe') + + content = content.replace( + '__NODE_VIRTUAL_PROMPT__', '({})'.format(tmpdir.basename)) + content = content.replace('__NODE_VIRTUAL_ENV__', str(tmpdir)) + content = content.replace( + '__SHIM_NODE__', str(tmpdir.join(bin_name).join(node_name))) + content = content.replace('__BIN_NAME__', bin_name) + content = content.replace( + '__MOD_NAME__', os.path.join('lib', 'node_modules')) + content = content.replace('__NPM_CONFIG_PREFIX__', '$NODE_VIRTUAL_ENV') + return content + + +@pytest.mark.parametrize('name, content_var', FILES.items()) +def test_write(tmpdir, name, content_var): + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + content = getattr(nodeenv, content_var) + assert bin_dir.join(name).read() == fix_content(content, tmpdir) + + +@pytest.mark.parametrize('name, content_var', FILES.items()) +def test_python_virtualenv(tmpdir, name, content_var): + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + with mock.patch.object(sys, 'argv', ['nodeenv', '-p']): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + content = getattr(nodeenv, content_var) + # If there's disable prompt content to be added, we're appending to + # the file so prepend the original content (and the wrapped + # disable/enable prompt content). + disable_prompt = nodeenv.DISABLE_PROMPT.get(name) + if disable_prompt: + enable_prompt = nodeenv.ENABLE_PROMPT.get(name, '') + content = name + disable_prompt + content + enable_prompt + assert bin_dir.join(name).read() == fix_content(content, tmpdir) + + +@pytest.mark.parametrize('name, content_var', FILES.items()) +def test_custom_prompt(tmpdir, name, content_var): + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + custom_prompt = '(my-custom-env)' + with mock.patch.object( + sys, 'argv', ['nodeenv', '--prompt', custom_prompt, str(tmpdir)] + ): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + content = getattr(nodeenv, content_var) + expected_content = content.replace( + '__NODE_VIRTUAL_PROMPT__', custom_prompt) + expected_content = expected_content.replace( + '__NODE_VIRTUAL_ENV__', str(tmpdir)) + if nodeenv.is_WIN: + node_name = 'node.exe' + else: + node_name = 'node' + expected_content = expected_content.replace( + '__SHIM_NODE__', str(bin_dir.join(node_name))) + expected_content = expected_content.replace( + '__BIN_NAME__', os.path.basename(str(bin_dir))) + expected_content = expected_content.replace( + '__MOD_NAME__', os.path.join('lib', 'node_modules')) + expected_content = expected_content.replace( + '__NPM_CONFIG_PREFIX__', '$NODE_VIRTUAL_ENV') + assert bin_dir.join(name).read() == expected_content + + +@pytest.mark.skipif(nodeenv.is_WIN, reason='system node is POSIX only') +def test_node_system_creates_shim(tmpdir): + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + + # Mock system node path + system_node = '/usr/bin/node' + + with mock.patch.object( + sys, 'argv', ['nodeenv', '--node=system', str(tmpdir)] + ): + with mock.patch('shutil.which', return_value=system_node): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + # Check that shim file was created for node + assert bin_dir.join('node').exists() + shim_content = bin_dir.join('node').read() + assert system_node in shim_content + assert 'NODE_PATH' in shim_content + + +@pytest.mark.skipif(nodeenv.is_WIN, reason='symlink test is POSIX only') +def test_nodejs_symlink_created(tmpdir): + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + # Create a dummy node file + node_file = bin_dir.join('node') + node_file.write('#!/bin/sh\necho node') + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + nodejs_file = bin_dir.join('nodejs') + assert nodejs_file.exists() + assert os.path.islink(str(nodejs_file)) + assert os.readlink(str(nodejs_file)) == 'node' + + +def test_file_overwrite(tmpdir): + """Test that files are correctly overwritten when they already exist""" + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write('old content') + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + # Verify files were updated with correct content + for name, content_var in FILES.items(): + content = getattr(nodeenv, content_var) + assert bin_dir.join(name).read() == fix_content(content, tmpdir) + + +def test_prompt_default_to_basename(tmpdir): + """Test that prompt defaults to environment directory basename""" + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + test_file = 'activate.bat' + else: + bin_dir = tmpdir.join('bin') + test_file = 'activate' + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + expected_prompt = '({})'.format(tmpdir.basename) + content = bin_dir.join(test_file).read() + assert expected_prompt in content + + +def test_python_virtualenv_with_custom_prompt(tmpdir): + """Test that custom prompt works with python virtualenv""" + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + test_file = 'activate.bat' + else: + bin_dir = tmpdir.join('bin') + test_file = 'activate' + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + custom_prompt = '(test-env)' + with mock.patch.object( + sys, 'argv', ['nodeenv', '-p', '--prompt', custom_prompt] + ): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + content = bin_dir.join(test_file).read() + assert custom_prompt in content + if not nodeenv.is_WIN: + # Check that DISABLE_PROMPT was prepended for non-Windows + if test_file in nodeenv.DISABLE_PROMPT: + assert 'NODE_VIRTUAL_ENV_DISABLE_PROMPT' in content + + +def test_all_placeholders_replaced(tmpdir): + """Test that all placeholders are properly replaced in generated files""" + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + for n in FILES: + bin_dir.join(n).write(n) + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + # Check that no placeholders remain in any file + for name in FILES: + content = bin_dir.join(name).read() + assert '__NODE_VIRTUAL_PROMPT__' not in content + assert '__NODE_VIRTUAL_ENV__' not in content + assert '__SHIM_NODE__' not in content + assert '__BIN_NAME__' not in content + assert '__MOD_NAME__' not in content + # __NPM_CONFIG_PREFIX__ might be in the file as a variable reference + # but not as an unreplaced placeholder, so check more carefully + if nodeenv.is_WIN: + # On Windows it should be replaced with the actual path + pass # Skip check on Windows as it's more complex + else: + # On Unix it should be replaced with '$NODE_VIRTUAL_ENV' + # The original placeholder should not exist + lines = content.split('\n') + for line in lines: + if '__NPM_CONFIG_PREFIX__' in line: + # Make sure it's not the actual placeholder being used + assert ( + 'NPM_CONFIG_PREFIX=' in line or + 'set NPM_CONFIG_PREFIX' in line + ), "Found unreplaced __NPM_CONFIG_PREFIX__ placeholder" + + +@pytest.mark.parametrize('name, content_var', FILES.items()) +def test_files_are_executable(tmpdir, name, content_var): + """Test that created activation files are executable when first created""" + if nodeenv.is_WIN: + bin_dir = tmpdir.join('Scripts') + else: + bin_dir = tmpdir.join('bin') + bin_dir.mkdir() + + with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): + opts = nodeenv.parse_args() + nodeenv.install_activate(str(tmpdir), opts) + + file_path = str(bin_dir.join(name)) + if not nodeenv.is_WIN: + # Check that file is executable on Unix systems + import stat + st = os.stat(file_path) + assert st.st_mode & stat.S_IXUSR, \ + f"File {name} should be executable by user" + assert st.st_mode & stat.S_IXGRP, \ + f"File {name} should be executable by group" + assert st.st_mode & stat.S_IXOTH, \ + f"File {name} should be executable by others" diff --git a/tox.ini b/tox.ini index 9111b7e..61513da 100644 --- a/tox.ini +++ b/tox.ini @@ -1,27 +1,20 @@ [tox] -# These should match the travis env list -envlist = py26,py27,py33,py34,pypy,pypy3 +# These should match the GitHub Actions env list +envlist = py310,py311,py312,py313,py314 [testenv] -install_command = pip install --use-wheel {opts} {packages} +install_command = pip install {opts} {packages} deps = -rrequirements-dev.txt setenv = LANG=en_US.UTF-8 commands = - coverage erase coverage run -p -m pytest {posargs:tests} - # Needed because we subprocess to ourselves - coverage combine - coverage report --show-missing --fail-under 60 # TODO: 100 - flake8 nodeenv.py tests setup.py + flake8 --extend-ignore=E127 nodeenv.py tests setup.py [testenv:venv] envdir = venv-nodeenv commands = -[testenv:docs] -deps = - {[testenv]deps} - sphinx -changedir = docs -commands = sphinx-build -b html -d build/doctrees source build/html +[pytest] +markers = + integration: tests that take a little bit longer