# HG changeset patch # User Stephen Thorne # Date 1307186324 -36000 # Branch 3.1 # Node ID 2be931c637f2d1e6e6374a0b91aeaae7a0041594 # Parent 0639e630426c6f6b14b3a3138f60f05850a4d18a Issue #11104: Read and respect the MANIFEST when no MANIFEST.in used. When MANIFEST does not contain the comment that indicates that it is created from a MANIFEST.in ignore any MANIFEST.in and read the files out of MANIFEST. Previous to this change, only files that would be auto-detected if no MANIFEST* files were present at all would be used. Based on the patch from jdennis diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -176,14 +176,19 @@ class sdist(Command): reading the manifest, or just using the default file set -- it all depends on the user's options. """ - # new behavior: + # new behavior when using a template: # the file list is recalculated everytime because # even if MANIFEST.in or setup.py are not changed # the user might have added some files in the tree that # need to be included. # - # This makes --force the default and only behavior. + # This makes --force the default and only behavior with templates. template_exists = os.path.isfile(self.template) + if not template_exists and self.check_manifest(): + self.read_manifest() + self.filelist.remove_duplicates() + return + if not template_exists: self.warn(("manifest template '%s' does not exist " + "(using default file list)") % @@ -200,8 +205,8 @@ class sdist(Command): self.prune_file_list() self.filelist.sort() + self.write_manifest() self.filelist.remove_duplicates() - self.write_manifest() def add_defaults(self): """Add all the default files to self.filelist: @@ -333,10 +338,9 @@ class sdist(Command): vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) - def write_manifest(self): - """Write the file list in 'self.filelist' (presumably as filled in - by 'add_defaults()' and 'read_template()') to the manifest file - named by 'self.manifest'. + def check_manifest(self): + """Look at 'self.manifest' to check if it is dynamically generated from + 'self.template', and return True if it is. """ if os.path.isfile(self.manifest): fp = open(self.manifest) @@ -345,10 +349,18 @@ class sdist(Command): finally: fp.close() - if first_line != '# file GENERATED by distutils, do NOT edit\n': - log.info("not writing to manually maintained " - "manifest file '%s'" % self.manifest) - return + return first_line != '# file GENERATED by distutils, do NOT edit\n' + return False + + def write_manifest(self): + """Write the file list in 'self.filelist' (presumably as filled in + by 'add_defaults()' and 'read_template()') to the manifest file + named by 'self.manifest'. + """ + if self.check_manifest(): + log.info("not writing to manually maintained " + "manifest file '%s'" % self.manifest) + return content = self.filelist.files[:] content.insert(0, '# file GENERATED by distutils, do NOT edit') @@ -362,12 +374,13 @@ class sdist(Command): """ log.info("reading manifest file '%s'", self.manifest) manifest = open(self.manifest) - while True: - line = manifest.readline() - if line == '': # end of file - break - if line[-1] == '\n': - line = line[0:-1] + for line in manifest: + # ignore comments and blank lines + if line.startswith('#'): + continue + line = line.rstrip('\r\n') + if not line: + continue self.filelist.append(line) manifest.close() diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py --- a/Lib/distutils/tests/test_sdist.py +++ b/Lib/distutils/tests/test_sdist.py @@ -7,6 +7,7 @@ from os.path import join import sys import tempfile import warnings +import tarfile from test.support import captured_stdout, check_warnings, run_unittest @@ -326,7 +327,7 @@ class SDistTestCase(PyPIRCCommandTestCas f.close() # do we have the new file in MANIFEST ? - self.assertEqual(len(manifest2), 6) + self.assertEqual(len(manifest2), 6, "MANIFEST size should have increased to 6") self.assertIn('doc2.txt', manifest2[-1]) @unittest.skipUnless(ZLIB_SUPPORT, 'Need zlib support to run') @@ -363,6 +364,24 @@ class SDistTestCase(PyPIRCCommandTestCas self.assertEqual(manifest, ['README.manual']) + def test_manifest_respected(self): + # check that a MANIFEST without a marker is left alone + dist, cmd = self.get_cmd() + cmd.ensure_finalized() + self.write_file((self.tmp_dir, cmd.manifest), 'test-file') + self.write_file((self.tmp_dir, 'test-file'), '') + cmd.run() + + self.assertIn('test-file', cmd.filelist.files, "test-file should be in the filelist attr") + + archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') + archive = tarfile.open(archive_name) + filenames = [tarinfo.name for tarinfo in archive] + self.assertIn('fake-1.0/test-file', + filenames, + "test-file was listed in MANIFEST but not included " + "in tar file") + def test_suite(): return unittest.makeSuite(SDistTestCase)