Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Nodeenv changelog
Version [unreleased]
--------------------

- `--prebuilt` installs no longer fail when the environment path or the
node.js version contains `[`, `*` or `?`
`#441 <https://github.com/ekalinin/nodeenv/issues/441>`_
- On Windows, Cygwin and MSYS the node.js zip archive is extracted 32 files
at a time instead of one by one, so a security scanner that checks every
new file no longer makes the install wait for each file in turn.
Expand Down
6 changes: 3 additions & 3 deletions nodeenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,9 +1070,9 @@ def copy_node_from_prebuilt(env_dir, src_dir, node_version):
else:
dest = env_dir

src_folder_tpl = src_dir + '/node-v%s-*' % node_version
src_folder, = glob.glob(src_folder_tpl)
copytree(src_folder, dest, True)
src_folder_tpl = glob.escape('node-v%s-' % node_version) + '*'
src_folder, = glob.glob(src_folder_tpl, root_dir=src_dir)
copytree(join(src_dir, src_folder), dest, True)

if is_CYGWIN:
for filename in ('npm', 'npx', 'node.exe'):
Expand Down
52 changes: 52 additions & 0 deletions tests/nodeenv_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,58 @@ def test_copytree_keeps_existing_symlink(tmpdir):
assert os.readlink(tmpdir.join('dst', 'bin', 'npm').strpath) == target


@pytest.mark.parametrize(
'dirname',
(
'proj[1]',
pytest.param('proj*', marks=pytest.mark.skipif(
nodeenv.is_WIN, reason='* is not a valid Windows filename')),
pytest.param('proj?', marks=pytest.mark.skipif(
nodeenv.is_WIN, reason='? is not a valid Windows filename')),
),
)
def test_copy_node_from_prebuilt_literal_path(tmpdir, monkeypatch, dirname):
monkeypatch.setattr(nodeenv, 'is_WIN', False)
monkeypatch.setattr(nodeenv, 'is_CYGWIN', False)
env_dir = tmpdir.join(dirname, 'env').ensure(dir=True)
src_dir = env_dir.join('src').ensure(dir=True)
archive = 'node-v18.0.0-test-platform'
source = src_dir.join(archive, 'bin', 'node').ensure()
source.write('literal source')
env_dir.join('keep.txt').write('keep this file')
decoy = tmpdir.join('proj1', 'env', 'src', archive, 'bin', 'node').ensure()
decoy.write('neighbor source')

nodeenv.copy_node_from_prebuilt(env_dir.strpath, src_dir.strpath, '18.0.0')

assert env_dir.join('bin', 'node').read() == 'literal source'
assert env_dir.join('keep.txt').read() == 'keep this file'
assert source.read() == 'literal source'
assert decoy.read() == 'neighbor source'


def test_copy_node_from_prebuilt_literal_version(tmp_path, monkeypatch):
monkeypatch.setattr(nodeenv, 'is_WIN', False)
monkeypatch.setattr(nodeenv, 'is_CYGWIN', False)
version = '18.0.0+build[1]'
env_dir = tmp_path / 'env'
env_dir.mkdir()
src_dir = tmp_path / 'src'
archive = src_dir / ('node-v%s-linux-x64' % version)
neighbor = src_dir / 'node-v18.0.0+build1-linux-x64'
for directory, contents in (
(archive, 'literal version'),
(neighbor, 'neighbor version')):
directory.mkdir(parents=True)
(directory / 'payload').write_text(contents, encoding='utf-8')

nodeenv.copy_node_from_prebuilt(str(env_dir), str(src_dir), version)

assert (env_dir / 'payload').read_text() == 'literal version'
assert (archive / 'payload').read_text() == 'literal version'
assert (neighbor / 'payload').read_text() == 'neighbor version'


def test_parse_version():
assert nodeenv.parse_version("v21.7") == (21, 7)
assert nodeenv.parse_version("v21.7.3") == (21, 7, 3)
Expand Down
Loading