From b740b3b365a473454fe88d40a8bd6a3e0ab895d1 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 16 Feb 2016 11:31:23 +0300 Subject: [PATCH 001/239] reverted to the last stable version (commit eea49abe73a) --- nodeenv.py | 114 ++++++++++++++++------------------------------------- 1 file changed, 34 insertions(+), 80 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 8772bf4..9872abc 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -511,42 +511,20 @@ def tarfile_open(*args, **kwargs): tf.close() -def download_node_bin(node_url, env_dir): +def download_node_src(node_url, src_dir, opt, prefix): """ - 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_tar(node_url, src_dir, strip=False): - """ - 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) + node_ver = opt.node.replace('.', '\.') + regex_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)" \ + % (prefix, node_ver) + if re.match(regex_string, member.name) is None: + extract_list.append(member) tarfile_obj.extractall(src_dir, extract_list) @@ -560,6 +538,16 @@ def urlopen(url): # Virtual environment functions +def copy_node_from_prebuilt(env_dir, src_dir): + """ + Copy prebuilt binaries into environment + """ + logger.info('.', extra=dict(continued=True)) + prefix = get_binary_prefix() + callit(['cp', '-a', src_dir + '/%s-v*/*' % prefix, env_dir], True, env_dir) + logger.info('.', extra=dict(continued=True)) + + def build_node_from_src(env_dir, src_dir, node_src_dir, opt): env = {} make_param_names = ['load-average', 'jobs'] @@ -626,27 +614,29 @@ def install_node(env_dir, src_dir, opt): """ env_dir = abspath(env_dir) prefix = get_binary_prefix() + logger.info(' * Install %s (%s' % (prefix, opt.node), + extra=dict(continued=True)) + 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) 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_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) + + # get src if not downloaded yet + if not os.path.exists(node_src_dir): + logger.info(')') + logger.info(' Downloading %s' % node_url) + download_node_src(node_url, src_dir, opt, prefix) - # 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) + logger.info('.', extra=dict(continued=True)) + if opt.prebuilt: + copy_node_from_prebuilt(env_dir, src_dir) + else: build_node_from_src(env_dir, src_dir, node_src_dir, opt) - logger.info(' Done.') + logger.info(' done.') def install_npm(env_dir, src_dir, opt): @@ -711,10 +701,7 @@ def install_activate(env_dir, opt): """ Install virtual environment activation script """ - if not is_WIN: - files = {'activate': ACTIVATE_SH, 'shim': SHIM} - else: - files = {'activate.bat': ACTIVATE_BAT} + files = {'activate': ACTIVATE_SH, 'shim': SHIM} if opt.node == "system": files["node"] = SHIM bin_dir = join(env_dir, 'bin') @@ -753,9 +740,7 @@ def install_activate(env_dir, opt): 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 - os.symlink("node", shim_nodejs) + os.symlink("node", shim_nodejs) def create_environment(env_dir, opt): @@ -953,37 +938,6 @@ def main(): exec __SHIM_NODE__ "$@" """ -# virtualenv script adapted for node environment -ACTIVATE_BAT = """\ -@echo off -set NODE_VIRTUAL_ENV="__NODE_VIRTUAL_ENV__" - -if defined _OLD_VIRTUAL_PROMPT ( - set "PROMPT=%_OLD_VIRTUAL_PROMPT%" -) else ( - if not defined PROMPT ( - set "PROMPT=$P$G" - ) - set "_OLD_VIRTUAL_PROMPT=%PROMPT%" -) -set "PROMPT=__NODE_VIRTUAL_PROMPT__ %PROMPT%" - -if not defined _OLD_VIRTUAL_NODE_PATH ( - set "_OLD_VIRTUAL_NODE_PATH=%NODE_PATH%" -) -set NODE_PATH=__NODE_VIRTUAL_ENV__\\lib\\node_modules - -if defined _OLD_VIRTUAL_NODE_PATH ( - set "PATH=%_OLD_VIRTUAL_NODE_PATH%" -) else ( - set "_OLD_VIRTUAL_NODE_PATH=%PATH%" -) -set "PATH=%NODE_VIRTUAL_ENV%\\bin;%PATH%" - -:END - -""" - ACTIVATE_SH = """ # This file must be used with "source bin/activate" *from bash* From 5cb2e139250c0696116d4ea1012d0d5a19b60758 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 16 Feb 2016 11:38:43 +0300 Subject: [PATCH 002/239] pep8 --- nodeenv.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 9872abc..f600a51 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -479,14 +479,14 @@ def get_root_url(version): 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', # Windows Server 2012 R2 (x64) } sysinfo = { - 'system': platform.system().lower(), - 'arch': archmap[platform.machine()], + 'system': platform.system().lower(), + 'arch': archmap[platform.machine()], } if is_WIN: filename = 'win-%(arch)s/node.exe' % sysinfo From 205f240282bae38b2853ce4898e1b0aba52fb4b6 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 16 Feb 2016 11:38:57 +0300 Subject: [PATCH 003/239] update AUTHORS --- AUTHORS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 17f2644..8c717da 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,9 +4,10 @@ Patches and Suggestions ``````````````````````` - jhermann +- anatoly techtonik - ivan hilkov -- Vincent Bernat - Anthony Sottile +- Vincent Bernat - Kyle P Davis - Elias Kunnas - Doug Turnbull @@ -28,6 +29,7 @@ Patches and Suggestions - Stan Seibert - Shubhang Mani - Rik +- Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski - Marc Abramowitz From 2cd7de2005c4e33cc324ecd2cf84c995ebcd2d19 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 16 Feb 2016 11:50:26 +0300 Subject: [PATCH 004/239] improved some output --- nodeenv.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index f600a51..63dd999 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -515,7 +515,9 @@ def download_node_src(node_url, src_dir, opt, prefix): """ Download source code """ + logger.info('.', extra=dict(continued=True)) tar_contents = io.BytesIO(urlopen(node_url).read()) + logger.info('.', extra=dict(continued=True)) with tarfile_open(fileobj=tar_contents) as tarfile_obj: member_list = tarfile_obj.getmembers() extract_list = [] @@ -614,19 +616,19 @@ def install_node(env_dir, src_dir, opt): """ env_dir = abspath(env_dir) prefix = get_binary_prefix() - logger.info(' * Install %s (%s' % (prefix, opt.node), + node_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) + src_type = "prebuilt" if opt.prebuilt else "source" + + logger.info(' * Install %s %s (%s) ' % (src_type, prefix, opt.node), extra=dict(continued=True)) if opt.prebuilt: node_url = get_node_bin_url(opt.node) else: node_url = get_node_src_url(opt.node) - node_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) # get src if not downloaded yet if not os.path.exists(node_src_dir): - logger.info(')') - logger.info(' Downloading %s' % node_url) download_node_src(node_url, src_dir, opt, prefix) logger.info('.', extra=dict(continued=True)) From 50cc741fcc8dd1b1ae58052e27a8dd5cc9850cc5 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 29 Feb 2016 22:30:15 +0300 Subject: [PATCH 005/239] add ut target into Makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index c7e6341..616a2b2 100644 --- a/Makefile +++ b/Makefile @@ -118,6 +118,9 @@ test8: clean tests: clean test1 test2 test3 test4 test5 test6 test7 test8 clean +ut: + @. env/bin/activate && tox -e py27 + contributors: @echo "Nodeenv is written and maintained by Eugene Kalinin." > AUTHORS @echo "" >> AUTHORS From d5189ccabbb67ada22338cac5aaabc71c22040e8 Mon Sep 17 00:00:00 2001 From: Kai Weber Date: Mon, 21 Mar 2016 10:46:19 +0100 Subject: [PATCH 006/239] Swallow output of cd The bash prints the directory it has changed to stdout if an option like autocd, cdspell, dirspell or CDPATH is used. We expect no output from this command. --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 63dd999..8312133 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1016,7 +1016,7 @@ def main(): 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 From 92b3fcef6453421d3153ab90e827c3a2649bda56 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 29 Mar 2016 17:00:09 +0300 Subject: [PATCH 007/239] use '--prebuilt' by default. fixed #161 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 8312133..4a67866 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -90,7 +90,7 @@ class Config(object): debug = False profile = False make = 'make' - prebuilt = False + prebuilt = True @classmethod def _load(cls, configfiles, verbose=False): From 58dc1885e6753c770171f616a1964c08f7db0a9a Mon Sep 17 00:00:00 2001 From: Laust Rud Jacobsen Date: Thu, 31 Mar 2016 10:10:18 +0200 Subject: [PATCH 008/239] README: note that python 2.6 or 2.7 is required This is based on this detail from the node build information: https://github.com/nodejs/node/blob/33c27f8fcffd7b0c6d609fdd4503b4f7a3c45bcd/BUILDING.md Trying to use python 3 when installing node currently does not do anything useful, hoping this can save somebody else a bit of time. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 63c8d14..0c602a2 100644 --- a/README.rst +++ b/README.rst @@ -72,7 +72,7 @@ Dependency For nodeenv ^^^^^^^^^^^ -* python (>= 2.6) +* python (2.6 or 2.7) * make * tail From dea0b51b5f7b79c1df09150e6ee39b8b81a546fd Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 27 Apr 2016 20:09:14 +0300 Subject: [PATCH 009/239] =?UTF-8?q?insert=20'=E2=80=B9envdir=E2=80=BA/node?= =?UTF-8?q?=5Fmodules/.bin'=20into=20PATH,=20fixed=20#86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 4a67866..299d674 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1029,7 +1029,7 @@ 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" From 04fcbdf7ec07d9a118248260664aeb95b037cca0 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 27 Apr 2016 20:11:37 +0300 Subject: [PATCH 010/239] update AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 8c717da..ef76267 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,7 +33,9 @@ Patches and Suggestions - Mrinal Wadhwa - Michal Kolodziejski - Marc Abramowitz +- Laust Rud Jacobsen - Ken Struys +- Kai Weber - Jesse Dhillon - Jeremy Banks - Geoffrey Huntley From d4b51ed3980d4e5f12b0dfb5cb730e8b0b0a907c Mon Sep 17 00:00:00 2001 From: Marc-Antoine Parent Date: Mon, 9 May 2016 16:20:03 -0400 Subject: [PATCH 011/239] Do not append content repeatedly to activate script. --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 299d674..11aa461 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -385,7 +385,7 @@ def writefile(dest, content, overwrite=True, append=False): 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 From 6caeb277b8c2171fc9ac7f49d0b3da906296add1 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 10 May 2016 16:19:04 +0300 Subject: [PATCH 012/239] update AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index ef76267..7fce9bf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,6 +32,7 @@ Patches and Suggestions - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski +- Marc-Antoine Parent - Marc Abramowitz - Laust Rud Jacobsen - Ken Struys From 0ef25780942c9b301d3e90344e013b3fc7e2af22 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 16 May 2016 11:22:55 +0300 Subject: [PATCH 013/239] setup.py: added classifiers for python 2.6/2.7, fixed #164 --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 8e0bdc9..3a70834 100644 --- a/setup.py +++ b/setup.py @@ -46,6 +46,8 @@ def read_file(file_name): 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', 'Topic :: Software Development :: Libraries :: Python Modules' ] ) From 8e69de0485af9fdabec5243c836977888a0797e2 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 16 May 2016 11:29:14 +0300 Subject: [PATCH 014/239] README: added TOC --- README.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.rst b/README.rst index 0c602a2..f998416 100644 --- a/README.rst +++ b/README.rst @@ -17,6 +17,20 @@ If you use nodeenv feel free to add your project on wiki: `Who-Uses-Nodeenv`_. .. image:: https://travis-ci.org/ekalinin/nodeenv.svg?branch=master :target: https://travis-ci.org/ekalinin/nodeenv +Table of Contents +----------------- + + * [Node.js virtual environment](#nodejs-virtual-environment) + * [Install](#install) + * [Dependency](#dependency) + * [Usage](#usage) + * [Configuration](#configuration) + * [Alternatives](#alternatives) + * [LICENSE](#license) + +Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) + + Install ------- From d3dd880e4aa47c01120d726290658b2aa2419604 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 16 May 2016 11:35:31 +0300 Subject: [PATCH 015/239] README: fixed TOC --- README.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/README.rst b/README.rst index f998416..14e675c 100644 --- a/README.rst +++ b/README.rst @@ -20,13 +20,7 @@ If you use nodeenv feel free to add your project on wiki: `Who-Uses-Nodeenv`_. Table of Contents ----------------- - * [Node.js virtual environment](#nodejs-virtual-environment) - * [Install](#install) - * [Dependency](#dependency) - * [Usage](#usage) - * [Configuration](#configuration) - * [Alternatives](#alternatives) - * [LICENSE](#license) +.. contents:: :local: Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) From ff25b285dee25294cdbc86dfa1d6338c3b22632e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 16 May 2016 11:37:18 +0300 Subject: [PATCH 016/239] README: fixed TOC --- README.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.rst b/README.rst index 14e675c..093d9d7 100644 --- a/README.rst +++ b/README.rst @@ -17,13 +17,8 @@ If you use nodeenv feel free to add your project on wiki: `Who-Uses-Nodeenv`_. .. image:: https://travis-ci.org/ekalinin/nodeenv.svg?branch=master :target: https://travis-ci.org/ekalinin/nodeenv -Table of Contents ------------------ - .. contents:: :local: -Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc) - Install ------- From d4a30ade59088b15ef88289ce94ed775436a3022 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 8 Sep 2016 15:30:01 +0300 Subject: [PATCH 017/239] added arm support; fixes #171 --- nodeenv.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index 11aa461..c15a85c 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -483,6 +483,9 @@ def get_node_bin_url(version): 'i686': 'x86', 'x86_64': 'x64', # Linux Ubuntu 64 'AMD64': 'x64', # Windows Server 2012 R2 (x64) + 'armv6l': 'armv6l', # arm + 'armv7l': 'armv7l', + 'aarch64': 'armv64', } sysinfo = { 'system': platform.system().lower(), From 99b2a4db01e163cbf754ad31de9c5f590f8b5c78 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Sep 2016 10:33:58 +0300 Subject: [PATCH 018/239] 1.0.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index c15a85c..25e4069 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -37,7 +37,7 @@ from pkg_resources import parse_version -nodeenv_version = '0.13.6' +nodeenv_version = '1.0.0' join = os.path.join abspath = os.path.abspath From fa2eee9ea23fa5ea7e28c7e27f0fbdcfffe8e7ee Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Sep 2016 11:22:45 +0300 Subject: [PATCH 019/239] added --source option --- README.rst | 9 +++++---- nodeenv.py | 7 ++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 093d9d7..ea6ce52 100644 --- a/README.rst +++ b/README.rst @@ -132,11 +132,12 @@ for compilation and npm.js "0.3.17":: $ nodeenv --without-ssl --node=0.4.3 --npm=0.3.17 --jobs=4 env-4.3 -Install node.js from prebuilt package:: +Install node.js from the source:: - $ nodeenv --node=0.10.25 --prebuilt env-0.10.25-prebuilt + $ nodeenv --node=0.10.25 --source env-0.10.25-prebuilt -It's much faster than installing & compiling node.js from source:: +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. @@ -145,7 +146,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 diff --git a/nodeenv.py b/nodeenv.py index 25e4069..ad5ff5e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -325,7 +325,12 @@ def parse_args(check=True): parser.add_option( '--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_option( + '--source', dest='prebuilt', + action='store_false', default=Config.prebuilt, + help='Install node.js from the source') options, args = parser.parse_args() if options.config_file is None: From 2b078fbbf463ef39871de5af1a2f5aad98cbbe0b Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Sep 2016 11:26:20 +0300 Subject: [PATCH 020/239] update CHANGES --- CHANGES | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES b/CHANGES index 354928a..244095f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,17 @@ Nodeenv changelog ================= +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`_ From e3bb9901536ec659a965595197148e229a6688bc Mon Sep 17 00:00:00 2001 From: Luis Orduz Date: Fri, 9 Sep 2016 11:29:03 -0500 Subject: [PATCH 021/239] Added functionality for deactivating node when the virtual environment is deactivated if nodeenv was run with "-p" --- .travis.yml | 1 + nodeenv.py | 11 +++++++++++ tests/nodeenv_test.py | 13 +++++++++++++ tox.ini | 2 +- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0306b61..2385b07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ env: # These should match the tox env list - TOXENV=py27 - TOXENV=py33 - TOXENV=py34 + - TEXENV=py35 - TOXENV=pypy - TOXENV=pypy3 install: pip install coveralls tox --use-mirrors diff --git a/nodeenv.py b/nodeenv.py index c15a85c..dad3990 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -748,6 +748,11 @@ def install_activate(env_dir, opt): os.symlink("node", shim_nodejs) +def set_predeactivate_hook(env_dir): + with open(join(env_dir, 'bin', 'predeactivate'), 'a') as hook: + hook.write(PREDEACTIVATE_SH) + + def create_environment(env_dir, opt): """ Creates a new environment in ``env_dir``. @@ -773,6 +778,8 @@ def create_environment(env_dir, opt): install_npm(env_dir, src_dir, opt) if opt.requirements: install_packages(env_dir, opt) + if opt.python_virtualenv: + set_predeactivate_hook(env_dir) # Cleanup if opt.clean_src: callit(['rm -rf', pipes.quote(src_dir)], opt.verbose, True, env_dir) @@ -1070,5 +1077,9 @@ def main(): fi """ +PREDEACTIVATE_SH = """ +if type -p deactivate_node > /dev/null; then deactivate_node;fi +""" + if __name__ == '__main__': main() diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index f13b219..d58010b 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -141,3 +141,16 @@ def test_print_node_versions_node(cap_logging_info): # 8 items per line = 7 tabs # The last line contains the remaning 3 items assert tabs_per_line == [7] * 28 + [2] + + +def test_predeactivate_hook(tmpdir): + # Throw error if the environment directory is not a string + with pytest.raises((TypeError, AttributeError)): + nodeenv.set_predeactivate_hook(tmpdir) + # Throw error if environment directory has no bin path + with pytest.raises((OSError, IOError)): + nodeenv.set_predeactivate_hook(tmpdir.strpath) + tmpdir.mkdir('bin') + nodeenv.set_predeactivate_hook(tmpdir.strpath) + p = tmpdir.join('bin').join('predeactivate') + assert 'deactivate_node' in p.read() diff --git a/tox.ini b/tox.ini index 9111b7e..15e0b97 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the travis env list -envlist = py26,py27,py33,py34,pypy,pypy3 +envlist = py26,py27,py33,py34,py35,pypy,pypy3 [testenv] install_command = pip install --use-wheel {opts} {packages} From 487f5b916b1dab2160e918b692a1d292d9d1f605 Mon Sep 17 00:00:00 2001 From: Max Liebkies Date: Tue, 8 Nov 2016 11:06:58 +0100 Subject: [PATCH 022/239] Fix Windows support for installing node and npm from prebuilt * This commit disables support for building from source *under Windows* altogether as we cannot really rely on a fixed environment (like gcc, make, etc) being present on Windows. I may add that support in the future * Under Windows, we need to always download npm seperately as it doesn't come bundled with the node.exe that we use. * Activation scripts are copied verbatim from ekalinin/nodeenv@windows-support * Using the node system version is not supported under Windows as we have no reliable way of knowing where it is installed --- nodeenv.py | 201 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 141 insertions(+), 60 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index bcf8ede..0c4f80f 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -23,6 +23,8 @@ import tarfile import pipes import platform +import zipfile +import shutil try: # pragma: no cover (py2 only) from ConfigParser import SafeConfigParser as ConfigParser @@ -84,7 +86,7 @@ class Config(object): # Defaults node = 'latest' npm = 'latest' - with_npm = False + with_npm = True if is_WIN else False jobs = '2' without_ssl = False debug = False @@ -222,15 +224,42 @@ def parse_args(check=True): 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.') + if not is_WIN: + 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_option( - '--load-average', dest='load_average', - help='Sets maximum load average for executing parallel commands ' - 'at node.js compilation.') + parser.add_option( + '--load-average', dest='load_average', + help='Sets maximum load average for executing parallel commands ' + 'at node.js compilation.') + + 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( + '--make', '-m', dest='make_path', + metavar='MAKE_PATH', + help='Path to make command', + default=Config.make) + + parser.add_option( + '--source', dest='prebuilt', + action='store_false', default=Config.prebuilt, + help='Install node.js from the source') parser.add_option( '-v', '--verbose', @@ -266,27 +295,12 @@ def parse_args(check=True): 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( '--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( '--npm', dest='npm', @@ -316,22 +330,11 @@ def parse_args(check=True): 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( '--prebuilt', dest='prebuilt', action='store_true', default=Config.prebuilt, help='Install node.js from prebuilt package (default)') - parser.add_option( - '--source', dest='prebuilt', - action='store_false', default=Config.prebuilt, - help='Install node.js from the source') - options, args = parser.parse_args() if options.config_file is None: options.config_file = ["./setup.cfg", "~/.nodeenvrc"] @@ -378,7 +381,7 @@ def writefile(dest, content, overwrite=True, append=False): 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 type(content) != bytes: content = bytes(content, 'utf-8') if not os.path.exists(dest): logger.debug(' * Writing %s ... ', dest, extra=dict(continued=True)) @@ -402,9 +405,9 @@ 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')) + if not is_WIN: f.write(DISABLE_PROMPT.encode('utf-8')) f.write(content) - f.write(ENABLE_PROMPT.encode('utf-8')) + if not is_WIN: f.write(ENABLE_PROMPT.encode('utf-8')) return logger.info(' * Overwriting %s with new content', dest) @@ -524,18 +527,22 @@ def download_node_src(node_url, src_dir, opt, prefix): Download source code """ logger.info('.', extra=dict(continued=True)) - tar_contents = io.BytesIO(urlopen(node_url).read()) + dl_contents = io.BytesIO(urlopen(node_url).read()) logger.info('.', extra=dict(continued=True)) - with tarfile_open(fileobj=tar_contents) as tarfile_obj: - member_list = tarfile_obj.getmembers() - extract_list = [] - for member in member_list: - node_ver = opt.node.replace('.', '\.') - regex_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)" \ - % (prefix, node_ver) - if re.match(regex_string, member.name) is None: - extract_list.append(member) - tarfile_obj.extractall(src_dir, extract_list) + + if is_WIN: + writefile(join(src_dir, 'node.exe'), dl_contents.read()) + else: + with tarfile_open(fileobj=dl_contents) as tarfile_obj: + member_list = tarfile_obj.getmembers() + extract_list = [] + for member in member_list: + node_ver = opt.node.replace('.', '\.') + regex_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)" \ + % (prefix, node_ver) + if re.match(regex_string, member.name) is None: + extract_list.append(member) + tarfile_obj.extractall(src_dir, extract_list) def urlopen(url): @@ -554,7 +561,10 @@ def copy_node_from_prebuilt(env_dir, src_dir): """ logger.info('.', extra=dict(continued=True)) prefix = get_binary_prefix() - callit(['cp', '-a', src_dir + '/%s-v*/*' % prefix, env_dir], True, env_dir) + if is_WIN: + callit(['copy', '/Y', '/L', join(src_dir, 'node.exe'), join(env_dir, 'Scripts', 'node.exe')], False, True) + else: + callit(['cp', '-a', join(src_dir, '/%s-v*/*' % prefix), env_dir], True, env_dir) logger.info('.', extra=dict(continued=True)) @@ -680,6 +690,35 @@ def install_npm(env_dir, src_dir, opt): logger.info('done.') +def install_npm_win(env_dir, src_dir, opt): + """ + Download source code for npm, unpack it + and install it in virtual environment. + """ + logger.info(' * Install npm.js (%s) ... ' % opt.npm, + extra=dict(continued=True)) + npm_contents = io.BytesIO(urlopen('https://github.com/npm/npm/archive/%s.zip' % opt.npm).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) + + shutil.copytree(join(src_dir, 'npm-%s' % opt.npm), node_modules_path) + shutil.copy(join(src_dir, 'npm-%s' % opt.npm, 'bin', 'npm.cmd'), join(bin_path, 'npm.cmd')) + shutil.copy(join(src_dir, 'npm-%s' % opt.npm, 'bin', 'npm-cli.js'), join(bin_path, 'npm-cli.js')) + + def install_packages(env_dir, opt): """ Install node.js packages via npm @@ -711,15 +750,23 @@ def install_activate(env_dir, opt): """ Install virtual environment activation script """ - files = {'activate': ACTIVATE_SH, 'shim': SHIM} + if is_WIN: + files = {'activate.bat': ACTIVATE_BAT} + bin_dir = join(env_dir, 'Scripts') + shim_node = join(bin_dir, "node.exe") + shim_nodejs = join(bin_dir, "nodejs.exe") + else: + files = {'activate': ACTIVATE_SH, 'shim': SHIM} + bin_dir = join(env_dir, 'bin') + shim_node = join(bin_dir, "node") + shim_nodejs = join(bin_dir, "nodejs") + if opt.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)) - 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)}) @@ -750,12 +797,16 @@ def install_activate(env_dir, opt): writefile(file_path, content, append=need_append) if not os.path.exists(shim_nodejs): - os.symlink("node", shim_nodejs) + if is_WIN: + callit(['mklink', shim_nodejs, 'node.exe'], True, True) + else: + os.symlink("node", shim_nodejs) def set_predeactivate_hook(env_dir): - with open(join(env_dir, 'bin', 'predeactivate'), 'a') as hook: - hook.write(PREDEACTIVATE_SH) + if not is_WIN: + with open(join(env_dir, 'bin', 'predeactivate'), 'a') as hook: + hook.write(PREDEACTIVATE_SH) def create_environment(env_dir, opt): @@ -780,14 +831,15 @@ def create_environment(env_dir, opt): # 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) + instfunc = install_npm_win if is_WIN else install_npm + instfunc(env_dir, src_dir, opt) if opt.requirements: install_packages(env_dir, opt) if opt.python_virtualenv: set_predeactivate_hook(env_dir) # Cleanup if opt.clean_src: - callit(['rm -rf', pipes.quote(src_dir)], opt.verbose, True, env_dir) + shutil.rmtree(src_dir) class GetsAHrefs(HTMLParser): @@ -917,6 +969,10 @@ def main(): opt, args = parse_args() + if opt.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" @@ -955,6 +1011,31 @@ def main(): exec __SHIM_NODE__ "$@" """ +ACTIVATE_BAT = """\ +@echo off +set NODE_VIRTUAL_ENV="__NODE_VIRTUAL_ENV__" +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) else ( + if not defined PROMPT ( + set "PROMPT=$P$G" + ) + set "_OLD_VIRTUAL_PROMPT=%PROMPT%" +) +set "PROMPT=__NODE_VIRTUAL_PROMPT__ %PROMPT%" +if not defined _OLD_VIRTUAL_NODE_PATH ( + set "_OLD_VIRTUAL_NODE_PATH=%NODE_PATH%" +) +set NODE_PATH=__NODE_VIRTUAL_ENV__\\lib\\node_modules +if defined _OLD_VIRTUAL_NODE_PATH ( + set "PATH=%_OLD_VIRTUAL_NODE_PATH%" +) else ( + set "_OLD_VIRTUAL_NODE_PATH=%PATH%" +) +set "PATH=%NODE_VIRTUAL_ENV%\\Scripts;%PATH%" +:END +""" + ACTIVATE_SH = """ # This file must be used with "source bin/activate" *from bash* From c626d74e2232078545fb352bc3b1d97f54ab2198 Mon Sep 17 00:00:00 2001 From: Max Liebkies Date: Tue, 8 Nov 2016 11:23:29 +0100 Subject: [PATCH 023/239] Revert unintended change to copy_node_from_prebuilt --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 0c4f80f..7e5b533 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -564,7 +564,7 @@ def copy_node_from_prebuilt(env_dir, src_dir): if is_WIN: callit(['copy', '/Y', '/L', join(src_dir, 'node.exe'), join(env_dir, 'Scripts', 'node.exe')], False, True) else: - callit(['cp', '-a', join(src_dir, '/%s-v*/*' % prefix), env_dir], True, env_dir) + callit(['cp', '-a', src_dir + '/%s-v*/*' % prefix, env_dir], True, env_dir) logger.info('.', extra=dict(continued=True)) From 319bd9b456dfffa836a6fd5ea6ec3b5d4570735e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 25 Nov 2016 20:21:17 -0800 Subject: [PATCH 024/239] Add python3 classifiers and note to README --- README.rst | 2 +- setup.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ea6ce52..6ebe976 100644 --- a/README.rst +++ b/README.rst @@ -75,7 +75,7 @@ Dependency For nodeenv ^^^^^^^^^^^ -* python (2.6 or 2.7) +* python (2.6+, 3.3+, or pypy) * make * tail diff --git a/setup.py b/setup.py index 3a70834..6ac6a36 100644 --- a/setup.py +++ b/setup.py @@ -46,8 +46,15 @@ def read_file(file_name): 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', + 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: Implementation :: CPython', + 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' ] ) From 542c30e96be6df6a8557dd196cf5ee5f6118e7b3 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 25 Nov 2016 20:26:00 -0800 Subject: [PATCH 025/239] Appease the latest version of flake8 --- nodeenv.py | 3 +++ setup.py | 1 + 2 files changed, 4 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index bcf8ede..1283ca1 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -196,6 +196,8 @@ def emit(self, record): # add ch to logger logger.addHandler(ch) return logger + + logger = create_logger() @@ -800,6 +802,7 @@ def handle_starttag(self, tag, attrs): if tag == 'a': self.hrefs.append(dict(attrs).get('href', '')) + VERSION_RE = re.compile('\d+\.\d+\.\d+') diff --git a/setup.py b/setup.py index 3a70834..a93bcd9 100644 --- a/setup.py +++ b/setup.py @@ -21,6 +21,7 @@ def read_file(file_name): encoding='utf-8', ).read() + ldesc = read_file('README.rst') ldesc += "\n\n" + read_file('CHANGES') From 8834f4c22871009abc215bb56cccb5f6d4bbe64f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 25 Nov 2016 20:32:48 -0800 Subject: [PATCH 026/239] Fix typo in .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2385b07..7e37778 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,11 @@ language: python +python: 3.5 env: # These should match the tox env list - TOXENV=py26 - TOXENV=py27 - TOXENV=py33 - TOXENV=py34 - - TEXENV=py35 + - TOXENV=py35 - TOXENV=pypy - TOXENV=pypy3 install: pip install coveralls tox --use-mirrors From c2a5923912a48518eeccb6dc1a362f4df831be80 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:04:49 +0300 Subject: [PATCH 027/239] removed iojs test; replaced py3.4 test with 3.5 --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 616a2b2..e2b0701 100644 --- a/Makefile +++ b/Makefile @@ -62,10 +62,10 @@ test3: clean # https://github.com/ekalinin/nodeenv/issues/43 test4: clean @echo " =" - @echo " = test4: separate nodejs's env for python3.4" + @echo " = test4: separate nodejs's env for python3.5" @echo " =" @rm -rf env && \ - virtualenv --no-site-packages --python=python3.4 env && \ + virtualenv --no-site-packages --python=python3.5 env && \ . env/bin/activate && \ python setup.py install && \ nodeenv 4 -p --prebuilt && \ @@ -116,7 +116,7 @@ test8: clean rm -rf öäü && mkdir öäü && cd öäü && \ nodeenv -j 4 --prebuilt env -tests: clean test1 test2 test3 test4 test5 test6 test7 test8 clean +tests: clean test1 test2 test3 test4 test5 test7 test8 clean ut: @. env/bin/activate && tox -e py27 From 95a42c99c55d5bc5c156bcf7833647621ceeeae6 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:05:20 +0300 Subject: [PATCH 028/239] update AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index 7fce9bf..de00419 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,6 +16,7 @@ Patches and Suggestions - Travis Miller - syndbg - Spencer Rathbun +- Luis Orduz - Lispython - Leonardo Fedalto - Kyle P Davis @@ -32,6 +33,7 @@ Patches and Suggestions - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski +- Max Liebkies - Marc-Antoine Parent - Marc Abramowitz - Laust Rud Jacobsen From fb79d0dc50383ee62bf3fde29c8e18162f0fa755 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:21:30 +0300 Subject: [PATCH 029/239] fixed travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e37778..a9d553a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ env: # These should match the tox env list - TOXENV=py35 - TOXENV=pypy - TOXENV=pypy3 -install: pip install coveralls tox --use-mirrors +install: pip install coveralls tox script: tox after_success: - coveralls From 2214effa28f4011e6dfa6945c3f2bcc91ce21211 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:35:11 +0300 Subject: [PATCH 030/239] flake8 --- nodeenv.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index b1c7129..38f217b 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -235,10 +235,10 @@ def parse_args(check=True): parser.add_option( '--load-average', dest='load_average', help='Sets maximum load average for executing parallel commands ' - 'at node.js compilation.') + 'at node.js compilation.') parser.add_option( - '--without-ssl', dest='without_ssl', + '--without-ssl', dest='without_ssl', action='store_true', default=Config.without_ssl, help='Build node.js without SSL support') @@ -407,9 +407,11 @@ def writefile(dest, content, overwrite=True, append=False): if append: logger.info(' * Appending data to %s', dest) with open(dest, 'ab') as f: - if not is_WIN: f.write(DISABLE_PROMPT.encode('utf-8')) + if not is_WIN: + f.write(DISABLE_PROMPT.encode('utf-8')) f.write(content) - if not is_WIN: f.write(ENABLE_PROMPT.encode('utf-8')) + if not is_WIN: + f.write(ENABLE_PROMPT.encode('utf-8')) return logger.info(' * Overwriting %s with new content', dest) @@ -540,9 +542,9 @@ def download_node_src(node_url, src_dir, opt, prefix): extract_list = [] for member in member_list: node_ver = opt.node.replace('.', '\.') - regex_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)" \ + rexp_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ % (prefix, node_ver) - if re.match(regex_string, member.name) is None: + if re.match(rexp_string, member.name) is None: extract_list.append(member) tarfile_obj.extractall(src_dir, extract_list) @@ -564,9 +566,12 @@ def copy_node_from_prebuilt(env_dir, src_dir): logger.info('.', extra=dict(continued=True)) prefix = get_binary_prefix() if is_WIN: - callit(['copy', '/Y', '/L', join(src_dir, 'node.exe'), join(env_dir, 'Scripts', 'node.exe')], False, True) + src_exe = join(src_dir, 'node.exe') + dst_exe = join(env_dir, 'Scripts', 'node.exe') + callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) else: - callit(['cp', '-a', src_dir + '/%s-v*/*' % prefix, env_dir], True, env_dir) + src_folder = src_dir + '/%s-v*/*' % prefix + callit(['cp', '-a', src_folder, env_dir], True, env_dir) logger.info('.', extra=dict(continued=True)) @@ -699,7 +704,8 @@ def install_npm_win(env_dir, src_dir, opt): """ logger.info(' * Install npm.js (%s) ... ' % opt.npm, extra=dict(continued=True)) - npm_contents = io.BytesIO(urlopen('https://github.com/npm/npm/archive/%s.zip' % opt.npm).read()) + npm_url = 'https://github.com/npm/npm/archive/%s.zip' % opt.npm + npm_contents = io.BytesIO(urlopen(npm_url).read()) bin_path = join(env_dir, 'Scripts') node_modules_path = join(bin_path, 'node_modules', 'npm') @@ -716,9 +722,12 @@ def install_npm_win(env_dir, src_dir, opt): with zipfile.ZipFile(npm_contents, 'r') as zipf: zipf.extractall(src_dir) - shutil.copytree(join(src_dir, 'npm-%s' % opt.npm), node_modules_path) - shutil.copy(join(src_dir, 'npm-%s' % opt.npm, 'bin', 'npm.cmd'), join(bin_path, 'npm.cmd')) - shutil.copy(join(src_dir, 'npm-%s' % opt.npm, 'bin', 'npm-cli.js'), join(bin_path, 'npm-cli.js')) + npm_ver = 'npm-%s' % opt.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')) def install_packages(env_dir, opt): @@ -1023,7 +1032,7 @@ def main(): if not defined PROMPT ( set "PROMPT=$P$G" ) - set "_OLD_VIRTUAL_PROMPT=%PROMPT%" + set "_OLD_VIRTUAL_PROMPT=%PROMPT%" ) set "PROMPT=__NODE_VIRTUAL_PROMPT__ %PROMPT%" if not defined _OLD_VIRTUAL_NODE_PATH ( From 79043e36d0554c86091c22f1e51beed2ca7b81f9 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:43:15 +0300 Subject: [PATCH 031/239] fixed failed pypy (decreased coverage level) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 15e0b97..1d23a1f 100644 --- a/tox.ini +++ b/tox.ini @@ -12,7 +12,7 @@ commands = coverage run -p -m pytest {posargs:tests} # Needed because we subprocess to ourselves coverage combine - coverage report --show-missing --fail-under 60 # TODO: 100 + coverage report --show-missing --fail-under 55 # TODO: 100 flake8 nodeenv.py tests setup.py [testenv:venv] From f6a974c9e90a3ef2cbd4747d230a0446f9f3a7a9 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:51:22 +0300 Subject: [PATCH 032/239] stopped to test against py26,pypy3, fix #175 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1d23a1f..faf6e9a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the travis env list -envlist = py26,py27,py33,py34,py35,pypy,pypy3 +envlist = py27,py33,py34,py35,pypy [testenv] install_command = pip install --use-wheel {opts} {packages} From 580dd4b6a3f9c24467bceb5c2a08e91f470535c3 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 7 Dec 2016 18:54:37 +0300 Subject: [PATCH 033/239] stopped to test against py26, pypy3 (+travis), fix #175 --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a9d553a..6745258 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,11 @@ language: python python: 3.5 env: # These should match the tox env list - - TOXENV=py26 - TOXENV=py27 - TOXENV=py33 - TOXENV=py34 - TOXENV=py35 - TOXENV=pypy - - TOXENV=pypy3 install: pip install coveralls tox script: tox after_success: From bff06e055afdd303ed2db7b89649b250d29e8396 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 20 Jan 2017 12:48:29 +0300 Subject: [PATCH 034/239] Windows - create Scripts dir if not exists Another commit for #140 --- nodeenv.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nodeenv.py b/nodeenv.py index 38f217b..46318c0 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -568,6 +568,7 @@ def copy_node_from_prebuilt(env_dir, src_dir): if is_WIN: src_exe = join(src_dir, 'node.exe') dst_exe = join(env_dir, 'Scripts', 'node.exe') + mkdir(join(env_dir, 'Scripts')) callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) else: src_folder = src_dir + '/%s-v*/*' % prefix From 22ea01b8ebdd15c24c1473d8712d3669f38701b8 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 20 Jan 2017 16:39:46 +0300 Subject: [PATCH 035/239] Do not fail if nodejs link can't be created on Windows Final fix for #140. `mklink` fails with `You do not have sufficient privilege to perform this operation.` on my system, so make it optional. --- nodeenv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 46318c0..166fa72 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -810,7 +810,10 @@ def install_activate(env_dir, opt): if not os.path.exists(shim_nodejs): if is_WIN: - callit(['mklink', shim_nodejs, 'node.exe'], True, True) + 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) From c525d5e3099b93948505772987310eb940fa3aae Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 20 Jan 2017 17:26:49 +0300 Subject: [PATCH 036/239] 1.1.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 166fa72..61d9f39 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -39,7 +39,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.0.0' +nodeenv_version = '1.1.0' join = os.path.join abspath = os.path.abspath From 40e02e76fe979e6837c1f7cc5ddb327fe0a17220 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 20 Jan 2017 17:32:02 +0300 Subject: [PATCH 037/239] update CHANGES --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 244095f..ebc168a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ Nodeenv changelog ================= +Version 1.1.0 +------------- +- Windows support + Version 1.0.0 ------------- - `--prebuilt` is default. See `# 161`_ From 5c96841c2549d987216e0673568740eb38789b04 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 20 Jan 2017 17:32:41 +0300 Subject: [PATCH 038/239] improved tests in Makefile --- Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index e2b0701..2b16635 100644 --- a/Makefile +++ b/Makefile @@ -62,13 +62,12 @@ test3: clean # https://github.com/ekalinin/nodeenv/issues/43 test4: clean @echo " =" - @echo " = test4: separate nodejs's env for python3.5" + @echo " = test4: system nodejs's for python3.5" @echo " =" @rm -rf env && \ virtualenv --no-site-packages --python=python3.5 env && \ . env/bin/activate && \ python setup.py install && \ - nodeenv 4 -p --prebuilt && \ nodeenv -p --node=system test5: clean @@ -79,8 +78,7 @@ test5: clean virtualenv --no-site-packages --python=python2.7 env && \ . env/bin/activate && \ python setup.py install && \ - nodeenv 4 -p --prebuilt && \ - nodeenv -p --node=system + nodeenv -p --prebuilt test6: clean @echo " =" From fba77e82d00e5a4f9da797e1e47eea6c1a9fd39e Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 27 Jan 2017 10:26:19 +0100 Subject: [PATCH 039/239] Fix activate.bat and add deactivate.bat. --- nodeenv.py | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 61d9f39..465f4a7 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -763,7 +763,7 @@ def install_activate(env_dir, opt): Install virtual environment activation script """ if is_WIN: - files = {'activate.bat': ACTIVATE_BAT} + files = {'activate.bat': ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT} bin_dir = join(env_dir, 'Scripts') shim_node = join(bin_dir, "node.exe") shim_nodejs = join(bin_dir, "nodejs.exe") @@ -1029,26 +1029,47 @@ def main(): ACTIVATE_BAT = """\ @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%\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 "PATH=%NODE_VIRTUAL_ENV%\\Scripts;%PATH%" +set _OLD_VIRTUAL_PATH= +set NODE_VIRTUAL_ENV= :END """ From a69f0232bd72a7184f64f8e00d7d507c95be0bad Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 27 Jan 2017 10:56:53 +0100 Subject: [PATCH 040/239] Add PowerShell Script. --- nodeenv.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 465f4a7..14b002a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -763,7 +763,7 @@ def install_activate(env_dir, opt): Install virtual environment activation script """ if is_WIN: - files = {'activate.bat': ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT} + 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") @@ -1073,6 +1073,53 @@ def main(): :END """ +ACTIVATE_PS1 = """\ +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 = """ # This file must be used with "source bin/activate" *from bash* From 90c64a17431b60b6dfd85d3b84348ce4eb074fb9 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 27 Jan 2017 11:21:22 +0100 Subject: [PATCH 041/239] Fix formatting to pass the test. --- nodeenv.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 14b002a..4eca78f 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -763,7 +763,11 @@ def install_activate(env_dir, opt): Install virtual environment activation script """ if is_WIN: - files = {'activate.bat': ACTIVATE_BAT, "deactivate.bat": DEACTIVATE_BAT, "Activate.ps1": ACTIVATE_PS1} + 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") From 2ded88e034c39fc63ced6fa0b0edf846db12579e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 27 Jan 2017 13:27:21 +0300 Subject: [PATCH 042/239] update AUTHORS --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index de00419..e49e190 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,11 +5,12 @@ Patches and Suggestions - jhermann - anatoly techtonik -- ivan hilkov - Anthony Sottile +- ivan hilkov - Vincent Bernat - Kyle P Davis - Elias Kunnas +- Pierre Le Marre - Doug Turnbull - Anton Parkhomenko - Vyacheslav Levit From 100b73d1f88cd1c0e5cb3d0fc62643ebe25fb954 Mon Sep 17 00:00:00 2001 From: Brian Jacobel Date: Tue, 31 Jan 2017 14:45:17 -0500 Subject: [PATCH 043/239] Fixed --force downgrading when a higher version node exists in /src --- nodeenv.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 4eca78f..2d07418 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -559,7 +559,7 @@ def urlopen(url): # Virtual environment functions -def copy_node_from_prebuilt(env_dir, src_dir): +def copy_node_from_prebuilt(env_dir, src_dir, node_version): """ Copy prebuilt binaries into environment """ @@ -571,7 +571,7 @@ def copy_node_from_prebuilt(env_dir, src_dir): mkdir(join(env_dir, 'Scripts')) callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) else: - src_folder = src_dir + '/%s-v*/*' % prefix + src_folder = src_dir + '/%s-v%s*/*' % (prefix, node_version) callit(['cp', '-a', src_folder, env_dir], True, env_dir) logger.info('.', extra=dict(continued=True)) @@ -660,7 +660,7 @@ def install_node(env_dir, src_dir, opt): logger.info('.', extra=dict(continued=True)) if opt.prebuilt: - copy_node_from_prebuilt(env_dir, src_dir) + copy_node_from_prebuilt(env_dir, src_dir, opt.node) else: build_node_from_src(env_dir, src_dir, node_src_dir, opt) From 07b5b6680eab005434d713361fb6e3a0da598d1d Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 2 Feb 2017 12:31:21 +0300 Subject: [PATCH 044/239] update AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e49e190..ea15c12 100644 --- a/AUTHORS +++ b/AUTHORS @@ -49,5 +49,6 @@ Patches and Suggestions - Dan Fuchs - Damien Nozay - cmehay +- Brian Jacobel - Ben Davis - Alexey Poryadin From e9d144a087522a2d89af8881f0adcc47de9a082f Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 2 Feb 2017 12:41:09 +0300 Subject: [PATCH 045/239] fixed #49 (again) --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2d07418..2a0f2f3 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -571,7 +571,7 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): mkdir(join(env_dir, 'Scripts')) callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) else: - src_folder = src_dir + '/%s-v%s*/*' % (prefix, node_version) + src_folder = src_dir + to_utf8('/%s-v%s*/*' % (prefix, node_version)) callit(['cp', '-a', src_folder, env_dir], True, env_dir) logger.info('.', extra=dict(continued=True)) From e57f922bad1f74340f8e71f8d3a5bb8c887b79c0 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 2 Feb 2017 12:41:55 +0300 Subject: [PATCH 046/239] 1.1.1 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2a0f2f3..190f518 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -39,7 +39,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.1.0' +nodeenv_version = '1.1.1' join = os.path.join abspath = os.path.abspath From 7dbffce17bf9768c5eb5b857e522da4e61b5dcb7 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 2 Feb 2017 17:32:38 +0300 Subject: [PATCH 047/239] Update MANIFEST.in. Fixed #184 fixed debian folder (was renamed to debian-upstream long time ago) --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index bde96b9..15c7f9f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,7 @@ include README LICENSE CHANGES AUTHORS include *.py *.rst setup.cfg Makefile -graft debian +graft debian-upstream prune debian/nodeenv prune debian/sdist recursive-exclude debian *.log *.substvars files From 5f13f8616551cbb7a4fa6550272257e8b1850050 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 2 Feb 2017 18:26:19 +0300 Subject: [PATCH 048/239] Update MANIFEST.in # 2. Fixed #184 Fixed all rows. --- MANIFEST.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 15c7f9f..daa88db 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,6 +2,6 @@ include README LICENSE CHANGES AUTHORS include *.py *.rst setup.cfg Makefile graft debian-upstream -prune debian/nodeenv -prune debian/sdist -recursive-exclude debian *.log *.substvars files +prune debian-upstream/nodeenv +prune debian-upstream/sdist +recursive-exclude debian-upstream *.log *.substvars files From c7e3593dc600dd40d082217598a7472baba9499a Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 3 Feb 2017 16:12:34 +0300 Subject: [PATCH 049/239] 1.1.2 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 190f518..4b00ca1 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -39,7 +39,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.1.1' +nodeenv_version = '1.1.2' join = os.path.join abspath = os.path.abspath From ad8eabe92610765fbbef19a9bf1733f594ebbd9a Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 12:17:27 +0300 Subject: [PATCH 050/239] fixed spaces in paths. fix #187 --- nodeenv.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 4b00ca1..643388a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -25,6 +25,7 @@ import platform import zipfile import shutil +import glob try: # pragma: no cover (py2 only) from ConfigParser import SafeConfigParser as ConfigParser @@ -559,6 +560,16 @@ def urlopen(url): # Virtual environment functions +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): + shutil.copytree(s, d, symlinks, ignore) + else: + shutil.copy2(s, d) + + def copy_node_from_prebuilt(env_dir, src_dir, node_version): """ Copy prebuilt binaries into environment @@ -571,8 +582,9 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): mkdir(join(env_dir, 'Scripts')) callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) else: - src_folder = src_dir + to_utf8('/%s-v%s*/*' % (prefix, node_version)) - callit(['cp', '-a', src_folder, env_dir], True, env_dir) + src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, node_version)) + for src_folder in glob.glob(src_folder_tpl): + copytree(src_folder, env_dir) logger.info('.', extra=dict(continued=True)) From 23e9d2345af677bb8ce69eb1911c421f572638b7 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 12:18:11 +0300 Subject: [PATCH 051/239] improved gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 40fddb5..3720e91 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ env /*.egg-info/ .ropeproject/ .tox/ +.idea/ +.cache/ debian debian-upstream/files debian-upstream/nodeenv.substvars From 244e89ac27d353f6d820ec4a29c7535e0e44e053 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 12:25:27 +0300 Subject: [PATCH 052/239] improved unittests --- Makefile | 10 ++++++++-- requirements-dev.txt | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2b16635..ef7b69d 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,12 @@ env: . env/bin/activate && \ python setup.py install +env-dev: + @rm -rf env-dev && \ + virtualenv --no-site-packages env-dev && \ + . env-dev/bin/activate && \ + pip install -r requirements-dev.txt + test1: clean @echo " =" @echo " = test1: separate nodejs's env" @@ -116,8 +122,8 @@ test8: clean tests: clean test1 test2 test3 test4 test5 test7 test8 clean -ut: - @. env/bin/activate && tox -e py27 +ut: env-dev + @. env-dev/bin/activate && tox -e py27 contributors: @echo "Nodeenv is written and maintained by Eugene Kalinin." > AUTHORS diff --git a/requirements-dev.txt b/requirements-dev.txt index 3e5c34e..f9f2a89 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,3 +4,4 @@ coverage flake8 mock pytest +tox \ No newline at end of file From b1cfb32b5c7db59b93aa7a39a8fc48b428318e20 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 12:28:39 +0300 Subject: [PATCH 053/239] improved gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3720e91..e10547b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.swp *.swo env +env-dev /nodeenv /TODO /build/ From 08f3510e485ebfbeafb224554cb293434c27a0ca Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 12:29:01 +0300 Subject: [PATCH 054/239] 1.1.3 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 643388a..273f35a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -40,7 +40,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.1.2' +nodeenv_version = '1.1.3' join = os.path.join abspath = os.path.abspath From 35102c02469b78f04f581c31906d06638195cd1a Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 16:12:24 +0300 Subject: [PATCH 055/239] fixed dir copy if it exists; + fixed symlinks as well. fix #188 --- nodeenv.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 273f35a..c286f56 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -565,9 +565,15 @@ def copytree(src, dst, symlinks=False, ignore=None): s = os.path.join(src, item) d = os.path.join(dst, item) if os.path.isdir(s): - shutil.copytree(s, d, symlinks, ignore) + try: + shutil.copytree(s, d, symlinks, ignore) + except OSError: + copytree(s, d, symlinks, ignore) else: - shutil.copy2(s, d) + if os.path.islink(s): + os.symlink(os.readlink(s), d) + else: + shutil.copy2(s, d) def copy_node_from_prebuilt(env_dir, src_dir, node_version): @@ -584,7 +590,7 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): else: src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, node_version)) for src_folder in glob.glob(src_folder_tpl): - copytree(src_folder, env_dir) + copytree(src_folder, env_dir, True) logger.info('.', extra=dict(continued=True)) From 3b947d2f994ed215e798165fb001f53c871fd698 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 16:12:38 +0300 Subject: [PATCH 056/239] added test9 --- Makefile | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ef7b69d..39cbf27 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,8 @@ test7: clean nodeenv -j 4 -p --prebuilt && \ . env/bin/activate && \ npm install -g sitemap && \ + npm -v && \ + node -v && \ test "`freeze | wc -l`" = "1"; test8: clean @@ -118,9 +120,22 @@ test8: clean . env/bin/activate && \ python setup.py install && \ rm -rf öäü && mkdir öäü && cd öäü && \ - nodeenv -j 4 --prebuilt env + nodeenv -j 4 --prebuilt env && \ + rm -rf öäü -tests: clean test1 test2 test3 test4 test5 test7 test8 clean +test9: clean + @echo " =" + @echo " = test9: unicode paths, #187" + @echo " =" + @rm -rf env && \ + virtualenv --no-site-packages env && \ + . env/bin/activate && \ + python setup.py install && \ + rm -rf "test dir" && mkdir "test dir" && cd "test dir" && \ + nodeenv -j 4 --prebuilt env && \ + rm -rf "test dir" + +tests: clean test1 test2 test3 test4 test5 test7 test8 test9 clean ut: env-dev @. env-dev/bin/activate && tox -e py27 From e0b0bd40556161b65eb97e537ae3ab30f5ab86c6 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 29 Jun 2017 16:13:30 +0300 Subject: [PATCH 057/239] 1.1.4 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index c286f56..bfa1987 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -40,7 +40,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.1.3' +nodeenv_version = '1.1.4' join = os.path.join abspath = os.path.abspath From d167d21b1186b86eced75a30180c0e52b25a83ba Mon Sep 17 00:00:00 2001 From: Lucas Cimon Date: Fri, 28 Jul 2017 14:33:32 +0200 Subject: [PATCH 058/239] Adding support for Cygwin --- nodeenv.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index bfa1987..1f6cda6 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -51,6 +51,7 @@ from functools import cmp_to_key is_WIN = platform.system() == 'Windows' +is_CYGWIN = platform.system().startswith('CYGWIN') # --------------------------------------------------------- @@ -504,7 +505,7 @@ def get_node_bin_url(version): 'system': platform.system().lower(), 'arch': archmap[platform.machine()], } - if is_WIN: + if is_WIN or is_CYGWIN: filename = 'win-%(arch)s/node.exe' % sysinfo else: postfix = '-%(system)s-%(arch)s.tar.gz' % sysinfo @@ -535,7 +536,7 @@ def download_node_src(node_url, src_dir, opt, prefix): dl_contents = io.BytesIO(urlopen(node_url).read()) logger.info('.', extra=dict(continued=True)) - if is_WIN: + if is_WIN or is_CYGWIN: writefile(join(src_dir, 'node.exe'), dl_contents.read()) else: with tarfile_open(fileobj=dl_contents) as tarfile_obj: @@ -794,6 +795,8 @@ def install_activate(env_dir, opt): 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 opt.node == "system": files["node"] = SHIM From fd909f6d3364799e244c3dcff92dfd0dedfd5985 Mon Sep 17 00:00:00 2001 From: Lucas Cimon Date: Fri, 28 Jul 2017 14:33:32 +0200 Subject: [PATCH 059/239] Fixing support for Cygwin --- nodeenv.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 1f6cda6..0844d18 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -88,7 +88,7 @@ class Config(object): # Defaults node = 'latest' npm = 'latest' - with_npm = True if is_WIN else False + with_npm = True if is_WIN or is_CYGWIN else False jobs = '2' without_ssl = False debug = False @@ -588,6 +588,12 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): dst_exe = join(env_dir, 'Scripts', 'node.exe') mkdir(join(env_dir, 'Scripts')) callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) + elif is_CYGWIN: + mkdir(join(env_dir, 'bin')) + writefile(join(env_dir, 'bin', 'node'), CYGWIN_NODE) + src_exe = join(src_dir, 'node.exe') + dst_exe = join(env_dir, 'bin', 'node.exe') + callit(['cp', '-a', src_exe, dst_exe], True, env_dir) else: src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, node_version)) for src_folder in glob.glob(src_folder_tpl): @@ -749,6 +755,11 @@ def install_npm_win(env_dir, src_dir, opt): 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')) + writefile(join(env_dir, 'bin', 'npm'), urlopen('https://raw.githubusercontent.com/npm/npm/{}/bin/npm'.format(opt.npm)).read()) + def install_packages(env_dir, opt): """ @@ -824,6 +835,11 @@ 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 @@ -871,7 +887,7 @@ def create_environment(env_dir, opt): # for install install_activate(env_dir, opt) if node_version_from_opt(opt) < parse_version("0.6.3") or opt.with_npm: - instfunc = install_npm_win if is_WIN else install_npm + instfunc = install_npm_win if is_WIN or is_CYGWIN else install_npm instfunc(env_dir, src_dir, opt) if opt.requirements: install_packages(env_dir, opt) @@ -1243,8 +1259,8 @@ def main(): _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" +NPM_CONFIG_PREFIX="__NPM_CONFIG_PREFIX__" +npm_config_prefix="__NPM_CONFIG_PREFIX__" export NPM_CONFIG_PREFIX export npm_config_prefix @@ -1276,5 +1292,17 @@ def main(): if type -p deactivate_node > /dev/null; then deactivate_node;fi """ +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() From cd59d83f677057ad3cf2aba427ce8c0df83f8d04 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 31 Jul 2017 11:26:13 +0300 Subject: [PATCH 060/239] added linter hints; pep8 --- nodeenv.py | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 0844d18..0bce18d 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -29,11 +29,13 @@ try: # pragma: no cover (py2 only) from ConfigParser import SafeConfigParser as ConfigParser + # noinspection PyCompatibility from HTMLParser import HTMLParser import urllib2 iteritems = operator.methodcaller('iteritems') except ImportError: # pragma: no cover (py3 only) from configparser import ConfigParser + # noinspection PyUnresolvedReferences from html.parser import HTMLParser import urllib.request as urllib2 iteritems = operator.methodcaller('items') @@ -176,8 +178,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): @@ -198,8 +200,8 @@ def emit(self, record): ch.setFormatter(formatter) # add ch to logger - logger.addHandler(ch) - return logger + loggr.addHandler(ch) + return loggr logger = create_logger() @@ -378,6 +380,7 @@ def mkdir(path): logger.debug(' * Directory %s already exists', path) +# noinspection PyArgumentList def writefile(dest, content, overwrite=True, append=False): """ Create file and write content in it @@ -488,7 +491,7 @@ def get_root_url(version): if parse_version(version) > parse_version("0.5.0"): return 'https://%s/dist/v%s/' % (src_domain, version) else: - return 'https://%s/dist/' % (src_domain) + return 'https://%s/dist/' % src_domain def get_node_bin_url(version): @@ -637,9 +640,10 @@ 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)) + conf_cmd = [ + './configure', + '--prefix=%s' % pipes.quote(env_dir) + ] if opt.without_ssl: conf_cmd.append('--without-ssl') if opt.debug: @@ -692,7 +696,7 @@ def install_node(env_dir, src_dir, opt): logger.info(' done.') -def install_npm(env_dir, src_dir, opt): +def install_npm(env_dir, _src_dir, opt): """ Download source code for npm, unpack it and install it in virtual environment. @@ -756,9 +760,13 @@ def install_npm_win(env_dir, src_dir, opt): 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')) - writefile(join(env_dir, 'bin', 'npm'), urlopen('https://raw.githubusercontent.com/npm/npm/{}/bin/npm'.format(opt.npm)).read()) + 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/npm' + npm_bin_url = '{}/{}/bin/npm'.format(npm_gh_url, opt.npm) + writefile(join(env_dir, 'bin', 'npm'), urlopen(npm_bin_url).read()) def install_packages(env_dir, opt): @@ -836,10 +844,12 @@ def install_activate(env_dir, opt): 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) + _, 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') + content = content.replace('__NPM_CONFIG_PREFIX__', + '$NODE_VIRTUAL_ENV') # if we call in the same environment: # $ nodeenv -p --prebuilt # $ nodeenv -p --node=system @@ -969,7 +979,7 @@ def get_last_stable_node_version(): """ Return last stable node.js version """ - response = urlopen('https://%s/dist/latest/' % (src_domain)) + response = urlopen('https://%s/dist/latest/' % src_domain) href_parser = GetsAHrefs() href_parser.feed(response.read().decode('UTF-8')) @@ -1012,6 +1022,7 @@ def is_installed(name): return True +# noinspection PyProtectedMember def main(): """ Entry point @@ -1022,6 +1033,7 @@ def main(): return opt, args = parse_args(check=False) + # noinspection PyProtectedMember Config._load(opt.config_file, opt.verbose) opt, args = parse_args() From 96bcdb6f42e3298c5fde19585175c58565c30d2a Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Mon, 31 Jul 2017 11:31:07 +0300 Subject: [PATCH 061/239] pep8 --- nodeenv.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 0bce18d..9f7e9d9 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -844,8 +844,9 @@ def install_activate(env_dir, opt): 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) + _, 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__', From b0c0625b2700e68834e7f97371cc191ed61027c6 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 31 Jul 2017 20:36:18 +0100 Subject: [PATCH 062/239] Include tox.ini as default configuration file --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 1f6cda6..62f2a59 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -341,7 +341,7 @@ def parse_args(check=True): options, args = parser.parse_args() if options.config_file is None: - options.config_file = ["./setup.cfg", "~/.nodeenvrc"] + options.config_file = ["./tox.ini", "./setup.cfg", "~/.nodeenvrc"] elif not options.config_file: options.config_file = [] else: From 7f9d52c4f6ce3753b13c939f487870edb3473e99 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 2 Aug 2017 13:51:16 +0300 Subject: [PATCH 063/239] update AUTHORS --- AUTHORS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS b/AUTHORS index ea15c12..0af7410 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,6 +18,7 @@ Patches and Suggestions - syndbg - Spencer Rathbun - Luis Orduz +- Lucas Cimon - Lispython - Leonardo Fedalto - Kyle P Davis @@ -34,6 +35,7 @@ Patches and Suggestions - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski +- michael - Max Liebkies - Marc-Antoine Parent - Marc Abramowitz From e662a14e71d4fd712e1dc2eb1b0d1f170bf9d303 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 2 Aug 2017 13:57:49 +0300 Subject: [PATCH 064/239] 1.2.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 41d2f28..ba84b05 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.1.4' +nodeenv_version = '1.2.0' join = os.path.join abspath = os.path.abspath From 6c2697559efa071c2060327f327e8c088408b309 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 9 Aug 2017 17:27:09 +0300 Subject: [PATCH 065/239] update CHANGES --- CHANGES | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGES b/CHANGES index ebc168a..cd6b599 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,34 @@ Nodeenv changelog ================= +Version 1.2.0 +------------- +- Support for Cygwin `#194 https://github.com/ekalinin/nodeenv/pull/194`_ `#195 + https://github.com/ekalinin/nodeenv/pull/195`_ +- tox.ini as default configuration file `#197 + https://github.com/ekalinin/nodeenv/pull/197`_ + +Version 1.1.4 +------------- +- Fixed directory copy `#188 https://github.com/ekalinin/nodeenv/issues/188`_ + +Version 1.1.3 +------------- +- Fixed spaces in paths `#187 https://github.com/ekalinin/nodeenv/issues/187`_ + +Version 1.1.2 +------------- +- Fixed MANIFEST.in `#184 https://github.com/ekalinin/nodeenv/issues/184`_ + +Version 1.1.1 +------------- +- Improve Windows support. See `#181 + https://github.com/ekalinin/nodeenv/pull/181`_ +- Fix bug when downgrading using `--force`. See `#183 + https://github.com/ekalinin/nodeenv/pull/183`_ +- Environment creation fails with non-ASCII chars in path. See `#49 + https://github.com/ekalinin/nodeenv/issues/49`_ + Version 1.1.0 ------------- - Windows support From e5b12be3562070f74bb6e1763544fbec8c0cdaea Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 14 Sep 2017 22:34:54 -0300 Subject: [PATCH 066/239] Add py36 environment to CI and fix test test_predeactivate_hook fails on py36 because tmpdir (py.local) now implements the __path__ protocol so it the call to open inside nodeenv.set_predeactivate_hook actually goes through but fails with an FileNotFoundError --- .travis.yml | 1 + setup.py | 1 + tests/nodeenv_test.py | 2 +- tox.ini | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6745258..8396c04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ env: # These should match the tox env list - TOXENV=py33 - TOXENV=py34 - TOXENV=py35 + - TOXENV=py36 - TOXENV=pypy install: pip install coveralls tox script: tox diff --git a/setup.py b/setup.py index e0b304d..2c1ff5d 100644 --- a/setup.py +++ b/setup.py @@ -54,6 +54,7 @@ def read_file(file_name): 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index d58010b..5e0c231 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -146,7 +146,7 @@ def test_print_node_versions_node(cap_logging_info): def test_predeactivate_hook(tmpdir): # Throw error if the environment directory is not a string with pytest.raises((TypeError, AttributeError)): - nodeenv.set_predeactivate_hook(tmpdir) + 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) diff --git a/tox.ini b/tox.ini index faf6e9a..10a37c2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the travis env list -envlist = py27,py33,py34,py35,pypy +envlist = py27,py33,py34,py35,py36,pypy [testenv] install_command = pip install --use-wheel {opts} {packages} From dcc491cdf163101de0abb50c7705301d69b6c83e Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 14 Sep 2017 22:43:50 -0300 Subject: [PATCH 067/239] Use tox-travis and list all python versions explicitly Travis does not guarantee that a certain python version other than the one specified in 'python' is installed, and since the new 'trusty' images have been introduced Python 3.3 and 3.6 are not installed by default. tox-travis automatically selects the appropriate tox environment based on the current python --- .travis.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8396c04..ec6baab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,12 @@ language: python -python: 3.5 -env: # These should match the tox env list - - TOXENV=py27 - - TOXENV=py33 - - TOXENV=py34 - - TOXENV=py35 - - TOXENV=py36 - - TOXENV=pypy -install: pip install coveralls tox +python: + - 2.7 + - 3.3 + - 3.4 + - 3.5 + - 3.6 + - pypy +install: pip install coveralls tox-travis script: tox after_success: - coveralls From ff9d2229defee8d93d3a33e36ad94d3b8add234a Mon Sep 17 00:00:00 2001 From: Terseus Date: Sat, 21 Oct 2017 14:25:20 +0200 Subject: [PATCH 068/239] Add "activate.fish" script for fish shell support --- nodeenv.py | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index ba84b05..3a4ab55 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -810,7 +810,11 @@ def install_activate(env_dir, opt): shim_node = join(bin_dir, "node.exe") shim_nodejs = join(bin_dir, "nodejs.exe") else: - files = {'activate': ACTIVATE_SH, 'shim': SHIM} + 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") @@ -1241,7 +1245,7 @@ def main(): fi } -# unset irrelavent variables +# unset irrelevant variables deactivate_node nondestructive # find the directory of this script @@ -1301,6 +1305,136 @@ def main(): 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 + + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + set -e _OLD_NODE_FISH_PROMPT_OVERRIDE + end + + 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 + +# NODE_VIRTUAL_ENV is the parent of the directory where this script is +set -gx NODE_VIRTUAL_ENV __NODE_VIRTUAL_ENV__ + +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 `_old_fish_prompt`. + functions -c fish_prompt _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 "" + printf '%s%s' "" (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$NODE_VIRTUAL_ENV") + end + + # Restore the original $status + echo "exit $old_status" | source + _old_fish_prompt + end + + set -gx _OLD_NODE_FISH_PROMPT_OVERRIDE "$NODE_VIRTUAL_ENV" +end +""" # noqa + PREDEACTIVATE_SH = """ if type -p deactivate_node > /dev/null; then deactivate_node;fi """ From 10a7a4b062f53bf70f4f472da5b650e998d6c355 Mon Sep 17 00:00:00 2001 From: dkgitdev <36101416+dkgitdev@users.noreply.github.com> Date: Wed, 7 Feb 2018 12:07:09 +0700 Subject: [PATCH 069/239] Fixed "CP866" encoded errors Ran into it on my windows pc. Fixed it that way. --- nodeenv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 3a4ab55..fed2d94 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -470,7 +470,10 @@ def callit(cmd, show_stdout=True, in_shell=False, line = stdout.readline() if not line: break - line = line.decode('utf-8').rstrip() + try: + line = line.decode('utf8').rstrip() + except UnicodeDecodeError: + line = line.decode('cp866').rstrip() all_output.append(line) if show_stdout: logger.info(line) From 84776c783954670d528ee9d47096d34f4f78bcd4 Mon Sep 17 00:00:00 2001 From: 0Xellos Date: Sat, 17 Feb 2018 19:02:04 +0100 Subject: [PATCH 070/239] conda support added support for conda virtual environments --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index fed2d94..8687c1a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1010,7 +1010,7 @@ def get_env_dir(opt, args): if opt.python_virtualenv: if hasattr(sys, 'real_prefix'): res = sys.prefix - elif hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix: + elif hasattr(sys, 'base_prefix') and (sys.base_prefix != sys.prefix or 'CONDA_PREFIX' in os.environ): res = sys.prefix else: logger.error('No python virtualenv is available') From d001e746d7af418c72872fb250036fd7fd07d1c1 Mon Sep 17 00:00:00 2001 From: 0Xellos Date: Mon, 19 Feb 2018 21:23:46 +0100 Subject: [PATCH 071/239] split long line into two ifs --- nodeenv.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 8687c1a..d288d51 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1010,7 +1010,9 @@ def get_env_dir(opt, args): if opt.python_virtualenv: if hasattr(sys, 'real_prefix'): res = sys.prefix - elif hasattr(sys, 'base_prefix') and (sys.base_prefix != sys.prefix or 'CONDA_PREFIX' in os.environ): + elif hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix: + res = sys.prefix + elif 'CONDA_PREFIX' in os.environ: res = sys.prefix else: logger.error('No python virtualenv is available') From c5a482fb0f6aef414df30efd20539f66a9a61fa0 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 21 Mar 2018 12:33:53 +0300 Subject: [PATCH 072/239] Copy link only if it not exists; fix #189 --- nodeenv.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index d288d51..a76e589 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -578,7 +578,9 @@ def copytree(src, dst, symlinks=False, ignore=None): copytree(s, d, symlinks, ignore) else: if os.path.islink(s): - os.symlink(os.readlink(s), d) + # 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) From 1102dc99a58e701e42989fd24785f40b0aa157eb Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 21 Mar 2018 12:34:13 +0300 Subject: [PATCH 073/239] 1.3.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index a76e589..106cde2 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.2.0' +nodeenv_version = '1.3.0' join = os.path.join abspath = os.path.abspath From 6a4c14fd1b5b7e10d6c1ac917f66f4a9863b10a8 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 21 Mar 2018 12:39:43 +0300 Subject: [PATCH 074/239] Added a test for #189 --- Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Makefile b/Makefile index 39cbf27..2c9a3d6 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,17 @@ test9: clean nodeenv -j 4 --prebuilt env && \ rm -rf "test dir" +test10: clean + @echo " =" + @echo " = test10: unicode paths, #189" + @echo " =" + @rm -rf env && \ + virtualenv --no-site-packages env && \ + . env/bin/activate && \ + python setup.py install && \ + nodeenv -j 4 -p --prebuilt && \ + nodeenv -j 4 -p --prebuilt + tests: clean test1 test2 test3 test4 test5 test7 test8 test9 clean ut: env-dev From bb3b35a34560e2d670e34f36257ff8d6c39b2d9a Mon Sep 17 00:00:00 2001 From: jiho Date: Sun, 25 Mar 2018 19:25:05 +0900 Subject: [PATCH 075/239] Fixed nodeenv -p execution error in Korean Windows environment --- nodeenv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 106cde2..2e1a966 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -471,7 +471,10 @@ def callit(cmd, show_stdout=True, in_shell=False, if not line: break try: - line = line.decode('utf8').rstrip() + 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) From 957df26f10738b9fcbac247d1b013875e101858c Mon Sep 17 00:00:00 2001 From: Fabricio C Zuardi Date: Wed, 28 Mar 2018 23:21:06 -0300 Subject: [PATCH 076/239] fix url for arm64 binaries see #209 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2e1a966..fe79d3e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -508,7 +508,7 @@ def get_node_bin_url(version): 'AMD64': 'x64', # Windows Server 2012 R2 (x64) 'armv6l': 'armv6l', # arm 'armv7l': 'armv7l', - 'aarch64': 'armv64', + 'aarch64': 'arm64', } sysinfo = { 'system': platform.system().lower(), From c8a35e596c091505b79f85c06e17acbc08bfb507 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 12 Apr 2018 16:22:58 +1200 Subject: [PATCH 077/239] Fix invalid fish-shell script generation with a python virtualenv --- nodeenv.py | 32 +++++++++---- tests/test_install_activate.py | 85 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 tests/test_install_activate.py diff --git a/nodeenv.py b/nodeenv.py index fe79d3e..749642c 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -412,11 +412,7 @@ def writefile(dest, content, overwrite=True, append=False): if append: logger.info(' * Appending data to %s', dest) with open(dest, 'ab') as f: - if not is_WIN: - f.write(DISABLE_PROMPT.encode('utf-8')) f.write(content) - if not is_WIN: - f.write(ENABLE_PROMPT.encode('utf-8')) return logger.info(' * Overwriting %s with new content', dest) @@ -869,7 +865,12 @@ def install_activate(env_dir, opt): # we should get `bin/node` not as binary+string. # `bin/activate` should be appended if we inside # existing python's virtual environment - need_append = 0 if name in ('node', 'shim') else opt.python_virtualenv + need_append = False + if opt.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): @@ -1077,16 +1078,29 @@ def main(): # --------------------------------------------------------- # 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 diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py new file mode 100644 index 0000000..74f4764 --- /dev/null +++ b/tests/test_install_activate.py @@ -0,0 +1,85 @@ +import sys +import os + +import mock +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()[0] + 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()[0] + 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) From dcb4f508137899eda18bbe27b01da3bc93942054 Mon Sep 17 00:00:00 2001 From: Chris Beaven Date: Thu, 12 Apr 2018 16:59:46 +1200 Subject: [PATCH 078/239] Fix flake8 issue --- tests/test_install_activate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 74f4764..80e32ad 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -41,7 +41,6 @@ def fix_content(content, tmpdir): return content - @pytest.mark.parametrize('name, content_var', FILES.items()) def test_write(tmpdir, name, content_var): if nodeenv.is_WIN: From f9dc1295c58a78c780d56ccd6350ac85fbbcbd7f Mon Sep 17 00:00:00 2001 From: Uman Shahzad Date: Sun, 29 Apr 2018 17:26:50 +0500 Subject: [PATCH 079/239] Add a space before the normal $PS1. This matches the outwards behavior of how the name of the virtualenv normally appears. --- nodeenv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index fe79d3e..afda27b 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1294,14 +1294,14 @@ def main(): 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" else - PS1="(`basename \"$NODE_VIRTUAL_ENV\"`)$PS1" + PS1="(`basename \"$NODE_VIRTUAL_ENV\"`) $PS1" fi fi export PS1 From 0672933cc9a0b87cd4f8c69ebfcd17fb19a1cdae Mon Sep 17 00:00:00 2001 From: Willem Jan Withagen Date: Sun, 10 Jun 2018 16:32:30 +0200 Subject: [PATCH 080/239] FreeBSD returns amd64 when running this --- nodeenv.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nodeenv.py b/nodeenv.py index fe79d3e..53a8ff6 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -505,6 +505,7 @@ def get_node_bin_url(version): 'x86': 'x86', # Windows Vista 32 'i686': 'x86', 'x86_64': 'x64', # Linux Ubuntu 64 + 'amd64': 'x64', # FreeBSD 64bits 'AMD64': 'x64', # Windows Server 2012 R2 (x64) 'armv6l': 'armv6l', # arm 'armv7l': 'armv7l', From c29e828016dde8e4532e81bdfc354d7ee828d21b Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 11:55:00 +0300 Subject: [PATCH 081/239] update AUTHORS --- AUTHORS | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0af7410..b2548e2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,9 +13,9 @@ Patches and Suggestions - Pierre Le Marre - Doug Turnbull - Anton Parkhomenko +- syndbg - Vyacheslav Levit - Travis Miller -- syndbg - Spencer Rathbun - Luis Orduz - Lucas Cimon @@ -23,19 +23,27 @@ Patches and Suggestions - Leonardo Fedalto - Kyle P Davis - Dennis Flanigan +- Chris Beaven +- Bruno Oliveira - Andrzej Pragacz - Alex Couper +- 0Xellos +- michael +- jiho +- dkgitdev +- dhilipsiva +- cmehay - Zenobius Jiricek - Yi-Feng Tzeng - Vladimír Gorej - Vincent Bernat +- Terseus - Stan Seibert - Shubhang Mani - Rik - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski -- michael - Max Liebkies - Marc-Antoine Parent - Marc Abramowitz @@ -45,12 +53,11 @@ Patches and Suggestions - Jesse Dhillon - Jeremy Banks - Geoffrey Huntley -- dhilipsiva +- Fabricio C Zuardi - Dennis Flanigan - Dan North - Dan Fuchs - Damien Nozay -- cmehay - Brian Jacobel - Ben Davis - Alexey Poryadin From 2c365a00f0487295431d0acd473706a80bb5215f Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 11:55:09 +0300 Subject: [PATCH 082/239] update CHANGES --- CHANGES | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGES b/CHANGES index cd6b599..ed50f27 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,22 @@ Nodeenv changelog ================= +Version 1.3.1 +------------- +- Windows related fix `#207 https://github.com/ekalinin/nodeenv/pull/207` +- Fixed url for arm64 `#210 https://github.com/ekalinin/nodeenv/pull/210`_ +- Fixed fish support `#212 https://github.com/ekalinin/nodeenv/pull/212`_ + + +Version 1.3.0 +------------- +- Fixed symlink creation `#189 https://github.com/ekalinin/nodeenv/issues/189`_ +- Python3.6 support `#200 https://github.com/ekalinin/nodeenv/pull/200`_ +- Added `activate` for fish `#201 https://github.com/ekalinin/nodeenv/pull/201`_ +- Fixed cp866 `#202 https://github.com/ekalinin/nodeenv/pull/202`_ +- Added Conda support `#203 https://github.com/ekalinin/nodeenv/pull/203`_ + + Version 1.2.0 ------------- - Support for Cygwin `#194 https://github.com/ekalinin/nodeenv/pull/194`_ `#195 From c8b9c5ea61990449ca0c0f937de95b4b4ba1b99f Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 11:55:44 +0300 Subject: [PATCH 083/239] Makefile: fixed deploy-pypi; added test10 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2c9a3d6..79c77b9 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ deploy-github: git push --tags origin master deploy-pypi: - python setup.py sdist upload + python setup.py sdist upload -r pypi update-pypi: python setup.py register @@ -146,7 +146,7 @@ test10: clean nodeenv -j 4 -p --prebuilt && \ nodeenv -j 4 -p --prebuilt -tests: clean test1 test2 test3 test4 test5 test7 test8 test9 clean +tests: test1 test2 test3 test4 test5 test7 test8 test9 test10 clean ut: env-dev @. env-dev/bin/activate && tox -e py27 From 33391193b2bc21d3305c164bcc372be000332510 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 11:55:56 +0300 Subject: [PATCH 084/239] 1.3.1 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 749642c..6269349 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.0' +nodeenv_version = '1.3.1' join = os.path.join abspath = os.path.abspath From 0a3b31c24d577bb4176ee840341d2d13d82b8c7e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 12:23:52 +0300 Subject: [PATCH 085/239] fixed tox.ini --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 10a37c2..784ebc1 100644 --- a/tox.ini +++ b/tox.ini @@ -3,7 +3,7 @@ envlist = py27,py33,py34,py35,py36,pypy [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 From 7f3121066edbf9b79a55f23f64fff03771076d47 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 14:07:02 +0300 Subject: [PATCH 086/239] fixed tox.ini (excluded py33) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 784ebc1..5263a28 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the travis env list -envlist = py27,py33,py34,py35,py36,pypy +envlist = py27,py34,py35,py36,pypy [testenv] install_command = pip install {opts} {packages} From cd4430f631d9e74a389a3df97a6a0eaffb1635b2 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 13 Jun 2018 14:12:12 +0300 Subject: [PATCH 087/239] travis: excluded py33 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ec6baab..b0202e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - 2.7 - - 3.3 - 3.4 - 3.5 - 3.6 From 3ce739b912386c4b31802f40797850e74bbe570b Mon Sep 17 00:00:00 2001 From: urbandove Date: Tue, 17 Jul 2018 10:24:38 -0400 Subject: [PATCH 088/239] update node/node -> node/cli the github location of npm has changed from github.com/npm/npm to npm/cli see https://github.com/npm/npm/ --- nodeenv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 6249536..6a89c3e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -739,7 +739,7 @@ def install_npm_win(env_dir, src_dir, opt): """ logger.info(' * Install npm.js (%s) ... ' % opt.npm, extra=dict(continued=True)) - npm_url = 'https://github.com/npm/npm/archive/%s.zip' % opt.npm + npm_url = 'https://github.com/npm/cli/archive/%s.zip' % opt.npm npm_contents = io.BytesIO(urlopen(npm_url).read()) bin_path = join(env_dir, 'Scripts') @@ -757,7 +757,7 @@ def install_npm_win(env_dir, src_dir, opt): with zipfile.ZipFile(npm_contents, 'r') as zipf: zipf.extractall(src_dir) - npm_ver = 'npm-%s' % opt.npm + npm_ver = 'cli-%s' % opt.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')) From 1ce90d1f98c63e06c38032eff7eda8a11dfa6774 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 19 Jul 2018 01:19:33 +0300 Subject: [PATCH 089/239] update AUTHORS --- AUTHORS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index b2548e2..0cda906 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,6 +28,7 @@ Patches and Suggestions - Andrzej Pragacz - Alex Couper - 0Xellos +- urbandove - michael - jiho - dkgitdev @@ -35,8 +36,10 @@ Patches and Suggestions - cmehay - Zenobius Jiricek - Yi-Feng Tzeng +- Willem Jan Withagen - Vladimír Gorej - Vincent Bernat +- Uman Shahzad - Terseus - Stan Seibert - Shubhang Mani From f3bfccf85b765d87f79c0189c3e0da9d32bdcaeb Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 19 Jul 2018 01:19:49 +0300 Subject: [PATCH 090/239] 1.3.2 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 6a89c3e..cfc7c28 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.1' +nodeenv_version = '1.3.2' join = os.path.join abspath = os.path.abspath From 15f3b4c7a93f41e972842472f9551715178717a0 Mon Sep 17 00:00:00 2001 From: Joby Harding Date: Thu, 19 Jul 2018 10:56:34 +0100 Subject: [PATCH 091/239] Update install from source example --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6ebe976..7743d6d 100644 --- a/README.rst +++ b/README.rst @@ -134,7 +134,7 @@ for compilation and npm.js "0.3.17":: Install node.js from the source:: - $ nodeenv --node=0.10.25 --source env-0.10.25-prebuilt + $ nodeenv --node=0.10.25 --source env-0.10.25 It's much faster to install from the prebuilt package than Install & compile node.js from source:: From 86f3bd19c4956f8bb6ea3b9d2984232fc740cd89 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 6 Nov 2018 14:36:34 +0300 Subject: [PATCH 092/239] install certain npm version via 'npm install'. fixes #225 --- nodeenv.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index cfc7c28..526ae4a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -708,7 +708,6 @@ def install_npm(env_dir, _src_dir, opt): """ logger.info(' * Install npm.js (%s) ... ' % opt.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', @@ -717,8 +716,9 @@ def install_npm(env_dir, _src_dir, opt): proc = subprocess.Popen( ( 'bash', '-c', - '. {0} && exec bash'.format( + '. {0} && npm install -g npm@{1}'.format( pipes.quote(join(env_dir, 'bin', 'activate')), + opt.npm, ) ), env=env, @@ -726,7 +726,7 @@ def install_npm(env_dir, _src_dir, opt): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) - out, _ = proc.communicate(npm_contents) + out, _ = proc.communicate() if opt.verbose: logger.info(out) logger.info('done.') From ad95372dea187a1ae34fb92a4d414880c6052c05 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 6 Nov 2018 15:54:09 +0300 Subject: [PATCH 093/239] fixed build (flake8) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 5263a28..31e0f24 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ commands = # Needed because we subprocess to ourselves coverage combine coverage report --show-missing --fail-under 55 # TODO: 100 - flake8 nodeenv.py tests setup.py + flake8 --ignore=W605,W504,E241 nodeenv.py tests setup.py [testenv:venv] envdir = venv-nodeenv From e9dccbaa592e52fbaf34ec069ecb2e970c59da73 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 6 Nov 2018 15:58:49 +0300 Subject: [PATCH 094/239] 1.3.3 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 526ae4a..853d71b 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.2' +nodeenv_version = '1.3.3' join = os.path.join abspath = os.path.abspath From d59d6341c371ab4b470f5a88856addf7e3abbafd Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 6 Nov 2018 16:07:21 +0300 Subject: [PATCH 095/239] fixed 'deploy-pypi' --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 79c77b9..39f9a46 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ deploy-github: git push --tags origin master deploy-pypi: - python setup.py sdist upload -r pypi + python setup.py sdist + twine upload --repository pypi dist/* update-pypi: python setup.py register From 14e45a12757c0331c38afb41f41c40aecb2cdd00 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 6 Nov 2018 16:29:37 +0300 Subject: [PATCH 096/239] update AUTHORS --- AUTHORS | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0cda906..83b7fb2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,9 +13,9 @@ Patches and Suggestions - Pierre Le Marre - Doug Turnbull - Anton Parkhomenko -- syndbg - Vyacheslav Levit - Travis Miller +- syndbg - Spencer Rathbun - Luis Orduz - Lucas Cimon @@ -28,17 +28,12 @@ Patches and Suggestions - Andrzej Pragacz - Alex Couper - 0Xellos -- urbandove -- michael -- jiho -- dkgitdev -- dhilipsiva -- cmehay - Zenobius Jiricek - Yi-Feng Tzeng - Willem Jan Withagen - Vladimír Gorej - Vincent Bernat +- urbandove - Uman Shahzad - Terseus - Stan Seibert @@ -47,20 +42,26 @@ Patches and Suggestions - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski +- michael - Max Liebkies - Marc-Antoine Parent - Marc Abramowitz - Laust Rud Jacobsen - Ken Struys - Kai Weber +- Joby Harding +- jiho - Jesse Dhillon - Jeremy Banks - Geoffrey Huntley - Fabricio C Zuardi +- dkgitdev +- dhilipsiva - Dennis Flanigan - Dan North - Dan Fuchs - Damien Nozay +- cmehay - Brian Jacobel - Ben Davis - Alexey Poryadin From bfe13b39d62d82ce39ce48a46f28b2eeeec6e3a5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 2 Jan 2019 21:14:26 -0800 Subject: [PATCH 097/239] Use prebuilt windows zip which contains npm --- .coveragerc | 1 - nodeenv.py | 79 ++++++++++++++++++++++++++++++++--------------------- tox.ini | 2 +- 3 files changed, 49 insertions(+), 33 deletions(-) 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/nodeenv.py b/nodeenv.py index 853d71b..6283e22 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -90,7 +90,7 @@ class Config(object): # Defaults node = 'latest' npm = 'latest' - with_npm = True if is_WIN or is_CYGWIN else False + with_npm = False jobs = '2' without_ssl = False debug = False @@ -380,13 +380,17 @@ 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 and type(content) != bytes: content = bytes(content, 'utf-8') @@ -394,7 +398,7 @@ def writefile(dest, content, overwrite=True, append=False): 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: @@ -512,7 +516,8 @@ def get_node_bin_url(version): 'arch': archmap[platform.machine()], } if is_WIN or is_CYGWIN: - filename = 'win-%(arch)s/node.exe' % sysinfo + postfix = '-win-%(arch)s.zip' % sysinfo + filename = '%s-v%s%s' % (get_binary_prefix(), version, postfix) else: postfix = '-%(system)s-%(arch)s.tar.gz' % sysinfo filename = '%s-v%s%s' % (get_binary_prefix(), version, postfix) @@ -543,18 +548,24 @@ def download_node_src(node_url, src_dir, opt, prefix): logger.info('.', extra=dict(continued=True)) if is_WIN or is_CYGWIN: - writefile(join(src_dir, 'node.exe'), dl_contents.read()) + ctx = zipfile.ZipFile(dl_contents) + members = operator.methodcaller('namelist') + member_name = lambda s: s # noqa: E731 else: - with tarfile_open(fileobj=dl_contents) as tarfile_obj: - member_list = tarfile_obj.getmembers() - extract_list = [] - for member in member_list: - node_ver = opt.node.replace('.', '\.') - rexp_string = "%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ - % (prefix, node_ver) - if re.match(rexp_string, member.name) is None: - extract_list.append(member) - tarfile_obj.extractall(src_dir, extract_list) + ctx = tarfile_open(fileobj=dl_contents) + members = operator.methodcaller('getmembers') + member_name = operator.attrgetter('name') + + with ctx as archive: + node_ver = re.escape(opt.node) + rexp_string = r"%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ + % (prefix, node_ver) + extract_list = [ + member + for member in members(archive) + if re.match(rexp_string, member_name(member)) is None + ] + archive.extractall(src_dir, extract_list) def urlopen(url): @@ -592,20 +603,26 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): logger.info('.', extra=dict(continued=True)) prefix = get_binary_prefix() if is_WIN: - src_exe = join(src_dir, 'node.exe') - dst_exe = join(env_dir, 'Scripts', 'node.exe') - mkdir(join(env_dir, 'Scripts')) - callit(['copy', '/Y', '/L', src_exe, dst_exe], False, True) + dest = join(env_dir, 'Scripts') + os.makedirs(dest) elif is_CYGWIN: - mkdir(join(env_dir, 'bin')) + dest = join(env_dir, 'bin') + os.makedirs(dest) + # write here to avoid https://bugs.python.org/issue35650 writefile(join(env_dir, 'bin', 'node'), CYGWIN_NODE) - src_exe = join(src_dir, 'node.exe') - dst_exe = join(env_dir, 'bin', 'node.exe') - callit(['cp', '-a', src_exe, dst_exe], True, env_dir) else: - src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, node_version)) - for src_folder in glob.glob(src_folder_tpl): - copytree(src_folder, env_dir, True) + dest = env_dir + + src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, 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)) @@ -934,7 +951,7 @@ def handle_starttag(self, tag, attrs): self.hrefs.append(dict(attrs).get('href', '')) -VERSION_RE = re.compile('\d+\.\d+\.\d+') +VERSION_RE = re.compile(r'\d+\.\d+\.\d+') def _py2_cmp(a, b): @@ -1110,7 +1127,7 @@ def main(): exec __SHIM_NODE__ "$@" """ -ACTIVATE_BAT = """\ +ACTIVATE_BAT = r"""\ @echo off set "NODE_VIRTUAL_ENV=__NODE_VIRTUAL_ENV__" if not defined PROMPT ( @@ -1156,7 +1173,7 @@ def main(): :END """ -ACTIVATE_PS1 = """\ +ACTIVATE_PS1 = r"""\ function global:deactivate ([switch]$NonDestructive) { # Revert to original values if (Test-Path function:_OLD_VIRTUAL_PROMPT) { @@ -1203,7 +1220,7 @@ def main(): $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* # you cannot run it directly diff --git a/tox.ini b/tox.ini index 31e0f24..5263a28 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ commands = # Needed because we subprocess to ourselves coverage combine coverage report --show-missing --fail-under 55 # TODO: 100 - flake8 --ignore=W605,W504,E241 nodeenv.py tests setup.py + flake8 nodeenv.py tests setup.py [testenv:venv] envdir = venv-nodeenv From abb49f54166d99bfa30b7f0cd8aad7350ccd79c8 Mon Sep 17 00:00:00 2001 From: rachmadaniHaryono Date: Mon, 21 Jan 2019 07:11:50 +0800 Subject: [PATCH 098/239] fix: url on changes file --- CHANGES | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGES b/CHANGES index ed50f27..2aa46b5 100644 --- a/CHANGES +++ b/CHANGES @@ -3,47 +3,47 @@ Nodeenv changelog Version 1.3.1 ------------- -- Windows related fix `#207 https://github.com/ekalinin/nodeenv/pull/207` -- Fixed url for arm64 `#210 https://github.com/ekalinin/nodeenv/pull/210`_ -- Fixed fish support `#212 https://github.com/ekalinin/nodeenv/pull/212`_ +- Windows related fix `#207 `_ +- Fixed url for arm64 `#210 `_ +- Fixed fish support `#212 `_ Version 1.3.0 ------------- -- Fixed symlink creation `#189 https://github.com/ekalinin/nodeenv/issues/189`_ -- Python3.6 support `#200 https://github.com/ekalinin/nodeenv/pull/200`_ -- Added `activate` for fish `#201 https://github.com/ekalinin/nodeenv/pull/201`_ -- Fixed cp866 `#202 https://github.com/ekalinin/nodeenv/pull/202`_ -- Added Conda support `#203 https://github.com/ekalinin/nodeenv/pull/203`_ +- 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 https://github.com/ekalinin/nodeenv/pull/194`_ `#195 - https://github.com/ekalinin/nodeenv/pull/195`_ +- Support for Cygwin `#194 `_ `#195 + `_ - tox.ini as default configuration file `#197 - https://github.com/ekalinin/nodeenv/pull/197`_ + `_ Version 1.1.4 ------------- -- Fixed directory copy `#188 https://github.com/ekalinin/nodeenv/issues/188`_ +- Fixed directory copy `#188 `_ Version 1.1.3 ------------- -- Fixed spaces in paths `#187 https://github.com/ekalinin/nodeenv/issues/187`_ +- Fixed spaces in paths `#187 `_ Version 1.1.2 ------------- -- Fixed MANIFEST.in `#184 https://github.com/ekalinin/nodeenv/issues/184`_ +- Fixed MANIFEST.in `#184 `_ Version 1.1.1 ------------- - Improve Windows support. See `#181 - https://github.com/ekalinin/nodeenv/pull/181`_ + `_ - Fix bug when downgrading using `--force`. See `#183 - https://github.com/ekalinin/nodeenv/pull/183`_ + `_ - Environment creation fails with non-ASCII chars in path. See `#49 - https://github.com/ekalinin/nodeenv/issues/49`_ + `_ Version 1.1.0 ------------- From 63af52f22041d146fe6286b735fe867316db02b4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 17 Feb 2019 11:18:22 -0800 Subject: [PATCH 099/239] Fix escape sequences fix Oops, looks like I broke this --- nodeenv.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 6283e22..4cade11 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -66,20 +66,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): @@ -1127,7 +1126,7 @@ def main(): exec __SHIM_NODE__ "$@" """ -ACTIVATE_BAT = r"""\ +ACTIVATE_BAT = r""" @echo off set "NODE_VIRTUAL_ENV=__NODE_VIRTUAL_ENV__" if not defined PROMPT ( @@ -1173,7 +1172,7 @@ def main(): :END """ -ACTIVATE_PS1 = r"""\ +ACTIVATE_PS1 = r""" function global:deactivate ([switch]$NonDestructive) { # Revert to original values if (Test-Path function:_OLD_VIRTUAL_PROMPT) { @@ -1220,7 +1219,7 @@ def main(): $env:PATH = "$env:NODE_VIRTUAL_ENV\Scripts;$env:PATH" """ -ACTIVATE_SH = r"""\ +ACTIVATE_SH = r""" # This file must be used with "source bin/activate" *from bash* # you cannot run it directly From ca4a17bd01bae3cf3a702bd1158a987095b4c375 Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 27 Feb 2019 22:27:41 -0500 Subject: [PATCH 100/239] fix npm_url in install_npm_win --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 4cade11..6f26f60 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -755,7 +755,7 @@ def install_npm_win(env_dir, src_dir, opt): """ logger.info(' * Install npm.js (%s) ... ' % opt.npm, extra=dict(continued=True)) - npm_url = 'https://github.com/npm/cli/archive/%s.zip' % opt.npm + npm_url = 'https://github.com/npm/cli/archive/v%s.zip' % opt.npm npm_contents = io.BytesIO(urlopen(npm_url).read()) bin_path = join(env_dir, 'Scripts') From ef9491c8d719627bc3123c6510846d2ef136d7cd Mon Sep 17 00:00:00 2001 From: Walter dos Santos Filho Date: Fri, 5 Apr 2019 14:07:44 -0300 Subject: [PATCH 101/239] Change URL for downloading npm in Cygwin. --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 6f26f60..e4bf509 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -785,7 +785,7 @@ def install_npm_win(env_dir, src_dir, opt): 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/npm' + npm_gh_url = 'https://raw.githubusercontent.com/npm/cli' npm_bin_url = '{}/{}/bin/npm'.format(npm_gh_url, opt.npm) writefile(join(env_dir, 'bin', 'npm'), urlopen(npm_bin_url).read()) From 1151fd3e897f0906230247b6d137385b5d109b8c Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Sun, 26 May 2019 04:16:27 -0400 Subject: [PATCH 102/239] Spit out a blank line when install_node fails The logger is configured to suppress newlines with continued=True. This extra logging call undoes that. #235 --- nodeenv.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index 6f26f60..f701d07 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -690,6 +690,14 @@ def install_node(env_dir, src_dir, opt): Download source code for node.js, unpack it and install it in virtual environment. """ + try: + install_node_wrapped(env_dir, src_dir, opt) + except: + # this restores the newline suppressed by continued=True + logger.info() + raise + +def install_node_wrapped(env_dir, src_dir, opt): env_dir = abspath(env_dir) prefix = get_binary_prefix() node_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) From 7d92752ec2ddeaebb5763ea9f8e8329a9aa6f40f Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Thu, 29 Aug 2019 08:58:24 -0700 Subject: [PATCH 103/239] Fix nodeenv in case python4 is ever a thing --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index e4bf509..c41e397 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -48,7 +48,7 @@ abspath = os.path.abspath src_domain = "nodejs.org" -is_PY3 = sys.version_info[0] == 3 +is_PY3 = sys.version_info[0] >= 3 if is_PY3: from functools import cmp_to_key From 3e198214c466c489867a4eb8d6636f6e802da74c Mon Sep 17 00:00:00 2001 From: Andreas Wirooks Date: Wed, 28 Mar 2018 14:20:08 +0200 Subject: [PATCH 104/239] Add option to set own mirror. --- nodeenv.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) mode change 100644 => 100755 nodeenv.py diff --git a/nodeenv.py b/nodeenv.py old mode 100644 new mode 100755 index c41e397..4467111 --- a/nodeenv.py +++ b/nodeenv.py @@ -46,6 +46,7 @@ join = os.path.join abspath = os.path.abspath +iojs_taken = False src_domain = "nodejs.org" is_PY3 = sys.version_info[0] >= 3 @@ -229,6 +230,11 @@ def parse_args(check=True): action='store_true', dest='io', default=False, help='Use iojs instead of nodejs.') + parser.add_option( + '--mirror', + action="store", dest='mirror', + help='Set mirror server of nodejs.org or iojs.org to download from.') + if not is_WIN: parser.add_option( '-j', '--jobs', dest='jobs', default=Config.jobs, @@ -682,7 +688,7 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): def get_binary_prefix(): - return to_utf8('node' if src_domain == 'nodejs.org' else 'iojs') + return to_utf8('node' if iojs_taken is False else 'iojs') def install_node(env_dir, src_dir, opt): @@ -1075,10 +1081,16 @@ def main(): logger.error('Installing system node.js on win32 is not supported!') exit(1) + global iojs_taken + global src_domain + if opt.io: - global src_domain + iojs_taken = True src_domain = "iojs.org" + if opt.mirror: + src_domain = opt.mirror + if not opt.node or opt.node.lower() == "latest": opt.node = get_last_stable_node_version() From e54d32cf704c0bd16e154c985a44d91f3744446e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sat, 16 Nov 2019 13:58:56 -0800 Subject: [PATCH 105/239] nodeenv is a pure python package, produce py2.py3 wheels --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2c1ff5d..5f39236 100644 --- a/setup.py +++ b/setup.py @@ -58,5 +58,6 @@ def read_file(file_name): 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' - ] + ], + options={'bdist_wheel': {'universal': True}}, ) From ef5a785fcaa98fe965632297c2aea25a0bd8bd99 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 19 Nov 2019 10:29:27 +0300 Subject: [PATCH 106/239] Makefile: deploy-pypi supports wheel --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 39f9a46..24c1b8b 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ deploy-github: git push --tags origin master deploy-pypi: - python setup.py sdist + python setup.py sdist bdist_wheel twine upload --repository pypi dist/* update-pypi: From e0914ddcd4e051243eca48403f32607f5e910ed5 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 19 Nov 2019 10:45:53 +0300 Subject: [PATCH 107/239] Better condition --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 43833cb..769bae6 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -688,7 +688,7 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): def get_binary_prefix(): - return to_utf8('node' if iojs_taken is False else 'iojs') + return to_utf8('node' if not iojs_taken else 'iojs') def install_node(env_dir, src_dir, opt): From 0909ba6d622c942f6a6c312e325f58687d3da8f2 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Dec 2019 14:54:33 -0800 Subject: [PATCH 108/239] Fix CI (flake8 errors) --- nodeenv.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 769bae6..fe06129 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -698,11 +698,12 @@ def install_node(env_dir, src_dir, opt): """ try: install_node_wrapped(env_dir, src_dir, opt) - except: + except BaseException: # this restores the newline suppressed by continued=True logger.info() raise + def install_node_wrapped(env_dir, src_dir, opt): env_dir = abspath(env_dir) prefix = get_binary_prefix() @@ -1420,7 +1421,7 @@ def main(): 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\.\-]+)*" + 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 | \ @@ -1431,7 +1432,7 @@ def main(): set NPM_LS "npm ls" set -e argv[1] end - set -l NPM_LIST (eval $NPM_LS | grep -E '^.{4}\w{1}' | \ + set -l NPM_LIST (eval $NPM_LS | grep -E '^.{4}\\w{1}' | \ grep -o -E "$re" | \ grep -v npm) end @@ -1494,7 +1495,7 @@ def main(): set -gx _OLD_NODE_FISH_PROMPT_OVERRIDE "$NODE_VIRTUAL_ENV" end -""" # noqa +""" # noqa: E501 PREDEACTIVATE_SH = """ if type -p deactivate_node > /dev/null; then deactivate_node;fi From 3cbec79d88328843e5205cf0a61ed56b8df74742 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Dec 2019 15:33:11 -0800 Subject: [PATCH 109/239] Fix call to logger.info(...) --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index fe06129..d8809e6 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -700,7 +700,7 @@ def install_node(env_dir, src_dir, opt): install_node_wrapped(env_dir, src_dir, opt) except BaseException: # this restores the newline suppressed by continued=True - logger.info() + logger.info('') raise From 51d3a86a4b05739529be60f486aaf37ca400cf93 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Dec 2019 16:41:08 -0800 Subject: [PATCH 110/239] Switch to using `/download/release/index.json` to discover versions --- nodeenv.py | 92 +------- tests/iojs.htm | 24 -- tests/iojs_dist.htm | 15 -- tests/nodeenv_test.py | 107 ++------- tests/nodejs.htm | 29 --- tests/nodejs_dist.htm | 255 --------------------- tests/nodejs_index.json | 487 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 511 insertions(+), 498 deletions(-) delete mode 100644 tests/iojs.htm delete mode 100644 tests/iojs_dist.htm delete mode 100644 tests/nodejs.htm delete mode 100644 tests/nodejs_dist.htm create mode 100644 tests/nodejs_index.json diff --git a/nodeenv.py b/nodeenv.py index fe06129..b319175 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -12,6 +12,7 @@ import contextlib import io +import json import sys import os import re @@ -30,13 +31,11 @@ try: # pragma: no cover (py2 only) from ConfigParser import SafeConfigParser as ConfigParser # noinspection PyCompatibility - from HTMLParser import HTMLParser import urllib2 iteritems = operator.methodcaller('iteritems') except ImportError: # pragma: no cover (py3 only) from configparser import ConfigParser # noinspection PyUnresolvedReferences - from html.parser import HTMLParser import urllib.request as urllib2 iteritems = operator.methodcaller('items') @@ -50,9 +49,6 @@ src_domain = "nodejs.org" is_PY3 = sys.version_info[0] >= 3 -if is_PY3: - from functools import cmp_to_key - is_WIN = platform.system() == 'Windows' is_CYGWIN = platform.system().startswith('CYGWIN') @@ -500,9 +496,9 @@ def callit(cmd, show_stdout=True, in_shell=False, def get_root_url(version): if parse_version(version) > parse_version("0.5.0"): - return 'https://%s/dist/v%s/' % (src_domain, version) + return 'https://%s/download/release/v%s/' % (src_domain, version) else: - return 'https://%s/dist/' % src_domain + return 'https://%s/download/release/' % src_domain def get_node_bin_url(version): @@ -954,59 +950,13 @@ def create_environment(env_dir, opt): shutil.rmtree(src_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(r'\d+\.\d+\.\d+') - - -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('https://%s/download/release/index.json' % src_domain) + 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(): @@ -1025,23 +975,7 @@ 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 links[-1][0] + return _get_versions_json()[0]['version'].lstrip('v') def get_env_dir(opt, args): @@ -1060,16 +994,6 @@ def get_env_dir(opt, args): 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(): """ 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 5e0c231..1296b73 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -1,7 +1,6 @@ from __future__ import absolute_import from __future__ import unicode_literals -import io import os.path import subprocess @@ -14,60 +13,6 @@ 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 @@ -83,16 +28,10 @@ def test_smoke(tmpdir): @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.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): +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 @@ -106,41 +45,27 @@ 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_get_node_versions_iojs(): +@pytest.mark.usefixtures('mock_index_json') +def test_get_node_versions(): 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.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'] - - -@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' + # 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 remaning 5 items + assert tabs_per_line == [7] * 60 + [4] def test_predeactivate_hook(tmpdir): 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..fbe8ecf --- /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-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-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} +] From 872db0cf20f2f2dd6622086033b6c47e3e95f27d Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 31 Dec 2019 17:29:33 -0800 Subject: [PATCH 111/239] Download musl-compatible nodeenv from unofficial-builds --- nodeenv.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index b319175..bc2aadd 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -26,6 +26,7 @@ import platform import zipfile import shutil +import sysconfig import glob try: # pragma: no cover (py2 only) @@ -501,6 +502,10 @@ def get_root_url(version): return 'https://%s/download/release/' % src_domain +def is_x86_64_musl(): + return sysconfig.get_config_var('HOST_GNU_TYPE') == 'x86_64-pc-linux-musl' + + def get_node_bin_url(version): archmap = { 'x86': 'x86', # Windows Vista 32 @@ -518,10 +523,11 @@ def get_node_bin_url(version): } if is_WIN or is_CYGWIN: postfix = '-win-%(arch)s.zip' % sysinfo - filename = '%s-v%s%s' % (get_binary_prefix(), version, postfix) + 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 = '%s-v%s%s' % (get_binary_prefix(), version, postfix) return get_root_url(version) + filename @@ -1023,6 +1029,9 @@ def main(): if opt.mirror: src_domain = opt.mirror + # use unofficial builds only if musl and no explicitly chosen mirror + elif is_x86_64_musl(): + src_domain = 'unofficial-builds.nodejs.org' if not opt.node or opt.node.lower() == "latest": opt.node = get_last_stable_node_version() From 028b0059f505fa1af8f1cd5b0680ea49e59a38c5 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 7 Jan 2020 21:27:55 +0300 Subject: [PATCH 112/239] 1.3.4 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index d8809e6..68ccf15 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.3' +nodeenv_version = '1.3.4' join = os.path.join abspath = os.path.abspath From 4cec85cf7d512fe51c41ba5db50bb5cff2bcb576 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Feb 2020 11:10:02 +0300 Subject: [PATCH 113/239] update AUTHORS --- AUTHORS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AUTHORS b/AUTHORS index 83b7fb2..a21201d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,6 +31,7 @@ Patches and Suggestions - Zenobius Jiricek - Yi-Feng Tzeng - Willem Jan Withagen +- Walter dos Santos Filho - Vladimír Gorej - Vincent Bernat - urbandove @@ -38,7 +39,9 @@ Patches and Suggestions - Terseus - Stan Seibert - Shubhang Mani +- sam - Rik +- rachmadaniHaryono - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski @@ -49,6 +52,7 @@ Patches and Suggestions - Laust Rud Jacobsen - Ken Struys - Kai Weber +- Josh Soref - Joby Harding - jiho - Jesse Dhillon @@ -64,4 +68,5 @@ Patches and Suggestions - cmehay - Brian Jacobel - Ben Davis +- Andreas Wirooks - Alexey Poryadin From ff8c15ead9aeb5d9ac8f003cb0966b43fc57a440 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Feb 2020 11:12:21 +0300 Subject: [PATCH 114/239] Fixed error if file already exists. Fixes #249 --- nodeenv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 68ccf15..c4e146a 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -609,10 +609,10 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): prefix = get_binary_prefix() if is_WIN: dest = join(env_dir, 'Scripts') - os.makedirs(dest) + mkdir(dest) elif is_CYGWIN: dest = join(env_dir, 'bin') - os.makedirs(dest) + mkdir(dest) # write here to avoid https://bugs.python.org/issue35650 writefile(join(env_dir, 'bin', 'node'), CYGWIN_NODE) else: From bc3f6da09d29e865e7ef2108ace33df434393fd4 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Feb 2020 11:12:51 +0300 Subject: [PATCH 115/239] 1.3.5 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index c4e146a..4f631ab 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -42,7 +42,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.4' +nodeenv_version = '1.3.5' join = os.path.join abspath = os.path.abspath From 38d61e3463f681320818eea86014c9680a209acf Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Feb 2020 15:38:56 +0800 Subject: [PATCH 116/239] accept URL as well as domain name for --mirror argument do not assume that the mirror mirrors the full directory structure of nodejs.org, actually, some mirros just have the part of `https://nodejs.org/download/release/` mirrored. for instance, https://npm.taobao.org/mirrors/node, and do not assume that the mirror always put the nodejs mirror in its `download/` directory. in this change, a URL is accepted as well as a domain name. if a mirror does not have "://" in it is specified, the default "https:///download/releases" URL is used. this change addresses the comment of https://github.com/ekalinin/nodeenv/pull/208#issuecomment-380434680 also, ignore E127 for multi-line `with` statement, see discussion at https://github.com/PyCQA/pycodestyle/issues/316, which is related to E126, but it also applies this case. Signed-off-by: Kefu Chai --- README.rst | 4 ++++ nodeenv.py | 20 ++++++++++++++------ tests/nodeenv_test.py | 28 ++++++++++++++++++++++++++++ tox.ini | 2 +- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 7743d6d..b9847ac 100644 --- a/README.rst +++ b/README.rst @@ -136,6 +136,10 @@ Install node.js from the source:: $ nodeenv --node=0.10.25 --source env-0.10.25 +Install node.js from a mirror:: + + $ 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:: diff --git a/nodeenv.py b/nodeenv.py index ebf93b8..dce60e6 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -47,7 +47,7 @@ join = os.path.join abspath = os.path.abspath iojs_taken = False -src_domain = "nodejs.org" +src_base_url = None is_PY3 = sys.version_info[0] >= 3 is_WIN = platform.system() == 'Windows' @@ -497,9 +497,9 @@ def callit(cmd, show_stdout=True, in_shell=False, def get_root_url(version): if parse_version(version) > parse_version("0.5.0"): - return 'https://%s/download/release/v%s/' % (src_domain, version) + return '%s/v%s/' % (src_base_url, version) else: - return 'https://%s/download/release/' % src_domain + return src_base_url def is_x86_64_musl(): @@ -957,7 +957,7 @@ def create_environment(env_dir, opt): def _get_versions_json(): - response = urlopen('https://%s/download/release/index.json' % src_domain) + response = urlopen('%s/index.json' % src_base_url) return json.loads(response.read().decode('UTF-8')) @@ -1021,17 +1021,25 @@ def main(): exit(1) global iojs_taken - global src_domain + global src_base_url + src_domain = None if opt.io: iojs_taken = True src_domain = "iojs.org" if opt.mirror: - src_domain = opt.mirror + if '://' in opt.mirror: + src_base_url = opt.mirror + else: + src_domain = opt.mirror # use unofficial builds only if musl and no explicitly chosen mirror elif is_x86_64_musl(): 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 opt.node or opt.node.lower() == "latest": opt.node = get_last_stable_node_version() diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 1296b73..ac0a613 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -3,6 +3,7 @@ import os.path import subprocess +import sys import mock import pytest @@ -79,3 +80,30 @@ def test_predeactivate_hook(tmpdir): 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')] + 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() diff --git a/tox.ini b/tox.ini index 5263a28..c713fbc 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ commands = # Needed because we subprocess to ourselves coverage combine coverage report --show-missing --fail-under 55 # TODO: 100 - flake8 nodeenv.py tests setup.py + flake8 --extend-ignore=E127 nodeenv.py tests setup.py [testenv:venv] envdir = venv-nodeenv From 7d3bf01c940b1caff560692b486469cfd5321a21 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 24 Feb 2020 16:10:16 +0800 Subject: [PATCH 117/239] drop iojs support node.js and io.js already merged back together since v4.0. and iojs.org redirects to nodejs.org. so, it does not make sense to offer this option for new developers using node.js >= 4.0 Signed-off-by: Kefu Chai --- Makefile | 10 ---------- README.rst | 12 ------------ nodeenv.py | 37 ++++++++++--------------------------- 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 24c1b8b..5ff5137 100644 --- a/Makefile +++ b/Makefile @@ -87,16 +87,6 @@ test5: clean python setup.py install && \ nodeenv -p --prebuilt -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 - test7: clean @echo " =" @echo " = test7: freeze for global installation" diff --git a/README.rst b/README.rst index b9847ac..c21bc09 100644 --- a/README.rst +++ b/README.rst @@ -230,18 +230,6 @@ use `shim` script:: $ ./env-4.3/bin/shim --version v0.4.3 - -If you want to install iojs instead of nodejs then use ``--iojs``:: - - $ 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 - - Configuration ------------- You can use the INI-style file ``~/.nodeenvrc`` to set default values for many options, diff --git a/nodeenv.py b/nodeenv.py index dce60e6..e7c646d 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -46,7 +46,6 @@ join = os.path.join abspath = os.path.abspath -iojs_taken = False src_base_url = None is_PY3 = sys.version_info[0] >= 3 @@ -222,15 +221,10 @@ def parse_args(check=True): 'The default is last stable version (`latest`). ' '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( '--mirror', action="store", dest='mirror', - help='Set mirror server of nodejs.org or iojs.org to download from.') + help='Set mirror server of nodejs.org to download from.') if not is_WIN: parser.add_option( @@ -527,12 +521,12 @@ def get_node_bin_url(version): 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 @@ -546,7 +540,7 @@ def tarfile_open(*args, **kwargs): tf.close() -def download_node_src(node_url, src_dir, opt, prefix): +def download_node_src(node_url, src_dir, opt): """ Download source code """ @@ -565,8 +559,8 @@ def download_node_src(node_url, src_dir, opt, prefix): with ctx as archive: node_ver = re.escape(opt.node) - rexp_string = r"%s-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ - % (prefix, node_ver) + rexp_string = r"node-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ + % node_ver extract_list = [ member for member in members(archive) @@ -608,7 +602,6 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): Copy prebuilt binaries into environment """ logger.info('.', extra=dict(continued=True)) - prefix = get_binary_prefix() if is_WIN: dest = join(env_dir, 'Scripts') mkdir(dest) @@ -620,7 +613,7 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): else: dest = env_dir - src_folder_tpl = src_dir + to_utf8('/%s-v%s*' % (prefix, node_version)) + src_folder_tpl = src_dir + to_utf8('/node-v%s*' % node_version) src_folder, = glob.glob(src_folder_tpl) copytree(src_folder, dest, True) @@ -689,10 +682,6 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): callit([make_cmd + ' install'], opt.verbose, True, node_src_dir, env) -def get_binary_prefix(): - return to_utf8('node' if not iojs_taken else 'iojs') - - def install_node(env_dir, src_dir, opt): """ Download source code for node.js, unpack it @@ -708,11 +697,10 @@ def install_node(env_dir, src_dir, opt): def install_node_wrapped(env_dir, src_dir, opt): env_dir = abspath(env_dir) - prefix = get_binary_prefix() - node_src_dir = join(src_dir, to_utf8('%s-v%s' % (prefix, opt.node))) + node_src_dir = join(src_dir, to_utf8('node-v%s' % opt.node)) src_type = "prebuilt" if opt.prebuilt else "source" - logger.info(' * Install %s %s (%s) ' % (src_type, prefix, opt.node), + logger.info(' * Install %s node (%s) ' % (src_type, opt.node), extra=dict(continued=True)) if opt.prebuilt: @@ -722,7 +710,7 @@ def install_node_wrapped(env_dir, src_dir, opt): # get src if not downloaded yet if not os.path.exists(node_src_dir): - download_node_src(node_url, src_dir, opt, prefix) + download_node_src(node_url, src_dir, opt) logger.info('.', extra=dict(continued=True)) @@ -1020,14 +1008,9 @@ def main(): logger.error('Installing system node.js on win32 is not supported!') exit(1) - global iojs_taken global src_base_url src_domain = None - if opt.io: - iojs_taken = True - src_domain = "iojs.org" - if opt.mirror: if '://' in opt.mirror: src_base_url = opt.mirror From f0c547ad80a8588f41e1a670e3f81bd6784a6180 Mon Sep 17 00:00:00 2001 From: zjeuhpiung liu Date: Fri, 24 Apr 2020 20:39:15 +0800 Subject: [PATCH 118/239] Fixed erase NODE_VIRTUAL_ENV while deactivate_node in fish --- nodeenv.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index e7c646d..4886c09 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -1337,6 +1337,8 @@ def main(): 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 From f12a4ef353040f454f8ef3152ff912a51555a835 Mon Sep 17 00:00:00 2001 From: Jon Winn Date: Fri, 24 Apr 2020 11:19:30 -0600 Subject: [PATCH 119/239] Jon Winn - adding option "--ignore_ssl_certs" to set ssl.SSLContext.verify_mode=ssl.CERT_NONE. Unsafe but allows users behind corporate firewalls to ignore cert errors due to MITM/firewall issues. --- nodeenv.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 4886c09..4a002e4 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -16,6 +16,7 @@ import sys import os import re +import ssl import stat import logging import operator @@ -52,6 +53,7 @@ is_WIN = platform.system() == 'Windows' is_CYGWIN = platform.system().startswith('CYGWIN') +ignore_ssl_certs = False # --------------------------------------------------------- # Utils @@ -93,6 +95,7 @@ class Config(object): profile = False make = 'make' prebuilt = True + ignore_ssl_certs = False @classmethod def _load(cls, configfiles, verbose=False): @@ -337,7 +340,13 @@ def parse_args(check=True): action='store_true', default=Config.prebuilt, help='Install node.js from prebuilt package (default)') + parser.add_option( + '--ignore_ssl_certs', dest='ignore_ssl_certs', + action='store_true', default=Config.ignore_ssl_certs, + help='Ignore certificates for package downloads - UNSAFE - (See ssl.SSLContext.verify_mode).') + options, args = parser.parse_args() + if options.config_file is None: options.config_file = ["./tox.ini", "./setup.cfg", "~/.nodeenvrc"] elif not options.config_file: @@ -573,7 +582,12 @@ 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) - return urllib2.urlopen(req) + if ignore_ssl_certs: + context = ssl.SSLContext() + context.verify_mode = ssl.CERT_NONE + return urllib2.urlopen(req, context=context) + else: + return urllib2.urlopen(req) # --------------------------------------------------------- # Virtual environment functions @@ -1009,6 +1023,9 @@ def main(): exit(1) global src_base_url + global ignore_ssl_certs + + ignore_ssl_certs = opt.ignore_ssl_certs src_domain = None if opt.mirror: From 203a221abd1797b60b4b9f582adf0e03604a16b1 Mon Sep 17 00:00:00 2001 From: Jon Winn Date: Fri, 24 Apr 2020 11:32:21 -0600 Subject: [PATCH 120/239] Shortened help text for '--ignore_ssl_certs' option. Removed else: from urlopen to be more pythonic. --- nodeenv.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 4a002e4..db83aff 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -343,7 +343,7 @@ def parse_args(check=True): parser.add_option( '--ignore_ssl_certs', dest='ignore_ssl_certs', action='store_true', default=Config.ignore_ssl_certs, - help='Ignore certificates for package downloads - UNSAFE - (See ssl.SSLContext.verify_mode).') + help='Ignore certificates for package downloads. - UNSAFE -') options, args = parser.parse_args() @@ -586,8 +586,7 @@ def urlopen(url): context = ssl.SSLContext() context.verify_mode = ssl.CERT_NONE return urllib2.urlopen(req, context=context) - else: - return urllib2.urlopen(req) + return urllib2.urlopen(req) # --------------------------------------------------------- # Virtual environment functions From e73c7fed2185bc1fdcf587b029123a2ae91289a3 Mon Sep 17 00:00:00 2001 From: Thomas Bechtold Date: Tue, 12 May 2020 05:45:47 +0200 Subject: [PATCH 121/239] Workaround IncompleteRead when downloading src From time to time it happens that downloading the source throws an exception like: http.client.IncompleteRead: IncompleteRead(12959497 bytes read, 5654772 more expected) This might be a problem with the server[1] [1] https://stackoverflow.com/questions/14442222/how-to-handle-incompleteread-in-python --- nodeenv.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 4886c09..2d86b5a 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -34,11 +34,15 @@ # noinspection PyCompatibility import urllib2 iteritems = operator.methodcaller('iteritems') + import httplib + IncompleteRead = httplib.IncompleteRead except ImportError: # pragma: no cover (py3 only) from configparser import ConfigParser # noinspection PyUnresolvedReferences import urllib.request as urllib2 iteritems = operator.methodcaller('items') + import http + IncompleteRead = http.client.IncompleteRead from pkg_resources import parse_version @@ -545,7 +549,12 @@ def download_node_src(node_url, src_dir, opt): Download source code """ logger.info('.', extra=dict(continued=True)) - dl_contents = io.BytesIO(urlopen(node_url).read()) + try: + dl_contents = io.BytesIO(urlopen(node_url).read()) + except IncompleteRead as e: + logger.warning('Incomplete read while reading' + 'from {}'.format(node_url)) + dl_contents = e.partial logger.info('.', extra=dict(continued=True)) if is_WIN or is_CYGWIN: From 584a43e711404e8228accdc731931e02e0f0ef08 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 2 Jun 2020 15:07:34 +0300 Subject: [PATCH 122/239] 1.4.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2d86b5a..e089599 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -46,7 +46,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.3.5' +nodeenv_version = '1.4.0' join = os.path.join abspath = os.path.abspath From c7edf713e9f9c9ea860562bdd2598b36abbbf297 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 2 Jun 2020 16:04:02 +0300 Subject: [PATCH 123/239] update AUTHORS --- AUTHORS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index a21201d..f4fea4c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,8 +4,8 @@ Patches and Suggestions ``````````````````````` - jhermann -- anatoly techtonik - Anthony Sottile +- anatoly techtonik - ivan hilkov - Vincent Bernat - Kyle P Davis @@ -22,12 +22,14 @@ Patches and Suggestions - Lispython - Leonardo Fedalto - Kyle P Davis +- Kefu Chai - Dennis Flanigan - Chris Beaven - Bruno Oliveira - Andrzej Pragacz - Alex Couper - 0Xellos +- zjeuhpiung liu - Zenobius Jiricek - Yi-Feng Tzeng - Willem Jan Withagen @@ -36,6 +38,7 @@ Patches and Suggestions - Vincent Bernat - urbandove - Uman Shahzad +- Thomas Bechtold - Terseus - Stan Seibert - Shubhang Mani From 5e757ffbee26e6b3871d230e659a331a76d798b5 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 1 Jun 2020 15:30:04 -0700 Subject: [PATCH 124/239] Improve quoting of varibles in the node shim for -n system - this isn't quite perfect, for example a node environment containaing a single quote character will still produce problems. but this is an improvement - a more thorough approach would be to use `shlex.quote` -- however I'm not 100% certain how that would interact with other shells and particularly windows --- nodeenv.py | 8 ++++---- tests/nodeenv_test.py | 19 ++++++++++++++++++- tox.ini | 4 ++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 2d86b5a..d9f3386 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -1074,10 +1074,10 @@ def main(): } 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__ "$@" +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__' "$@" """ ACTIVATE_BAT = r""" diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index ac0a613..526cdb8 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import os.path +import pipes import subprocess import sys @@ -23,8 +24,24 @@ def test_smoke(tmpdir): '-m', 'nodeenv', '--prebuilt', nenv_path, ]) assert os.path.exists(nenv_path) + activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ - 'sh', '-c', '. {0}/bin/activate && nodejs --version'.format(nenv_path), + 'sh', '-c', '. {} && nodejs --version'.format(activate), + ]) + + +@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 = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) + subprocess.check_call([ + 'sh', '-c', '. {} && nodejs --version'.format(activate), ]) diff --git a/tox.ini b/tox.ini index c713fbc..14d48da 100644 --- a/tox.ini +++ b/tox.ini @@ -25,3 +25,7 @@ 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 From 73bb52dcc077cfb0c50f59e5ba14523033d45c1f Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Thu, 6 Aug 2020 15:24:45 +0300 Subject: [PATCH 125/239] Support MSYS2 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 0ed0d67..6ddb021 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -55,7 +55,7 @@ is_PY3 = sys.version_info[0] >= 3 is_WIN = platform.system() == 'Windows' -is_CYGWIN = platform.system().startswith('CYGWIN') +is_CYGWIN = platform.system().startswith(('CYGWIN', 'MSYS')) ignore_ssl_certs = False From 7845e0c27d491777c8c058fb444bcde903c4041d Mon Sep 17 00:00:00 2001 From: Cerem Cem ASLAN Date: Thu, 6 Aug 2020 16:42:24 +0300 Subject: [PATCH 126/239] added --prompt switch usage to the documentation --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index c21bc09..3b6819a 100644 --- a/README.rst +++ b/README.rst @@ -213,6 +213,10 @@ environment:: $ npm install -g coffee-script $ which 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:: From b61d44f70a9acf56632e35fefd1a6548d7d01d5c Mon Sep 17 00:00:00 2001 From: Duncan Bellamy <32509178+a16bitsysop@users.noreply.github.com> Date: Mon, 10 Aug 2020 21:35:45 +0100 Subject: [PATCH 127/239] Update nodeenv.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing arch’s to allow tests to run in CI, part of #267 --- nodeenv.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index 6ddb021..dcdeb77 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -522,7 +522,10 @@ def get_node_bin_url(version): 'AMD64': 'x64', # Windows Server 2012 R2 (x64) 'armv6l': 'armv6l', # arm 'armv7l': 'armv7l', + 'armv8l': 'armv7l', 'aarch64': 'arm64', + 'ppc64le': 'ppc64le', # Power PC + 's390x': 's390x', # IBM S390x } sysinfo = { 'system': platform.system().lower(), From b4901be378986ba97d9673815c248448790ae588 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 12 Aug 2020 01:06:19 +0300 Subject: [PATCH 128/239] Fixed linter --- nodeenv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index dcdeb77..8a0116c 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -524,8 +524,8 @@ def get_node_bin_url(version): 'armv7l': 'armv7l', 'armv8l': 'armv7l', 'aarch64': 'arm64', - 'ppc64le': 'ppc64le', # Power PC - 's390x': 's390x', # IBM S390x + 'ppc64le': 'ppc64le', # Power PC + 's390x': 's390x', # IBM S390x } sysinfo = { 'system': platform.system().lower(), From ccab3b52ed3b2004b539d23a1bbbaef3d1f09a2c Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sun, 23 Aug 2020 21:12:18 +0300 Subject: [PATCH 129/239] Makefile: deploy-pypi, remove old builds before packaging --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 5ff5137..17d1b23 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ deploy-github: git push --tags origin master deploy-pypi: + rm -rf dist python setup.py sdist bdist_wheel twine upload --repository pypi dist/* From b4eb149fc717f470db8499b26b45813509319844 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sun, 23 Aug 2020 21:14:52 +0300 Subject: [PATCH 130/239] AUTHORS: update --- AUTHORS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index f4fea4c..76ef9ce 100644 --- a/AUTHORS +++ b/AUTHORS @@ -23,8 +23,10 @@ Patches and Suggestions - Leonardo Fedalto - Kyle P Davis - Kefu Chai +- Jon Winn - Dennis Flanigan - Chris Beaven +- Cerem Cem ASLAN - Bruno Oliveira - Andrzej Pragacz - Alex Couper @@ -62,6 +64,7 @@ Patches and Suggestions - Jeremy Banks - Geoffrey Huntley - Fabricio C Zuardi +- Duncan Bellamy - dkgitdev - dhilipsiva - Dennis Flanigan From 95c500d473b5108a83a34289714493230d5fc906 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sun, 23 Aug 2020 21:26:37 +0300 Subject: [PATCH 131/239] 1.5.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 8a0116c..c1e7ece 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -47,7 +47,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.4.0' +nodeenv_version = '1.5.0' join = os.path.join abspath = os.path.abspath From 766f9e3eab58ff7ba02c33cadf4420a708fc3cee Mon Sep 17 00:00:00 2001 From: Duncan Bellamy Date: Sat, 29 Aug 2020 08:30:28 +0100 Subject: [PATCH 132/239] test for nodejs or node in tests --- tests/nodeenv_test.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 526cdb8..ef59891 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -15,6 +15,25 @@ HERE = os.path.abspath(os.path.dirname(__file__)) +if subprocess.run(["which", "nodejs"],capture_output=True).returncode == 0: + is_nodejs = True +else: + is_nodejs = False + + +def call_nodejs(ev_path): + assert os.path.exists(ev_path) + activate = pipes.quote(os.path.join(ev_path, 'bin', 'activate')) + if is_nodejs: + subprocess.check_call([ + 'sh', '-c', '. {} && nodejs --version'.format(activate), + ]) + else: + subprocess.check_call([ + 'sh', '-c', '. {} && node --version'.format(activate), + ]) + + @pytest.mark.integration def test_smoke(tmpdir): nenv_path = tmpdir.join('nenv').strpath @@ -23,11 +42,7 @@ def test_smoke(tmpdir): 'coverage', 'run', '-p', '-m', 'nodeenv', '--prebuilt', nenv_path, ]) - assert os.path.exists(nenv_path) - activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) - subprocess.check_call([ - 'sh', '-c', '. {} && nodejs --version'.format(activate), - ]) + call_nodejs(nenv_path) @pytest.mark.integration @@ -38,11 +53,7 @@ def test_smoke_n_system_special_chars(tmpdir): 'coverage', 'run', '-p', '-m', 'nodeenv', '-n', 'system', nenv_path, )) - assert os.path.exists(nenv_path) - activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) - subprocess.check_call([ - 'sh', '-c', '. {} && nodejs --version'.format(activate), - ]) + call_nodejs(nenv_path) @pytest.yield_fixture From f4a57d0bcc69c187e15d9f88e1f515aa09ff123c Mon Sep 17 00:00:00 2001 From: Duncan Bellamy Date: Sat, 29 Aug 2020 10:07:46 +0100 Subject: [PATCH 133/239] remove main node.js mirror in tests if musl last fix for #267 fixes #267 --- tests/nodeenv_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index ef59891..ecf182c 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -5,6 +5,7 @@ import pipes import subprocess import sys +import sysconfig import mock import pytest @@ -117,6 +118,11 @@ def test_mirror_option(): '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() with open(os.path.join(HERE, 'nodejs_index.json'), 'rb') as f: def rewind(_): f.seek(0) From 07e2123c985065e243223f763a542c23839758f3 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 6 Oct 2020 15:31:17 +0800 Subject: [PATCH 134/239] tests: support python releases before 3.7 the "capture_output" parameter of subprocess.run() was introduced in python3.7. and subprocess.run() does not exist in python2. so should not rely on them unless we drop the support of python2 and python3.6 Signed-off-by: Kefu Chai --- tests/nodeenv_test.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index ecf182c..f49cf1d 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -3,6 +3,7 @@ import os.path import pipes +import shutil import subprocess import sys import sysconfig @@ -15,11 +16,15 @@ HERE = os.path.abspath(os.path.dirname(__file__)) - -if subprocess.run(["which", "nodejs"],capture_output=True).returncode == 0: - is_nodejs = True -else: - is_nodejs = False +try: + is_nodejs = shutil.which("nodejs") is not None +except AttributeError: + try: + subprocess.check_call(["which", "nodejs"], stdout=subprocess.PIPE) + except subprocess.CalledProcessError: + is_nodejs = False + else: + is_nodejs = True def call_nodejs(ev_path): From 9ac075d10405f944074b66d08e87407e077f1e73 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 6 Oct 2020 15:42:05 +0800 Subject: [PATCH 135/239] drop python3.4 and python3.5 and add python3.7 as they are not widely used anymore in modern releases of popular distros. Signed-off-by: Kefu Chai --- .travis.yml | 3 +-- README.rst | 2 +- tox.ini | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b0202e1..ef12b58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ language: python python: - 2.7 - - 3.4 - - 3.5 - 3.6 + - 3.7 - pypy install: pip install coveralls tox-travis script: tox diff --git a/README.rst b/README.rst index 3b6819a..43c69a2 100644 --- a/README.rst +++ b/README.rst @@ -75,7 +75,7 @@ Dependency For nodeenv ^^^^^^^^^^^ -* python (2.6+, 3.3+, or pypy) +* python (2.6+, 3.5+, or pypy) * make * tail diff --git a/tox.ini b/tox.ini index 14d48da..80b9ab4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the travis env list -envlist = py27,py34,py35,py36,pypy +envlist = py27,py36,py37,pypy [testenv] install_command = pip install {opts} {packages} From 94c1608833c2d6ac4bb1d0ec735e6e10406a8b70 Mon Sep 17 00:00:00 2001 From: Eashwar Ranganathan Date: Sun, 25 Oct 2020 19:14:35 -0700 Subject: [PATCH 136/239] Fix nodeenv prompt when using Fish --- nodeenv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index c1e7ece..5a48abf 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -1436,8 +1436,8 @@ def main(): # Prompt override provided? # If not, just prepend the environment name. - if test -n "" - printf '%s%s' "" (set_color normal) + 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 From f5e290c8c37ab02feb938ed593d62b636101b2aa Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 3 Nov 2020 09:23:50 -0800 Subject: [PATCH 137/239] Revert "Merge pull request #270 from a16bitsysop/tests" This reverts commit 797c354d42e90927ecb38a0919afb79955574a42, reversing changes made to 95c500d473b5108a83a34289714493230d5fc906. --- tests/nodeenv_test.py | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index ecf182c..580a4f1 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -16,25 +16,6 @@ HERE = os.path.abspath(os.path.dirname(__file__)) -if subprocess.run(["which", "nodejs"],capture_output=True).returncode == 0: - is_nodejs = True -else: - is_nodejs = False - - -def call_nodejs(ev_path): - assert os.path.exists(ev_path) - activate = pipes.quote(os.path.join(ev_path, 'bin', 'activate')) - if is_nodejs: - subprocess.check_call([ - 'sh', '-c', '. {} && nodejs --version'.format(activate), - ]) - else: - subprocess.check_call([ - 'sh', '-c', '. {} && node --version'.format(activate), - ]) - - @pytest.mark.integration def test_smoke(tmpdir): nenv_path = tmpdir.join('nenv').strpath @@ -43,7 +24,11 @@ def test_smoke(tmpdir): 'coverage', 'run', '-p', '-m', 'nodeenv', '--prebuilt', nenv_path, ]) - call_nodejs(nenv_path) + assert os.path.exists(nenv_path) + activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) + subprocess.check_call([ + 'sh', '-c', '. {} && nodejs --version'.format(activate), + ]) @pytest.mark.integration @@ -54,7 +39,11 @@ def test_smoke_n_system_special_chars(tmpdir): 'coverage', 'run', '-p', '-m', 'nodeenv', '-n', 'system', nenv_path, )) - call_nodejs(nenv_path) + assert os.path.exists(nenv_path) + activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) + subprocess.check_call([ + 'sh', '-c', '. {} && nodejs --version'.format(activate), + ]) @pytest.yield_fixture From c53427dc5c4278ecd90d44ccfbfb2ad1a17f8bf4 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Tue, 3 Nov 2020 09:25:03 -0800 Subject: [PATCH 138/239] use node instead of nodejs --- tests/nodeenv_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 580a4f1..bb1ec7f 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -27,7 +27,7 @@ def test_smoke(tmpdir): assert os.path.exists(nenv_path) activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ - 'sh', '-c', '. {} && nodejs --version'.format(activate), + 'sh', '-c', '. {} && node --version'.format(activate), ]) @@ -42,7 +42,7 @@ def test_smoke_n_system_special_chars(tmpdir): assert os.path.exists(nenv_path) activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ - 'sh', '-c', '. {} && nodejs --version'.format(activate), + 'sh', '-c', '. {} && node --version'.format(activate), ]) From d5af247c97e7b3a5b8d4a8006c31dcb95c897903 Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Wed, 30 Dec 2020 16:26:17 +1100 Subject: [PATCH 139/239] docs: fix simple typo, remaning -> remaining There is a small typo in tests/nodeenv_test.py. Should read `remaining` rather than `remaning`. --- tests/nodeenv_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index bb1ec7f..d3a92c4 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -83,7 +83,7 @@ def test_print_node_versions(cap_logging_info): 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 5 items + # The last line contains the remaining 5 items assert tabs_per_line == [7] * 60 + [4] From bba950a8eddb0fc3f3ce06875544e309f3f1b2f7 Mon Sep 17 00:00:00 2001 From: Eashwar Ranganathan Date: Wed, 30 Dec 2020 03:49:11 -0800 Subject: [PATCH 140/239] Resolve venv dir for Fish --- nodeenv.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 5a48abf..3686bc1 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -1401,8 +1401,17 @@ def main(): # unset irrelevant variables deactivate_node nondestructive -# NODE_VIRTUAL_ENV is the parent of the directory where this script is -set -gx NODE_VIRTUAL_ENV __NODE_VIRTUAL_ENV__ +# 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 From d7bc684685c411fb5ae84d8dd3199a6cc81f6ee4 Mon Sep 17 00:00:00 2001 From: Eashwar Ranganathan Date: Wed, 10 Feb 2021 22:10:43 -0800 Subject: [PATCH 141/239] Add support for installing latest LTS release --- nodeenv.py | 12 +++++++++++- tests/nodeenv_test.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 3686bc1..0610db1 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -226,6 +226,7 @@ def parse_args(check=True): '--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( @@ -997,6 +998,13 @@ def get_last_stable_node_version(): return _get_versions_json()[0]['version'].lstrip('v') +def get_last_lts_node_version(): + """ + Return the last node.js version marked as LTS + """ + return next((v['version'].lstrip('v') for v in _get_versions_json() if v['lts']), None) + + def get_env_dir(opt, args): if opt.python_virtualenv: if hasattr(sys, 'real_prefix'): @@ -1052,8 +1060,10 @@ def main(): if src_base_url is None: src_base_url = 'https://%s/download/release' % src_domain - if not opt.node or opt.node.lower() == "latest": + if not opt.node or opt.node.lower() == 'latest': opt.node = get_last_stable_node_version() + elif opt.node.lower() == 'lts': + opt.node = get_last_lts_node_version() if opt.list: print_node_versions() diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index d3a92c4..e1b6517 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -130,3 +130,13 @@ def rewind(_): nodeenv.main() mock_urlopen.assert_called_with(url) mock_logger.assert_called() + + +@pytest.mark.usefixtures('mock_index_json') +def test_get_latest_node_version(): + assert nodeenv.get_last_stable_node_version() == '13.5.0' + + +@pytest.mark.usefixtures('mock_index_json') +def test_get_lts_node_version(): + assert nodeenv.get_last_lts_node_version() == '12.14.0' From 04ecd3009032e450c1f16f1616d8df5be3d28aab Mon Sep 17 00:00:00 2001 From: Max R Date: Wed, 17 Mar 2021 19:32:32 -0400 Subject: [PATCH 142/239] Create broad mapping for M1 --- nodeenv.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index 3686bc1..fc69d14 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -524,6 +524,10 @@ def get_node_bin_url(version): 'armv7l': 'armv7l', 'armv8l': 'armv7l', 'aarch64': 'arm64', + 'arm64': 'arm64', + 'arm64/v8': 'arm64', + 'armv8': 'arm64', + 'armv8.4': 'arm64', 'ppc64le': 'ppc64le', # Power PC 's390x': 's390x', # IBM S390x } From 3aa5ac26776aa081229c83ecf931b5ed833e31d1 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Apr 2021 11:10:31 +0300 Subject: [PATCH 143/239] 1.6.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index bc8aa20..1d716d2 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -47,7 +47,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.5.0' +nodeenv_version = '1.6.0' join = os.path.join abspath = os.path.abspath From 13f4aef3441a61e2c2ea692db2dde615c131ad7e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Apr 2021 11:13:40 +0300 Subject: [PATCH 144/239] AUTHORS --- AUTHORS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AUTHORS b/AUTHORS index 76ef9ce..4a975de 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,6 +11,7 @@ Patches and Suggestions - Kyle P Davis - Elias Kunnas - Pierre Le Marre +- Eashwar Ranganathan - Doug Turnbull - Anton Parkhomenko - Vyacheslav Levit @@ -24,6 +25,7 @@ Patches and Suggestions - Kyle P Davis - Kefu Chai - Jon Winn +- Duncan Bellamy - Dennis Flanigan - Chris Beaven - Cerem Cem ASLAN @@ -40,6 +42,7 @@ Patches and Suggestions - Vincent Bernat - urbandove - Uman Shahzad +- Tim Gates - Thomas Bechtold - Terseus - Stan Seibert @@ -51,6 +54,7 @@ Patches and Suggestions - Mrinal Wadhwa - Michal Kolodziejski - michael +- Max R - Max Liebkies - Marc-Antoine Parent - Marc Abramowitz From feba8a080bee4e2d35739b8c2fbf5042c87ab1d3 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Apr 2021 11:21:22 +0300 Subject: [PATCH 145/239] removed unused lib --- tests/nodeenv_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index a8c7f24..e1b6517 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -3,7 +3,6 @@ import os.path import pipes -import shutil import subprocess import sys import sysconfig From 912dcdad7053a2987edf0cb393c2a68b11abf305 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Apr 2021 11:30:35 +0300 Subject: [PATCH 146/239] fix linter --- nodeenv.py | 3 ++- tests/nodeenv_test.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 1d716d2..4465b04 100755 --- a/nodeenv.py +++ b/nodeenv.py @@ -1006,7 +1006,8 @@ def get_last_lts_node_version(): """ Return the last node.js version marked as LTS """ - return next((v['version'].lstrip('v') for v in _get_versions_json() if v['lts']), None) + return next((v['version'].lstrip('v') + for v in _get_versions_json() if v['lts']), None) def get_env_dir(opt, args): diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index e1b6517..752b6d4 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -123,9 +123,9 @@ def rewind(_): 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: + 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) From 21d6a78312f618cb993d02535695f9f79b7a2989 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 9 Apr 2021 12:44:25 +0300 Subject: [PATCH 147/239] update setup.py: remove py3.4,3.5 --- setup.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 5f39236..a868500 100644 --- a/setup.py +++ b/setup.py @@ -42,19 +42,15 @@ 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.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Software Development :: Libraries :: Python Modules' From f01c7d617cfb91a32103ad9b4f7d4628c7b5893d Mon Sep 17 00:00:00 2001 From: Tom Whitwell Date: Tue, 12 Oct 2021 12:55:22 +0100 Subject: [PATCH 148/239] Use version specified in `.node-version` if exists It's pretty common to have a file `.node-version` in a repo to specify the version of node to use. This will pick up the version specified in this file and use that as the default when `Config` is initialised. --- nodeenv.py | 5 +++++ 1 file changed, 5 insertions(+) mode change 100755 => 100644 nodeenv.py diff --git a/nodeenv.py b/nodeenv.py old mode 100755 new mode 100644 index 4465b04..ba64aa8 --- a/nodeenv.py +++ b/nodeenv.py @@ -106,6 +106,7 @@ 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) @@ -133,6 +134,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.readlines(1)[0].strip()) + @classmethod def _dump(cls): """ From 5e35146b58bf4b1248698032a461d6a9041a1a05 Mon Sep 17 00:00:00 2001 From: Augusto Andreoli Date: Sun, 7 Nov 2021 01:16:30 +0100 Subject: [PATCH 149/239] Require setuptools (because of pkg_resources) See https://github.com/pre-commit/pre-commit/issues/2122 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index a868500..eb4c759 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ def read_file(file_name): license='BSD', author='Eugene Kalinin', author_email='e.v.kalinin@gmail.com', - install_requires=[], + install_requires=['setuptools'], description="Node.js virtual environment builder", long_description=ldesc, py_modules=['nodeenv'], From d65c3f21f9906d1ce463c3bbe800a6e5caeb41d1 Mon Sep 17 00:00:00 2001 From: proItheus <50539150+proItheus@users.noreply.github.com> Date: Mon, 6 Dec 2021 00:26:43 +0800 Subject: [PATCH 150/239] Fix problem when used with fish and virtualenv Changed "_old_fish_prompt" to "_node_old_fish_prompt" to avoid conflict with virtualenv --- nodeenv.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index ba64aa8..56e01bf 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1380,8 +1380,8 @@ def main(): # Erase virtualenv's `fish_prompt` and restore the original. functions -e fish_prompt - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt + functions -c _node_old_fish_prompt fish_prompt + functions -e _node_old_fish_prompt set -e _OLD_NODE_FISH_PROMPT_OVERRIDE end @@ -1456,8 +1456,8 @@ def main(): set -gx npm_config_prefix "__NPM_CONFIG_PREFIX__" if test -z "$NODE_VIRTUAL_ENV_DISABLE_PROMPT" - # Copy the current `fish_prompt` function as `_old_fish_prompt`. - functions -c fish_prompt _old_fish_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. From 8e1c5746f79ce99a67b6d8a01ab403fa21e9b751 Mon Sep 17 00:00:00 2001 From: Andrey Mishchenko Date: Sat, 4 Dec 2021 13:24:46 -0500 Subject: [PATCH 151/239] Replace optparse with argparse Optparse is deprecated since Python 3.2: https://docs.python.org/3/library/optparse.html This PR updates the optparse code to use argparse, as well as to use the variable naming conventions that are typically used with argparse code. See: https://docs.python.org/3/library/argparse.html#upgrading-optparse-code --- nodeenv.py | 257 +++++++++++++++++++++++++++-------------------------- 1 file changed, 129 insertions(+), 128 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 56e01bf..004c2e2 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -20,7 +20,7 @@ import stat import logging import operator -import optparse +import argparse import subprocess import tarfile import pipes @@ -169,16 +169,16 @@ def remove_env_bin_from_path(env, env_bin_dir): return env.replace(env_bin_dir + ':', '') -def node_version_from_opt(opt): +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(opt.node) + return parse_version(args.node) def create_logger(): @@ -221,11 +221,13 @@ def parse_args(check=True): Set `check` to False to skip validation checks. """ - parser = optparse.OptionParser( - version=nodeenv_version, - usage="%prog [OPTIONS] ENV_DIR") + parser = argparse.ArgumentParser( + usage="%(prog)s [OPTIONS] DEST_DIR") - parser.add_option( + parser.add_argument( + '--version', action='version', version=nodeenv_version) + + 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 ' @@ -234,90 +236,90 @@ def parse_args(check=True): 'Use `lts` to use the latest LTS release. ' 'Use `system` to use system-wide node.') - parser.add_option( + parser.add_argument( '--mirror', action="store", dest='mirror', help='Set mirror server of nodejs.org to download from.') if not is_WIN: - parser.add_option( + 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_option( + parser.add_argument( '--load-average', dest='load_average', help='Sets maximum load average for executing parallel commands ' 'at node.js compilation.') - parser.add_option( + parser.add_argument( '--without-ssl', dest='without_ssl', action='store_true', default=Config.without_ssl, help='Build node.js without SSL support') - parser.add_option( + parser.add_argument( '--debug', dest='debug', action='store_true', default=Config.debug, help='Build debug variant of the node.js') - parser.add_option( + parser.add_argument( '--profile', dest='profile', action='store_true', default=Config.profile, help='Enable profiling for node.js') - parser.add_option( + parser.add_argument( '--make', '-m', dest='make_path', metavar='MAKE_PATH', help='Path to make command', default=Config.make) - parser.add_option( + parser.add_argument( '--source', dest='prebuilt', action='store_false', default=Config.prebuilt, help='Install node.js from the source') - parser.add_option( + 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( + 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. 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., ' @@ -325,62 +327,61 @@ 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( + parser.add_argument( '--prebuilt', dest='prebuilt', action='store_true', default=Config.prebuilt, help='Install node.js from prebuilt package (default)') - parser.add_option( + 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 -') - options, args = parser.parse_args() + parser.add_argument( + metavar='DEST_DIR', dest='env_dir', nargs='?', help='Destination directory') + + args = parser.parse_args() - if options.config_file is None: - options.config_file = ["./tox.ini", "./setup.cfg", "~/.nodeenvrc"] - elif not options.config_file: - options.config_file = [] + 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): @@ -566,7 +567,7 @@ def tarfile_open(*args, **kwargs): tf.close() -def download_node_src(node_url, src_dir, opt): +def download_node_src(node_url, src_dir, args): """ Download source code """ @@ -589,7 +590,7 @@ def download_node_src(node_url, src_dir, opt): member_name = operator.attrgetter('name') with ctx as archive: - node_ver = re.escape(opt.node) + node_ver = re.escape(args.node) rexp_string = r"node-v%s[^/]*/(README\.md|CHANGELOG\.md|LICENSE)"\ % node_ver extract_list = [ @@ -661,11 +662,11 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version): logger.info('.', extra=dict(continued=True)) -def build_node_from_src(env_dir, src_dir, node_src_dir, opt): +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) @@ -680,7 +681,7 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): # python 2.* version in this case. try: _, which_python2_output = callit( - ['which', 'python2'], opt.verbose, True, node_src_dir, env + ['which', 'python2'], args.verbose, True, node_src_dir, env ) python2_path = which_python2_output[0] except (OSError, IndexError): @@ -701,80 +702,80 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, opt): './configure', '--prefix=%s' % pipes.quote(env_dir) ] - if opt.without_ssl: + 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 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, opt) + 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, opt): +def install_node_wrapped(env_dir, src_dir, args): env_dir = abspath(env_dir) - node_src_dir = join(src_dir, to_utf8('node-v%s' % opt.node)) - src_type = "prebuilt" if opt.prebuilt else "source" + 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, opt.node), + logger.info(' * Install %s node (%s) ' % (src_type, args.node), extra=dict(continued=True)) - if opt.prebuilt: - node_url = get_node_bin_url(opt.node) + if args.prebuilt: + node_url = get_node_bin_url(args.node) else: - node_url = get_node_src_url(opt.node) + node_url = get_node_src_url(args.node) # get src if not downloaded yet if not os.path.exists(node_src_dir): - download_node_src(node_url, src_dir, opt) + download_node_src(node_url, src_dir, args) logger.info('.', extra=dict(continued=True)) - if opt.prebuilt: - copy_node_from_prebuilt(env_dir, src_dir, opt.node) + 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, opt) + 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)) 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} && npm install -g npm@{1}'.format( pipes.quote(join(env_dir, 'bin', 'activate')), - opt.npm, + args.npm, ) ), env=env, @@ -783,19 +784,19 @@ def install_npm(env_dir, _src_dir, opt): stderr=subprocess.STDOUT, ) out, _ = proc.communicate() - if opt.verbose: + if args.verbose: logger.info(out) logger.info('done.') -def install_npm_win(env_dir, src_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) ... ' % opt.npm, + logger.info(' * Install npm.js (%s) ... ' % args.npm, extra=dict(continued=True)) - npm_url = 'https://github.com/npm/cli/archive/v%s.zip' % opt.npm + 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') @@ -813,7 +814,7 @@ def install_npm_win(env_dir, src_dir, opt): with zipfile.ZipFile(npm_contents, 'r') as zipf: zipf.extractall(src_dir) - npm_ver = 'cli-%s' % opt.npm + 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')) @@ -826,21 +827,21 @@ def install_npm_win(env_dir, src_dir, opt): 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, opt.npm) + 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, opt): +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": + 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 = '. ' + pipes.quote(activate_path) + \ ' && npm install -g %(pack)s' else: @@ -852,12 +853,12 @@ 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 """ @@ -882,13 +883,13 @@ def install_activate(env_dir, opt): if is_CYGWIN: mkdir(bin_dir) - if opt.node == "system": + if args.node == "system": files["node"] = SHIM 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)) - if opt.node == "system": + if args.node == "system": env = os.environ.copy() env.update({'PATH': remove_env_bin_from_path(env['PATH'], bin_dir)}) for candidate in ("nodejs", "node"): @@ -923,7 +924,7 @@ def install_activate(env_dir, opt): # `bin/activate` should be appended if we inside # existing python's virtual environment need_append = False - if opt.python_virtualenv: + if args.python_virtualenv: disable_prompt = DISABLE_PROMPT.get(name, '') enable_prompt = ENABLE_PROMPT.get(name, '') content = disable_prompt + content + enable_prompt @@ -946,19 +947,19 @@ def set_predeactivate_hook(env_dir): hook.write(PREDEACTIVATE_SH) -def create_environment(env_dir, opt): +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')) @@ -966,16 +967,16 @@ 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_activate(env_dir, args) + if node_version_from_args(args) < parse_version("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, opt) - if opt.requirements: - install_packages(env_dir, opt) - if opt.python_virtualenv: + 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: + if args.clean_src: shutil.rmtree(src_dir) @@ -1015,8 +1016,8 @@ def get_last_lts_node_version(): for v in _get_versions_json() if v['lts']), None) -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: @@ -1027,7 +1028,7 @@ def get_env_dir(opt, args): logger.error('No python virtualenv is available') sys.exit(2) else: - res = args[0] + res = args.env_dir return to_utf8(res) @@ -1041,27 +1042,27 @@ def main(): Config._dump() return - opt, args = parse_args(check=False) + args = parse_args(check=False) # noinspection PyProtectedMember - Config._load(opt.config_file, opt.verbose) + Config._load(args.config_file, args.verbose) - opt, args = parse_args() + args = parse_args() - if opt.node.lower() == 'system' and is_WIN: + if args.node.lower() == 'system' and is_WIN: logger.error('Installing system node.js on win32 is not supported!') exit(1) global src_base_url global ignore_ssl_certs - ignore_ssl_certs = opt.ignore_ssl_certs + ignore_ssl_certs = args.ignore_ssl_certs src_domain = None - if opt.mirror: - if '://' in opt.mirror: - src_base_url = opt.mirror + if args.mirror: + if '://' in args.mirror: + src_base_url = args.mirror else: - src_domain = opt.mirror + src_domain = args.mirror # use unofficial builds only if musl and no explicitly chosen mirror elif is_x86_64_musl(): src_domain = 'unofficial-builds.nodejs.org' @@ -1070,19 +1071,19 @@ def main(): if src_base_url is None: src_base_url = 'https://%s/download/release' % src_domain - if not opt.node or opt.node.lower() == 'latest': - opt.node = get_last_stable_node_version() - elif opt.node.lower() == 'lts': - opt.node = get_last_lts_node_version() + 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 opt.list: + 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) # --------------------------------------------------------- From 1774d04daf9521a77c3cc116d59b3e9957fc7f2b Mon Sep 17 00:00:00 2001 From: Andrey Mishchenko Date: Sat, 4 Dec 2021 14:26:24 -0500 Subject: [PATCH 152/239] Split making and invoking the ArgumentParser into two functions --- nodeenv.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 004c2e2..cf5d0ee 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -215,11 +215,9 @@ def emit(self, record): 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 = argparse.ArgumentParser( usage="%(prog)s [OPTIONS] DEST_DIR") @@ -360,6 +358,16 @@ def parse_args(check=True): parser.add_argument( metavar='DEST_DIR', dest='env_dir', nargs='?', help='Destination directory') + return parser + + +def parse_args(check=True): + """ + Parses command line arguments. + + Set `check` to False to skip validation checks. + """ + parser = make_parser() args = parser.parse_args() if args.config_file is None: From d4aa5cb7e9c7887bb6c78bb12fbf5d75bf2c9dbf Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Wed, 8 Dec 2021 10:18:51 +0300 Subject: [PATCH 153/239] Set SSL protocol, if need to ignore ssl. Fixes #296 --- nodeenv.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 56e01bf..2e07102 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -605,7 +605,9 @@ def urlopen(url): headers = {'User-Agent': 'nodeenv/%s (%s)' % (nodeenv_version, home_url)} req = urllib2.Request(url, None, headers) if ignore_ssl_certs: - context = ssl.SSLContext() + # 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) From dd15674d351d9d78ed020aa1cd5bb4b3aa62ee82 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 5 Jan 2022 15:16:56 +0000 Subject: [PATCH 154/239] Fix warning on Pytest Fix: ``` tests/nodeenv_test.py:49 /home/runner/work/nodeenv/nodeenv/tests/nodeenv_test.py:49: PytestDeprecationWarning: @pytest.yield_fixture is deprecated. Use @pytest.fixture instead; they are the same. @pytest.yield_fixture ``` --- tests/nodeenv_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 752b6d4..a623707 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -46,7 +46,7 @@ def test_smoke_n_system_special_chars(tmpdir): ]) -@pytest.yield_fixture +@pytest.fixture def mock_index_json(): # retrieved 2019-12-31 with open(os.path.join(HERE, 'nodejs_index.json'), 'rb') as f: @@ -54,7 +54,7 @@ def mock_index_json(): yield -@pytest.yield_fixture +@pytest.fixture def cap_logging_info(): with mock.patch.object(nodeenv.logger, 'info') as mck: yield mck From 74ccd951647edd385fe2e7b0b6d2ceeb64b7ae9c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 5 Jan 2022 15:21:28 +0000 Subject: [PATCH 155/239] Fix Flake8 error Fix this error: ``` nodeenv.py:359:80: E501 line too long (84 > 79 characters) ``` Added in 8e1c5746 --- nodeenv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2ca89ea..9802686 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -356,7 +356,8 @@ def make_parser(): help='Ignore certificates for package downloads. - UNSAFE -') parser.add_argument( - metavar='DEST_DIR', dest='env_dir', nargs='?', help='Destination directory') + metavar='DEST_DIR', dest='env_dir', nargs='?', + help='Destination directory') return parser From 924933db138e024db64d3b7b97e32d6cf5509b75 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 5 Jan 2022 15:17:20 +0000 Subject: [PATCH 156/239] Update argument parser usage in tests Missed in 8e1c5746. --- tests/test_install_activate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 80e32ad..d729fd1 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -52,7 +52,7 @@ def test_write(tmpdir, name, content_var): bin_dir.join(n).write(n) with mock.patch.object(sys, 'argv', ['nodeenv', str(tmpdir)]): - opts = nodeenv.parse_args()[0] + opts = nodeenv.parse_args() nodeenv.install_activate(str(tmpdir), opts) content = getattr(nodeenv, content_var) @@ -70,7 +70,7 @@ def test_python_virtualenv(tmpdir, name, content_var): bin_dir.join(n).write(n) with mock.patch.object(sys, 'argv', ['nodeenv', '-p']): - opts = nodeenv.parse_args()[0] + opts = nodeenv.parse_args() nodeenv.install_activate(str(tmpdir), opts) content = getattr(nodeenv, content_var) From 2461929b505d8fe9146fb89813e9c4a0d3b62d18 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Wed, 5 Jan 2022 15:09:37 +0000 Subject: [PATCH 157/239] Drop Python 3.6, add Python 3.10, run tests on GitHub Actions --- .github/workflows/main.yml | 76 ++++++++++++++++++++++++++++++++++++++ .travis.yml | 11 ------ setup.py | 7 +++- tox.ini | 15 +------- 4 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..55c84d6 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,76 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +jobs: + tests: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-20.04 + + strategy: + matrix: + python-version: + - 2.7 + - 3.7 + - 3.8 + - 3.9 + - '3.10' + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade tox + + - name: Run tox targets for ${{ matrix.python-version }} + run: | + ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}") + TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') tox + + - name: Upload coverage data + uses: actions/upload-artifact@v2 + with: + name: coverage-data + path: '.coverage.*' + + coverage: + name: Coverage + runs-on: ubuntu-20.04 + needs: tests + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-python@v2 + with: + python-version: '3.10' + + - name: Install dependencies + run: python -m pip install --upgrade coverage[toml] + + - name: Download data + uses: actions/download-artifact@v2 + with: + name: coverage-data + + - 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 + if: ${{ failure() }} + uses: actions/upload-artifact@v2 + with: + name: html-report + path: htmlcov diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ef12b58..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: python -python: - - 2.7 - - 3.6 - - 3.7 - - pypy -install: pip install coveralls tox-travis -script: tox -after_success: - - coveralls -sudo: false diff --git a/setup.py b/setup.py index eb4c759..c755cfd 100644 --- a/setup.py +++ b/setup.py @@ -33,6 +33,9 @@ def read_file(file_name): author='Eugene Kalinin', author_email='e.v.kalinin@gmail.com', install_requires=['setuptools'], + 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'], @@ -49,8 +52,10 @@ def read_file(file_name): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', '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' diff --git a/tox.ini b/tox.ini index 80b9ab4..4fea8e0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] -# These should match the travis env list -envlist = py27,py36,py37,pypy +# These should match the GitHub Actions env list +envlist = py27,py37,py38,py39,py310 [testenv] install_command = pip install {opts} {packages} @@ -8,24 +8,13 @@ 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 55 # TODO: 100 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 From be2b958a91cef3d38a85856385d70f76761b6d6e Mon Sep 17 00:00:00 2001 From: Max Melamed Date: Tue, 11 Jan 2022 12:32:17 -0500 Subject: [PATCH 158/239] Patch node installation for M1 --- nodeenv.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 2ca89ea..79475f6 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -756,7 +756,12 @@ def install_node_wrapped(env_dir, src_dir, args): # get src if not downloaded yet if not os.path.exists(node_src_dir): - download_node_src(node_url, src_dir, args) + 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) logger.info('.', extra=dict(continued=True)) From 384ba984b53855d185c87ce36e0044edae3e97f2 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Thu, 21 Apr 2022 22:35:09 +0300 Subject: [PATCH 159/239] Fix pep --- nodeenv.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 77fd902..3249873 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -762,7 +762,8 @@ def install_node_wrapped(env_dir, 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) + download_node_src(node_url.replace('arm64', 'x64'), + src_dir, args) logger.info('.', extra=dict(continued=True)) @@ -937,7 +938,7 @@ def install_activate(env_dir, args): # $ 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 = False if args.python_virtualenv: From ac9a510e11ac5ee10178b218eae1a947e0e3fcc8 Mon Sep 17 00:00:00 2001 From: rely10 Date: Thu, 16 Jun 2022 11:18:13 -0700 Subject: [PATCH 160/239] Add ability to configure mirror through setting file --- README.rst | 16 +++++++++------- nodeenv.py | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 43c69a2..ffa3b14 100644 --- a/README.rst +++ b/README.rst @@ -242,15 +242,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 ------------ diff --git a/nodeenv.py b/nodeenv.py index 3249873..fc30e28 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -100,6 +100,7 @@ class Config(object): make = 'make' prebuilt = True ignore_ssl_certs = False + mirror = None @classmethod def _load(cls, configfiles, verbose=False): @@ -236,7 +237,7 @@ def make_parser(): parser.add_argument( '--mirror', - action="store", dest='mirror', + action="store", dest='mirror', default=Config.mirror, help='Set mirror server of nodejs.org to download from.') if not is_WIN: From a06b15812b3d1f6cb881da5a7a1400e0aff7f0b9 Mon Sep 17 00:00:00 2001 From: Maxim Mazurok Date: Wed, 22 Jun 2022 16:09:56 +1000 Subject: [PATCH 161/239] Add --with-npm to readme This `python -m nodeenv env --node=18.1.0 --npm=7.15.1` doesn't install npm@7.15.1 It will only work if we add `--with-npm`, so update docs example. I think caused by this https://github.com/ekalinin/nodeenv/commit/a92badca32381b97a8743e7097d6ff90208dfd48 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ffa3b14..c9e130b 100644 --- a/README.rst +++ b/README.rst @@ -130,7 +130,7 @@ Get available node.js versions:: 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:: From 63b3e6d8c96747461e6c3ba074dc468ab4b95e8b Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 25 Jun 2022 17:30:15 +0300 Subject: [PATCH 162/239] Makefile: update ut tests --- Makefile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 17d1b23..41dcf5b 100644 --- a/Makefile +++ b/Makefile @@ -25,14 +25,18 @@ clean: @rm -rf nodeenv/ env: + # https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages + # https://github.com/pypa/virtualenv/issues/1681 @rm -rf env && \ - virtualenv --no-site-packages env && \ + virtualenv env && \ . env/bin/activate && \ python setup.py install env-dev: + # https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages + # https://github.com/pypa/virtualenv/issues/1681 @rm -rf env-dev && \ - virtualenv --no-site-packages env-dev && \ + virtualenv env-dev && \ . env-dev/bin/activate && \ pip install -r requirements-dev.txt @@ -141,7 +145,7 @@ test10: clean tests: test1 test2 test3 test4 test5 test7 test8 test9 test10 clean ut: env-dev - @. env-dev/bin/activate && tox -e py27 + @. env-dev/bin/activate && tox -e py39 contributors: @echo "Nodeenv is written and maintained by Eugene Kalinin." > AUTHORS From 4f75a48775f32580d790c039997547694ee3934f Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 25 Jun 2022 18:20:38 +0300 Subject: [PATCH 163/239] Makefile: reg.tests work again --- Makefile | 118 +++++++++++++++++++++++++------------------------------ 1 file changed, 54 insertions(+), 64 deletions(-) diff --git a/Makefile b/Makefile index 41dcf5b..12a40de 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,7 @@ .PHONY: default deploy deploy-github deploy-pypi update-pypi clean tests env +TEST_ENV=env +DEV_TEST_ENV=env-dev +SETUP=python setup.py install > /dev/null default: : do nothing when dpkg-buildpackage runs this project Makefile @@ -21,131 +24,118 @@ clean: @rm -rf nodeenv.egg-info/ @rm -rf dist/ @rm -rf build/ - @rm -rf env/ + @rm -rf ${TEST_ENV}/ @rm -rf nodeenv/ -env: - # https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages - # https://github.com/pypa/virtualenv/issues/1681 - @rm -rf env && \ - virtualenv env && \ - . env/bin/activate && \ +clean-test-env: + @rm -rf ${TEST_ENV} + +# 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: - # https://virtualenv.pypa.io/en/legacy/reference.html#cmdoption-no-site-packages - # https://github.com/pypa/virtualenv/issues/1681 - @rm -rf env-dev && \ - virtualenv env-dev && \ - . env-dev/bin/activate && \ + @rm -rf ${DEV_TEST_ENV} && \ + virtualenv ${DEV_TEST_ENV} && \ + . ${DEV_TEST_ENV}/bin/activate && \ pip install -r requirements-dev.txt -test1: clean +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: system nodejs's for python3.5" + @echo " = test4: system nodejs's for python3.9" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages --python=python3.5 env && \ - . env/bin/activate && \ - python setup.py install && \ + @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 && \ + @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 && \ npm -v && \ node -v && \ - test "`freeze | wc -l`" = "1"; + 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 && \ rm -rf öäü -test9: clean +test9: clean clean-test-env setup-test-env @echo " =" @echo " = test9: unicode paths, #187" @echo " =" - @rm -rf env && \ - virtualenv --no-site-packages env && \ - . env/bin/activate && \ - python setup.py install && \ + @. ${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 +test10: clean clean-test-env setup-test-env @echo " =" - @echo " = test10: unicode paths, #189" + @echo " = test10: symlink does not fail if npm already exists, #189" @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 && \ nodeenv -j 4 -p --prebuilt -tests: test1 test2 test3 test4 test5 test7 test8 test9 test10 clean +tests: test1 test2 test3 test4 test7 test8 test9 test10 clean ut: env-dev - @. env-dev/bin/activate && tox -e py39 + @. ${DEV_TEST_ENV}/bin/activate && tox -e py39 contributors: @echo "Nodeenv is written and maintained by Eugene Kalinin." > AUTHORS From 60f71c61ae7177b1abdfbd2469d4346fe8072007 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 25 Jun 2022 18:30:09 +0300 Subject: [PATCH 164/239] update AUTHORS --- AUTHORS | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4a975de..d88a11d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,21 +9,22 @@ Patches and Suggestions - ivan hilkov - Vincent Bernat - Kyle P Davis +- Kefu Chai - Elias Kunnas +- Adam Johnson - Pierre Le Marre - Eashwar Ranganathan - Doug Turnbull - Anton Parkhomenko +- syndbg - Vyacheslav Levit - Travis Miller -- syndbg - Spencer Rathbun - Luis Orduz - Lucas Cimon - Lispython - Leonardo Fedalto - Kyle P Davis -- Kefu Chai - Jon Winn - Duncan Bellamy - Dennis Flanigan @@ -31,30 +32,40 @@ Patches and Suggestions - Cerem Cem ASLAN - Bruno Oliveira - Andrzej Pragacz +- Andrey Mishchenko - Alex Couper - 0Xellos - zjeuhpiung liu +- urbandove +- sam +- rely10 +- rachmadaniHaryono +- proItheus +- michael +- jiho +- dkgitdev +- dhilipsiva +- cmehay - Zenobius Jiricek - Yi-Feng Tzeng - Willem Jan Withagen - Walter dos Santos Filho - Vladimír Gorej - Vincent Bernat -- urbandove - Uman Shahzad +- Tom Whitwell - Tim Gates - Thomas Bechtold - Terseus - Stan Seibert - Shubhang Mani -- sam - Rik -- rachmadaniHaryono - Philipp Dieter - Mrinal Wadhwa - Michal Kolodziejski -- michael +- Maxim Mazurok - Max R +- Max Melamed - Max Liebkies - Marc-Antoine Parent - Marc Abramowitz @@ -63,20 +74,17 @@ Patches and Suggestions - Kai Weber - Josh Soref - Joby Harding -- jiho - Jesse Dhillon - Jeremy Banks - Geoffrey Huntley - Fabricio C Zuardi - Duncan Bellamy -- dkgitdev -- dhilipsiva - Dennis Flanigan - Dan North - Dan Fuchs - Damien Nozay -- cmehay - Brian Jacobel - Ben Davis +- Augusto Andreoli - Andreas Wirooks - Alexey Poryadin From 32113e3606082bc667d9dc0e872cde18ad3cde00 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 25 Jun 2022 18:31:12 +0300 Subject: [PATCH 165/239] Makefile: fix trailing spaces in AUTHORS --- AUTHORS | 170 +++++++++++++++++++++++++++---------------------------- Makefile | 2 +- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/AUTHORS b/AUTHORS index d88a11d..ce58a75 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,88 +3,88 @@ Nodeenv is written and maintained by Eugene Kalinin. Patches and Suggestions ``````````````````````` -- jhermann -- Anthony Sottile -- anatoly techtonik -- ivan hilkov -- Vincent Bernat -- Kyle P Davis -- Kefu Chai -- Elias Kunnas -- Adam Johnson -- Pierre Le Marre -- Eashwar Ranganathan -- Doug Turnbull -- Anton Parkhomenko -- syndbg -- Vyacheslav Levit -- Travis Miller -- Spencer Rathbun -- Luis Orduz -- Lucas Cimon -- Lispython -- Leonardo Fedalto -- Kyle P Davis -- Jon Winn -- Duncan Bellamy -- Dennis Flanigan -- Chris Beaven -- Cerem Cem ASLAN -- Bruno Oliveira -- Andrzej Pragacz -- Andrey Mishchenko -- Alex Couper -- 0Xellos -- zjeuhpiung liu -- urbandove -- sam -- rely10 -- rachmadaniHaryono -- proItheus -- michael -- jiho -- dkgitdev -- dhilipsiva -- cmehay -- Zenobius Jiricek -- Yi-Feng Tzeng -- Willem Jan Withagen -- Walter dos Santos Filho -- Vladimír Gorej -- Vincent Bernat -- Uman Shahzad -- Tom Whitwell -- Tim Gates -- Thomas Bechtold -- Terseus -- Stan Seibert -- Shubhang Mani -- Rik -- Philipp Dieter -- Mrinal Wadhwa -- Michal Kolodziejski -- Maxim Mazurok -- Max R -- Max Melamed -- Max Liebkies -- Marc-Antoine Parent -- Marc Abramowitz -- Laust Rud Jacobsen -- Ken Struys -- Kai Weber -- Josh Soref -- Joby Harding -- Jesse Dhillon -- Jeremy Banks -- Geoffrey Huntley -- Fabricio C Zuardi -- Duncan Bellamy -- Dennis Flanigan -- Dan North -- Dan Fuchs -- Damien Nozay -- Brian Jacobel -- Ben Davis -- Augusto Andreoli -- Andreas Wirooks -- Alexey Poryadin +- jhermann +- Anthony Sottile +- anatoly techtonik +- ivan hilkov +- Vincent Bernat +- Kyle P Davis +- Kefu Chai +- Elias Kunnas +- Adam Johnson +- Pierre Le Marre +- Eashwar Ranganathan +- Doug Turnbull +- Anton Parkhomenko +- syndbg +- Vyacheslav Levit +- Travis Miller +- Spencer Rathbun +- Luis Orduz +- Lucas Cimon +- Lispython +- Leonardo Fedalto +- Kyle P Davis +- Jon Winn +- Duncan Bellamy +- Dennis Flanigan +- Chris Beaven +- Cerem Cem ASLAN +- Bruno Oliveira +- Andrzej Pragacz +- Andrey Mishchenko +- Alex Couper +- 0Xellos +- zjeuhpiung liu +- urbandove +- sam +- rely10 +- rachmadaniHaryono +- proItheus +- michael +- jiho +- dkgitdev +- dhilipsiva +- cmehay +- Zenobius Jiricek +- Yi-Feng Tzeng +- Willem Jan Withagen +- Walter dos Santos Filho +- Vladimír Gorej +- Vincent Bernat +- Uman Shahzad +- Tom Whitwell +- Tim Gates +- Thomas Bechtold +- Terseus +- Stan Seibert +- Shubhang Mani +- Rik +- Philipp Dieter +- Mrinal Wadhwa +- Michal Kolodziejski +- Maxim Mazurok +- Max R +- Max Melamed +- Max Liebkies +- Marc-Antoine Parent +- Marc Abramowitz +- Laust Rud Jacobsen +- Ken Struys +- Kai Weber +- Josh Soref +- Joby Harding +- Jesse Dhillon +- Jeremy Banks +- Geoffrey Huntley +- Fabricio C Zuardi +- Duncan Bellamy +- Dennis Flanigan +- Dan North +- Dan Fuchs +- Damien Nozay +- Brian Jacobel +- Ben Davis +- Augusto Andreoli +- Andreas Wirooks +- Alexey Poryadin diff --git a/Makefile b/Makefile index 12a40de..f2f67cb 100644 --- a/Makefile +++ b/Makefile @@ -146,4 +146,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 From 36312be84d88a8b556d22778cfdcd1f23251d110 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 25 Jun 2022 18:33:28 +0300 Subject: [PATCH 166/239] 1.7.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index fc30e28..7e57016 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -47,7 +47,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.6.0' +nodeenv_version = '1.7.0' join = os.path.join abspath = os.path.abspath From b530ef9bbff061441b347998059acc66e415a31f Mon Sep 17 00:00:00 2001 From: Eashwar Ranganathan Date: Wed, 3 Aug 2022 10:52:21 -0700 Subject: [PATCH 167/239] Fix function name in fish_prompt --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 7e57016..3315d85 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1492,7 +1492,7 @@ def main(): # Restore the original $status echo "exit $old_status" | source - _old_fish_prompt + _node_old_fish_prompt end set -gx _OLD_NODE_FISH_PROMPT_OVERRIDE "$NODE_VIRTUAL_ENV" From cc67d5a4045220ab6b0785b8e3b01cab488dc2fa Mon Sep 17 00:00:00 2001 From: Avimitin Date: Mon, 8 Aug 2022 15:32:43 +0800 Subject: [PATCH 168/239] Add riscv64 into archmap Signed-off-by: Avimitin --- nodeenv.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nodeenv.py b/nodeenv.py index 7e57016..b68a506 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -547,6 +547,7 @@ def get_node_bin_url(version): 'armv8.4': 'arm64', 'ppc64le': 'ppc64le', # Power PC 's390x': 's390x', # IBM S390x + 'riscv64': 'riscv64', # RISCV 64 } sysinfo = { 'system': platform.system().lower(), From e2ca2ab08bbe2603a63090bd8862f6c391c2a08e Mon Sep 17 00:00:00 2001 From: Avimitin Date: Mon, 8 Aug 2022 16:12:30 +0800 Subject: [PATCH 169/239] Add unofficial mirror for riscv64 Signed-off-by: Avimitin --- nodeenv.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index b68a506..efa1b78 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -529,6 +529,8 @@ def get_root_url(version): 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 = { @@ -1083,7 +1085,7 @@ def main(): else: src_domain = args.mirror # use unofficial builds only if musl and no explicitly chosen mirror - elif is_x86_64_musl(): + elif is_x86_64_musl() or is_riscv64(): src_domain = 'unofficial-builds.nodejs.org' else: src_domain = 'nodejs.org' From 20e11d745e92eb3f2271d4892293ddd04bc91f96 Mon Sep 17 00:00:00 2001 From: Avimitin Date: Mon, 8 Aug 2022 16:42:58 +0800 Subject: [PATCH 170/239] Check architecture in mirror test Signed-off-by: Avimitin --- tests/nodeenv_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index a623707..0422cfa 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -6,6 +6,7 @@ import subprocess import sys import sysconfig +import platform import mock import pytest @@ -112,6 +113,8 @@ def test_mirror_option(): # 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) From 9ee50cf9921fb1f319834510823d8b340e087e99 Mon Sep 17 00:00:00 2001 From: Avimitin Date: Mon, 22 Aug 2022 13:53:20 +0800 Subject: [PATCH 171/239] Fix ci Signed-off-by: Avimitin --- nodeenv.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index efa1b78..7f7bcb7 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -529,8 +529,10 @@ def get_root_url(version): 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" + return platform.machine() == 'riscv64' + def get_node_bin_url(version): archmap = { From 8863ba1eeea1867bd374ecc6910ef29578ad38ad Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Fri, 16 Sep 2022 15:56:14 +0200 Subject: [PATCH 172/239] Upgrade GitHub Actions https://github.com/actions/checkout/releases https://github.com/actions/download-artifact/releases https://github.com/actions/setup-python/releases https://github.com/actions/upload-artifact/releases --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 55c84d6..9784349 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,9 +21,9 @@ jobs: - '3.10' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -38,7 +38,7 @@ jobs: TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') tox - name: Upload coverage data - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: coverage-data path: '.coverage.*' @@ -48,9 +48,9 @@ jobs: runs-on: ubuntu-20.04 needs: tests steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: '3.10' @@ -58,7 +58,7 @@ jobs: run: python -m pip install --upgrade coverage[toml] - name: Download data - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: coverage-data @@ -70,7 +70,7 @@ jobs: - name: Upload HTML report if: ${{ failure() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: html-report path: htmlcov From de8dc7d075f5d4d1bcbd527005d81a60da8a5251 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Mon, 21 Nov 2022 14:07:15 +0100 Subject: [PATCH 173/239] Make the mock dependency optional Since Python 3.3 unittest contains the mock module, deprecating the seperate mock module. --- requirements-dev.txt | 4 ++-- tests/nodeenv_test.py | 5 ++++- tests/test_install_activate.py | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index f9f2a89..47cbb6b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,6 +2,6 @@ coverage flake8 -mock +mock; python_version < '3.3' pytest -tox \ No newline at end of file +tox diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index a623707..9e8924a 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -7,7 +7,10 @@ import sys import sysconfig -import mock +try: + from unittest import mock +except ImportError: + import mock import pytest import nodeenv diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index d729fd1..80516a8 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -1,7 +1,10 @@ import sys import os -import mock +try: + from unittest import mock +except ImportError: + import mock import pytest import nodeenv From f0f2a4b35cc6b8185b17135536def1bfef3a1492 Mon Sep 17 00:00:00 2001 From: zbw Date: Mon, 16 Jan 2023 15:19:05 -0800 Subject: [PATCH 174/239] fix: prevent error about fish_prompt when using nested fish instances --- nodeenv.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 3315d85..e00af8e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1397,10 +1397,13 @@ def main(): # `fish_prompt` using `functions -e`. set -l fish_function_path - # 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 + # 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 From b0b0670115570d5604284715b97c0fca95b8f169 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Thu, 16 Mar 2023 20:31:22 +0100 Subject: [PATCH 175/239] GitHub Actions: fail-fast: false See which tests pass and which fail. --- .github/workflows/main.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9784349..2ec31b5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,13 +12,15 @@ jobs: runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: python-version: - - 2.7 - - 3.7 - - 3.8 - - 3.9 + - '2.7' + - '3.7' + - '3.8' + - '3.9' - '3.10' + - '3.11' steps: - uses: actions/checkout@v3 From 9f2f0c426e03c4f95af3e9c1b06becbf7d6e2a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Sun, 7 May 2023 10:26:00 +0200 Subject: [PATCH 176/239] Do multiple attempt to download the nodejs archive (IncompleteRead error) (#329) * Do multiple attempt to download the nodejs archive (fix for IncompleteRead error) * use logger instead of print * Fix linters errors * fix incomaptible py2.7 imports --- nodeenv.py | 23 +++++++++++++++++------ tests/nodeenv_test.py | 13 ++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 53ff5d7..f9c1d9e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -582,17 +582,28 @@ def tarfile_open(*args, **kwargs): tf.close() +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_src(node_url, src_dir, args): """ Download source code """ logger.info('.', extra=dict(continued=True)) - try: - dl_contents = io.BytesIO(urlopen(node_url).read()) - except IncompleteRead as e: - logger.warning('Incomplete read while reading' - 'from {}'.format(node_url)) - dl_contents = e.partial + dl_contents = _download_node_file(node_url) logger.info('.', extra=dict(continued=True)) if is_WIN or is_CYGWIN: diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index ab59775..09bcbb0 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -15,7 +15,7 @@ import pytest import nodeenv - +from nodeenv import IncompleteRead HERE = os.path.abspath(os.path.dirname(__file__)) @@ -146,3 +146,14 @@ def test_get_latest_node_version(): @pytest.mark.usefixtures('mock_index_json') def test_get_lts_node_version(): assert nodeenv.get_last_lts_node_version() == '12.14.0' + + +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 From 22d4cd9994e0a47b1f5d501cc674b5f48d7cc145 Mon Sep 17 00:00:00 2001 From: Tom Parker-Shemilt Date: Mon, 8 May 2023 23:09:35 +0100 Subject: [PATCH 177/239] On download failures, log the URL (#330) --- nodeenv.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index f9c1d9e..5c8aa2e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -781,6 +781,8 @@ def install_node_wrapped(env_dir, src_dir, args): # 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) logger.info('.', extra=dict(continued=True)) From 7b2695aaf5eefd0abf79b39c337aa27834bbc3dd Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 12 May 2023 11:01:22 +0300 Subject: [PATCH 178/239] 1.8.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 5c8aa2e..043766d 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -47,7 +47,7 @@ from pkg_resources import parse_version -nodeenv_version = '1.7.0' +nodeenv_version = '1.8.0' join = os.path.join abspath = os.path.abspath From 4ae75e3c3dfabee705405e0ef4e7459721fb17c4 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Fri, 12 May 2023 11:01:49 +0300 Subject: [PATCH 179/239] update AUTHORS --- AUTHORS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AUTHORS b/AUTHORS index ce58a75..fc17250 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,6 +11,7 @@ Patches and Suggestions - Kyle P Davis - Kefu Chai - Elias Kunnas +- Avimitin - Adam Johnson - Pierre Le Marre - Eashwar Ranganathan @@ -28,6 +29,7 @@ Patches and Suggestions - Jon Winn - Duncan Bellamy - Dennis Flanigan +- Christian Clauss - Chris Beaven - Cerem Cem ASLAN - Bruno Oliveira @@ -36,6 +38,7 @@ Patches and Suggestions - Alex Couper - 0Xellos - zjeuhpiung liu +- zbw - urbandove - sam - rely10 @@ -54,6 +57,7 @@ Patches and Suggestions - Vincent Bernat - Uman Shahzad - Tom Whitwell +- Tom Parker-Shemilt - Tim Gates - Thomas Bechtold - Terseus @@ -76,8 +80,10 @@ Patches and Suggestions - Joby Harding - Jesse Dhillon - Jeremy Banks +- Jelle van der Waa - Geoffrey Huntley - Fabricio C Zuardi +- Eashwar Ranganathan - Duncan Bellamy - Dennis Flanigan - Dan North @@ -85,6 +91,7 @@ Patches and Suggestions - Damien Nozay - Brian Jacobel - Ben Davis +- Bastien Gérard - Augusto Andreoli - Andreas Wirooks - Alexey Poryadin From 441de9cefefc919a18e22c96488f0f16a1456dbe Mon Sep 17 00:00:00 2001 From: Philipp A Date: Thu, 5 Oct 2023 19:10:41 +0200 Subject: [PATCH 180/239] Switch to packaging (#338) * Switch to packaging * install package * fix * support isolated builds --- .github/workflows/main.yml | 6 ++++-- nodeenv.py | 14 +++++++------- pyproject.toml | 3 +++ setup.py | 8 ++++++-- 4 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 pyproject.toml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2ec31b5..cbe60e4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -31,8 +31,10 @@ jobs: - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox + # 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: | diff --git a/nodeenv.py b/nodeenv.py index 043766d..f0cabac 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -45,7 +45,7 @@ import http IncompleteRead = http.client.IncompleteRead -from pkg_resources import parse_version +from packaging import version nodeenv_version = '1.8.0' @@ -177,9 +177,9 @@ def node_version_from_args(args): if args.node == 'system': out, err = subprocess.Popen( ["node", "--version"], stdout=subprocess.PIPE).communicate() - return parse_version(clear_output(out).replace('v', '')) + return version.parse(clear_output(out).replace('v', '')) - return parse_version(args.node) + return version.parse(args.node) def create_logger(): @@ -519,9 +519,9 @@ 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 '%s/v%s/' % (src_base_url, version) +def get_root_url(version_str): + if version.parse(version_str) > version.parse("0.5.0"): + return '%s/v%s/' % (src_base_url, version_str) else: return src_base_url @@ -1004,7 +1004,7 @@ def create_environment(env_dir, args): # before npm install, npm use activate # for install install_activate(env_dir, args) - if node_version_from_args(args) < parse_version("0.6.3") or args.with_npm: + if node_version_from_args(args) < version.parse("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: 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/setup.py b/setup.py index c755cfd..e02793a 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 + def read_file(file_name): return codecs.open( @@ -32,7 +36,7 @@ def read_file(file_name): license='BSD', author='Eugene Kalinin', author_email='e.v.kalinin@gmail.com', - install_requires=['setuptools'], + install_requires=['packaging'], python_requires=( ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" ), From eaa9de97e561ab4f99458c94633e92547e72d5f1 Mon Sep 17 00:00:00 2001 From: Johnny Lim Date: Fri, 6 Oct 2023 02:12:04 +0900 Subject: [PATCH 181/239] Add a missing space in warning log message in _download_node_file() (#340) --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index f0cabac..9d5dd06 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -590,7 +590,7 @@ def _download_node_file(node_url, n_attempt=3): return io.BytesIO(urlopen(node_url).read()) except IncompleteRead as e: logger.warning( - 'Incomplete read while reading' + 'Incomplete read while reading ' 'from {} - {}'.format(node_url, e) ) n_attempt -= 1 From bbffd9b236857a4a5cfa18f27ca10359f0c8600f Mon Sep 17 00:00:00 2001 From: Robert Schwebel Date: Tue, 28 May 2024 19:45:23 +0200 Subject: [PATCH 182/239] Fix Github Actions (#347) * workflows: add a workflow_dispatch trigger to start workflows manually To be able to manually run a workflow from the Github web interface, add a workflow_dispatch trigger. Note that this does only work once this change has hit the default branch. * workflow: remove python 2.7 testing Python 2.7 is long obsolete, deprecated and not supported any more. Remove it from the tests. This test job is especially supposed to run on ubuntu-20.04, which doesn't have Python 2.7 any more. Without this patch, this workflow fails with: Warning: The support for python 2.7 will be removed on June 19. Related issue: https://github.com/actions/setup-python/issues/672 Version 2.7 was not found in the local cache Error: The version '2.7' with architecture 'x64' was not found for Ubuntu 20.04. The list of all available versions can be found here: https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json * setup.py: ignore flake8 warning about module import at top of file Flake8 is unhappy with us because we violate PEP8: rsc@leda:~/git/nodeenv$ flake8 --extend-ignore=E127 nodeenv.py tests setup.py setup.py:16:1: E402 module level import not at top of file Ignore this warning in this case. * nodeenv.py: do not compare types According to this flake8 error: (env) rsc@leda:~/git/nodeenv$ flake8 --extend-ignore=E127 nodeenv.py tests setup.py nodeenv.py:421:19: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()` we should not compare types but use isinstance() instead, which can handle subclasses as well. See https://www.flake8rules.com/rules/E721.html for details. --- .github/workflows/main.yml | 2 +- nodeenv.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cbe60e4..69b2739 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,6 +5,7 @@ on: branches: - master pull_request: + workflow_dispatch: jobs: tests: @@ -15,7 +16,6 @@ jobs: fail-fast: false matrix: python-version: - - '2.7' - '3.7' - '3.8' - '3.9' diff --git a/nodeenv.py b/nodeenv.py index 9d5dd06..59fe1f4 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -418,7 +418,7 @@ def writefile(dest, content, overwrite=True, append=False): Create file and write content in it """ content = to_utf8(content) - if is_PY3 and type(content) != bytes: + 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)) diff --git a/setup.py b/setup.py index e02793a..10c147a 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ sys.path.insert(0, '.') -from nodeenv import nodeenv_version +from nodeenv import nodeenv_version # noqa: E402 def read_file(file_name): From 3e574a57cbed071df713d05082896d073a00c738 Mon Sep 17 00:00:00 2001 From: Robert Schwebel Date: Tue, 28 May 2024 19:47:15 +0200 Subject: [PATCH 183/239] Add Python 3.11 and 3.12 Test Coverage (#348) * workflows: add test coverage for Python 3.12 Python 3.12 has been released for a while, add test coverage support in our workflows. * tox: add environment for Python 3.11 Create a Python 3.11 test environment. * tox: add environment for Python 3.12 Create a Python 3.12 test environment. --- .github/workflows/main.yml | 1 + tox.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 69b2739..3f6a11d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -21,6 +21,7 @@ jobs: - '3.9' - '3.10' - '3.11' + - '3.12' steps: - uses: actions/checkout@v3 diff --git a/tox.ini b/tox.ini index 4fea8e0..de3ecac 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the GitHub Actions env list -envlist = py27,py37,py38,py39,py310 +envlist = py27,py37,py38,py39,py310,py311,py312 [testenv] install_command = pip install {opts} {packages} From dc114e19815bb74b3a1b45038c6197c08160d86a Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Tue, 28 May 2024 20:52:26 +0300 Subject: [PATCH 184/239] Drop `packaging` dependency in favor of a simple version-parsing function (#352) --- nodeenv.py | 17 +++++++++++------ setup.py | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 59fe1f4..e01d9e7 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -45,8 +45,6 @@ import http IncompleteRead = http.client.IncompleteRead -from packaging import version - nodeenv_version = '1.8.0' join = os.path.join @@ -170,6 +168,13 @@ def remove_env_bin_from_path(env, env_bin_dir): return env.replace(env_bin_dir + ':', '') +def parse_version(version_str): + """ + Parse version string to a tuple of integer parts + """ + return tuple(map(int, version_str.replace('v', '').split('.'))) + + def node_version_from_args(args): """ Parse the node version from the argparse args @@ -177,9 +182,9 @@ def node_version_from_args(args): if args.node == 'system': out, err = subprocess.Popen( ["node", "--version"], stdout=subprocess.PIPE).communicate() - return version.parse(clear_output(out).replace('v', '')) + return parse_version(clear_output(out)) - return version.parse(args.node) + return parse_version(args.node) def create_logger(): @@ -520,7 +525,7 @@ def callit(cmd, show_stdout=True, in_shell=False, def get_root_url(version_str): - if version.parse(version_str) > version.parse("0.5.0"): + if parse_version(version_str) > (0, 5): return '%s/v%s/' % (src_base_url, version_str) else: return src_base_url @@ -1004,7 +1009,7 @@ def create_environment(env_dir, args): # before npm install, npm use activate # for install install_activate(env_dir, args) - if node_version_from_args(args) < version.parse("0.6.3") or args.with_npm: + 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: diff --git a/setup.py b/setup.py index 10c147a..2977546 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ def read_file(file_name): license='BSD', author='Eugene Kalinin', author_email='e.v.kalinin@gmail.com', - install_requires=['packaging'], + install_requires=[], python_requires=( ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" ), From de428ee8e9c0189e8ba9b3dc5736552babbca28c Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Tue, 28 May 2024 20:10:39 +0200 Subject: [PATCH 185/239] Support shells with "set -u" (#345) --- nodeenv.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index e01d9e7..7d68237 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1261,17 +1261,17 @@ def main(): 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 @@ -1281,18 +1281,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 @@ -1306,7 +1306,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 @@ -1326,7 +1326,7 @@ def main(): # 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 @@ -1346,28 +1346,28 @@ def main(): 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" +_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 @@ -1376,7 +1376,7 @@ 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 """ From c1dffc5c64377cfcda9f2befd357e4791903bf39 Mon Sep 17 00:00:00 2001 From: Ben Beasley Date: Tue, 28 May 2024 14:12:55 -0400 Subject: [PATCH 186/239] On Python 3.3+, replace pipes.quote with shlex.quote (#342) * On Python 3.3+, replace pipes.quote with shlex.quote The pipes.quote() function was undocumented, and the pipes module was deprecated in Python 3.11 and will be removed in Python 3.13. Fixes #341. * Choose shlex or pipes based on Python version It was pointed out that pyupgrade can handle this better than try/except. --- nodeenv.py | 13 ++++++++----- tests/nodeenv_test.py | 9 ++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 7d68237..88c849f 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -23,7 +23,10 @@ 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 @@ -733,7 +736,7 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, args): conf_cmd = [ './configure', - '--prefix=%s' % pipes.quote(env_dir) + '--prefix=%s' % _quote(env_dir) ] if args.without_ssl: conf_cmd.append('--without-ssl') @@ -815,7 +818,7 @@ def install_npm(env_dir, _src_dir, args): ( 'bash', '-c', '. {0} && npm install -g npm@{1}'.format( - pipes.quote(join(env_dir, 'bin', 'activate')), + _quote(join(env_dir, 'bin', 'activate')), args.npm, ) ), @@ -883,10 +886,10 @@ def install_packages(env_dir, args): activate_path = join(env_dir, 'bin', 'activate') 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 = '. ' + pipes.quote(activate_path) + \ + 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' diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 09bcbb0..22dd5eb 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -2,7 +2,10 @@ from __future__ import unicode_literals import os.path -import pipes +if sys.version_info < (3, 3): + from pipes import quote as _quote +else: + from shlex import quote as _quote import subprocess import sys import sysconfig @@ -29,7 +32,7 @@ def test_smoke(tmpdir): '-m', 'nodeenv', '--prebuilt', nenv_path, ]) assert os.path.exists(nenv_path) - activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) + activate = _quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ 'sh', '-c', '. {} && node --version'.format(activate), ]) @@ -44,7 +47,7 @@ def test_smoke_n_system_special_chars(tmpdir): '-m', 'nodeenv', '-n', 'system', nenv_path, )) assert os.path.exists(nenv_path) - activate = pipes.quote(os.path.join(nenv_path, 'bin', 'activate')) + activate = _quote(os.path.join(nenv_path, 'bin', 'activate')) subprocess.check_call([ 'sh', '-c', '. {} && node --version'.format(activate), ]) From 066a02c69f202b84f6aa110bdb3837df34efa8c7 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 28 May 2024 21:24:46 +0300 Subject: [PATCH 187/239] Fix tests after #342 (#354) * fix tests after #342 * add coverage files into gitignore --- .gitignore | 1 + tests/nodeenv_test.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e10547b..26c0261 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .coverage +.coverage.* *.pyc *.pyo *.swp diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 22dd5eb..302e373 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -1,11 +1,12 @@ from __future__ import absolute_import from __future__ import unicode_literals -import os.path +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 From 1024f4f64ceabd612b4df9a0b9dbe2691b2f5f9d Mon Sep 17 00:00:00 2001 From: Sam James Date: Tue, 28 May 2024 19:26:30 +0100 Subject: [PATCH 188/239] Remove usage of non-portable `which` (#346) * Use Python's shutil.which() instead of shelling out to `which` to find Python 2 * Use `command -v` instead of `which` in README Fixes: https://github.com/ekalinin/nodeenv/issues/333 --- README.rst | 2 +- README.ru.rst | 2 +- nodeenv.py | 8 ++------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index c9e130b..3459572 100644 --- a/README.rst +++ b/README.rst @@ -211,7 +211,7 @@ 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: 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 88c849f..4bede6d 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -715,12 +715,8 @@ def build_node_from_src(env_dir, src_dir, node_src_dir, args): # 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'], args.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' From 5aaed3c89f7f5e3b4d88cfd7183fc168d5cd0b66 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 28 May 2024 21:40:26 +0300 Subject: [PATCH 189/239] Makefile: fixed tests target (regression tests) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f2f67cb..92a7557 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: default deploy deploy-github deploy-pypi update-pypi clean tests env TEST_ENV=env DEV_TEST_ENV=env-dev -SETUP=python setup.py install > /dev/null +SETUP=pip install -U pip setuptools && python setup.py install > /dev/null default: : do nothing when dpkg-buildpackage runs this project Makefile From 2aa4a494b89981269f368e4c29c168d98cd6bd94 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 28 May 2024 21:41:16 +0300 Subject: [PATCH 190/239] 1.9.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 4bede6d..bbc19fb 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -48,7 +48,7 @@ import http IncompleteRead = http.client.IncompleteRead -nodeenv_version = '1.8.0' +nodeenv_version = '1.9.0' join = os.path.join abspath = os.path.abspath From 9d74cd8f083ceeb546a33052683f8df083d54b1e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 28 May 2024 21:42:11 +0300 Subject: [PATCH 191/239] update AUTHORS --- AUTHORS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/AUTHORS b/AUTHORS index fc17250..2d64512 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,6 +21,7 @@ Patches and Suggestions - Vyacheslav Levit - Travis Miller - Spencer Rathbun +- Robert Schwebel - Luis Orduz - Lucas Cimon - Lispython @@ -56,6 +57,7 @@ Patches and Suggestions - Vladimír Gorej - Vincent Bernat - Uman Shahzad +- Tomi Belan - Tom Whitwell - Tom Parker-Shemilt - Tim Gates @@ -63,8 +65,10 @@ Patches and Suggestions - Terseus - Stan Seibert - Shubhang Mani +- Sam James - Rik - Philipp Dieter +- Philipp A - Mrinal Wadhwa - Michal Kolodziejski - Maxim Mazurok @@ -77,6 +81,7 @@ Patches and Suggestions - Ken Struys - Kai Weber - Josh Soref +- Johnny Lim - Joby Harding - Jesse Dhillon - Jeremy Banks @@ -91,7 +96,9 @@ Patches and Suggestions - Damien Nozay - Brian Jacobel - Ben Davis +- Ben Beasley - Bastien Gérard - Augusto Andreoli - Andreas Wirooks - Alexey Poryadin +- Aarni Koskela From 69e310af9b8de6d8398b69c8c9a3c902663c928c Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 21:42:31 +0300 Subject: [PATCH 192/239] Fix version discovery; #356, #357 (#358) --- nodeenv.py | 6 +++++- tests/nodeenv_test.py | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index bbc19fb..245ccd0 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -175,7 +175,11 @@ def parse_version(version_str): """ Parse version string to a tuple of integer parts """ - return tuple(map(int, version_str.replace('v', '').split('.'))) + 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): diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 302e373..6094c16 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -161,3 +161,9 @@ def test__download_node_file(): 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) From 231431ed1a6239708fb715edb56730474a416e32 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 21:43:41 +0300 Subject: [PATCH 193/239] 1.9.1 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 245ccd0..e3aaffd 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -48,7 +48,7 @@ import http IncompleteRead = http.client.IncompleteRead -nodeenv_version = '1.9.0' +nodeenv_version = '1.9.1' join = os.path.join abspath = os.path.abspath From 5d0a9d789e6dc6d558da5598238630af83fefa12 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 22:33:14 +0300 Subject: [PATCH 194/239] Makefile: add coverage target --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index 92a7557..e51464a 100644 --- a/Makefile +++ b/Makefile @@ -137,6 +137,12 @@ tests: test1 test2 test3 test4 test7 test8 test9 test10 clean ut: env-dev @. ${DEV_TEST_ENV}/bin/activate && tox -e py39 +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 @echo "" >> AUTHORS From 95f2e5eec81f71724817dd19e630e08f14fd3690 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 23:07:04 +0300 Subject: [PATCH 195/239] Add gh release config --- .github/release.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/release.yml diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000..e69de29 From 736812d1e5235ac0e29a5cd6418a8e7e0be0756d Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 23:07:28 +0300 Subject: [PATCH 196/239] Add gh release config - 2 --- .github/release.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index e69de29..e6805cf 100644 --- a/.github/release.yml +++ 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 From a6585e9a63e1601c4a37f3a1bb8fd0722dd6b51c Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Tue, 4 Jun 2024 23:08:24 +0300 Subject: [PATCH 197/239] Add a couple of tests --- tests/nodeenv_test.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 6094c16..d28d42b 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -167,3 +167,14 @@ 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') From 62ea1b7b71b4cfdef4381999817793e2ef041a95 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sat, 24 Aug 2024 22:00:41 +0300 Subject: [PATCH 198/239] Add support for Python 3.13 (#367) --- .github/workflows/main.yml | 10 ++++++---- tox.ini | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f6a11d..d7ea360 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,13 +22,15 @@ jobs: - '3.10' - '3.11' - '3.12' + - '3.13' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - name: Install dependencies run: | @@ -53,9 +55,9 @@ jobs: runs-on: ubuntu-20.04 needs: tests steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.10' diff --git a/tox.ini b/tox.ini index de3ecac..6ec9b41 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the GitHub Actions env list -envlist = py27,py37,py38,py39,py310,py311,py312 +envlist = py37,py38,py39,py310,py311,py312,py313 [testenv] install_command = pip install {opts} {packages} From 4442d108356ec61231a915e13d008869d1f56104 Mon Sep 17 00:00:00 2001 From: Han Yeong-woo Date: Sun, 25 Aug 2024 19:56:00 +0900 Subject: [PATCH 199/239] Support leading `v` in `.node-version` (#359) --- nodeenv.py | 2 +- tests/nodeenv_test.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index e3aaffd..2118186 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -138,7 +138,7 @@ def _load(cls, configfiles, verbose=False): if os.path.exists(".node-version"): with open(".node-version", "r") as v_file: - setattr(cls, "node", v_file.readlines(1)[0].strip()) + setattr(cls, "node", v_file.readline().strip().lstrip("v")) @classmethod def _dump(cls): diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index d28d42b..a70973d 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -178,3 +178,32 @@ 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 From cf0c9937da6db7afa3afa6cb03d2bcc84462c459 Mon Sep 17 00:00:00 2001 From: max0x53 <110969456+max0x53@users.noreply.github.com> Date: Sun, 25 Aug 2024 11:58:22 +0100 Subject: [PATCH 200/239] Check host platform when finding `node` version (#363) See #362 --- nodeenv.py | 25 ++++++++++++++++++++++--- tests/nodeenv_test.py | 28 ++++++++++++++++++++++++++-- tests/nodejs_index.json | 4 ++-- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 2118186..505583b 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1045,19 +1045,38 @@ 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 """ - return _get_versions_json()[0]['version'].lstrip('v') + return _get_last_node_version() def get_last_lts_node_version(): """ Return the last node.js version marked as LTS """ - return next((v['version'].lstrip('v') - for v in _get_versions_json() if v['lts']), None) + return _get_last_node_version(lts=True) def get_env_dir(args): diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index a70973d..d418e7a 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -68,6 +68,20 @@ def cap_logging_info(): yield mck +@pytest.fixture +def mock_host_platform(): + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False) as x64_mck: + with mock.patch.object(nodeenv, 'is_riscv64', return_value=False) as risc_mck: + yield + + +@pytest.fixture +def mock_riscv64_platform(): + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False) as x64_mck: + with mock.patch.object(nodeenv, 'is_riscv64', return_value=True) as risc_mck: + yield + + def mck_to_out(mck): return '\n'.join(call[0][0] for call in mck.call_args_list) @@ -142,16 +156,26 @@ def rewind(_): mock_logger.assert_called() -@pytest.mark.usefixtures('mock_index_json') +@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') +@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") diff --git a/tests/nodejs_index.json b/tests/nodejs_index.json index fbe8ecf..11bb736 100644 --- a/tests/nodejs_index.json +++ b/tests/nodejs_index.json @@ -1,13 +1,13 @@ [ {"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-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.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-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.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}, From 7ea0a4806a1b8c95cd4b0a2d3523537df0b6f79b Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sun, 25 Aug 2024 14:10:59 +0300 Subject: [PATCH 201/239] Fix linter errors after #363 --- nodeenv.py | 1 + tests/nodeenv_test.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 505583b..bccdfee 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1050,6 +1050,7 @@ 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 diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index d418e7a..e830a75 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -70,15 +70,15 @@ def cap_logging_info(): @pytest.fixture def mock_host_platform(): - with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False) as x64_mck: - with mock.patch.object(nodeenv, 'is_riscv64', return_value=False) as risc_mck: + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False): + with mock.patch.object(nodeenv, 'is_riscv64', return_value=False): yield @pytest.fixture def mock_riscv64_platform(): - with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False) as x64_mck: - with mock.patch.object(nodeenv, 'is_riscv64', return_value=True) as risc_mck: + with mock.patch.object(nodeenv, 'is_x86_64_musl', return_value=False): + with mock.patch.object(nodeenv, 'is_riscv64', return_value=True): yield From 23b25bc3f8fc266696202d01429554b71f22b700 Mon Sep 17 00:00:00 2001 From: Rob Moss <15984835+robmoss2k@users.noreply.github.com> Date: Sat, 20 Dec 2025 07:25:20 +0000 Subject: [PATCH 202/239] Use lowercase lookup for archmap (#382) --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index bccdfee..d48076e 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -567,7 +567,7 @@ def get_node_bin_url(version): } sysinfo = { 'system': platform.system().lower(), - 'arch': archmap[platform.machine()], + 'arch': archmap[platform.machine().lower()], } if is_WIN or is_CYGWIN: postfix = '-win-%(arch)s.zip' % sysinfo From 2f57b747fcbff2b6d811bbb76c9c2ad5765e3b6d Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 10:44:02 +0300 Subject: [PATCH 203/239] test: add tests for various platform architectures --- nodeenv.py | 2 +- tests/nodeenv_test.py | 262 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index d48076e..ec9bafd 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -552,7 +552,7 @@ def get_node_bin_url(version): 'i686': 'x86', 'x86_64': 'x64', # Linux Ubuntu 64 'amd64': 'x64', # FreeBSD 64bits - 'AMD64': 'x64', # Windows Server 2012 R2 (x64) + 'amd64': 'x64', # Windows Server 2012 R2 (x64) 'armv6l': 'armv6l', # arm 'armv7l': 'armv7l', 'armv8l': 'armv7l', diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index e830a75..baa0b84 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -231,3 +231,265 @@ def custom_open(file_path, *args, **kwargs): ): 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'), + ('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 From 4b208519cd4850b2c33339cd1e35dd4bb29fcd43 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 10:48:06 +0300 Subject: [PATCH 204/239] test: update Makefile and tox.ini for Py3.14 support - Changed Python command in Makefile to use variable for consistency. - Updated deployment commands to use the new Python variable. - Added Python 3.14 to the tox environment list. --- Makefile | 13 +++++++------ tox.ini | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index e51464a..92c8ee2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +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 +SETUP=pip install -U pip setuptools && $(PYTHON) setup.py install > /dev/null default: : do nothing when dpkg-buildpackage runs this project Makefile @@ -12,11 +13,11 @@ deploy-github: deploy-pypi: rm -rf dist - python setup.py sdist bdist_wheel + $(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 @@ -37,13 +38,13 @@ setup-test-env: env: clean-test-env setup-test-env @. ${TEST_ENV}/bin/activate && \ - python setup.py install + $(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} && \ - virtualenv ${DEV_TEST_ENV} && \ + $(PYTHON) -m venv ${DEV_TEST_ENV} && \ . ${DEV_TEST_ENV}/bin/activate && \ pip install -r requirements-dev.txt @@ -135,7 +136,7 @@ test10: clean clean-test-env setup-test-env tests: test1 test2 test3 test4 test7 test8 test9 test10 clean ut: env-dev - @. ${DEV_TEST_ENV}/bin/activate && tox -e py39 + @. ${DEV_TEST_ENV}/bin/activate && tox -e py314 coverage: env-dev @. ${DEV_TEST_ENV}/bin/activate && \ diff --git a/tox.ini b/tox.ini index 6ec9b41..e7e362f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the GitHub Actions env list -envlist = py37,py38,py39,py310,py311,py312,py313 +envlist = py37,py38,py39,py310,py311,py312,py313,py314 [testenv] install_command = pip install {opts} {packages} From c8419f33bec26fdcd1b9506ab921edeeb5475f14 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 10:56:16 +0300 Subject: [PATCH 205/239] ci: update GitHub Actions and tox configuration for Python 3.14 - Updated the Python version matrix in GitHub Actions to include Python 3.14. - Changed the runner environment to Ubuntu 24.04. - Updated actions/checkout and actions/setup-python to their latest versions. - Modified tox.ini to reflect the updated environment list. --- .github/workflows/main.yml | 20 +++++++++----------- tox.ini | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d7ea360..98bafe1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,24 +10,22 @@ on: jobs: tests: name: Python ${{ matrix.python-version }} - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false matrix: python-version: - - '3.7' - - '3.8' - - '3.9' - '3.10' - '3.11' - '3.12' - '3.13' + - '3.14' steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} allow-prereleases: true @@ -52,20 +50,20 @@ jobs: coverage: name: Coverage - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 needs: tests steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: - python-version: '3.10' + python-version: '3.14' - name: Install dependencies run: python -m pip install --upgrade coverage[toml] - name: Download data - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v5 with: name: coverage-data diff --git a/tox.ini b/tox.ini index e7e362f..61513da 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # These should match the GitHub Actions env list -envlist = py37,py38,py39,py310,py311,py312,py313,py314 +envlist = py310,py311,py312,py313,py314 [testenv] install_command = pip install {opts} {packages} From d2ad990358e484bcc491fbd7dab28a8b9da3a288 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 10:57:57 +0300 Subject: [PATCH 206/239] ci: update GitHub Actions to use latest artifact actions - Upgraded actions/download-artifact from v5 to v7. - Upgraded actions/upload-artifact from v3 to v6. --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 98bafe1..796c9cd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,7 +63,7 @@ jobs: run: python -m pip install --upgrade coverage[toml] - name: Download data - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v7 with: name: coverage-data @@ -75,7 +75,7 @@ jobs: - name: Upload HTML report if: ${{ failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v6 with: name: html-report path: htmlcov From f8d244f7e67b3d990d84997c209850d050c6fb63 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 10:58:48 +0300 Subject: [PATCH 207/239] ci: upgrade upload-artifact action to v6 in GitHub Actions workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 796c9cd..901728a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') tox - name: Upload coverage data - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v6 with: name: coverage-data path: '.coverage.*' From 6eb9bf05336ef028b1210bf1c05d9b1c6cbb3129 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 13:39:14 +0300 Subject: [PATCH 208/239] ci: enhance coverage data handling in GitHub Actions workflow - Updated the coverage data upload step to include the Python version in the artifact name. - Modified the download step to use a pattern for coverage data and enabled merging of multiple artifacts. --- .github/workflows/main.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 901728a..c51aaf3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,9 +43,10 @@ jobs: TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') tox - name: Upload coverage data + if: always() uses: actions/upload-artifact@v6 with: - name: coverage-data + name: coverage-data-${{ matrix.python-version }} path: '.coverage.*' coverage: @@ -65,7 +66,8 @@ jobs: - name: Download data uses: actions/download-artifact@v7 with: - name: coverage-data + pattern: coverage-data-* + merge-multiple: true - name: Combine coverage and fail if it's <100% run: | From 5822cc025e12176f188355a668faeefa978fc048 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 13:48:25 +0300 Subject: [PATCH 209/239] ci: update GH workflow (coverage fix) - Changed the runner environment from ubuntu-24.04 to ubuntu-latest for both tests and coverage jobs. - Simplified the tox command to directly specify the environment. - Adjusted the coverage data upload path to include the Python version. --- .github/workflows/main.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c51aaf3..b2eaddf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,7 +10,7 @@ on: jobs: tests: name: Python ${{ matrix.python-version }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest strategy: fail-fast: false @@ -28,7 +28,6 @@ jobs: - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - allow-prereleases: true - name: Install dependencies run: | @@ -39,19 +38,21 @@ jobs: - name: Run tox targets for ${{ matrix.python-version }} run: | - ENV_PREFIX=$(tr -C -d "0-9" <<< "${{ matrix.python-version }}") - TOXENV=$(tox --listenvs | grep "^py$ENV_PREFIX" | tr '\n' ',') tox + tox -e py${{ matrix.python-version }} + env: + # Set the COVERAGE_FILE environment variable for coverage.py + COVERAGE_FILE: .coverage.${{ matrix.python-version }} - name: Upload coverage data if: always() uses: actions/upload-artifact@v6 with: name: coverage-data-${{ matrix.python-version }} - path: '.coverage.*' + path: .coverage.${{ matrix.python-version }} coverage: name: Coverage - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest needs: tests steps: - uses: actions/checkout@v5 @@ -76,7 +77,6 @@ jobs: python -m coverage report --fail-under=55 - name: Upload HTML report - if: ${{ failure() }} uses: actions/upload-artifact@v6 with: name: html-report From d4b4abd36d07a6b26ac61df9b276d5c9b2b139c1 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:35:02 +0300 Subject: [PATCH 210/239] ci: refine tox command in GitHub Actions workflow - Updated the tox command to dynamically generate the environment suffix based on the Python version, improving compatibility and clarity. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b2eaddf..b6ccfca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,7 +38,8 @@ jobs: - name: Run tox targets for ${{ matrix.python-version }} run: | - tox -e py${{ matrix.python-version }} + ENV_SUFFIX=$(echo "${{ matrix.python-version }}" | tr -d '.') + tox -e py${ENV_SUFFIX} env: # Set the COVERAGE_FILE environment variable for coverage.py COVERAGE_FILE: .coverage.${{ matrix.python-version }} From aec300d8b39e6b9f052f461609983d218f410e58 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:41:02 +0300 Subject: [PATCH 211/239] ci: add debugging commands to GH workflow --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b6ccfca..d94ab4c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -76,6 +76,8 @@ jobs: python -m coverage combine python -m coverage html --skip-covered --skip-empty python -m coverage report --fail-under=55 + pwd + ls -l - name: Upload HTML report uses: actions/upload-artifact@v6 From 212f5ee88598155f80ffea481441093143346940 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:45:52 +0300 Subject: [PATCH 212/239] ci: add debugging output to gh workflow 2 --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d94ab4c..27fc645 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,6 +40,8 @@ jobs: run: | ENV_SUFFIX=$(echo "${{ matrix.python-version }}" | tr -d '.') tox -e py${ENV_SUFFIX} + pwd + ls -l env: # Set the COVERAGE_FILE environment variable for coverage.py COVERAGE_FILE: .coverage.${{ matrix.python-version }} @@ -76,8 +78,6 @@ jobs: python -m coverage combine python -m coverage html --skip-covered --skip-empty python -m coverage report --fail-under=55 - pwd - ls -l - name: Upload HTML report uses: actions/upload-artifact@v6 From 7feaa952a514de5fd0080a40f5cf4488293d5b99 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:49:24 +0300 Subject: [PATCH 213/239] ci: simplify debugging output in GH workflow - 3 --- .github/workflows/main.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 27fc645..b079d95 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,10 +41,7 @@ jobs: ENV_SUFFIX=$(echo "${{ matrix.python-version }}" | tr -d '.') tox -e py${ENV_SUFFIX} pwd - ls -l - env: - # Set the COVERAGE_FILE environment variable for coverage.py - COVERAGE_FILE: .coverage.${{ matrix.python-version }} + ls -la - name: Upload coverage data if: always() From ebb5e9003a491566f04be539c5a6872881e82ab4 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:50:44 +0300 Subject: [PATCH 214/239] ci: update coverage data upload path in GH workflow --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b079d95..a64c255 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,7 +48,7 @@ jobs: uses: actions/upload-artifact@v6 with: name: coverage-data-${{ matrix.python-version }} - path: .coverage.${{ matrix.python-version }} + path: .coverage.* coverage: name: Coverage From 919c6f5fe4f45127ab14c6f5461365e6162675c7 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 15:52:09 +0300 Subject: [PATCH 215/239] ci: include hidden files in coverage data upload step of GH workflow --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a64c255..2bcc8df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,6 +49,7 @@ jobs: with: name: coverage-data-${{ matrix.python-version }} path: .coverage.* + include-hidden-files: true coverage: name: Coverage From ef68d5a7632a32df5e3c7335db56319b705ef22e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:01:46 +0300 Subject: [PATCH 216/239] ci: clean up debugging output and rename coverage path in GH workflow --- .github/workflows/main.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2bcc8df..40d7bb1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,8 +40,6 @@ jobs: run: | ENV_SUFFIX=$(echo "${{ matrix.python-version }}" | tr -d '.') tox -e py${ENV_SUFFIX} - pwd - ls -la - name: Upload coverage data if: always() @@ -81,4 +79,4 @@ jobs: uses: actions/upload-artifact@v6 with: name: html-report - path: htmlcov + path: coverage-html From 995aa1a438a801b68e6acf13aa47dc9e3a2e5dc6 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:02:56 +0300 Subject: [PATCH 217/239] docs: update README with GH CI badge --- README.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 3459572..7a06bf4 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,9 @@ 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: @@ -54,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 @@ -127,7 +128,7 @@ 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 --with-npm --jobs=4 env-4.3 @@ -176,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:: @@ -201,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 @@ -213,7 +214,7 @@ environment:: $ npm install -g coffee-script $ 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 From ea4b215bdea49bba3f077bd2d8bbfc37e8523e6f Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:10:01 +0300 Subject: [PATCH 218/239] docs: expand README with detailed command line options and installation instructions --- README.rst | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/README.rst b/README.rst index 7a06bf4..4d8c872 100644 --- a/README.rst +++ b/README.rst @@ -235,6 +235,104 @@ use `shim` script:: $ ./env-4.3/bin/shim --version v0.4.3 +Command Line Options +-------------------- + +Basic options +^^^^^^^^^^^^^ + +``-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 ------------- You can use the INI-style file ``~/.nodeenvrc`` to set default values for many options, From 694509f65e2c00c8fcd7a69233853f3142cead63 Mon Sep 17 00:00:00 2001 From: Vizonex <114684698+Vizonex@users.noreply.github.com> Date: Sat, 20 Dec 2025 07:12:05 -0600 Subject: [PATCH 219/239] Add UV Virtual Environment support (#386) --- nodeenv.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index ec9bafd..088d2cc 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1088,6 +1088,8 @@ def get_env_dir(args): 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) From a6199d6fc04aed340cfbbda03007992fd8f55eff Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:16:08 +0300 Subject: [PATCH 220/239] test: add tests for get_env_dir - Implemented multiple test cases for the get_env_dir function to handle various scenarios including Python virtualenv with real_prefix, base_prefix, conda prefix, and VIRTUAL_ENV variable. - Added tests to ensure proper exit behavior when no virtualenv is available and to verify UTF-8 string encoding. --- tests/nodeenv_test.py | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index baa0b84..a41d3c4 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -493,3 +493,128 @@ def test_uppercase_machine_amd64(self): 'node-v18.0.0-win-x64.zip' ) assert url == expected + + +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' From 561e803187c638c97f822270fdf189958d512ea7 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 20 Dec 2025 13:19:33 +0000 Subject: [PATCH 221/239] Use sh instead of bash (#389) Currently bash is used to run some pretty trivial commands, but these commands don't require anything bash-specific and can run with a regular POSIX shell. Use sh instead, to remove bash as a dependency for this package. There is no need to update the list of dependencies since bash was already missing from this list. --- README.rst | 2 +- nodeenv.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 4d8c872..09880b8 100644 --- a/README.rst +++ b/README.rst @@ -362,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/nodeenv.py b/nodeenv.py index 088d2cc..a58c278 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -816,7 +816,7 @@ def install_npm(env_dir, _src_dir, args): ) proc = subprocess.Popen( ( - 'bash', '-c', + 'sh', '-c', '. {0} && npm install -g npm@{1}'.format( _quote(join(env_dir, 'bin', 'activate')), args.npm, @@ -1179,7 +1179,7 @@ def main(): """, } -SHIM = """#!/usr/bin/env bash +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__' @@ -1281,7 +1281,7 @@ def main(): 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 () { From 326a7a4c1ced11fb3356cdd2c8511f9cdeb81ebc Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:23:43 +0300 Subject: [PATCH 222/239] test: add comprehensive tests for install_npm and install_npm_win functions - Introduced multiple test cases for the install_npm function, covering basic installation, handling of the no_npm_clean flag, verbose output, special characters in paths, and environment variable inheritance. - Added tests for the install_npm_win function, ensuring correct URL construction, file removal before installation, and proper handling of different version formats. - Verified logging and subprocess behavior in various scenarios to ensure robustness of npm installation processes. --- tests/nodeenv_test.py | 429 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 429 insertions(+) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index a41d3c4..d590854 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -618,3 +618,432 @@ def test_returns_utf8_encoded_string(self): # 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 + assert os.path.join(env_dir, 'Scripts', 'node_modules', 'npm') == 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) + From 37c0c304317b9a5646e1779d38b71c4c6928a0a5 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:33:50 +0300 Subject: [PATCH 223/239] ci: add GH workflow for testing and coverage in PR --- .github/workflows/tests.yml | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/tests.yml 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/ + From 0b5ea9d55ad72ef30a5a7461e27b95c9453bd833 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:42:35 +0300 Subject: [PATCH 224/239] refactor(tests): improve readability of mock patches in nodeenv tests - Reformatted mock.patch.object calls in the TestInstallNpm and TestInstallNpmWin classes for better readability by splitting long lines. - Ensured consistent formatting across multiple test cases to enhance maintainability. --- tests/nodeenv_test.py | 65 ++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index d590854..c0dd36b 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -636,7 +636,9 @@ def test_install_npm_basic(self): 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, \ + 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) @@ -685,7 +687,9 @@ def test_install_npm_with_no_npm_clean(self): mock_proc = mock.Mock() mock_proc.communicate.return_value = (b'', None) - with mock.patch.object(subprocess, 'Popen', return_value=mock_proc) as mock_popen, \ + 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) @@ -730,7 +734,9 @@ def test_install_npm_latest_version(self): mock_proc = mock.Mock() mock_proc.communicate.return_value = (b'', None) - with mock.patch.object(subprocess, 'Popen', return_value=mock_proc) as mock_popen, \ + 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) @@ -752,7 +758,9 @@ def test_install_npm_with_special_chars_in_path(self): mock_proc = mock.Mock() mock_proc.communicate.return_value = (b'', None) - with mock.patch.object(subprocess, 'Popen', return_value=mock_proc) as mock_popen, \ + 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) @@ -778,7 +786,9 @@ def test_install_npm_environment_inheritance(self): 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, \ + 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) @@ -807,7 +817,9 @@ def test_install_npm_specific_version_formats(self): mock_proc = mock.Mock() mock_proc.communicate.return_value = (b'', None) - with mock.patch.object(subprocess, 'Popen', return_value=mock_proc) as mock_popen, \ + 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) @@ -841,7 +853,9 @@ def test_install_npm_win_basic(self): 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), \ + 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), \ @@ -883,11 +897,14 @@ def test_install_npm_win_removes_existing_files(self): # Simulate existing files def exists_side_effect(path): - if 'node_modules' in path or 'npm.cmd' in path or 'npm-cli.js' in 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), \ + 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), \ @@ -940,7 +957,9 @@ def test_install_npm_win_cygwin(self): # 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) + 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""" @@ -961,7 +980,9 @@ def test_install_npm_win_different_versions(self): 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, \ + 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), \ @@ -971,7 +992,9 @@ def test_install_npm_win_different_versions(self): 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' + 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): @@ -990,7 +1013,9 @@ def test_install_npm_win_paths(self): 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), \ + 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), \ @@ -1005,7 +1030,10 @@ def test_install_npm_win_paths(self): dst_path = copytree_call[1] assert 'cli-8.5.0' in src_path - assert os.path.join(env_dir, 'Scripts', 'node_modules', 'npm') == dst_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 @@ -1030,9 +1058,13 @@ def test_install_npm_win_zip_extraction(self): mock_zip.__exit__ = mock.Mock(return_value=False) mock_zip.extractall = mock.Mock() - with mock.patch.object(nodeenv, 'urlopen', return_value=mock_response), \ + 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( + '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'), \ @@ -1046,4 +1078,3 @@ def test_install_npm_win_zip_extraction(self): # Verify extraction mock_zip.extractall.assert_called_once_with(src_dir) - From b4cd00d453d9f4772c7c410dfbc57d7e757dad5e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:42:48 +0300 Subject: [PATCH 225/239] test: enhance activation tests for nodeenv with custom prompts and file handling - Added tests for custom prompts in nodeenv activation scripts, ensuring that the prompt can be set and correctly reflected in generated files. - Implemented tests to verify that activation files are executable upon creation and that all placeholders are replaced with appropriate values. - Included tests for creating symlinks and handling system node paths, improving coverage of the activation functionality. --- tests/test_install_activate.py | 214 +++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 80516a8..898896a 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -85,3 +85,217 @@ def test_python_virtualenv(tmpdir, name, content_var): 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' + mock_popen = mock.MagicMock() + mock_popen.communicate.return_value = ( + system_node.encode() + b'\n', b'') + + with mock.patch.object( + sys, 'argv', ['nodeenv', '--node=system', str(tmpdir)] + ): + with mock.patch('subprocess.Popen', return_value=mock_popen): + 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" From e868dbe29cad74819615d039b78af21bb2ae431d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sat, 20 Dec 2025 14:48:40 +0100 Subject: [PATCH 226/239] Replace additional use of `which(1)` with `shutil.which()` (#355) Replace the remaining use of external `which(1)` tool with `shutil.which()` from the standard Python library, finally removing the dependency on a third party package. This is a followup to 1024f4f64ceabd612b4df9a0b9dbe2691b2f5f9d. --- nodeenv.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index a58c278..3d5d264 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -934,14 +934,10 @@ def install_activate(env_dir, args): prompt = args.prompt or '(%s)' % os.path.basename(os.path.abspath(env_dir)) if args.node == "system": - env = os.environ.copy() - env.update({'PATH': remove_env_bin_from_path(env['PATH'], bin_dir)}) + 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" From 5f694e6ac261f29233a28061e4af64669199721e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:52:42 +0300 Subject: [PATCH 227/239] test: update test test_node_system_creates_shim - Replaced the use of `subprocess.Popen` with `shutil.which` to mock the system node path in the activation tests, enhancing the reliability of the test environment. - This change aligns with the ongoing effort to minimize external dependencies and improve test performance. --- tests/test_install_activate.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 898896a..10c3f43 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -131,14 +131,11 @@ def test_node_system_creates_shim(tmpdir): # Mock system node path system_node = '/usr/bin/node' - mock_popen = mock.MagicMock() - mock_popen.communicate.return_value = ( - system_node.encode() + b'\n', b'') with mock.patch.object( sys, 'argv', ['nodeenv', '--node=system', str(tmpdir)] ): - with mock.patch('subprocess.Popen', return_value=mock_popen): + with mock.patch('shutil.which', return_value=system_node): opts = nodeenv.parse_args() nodeenv.install_activate(str(tmpdir), opts) From 55d6c21a6d56631c0c1d08a04d3c1ea3531ba832 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:54:17 +0300 Subject: [PATCH 228/239] chore: update AUTHORS --- AUTHORS | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/AUTHORS b/AUTHORS index 2d64512..99ce636 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,9 +17,9 @@ Patches and Suggestions - Eashwar Ranganathan - Doug Turnbull - Anton Parkhomenko -- syndbg - Vyacheslav Levit - Travis Miller +- syndbg - Spencer Rathbun - Robert Schwebel - Luis Orduz @@ -39,23 +39,15 @@ Patches and Suggestions - Alex Couper - 0Xellos - zjeuhpiung liu -- zbw -- urbandove -- sam -- rely10 -- rachmadaniHaryono -- proItheus -- michael -- jiho -- dkgitdev -- dhilipsiva -- cmehay - 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 @@ -66,12 +58,20 @@ Patches and Suggestions - 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 @@ -83,17 +83,24 @@ Patches and Suggestions - 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 From d45aabbf54139f5ecbaf9db05d3949d39999136e Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:56:03 +0300 Subject: [PATCH 229/239] chore: add pyright ignore comments for compatibility --- nodeenv.py | 6 +++--- tests/test_install_activate.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 3d5d264..07c873a 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -34,11 +34,11 @@ import glob try: # pragma: no cover (py2 only) - from ConfigParser import SafeConfigParser as ConfigParser + from ConfigParser import SafeConfigParser as ConfigParser # pyright: ignore[reportMissingImports] # noinspection PyCompatibility - import urllib2 + import urllib2 # pyright: ignore[reportMissingImports] iteritems = operator.methodcaller('iteritems') - import httplib + import httplib # pyright: ignore[reportMissingImports] IncompleteRead = httplib.IncompleteRead except ImportError: # pragma: no cover (py3 only) from configparser import ConfigParser diff --git a/tests/test_install_activate.py b/tests/test_install_activate.py index 10c3f43..6a2b82b 100644 --- a/tests/test_install_activate.py +++ b/tests/test_install_activate.py @@ -4,7 +4,7 @@ try: from unittest import mock except ImportError: - import mock + import mock # pyright: ignore[reportMissingModuleSource] import pytest import nodeenv From 9dee547f5e45c9d1b155e4351d165f2b504ae281 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 16:56:42 +0300 Subject: [PATCH 230/239] chore: bump nodeenv version to 1.10.0 --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 07c873a..02bc318 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -48,7 +48,7 @@ import http IncompleteRead = http.client.IncompleteRead -nodeenv_version = '1.9.1' +nodeenv_version = '1.10.0' join = os.path.join abspath = os.path.abspath From ca775759f4b6740d5ebcd933d386a50bce1fe0e8 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 17:15:36 +0300 Subject: [PATCH 231/239] chore: update deploy-pypi in Makefile to use virtualenv --- Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 92c8ee2..7bd20a8 100644 --- a/Makefile +++ b/Makefile @@ -13,13 +13,15 @@ deploy-github: deploy-pypi: rm -rf dist - $(PYTHON) setup.py sdist bdist_wheel - twine upload --repository pypi 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 -deploy: contributors deploy-github deploy-pypi +deploy: contributors ut deploy-github deploy-pypi clean: @rm -rf nodeenv.egg-info/ From e716ac4054bdbe2208709e40745c3716b708d675 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 17:15:43 +0300 Subject: [PATCH 232/239] fix: add noqa comment for line length in ConfigParser import for compatibility --- nodeenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index 02bc318..451d3c3 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -34,7 +34,7 @@ import glob try: # pragma: no cover (py2 only) - from ConfigParser import SafeConfigParser as ConfigParser # pyright: ignore[reportMissingImports] + from ConfigParser import SafeConfigParser as ConfigParser # pyright: ignore[reportMissingImports] # noqa: E501 # noinspection PyCompatibility import urllib2 # pyright: ignore[reportMissingImports] iteritems = operator.methodcaller('iteritems') From d985d9be5d095b39321d6f156d3d95d123977ebf Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 20 Dec 2025 17:15:52 +0300 Subject: [PATCH 233/239] chore: update development dependencies in requirements-dev.txt - Added setuptools, twine, and wheel to the development requirements to support packaging and distribution tasks. --- requirements-dev.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requirements-dev.txt b/requirements-dev.txt index 47cbb6b..aa38656 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,4 +4,7 @@ coverage flake8 mock; python_version < '3.3' pytest +setuptools tox +twine +wheel From 68abdc398f42313c9204d1a8bd6b5fcc584a800e Mon Sep 17 00:00:00 2001 From: quazgar Date: Sat, 27 Dec 2025 20:15:47 +0100 Subject: [PATCH 234/239] FEAT: Check if activate is called as script. (#384) Co-authored-by: Daniel --- CHANGES | 5 +++++ nodeenv.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGES b/CHANGES index 2aa46b5..de03fd7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,11 @@ Nodeenv changelog ================= +Version [unreleased] +-------------------- + +- Added check for how `activate` is called. + Version 1.3.1 ------------- - Windows related fix `#207 `_ diff --git a/nodeenv.py b/nodeenv.py index 451d3c3..f7da140 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -1342,6 +1342,16 @@ def main(): fi } + +# 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 From 9d8c35e9cca8b2bdf6d099a2f5f83a2fe60022d7 Mon Sep 17 00:00:00 2001 From: Nathan Ernst Date: Sat, 27 Dec 2025 13:18:47 -0600 Subject: [PATCH 235/239] address deprecation warning in tarfile.TarFile.extract all in Python >= 3.12: explicitly set filter='data' to prevent writing files via '..' or absolute paths in the source tarfile (#380) --- nodeenv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nodeenv.py b/nodeenv.py index f7da140..9dd2aa9 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -636,7 +636,10 @@ def download_node_src(node_url, src_dir, args): for member in members(archive) if re.match(rexp_string, member_name(member)) is None ] - archive.extractall(src_dir, extract_list) + if sys.version_info >= (3, 12): + archive.extractall(src_dir, extract_list, filter="data") + else: + archive.extractall(src_dir, extract_list) def urlopen(url): From 22aa98a07b9c2d66bdb37efe0d203bf859d226e7 Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 27 Dec 2025 22:26:46 +0300 Subject: [PATCH 236/239] feat: add support for Solaris/illumos. fixes #360 - Updated the get_node_bin_url function to include 'i86pc' as a key mapping to 'x64'. - Enhanced test coverage by adding a corresponding test case for the new architecture. --- nodeenv.py | 1 + tests/nodeenv_test.py | 1 + 2 files changed, 2 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index f7da140..38cedfd 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -553,6 +553,7 @@ def get_node_bin_url(version): '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', diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index c0dd36b..0ad3948 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -244,6 +244,7 @@ class TestGetNodeBinUrl: ('x86_64', 'x64'), ('amd64', 'x64'), ('AMD64', 'x64'), + ('i86pc', 'x64'), ('armv6l', 'armv6l'), ('armv7l', 'armv7l'), ('armv8l', 'armv7l'), From d9ddf43658bf766fcc0d8f73b9ae4ef4e8d8e0fe Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 27 Dec 2025 22:39:53 +0300 Subject: [PATCH 237/239] feat: add predeactivate hooks for Windows - Implemented predeactivate hooks for Windows, creating both predeactivate.bat and predeactivate.ps1 files. - Updated set_predeactivate_hook function to handle both Windows and Unix systems. - Enhanced tests to verify the creation and content of predeactivate hooks based on the operating system. --- nodeenv.py | 24 +++++++++++++++++++++++- tests/nodeenv_test.py | 23 +++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index 470bfc3..395d632 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -986,7 +986,14 @@ def install_activate(env_dir, args): def set_predeactivate_hook(env_dir): - if not is_WIN: + 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) @@ -1564,6 +1571,21 @@ def main(): 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 diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 0ad3948..56bd4a4 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -116,10 +116,25 @@ def test_predeactivate_hook(tmpdir): # Throw error if environment directory has no bin path with pytest.raises((OSError, IOError)): nodeenv.set_predeactivate_hook(tmpdir.strpath) - tmpdir.mkdir('bin') - nodeenv.set_predeactivate_hook(tmpdir.strpath) - p = tmpdir.join('bin').join('predeactivate') - assert 'deactivate_node' in p.read() + + 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(): From e1302f7bb713552017542d6820f96916caff8f3b Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 27 Dec 2025 22:56:31 +0300 Subject: [PATCH 238/239] feat: enhance install_node_wrapped with error handling and extensive tests. fixes #336 - Added error handling to raise exceptions on download failures in install_node_wrapped. - Introduced a comprehensive test suite for install_node_wrapped, covering successful installations, fallback mechanisms, and error scenarios. - Ensured that no copy or build actions are performed after download failures, improving robustness. --- nodeenv.py | 1 + tests/nodeenv_test.py | 430 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 431 insertions(+) diff --git a/nodeenv.py b/nodeenv.py index 395d632..e1d5723 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -795,6 +795,7 @@ def install_node_wrapped(env_dir, src_dir, args): src_dir, args) else: logger.warning('Failed to download from %s' % node_url) + raise logger.info('.', extra=dict(continued=True)) diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 56bd4a4..03ae55e 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -511,6 +511,436 @@ def test_uppercase_machine_amd64(self): 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) + + node_src_dir = os.path.join(src_dir, 'node-v18.0.0') + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value='https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz' + ), \ + 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( + 'https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz', + 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') + + with mock.patch.object( + nodeenv, 'get_node_src_url', + return_value='https://nodejs.org/download/release/v18.0.0/node-v18.0.0.tar.gz' + ), \ + 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( + 'https://nodejs.org/download/release/v18.0.0/node-v18.0.0.tar.gz', + 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 download 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' + x64_url = 'https://nodejs.org/download/release/v16.0.0/node-v16.0.0-darwin-x64.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 directory 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) + + with mock.patch.object( + nodeenv, 'get_node_bin_url', + return_value='https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz' + ), \ + 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 download 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 that copy_node_from_prebuilt is not called after download 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 that build_node_from_src is not called after download 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 that copy is not called when both arm64 and x64 downloads 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""" From d1a89c4a0d2eae350f43368a1c8ec3b56fbcabff Mon Sep 17 00:00:00 2001 From: Eugene Kalinin Date: Sat, 27 Dec 2025 23:06:26 +0300 Subject: [PATCH 239/239] chore: fix linters --- nodeenv.py | 3 +- tests/nodeenv_test.py | 80 ++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/nodeenv.py b/nodeenv.py index e1d5723..e2cf1f0 100644 --- a/nodeenv.py +++ b/nodeenv.py @@ -988,7 +988,8 @@ def install_activate(env_dir, args): def set_predeactivate_hook(env_dir): if is_WIN: - # Windows: create predeactivate.bat for CMD and predeactivate.ps1 for PowerShell + # 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: diff --git a/tests/nodeenv_test.py b/tests/nodeenv_test.py index 03ae55e..818c182 100644 --- a/tests/nodeenv_test.py +++ b/tests/nodeenv_test.py @@ -136,7 +136,6 @@ def test_predeactivate_hook(tmpdir): 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'), @@ -525,11 +524,13 @@ def test_install_node_wrapped_success(self, tmpdir): src_dir = tmpdir.join('src').strpath os.makedirs(src_dir) - node_src_dir = os.path.join(src_dir, 'node-v18.0.0') - + 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='https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz' + return_value=bin_url ), \ mock.patch.object( nodeenv, 'download_node_src' @@ -543,7 +544,7 @@ def test_install_node_wrapped_success(self, tmpdir): # Verify download was called mock_download.assert_called_once_with( - 'https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz', + bin_url, src_dir, args ) @@ -564,9 +565,13 @@ def test_install_node_wrapped_from_source(self, tmpdir): 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='https://nodejs.org/download/release/v18.0.0/node-v18.0.0.tar.gz' + return_value=src_url ), \ mock.patch.object( nodeenv, 'download_node_src' @@ -580,7 +585,7 @@ def test_install_node_wrapped_from_source(self, tmpdir): # Verify download was called with source URL mock_download.assert_called_once_with( - 'https://nodejs.org/download/release/v18.0.0/node-v18.0.0.tar.gz', + src_url, src_dir, args ) @@ -591,7 +596,7 @@ def test_install_node_wrapped_from_source(self, tmpdir): ) def test_install_node_wrapped_arm64_fallback_to_x64(self, tmpdir): - """Test arm64 download fallback to x64 when arm64 is not available""" + """Test arm64 fallback to x64 when arm64 is not available""" args = mock.Mock() args.node = '16.0.0' args.prebuilt = True @@ -601,8 +606,10 @@ def test_install_node_wrapped_arm64_fallback_to_x64(self, tmpdir): 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' - x64_url = 'https://nodejs.org/download/release/v16.0.0/node-v16.0.0-darwin-x64.tar.gz' + 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): @@ -649,7 +656,10 @@ def test_install_node_wrapped_http_error_non_arm64(self, tmpdir): 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' + 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): @@ -681,7 +691,7 @@ def download_side_effect(url, src_dir, args): mock_download.assert_called_once() def test_install_node_wrapped_skips_download_if_exists(self, tmpdir): - """Test that download is skipped if node source directory exists""" + """Test that download is skipped if node source dir exists""" args = mock.Mock() args.node = '18.0.0' args.prebuilt = True @@ -694,9 +704,13 @@ def test_install_node_wrapped_skips_download_if_exists(self, tmpdir): 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='https://nodejs.org/download/release/v18.0.0/node-v18.0.0-linux-x64.tar.gz' + return_value=bin_url ), \ mock.patch.object( nodeenv, 'download_node_src' @@ -787,7 +801,7 @@ def test_install_node_wrapped_prebuilt_vs_source_urls(self, tmpdir): mock_bin_url.assert_not_called() def test_install_node_wrapped_arm64_fallback_both_fail(self, tmpdir): - """Test that both arm64 and x64 download failures raise exception""" + """Test that both arm64 and x64 failures raise exception""" args = mock.Mock() args.node = '16.0.0' args.prebuilt = True @@ -797,7 +811,10 @@ def test_install_node_wrapped_arm64_fallback_both_fail(self, tmpdir): 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' + 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): @@ -821,8 +838,10 @@ def download_side_effect(url, 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 that copy_node_from_prebuilt is not called after download failure""" + 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 @@ -832,7 +851,10 @@ def test_install_node_wrapped_no_copy_after_download_failure(self, tmpdir): 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' + 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): @@ -860,8 +882,10 @@ def download_side_effect(url, 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 that build_node_from_src is not called after download failure""" + 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 @@ -871,7 +895,10 @@ def test_install_node_wrapped_no_build_after_download_failure(self, tmpdir): 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' + 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): @@ -899,8 +926,10 @@ def download_side_effect(url, 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 that copy is not called when both arm64 and x64 downloads fail""" + 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 @@ -910,7 +939,10 @@ def test_install_node_wrapped_no_copy_after_arm64_fallback_failure(self, tmpdir) 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' + 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):