@@ -71,7 +71,7 @@ def get_download_url(cls, purl):
7171 name = purl_data .name
7272 version = purl_data .version
7373 if not version :
74- raise Exception ("Version is requierd ." )
74+ raise Exception ("Version is required ." )
7575 qualifiers = purl_data .qualifiers or {}
7676
7777 if "system" in qualifiers :
@@ -130,28 +130,30 @@ def get_upstream_src_download_url(cls, purl):
130130 if shutil .which ("nix" ) is not None :
131131 have_nix = True
132132
133- namespace = purl_data .namespace
134- # We will only work with the official nixpkgs repository, at least
135- # for now.
136- if not namespace or namespace .lower () != "nixpkgs" :
137- raise Exception (
138- "Only official nixpkgs repository is supported (i.e. namespace=nixpkgs)."
139- )
140133 name = purl_data .name
134+ namespace = purl_data .namespace
141135 version = purl_data .version
136+ qualifiers = purl_data .qualifiers or {}
137+ commit_hash = qualifiers .get ("commit" , "" )
138+ flakeref = qualifiers .get ("flakeref" , "" )
139+
142140 if not version :
143141 raise Exception ("Version is requierd." )
144- data = cls .get_package_data (purl )
142+
143+ if namespace != "nixpkgs" and not flakeref :
144+ raise Exception (
145+ "Only official nixpkgs repository is supported, "
146+ "or please provide the flakeref qualifier."
147+ )
148+ data = cls .get_package_data (purl ) if not flakeref else None
145149
146150 if data :
147151 download_url = construct_url_based_on_homepage_url (purl_data , data )
148152
149153 if not download_url and have_nix :
150- download_url = retrieve_src_download_url_with_nix (name , version )
151- if not download_url and data and version :
154+ if not commit_hash and data :
152155 commit_hash = get_commit_hash (data , version )
153- if commit_hash :
154- download_url = retrieve_src_download_url_with_nix (name , version , commit_hash )
156+ download_url = retrieve_src_download_url_with_nix (name , version , commit_hash , flakeref )
155157
156158 if not download_url and not have_nix :
157159 print ("Install `nix` and re-run to let `nix` determine the download URL." )
@@ -208,11 +210,11 @@ def get_nix_store_path_with_nix(name, system, output, commit_hash):
208210 return None
209211
210212
211- def retrieve_src_download_url_with_nix (name , version = None , commit_hash = None ):
213+ def retrieve_src_download_url_with_nix (name , version , commit_hash = None , flakeref = None ):
212214 """
213215 Find and return the source download url using 'nix'
214216 """
215- info = get_src_info (name , commit_hash )
217+ info = get_src_info (name , version , commit_hash , flakeref )
216218 urls = info .get ("urls" , [])
217219
218220 download_url = None
@@ -260,14 +262,35 @@ def retrieve_src_download_url_with_nix(name, version=None, commit_hash=None):
260262 return download_url
261263
262264
263- def get_src_info (attr_path , commit_hash = None ):
265+ def get_src_info (attr_path , version , commit_hash = None , flakeref = None ):
264266 """
265267 Use the `nix-instantiate` command together with the nix_expression to
266268 retrieve the package’s version and download URL. Return a dictionary
267269 with "version" and "urls" keys.
268270 """
269271 config_str = "config = { allowBroken = true; allowUnfree = true; };"
270272
273+ if flakeref :
274+ if not flakeref .startswith ("github" ):
275+ print ("Only flakeref for github is supported at the moment." )
276+ return {"version" : None , "urls" : []}
277+
278+ rest = flakeref .partition (":" )[2 ]
279+ parts = rest .split ("/" )
280+ if len (parts ) < 2 :
281+ return {"version" : None , "urls" : []}
282+ owner , repo = parts [0 ], parts [1 ]
283+ git_repo = f"https://github.com/{ owner } /{ repo } .git"
284+
285+ version_tag = version
286+ if not commit_hash :
287+ commit_hash , version_tag = get_flakeref_version_commit_hash (git_repo , version )
288+ if commit_hash and version_tag :
289+ url = f"https://github.com/{ owner } /{ repo } /archive/{ commit_hash } .tar.gz"
290+ return {"version" : version_tag , "urls" : [url ]}
291+ else :
292+ return {"version" : None , "urls" : []}
293+
271294 # Determine the repository entry point definition
272295 if commit_hash :
273296 nixpkgs_import = (
@@ -308,6 +331,44 @@ def get_src_info(attr_path, commit_hash=None):
308331 return {"version" : None , "urls" : []}
309332
310333
334+ def get_flakeref_version_commit_hash (git_repo , version ):
335+ """
336+ Get the commit hash from the given version.
337+ """
338+ if shutil .which ("git" ) is None :
339+ return None , None
340+ cmd = [
341+ "git" ,
342+ "ls-remote" ,
343+ "--tags" ,
344+ git_repo ,
345+ ]
346+ try :
347+ result = subprocess .run (cmd , capture_output = True , text = True , check = True , timeout = 300 )
348+ except (subprocess .CalledProcessError , subprocess .TimeoutExpired ) as e :
349+ print (f"Error running git ls-remote for { git_repo } : { e } " , file = sys .stderr )
350+ return None , None
351+
352+ potential_version_matches = [
353+ version ,
354+ f"v{ version } " ,
355+ f"V{ version } " ,
356+ f"v-{ version } " ,
357+ f"V-{ version } " ,
358+ f"release-{ version } " ,
359+ f"RELEASE-{ version } " ,
360+ ]
361+ for line in result .stdout .splitlines ():
362+ parts = line .split ("\t " )
363+ remote_hash = parts [0 ]
364+ reference_tag = parts [1 ]
365+ version_tag = reference_tag .replace ("refs/tags/" , "" ).replace ("^{}" , "" )
366+
367+ if version_tag in potential_version_matches :
368+ return remote_hash , version_tag
369+ return None , None
370+
371+
311372def construct_url_based_on_homepage_url (input_purl , data ):
312373 """
313374 Determine and return the download url based on the homepage and
0 commit comments