Skip to content

Commit 886ff68

Browse files
committed
Complete gitref support for transitive deps and npm lockfile v1.
1 parent 1c58197 commit 886ff68

File tree

10 files changed

+476
-73
lines changed

10 files changed

+476
-73
lines changed

node/flatpak_node_generator/providers/npm.py

Lines changed: 132 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
NamedTuple,
99
Optional,
1010
Set,
11+
Tuple,
1112
Type,
1213
)
1314

@@ -79,11 +80,17 @@ def _process_packages_v1(
7980
elif version_url.scheme == 'file':
8081
source = LocalSource(path=version_url.path)
8182
else:
82-
integrity = Integrity.parse(info['integrity'])
83+
integrity = None
84+
if 'integrity' in info:
85+
integrity = Integrity.parse(info['integrity'])
86+
8387
if 'resolved' in info:
84-
source = ResolvedSource(
85-
resolved=info['resolved'], integrity=integrity
86-
)
88+
if info['resolved'].startswith('git+'):
89+
source = self.parse_git_source(info['resolved'])
90+
else:
91+
source = ResolvedSource(
92+
resolved=info['resolved'], integrity=integrity
93+
)
8794
elif version_url.scheme in {'http', 'https'}:
8895
source = PackageURLSource(resolved=version, integrity=integrity)
8996
else:
@@ -127,9 +134,8 @@ def _process_packages_v2(
127134
elif resolved_url.scheme.startswith('git+'):
128135
source = self.parse_git_source(info['resolved'])
129136
else:
130-
raise NotImplementedError(
131-
f"Don't know how to handle package {install_path} in {lockfile}"
132-
)
137+
source = LocalSource(path=install_path)
138+
name = install_path
133139

134140
# NOTE We can't reliably determine the package name from the lockfile v2 syntax,
135141
# but we need it for registry queries and special source processing;
@@ -200,7 +206,7 @@ def __init__(
200206
self.all_lockfiles: Set[Path] = set()
201207
# Mapping of lockfiles to a dict of the Git source target paths and GitSource objects.
202208
self.git_sources: DefaultDict[
203-
Path, Dict[Path, (str, GitSource)]
209+
Path, Dict[Path, Tuple[str, GitSource]]
204210
] = collections.defaultdict(lambda: {})
205211
# FIXME better pass the same provider object we created in main
206212
self.rcfile_provider = NpmRCFileProvider()
@@ -364,6 +370,46 @@ async def generate_package(self, package: Package) -> None:
364370
self.git_sources[package.lockfile][path] = (package.name, source)
365371
self.gen.add_git_source(source.url, source.commit, path)
366372

373+
url = urllib.parse.urlparse(source.url)
374+
if url.netloc == '[email protected]' or url.netloc == 'github.com':
375+
url = url._replace(
376+
netloc='codeload.github.com', path=re.sub('.git$', '', url.path)
377+
)
378+
tarball_url = url._replace(
379+
path=re.sub('$', f'/tar.gz/{source.commit}', url.path)
380+
)
381+
index_url = tarball_url.geturl()
382+
elif url.netloc == '[email protected]' or url.netloc == 'gitlab.com':
383+
url = url._replace(
384+
netloc='gitlab.com', path=re.sub('.git$', '', url.path)
385+
)
386+
tarball_url = url._replace(
387+
path=re.sub(
388+
'$',
389+
f'/-/archive/{source.commit}/{package.name}-{source.commit}.tar.gz',
390+
url.path,
391+
)
392+
)
393+
index_url = url._replace(
394+
path=re.sub(
395+
'$', f'/repository/archive.tar.gz?ref={source.commit}', url.path
396+
)
397+
).geturl()
398+
metadata = await RemoteUrlMetadata.get(
399+
tarball_url.geturl(), cachable=True, integrity_algorithm='sha512'
400+
)
401+
402+
self.gen.add_url_source(
403+
url=tarball_url.geturl(),
404+
integrity=metadata.integrity,
405+
destination=self.get_cacache_content_path(metadata.integrity),
406+
)
407+
408+
self.add_index_entry(
409+
url=index_url,
410+
metadata=metadata,
411+
)
412+
367413
elif isinstance(source, LocalSource):
368414
pass
369415

@@ -417,61 +463,91 @@ def _finalize(self) -> None:
417463
)
418464

419465
if self.git_sources:
420-
# Generate jq script to patch the package.json file
421-
script = r"""
422-
walk(
423-
if type == "object"
424-
then
425-
to_entries | map(
426-
if (.key | type == "string") and $data[.key]
427-
then .value = "git+file://\($buildroot)/\($data[.key])"
428-
else .
429-
end
430-
) | from_entries
431-
else .
432-
end
433-
)
434-
"""
466+
# Generate jq scripts to patch the package*.json files.
467+
scripts = {
468+
'package.json': r"""
469+
walk(
470+
if type == "object"
471+
then
472+
to_entries | map(
473+
if (.key | type == "string") and $data[.key]
474+
then .value = "git+file://\($buildroot)/\($data[.key])"
475+
else .
476+
end
477+
) | from_entries
478+
else .
479+
end
480+
)
481+
""",
482+
'package-lock.json': r"""
483+
walk(
484+
if type == "object" and (.version | type == "string") and $data[.version]
485+
then
486+
.resolved = "git+file:\($buildroot)/\($data[.version])"
487+
else .
488+
end
489+
)
490+
""",
491+
}
435492

436493
for lockfile, sources in self.git_sources.items():
437494
prefix = self.relative_lockfile_dir(lockfile)
438-
data: Dict[str, str] = {}
439-
440-
for path, name_source in sources.items():
441-
name, source = name_source
442-
new_version = f'{path}#{source.commit}'
443-
data[name] = new_version
444-
445-
filename = 'package.json'
446-
target = Path('$FLATPAK_BUILDER_BUILDDIR') / prefix / filename
447-
script = textwrap.dedent(script.lstrip('\n')).strip().replace('\n', '')
448-
json_data = json.dumps(data)
449-
patch_commands[lockfile].append(
450-
'jq'
451-
' --arg buildroot "$FLATPAK_BUILDER_BUILDDIR"'
452-
f' --argjson data {shlex.quote(json_data)}'
453-
f' {shlex.quote(script)} {target}'
454-
f' > {target}.new'
455-
)
456-
patch_commands[lockfile].append(f'mv {target}{{.new,}}')
495+
data: Dict[str, Dict[str, str]] = {
496+
'package.json': {},
497+
'package-lock.json': {},
498+
}
499+
500+
with open(lockfile) as fp:
501+
lockfile_v1 = json.load(fp)['lockfileVersion'] == 1
502+
503+
if lockfile_v1:
504+
for path, name_source in sources.items():
505+
GIT_URL_PREFIX = 'git+'
506+
name, source = name_source
507+
new_version = f'{path}#{source.commit}'
508+
data['package.json'][name] = new_version
509+
data['package-lock.json'][source.original] = new_version
510+
511+
if source.original.startswith(GIT_URL_PREFIX):
512+
data['package-lock.json'][
513+
source.original[len(GIT_URL_PREFIX) :]
514+
] = new_version
515+
516+
for filename, script in scripts.items():
517+
target = Path('$FLATPAK_BUILDER_BUILDDIR') / prefix / filename
518+
script = (
519+
textwrap.dedent(script.lstrip('\n'))
520+
.strip()
521+
.replace('\n', '')
522+
)
523+
json_data = json.dumps(data[filename])
524+
patch_commands[lockfile].append(
525+
'jq'
526+
' --arg buildroot "$FLATPAK_BUILDER_BUILDDIR"'
527+
f' --argjson data {shlex.quote(json_data)}'
528+
f' {shlex.quote(script)} {target}'
529+
f' > {target}.new'
530+
)
531+
patch_commands[lockfile].append(f'mv {target}{{.new,}}')
457532

458-
patch_all_commands: List[str] = []
459-
for lockfile in self.all_lockfiles:
460-
patch_dest = (
461-
self.gen.data_root / 'patch' / self.relative_lockfile_dir(lockfile)
462-
)
463-
# Don't use with_extension to avoid problems if the package has a . in its name.
464-
patch_dest = patch_dest.with_name(patch_dest.name + '.sh')
533+
if len(patch_commands) > 0:
534+
patch_all_commands: List[str] = []
535+
for lockfile in self.all_lockfiles:
536+
patch_dest = (
537+
self.gen.data_root / 'patch' / self.relative_lockfile_dir(lockfile)
538+
)
539+
# Don't use with_extension to avoid problems if the package has a . in its name.
540+
patch_dest = patch_dest.with_name(patch_dest.name + '.sh')
465541

466-
self.gen.add_script_source(patch_commands[lockfile], patch_dest)
467-
patch_all_commands.append(f'$FLATPAK_BUILDER_BUILDDIR/{patch_dest}')
542+
self.gen.add_script_source(patch_commands[lockfile], patch_dest)
543+
patch_all_commands.append(f'$FLATPAK_BUILDER_BUILDDIR/{patch_dest}')
468544

469-
patch_all_dest = self.gen.data_root / 'patch-all.sh'
470-
self.gen.add_script_source(patch_all_commands, patch_all_dest)
545+
patch_all_dest = self.gen.data_root / 'patch-all.sh'
546+
self.gen.add_script_source(patch_all_commands, patch_all_dest)
471547

472-
if not self.no_autopatch:
473-
# FLATPAK_BUILDER_BUILDDIR isn't defined yet for script sources.
474-
self.gen.add_command(f'FLATPAK_BUILDER_BUILDDIR=$PWD {patch_all_dest}')
548+
if not self.no_autopatch:
549+
# FLATPAK_BUILDER_BUILDDIR isn't defined yet for script sources.
550+
self.gen.add_command(f'FLATPAK_BUILDER_BUILDDIR=$PWD {patch_all_dest}')
475551

476552
if self.index_entries:
477553
for path, entry in self.index_entries.items():

node/tests/data/packages/git/package-lock.v1.json

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,62 @@
44
"lockfileVersion": 1,
55
"requires": true,
66
"dependencies": {
7+
"@flatpak-node-generator-tests/subdir": {
8+
"version": "file:subdir",
9+
"requires": {
10+
"arr-diff": "github:jonschlinkert/arr-diff#f39e5f10f55fd0cc38fa686c6ebc11747815850c",
11+
"array.chunk": "git+https://github.com/zhiyelee/array.chunk.git",
12+
"decamelize": "git+https://github.com/sindresorhus/decamelize.git#da8552d335f9067354ca9b93378482eb9f1fb821",
13+
"filled-array": "github:sindresorhus/filled-array#v2.1.0",
14+
"in-array": "git+ssh://[email protected]/jonschlinkert/in-array.git",
15+
"sorted-object": "github:domenic/sorted-object",
16+
"text-encoding-shim": "gitlab:t-affeldt/text-encoding-shim",
17+
"unordered-array-remove": "git+ssh://[email protected]/mafintosh/unordered-array-remove.git#9ecfd7d63da6e5499b3a530574aca2d8c826af93"
18+
}
19+
},
20+
"arr-diff": {
21+
"version": "github:jonschlinkert/arr-diff#f39e5f10f55fd0cc38fa686c6ebc11747815850c",
22+
"from": "github:jonschlinkert/arr-diff#f39e5f10f55fd0cc38fa686c6ebc11747815850c"
23+
},
724
"array-range": {
8-
"version": "git+ssh://[email protected]/mattdesl/array-range.git#d8b6fbdfc29caf846be02229325dfb4967f1dcd6",
9-
"from": "array-range@github:mattdesl/array-range#master"
25+
"version": "github:mattdesl/array-range#d8b6fbdfc29caf846be02229325dfb4967f1dcd6",
26+
"from": "github:mattdesl/array-range#master"
27+
},
28+
"array.chunk": {
29+
"version": "git+https://github.com/zhiyelee/array.chunk.git#1ba8011a64448210e334a17642e395690a7164c0",
30+
"from": "git+https://github.com/zhiyelee/array.chunk.git"
31+
},
32+
"decamelize": {
33+
"version": "git+https://github.com/sindresorhus/decamelize.git#da8552d335f9067354ca9b93378482eb9f1fb821",
34+
"from": "git+https://github.com/sindresorhus/decamelize.git#da8552d335f9067354ca9b93378482eb9f1fb821"
35+
},
36+
"filled-array": {
37+
"version": "github:sindresorhus/filled-array#3529bc985247d0f84db4080fecd8276643838d0c",
38+
"from": "github:sindresorhus/filled-array#v2.1.0"
39+
},
40+
"in-array": {
41+
"version": "git+ssh://[email protected]/jonschlinkert/in-array.git#47a5e55362098646b56a3ec6775bd5198df1c7ed",
42+
"from": "git+ssh://[email protected]/jonschlinkert/in-array.git"
1043
},
1144
"is-empty-object": {
12-
"version": "git+ssh://git@github.com/gummesson/is-empty-object.git#7b50c8eb4e14135631f7c94e01c0c8a36e5d75f8",
13-
"from": "is-empty-object@github:gummesson/is-empty-object#7b50c8eb4e14135631f7c94e01c0c8a36e5d75f8"
45+
"version": "github:gummesson/is-empty-object#7b50c8eb4e14135631f7c94e01c0c8a36e5d75f8",
46+
"from": "github:gummesson/is-empty-object#7b50c8eb4e14135631f7c94e01c0c8a36e5d75f8"
1447
},
1548
"is-number": {
16-
"version": "git+ssh://git@github.com/jonschlinkert/is-number.git#98e8ff1da1a89f93d1397a24d7413ed15421c139",
17-
"from": "is-number@github:jonschlinkert/is-number"
49+
"version": "github:jonschlinkert/is-number#98e8ff1da1a89f93d1397a24d7413ed15421c139",
50+
"from": "github:jonschlinkert/is-number"
1851
},
1952
"person-lib": {
20-
"version": "git+ssh://[email protected]/volodymyrkr/person-lib.git#752fd1828b1eb3a9635bf725ae5e1704a375e524",
21-
"from": "person-lib@gitlab:volodymyrkr/person-lib"
53+
"version": "gitlab:volodymyrkr/person-lib#752fd1828b1eb3a9635bf725ae5e1704a375e524",
54+
"from": "gitlab:volodymyrkr/person-lib"
55+
},
56+
"sorted-object": {
57+
"version": "github:domenic/sorted-object#87105deb13d4f4151b2abd1a78d27a5216e3e79d",
58+
"from": "github:domenic/sorted-object"
59+
},
60+
"text-encoding-shim": {
61+
"version": "gitlab:t-affeldt/text-encoding-shim#33b05934b4e4e6c65fc06260eaa3b2aa2909e7b5",
62+
"from": "gitlab:t-affeldt/text-encoding-shim"
2263
},
2364
"to-camel-case": {
2465
"version": "git+ssh://[email protected]/ianstormtaylor/to-camel-case.git#00a20429b600ddb6e4f8ff5b17c52914f40fe67d",
@@ -35,15 +76,19 @@
3576
}
3677
},
3778
"to-no-case": {
38-
"version": "git+https://[email protected]/ianstormtaylor/to-no-case.git#9078578dcf394e63f34fd7c6666772192e537b90",
39-
"from": "git+https://[email protected]/ianstormtaylor/to-no-case.git#9078578dcf394e63f34fd7c6666772192e537b90"
79+
"version": "1.0.0",
80+
"resolved": "git+https://[email protected]/ianstormtaylor/to-no-case.git#9078578dcf394e63f34fd7c6666772192e537b90"
4081
},
4182
"to-space-case": {
42-
"version": "git+ssh://[email protected]/ianstormtaylor/to-space-case.git#aa68213d1211745ce7c6c725ba072e6b13bef640",
43-
"from": "git+ssh://[email protected]/ianstormtaylor/to-space-case.git#aa68213d1211745ce7c6c725ba072e6b13bef640",
83+
"version": "1.0.0",
84+
"resolved": "git+ssh://[email protected]/ianstormtaylor/to-space-case.git#aa68213d1211745ce7c6c725ba072e6b13bef640",
4485
"requires": {
4586
"to-no-case": "^1.0.0"
4687
}
88+
},
89+
"unordered-array-remove": {
90+
"version": "git+ssh://[email protected]/mafintosh/unordered-array-remove.git#9ecfd7d63da6e5499b3a530574aca2d8c826af93",
91+
"from": "git+ssh://[email protected]/mafintosh/unordered-array-remove.git#9ecfd7d63da6e5499b3a530574aca2d8c826af93"
4792
}
4893
}
4994
}

0 commit comments

Comments
 (0)