2525from ..package import (
2626 GitSource ,
2727 LocalSource ,
28+ Lockfile ,
29+ NamedGitSource ,
2830 Package ,
2931 PackageSource ,
3032 PackageURLSource ,
@@ -52,7 +54,7 @@ def __init__(self, options: Options):
5254 self .no_devel = options .no_devel
5355
5456 def _process_packages_v1 (
55- self , lockfile : Path , entry : Dict [str , Dict [Any , Any ]]
57+ self , lockfile : Lockfile , entry : Dict [str , Dict [Any , Any ]]
5658 ) -> Iterator [Package ]:
5759 for pkgname , info in entry .get ('dependencies' , {}).items ():
5860 if info .get ('dev' ) and self .no_devel :
@@ -81,23 +83,33 @@ def _process_packages_v1(
8183 elif version_url .scheme == 'file' :
8284 source = LocalSource (path = version_url .path )
8385 else :
84- integrity = Integrity .parse (info ['integrity' ])
86+ integrity = None
87+ if 'integrity' in info :
88+ integrity = Integrity .parse (info ['integrity' ])
89+
8590 if 'resolved' in info :
86- source = ResolvedSource (
87- resolved = info ['resolved' ], integrity = integrity
88- )
91+ resolved = info ['resolved' ]
92+ if resolved .startswith ('git+' ):
93+ source = self .parse_git_source (resolved )
94+ else :
95+ source = ResolvedSource (resolved = resolved , integrity = integrity )
8996 elif version_url .scheme in {'http' , 'https' }:
9097 source = PackageURLSource (resolved = version , integrity = integrity )
9198 else :
9299 source = RegistrySource (integrity = integrity )
93100
94- yield Package (name = name , version = version , source = source , lockfile = lockfile )
101+ yield Package (
102+ name = name ,
103+ version = version ,
104+ source = source ,
105+ lockfile = lockfile ,
106+ )
95107
96108 if 'dependencies' in info :
97109 yield from self ._process_packages_v1 (lockfile , info )
98110
99111 def _process_packages_v2 (
100- self , lockfile : Path , entry : Dict [str , Dict [Any , Any ]]
112+ self , lockfile : Lockfile , entry : Dict [str , Dict [Any , Any ]]
101113 ) -> Iterator [Package ]:
102114 for install_path , info in entry .get ('packages' , {}).items ():
103115 if (info .get ('dev' ) or info .get ('devOptional' )) and self .no_devel :
@@ -127,14 +139,10 @@ def _process_packages_v2(
127139 integrity = integrity , resolved = info ['resolved' ]
128140 )
129141 elif resolved_url .scheme .startswith ('git+' ):
130- raise NotImplementedError (
131- 'Git sources in lockfile v2 format are not supported yet'
132- f' (package { install_path } in { lockfile } )'
133- )
142+ source = self .parse_git_source (info ['resolved' ])
134143 else :
135- raise NotImplementedError (
136- f"Don't know how to handle package { install_path } in { lockfile } "
137- )
144+ source = LocalSource (path = install_path )
145+ name = install_path
138146
139147 # NOTE We can't reliably determine the package name from the lockfile v2 syntax,
140148 # but we need it for registry queries and special source processing;
@@ -151,20 +159,20 @@ def _process_packages_v2(
151159 source = source ,
152160 )
153161
154- def process_lockfile (self , lockfile : Path ) -> Iterator [Package ]:
155- with open (lockfile , encoding = 'utf-8' ) as fp :
162+ def process_lockfile (self , lockfile_path : Path ) -> Iterator [Package ]:
163+ with open (lockfile_path , encoding = 'utf-8' ) as fp :
156164 data = json .load (fp )
157165
166+ lockfile = Lockfile (lockfile_path , data ['lockfileVersion' ])
167+
158168 # TODO Once lockfile v2 syntax support is complete, use _process_packages_v2
159169 # for both v2 and v2 lockfiles
160- if data [ 'lockfileVersion' ] in {1 , 2 }:
170+ if lockfile . version in {1 , 2 }:
161171 yield from self ._process_packages_v1 (lockfile , data )
162- elif data [ 'lockfileVersion' ] in {3 }:
172+ elif lockfile . version in {3 }:
163173 yield from self ._process_packages_v2 (lockfile , data )
164174 else :
165- raise NotImplementedError (
166- f'Unknown lockfile version { data ["lockfileVersion" ]} '
167- )
175+ raise NotImplementedError (f'Unknown lockfile version { lockfile .version } ' )
168176
169177
170178class NpmRCFileProvider (RCFileProvider ):
@@ -202,9 +210,10 @@ def __init__(
202210 str , asyncio .Future [NpmModuleProvider .RegistryPackageIndex ]
203211 ] = {}
204212 self .index_entries : Dict [Path , str ] = {}
205- self .all_lockfiles : Set [Path ] = set ()
206- # Mapping of lockfiles to a dict of the Git source target paths and GitSource objects.
207- self .git_sources : DefaultDict [Path , Dict [Path , GitSource ]] = (
213+ self .all_lockfiles : Set [Lockfile ] = set ()
214+ # Mapping of lockfiles to a dict of the Git source target paths and
215+ # NamedGitSource objects (package name + GitSource)
216+ self .git_sources : DefaultDict [Lockfile , Dict [Path , NamedGitSource ]] = (
208217 collections .defaultdict (lambda : {})
209218 )
210219 # FIXME better pass the same provider object we created in main
@@ -369,9 +378,54 @@ async def generate_package(self, package: Package) -> None:
369378 # Get a unique name to use for the Git repository folder.
370379 name = f'{ package .name } -{ source .commit } '
371380 path = self .gen .data_root / 'git-packages' / name
372- self .git_sources [package .lockfile ][path ] = source
381+ self .git_sources [package .lockfile ][path ] = NamedGitSource (
382+ package .name , source
383+ )
373384 self .gen .add_git_source (source .url , source .commit , path )
374385
386+ git_suffix = re .compile (r'\.git$' )
387+ url = urllib .parse .urlparse (source .url )
388+
389+ if url .hostname == 'github.com' :
390+ url = url ._replace (
391+ netloc = 'codeload.github.com' ,
392+ path = git_suffix .sub ('' , url .path ),
393+ )
394+ tarball_url = url ._replace (path = url .path + f'/tar.gz/{ source .commit } ' )
395+ index_url = tarball_url .geturl ()
396+ elif url .hostname == 'gitlab.com' :
397+ url = url ._replace (
398+ netloc = 'gitlab.com' , path = git_suffix .sub ('' , url .path )
399+ )
400+ tarball_url = url ._replace (
401+ path = url .path
402+ + f'/-/archive/{ source .commit } /{ package .name } -{ source .commit } .tar.gz'
403+ )
404+ index_url = url ._replace (
405+ path = url .path + f'/repository/archive.tar.gz?ref={ source .commit } '
406+ ).geturl ()
407+ else :
408+ raise NotImplementedError (
409+ f"Don't know how to handle git source with url { url .geturl ()} "
410+ )
411+
412+ metadata = await RemoteUrlMetadata .get (
413+ tarball_url .geturl (),
414+ cachable = True ,
415+ integrity_algorithm = 'sha512' ,
416+ )
417+
418+ self .gen .add_url_source (
419+ url = tarball_url .geturl (),
420+ integrity = metadata .integrity ,
421+ destination = self .get_cacache_content_path (metadata .integrity ),
422+ )
423+
424+ self .add_index_entry (
425+ url = index_url ,
426+ metadata = metadata ,
427+ )
428+
375429 elif isinstance (source , LocalSource ):
376430 pass
377431
@@ -393,7 +447,7 @@ def get_lockfile_rc(self, lockfile: Path) -> Dict[str, str]:
393447
394448 def get_package_registry (self , package : Package ) -> str :
395449 assert isinstance (package .source , RegistrySource )
396- rc = self .get_lockfile_rc (package .lockfile )
450+ rc = self .get_lockfile_rc (package .lockfile . path )
397451 if rc and '/' in package .name :
398452 scope , _ = package .name .split ('/' , maxsplit = 1 )
399453 if f'{ scope } :registry' in rc :
@@ -432,8 +486,8 @@ def _finalize(self) -> None:
432486 if type == "object"
433487 then
434488 to_entries | map(
435- if (.value | type == "string") and $data[.value ]
436- then .value = "git+file:\($buildroot)/\($data[.value ])"
489+ if (.key | type == "string") and $data[.key ]
490+ then .value = "git+file:// \($buildroot)/\($data[.key ])"
437491 else .
438492 end
439493 ) | from_entries
@@ -445,70 +499,79 @@ def _finalize(self) -> None:
445499 walk(
446500 if type == "object" and (.version | type == "string") and $data[.version]
447501 then
448- .version = "git+file:\($buildroot)/\($data[.version])"
502+ .resolved = "git+file:\($buildroot)/\($data[.version])"
449503 else .
450504 end
451505 )
452506 """ ,
453507 }
454508
455509 for lockfile , sources in self .git_sources .items ():
456- prefix = self .relative_lockfile_dir (lockfile )
510+ prefix = self .relative_lockfile_dir (lockfile . path )
457511 data : Dict [str , Dict [str , str ]] = {
458512 'package.json' : {},
459513 'package-lock.json' : {},
460514 }
461515
462- for path , source in sources .items ():
463- GIT_URL_PREFIX = 'git+'
464-
465- new_version = f'{ path } #{ source .commit } '
466- assert source .from_ is not None
467- data ['package.json' ][source .from_ ] = new_version
468- data ['package-lock.json' ][source .original ] = new_version
469-
470- if source .from_ .startswith (GIT_URL_PREFIX ):
471- data ['package.json' ][source .from_ [len (GIT_URL_PREFIX ) :]] = (
516+ if lockfile .version == 1 :
517+ for path , named_git_source in sources .items ():
518+ GIT_URL_PREFIX = 'git+'
519+ new_version = f'{ path } #{ named_git_source .git_source .commit } '
520+ data ['package.json' ][named_git_source .package_name ] = (
472521 new_version
473522 )
474-
475- if source .original .startswith (GIT_URL_PREFIX ):
476523 data ['package-lock.json' ][
477- source . original [ len ( GIT_URL_PREFIX ) :]
524+ named_git_source . git_source . original
478525 ] = new_version
479526
480- for filename , script in scripts .items ():
481- target = Path ('$FLATPAK_BUILDER_BUILDDIR' ) / prefix / filename
482- processed_script = (
483- textwrap .dedent (script .lstrip ('\n ' )).strip ().replace ('\n ' , '' )
484- )
485- json_data = json .dumps (data [filename ])
486- patch_commands [lockfile ].append (
487- 'jq'
488- ' --arg buildroot "$FLATPAK_BUILDER_BUILDDIR"'
489- f' --argjson data { shlex .quote (json_data )} '
490- f' { shlex .quote (processed_script )} { target } '
491- f' > { target } .new'
492- )
493- patch_commands [lockfile ].append (f'mv { target } {{.new,}}' )
494-
495- patch_all_commands : List [str ] = []
496- for lockfile in self .all_lockfiles :
497- patch_dest = (
498- self .gen .data_root / 'patch' / self .relative_lockfile_dir (lockfile )
499- )
500- # Don't use with_extension to avoid problems if the package has a . in its name.
501- patch_dest = patch_dest .with_name (patch_dest .name + '.sh' )
527+ if named_git_source .git_source .original .startswith (
528+ GIT_URL_PREFIX
529+ ):
530+ data ['package-lock.json' ][
531+ named_git_source .git_source .original [
532+ len (GIT_URL_PREFIX ) :
533+ ]
534+ ] = new_version
535+
536+ for filename , script in scripts .items ():
537+ target = Path ('$FLATPAK_BUILDER_BUILDDIR' ) / prefix / filename
538+ minified_script = (
539+ textwrap .dedent (script .lstrip ('\n ' ))
540+ .strip ()
541+ .replace ('\n ' , '' )
542+ )
543+ json_data = json .dumps (data [filename ])
544+ patch_commands [lockfile .path ].append (
545+ 'jq'
546+ ' --arg buildroot "$FLATPAK_BUILDER_BUILDDIR"'
547+ f' --argjson data { shlex .quote (json_data )} '
548+ f' { shlex .quote (minified_script )} { target } '
549+ f' > { target } .new'
550+ )
551+ patch_commands [lockfile .path ].append (f'mv { target } {{.new,}}' )
552+
553+ if len (patch_commands ) > 0 :
554+ patch_all_commands : List [str ] = []
555+ for lockfile in self .all_lockfiles :
556+ patch_dest = (
557+ self .gen .data_root
558+ / 'patch'
559+ / self .relative_lockfile_dir (lockfile .path )
560+ )
561+ # Don't use with_extension to avoid problems if the package has a . in its name.
562+ patch_dest = patch_dest .with_name (patch_dest .name + '.sh' )
502563
503- self .gen .add_script_source (patch_commands [lockfile ], patch_dest )
504- patch_all_commands .append (f'"$FLATPAK_BUILDER_BUILDDIR"/{ patch_dest } ' )
564+ self .gen .add_script_source (patch_commands [lockfile . path ], patch_dest )
565+ patch_all_commands .append (f'"$FLATPAK_BUILDER_BUILDDIR"/{ patch_dest } ' )
505566
506- patch_all_dest = self .gen .data_root / 'patch-all.sh'
507- self .gen .add_script_source (patch_all_commands , patch_all_dest )
567+ patch_all_dest = self .gen .data_root / 'patch-all.sh'
568+ self .gen .add_script_source (patch_all_commands , patch_all_dest )
508569
509- if not self .no_autopatch :
510- # FLATPAK_BUILDER_BUILDDIR isn't defined yet for script sources.
511- self .gen .add_command (f'FLATPAK_BUILDER_BUILDDIR="$PWD" { patch_all_dest } ' )
570+ if not self .no_autopatch :
571+ # FLATPAK_BUILDER_BUILDDIR isn't defined yet for script sources.
572+ self .gen .add_command (
573+ f'FLATPAK_BUILDER_BUILDDIR="$PWD" { patch_all_dest } '
574+ )
512575
513576 if self .index_entries :
514577 for path , entry in self .index_entries .items ():
0 commit comments