17db96d56Sopenharmony_ci"""distutils.command.sdist 27db96d56Sopenharmony_ci 37db96d56Sopenharmony_ciImplements the Distutils 'sdist' command (create a source distribution).""" 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ciimport os 67db96d56Sopenharmony_ciimport sys 77db96d56Sopenharmony_cifrom glob import glob 87db96d56Sopenharmony_cifrom warnings import warn 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_cifrom distutils.core import Command 117db96d56Sopenharmony_cifrom distutils import dir_util 127db96d56Sopenharmony_cifrom distutils import file_util 137db96d56Sopenharmony_cifrom distutils import archive_util 147db96d56Sopenharmony_cifrom distutils.text_file import TextFile 157db96d56Sopenharmony_cifrom distutils.filelist import FileList 167db96d56Sopenharmony_cifrom distutils import log 177db96d56Sopenharmony_cifrom distutils.util import convert_path 187db96d56Sopenharmony_cifrom distutils.errors import DistutilsTemplateError, DistutilsOptionError 197db96d56Sopenharmony_ci 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_cidef show_formats(): 227db96d56Sopenharmony_ci """Print all possible values for the 'formats' option (used by 237db96d56Sopenharmony_ci the "--help-formats" command-line option). 247db96d56Sopenharmony_ci """ 257db96d56Sopenharmony_ci from distutils.fancy_getopt import FancyGetopt 267db96d56Sopenharmony_ci from distutils.archive_util import ARCHIVE_FORMATS 277db96d56Sopenharmony_ci formats = [] 287db96d56Sopenharmony_ci for format in ARCHIVE_FORMATS.keys(): 297db96d56Sopenharmony_ci formats.append(("formats=" + format, None, 307db96d56Sopenharmony_ci ARCHIVE_FORMATS[format][2])) 317db96d56Sopenharmony_ci formats.sort() 327db96d56Sopenharmony_ci FancyGetopt(formats).print_help( 337db96d56Sopenharmony_ci "List of available source distribution formats:") 347db96d56Sopenharmony_ci 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ciclass sdist(Command): 377db96d56Sopenharmony_ci 387db96d56Sopenharmony_ci description = "create a source distribution (tarball, zip file, etc.)" 397db96d56Sopenharmony_ci 407db96d56Sopenharmony_ci def checking_metadata(self): 417db96d56Sopenharmony_ci """Callable used for the check sub-command. 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci Placed here so user_options can view it""" 447db96d56Sopenharmony_ci return self.metadata_check 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci user_options = [ 477db96d56Sopenharmony_ci ('template=', 't', 487db96d56Sopenharmony_ci "name of manifest template file [default: MANIFEST.in]"), 497db96d56Sopenharmony_ci ('manifest=', 'm', 507db96d56Sopenharmony_ci "name of manifest file [default: MANIFEST]"), 517db96d56Sopenharmony_ci ('use-defaults', None, 527db96d56Sopenharmony_ci "include the default file set in the manifest " 537db96d56Sopenharmony_ci "[default; disable with --no-defaults]"), 547db96d56Sopenharmony_ci ('no-defaults', None, 557db96d56Sopenharmony_ci "don't include the default file set"), 567db96d56Sopenharmony_ci ('prune', None, 577db96d56Sopenharmony_ci "specifically exclude files/directories that should not be " 587db96d56Sopenharmony_ci "distributed (build tree, RCS/CVS dirs, etc.) " 597db96d56Sopenharmony_ci "[default; disable with --no-prune]"), 607db96d56Sopenharmony_ci ('no-prune', None, 617db96d56Sopenharmony_ci "don't automatically exclude anything"), 627db96d56Sopenharmony_ci ('manifest-only', 'o', 637db96d56Sopenharmony_ci "just regenerate the manifest and then stop " 647db96d56Sopenharmony_ci "(implies --force-manifest)"), 657db96d56Sopenharmony_ci ('force-manifest', 'f', 667db96d56Sopenharmony_ci "forcibly regenerate the manifest and carry on as usual. " 677db96d56Sopenharmony_ci "Deprecated: now the manifest is always regenerated."), 687db96d56Sopenharmony_ci ('formats=', None, 697db96d56Sopenharmony_ci "formats for source distribution (comma-separated list)"), 707db96d56Sopenharmony_ci ('keep-temp', 'k', 717db96d56Sopenharmony_ci "keep the distribution tree around after creating " + 727db96d56Sopenharmony_ci "archive file(s)"), 737db96d56Sopenharmony_ci ('dist-dir=', 'd', 747db96d56Sopenharmony_ci "directory to put the source distribution archive(s) in " 757db96d56Sopenharmony_ci "[default: dist]"), 767db96d56Sopenharmony_ci ('metadata-check', None, 777db96d56Sopenharmony_ci "Ensure that all required elements of meta-data " 787db96d56Sopenharmony_ci "are supplied. Warn if any missing. [default]"), 797db96d56Sopenharmony_ci ('owner=', 'u', 807db96d56Sopenharmony_ci "Owner name used when creating a tar file [default: current user]"), 817db96d56Sopenharmony_ci ('group=', 'g', 827db96d56Sopenharmony_ci "Group name used when creating a tar file [default: current group]"), 837db96d56Sopenharmony_ci ] 847db96d56Sopenharmony_ci 857db96d56Sopenharmony_ci boolean_options = ['use-defaults', 'prune', 867db96d56Sopenharmony_ci 'manifest-only', 'force-manifest', 877db96d56Sopenharmony_ci 'keep-temp', 'metadata-check'] 887db96d56Sopenharmony_ci 897db96d56Sopenharmony_ci help_options = [ 907db96d56Sopenharmony_ci ('help-formats', None, 917db96d56Sopenharmony_ci "list available distribution formats", show_formats), 927db96d56Sopenharmony_ci ] 937db96d56Sopenharmony_ci 947db96d56Sopenharmony_ci negative_opt = {'no-defaults': 'use-defaults', 957db96d56Sopenharmony_ci 'no-prune': 'prune' } 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_ci sub_commands = [('check', checking_metadata)] 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_ci READMES = ('README', 'README.txt', 'README.rst') 1007db96d56Sopenharmony_ci 1017db96d56Sopenharmony_ci def initialize_options(self): 1027db96d56Sopenharmony_ci # 'template' and 'manifest' are, respectively, the names of 1037db96d56Sopenharmony_ci # the manifest template and manifest file. 1047db96d56Sopenharmony_ci self.template = None 1057db96d56Sopenharmony_ci self.manifest = None 1067db96d56Sopenharmony_ci 1077db96d56Sopenharmony_ci # 'use_defaults': if true, we will include the default file set 1087db96d56Sopenharmony_ci # in the manifest 1097db96d56Sopenharmony_ci self.use_defaults = 1 1107db96d56Sopenharmony_ci self.prune = 1 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci self.manifest_only = 0 1137db96d56Sopenharmony_ci self.force_manifest = 0 1147db96d56Sopenharmony_ci 1157db96d56Sopenharmony_ci self.formats = ['gztar'] 1167db96d56Sopenharmony_ci self.keep_temp = 0 1177db96d56Sopenharmony_ci self.dist_dir = None 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ci self.archive_files = None 1207db96d56Sopenharmony_ci self.metadata_check = 1 1217db96d56Sopenharmony_ci self.owner = None 1227db96d56Sopenharmony_ci self.group = None 1237db96d56Sopenharmony_ci 1247db96d56Sopenharmony_ci def finalize_options(self): 1257db96d56Sopenharmony_ci if self.manifest is None: 1267db96d56Sopenharmony_ci self.manifest = "MANIFEST" 1277db96d56Sopenharmony_ci if self.template is None: 1287db96d56Sopenharmony_ci self.template = "MANIFEST.in" 1297db96d56Sopenharmony_ci 1307db96d56Sopenharmony_ci self.ensure_string_list('formats') 1317db96d56Sopenharmony_ci 1327db96d56Sopenharmony_ci bad_format = archive_util.check_archive_formats(self.formats) 1337db96d56Sopenharmony_ci if bad_format: 1347db96d56Sopenharmony_ci raise DistutilsOptionError( 1357db96d56Sopenharmony_ci "unknown archive format '%s'" % bad_format) 1367db96d56Sopenharmony_ci 1377db96d56Sopenharmony_ci if self.dist_dir is None: 1387db96d56Sopenharmony_ci self.dist_dir = "dist" 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci def run(self): 1417db96d56Sopenharmony_ci # 'filelist' contains the list of files that will make up the 1427db96d56Sopenharmony_ci # manifest 1437db96d56Sopenharmony_ci self.filelist = FileList() 1447db96d56Sopenharmony_ci 1457db96d56Sopenharmony_ci # Run sub commands 1467db96d56Sopenharmony_ci for cmd_name in self.get_sub_commands(): 1477db96d56Sopenharmony_ci self.run_command(cmd_name) 1487db96d56Sopenharmony_ci 1497db96d56Sopenharmony_ci # Do whatever it takes to get the list of files to process 1507db96d56Sopenharmony_ci # (process the manifest template, read an existing manifest, 1517db96d56Sopenharmony_ci # whatever). File list is accumulated in 'self.filelist'. 1527db96d56Sopenharmony_ci self.get_file_list() 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci # If user just wanted us to regenerate the manifest, stop now. 1557db96d56Sopenharmony_ci if self.manifest_only: 1567db96d56Sopenharmony_ci return 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci # Otherwise, go ahead and create the source distribution tarball, 1597db96d56Sopenharmony_ci # or zipfile, or whatever. 1607db96d56Sopenharmony_ci self.make_distribution() 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci def check_metadata(self): 1637db96d56Sopenharmony_ci """Deprecated API.""" 1647db96d56Sopenharmony_ci warn("distutils.command.sdist.check_metadata is deprecated, \ 1657db96d56Sopenharmony_ci use the check command instead", PendingDeprecationWarning) 1667db96d56Sopenharmony_ci check = self.distribution.get_command_obj('check') 1677db96d56Sopenharmony_ci check.ensure_finalized() 1687db96d56Sopenharmony_ci check.run() 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci def get_file_list(self): 1717db96d56Sopenharmony_ci """Figure out the list of files to include in the source 1727db96d56Sopenharmony_ci distribution, and put it in 'self.filelist'. This might involve 1737db96d56Sopenharmony_ci reading the manifest template (and writing the manifest), or just 1747db96d56Sopenharmony_ci reading the manifest, or just using the default file set -- it all 1757db96d56Sopenharmony_ci depends on the user's options. 1767db96d56Sopenharmony_ci """ 1777db96d56Sopenharmony_ci # new behavior when using a template: 1787db96d56Sopenharmony_ci # the file list is recalculated every time because 1797db96d56Sopenharmony_ci # even if MANIFEST.in or setup.py are not changed 1807db96d56Sopenharmony_ci # the user might have added some files in the tree that 1817db96d56Sopenharmony_ci # need to be included. 1827db96d56Sopenharmony_ci # 1837db96d56Sopenharmony_ci # This makes --force the default and only behavior with templates. 1847db96d56Sopenharmony_ci template_exists = os.path.isfile(self.template) 1857db96d56Sopenharmony_ci if not template_exists and self._manifest_is_not_generated(): 1867db96d56Sopenharmony_ci self.read_manifest() 1877db96d56Sopenharmony_ci self.filelist.sort() 1887db96d56Sopenharmony_ci self.filelist.remove_duplicates() 1897db96d56Sopenharmony_ci return 1907db96d56Sopenharmony_ci 1917db96d56Sopenharmony_ci if not template_exists: 1927db96d56Sopenharmony_ci self.warn(("manifest template '%s' does not exist " + 1937db96d56Sopenharmony_ci "(using default file list)") % 1947db96d56Sopenharmony_ci self.template) 1957db96d56Sopenharmony_ci self.filelist.findall() 1967db96d56Sopenharmony_ci 1977db96d56Sopenharmony_ci if self.use_defaults: 1987db96d56Sopenharmony_ci self.add_defaults() 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci if template_exists: 2017db96d56Sopenharmony_ci self.read_template() 2027db96d56Sopenharmony_ci 2037db96d56Sopenharmony_ci if self.prune: 2047db96d56Sopenharmony_ci self.prune_file_list() 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci self.filelist.sort() 2077db96d56Sopenharmony_ci self.filelist.remove_duplicates() 2087db96d56Sopenharmony_ci self.write_manifest() 2097db96d56Sopenharmony_ci 2107db96d56Sopenharmony_ci def add_defaults(self): 2117db96d56Sopenharmony_ci """Add all the default files to self.filelist: 2127db96d56Sopenharmony_ci - README or README.txt 2137db96d56Sopenharmony_ci - setup.py 2147db96d56Sopenharmony_ci - test/test*.py 2157db96d56Sopenharmony_ci - all pure Python modules mentioned in setup script 2167db96d56Sopenharmony_ci - all files pointed by package_data (build_py) 2177db96d56Sopenharmony_ci - all files defined in data_files. 2187db96d56Sopenharmony_ci - all files defined as scripts. 2197db96d56Sopenharmony_ci - all C sources listed as part of extensions or C libraries 2207db96d56Sopenharmony_ci in the setup script (doesn't catch C headers!) 2217db96d56Sopenharmony_ci Warns if (README or README.txt) or setup.py are missing; everything 2227db96d56Sopenharmony_ci else is optional. 2237db96d56Sopenharmony_ci """ 2247db96d56Sopenharmony_ci self._add_defaults_standards() 2257db96d56Sopenharmony_ci self._add_defaults_optional() 2267db96d56Sopenharmony_ci self._add_defaults_python() 2277db96d56Sopenharmony_ci self._add_defaults_data_files() 2287db96d56Sopenharmony_ci self._add_defaults_ext() 2297db96d56Sopenharmony_ci self._add_defaults_c_libs() 2307db96d56Sopenharmony_ci self._add_defaults_scripts() 2317db96d56Sopenharmony_ci 2327db96d56Sopenharmony_ci @staticmethod 2337db96d56Sopenharmony_ci def _cs_path_exists(fspath): 2347db96d56Sopenharmony_ci """ 2357db96d56Sopenharmony_ci Case-sensitive path existence check 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_ci >>> sdist._cs_path_exists(__file__) 2387db96d56Sopenharmony_ci True 2397db96d56Sopenharmony_ci >>> sdist._cs_path_exists(__file__.upper()) 2407db96d56Sopenharmony_ci False 2417db96d56Sopenharmony_ci """ 2427db96d56Sopenharmony_ci if not os.path.exists(fspath): 2437db96d56Sopenharmony_ci return False 2447db96d56Sopenharmony_ci # make absolute so we always have a directory 2457db96d56Sopenharmony_ci abspath = os.path.abspath(fspath) 2467db96d56Sopenharmony_ci directory, filename = os.path.split(abspath) 2477db96d56Sopenharmony_ci return filename in os.listdir(directory) 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci def _add_defaults_standards(self): 2507db96d56Sopenharmony_ci standards = [self.READMES, self.distribution.script_name] 2517db96d56Sopenharmony_ci for fn in standards: 2527db96d56Sopenharmony_ci if isinstance(fn, tuple): 2537db96d56Sopenharmony_ci alts = fn 2547db96d56Sopenharmony_ci got_it = False 2557db96d56Sopenharmony_ci for fn in alts: 2567db96d56Sopenharmony_ci if self._cs_path_exists(fn): 2577db96d56Sopenharmony_ci got_it = True 2587db96d56Sopenharmony_ci self.filelist.append(fn) 2597db96d56Sopenharmony_ci break 2607db96d56Sopenharmony_ci 2617db96d56Sopenharmony_ci if not got_it: 2627db96d56Sopenharmony_ci self.warn("standard file not found: should have one of " + 2637db96d56Sopenharmony_ci ', '.join(alts)) 2647db96d56Sopenharmony_ci else: 2657db96d56Sopenharmony_ci if self._cs_path_exists(fn): 2667db96d56Sopenharmony_ci self.filelist.append(fn) 2677db96d56Sopenharmony_ci else: 2687db96d56Sopenharmony_ci self.warn("standard file '%s' not found" % fn) 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_ci def _add_defaults_optional(self): 2717db96d56Sopenharmony_ci optional = ['test/test*.py', 'setup.cfg'] 2727db96d56Sopenharmony_ci for pattern in optional: 2737db96d56Sopenharmony_ci files = filter(os.path.isfile, glob(pattern)) 2747db96d56Sopenharmony_ci self.filelist.extend(files) 2757db96d56Sopenharmony_ci 2767db96d56Sopenharmony_ci def _add_defaults_python(self): 2777db96d56Sopenharmony_ci # build_py is used to get: 2787db96d56Sopenharmony_ci # - python modules 2797db96d56Sopenharmony_ci # - files defined in package_data 2807db96d56Sopenharmony_ci build_py = self.get_finalized_command('build_py') 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci # getting python files 2837db96d56Sopenharmony_ci if self.distribution.has_pure_modules(): 2847db96d56Sopenharmony_ci self.filelist.extend(build_py.get_source_files()) 2857db96d56Sopenharmony_ci 2867db96d56Sopenharmony_ci # getting package_data files 2877db96d56Sopenharmony_ci # (computed in build_py.data_files by build_py.finalize_options) 2887db96d56Sopenharmony_ci for pkg, src_dir, build_dir, filenames in build_py.data_files: 2897db96d56Sopenharmony_ci for filename in filenames: 2907db96d56Sopenharmony_ci self.filelist.append(os.path.join(src_dir, filename)) 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci def _add_defaults_data_files(self): 2937db96d56Sopenharmony_ci # getting distribution.data_files 2947db96d56Sopenharmony_ci if self.distribution.has_data_files(): 2957db96d56Sopenharmony_ci for item in self.distribution.data_files: 2967db96d56Sopenharmony_ci if isinstance(item, str): 2977db96d56Sopenharmony_ci # plain file 2987db96d56Sopenharmony_ci item = convert_path(item) 2997db96d56Sopenharmony_ci if os.path.isfile(item): 3007db96d56Sopenharmony_ci self.filelist.append(item) 3017db96d56Sopenharmony_ci else: 3027db96d56Sopenharmony_ci # a (dirname, filenames) tuple 3037db96d56Sopenharmony_ci dirname, filenames = item 3047db96d56Sopenharmony_ci for f in filenames: 3057db96d56Sopenharmony_ci f = convert_path(f) 3067db96d56Sopenharmony_ci if os.path.isfile(f): 3077db96d56Sopenharmony_ci self.filelist.append(f) 3087db96d56Sopenharmony_ci 3097db96d56Sopenharmony_ci def _add_defaults_ext(self): 3107db96d56Sopenharmony_ci if self.distribution.has_ext_modules(): 3117db96d56Sopenharmony_ci build_ext = self.get_finalized_command('build_ext') 3127db96d56Sopenharmony_ci self.filelist.extend(build_ext.get_source_files()) 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci def _add_defaults_c_libs(self): 3157db96d56Sopenharmony_ci if self.distribution.has_c_libraries(): 3167db96d56Sopenharmony_ci build_clib = self.get_finalized_command('build_clib') 3177db96d56Sopenharmony_ci self.filelist.extend(build_clib.get_source_files()) 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci def _add_defaults_scripts(self): 3207db96d56Sopenharmony_ci if self.distribution.has_scripts(): 3217db96d56Sopenharmony_ci build_scripts = self.get_finalized_command('build_scripts') 3227db96d56Sopenharmony_ci self.filelist.extend(build_scripts.get_source_files()) 3237db96d56Sopenharmony_ci 3247db96d56Sopenharmony_ci def read_template(self): 3257db96d56Sopenharmony_ci """Read and parse manifest template file named by self.template. 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci (usually "MANIFEST.in") The parsing and processing is done by 3287db96d56Sopenharmony_ci 'self.filelist', which updates itself accordingly. 3297db96d56Sopenharmony_ci """ 3307db96d56Sopenharmony_ci log.info("reading manifest template '%s'", self.template) 3317db96d56Sopenharmony_ci template = TextFile(self.template, strip_comments=1, skip_blanks=1, 3327db96d56Sopenharmony_ci join_lines=1, lstrip_ws=1, rstrip_ws=1, 3337db96d56Sopenharmony_ci collapse_join=1) 3347db96d56Sopenharmony_ci 3357db96d56Sopenharmony_ci try: 3367db96d56Sopenharmony_ci while True: 3377db96d56Sopenharmony_ci line = template.readline() 3387db96d56Sopenharmony_ci if line is None: # end of file 3397db96d56Sopenharmony_ci break 3407db96d56Sopenharmony_ci 3417db96d56Sopenharmony_ci try: 3427db96d56Sopenharmony_ci self.filelist.process_template_line(line) 3437db96d56Sopenharmony_ci # the call above can raise a DistutilsTemplateError for 3447db96d56Sopenharmony_ci # malformed lines, or a ValueError from the lower-level 3457db96d56Sopenharmony_ci # convert_path function 3467db96d56Sopenharmony_ci except (DistutilsTemplateError, ValueError) as msg: 3477db96d56Sopenharmony_ci self.warn("%s, line %d: %s" % (template.filename, 3487db96d56Sopenharmony_ci template.current_line, 3497db96d56Sopenharmony_ci msg)) 3507db96d56Sopenharmony_ci finally: 3517db96d56Sopenharmony_ci template.close() 3527db96d56Sopenharmony_ci 3537db96d56Sopenharmony_ci def prune_file_list(self): 3547db96d56Sopenharmony_ci """Prune off branches that might slip into the file list as created 3557db96d56Sopenharmony_ci by 'read_template()', but really don't belong there: 3567db96d56Sopenharmony_ci * the build tree (typically "build") 3577db96d56Sopenharmony_ci * the release tree itself (only an issue if we ran "sdist" 3587db96d56Sopenharmony_ci previously with --keep-temp, or it aborted) 3597db96d56Sopenharmony_ci * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories 3607db96d56Sopenharmony_ci """ 3617db96d56Sopenharmony_ci build = self.get_finalized_command('build') 3627db96d56Sopenharmony_ci base_dir = self.distribution.get_fullname() 3637db96d56Sopenharmony_ci 3647db96d56Sopenharmony_ci self.filelist.exclude_pattern(None, prefix=build.build_base) 3657db96d56Sopenharmony_ci self.filelist.exclude_pattern(None, prefix=base_dir) 3667db96d56Sopenharmony_ci 3677db96d56Sopenharmony_ci if sys.platform == 'win32': 3687db96d56Sopenharmony_ci seps = r'/|\\' 3697db96d56Sopenharmony_ci else: 3707db96d56Sopenharmony_ci seps = '/' 3717db96d56Sopenharmony_ci 3727db96d56Sopenharmony_ci vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', 3737db96d56Sopenharmony_ci '_darcs'] 3747db96d56Sopenharmony_ci vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) 3757db96d56Sopenharmony_ci self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) 3767db96d56Sopenharmony_ci 3777db96d56Sopenharmony_ci def write_manifest(self): 3787db96d56Sopenharmony_ci """Write the file list in 'self.filelist' (presumably as filled in 3797db96d56Sopenharmony_ci by 'add_defaults()' and 'read_template()') to the manifest file 3807db96d56Sopenharmony_ci named by 'self.manifest'. 3817db96d56Sopenharmony_ci """ 3827db96d56Sopenharmony_ci if self._manifest_is_not_generated(): 3837db96d56Sopenharmony_ci log.info("not writing to manually maintained " 3847db96d56Sopenharmony_ci "manifest file '%s'" % self.manifest) 3857db96d56Sopenharmony_ci return 3867db96d56Sopenharmony_ci 3877db96d56Sopenharmony_ci content = self.filelist.files[:] 3887db96d56Sopenharmony_ci content.insert(0, '# file GENERATED by distutils, do NOT edit') 3897db96d56Sopenharmony_ci self.execute(file_util.write_file, (self.manifest, content), 3907db96d56Sopenharmony_ci "writing manifest file '%s'" % self.manifest) 3917db96d56Sopenharmony_ci 3927db96d56Sopenharmony_ci def _manifest_is_not_generated(self): 3937db96d56Sopenharmony_ci # check for special comment used in 3.1.3 and higher 3947db96d56Sopenharmony_ci if not os.path.isfile(self.manifest): 3957db96d56Sopenharmony_ci return False 3967db96d56Sopenharmony_ci 3977db96d56Sopenharmony_ci fp = open(self.manifest) 3987db96d56Sopenharmony_ci try: 3997db96d56Sopenharmony_ci first_line = fp.readline() 4007db96d56Sopenharmony_ci finally: 4017db96d56Sopenharmony_ci fp.close() 4027db96d56Sopenharmony_ci return first_line != '# file GENERATED by distutils, do NOT edit\n' 4037db96d56Sopenharmony_ci 4047db96d56Sopenharmony_ci def read_manifest(self): 4057db96d56Sopenharmony_ci """Read the manifest file (named by 'self.manifest') and use it to 4067db96d56Sopenharmony_ci fill in 'self.filelist', the list of files to include in the source 4077db96d56Sopenharmony_ci distribution. 4087db96d56Sopenharmony_ci """ 4097db96d56Sopenharmony_ci log.info("reading manifest file '%s'", self.manifest) 4107db96d56Sopenharmony_ci with open(self.manifest) as manifest: 4117db96d56Sopenharmony_ci for line in manifest: 4127db96d56Sopenharmony_ci # ignore comments and blank lines 4137db96d56Sopenharmony_ci line = line.strip() 4147db96d56Sopenharmony_ci if line.startswith('#') or not line: 4157db96d56Sopenharmony_ci continue 4167db96d56Sopenharmony_ci self.filelist.append(line) 4177db96d56Sopenharmony_ci 4187db96d56Sopenharmony_ci def make_release_tree(self, base_dir, files): 4197db96d56Sopenharmony_ci """Create the directory tree that will become the source 4207db96d56Sopenharmony_ci distribution archive. All directories implied by the filenames in 4217db96d56Sopenharmony_ci 'files' are created under 'base_dir', and then we hard link or copy 4227db96d56Sopenharmony_ci (if hard linking is unavailable) those files into place. 4237db96d56Sopenharmony_ci Essentially, this duplicates the developer's source tree, but in a 4247db96d56Sopenharmony_ci directory named after the distribution, containing only the files 4257db96d56Sopenharmony_ci to be distributed. 4267db96d56Sopenharmony_ci """ 4277db96d56Sopenharmony_ci # Create all the directories under 'base_dir' necessary to 4287db96d56Sopenharmony_ci # put 'files' there; the 'mkpath()' is just so we don't die 4297db96d56Sopenharmony_ci # if the manifest happens to be empty. 4307db96d56Sopenharmony_ci self.mkpath(base_dir) 4317db96d56Sopenharmony_ci dir_util.create_tree(base_dir, files, dry_run=self.dry_run) 4327db96d56Sopenharmony_ci 4337db96d56Sopenharmony_ci # And walk over the list of files, either making a hard link (if 4347db96d56Sopenharmony_ci # os.link exists) to each one that doesn't already exist in its 4357db96d56Sopenharmony_ci # corresponding location under 'base_dir', or copying each file 4367db96d56Sopenharmony_ci # that's out-of-date in 'base_dir'. (Usually, all files will be 4377db96d56Sopenharmony_ci # out-of-date, because by default we blow away 'base_dir' when 4387db96d56Sopenharmony_ci # we're done making the distribution archives.) 4397db96d56Sopenharmony_ci 4407db96d56Sopenharmony_ci if hasattr(os, 'link'): # can make hard links on this system 4417db96d56Sopenharmony_ci link = 'hard' 4427db96d56Sopenharmony_ci msg = "making hard links in %s..." % base_dir 4437db96d56Sopenharmony_ci else: # nope, have to copy 4447db96d56Sopenharmony_ci link = None 4457db96d56Sopenharmony_ci msg = "copying files to %s..." % base_dir 4467db96d56Sopenharmony_ci 4477db96d56Sopenharmony_ci if not files: 4487db96d56Sopenharmony_ci log.warn("no files to distribute -- empty manifest?") 4497db96d56Sopenharmony_ci else: 4507db96d56Sopenharmony_ci log.info(msg) 4517db96d56Sopenharmony_ci for file in files: 4527db96d56Sopenharmony_ci if not os.path.isfile(file): 4537db96d56Sopenharmony_ci log.warn("'%s' not a regular file -- skipping", file) 4547db96d56Sopenharmony_ci else: 4557db96d56Sopenharmony_ci dest = os.path.join(base_dir, file) 4567db96d56Sopenharmony_ci self.copy_file(file, dest, link=link) 4577db96d56Sopenharmony_ci 4587db96d56Sopenharmony_ci self.distribution.metadata.write_pkg_info(base_dir) 4597db96d56Sopenharmony_ci 4607db96d56Sopenharmony_ci def make_distribution(self): 4617db96d56Sopenharmony_ci """Create the source distribution(s). First, we create the release 4627db96d56Sopenharmony_ci tree with 'make_release_tree()'; then, we create all required 4637db96d56Sopenharmony_ci archive files (according to 'self.formats') from the release tree. 4647db96d56Sopenharmony_ci Finally, we clean up by blowing away the release tree (unless 4657db96d56Sopenharmony_ci 'self.keep_temp' is true). The list of archive files created is 4667db96d56Sopenharmony_ci stored so it can be retrieved later by 'get_archive_files()'. 4677db96d56Sopenharmony_ci """ 4687db96d56Sopenharmony_ci # Don't warn about missing meta-data here -- should be (and is!) 4697db96d56Sopenharmony_ci # done elsewhere. 4707db96d56Sopenharmony_ci base_dir = self.distribution.get_fullname() 4717db96d56Sopenharmony_ci base_name = os.path.join(self.dist_dir, base_dir) 4727db96d56Sopenharmony_ci 4737db96d56Sopenharmony_ci self.make_release_tree(base_dir, self.filelist.files) 4747db96d56Sopenharmony_ci archive_files = [] # remember names of files we create 4757db96d56Sopenharmony_ci # tar archive must be created last to avoid overwrite and remove 4767db96d56Sopenharmony_ci if 'tar' in self.formats: 4777db96d56Sopenharmony_ci self.formats.append(self.formats.pop(self.formats.index('tar'))) 4787db96d56Sopenharmony_ci 4797db96d56Sopenharmony_ci for fmt in self.formats: 4807db96d56Sopenharmony_ci file = self.make_archive(base_name, fmt, base_dir=base_dir, 4817db96d56Sopenharmony_ci owner=self.owner, group=self.group) 4827db96d56Sopenharmony_ci archive_files.append(file) 4837db96d56Sopenharmony_ci self.distribution.dist_files.append(('sdist', '', file)) 4847db96d56Sopenharmony_ci 4857db96d56Sopenharmony_ci self.archive_files = archive_files 4867db96d56Sopenharmony_ci 4877db96d56Sopenharmony_ci if not self.keep_temp: 4887db96d56Sopenharmony_ci dir_util.remove_tree(base_dir, dry_run=self.dry_run) 4897db96d56Sopenharmony_ci 4907db96d56Sopenharmony_ci def get_archive_files(self): 4917db96d56Sopenharmony_ci """Return the list of archive files created when the command 4927db96d56Sopenharmony_ci was run, or None if the command hasn't run yet. 4937db96d56Sopenharmony_ci """ 4947db96d56Sopenharmony_ci return self.archive_files 495