17db96d56Sopenharmony_ci"""distutils.archive_util 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciUtility functions for creating archive files (tarballs, zip files, 47db96d56Sopenharmony_cithat sort of thing).""" 57db96d56Sopenharmony_ci 67db96d56Sopenharmony_ciimport os 77db96d56Sopenharmony_cifrom warnings import warn 87db96d56Sopenharmony_ciimport sys 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_citry: 117db96d56Sopenharmony_ci import zipfile 127db96d56Sopenharmony_ciexcept ImportError: 137db96d56Sopenharmony_ci zipfile = None 147db96d56Sopenharmony_ci 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_cifrom distutils.errors import DistutilsExecError 177db96d56Sopenharmony_cifrom distutils.spawn import spawn 187db96d56Sopenharmony_cifrom distutils.dir_util import mkpath 197db96d56Sopenharmony_cifrom distutils import log 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_citry: 227db96d56Sopenharmony_ci from pwd import getpwnam 237db96d56Sopenharmony_ciexcept ImportError: 247db96d56Sopenharmony_ci getpwnam = None 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_citry: 277db96d56Sopenharmony_ci from grp import getgrnam 287db96d56Sopenharmony_ciexcept ImportError: 297db96d56Sopenharmony_ci getgrnam = None 307db96d56Sopenharmony_ci 317db96d56Sopenharmony_cidef _get_gid(name): 327db96d56Sopenharmony_ci """Returns a gid, given a group name.""" 337db96d56Sopenharmony_ci if getgrnam is None or name is None: 347db96d56Sopenharmony_ci return None 357db96d56Sopenharmony_ci try: 367db96d56Sopenharmony_ci result = getgrnam(name) 377db96d56Sopenharmony_ci except KeyError: 387db96d56Sopenharmony_ci result = None 397db96d56Sopenharmony_ci if result is not None: 407db96d56Sopenharmony_ci return result[2] 417db96d56Sopenharmony_ci return None 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_cidef _get_uid(name): 447db96d56Sopenharmony_ci """Returns an uid, given a user name.""" 457db96d56Sopenharmony_ci if getpwnam is None or name is None: 467db96d56Sopenharmony_ci return None 477db96d56Sopenharmony_ci try: 487db96d56Sopenharmony_ci result = getpwnam(name) 497db96d56Sopenharmony_ci except KeyError: 507db96d56Sopenharmony_ci result = None 517db96d56Sopenharmony_ci if result is not None: 527db96d56Sopenharmony_ci return result[2] 537db96d56Sopenharmony_ci return None 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_cidef make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, 567db96d56Sopenharmony_ci owner=None, group=None): 577db96d56Sopenharmony_ci """Create a (possibly compressed) tar file from all the files under 587db96d56Sopenharmony_ci 'base_dir'. 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci 'compress' must be "gzip" (the default), "bzip2", "xz", "compress", or 617db96d56Sopenharmony_ci None. ("compress" will be deprecated in Python 3.2) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci 'owner' and 'group' can be used to define an owner and a group for the 647db96d56Sopenharmony_ci archive that is being built. If not provided, the current owner and group 657db96d56Sopenharmony_ci will be used. 667db96d56Sopenharmony_ci 677db96d56Sopenharmony_ci The output tar file will be named 'base_dir' + ".tar", possibly plus 687db96d56Sopenharmony_ci the appropriate compression extension (".gz", ".bz2", ".xz" or ".Z"). 697db96d56Sopenharmony_ci 707db96d56Sopenharmony_ci Returns the output filename. 717db96d56Sopenharmony_ci """ 727db96d56Sopenharmony_ci tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', 'xz': 'xz', None: '', 737db96d56Sopenharmony_ci 'compress': ''} 747db96d56Sopenharmony_ci compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'xz': '.xz', 757db96d56Sopenharmony_ci 'compress': '.Z'} 767db96d56Sopenharmony_ci 777db96d56Sopenharmony_ci # flags for compression program, each element of list will be an argument 787db96d56Sopenharmony_ci if compress is not None and compress not in compress_ext.keys(): 797db96d56Sopenharmony_ci raise ValueError( 807db96d56Sopenharmony_ci "bad value for 'compress': must be None, 'gzip', 'bzip2', " 817db96d56Sopenharmony_ci "'xz' or 'compress'") 827db96d56Sopenharmony_ci 837db96d56Sopenharmony_ci archive_name = base_name + '.tar' 847db96d56Sopenharmony_ci if compress != 'compress': 857db96d56Sopenharmony_ci archive_name += compress_ext.get(compress, '') 867db96d56Sopenharmony_ci 877db96d56Sopenharmony_ci mkpath(os.path.dirname(archive_name), dry_run=dry_run) 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci # creating the tarball 907db96d56Sopenharmony_ci import tarfile # late import so Python build itself doesn't break 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci log.info('Creating tar archive') 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci uid = _get_uid(owner) 957db96d56Sopenharmony_ci gid = _get_gid(group) 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci def _set_uid_gid(tarinfo): 987db96d56Sopenharmony_ci if gid is not None: 997db96d56Sopenharmony_ci tarinfo.gid = gid 1007db96d56Sopenharmony_ci tarinfo.gname = group 1017db96d56Sopenharmony_ci if uid is not None: 1027db96d56Sopenharmony_ci tarinfo.uid = uid 1037db96d56Sopenharmony_ci tarinfo.uname = owner 1047db96d56Sopenharmony_ci return tarinfo 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci if not dry_run: 1077db96d56Sopenharmony_ci tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) 1087db96d56Sopenharmony_ci try: 1097db96d56Sopenharmony_ci tar.add(base_dir, filter=_set_uid_gid) 1107db96d56Sopenharmony_ci finally: 1117db96d56Sopenharmony_ci tar.close() 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci # compression using `compress` 1147db96d56Sopenharmony_ci if compress == 'compress': 1157db96d56Sopenharmony_ci warn("'compress' will be deprecated.", PendingDeprecationWarning) 1167db96d56Sopenharmony_ci # the option varies depending on the platform 1177db96d56Sopenharmony_ci compressed_name = archive_name + compress_ext[compress] 1187db96d56Sopenharmony_ci if sys.platform == 'win32': 1197db96d56Sopenharmony_ci cmd = [compress, archive_name, compressed_name] 1207db96d56Sopenharmony_ci else: 1217db96d56Sopenharmony_ci cmd = [compress, '-f', archive_name] 1227db96d56Sopenharmony_ci spawn(cmd, dry_run=dry_run) 1237db96d56Sopenharmony_ci return compressed_name 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci return archive_name 1267db96d56Sopenharmony_ci 1277db96d56Sopenharmony_cidef make_zipfile(base_name, base_dir, verbose=0, dry_run=0): 1287db96d56Sopenharmony_ci """Create a zip file from all the files under 'base_dir'. 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci The output zip file will be named 'base_name' + ".zip". Uses either the 1317db96d56Sopenharmony_ci "zipfile" Python module (if available) or the InfoZIP "zip" utility 1327db96d56Sopenharmony_ci (if installed and found on the default search path). If neither tool is 1337db96d56Sopenharmony_ci available, raises DistutilsExecError. Returns the name of the output zip 1347db96d56Sopenharmony_ci file. 1357db96d56Sopenharmony_ci """ 1367db96d56Sopenharmony_ci zip_filename = base_name + ".zip" 1377db96d56Sopenharmony_ci mkpath(os.path.dirname(zip_filename), dry_run=dry_run) 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci # If zipfile module is not available, try spawning an external 1407db96d56Sopenharmony_ci # 'zip' command. 1417db96d56Sopenharmony_ci if zipfile is None: 1427db96d56Sopenharmony_ci if verbose: 1437db96d56Sopenharmony_ci zipoptions = "-r" 1447db96d56Sopenharmony_ci else: 1457db96d56Sopenharmony_ci zipoptions = "-rq" 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci try: 1487db96d56Sopenharmony_ci spawn(["zip", zipoptions, zip_filename, base_dir], 1497db96d56Sopenharmony_ci dry_run=dry_run) 1507db96d56Sopenharmony_ci except DistutilsExecError: 1517db96d56Sopenharmony_ci # XXX really should distinguish between "couldn't find 1527db96d56Sopenharmony_ci # external 'zip' command" and "zip failed". 1537db96d56Sopenharmony_ci raise DistutilsExecError(("unable to create zip file '%s': " 1547db96d56Sopenharmony_ci "could neither import the 'zipfile' module nor " 1557db96d56Sopenharmony_ci "find a standalone zip utility") % zip_filename) 1567db96d56Sopenharmony_ci 1577db96d56Sopenharmony_ci else: 1587db96d56Sopenharmony_ci log.info("creating '%s' and adding '%s' to it", 1597db96d56Sopenharmony_ci zip_filename, base_dir) 1607db96d56Sopenharmony_ci 1617db96d56Sopenharmony_ci if not dry_run: 1627db96d56Sopenharmony_ci try: 1637db96d56Sopenharmony_ci zip = zipfile.ZipFile(zip_filename, "w", 1647db96d56Sopenharmony_ci compression=zipfile.ZIP_DEFLATED) 1657db96d56Sopenharmony_ci except RuntimeError: 1667db96d56Sopenharmony_ci zip = zipfile.ZipFile(zip_filename, "w", 1677db96d56Sopenharmony_ci compression=zipfile.ZIP_STORED) 1687db96d56Sopenharmony_ci 1697db96d56Sopenharmony_ci with zip: 1707db96d56Sopenharmony_ci if base_dir != os.curdir: 1717db96d56Sopenharmony_ci path = os.path.normpath(os.path.join(base_dir, '')) 1727db96d56Sopenharmony_ci zip.write(path, path) 1737db96d56Sopenharmony_ci log.info("adding '%s'", path) 1747db96d56Sopenharmony_ci for dirpath, dirnames, filenames in os.walk(base_dir): 1757db96d56Sopenharmony_ci for name in dirnames: 1767db96d56Sopenharmony_ci path = os.path.normpath(os.path.join(dirpath, name, '')) 1777db96d56Sopenharmony_ci zip.write(path, path) 1787db96d56Sopenharmony_ci log.info("adding '%s'", path) 1797db96d56Sopenharmony_ci for name in filenames: 1807db96d56Sopenharmony_ci path = os.path.normpath(os.path.join(dirpath, name)) 1817db96d56Sopenharmony_ci if os.path.isfile(path): 1827db96d56Sopenharmony_ci zip.write(path, path) 1837db96d56Sopenharmony_ci log.info("adding '%s'", path) 1847db96d56Sopenharmony_ci 1857db96d56Sopenharmony_ci return zip_filename 1867db96d56Sopenharmony_ci 1877db96d56Sopenharmony_ciARCHIVE_FORMATS = { 1887db96d56Sopenharmony_ci 'gztar': (make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 1897db96d56Sopenharmony_ci 'bztar': (make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), 1907db96d56Sopenharmony_ci 'xztar': (make_tarball, [('compress', 'xz')], "xz'ed tar-file"), 1917db96d56Sopenharmony_ci 'ztar': (make_tarball, [('compress', 'compress')], "compressed tar file"), 1927db96d56Sopenharmony_ci 'tar': (make_tarball, [('compress', None)], "uncompressed tar file"), 1937db96d56Sopenharmony_ci 'zip': (make_zipfile, [],"ZIP file") 1947db96d56Sopenharmony_ci } 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_cidef check_archive_formats(formats): 1977db96d56Sopenharmony_ci """Returns the first format from the 'format' list that is unknown. 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci If all formats are known, returns None 2007db96d56Sopenharmony_ci """ 2017db96d56Sopenharmony_ci for format in formats: 2027db96d56Sopenharmony_ci if format not in ARCHIVE_FORMATS: 2037db96d56Sopenharmony_ci return format 2047db96d56Sopenharmony_ci return None 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_cidef make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, 2077db96d56Sopenharmony_ci dry_run=0, owner=None, group=None): 2087db96d56Sopenharmony_ci """Create an archive file (eg. zip or tar). 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci 'base_name' is the name of the file to create, minus any format-specific 2117db96d56Sopenharmony_ci extension; 'format' is the archive format: one of "zip", "tar", "gztar", 2127db96d56Sopenharmony_ci "bztar", "xztar", or "ztar". 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_ci 'root_dir' is a directory that will be the root directory of the 2157db96d56Sopenharmony_ci archive; ie. we typically chdir into 'root_dir' before creating the 2167db96d56Sopenharmony_ci archive. 'base_dir' is the directory where we start archiving from; 2177db96d56Sopenharmony_ci ie. 'base_dir' will be the common prefix of all files and 2187db96d56Sopenharmony_ci directories in the archive. 'root_dir' and 'base_dir' both default 2197db96d56Sopenharmony_ci to the current directory. Returns the name of the archive file. 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci 'owner' and 'group' are used when creating a tar archive. By default, 2227db96d56Sopenharmony_ci uses the current owner and group. 2237db96d56Sopenharmony_ci """ 2247db96d56Sopenharmony_ci save_cwd = os.getcwd() 2257db96d56Sopenharmony_ci if root_dir is not None: 2267db96d56Sopenharmony_ci log.debug("changing into '%s'", root_dir) 2277db96d56Sopenharmony_ci base_name = os.path.abspath(base_name) 2287db96d56Sopenharmony_ci if not dry_run: 2297db96d56Sopenharmony_ci os.chdir(root_dir) 2307db96d56Sopenharmony_ci 2317db96d56Sopenharmony_ci if base_dir is None: 2327db96d56Sopenharmony_ci base_dir = os.curdir 2337db96d56Sopenharmony_ci 2347db96d56Sopenharmony_ci kwargs = {'dry_run': dry_run} 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_ci try: 2377db96d56Sopenharmony_ci format_info = ARCHIVE_FORMATS[format] 2387db96d56Sopenharmony_ci except KeyError: 2397db96d56Sopenharmony_ci raise ValueError("unknown archive format '%s'" % format) 2407db96d56Sopenharmony_ci 2417db96d56Sopenharmony_ci func = format_info[0] 2427db96d56Sopenharmony_ci for arg, val in format_info[1]: 2437db96d56Sopenharmony_ci kwargs[arg] = val 2447db96d56Sopenharmony_ci 2457db96d56Sopenharmony_ci if format != 'zip': 2467db96d56Sopenharmony_ci kwargs['owner'] = owner 2477db96d56Sopenharmony_ci kwargs['group'] = group 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci try: 2507db96d56Sopenharmony_ci filename = func(base_name, base_dir, **kwargs) 2517db96d56Sopenharmony_ci finally: 2527db96d56Sopenharmony_ci if root_dir is not None: 2537db96d56Sopenharmony_ci log.debug("changing back to '%s'", save_cwd) 2547db96d56Sopenharmony_ci os.chdir(save_cwd) 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci return filename 257