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