66import pprint
77import subprocess
88import sys
9+ import re
10+ from urllib .request import Request , urlopen
11+ from urllib .error import HTTPError
12+ from collections import defaultdict
13+ import toml
14+ from contextlib import suppress
915
1016from .setup import Setup
1117from .generator_data import MissingReporter
@@ -256,6 +262,171 @@ def run(self, args):
256262 pprint .pprint (platforms .get_platform_override_keys (p ))
257263
258264
265+ class MavenParser :
266+
267+ after_archs = [
268+ "static" ,
269+ "debug" ,
270+ "staticdebug" ,
271+ ]
272+
273+ @classmethod
274+ def add_subparser (cls , parent_parser , subparsers ):
275+ parser = subparsers .add_parser (
276+ "parse-maven" ,
277+ help = "Find supported platforms from a pyproject.toml" ,
278+ parents = [parent_parser ],
279+ )
280+ parser .add_argument (
281+ "toml_link" , help = "Ex: pyproject.toml" ,
282+ )
283+ parser .add_argument (
284+ "-b" ,
285+ "--brute_force" ,
286+ action = "store_true" ,
287+ help = "Try known os and arch combinations instead of parsing html (needed for rev)" ,
288+ )
289+ return parser
290+
291+ def check_url_exists (self , file_url ):
292+ with suppress (Exception ):
293+ if urlopen (Request (file_url )).code == 200 :
294+ return True
295+ return False
296+
297+ def run (self , args ):
298+
299+ self .os_names = set ()
300+ self .arch_names = set ()
301+ for plat in platforms ._platforms .values ():
302+ self .os_names .add (plat .os )
303+ self .arch_names .add (plat .arch )
304+
305+ with open (args .toml_link ) as fp :
306+ config = toml .load (fp )["tool" ]["robotpy-build" ]
307+
308+ wrappers = {}
309+ if "wrappers" in config :
310+ wrappers = {
311+ k : v
312+ for (k , v ) in config ["wrappers" ].items ()
313+ if "maven_lib_download" in v
314+ }
315+
316+ static_libs = {}
317+ if "static_libs" in config :
318+ static_libs = {
319+ k : v
320+ for (k , v ) in config ["static_libs" ].items ()
321+ if "maven_lib_download" in v
322+ }
323+
324+ if wrappers == {} and static_libs == {}:
325+ print ("No maven_lib_downloads in pyproject.toml" )
326+ exit ()
327+
328+ for w_name , wrapper in {** wrappers , ** static_libs }.items ():
329+
330+ if "maven_lib_download" not in wrapper :
331+ continue
332+
333+ mvl = wrapper ["maven_lib_download" ]
334+
335+ repo_url = mvl ["repo_url" ]
336+ grp = mvl ["group_id" ].replace ("." , "/" )
337+ art = mvl ["artifact_id" ]
338+ ver = mvl ["version" ]
339+
340+ dir_url = f"{ repo_url } /{ grp } /{ art } /{ ver } /"
341+
342+ plats = defaultdict (set )
343+
344+ found_source = False
345+ source_name = None
346+
347+ if args .brute_force :
348+
349+ for os in self .os_names :
350+ for arch in self .arch_names :
351+ for after_arch in self .after_archs + ["" ]:
352+ classifier = os + arch + after_arch
353+ file_url = f"{ dir_url } { art } -{ ver } -{ classifier } .zip"
354+
355+ if self .check_url_exists (file_url ):
356+ plats [os ].add (arch )
357+
358+ if self .check_url_exists (f"{ dir_url } { art } -{ ver } -source.zip" ):
359+ found_source = True
360+ source_name = "source"
361+
362+ if self .check_url_exists (f"{ dir_url } { art } -{ ver } -sources.zip" ):
363+ found_source = True
364+ source_name = "sources"
365+
366+ else :
367+ try :
368+ html = str (urlopen (Request (dir_url )).read ())
369+ except HTTPError as e :
370+ if e .code != 404 :
371+ raise e
372+ else :
373+ print (
374+ "The repo url returned a 404 error. Try using the brute_force flag."
375+ )
376+ exit ()
377+
378+ found_source = False
379+ source_name = None
380+
381+ if "source.zip" in html :
382+ found_source = True
383+ source_name = "source"
384+
385+ if "sources.zip" in html :
386+ found_source = True
387+ source_name = "sources"
388+
389+ # matches = re.findall('\.zip">(.*?)\.zip</a>', html, re.I) # match on text
390+ matches = re .findall ('href="(.*?)">' , html , re .I ) # match on links
391+ matches = [
392+ m [:- 4 ] for m in matches if m [- 4 :] == ".zip"
393+ ] # match on zip files and remove extension
394+
395+ for m in matches :
396+ for os in self .os_names :
397+ idx = m .find (os )
398+
399+ if idx != - 1 :
400+ arch = m [idx + len (os ) :]
401+
402+ for after_arch in self .after_archs :
403+ arch = arch .replace (after_arch , "" )
404+
405+ plats [os ].add (arch )
406+ break
407+
408+ # Formatting
409+ print ()
410+ print (f"Wrapper / static_lib :: { w_name } " )
411+ print (f"Artifact ID :: { art } " )
412+ print ()
413+
414+ if found_source :
415+ print ("This repo appears to provide sources." )
416+ print ("The name of the source file is:" , source_name )
417+ print ()
418+
419+ plat_str = "supported_platforms = [\n "
420+ for os in plats :
421+ for arch in plats [os ]:
422+ plat_str += ' {{ os = "{}", arch = "{}" }},\n ' .format (
423+ os , arch
424+ )
425+ plat_str += "]"
426+
427+ print (plat_str )
428+
429+
259430def main ():
260431
261432 parser = argparse .ArgumentParser (prog = "robotpy-build" )
@@ -270,6 +441,7 @@ def main():
270441 ImportCreator ,
271442 LibraryRelinker ,
272443 PlatformInfo ,
444+ MavenParser ,
273445 ):
274446 cls .add_subparser (parent_parser , subparsers ).set_defaults (cls = cls )
275447
0 commit comments