@@ -896,7 +896,7 @@ def _get_uid(name):
896896 return None
897897
898898def _make_tarball (base_name , base_dir , compress = "gzip" , verbose = 0 , dry_run = 0 ,
899- owner = None , group = None , logger = None ):
899+ owner = None , group = None , logger = None , root_dir = None ):
900900 """Create a (possibly compressed) tar file from all the files under
901901 'base_dir'.
902902
@@ -953,14 +953,20 @@ def _set_uid_gid(tarinfo):
953953
954954 if not dry_run :
955955 tar = tarfile .open (archive_name , 'w|%s' % tar_compression )
956+ arcname = base_dir
957+ if root_dir is not None :
958+ base_dir = os .path .join (root_dir , base_dir )
956959 try :
957- tar .add (base_dir , filter = _set_uid_gid )
960+ tar .add (base_dir , arcname , filter = _set_uid_gid )
958961 finally :
959962 tar .close ()
960963
964+ if root_dir is not None :
965+ archive_name = os .path .abspath (archive_name )
961966 return archive_name
962967
963- def _make_zipfile (base_name , base_dir , verbose = 0 , dry_run = 0 , logger = None ):
968+ def _make_zipfile (base_name , base_dir , verbose = 0 , dry_run = 0 ,
969+ logger = None , owner = None , group = None , root_dir = None ):
964970 """Create a zip file from all the files under 'base_dir'.
965971
966972 The output zip file will be named 'base_name' + ".zip". Returns the
@@ -984,42 +990,60 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None):
984990 if not dry_run :
985991 with zipfile .ZipFile (zip_filename , "w" ,
986992 compression = zipfile .ZIP_DEFLATED ) as zf :
987- path = os .path .normpath (base_dir )
988- if path != os .curdir :
989- zf .write (path , path )
993+ arcname = os .path .normpath (base_dir )
994+ if root_dir is not None :
995+ base_dir = os .path .join (root_dir , base_dir )
996+ base_dir = os .path .normpath (base_dir )
997+ if arcname != os .curdir :
998+ zf .write (base_dir , arcname )
990999 if logger is not None :
991- logger .info ("adding '%s'" , path )
1000+ logger .info ("adding '%s'" , base_dir )
9921001 for dirpath , dirnames , filenames in os .walk (base_dir ):
1002+ arcdirpath = dirpath
1003+ if root_dir is not None :
1004+ arcdirpath = os .path .relpath (arcdirpath , root_dir )
1005+ arcdirpath = os .path .normpath (arcdirpath )
9931006 for name in sorted (dirnames ):
994- path = os .path .normpath (os .path .join (dirpath , name ))
995- zf .write (path , path )
1007+ path = os .path .join (dirpath , name )
1008+ arcname = os .path .join (arcdirpath , name )
1009+ zf .write (path , arcname )
9961010 if logger is not None :
9971011 logger .info ("adding '%s'" , path )
9981012 for name in filenames :
999- path = os .path .normpath (os .path .join (dirpath , name ))
1013+ path = os .path .join (dirpath , name )
1014+ path = os .path .normpath (path )
10001015 if os .path .isfile (path ):
1001- zf .write (path , path )
1016+ arcname = os .path .join (arcdirpath , name )
1017+ zf .write (path , arcname )
10021018 if logger is not None :
10031019 logger .info ("adding '%s'" , path )
10041020
1021+ if root_dir is not None :
1022+ zip_filename = os .path .abspath (zip_filename )
10051023 return zip_filename
10061024
1025+ # Maps the name of the archive format to a tuple containing:
1026+ # * the archiving function
1027+ # * extra keyword arguments
1028+ # * description
1029+ # * does it support the root_dir argument?
10071030_ARCHIVE_FORMATS = {
1008- 'tar' : (_make_tarball , [('compress' , None )], "uncompressed tar file" ),
1031+ 'tar' : (_make_tarball , [('compress' , None )],
1032+ "uncompressed tar file" , True ),
10091033}
10101034
10111035if _ZLIB_SUPPORTED :
10121036 _ARCHIVE_FORMATS ['gztar' ] = (_make_tarball , [('compress' , 'gzip' )],
1013- "gzip'ed tar-file" )
1014- _ARCHIVE_FORMATS ['zip' ] = (_make_zipfile , [], "ZIP file" )
1037+ "gzip'ed tar-file" , True )
1038+ _ARCHIVE_FORMATS ['zip' ] = (_make_zipfile , [], "ZIP file" , True )
10151039
10161040if _BZ2_SUPPORTED :
10171041 _ARCHIVE_FORMATS ['bztar' ] = (_make_tarball , [('compress' , 'bzip2' )],
1018- "bzip2'ed tar-file" )
1042+ "bzip2'ed tar-file" , True )
10191043
10201044if _LZMA_SUPPORTED :
10211045 _ARCHIVE_FORMATS ['xztar' ] = (_make_tarball , [('compress' , 'xz' )],
1022- "xz'ed tar-file" )
1046+ "xz'ed tar-file" , True )
10231047
10241048def get_archive_formats ():
10251049 """Returns a list of supported formats for archiving and unarchiving.
@@ -1050,7 +1074,7 @@ def register_archive_format(name, function, extra_args=None, description=''):
10501074 if not isinstance (element , (tuple , list )) or len (element ) != 2 :
10511075 raise TypeError ('extra_args elements are : (arg_name, value)' )
10521076
1053- _ARCHIVE_FORMATS [name ] = (function , extra_args , description )
1077+ _ARCHIVE_FORMATS [name ] = (function , extra_args , description , False )
10541078
10551079def unregister_archive_format (name ):
10561080 del _ARCHIVE_FORMATS [name ]
@@ -1074,36 +1098,38 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0,
10741098 uses the current owner and group.
10751099 """
10761100 sys .audit ("shutil.make_archive" , base_name , format , root_dir , base_dir )
1077- save_cwd = os .getcwd ()
1078- if root_dir is not None :
1079- if logger is not None :
1080- logger .debug ("changing into '%s'" , root_dir )
1081- base_name = os .path .abspath (base_name )
1082- if not dry_run :
1083- os .chdir (root_dir )
1084-
1085- if base_dir is None :
1086- base_dir = os .curdir
1087-
1088- kwargs = {'dry_run' : dry_run , 'logger' : logger }
1089-
10901101 try :
10911102 format_info = _ARCHIVE_FORMATS [format ]
10921103 except KeyError :
10931104 raise ValueError ("unknown archive format '%s'" % format ) from None
10941105
1106+ kwargs = {'dry_run' : dry_run , 'logger' : logger ,
1107+ 'owner' : owner , 'group' : group }
1108+
10951109 func = format_info [0 ]
10961110 for arg , val in format_info [1 ]:
10971111 kwargs [arg ] = val
10981112
1099- if format != 'zip' :
1100- kwargs ['owner' ] = owner
1101- kwargs ['group' ] = group
1113+ if base_dir is None :
1114+ base_dir = os .curdir
1115+
1116+ support_root_dir = format_info [3 ]
1117+ save_cwd = None
1118+ if root_dir is not None :
1119+ if support_root_dir :
1120+ kwargs ['root_dir' ] = root_dir
1121+ else :
1122+ save_cwd = os .getcwd ()
1123+ if logger is not None :
1124+ logger .debug ("changing into '%s'" , root_dir )
1125+ base_name = os .path .abspath (base_name )
1126+ if not dry_run :
1127+ os .chdir (root_dir )
11021128
11031129 try :
11041130 filename = func (base_name , base_dir , ** kwargs )
11051131 finally :
1106- if root_dir is not None :
1132+ if save_cwd is not None :
11071133 if logger is not None :
11081134 logger .debug ("changing back to '%s'" , save_cwd )
11091135 os .chdir (save_cwd )
@@ -1216,6 +1242,11 @@ def _unpack_tarfile(filename, extract_dir):
12161242 finally :
12171243 tarobj .close ()
12181244
1245+ # Maps the name of the unpack format to a tuple containing:
1246+ # * extensions
1247+ # * the unpacking function
1248+ # * extra keyword arguments
1249+ # * description
12191250_UNPACK_FORMATS = {
12201251 'tar' : (['.tar' ], _unpack_tarfile , [], "uncompressed tar file" ),
12211252 'zip' : (['.zip' ], _unpack_zipfile , [], "ZIP file" ),
0 commit comments