@@ -480,12 +480,31 @@ def should_repack_archive(
480480 return True
481481
482482
483+ EXECUTABLE_SIGNATURES = [
484+ b"\xFE \xED \xFA \xCE " , # mach-o 32-bits big endian
485+ b"\xCE \xFA \xED \xFE " , # mach-o 32-bits little endian
486+ b"\xFE \xED \xFA \xCF " , # mach-o 64-bits big endian
487+ b"\xCF \xFA \xED \xFE " , # mach-o 64-bits little endian
488+ b"\xCA \xFE \xBA \xBE " , # mach-o FAT binary
489+ b"\x7F \x45 \x4C \x46 " , # Elf binary
490+ ]
491+
492+
483493def repack_archive (
484- orig : pathlib .Path , dest : pathlib .Path , strip_components = 0 , prefix = ""
494+ orig : pathlib .Path ,
495+ dest : pathlib .Path ,
496+ strip_components = 0 ,
497+ prefix = "" ,
498+ single_file = False ,
485499):
486500 assert orig != dest
487501 log (f"Repacking { orig } as { dest } " )
488- orig_typ , ifh = open_stream (orig )
502+ if single_file :
503+ ifh = io .BufferedReader (orig .open (mode = "rb" ))
504+ signature = ifh .peek (4 )[:4 ]
505+ orig_typ = "exec" if signature in EXECUTABLE_SIGNATURES else None
506+ else :
507+ orig_typ , ifh = open_stream (orig )
489508 typ = archive_type (dest )
490509 if not typ :
491510 raise Exception ("Archive type not supported for %s" % dest .name )
@@ -510,7 +529,20 @@ def repack_archive(
510529
511530 with rename_after_close (dest , "wb" ) as fh :
512531 ctx = ZstdCompressor ()
513- if orig_typ == "zip" :
532+ if single_file :
533+ with ctx .stream_writer (fh ) as compressor , tarfile .open (
534+ fileobj = compressor ,
535+ mode = "w:" ,
536+ ) as tar :
537+ tarinfo = tarfile .TarInfo ()
538+ tarinfo .name = filter (orig .name ) if filter else orig .name
539+ st = orig .stat ()
540+ tarinfo .size = st .st_size
541+ tarinfo .mtime = st .st_mtime
542+ tarinfo .mode = 0o0755 if orig_typ == "exec" else 0o0644
543+ tar .addfile (tarinfo , ifh )
544+
545+ elif orig_typ == "zip" :
514546 assert typ == "tar"
515547 zip = zipfile .ZipFile (ifh )
516548 # Convert the zip stream to a tar on the fly.
@@ -824,8 +856,12 @@ def command_static_url(args):
824856 if gpg_sig_url :
825857 gpg_verify_path (dl_dest , gpg_key , gpg_signature )
826858
827- if should_repack_archive (dl_dest , dest , args .strip_components , args .add_prefix ):
828- repack_archive (dl_dest , dest , args .strip_components , args .add_prefix )
859+ if args .single_file or should_repack_archive (
860+ dl_dest , dest , args .strip_components , args .add_prefix
861+ ):
862+ repack_archive (
863+ dl_dest , dest , args .strip_components , args .add_prefix , args .single_file
864+ )
829865 elif dl_dest != dest :
830866 log (f"Renaming { dl_dest } to { dest } " )
831867 dl_dest .rename (dest )
@@ -960,6 +996,11 @@ def main():
960996 dest = "headers" ,
961997 help = "Header to send as part of the request, can be passed " "multiple times" ,
962998 )
999+ url .add_argument (
1000+ "--single-file" ,
1001+ action = "store_true" ,
1002+ help = "The downloaded file is not an archive and should be put inside one" ,
1003+ )
9631004 url .add_argument ("url" , help = "URL to fetch" )
9641005 url .add_argument ("dest" , help = "Destination path" )
9651006
0 commit comments