def test_process_template_line(self): # testing all MANIFEST.in template patterns file_list = FileList() # simulated file list file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', join('global', 'one.txt'), join('global', 'two.txt'), join('global', 'files.x'), join('global', 'here.tmp'), join('f', 'o', 'f.oo'), join('dir', 'graft-one'), join('dir', 'dir2', 'graft2'), join('dir3', 'ok'), join('dir3', 'sub', 'ok.txt') ] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) wanted = ['ok', 'four.txt', join('global', 'one.txt'), join('global', 'two.txt'), join('f', 'o', 'f.oo'), join('dir', 'graft-one'), join('dir', 'dir2', 'graft2')] self.assertEquals(file_list.files, wanted)
def fileList( template ): """Produce a formatted file-list for storing in a file""" files = FileList() for line in filter(None,template.splitlines()): files.process_template_line( line ) content = '\n'.join( files.files ) return content
def test_process_template_line(self): # testing all MANIFEST.in template patterns file_list = FileList() # simulated file list file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', 'global/one.txt', 'global/two.txt', 'global/files.x', 'global/here.tmp', 'f/o/f.oo', 'dir/graft-one', 'dir/dir2/graft2', 'dir3/ok', 'dir3/sub/ok.txt', ] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) wanted = ['ok', 'four.txt', 'global/one.txt', 'global/two.txt', 'f/o/f.oo', 'dir/graft-one', 'dir/dir2/graft2'] self.assertEqual(file_list.files, wanted)
def run(self): from distutils import log from distutils.filelist import FileList global CLEANUP distutils.command.clean.clean.run(self) if self.all: fl = FileList() fl.include_pattern("*.pyc", 0) fl.include_pattern("*.pyd", 0) fl.include_pattern("*.so", 0) CLEANUP += fl.files for f in CLEANUP: if os.path.isdir(f): try: if not self.dry_run and os.path.exists(f): os.rmdir(f) log.info("removing '%s'", f) except IOError: log.warning("unable to remove '%s'", f) else: try: if not self.dry_run and os.path.exists(f): os.remove(f) log.info("removing '%s'", f) except IOError: log.warning("unable to remove '%s'", f)
def test_process_template_line(self): file_list = FileList() l = make_local_path file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', 'buildout.cfg', l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('global/files.x'), l('global/here.tmp'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2'), l('dir3/ok'), l('dir3/sub/ok.txt')] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) wanted = ['ok', 'buildout.cfg', 'four.txt', l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2')] self.assertEqual(file_list.files, wanted)
def setup_python3(): """Taken from "distribute" setup.py.""" from distutils.filelist import FileList from distutils import dir_util, file_util, util from os.path import join, exists tmp_src = join("build", "src") # Not covered by "setup.py clean --all", so explicit deletion required. if exists(tmp_src): dir_util.remove_tree(tmp_src) # log.set_verbosity(1) fl = FileList() for line in open("MANIFEST.in"): if not line.strip(): continue fl.process_template_line(line) dir_util.create_tree(tmp_src, fl.files) outfiles_2to3 = [] for f in fl.files: outf, copied = file_util.copy_file(f, join(tmp_src, f), update=1) if copied and outf.endswith(".py"): outfiles_2to3.append(outf) util.run_2to3(outfiles_2to3) # arrange setup to use the copy sys.path.insert(0, tmp_src) return tmp_src
def parse_manifestin(template): """This function parses template file (usually MANIFEST.in)""" if not os.path.exists(template): return [] template = TextFile(template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) file_list = FileList() try: while True: line = template.readline() if line is None: # end of file break try: file_list.process_template_line(line) # the call above can raise a DistutilsTemplateError for # malformed lines, or a ValueError from the lower-level # convert_path function except (DistutilsTemplateError, ValueError) as msg: print("%s, line %d: %s" % (template.filename, template.current_line, msg)) return file_list.files finally: template.close()
def _data_files(): """List files to be copied to the TAU Commander installation. Start with the files listed in MANIFEST.in, then exclude files that should not be installed. """ from distutils.filelist import FileList from distutils.text_file import TextFile from distutils.errors import DistutilsTemplateError filelist = FileList() template = TextFile(os.path.join(PACKAGE_TOPDIR, 'MANIFEST.in'), strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) try: while True: line = template.readline() if line is None: break try: filelist.process_template_line(line) except (DistutilsTemplateError, ValueError) as err: print "%s, line %d: %s" % (template.filename, template.current_line, err) finally: template.close() excluded = ['Makefile', 'VERSION', 'MANIFEST.in', '*Miniconda*'] data_files = [] for path in filelist.files: for excl in excluded: if fnmatch.fnmatchcase(path, excl): break else: data_files.append((os.path.dirname(path), [path])) return data_files
def setup_python3(): # Taken from "distribute" setup.py from distutils.filelist import FileList from distutils import dir_util, file_util, util, log from os.path import join tmp_src = join("build", "src") log.set_verbosity(1) fl = FileList() for line in open("MANIFEST.in"): if not line.strip(): continue fl.process_template_line(line) dir_util.create_tree(tmp_src, fl.files) outfiles_2to3 = [] for f in fl.files: outf, copied = file_util.copy_file(f, join(tmp_src, f), update=1) if copied and outf.endswith(".py"): outfiles_2to3.append(outf) util.run_2to3(outfiles_2to3) # arrange setup to use the copy sys.path.insert(0, tmp_src) return tmp_src
def get_files(pattern): filelist = FileList() if '**' in pattern: pattern = pattern.replace('**', '*') anchor = False else: anchor = True filelist.include_pattern(pattern, anchor) return filelist.files
def get_files(pattern): filelist = FileList() if "**" in pattern: pattern = pattern.replace("**", "*") anchor = False else: anchor = True filelist.include_pattern(pattern, anchor) return filelist.files
def get_translatable_files(root): pofiles = os.path.join(root, 'po', POTFILES) if not os.path.exists(pofiles): print 'Warning: Could not find %s' % pofiles return [] filelist = FileList() fp = open(pofiles) for line in fp.readlines(): filelist.process_template_line(line) return sorted(filelist.files)
def _get_manifest_files(): filelist = FileList() old_wd = os.getcwd() try: os.chdir(SOURCE_DIRECTORY) filelist.findall() finally: os.chdir(old_wd) with open(MANIFEST, 'r') as source: for line in source: filelist.process_template_line(line.strip()) return filelist.files
def test_exclude_pattern(self): file_list = FileList() self.assertFalse(file_list.exclude_pattern('*.py')) file_list = FileList() file_list.files = ['a.py', 'b.py'] self.assertTrue(file_list.exclude_pattern('*.py')) file_list = FileList() file_list.files = ['a.py', 'a.txt'] file_list.exclude_pattern('*.py') self.assertEqual(file_list.files, ['a.txt'])
def test_exclude_pattern(self): file_list = FileList() self.assertFalse(file_list.exclude_pattern("*.py")) file_list = FileList() file_list.files = ["a.py", "b.py"] self.assertTrue(file_list.exclude_pattern("*.py")) file_list = FileList() file_list.files = ["a.py", "a.txt"] file_list.exclude_pattern("*.py") self.assertEqual(file_list.files, ["a.txt"])
def run (self): # try to run swig self.swig_name = None for swig_name in ('swig', 'swig1.3'): try: # should do a version check self.spawn([swig_name, '-version']) self.swig_name = swig_name if not check_swig_version(swig_name): handle_wrong_swig_version() self.swig_name = None break except: pass # if brain dead spawn doesn't work... if self.swig_name is None: for swig_name in ('swig', 'swig1.3'): try: r = os.system("%s -version" % swig_name) except: r == 99999999 if r == 256: self.swig_name = swig_name if not check_swig_version(swig_name): handle_wrong_swig_version() # found the swig name, stop checking. break if self.swig_name is None: self.warn("Can't find SWIG, will just have to do with the existing wrapper source.") else: self.mkpath('src/interface') self.mkpath('src/shadow') interfaces = [] f = FileList() f.findall('interface') f.process_template_line('global-include *.i') f.files.sort() for file in f.files: interfaces.append(string.join(string.split(os.path.splitext(file)[0], os.sep)[1:], '.')) interfaces.sort() for full_module_name in interfaces: self.swig(full_module_name)
def get_files(pattern): """ Retrieve all files in the current directory by a pattern. Use ** as greedy wildcard and * as non-greedy wildcard. :param pattern: The pattern as used by :obj:`distutils.filelist.Filelist` """ filelist = FileList() if '**' in pattern: pattern = pattern.replace('**', '*') anchor = False else: anchor = True filelist.include_pattern(pattern, anchor) return filelist.files
def test_debug_print(self): file_list = FileList() with captured_stdout() as stdout: file_list.debug_print("xxx") stdout.seek(0) self.assertEqual(stdout.read(), "") debug.DEBUG = True try: with captured_stdout() as stdout: file_list.debug_print("xxx") stdout.seek(0) self.assertEqual(stdout.read(), "xxx\n") finally: debug.DEBUG = False
def run(self): self._check_compiler() customize_compiler(self.compiler) for name, value in self.distribution.define_macros: self.compiler.define_macro(name, value) self.dump_source = 0 f = FileList() f.process_template_line('include src/shadow/*.c') for file in f.files: try: BUILD = get_build_info(file) #if (not BUILD.has_key('platform_include') or sys.platform in BUILD['platform_include']) and (not BUILD.has_key('platform_exclude') or sys.platform not in BUILD['platform_exclude']): if not BUILD.has_key('gl_platforms') or self.distribution.gl_platform in BUILD['gl_platforms']: libs = ['GL', 'GLU'] headers = [] if BUILD.has_key('libs'): libs.extend(BUILD['libs']) if BUILD.has_key( 'include_dirs' ): headers = BUILD['include_dirs'] self.libraries = self.distribution.transform_libs(libs) self.try_run( open(file).read(), library_dirs = self.distribution.library_dirs, include_dirs = self.distribution.include_dirs + headers, ) api_version_string = open('api_version').read() if not api_version_string: self.warn( """No current api_version_string, expect %s to be improperly generated"""%( file, )) src = os.path.join( os.path.splitext(file)[0]+ '.py' ) else: # has an api_version_string src = os.path.join( os.path.splitext(file)[0]+ '.%04x.py' % string.atoi(api_version_string) ) names = string.split(os.path.splitext(os.path.split(file)[1])[0], '.') dest = self.get_module_outfile(self.build_lib, ['OpenGL'] + names[:-1], names[-1]) self.mkpath(os.path.split(dest)[0]) self.copy_file(src, dest) os.remove('api_version') except: import traceback traceback.print_exc() self.warn( """Failure compiling version-selector, likely will be missing shadow modules for %r"""%( file,)) distutils.command.build_py.build_py.run(self)
class sdist_testimages(sdist): """ Tailor made sdist for debian containing only testimages * remove everything * add image files from testimages/* """ to_remove = ["PKG-INFO", "setup.cfg"] def run(self): self.filelist = FileList() self.add_defaults() self.make_distribution() def add_defaults(self): print("in sdist_testimages.add_defaults") self.filelist.extend([op.join("testimages", i) for i in download_images()]) print(self.filelist.files) def make_release_tree(self, base_dir, files): print("in sdist_testimages.make_release_tree") sdist.make_release_tree(self, base_dir, files) for afile in self.to_remove: dest = os.path.join(base_dir, afile) if os.path.exists(dest): os.unlink(dest) def make_distribution(self): print("in sdist_testimages.make_distribution") sdist.make_distribution(self) dest = self.archive_files[0] dirname, basename = op.split(dest) base, ext = op.splitext(basename) while ext in [".zip", ".tar", ".bz2", ".gz", ".Z", ".lz", ".orig"]: base, ext = op.splitext(base) if ext: dest = "".join((base, ext)) else: dest = base sp = dest.split("-") base = sp[:-1] nr = sp[-1] debian_arch = op.join(dirname, "-".join(base) + "_" + nr + ".orig-testimages.tar.gz") os.rename(self.archive_files[0], debian_arch) self.archive_files = [debian_arch] print("Building debian orig-testimages.tar.gz in %s" % self.archive_files[0])
def run(self): self.filelist = FileList() for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) self.get_file_list() if self.manifest_only: return self.make_distribution()
def test_process_template_line(self): # testing all MANIFEST.in template patterns file_list = FileList() l = make_local_path # simulated file list file_list.allfiles = [ 'foo.tmp', 'ok', 'xo', 'four.txt', 'buildout.cfg', # filelist does not filter out VCS directories, # it's sdist that does l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('global/files.x'), l('global/here.tmp'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2'), l('dir3/ok'), l('dir3/sub/ok.txt'), ] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) wanted = [ 'ok', 'buildout.cfg', 'four.txt', l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2'), ] self.assertEqual(file_list.files, wanted)
def test_exclude_pattern(self): # return False if no match file_list = FileList() self.assertFalse(file_list.exclude_pattern('*.py')) # return True if files match file_list = FileList() file_list.files = ['a.py', 'b.py'] self.assertTrue(file_list.exclude_pattern('*.py')) # test excludes file_list = FileList() file_list.files = ['a.py', 'a.txt'] file_list.exclude_pattern('*.py') self.assertEqual(file_list.files, ['a.txt'])
def get_files(pattern): """Retrieve all files in the current directory by a pattern. Use ** as greedy wildcard and * as non-greedy wildcard. Args: pattern (str): pattern as used by :obj:`distutils.filelist.Filelist` Returns: [str]: list of files """ filelist = FileList() if '**' in pattern: pattern = pattern.replace('**', '*') anchor = False else: anchor = True filelist.include_pattern(pattern, anchor) return filelist.files
def run(self): log.info("generating INFO_SRC and INFO_BIN files") generate_info_files() self.distribution.data_files = None self.filelist = FileList() for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) self.get_file_list() self.make_distribution()
def _get_manifest_files(): filelist = FileList() old_wd = os.getcwd() try: os.chdir(SOURCE_DIRECTORY) filelist.findall() finally: os.chdir(old_wd) with open(MANIFEST, 'r', encoding='utf-8') as source: for line in source: filelist.process_template_line(line.strip()) filelist.process_template_line('prune .tox') return filelist.files
def run(self): self.filelist = FileList() self.get_file_list() self.make_distribution() dist_files = getattr(self.distribution, 'dist_files', []) for file in self.archive_files: data = ('ezip', '', file) if data not in dist_files: dist_files.append(data)
def run(self): self.filelist = FileList() if not os.path.exists(self.manifest): self.write_manifest() # it must exist so it'll get in the list self.filelist.findall() self.add_defaults() if os.path.exists(self.template): self.read_template() self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest()
def run(self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Run sub commands for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution()
def run(self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Ensure that all required meta-data is given; warn if not (but # don't die, it's not *that* serious!) self.check_metadata() # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution()
def test_remove_duplicates(self): file_list = FileList() file_list.files = ['a', 'b', 'a', 'g', 'c', 'g'] # files must be sorted beforehand (sdist does it) file_list.sort() file_list.remove_duplicates() self.assertEqual(file_list.files, ['a', 'b', 'c', 'g'])
def copydir_run_2to3(src, dest, template=None, fixer_names=None, options=None, explicit=None): """Recursively copy a directory, only copying new and changed files, running run_2to3 over all newly copied Python modules afterward. If you give a template string, it's parsed like a MANIFEST.in. """ from distutils.dir_util import mkpath from distutils.file_util import copy_file from distutils.filelist import FileList filelist = FileList() curdir = os.getcwd() os.chdir(src) try: filelist.findall() finally: os.chdir(curdir) filelist.files[:] = filelist.allfiles if template: for line in template.splitlines(): line = line.strip() if not line: continue filelist.process_template_line(line) copied = [] for filename in filelist.files: outname = os.path.join(dest, filename) mkpath(os.path.dirname(outname)) res = copy_file(os.path.join(src, filename), outname, update=1) if res[1]: copied.append(outname) run_2to3([fn for fn in copied if fn.lower().endswith('.py')], fixer_names=fixer_names, options=options, explicit=explicit) return copied
def test_add_defaults_empty(self): readme = os.path.join(self.srcdir, 'README') setup_py = os.path.join(self.srcdir, 'setup.py') open(readme, 'w') open(setup_py, 'w') dist = Distribution({'srcdir': self.srcdir, 'script_name': 'setup.py'}) cmd = sdist(dist) cmd.ensure_finalized() cmd.filelist = FileList() cmd.add_defaults() self.assertEqual(cmd.filelist.files, [readme, setup_py])
def test_process_template_line(self): # testing all MANIFEST.in template patterns file_list = FileList() l = make_local_path # simulated file list file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', 'buildout.cfg', # filelist does not filter out VCS directories, # it's sdist that does l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('global/files.x'), l('global/here.tmp'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2'), l('dir3/ok'), l('dir3/sub/ok.txt'), ] for line in MANIFEST_IN.split('\n'): if line.strip() == '': continue file_list.process_template_line(line) wanted = ['ok', 'buildout.cfg', 'four.txt', l('.hg/last-message.txt'), l('global/one.txt'), l('global/two.txt'), l('f/o/f.oo'), l('dir/graft-one'), l('dir/dir2/graft2'), ] self.assertEqual(file_list.files, wanted)
def process_templates(self, target): # Build list of files to be processed. filelist = FileList() if filelist.include_pattern('*.dist_template', anchor=0) == 0: # Nothing to do. return # FIXME: For compatibility with old packages not yet using the version # module. Change to unconditional import in gnue-common 0.8. try: from src import version except: return # List of keywords to replace. keywords = { ':PACKAGE:': self.distribution.get_name(), ':TITLE:': self.distribution.get_description(), ':VERSION:': self.distribution.get_version(), ':MAJOR:': str(version.major), ':MINOR:': str(version.minor), ':PHASE:': str(version.phase), ':BUILD:': str(version.build), ':SVN:': str(version.svn), ':DATE_ISO:': time.strftime('%Y-%m-%d', time.gmtime()), ':DATE_RFC:': time.strftime('%a, %d %b %Y', time.gmtime()), ':TIME:': time.strftime('%H:%M:%S', time.gmtime())} # Hack for version numbering schemes that are limited to x.y.z. if version.phase == 'final': keywords[':FINAL:'] = str(version.build) else: keywords[':FINAL:'] = '0' for src in filelist.files: dst = os.path.join(target, src[:-14]) args = (src, dst, keywords) self.execute(self.__process_template, args, "generating %s from %s" % (dst, src))
def get_outputs(self, include_bytecode=1): outputs = [] f = FileList() f.process_template_line('include src/shadow/*.c') for file in f.files: try: BUILD = get_build_info(file) #if (not BUILD.has_key('platform_include') or sys.platform in BUILD['platform_include']) and (not BUILD.has_key('platform_exclude') or sys.platform not in BUILD['platform_exclude']): if not BUILD.has_key('gl_platforms') or self.distribution.gl_platform in BUILD['gl_platforms']: names = string.split(os.path.splitext(os.path.split(file)[1])[0], '.') dest = self.get_module_outfile(self.build_lib, ['OpenGL'] + names[:-1], names[-1]) outputs.append(dest) if include_bytecode: if self.compile: outputs.append(dest + "c") if self.optimize > 0: outputs.append(dest + "o") except: import traceback traceback.print_exc() return outputs + (distutils.command.build_py.build_py.get_outputs(self, include_bytecode) or [])
def run(self): """Run the command.""" self.log.info("generating INFO_SRC and INFO_BIN files") write_info_src(VERSION) write_info_bin() self.distribution.data_files = None self.filelist = FileList() for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) self.get_file_list() self.make_distribution()
def finalize(self): """ complete the files list by processing the given template """ if self.finalized: return if self.files == None: self.files = [] if self.template != None: if type(self.template) == str: self.template = str(self.template).split(";") filelist = FileList(self.warn, self.debug_print) for line in self.template: filelist.process_template_line(str(line).strip()) filelist.sort() filelist.remove_duplicates() self.files.extend(filelist.files) self.finalized = 1
def run(self): self.filelist = FileList() self.get_file_list() make_resource_module(self.filelist.files) r = super().run() assert len(self.archive_files) == 1 print("filtering files and recompressing with 4K dictionary") filter_tar(self.archive_files[0]) outbuf.seek(0) gzip_4k(outbuf, self.archive_files[0]) return r
def run(self): from distutils.filelist import FileList self.keep_temp = 1 #Rewrite: sdist.run(self) self.manifest = "MANIFEST" self.filelist = FileList() self.check_metadata() self.get_file_list() ## Exclude mo files: self.read_manifest_no_mo() if self.manifest_only: return self.make_distribution() self.finish_banner()
def _parse_template_file(filename, path=None): template = TextFile(filename, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) lines = template.readlines() filelist = FileList() try: if path is not None and not path == os.getcwd(): oldpath = os.getcwd() os.chdir(path) else: oldpath = None for line in lines: filelist.process_template_line(line) finally: if oldpath is not None: os.chdir(oldpath) return filelist.files
def test_remove_duplicates(self): file_list = FileList() file_list.files = ['a', 'b', 'a', 'g', 'c', 'g'] file_list.sort() file_list.remove_duplicates() self.assertEqual(file_list.files, ['a', 'b', 'c', 'g'])
def get_extra_source_files(): """Return the list of files included in the tarball.""" # FIXME: handle redundancies between data files, package data files # (i.e. installed data files) and files included as part of modules, # packages, extensions, .... Given the giant mess that distutils makes # of things here, it may not be possible to get everything right, # though. dist = _Distribution() sdist = old_sdist(dist) sdist.initialize_options() sdist.finalize_options() sdist.manifest_only = True sdist.filelist = FileList() sdist.distribution.script_name = filename sdist.get_file_list() return sdist.filelist.files
def run(self): self.formats = ["zip"] self.filelist = FileList() self.check_metadata() self.get_file_list() if self.manifest_only: return """ # converting character code into Shift-JIS import re for f in self.filelist.files: if not re.match('OpenRTM_aist.*\.py$', f): continue convert_file_code(f, "shift_jis", "\r\n", "euc_jp") """ self.make_distribution() """
def run(self): # try to run swig self.swig_name = None for swig_name in ('swig', 'swig1.3'): try: # should do a version check self.spawn([swig_name, '-version']) self.swig_name = swig_name if not check_swig_version(swig_name): handle_wrong_swig_version() self.swig_name = None break except: pass # if brain dead spawn doesn't work... if self.swig_name is None: for swig_name in ('swig', 'swig1.3'): try: r = os.system("%s -version" % swig_name) except: r == 99999999 if r == 256: self.swig_name = swig_name if not check_swig_version(swig_name): handle_wrong_swig_version() # found the swig name, stop checking. break if self.swig_name is None: self.warn( "Can't find SWIG, will just have to do with the existing wrapper source." ) else: self.mkpath('src/interface') self.mkpath('src/shadow') interfaces = [] f = FileList() f.findall('interface') f.process_template_line('global-include *.i') f.files.sort() for file in f.files: interfaces.append( string.join( string.split(os.path.splitext(file)[0], os.sep)[1:], '.')) interfaces.sort() for full_module_name in interfaces: self.swig(full_module_name)
def test_debug_print(self): file_list = FileList() with captured_stdout() as stdout: file_list.debug_print('xxx') self.assertEqual(stdout.getvalue(), '') debug.DEBUG = True try: with captured_stdout() as stdout: file_list.debug_print('xxx') self.assertEqual(stdout.getvalue(), 'xxx\n') finally: debug.DEBUG = False
def run(self): """The primary driver for the documentation-building system """ ## Build our Java class-path value paths = [] for (variable,jarName, packageName) in [ ("SAXON_HOME", "saxon.jar", "Saxon XSL Processor"), ("RESOLVER_HOME","resolver.jar", "Sun Resolver XML Package"), ]: if not os.environ.has_key(variable): self.warn( """Could not find %(variable)s environmental variable. Install %(packageName)s and set environmental variable %(variable)s to point to the directory holding %(jarName)s. Aborting documentation generation."""%locals() ) return paths.append( os.path.join(os.environ[variable], jarName) ) # Add the docbook-xsl extensions os.path.join(DOCBOOK_XSL_HOME, 'extensions', 'saxon643.jar') for path in paths: if not os.path.isfile( path ): self.warn( """The class-path value %s does not appear to be a valid file, errors may result. Please check environmental variables."""%(path,) ) # Following puts the CatalogManager.properties file on the # path, though that doesn't seem to actually help much in # reducing reliance on networked files :( paths.append( DOCBOOK_DTD_HOME ) self.cp = string.join( paths, os.pathsep ) f = FileList() f.findall('doc') f.process_template_line('global-include *.xml') manualTemp = os.path.join('build', 'doc', 'manual.xml') self.make_file( f.files, manualTemp, self.merge_doc, ( os.path.join('doc', 'manual', 'manual.xml'), manualTemp, ), exec_msg = 'Merging manpages and Python-specific documentation', skip_msg = 'Manpages already merged with Python-specific documentation' ) for format in self.formats: name = 'run_' + format if hasattr(self, name): self.announce( """Building format %s"""%( format,)) getattr(self, name)() else: self.announce( """No support available for format %s"""%( format,))
def copydir_run_2to3(src, dest, template=None, fixer_names=None, options=None, explicit=None): """Recursively copy a directory, only copying new and changed files, running run_2to3 over all newly copied Python modules afterward. If you give a template string, it's parsed like a MANIFEST.in. """ from distutils.dir_util import mkpath from distutils.file_util import copy_file from distutils.filelist import FileList filelist = FileList() curdir = os.getcwd() os.chdir(src) try: filelist.findall() finally: os.chdir(curdir) filelist.files[:] = filelist.allfiles if template: for line in template.splitlines(): line = line.strip() if not line: continue filelist.process_template_line(line) copied = [] for filename in filelist.files: outname = os.path.join(dest, filename) mkpath(os.path.dirname(outname)) res = copy_file(os.path.join(src, filename), outname, update=1) if res[1]: copied.append(outname) run_2to3( [fn for fn in copied if fn.lower().endswith(".py")], fixer_names=fixer_names, options=options, explicit=explicit, ) return copied
def run_htmlhelp(self): """Generate MS HTMLHelp documentation""" self.make_file(['build/doc/manual.xml'], 'build/doc/htmlhelp/index.html', self.gen_html, ('build/doc/htmlhelp', 'build/doc/htmlhelp', 'htmlhelp.xsl')) self.mkpath('build/doc/htmlhelp') for file in ('manual.hhp', 'manual.hhc'): if os.path.exists(file): x = open(file).read() ## x = string.replace(x, 'build/doc/htmlhelp_raw/', '') x = string.replace(x, 'build/doc/htmlhelp/', '') open(os.path.join('build', 'doc', 'htmlhelp', file), 'w').write(x) os.remove(file) # self.move_file('manual.hhp', 'build/doc/htmlhelp') # self.move_file('toc.hhc', 'build/doc/htmlhelp') ## self.make_file(['build/doc/htmlhelp_raw/index.html'], ## 'build/doc/htmlhelp/index.html', ## self.xform_html, ## ('build/doc/htmlhelp_raw', 'build/doc/htmlhelp')) self.copy_file('doc/misc/style.css', 'build/doc/htmlhelp') self.copy_file('doc/misc/greypinstripe.png', 'build/doc/htmlhelp') f = FileList() f.findall('build/doc/htmlhelp') f.process_template_line('global-include *') self.make_file(f.files, 'build/doc/htmlhelp/manual.chm', self.hhc, ()) self.copy_file('build/doc/htmlhelp/manual.chm', 'OpenGL/doc')
#!/usr/bin/env python """Distutils setup file, used to install or test 'setuptools'""" import sys import os src_root = None if sys.version_info >= (3, ): tmp_src = os.path.join("build", "src") from distutils.filelist import FileList from distutils import dir_util, file_util, util, log log.set_verbosity(1) fl = FileList() for line in open("MANIFEST.in"): fl.process_template_line(line) dir_util.create_tree(tmp_src, fl.files) outfiles_2to3 = [] dist_script = os.path.join("build", "src", "distribute_setup.py") for f in fl.files: outf, copied = file_util.copy_file(f, os.path.join(tmp_src, f), update=1) if copied and outf.endswith(".py") and outf != dist_script: outfiles_2to3.append(outf) if copied and outf.endswith('api_tests.txt'): # XXX support this in distutils as well from lib2to3.main import main main( 'lib2to3.fixes', ['-wd', os.path.join(tmp_src, 'tests', 'api_tests.txt')]) util.run_2to3(outfiles_2to3)
class sdist(Command): description = 'create a source distribution (tarball, zip file, etc.)' def checking_metadata(self): """Callable used for the check sub-command. Placed here so user_options can view it""" return self.metadata_check user_options = [('template=', 't', 'name of manifest template file [default: MANIFEST.in]'), ('manifest=', 'm', 'name of manifest file [default: MANIFEST]'), ('use-defaults', None, 'include the default file set in the manifest [default; disable with --no-defaults]'), ('no-defaults', None, "don't include the default file set"), ('prune', None, 'specifically exclude files/directories that should not be distributed (build tree, RCS/CVS dirs, etc.) [default; disable with --no-prune]'), ('no-prune', None, "don't automatically exclude anything"), ('manifest-only', 'o', 'just regenerate the manifest and then stop (implies --force-manifest)'), ('force-manifest', 'f', 'forcibly regenerate the manifest and carry on as usual. Deprecated: now the manifest is always regenerated.'), ('formats=', None, 'formats for source distribution (comma-separated list)'), ('keep-temp', 'k', 'keep the distribution tree around after creating ' + 'archive file(s)'), ('dist-dir=', 'd', 'directory to put the source distribution archive(s) in [default: dist]'), ('metadata-check', None, 'Ensure that all required elements of meta-data are supplied. Warn if any missing. [default]'), ('owner=', 'u', 'Owner name used when creating a tar file [default: current user]'), ('group=', 'g', 'Group name used when creating a tar file [default: current group]')] boolean_options = ['use-defaults', 'prune', 'manifest-only', 'force-manifest', 'keep-temp', 'metadata-check'] help_options = [('help-formats', None, 'list available distribution formats', show_formats)] negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune'} default_format = {'posix': 'gztar', 'nt': 'zip'} sub_commands = [('check', checking_metadata)] def initialize_options(self): self.template = None self.manifest = None self.use_defaults = 1 self.prune = 1 self.manifest_only = 0 self.force_manifest = 0 self.formats = None self.keep_temp = 0 self.dist_dir = None self.archive_files = None self.metadata_check = 1 self.owner = None self.group = None return def finalize_options(self): if self.manifest is None: self.manifest = 'MANIFEST' if self.template is None: self.template = 'MANIFEST.in' self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise DistutilsPlatformError, "don't know how to create source distributions " + 'on platform %s' % os.name bad_format = archive_util.check_archive_formats(self.formats) if bad_format: raise DistutilsOptionError, "unknown archive format '%s'" % bad_format if self.dist_dir is None: self.dist_dir = 'dist' return def run(self): self.filelist = FileList() for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) self.get_file_list() if self.manifest_only: return self.make_distribution() def check_metadata(self): """Deprecated API.""" warn('distutils.command.sdist.check_metadata is deprecated, use the check command instead', PendingDeprecationWarning) check = self.distribution.get_command_obj('check') check.ensure_finalized() check.run() def get_file_list(self): """Figure out the list of files to include in the source distribution, and put it in 'self.filelist'. This might involve reading the manifest template (and writing the manifest), or just reading the manifest, or just using the default file set -- it all depends on the user's options. """ template_exists = os.path.isfile(self.template) if not template_exists and self._manifest_is_not_generated(): self.read_manifest() self.filelist.sort() self.filelist.remove_duplicates() return if not template_exists: self.warn(("manifest template '%s' does not exist " + '(using default file list)') % self.template) self.filelist.findall() if self.use_defaults: self.add_defaults() if template_exists: self.read_template() if self.prune: self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest() def add_defaults(self): """Add all the default files to self.filelist: - README or README.txt - setup.py - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. - all files defined as scripts. - all C sources listed as part of extensions or C libraries in the setup script (doesn't catch C headers!) Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ standards = [('README', 'README.txt'), self.distribution.script_name] for fn in standards: if isinstance(fn, tuple): alts = fn got_it = 0 for fn in alts: if os.path.exists(fn): got_it = 1 self.filelist.append(fn) break if not got_it: self.warn('standard file not found: should have one of ' + string.join(alts, ', ')) elif os.path.exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = filter(os.path.isfile, glob(pattern)) if files: self.filelist.extend(files) build_py = self.get_finalized_command('build_py') if self.distribution.has_pure_modules(): self.filelist.extend(build_py.get_source_files()) for pkg, src_dir, build_dir, filenames in build_py.data_files: for filename in filenames: self.filelist.append(os.path.join(src_dir, filename)) if self.distribution.has_data_files(): for item in self.distribution.data_files: if isinstance(item, str): item = convert_path(item) if os.path.isfile(item): self.filelist.append(item) else: dirname, filenames = item for f in filenames: f = convert_path(f) if os.path.isfile(f): self.filelist.append(f) if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) def read_template(self): """Read and parse manifest template file named by self.template. (usually "MANIFEST.in") The parsing and processing is done by 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) template = TextFile(self.template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) try: while 1: line = template.readline() if line is None: break try: self.filelist.process_template_line(line) except (DistutilsTemplateError, ValueError) as msg: self.warn('%s, line %d: %s' % (template.filename, template.current_line, msg)) finally: template.close() return def prune_file_list(self): """Prune off branches that might slip into the file list as created by 'read_template()', but really don't belong there: * the build tree (typically "build") * the release tree itself (only an issue if we ran "sdist" previously with --keep-temp, or it aborted) * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories """ build = self.get_finalized_command('build') base_dir = self.distribution.get_fullname() self.filelist.exclude_pattern(None, prefix=build.build_base) self.filelist.exclude_pattern(None, prefix=base_dir) if sys.platform == 'win32': seps = '/|\\\\' else: seps = '/' vcs_dirs = ['RCS', 'CVS', '\\.svn', '\\.hg', '\\.git', '\\.bzr', '_darcs'] vcs_ptrn = '(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) return 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._manifest_is_not_generated(): 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') self.execute(file_util.write_file, (self.manifest, content), "writing manifest file '%s'" % self.manifest) def _manifest_is_not_generated(self): if not os.path.isfile(self.manifest): return False fp = open(self.manifest, 'rU') try: first_line = fp.readline() finally: fp.close() return first_line != '# file GENERATED by distutils, do NOT edit\n' def read_manifest(self): """Read the manifest file (named by 'self.manifest') and use it to fill in 'self.filelist', the list of files to include in the source distribution. """ log.info("reading manifest file '%s'", self.manifest) manifest = open(self.manifest) for line in manifest: line = line.strip() if line.startswith('#') or not line: continue self.filelist.append(line) manifest.close() def make_release_tree(self, base_dir, files): """Create the directory tree that will become the source distribution archive. All directories implied by the filenames in 'files' are created under 'base_dir', and then we hard link or copy (if hard linking is unavailable) those files into place. Essentially, this duplicates the developer's source tree, but in a directory named after the distribution, containing only the files to be distributed. """ self.mkpath(base_dir) dir_util.create_tree(base_dir, files, dry_run=self.dry_run) if hasattr(os, 'link'): link = 'hard' msg = 'making hard links in %s...' % base_dir else: link = None msg = 'copying files to %s...' % base_dir if not files: log.warn('no files to distribute -- empty manifest?') else: log.info(msg) for file in files: if not os.path.isfile(file): log.warn("'%s' not a regular file -- skipping" % file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) self.distribution.metadata.write_pkg_info(base_dir) return def make_distribution(self): """Create the source distribution(s). First, we create the release tree with 'make_release_tree()'; then, we create all required archive files (according to 'self.formats') from the release tree. Finally, we clean up by blowing away the release tree (unless 'self.keep_temp' is true). The list of archive files created is stored so it can be retrieved later by 'get_archive_files()'. """ base_dir = self.distribution.get_fullname() base_name = os.path.join(self.dist_dir, base_dir) self.make_release_tree(base_dir, self.filelist.files) archive_files = [] if 'tar' in self.formats: self.formats.append(self.formats.pop(self.formats.index('tar'))) for fmt in self.formats: file = self.make_archive(base_name, fmt, base_dir=base_dir, owner=self.owner, group=self.group) archive_files.append(file) self.distribution.dist_files.append(('sdist', '', file)) self.archive_files = archive_files if not self.keep_temp: dir_util.remove_tree(base_dir, dry_run=self.dry_run) def get_archive_files(self): """Return the list of archive files created when the command was run, or None if the command hasn't run yet. """ return self.archive_files
class spa (Command): description = "create a source distribution (tarball, zip file, etc.)" user_options = [ ('template=', 't', "name of manifest template file [default: MANIFEST.in]"), ('manifest=', 'm', "name of manifest file [default: MANIFEST]"), ('use-defaults', None, "include the default file set in the manifest " "[default; disable with --no-defaults]"), ('no-defaults', None, "don't include the default file set"), ('prune', None, "specifically exclude files/directories that should not be " "distributed (build tree, RCS/CVS dirs, etc.) " "[default; disable with --no-prune]"), ('no-prune', None, "don't automatically exclude anything"), ('manifest-only', 'o', "just regenerate the manifest and then stop " "(implies --force-manifest)"), ('force-manifest', 'f', "forcibly regenerate the manifest and carry on as usual"), ('formats=', None, "formats for source distribution (comma-separated list)"), ('keep-temp', 'k', "keep the distribution tree around after creating " + "archive file(s)"), ('dist-dir=', 'd', "directory to put the source distribution archive(s) in " "[default: dist]"), ] boolean_options = ['use-defaults', 'prune', 'manifest-only', 'force-manifest', 'keep-temp'] help_options = [ ('help-formats', None, "list available distribution formats", show_formats), ] negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune' } default_format = { 'posix': 'gztar', 'nt': 'zip' } def initialize_options (self): # 'template' and 'manifest' are, respectively, the names of # the manifest template and manifest file. self.template = None self.manifest = None # 'use_defaults': if true, we will include the default file set # in the manifest self.use_defaults = 1 self.prune = 1 self.manifest_only = 0 self.force_manifest = 0 self.formats = None self.keep_temp = 0 self.dist_dir = None self.archive_files = None def finalize_options (self): if self.manifest is None: self.manifest = "MANIFEST" if self.template is None: self.template = "MANIFEST.in" self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise DistutilsPlatformError, \ "don't know how to create source distributions " + \ "on platform %s" % os.name bad_format = archive_util.check_archive_formats(self.formats) if bad_format: raise DistutilsOptionError, \ "unknown archive format '%s'" % bad_format if self.dist_dir is None: self.dist_dir = "dist" def run (self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Ensure that all required meta-data is given; warn if not (but # don't die, it's not *that* serious!) self.check_metadata() # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution() def check_metadata (self): """Ensure that all required elements of meta-data (name, version, URL, (author and author_email) or (maintainer and maintainer_email)) are supplied by the Distribution object; warn if any are missing. """ metadata = self.distribution.metadata missing = [] for attr in ('name', 'version', 'url'): if not (hasattr(metadata, attr) and getattr(metadata, attr)): missing.append(attr) if missing: self.warn("missing required meta-data: " + string.join(missing, ", ")) if metadata.author: if not metadata.author_email: self.warn("missing meta-data: if 'author' supplied, " + "'author_email' must be supplied too") elif metadata.maintainer: if not metadata.maintainer_email: self.warn("missing meta-data: if 'maintainer' supplied, " + "'maintainer_email' must be supplied too") else: self.warn("missing meta-data: either (author and author_email) " + "or (maintainer and maintainer_email) " + "must be supplied") # check_metadata () def get_file_list (self): """Figure out the list of files to include in the source distribution, and put it in 'self.filelist'. This might involve reading the manifest template (and writing the manifest), or just reading the manifest, or just using the default file set -- it all depends on the user's options and the state of the filesystem. """ # If we have a manifest template, see if it's newer than the # manifest; if so, we'll regenerate the manifest. template_exists = os.path.isfile(self.template) if template_exists: template_newer = dep_util.newer(self.template, self.manifest) # The contents of the manifest file almost certainly depend on the # setup script as well as the manifest template -- so if the setup # script is newer than the manifest, we'll regenerate the manifest # from the template. (Well, not quite: if we already have a # manifest, but there's no template -- which will happen if the # developer elects to generate a manifest some other way -- then we # can't regenerate the manifest, so we don't.) self.debug_print("checking if %s newer than %s" % (self.distribution.script_name, self.manifest)) setup_newer = dep_util.newer(self.distribution.script_name, self.manifest) # cases: # 1) no manifest, template exists: generate manifest # (covered by 2a: no manifest == template newer) # 2) manifest & template exist: # 2a) template or setup script newer than manifest: # regenerate manifest # 2b) manifest newer than both: # do nothing (unless --force or --manifest-only) # 3) manifest exists, no template: # do nothing (unless --force or --manifest-only) # 4) no manifest, no template: generate w/ warning ("defaults only") manifest_outofdate = (template_exists and (template_newer or setup_newer)) force_regen = self.force_manifest or self.manifest_only manifest_exists = os.path.isfile(self.manifest) neither_exists = (not template_exists and not manifest_exists) # Regenerate the manifest if necessary (or if explicitly told to) if manifest_outofdate or neither_exists or force_regen: if not template_exists: self.warn(("manifest template '%s' does not exist " + "(using default file list)") % self.template) self.filelist.findall() if self.use_defaults: self.add_defaults() if template_exists: self.read_template() if self.prune: self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest() # Don't regenerate the manifest, just read it in. else: self.read_manifest() # get_file_list () def add_defaults (self): """Add all the default files to self.filelist: - README or README.txt - setup.py - test/test*.py - all pure Python modules mentioned in setup script - all C sources listed as part of extensions or C libraries in the setup script (doesn't catch C headers!) Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ standards = [('README', 'README.txt'), self.distribution.script_name] for fn in standards: # XXX if fn == 'setup.py': continue # We don't want setup.py if type(fn) is TupleType: alts = fn got_it = 0 for fn in alts: if os.path.exists(fn): got_it = 1 self.filelist.append(fn) break if not got_it: self.warn("standard file not found: should have one of " + string.join(alts, ', ')) else: if os.path.exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = filter(os.path.isfile, glob(pattern)) if files: self.filelist.extend(files) if self.distribution.has_pure_modules(): build_py = self.get_finalized_command('build_py') self.filelist.extend(build_py.get_source_files()) if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) # add_defaults () def read_template (self): """Read and parse manifest template file named by self.template. (usually "MANIFEST.in") The parsing and processing is done by 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) template = TextFile(self.template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) while 1: line = template.readline() if line is None: # end of file break try: self.filelist.process_template_line(line) except DistutilsTemplateError, msg: self.warn("%s, line %d: %s" % (template.filename, template.current_line, msg))
def copy_transformed_tree(self, install_specs, dst_root=None, src_root=None, substitutions={}): """ Copy parts of a source tree to a destination tree with a different tree structure and/or names. The basic idea: given a set of source files, copy them to a destination directory, let's call this operation an install_spec. A sequence of install_spec's allows one to build up the destrination tree in any structure desired. Each install_spec consists of 3 components (manifest_template, dst_xforms, dst_dir): The manifest_template is a sequence where each item is identical to a line in the MANIFEST.in template described in distutils. This gives you ability to easily specify a set of source files in a compact abstract manner (with recursion, exclusion, etc.) The manifest_template yields a sequence of source paths. dst_xforms is a sequence of regular expression substitutions applied to the each source path to yield a rewritten destination path. Each transform is expressed as a two-valued sequence (pattern, replacement) dst_dir is a destination directory where the destinations paths are written to. dst_dir is always relative to the dst_root. All input may be parametrized via variable substitutions supplied by a substitution dict. Any use of $name will cause name to be looked up first in the substitution dict and then if its not found there in the enviorment. If found it will be replaced with it's value. The pseudo code algorithm for processing an install_spec is: substitute all variables in manifest template src_list = evaluate manifest template for each src_path in src_list: dst_path = src_path for each xform in dst_xform: apply xform to dst_path copy src_root+src_path to dst_root+dest_dir+dest_path This process is repeated for each install spec. The src_root and dst_root are also subject to variable substitution. Examples: Copy all text files in build/doc to doc: copy_transformed_tree([[["include build/doc *.txt"], None, 'doc']]) Copy all html files found under build to doc/html and change the extension from .html to .htm copy_transformed_tree([[["include build *.html"], [('\.html$','.htm')], 'doc']]) """ if src_root is not None: src_root = subst_vars(src_root, substitutions) if dst_root is not None: dst_root = subst_vars(dst_root, substitutions) filelist = FileList() if src_root is None: filelist.findall() else: filelist.findall(src_root) for manifest_template, dst_xforms, dst_dir in install_specs: if dst_dir is not None: dst_dir = subst_vars(dst_dir, substitutions) filelist.files = [] # reinitialize to empty for line in manifest_template: filelist.process_template_line(subst_vars(line, substitutions)) for src_path in filelist.files: dst_path = src_path if dst_xforms: for dst_xform in dst_xforms: dst_path = re.sub(dst_xform[0], dst_xform[1], dst_path) if dst_dir is not None: dst_path = change_root(dst_dir, dst_path) if dst_root is None: full_dst_path = dst_path else: full_dst_path = change_root(dst_root, dst_path) full_dst_dir = os.path.dirname(full_dst_path) self.mkpath(full_dst_dir) self.copy_file(src_path, full_dst_path)
class sdist(Command): description = "create a source distribution (tarball, zip file, etc.)" user_options = [ ('template=', 't', "name of manifest template file [default: MANIFEST.in]"), ('manifest=', 'm', "name of manifest file [default: MANIFEST]"), ('use-defaults', None, "include the default file set in the manifest " "[default; disable with --no-defaults]"), ('no-defaults', None, "don't include the default file set"), ('prune', None, "specifically exclude files/directories that should not be " "distributed (build tree, RCS/CVS dirs, etc.) " "[default; disable with --no-prune]"), ('no-prune', None, "don't automatically exclude anything"), ('manifest-only', 'o', "just regenerate the manifest and then stop " "(implies --force-manifest)"), ('force-manifest', 'f', "forcibly regenerate the manifest and carry on as usual"), ('formats=', None, "formats for source distribution (comma-separated list)"), ('keep-temp', 'k', "keep the distribution tree around after creating " + "archive file(s)"), ('dist-dir=', 'd', "directory to put the source distribution archive(s) in " "[default: dist]"), ] boolean_options = [ 'use-defaults', 'prune', 'manifest-only', 'force-manifest', 'keep-temp' ] help_options = [ ('help-formats', None, "list available distribution formats", show_formats), ] negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune'} default_format = {'posix': 'gztar', 'java': 'gztar', 'nt': 'zip'} def initialize_options(self): # 'template' and 'manifest' are, respectively, the names of # the manifest template and manifest file. self.template = None self.manifest = None # 'use_defaults': if true, we will include the default file set # in the manifest self.use_defaults = 1 self.prune = 1 self.manifest_only = 0 self.force_manifest = 0 self.formats = None self.keep_temp = 0 self.dist_dir = None self.archive_files = None def finalize_options(self): if self.manifest is None: self.manifest = "MANIFEST" if self.template is None: self.template = "MANIFEST.in" self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise DistutilsPlatformError("don't know how to create source distributions " + \ "on platform %s" % os.name) bad_format = archive_util.check_archive_formats(self.formats) if bad_format: raise DistutilsOptionError("unknown archive format '%s'" % bad_format) if self.dist_dir is None: self.dist_dir = "dist" def run(self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Ensure that all required meta-data is given; warn if not (but # don't die, it's not *that* serious!) self.check_metadata() # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution() def check_metadata(self): """Ensure that all required elements of meta-data (name, version, URL, (author and author_email) or (maintainer and maintainer_email)) are supplied by the Distribution object; warn if any are missing. """ metadata = self.distribution.metadata missing = [] for attr in ('name', 'version', 'url'): if not (hasattr(metadata, attr) and getattr(metadata, attr)): missing.append(attr) if missing: self.warn("missing required meta-data: " + string.join(missing, ", ")) if metadata.author: if not metadata.author_email: self.warn("missing meta-data: if 'author' supplied, " + "'author_email' must be supplied too") elif metadata.maintainer: if not metadata.maintainer_email: self.warn("missing meta-data: if 'maintainer' supplied, " + "'maintainer_email' must be supplied too") else: self.warn("missing meta-data: either (author and author_email) " + "or (maintainer and maintainer_email) " + "must be supplied") # check_metadata () def get_file_list(self): """Figure out the list of files to include in the source distribution, and put it in 'self.filelist'. This might involve reading the manifest template (and writing the manifest), or just reading the manifest, or just using the default file set -- it all depends on the user's options and the state of the filesystem. """ # If we have a manifest template, see if it's newer than the # manifest; if so, we'll regenerate the manifest. template_exists = os.path.isfile(self.template) if template_exists: template_newer = dep_util.newer(self.template, self.manifest) # The contents of the manifest file almost certainly depend on the # setup script as well as the manifest template -- so if the setup # script is newer than the manifest, we'll regenerate the manifest # from the template. (Well, not quite: if we already have a # manifest, but there's no template -- which will happen if the # developer elects to generate a manifest some other way -- then we # can't regenerate the manifest, so we don't.) self.debug_print("checking if %s newer than %s" % (self.distribution.script_name, self.manifest)) setup_newer = dep_util.newer(self.distribution.script_name, self.manifest) # cases: # 1) no manifest, template exists: generate manifest # (covered by 2a: no manifest == template newer) # 2) manifest & template exist: # 2a) template or setup script newer than manifest: # regenerate manifest # 2b) manifest newer than both: # do nothing (unless --force or --manifest-only) # 3) manifest exists, no template: # do nothing (unless --force or --manifest-only) # 4) no manifest, no template: generate w/ warning ("defaults only") manifest_outofdate = (template_exists and (template_newer or setup_newer)) force_regen = self.force_manifest or self.manifest_only manifest_exists = os.path.isfile(self.manifest) neither_exists = (not template_exists and not manifest_exists) # Regenerate the manifest if necessary (or if explicitly told to) if manifest_outofdate or neither_exists or force_regen: if not template_exists: self.warn(("manifest template '%s' does not exist " + "(using default file list)") % self.template) self.filelist.findall() if self.use_defaults: self.add_defaults() if template_exists: self.read_template() if self.prune: self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest() # Don't regenerate the manifest, just read it in. else: self.read_manifest() # get_file_list () def add_defaults(self): """Add all the default files to self.filelist: - README or README.txt - setup.py - test/test*.py - all pure Python modules mentioned in setup script - all C sources listed as part of extensions or C libraries in the setup script (doesn't catch C headers!) Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ standards = [('README', 'README.txt'), self.distribution.script_name] for fn in standards: if type(fn) is TupleType: alts = fn got_it = 0 for fn in alts: if os.path.exists(fn): got_it = 1 self.filelist.append(fn) break if not got_it: self.warn("standard file not found: should have one of " + string.join(alts, ', ')) else: if os.path.exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = list(filter(os.path.isfile, glob(pattern))) if files: self.filelist.extend(files) if self.distribution.has_pure_modules(): build_py = self.get_finalized_command('build_py') self.filelist.extend(build_py.get_source_files()) if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) # add_defaults () def read_template(self): """Read and parse manifest template file named by self.template. (usually "MANIFEST.in") The parsing and processing is done by 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) template = TextFile(self.template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) while 1: line = template.readline() if line is None: # end of file break try: self.filelist.process_template_line(line) except DistutilsTemplateError as msg: self.warn("%s, line %d: %s" % (template.filename, template.current_line, msg)) # read_template () def prune_file_list(self): """Prune off branches that might slip into the file list as created by 'read_template()', but really don't belong there: * the build tree (typically "build") * the release tree itself (only an issue if we ran "sdist" previously with --keep-temp, or it aborted) * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories """ build = self.get_finalized_command('build') base_dir = self.distribution.get_fullname() self.filelist.exclude_pattern(None, prefix=build.build_base) self.filelist.exclude_pattern(None, prefix=base_dir) self.filelist.exclude_pattern( r'(^|/)(RCS|CVS|\.svn|\.hg|\.git|\.bzr|_darcs)/.*', 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'. """ self.execute(file_util.write_file, (self.manifest, self.filelist.files), "writing manifest file '%s'" % self.manifest) # write_manifest () def read_manifest(self): """Read the manifest file (named by 'self.manifest') and use it to fill in 'self.filelist', the list of files to include in the source distribution. """ log.info("reading manifest file '%s'", self.manifest) manifest = open(self.manifest) try: while 1: line = manifest.readline() if line == '': # end of file break if line[-1] == '\n': line = line[0:-1] self.filelist.append(line) finally: manifest.close() # read_manifest () def make_release_tree(self, base_dir, files): """Create the directory tree that will become the source distribution archive. All directories implied by the filenames in 'files' are created under 'base_dir', and then we hard link or copy (if hard linking is unavailable) those files into place. Essentially, this duplicates the developer's source tree, but in a directory named after the distribution, containing only the files to be distributed. """ # Create all the directories under 'base_dir' necessary to # put 'files' there; the 'mkpath()' is just so we don't die # if the manifest happens to be empty. self.mkpath(base_dir) dir_util.create_tree(base_dir, files, dry_run=self.dry_run) # And walk over the list of files, either making a hard link (if # os.link exists) to each one that doesn't already exist in its # corresponding location under 'base_dir', or copying each file # that's out-of-date in 'base_dir'. (Usually, all files will be # out-of-date, because by default we blow away 'base_dir' when # we're done making the distribution archives.) if hasattr(os, 'link'): # can make hard links on this system link = 'hard' msg = "making hard links in %s..." % base_dir else: # nope, have to copy link = None msg = "copying files to %s..." % base_dir if not files: log.warn("no files to distribute -- empty manifest?") else: log.info(msg) for file in files: if not os.path.isfile(file): log.warn("'%s' not a regular file -- skipping" % file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) self.distribution.metadata.write_pkg_info(base_dir) # make_release_tree () def make_distribution(self): """Create the source distribution(s). First, we create the release tree with 'make_release_tree()'; then, we create all required archive files (according to 'self.formats') from the release tree. Finally, we clean up by blowing away the release tree (unless 'self.keep_temp' is true). The list of archive files created is stored so it can be retrieved later by 'get_archive_files()'. """ # Don't warn about missing meta-data here -- should be (and is!) # done elsewhere. base_dir = self.distribution.get_fullname() base_name = os.path.join(self.dist_dir, base_dir) self.make_release_tree(base_dir, self.filelist.files) archive_files = [] # remember names of files we create for fmt in self.formats: file = self.make_archive(base_name, fmt, base_dir=base_dir) archive_files.append(file) self.distribution.dist_files.append(('sdist', '', file)) self.archive_files = archive_files if not self.keep_temp: dir_util.remove_tree(base_dir, dry_run=self.dry_run) def get_archive_files(self): """Return the list of archive files created when the command was run, or None if the command hasn't run yet. """ return self.archive_files
class sdist(Command): description = "create a source distribution (tarball, zip file, etc.)" def checking_metadata(self): """Callable used for the check sub-command. Placed here so user_options can view it""" return self.metadata_check user_options = [ ('template=', 't', "name of manifest template file [default: MANIFEST.in]"), ('manifest=', 'm', "name of manifest file [default: MANIFEST]"), ('use-defaults', None, "include the default file set in the manifest " "[default; disable with --no-defaults]"), ('no-defaults', None, "don't include the default file set"), ('prune', None, "specifically exclude files/directories that should not be " "distributed (build tree, RCS/CVS dirs, etc.) " "[default; disable with --no-prune]"), ('no-prune', None, "don't automatically exclude anything"), ('manifest-only', 'o', "just regenerate the manifest and then stop " "(implies --force-manifest)"), ('force-manifest', 'f', "forcibly regenerate the manifest and carry on as usual. " "Deprecated: now the manifest is always regenerated."), ('formats=', None, "formats for source distribution (comma-separated list)"), ('keep-temp', 'k', "keep the distribution tree around after creating " + "archive file(s)"), ('dist-dir=', 'd', "directory to put the source distribution archive(s) in " "[default: dist]"), ('metadata-check', None, "Ensure that all required elements of meta-data " "are supplied. Warn if any missing. [default]"), ('owner=', 'u', "Owner name used when creating a tar file [default: current user]"), ('group=', 'g', "Group name used when creating a tar file [default: current group]"), ] boolean_options = ['use-defaults', 'prune', 'manifest-only', 'force-manifest', 'keep-temp', 'metadata-check'] help_options = [ ('help-formats', None, "list available distribution formats", show_formats), ] negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune' } sub_commands = [('check', checking_metadata)] READMES = ('README', 'README.txt', 'README.rst') def initialize_options(self): # 'template' and 'manifest' are, respectively, the names of # the manifest template and manifest file. self.template = None self.manifest = None # 'use_defaults': if true, we will include the default file set # in the manifest self.use_defaults = 1 self.prune = 1 self.manifest_only = 0 self.force_manifest = 0 self.formats = ['gztar'] self.keep_temp = 0 self.dist_dir = None self.archive_files = None self.metadata_check = 1 self.owner = None self.group = None def finalize_options(self): if self.manifest is None: self.manifest = "MANIFEST" if self.template is None: self.template = "MANIFEST.in" self.ensure_string_list('formats') bad_format = archive_util.check_archive_formats(self.formats) if bad_format: raise DistutilsOptionError( "unknown archive format '%s'" % bad_format) if self.dist_dir is None: self.dist_dir = "dist" def run(self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Run sub commands for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution() def check_metadata(self): """Deprecated API.""" warn("distutils.command.sdist.check_metadata is deprecated, \ use the check command instead", PendingDeprecationWarning) check = self.distribution.get_command_obj('check') check.ensure_finalized() check.run() def get_file_list(self): """Figure out the list of files to include in the source distribution, and put it in 'self.filelist'. This might involve reading the manifest template (and writing the manifest), or just reading the manifest, or just using the default file set -- it all depends on the user's options. """ # new behavior when using a template: # the file list is recalculated every time 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 with templates. template_exists = os.path.isfile(self.template) if not template_exists and self._manifest_is_not_generated(): self.read_manifest() self.filelist.sort() self.filelist.remove_duplicates() return if not template_exists: self.warn(("manifest template '%s' does not exist " + "(using default file list)") % self.template) self.filelist.findall() if self.use_defaults: self.add_defaults() if template_exists: self.read_template() if self.prune: self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest() def add_defaults(self): """Add all the default files to self.filelist: - README or README.txt - setup.py - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. - all files defined as scripts. - all C sources listed as part of extensions or C libraries in the setup script (doesn't catch C headers!) Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ self._add_defaults_standards() self._add_defaults_optional() self._add_defaults_python() self._add_defaults_data_files() self._add_defaults_ext() self._add_defaults_c_libs() self._add_defaults_scripts() @staticmethod def _cs_path_exists(fspath): """ Case-sensitive path existence check >>> sdist._cs_path_exists(__file__) True >>> sdist._cs_path_exists(__file__.upper()) False """ if not os.path.exists(fspath): return False # make absolute so we always have a directory abspath = os.path.abspath(fspath) directory, filename = os.path.split(abspath) return filename in os.listdir(directory) def _add_defaults_standards(self): standards = [self.READMES, self.distribution.script_name] for fn in standards: if isinstance(fn, tuple): alts = fn got_it = False for fn in alts: if self._cs_path_exists(fn): got_it = True self.filelist.append(fn) break if not got_it: self.warn("standard file not found: should have one of " + ', '.join(alts)) else: if self._cs_path_exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) def _add_defaults_optional(self): optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = filter(os.path.isfile, glob(pattern)) self.filelist.extend(files) def _add_defaults_python(self): # build_py is used to get: # - python modules # - files defined in package_data build_py = self.get_finalized_command('build_py') # getting python files if self.distribution.has_pure_modules(): self.filelist.extend(build_py.get_source_files()) # getting package_data files # (computed in build_py.data_files by build_py.finalize_options) for pkg, src_dir, build_dir, filenames in build_py.data_files: for filename in filenames: self.filelist.append(os.path.join(src_dir, filename)) def _add_defaults_data_files(self): # getting distribution.data_files if self.distribution.has_data_files(): for item in self.distribution.data_files: if isinstance(item, str): # plain file item = convert_path(item) if os.path.isfile(item): self.filelist.append(item) else: # a (dirname, filenames) tuple dirname, filenames = item for f in filenames: f = convert_path(f) if os.path.isfile(f): self.filelist.append(f) def _add_defaults_ext(self): if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) def _add_defaults_c_libs(self): if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) def _add_defaults_scripts(self): if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) def read_template(self): """Read and parse manifest template file named by self.template. (usually "MANIFEST.in") The parsing and processing is done by 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) template = TextFile(self.template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) try: while True: line = template.readline() if line is None: # end of file break try: self.filelist.process_template_line(line) # the call above can raise a DistutilsTemplateError for # malformed lines, or a ValueError from the lower-level # convert_path function except (DistutilsTemplateError, ValueError) as msg: self.warn("%s, line %d: %s" % (template.filename, template.current_line, msg)) finally: template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created by 'read_template()', but really don't belong there: * the build tree (typically "build") * the release tree itself (only an issue if we ran "sdist" previously with --keep-temp, or it aborted) * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories """ build = self.get_finalized_command('build') base_dir = self.distribution.get_fullname() self.filelist.exclude_pattern(None, prefix=build.build_base) self.filelist.exclude_pattern(None, prefix=base_dir) if sys.platform == 'win32': seps = r'/|\\' else: seps = '/' vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', '_darcs'] 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'. """ if self._manifest_is_not_generated(): 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') self.execute(file_util.write_file, (self.manifest, content), "writing manifest file '%s'" % self.manifest) def _manifest_is_not_generated(self): # check for special comment used in 3.1.3 and higher if not os.path.isfile(self.manifest): return False fp = open(self.manifest) try: first_line = fp.readline() finally: fp.close() return first_line != '# file GENERATED by distutils, do NOT edit\n' def read_manifest(self): """Read the manifest file (named by 'self.manifest') and use it to fill in 'self.filelist', the list of files to include in the source distribution. """ log.info("reading manifest file '%s'", self.manifest) manifest = open(self.manifest) for line in manifest: # ignore comments and blank lines line = line.strip() if line.startswith('#') or not line: continue self.filelist.append(line) manifest.close() def make_release_tree(self, base_dir, files): """Create the directory tree that will become the source distribution archive. All directories implied by the filenames in 'files' are created under 'base_dir', and then we hard link or copy (if hard linking is unavailable) those files into place. Essentially, this duplicates the developer's source tree, but in a directory named after the distribution, containing only the files to be distributed. """ # Create all the directories under 'base_dir' necessary to # put 'files' there; the 'mkpath()' is just so we don't die # if the manifest happens to be empty. self.mkpath(base_dir) dir_util.create_tree(base_dir, files, dry_run=self.dry_run) # And walk over the list of files, either making a hard link (if # os.link exists) to each one that doesn't already exist in its # corresponding location under 'base_dir', or copying each file # that's out-of-date in 'base_dir'. (Usually, all files will be # out-of-date, because by default we blow away 'base_dir' when # we're done making the distribution archives.) if hasattr(os, 'link'): # can make hard links on this system link = 'hard' msg = "making hard links in %s..." % base_dir else: # nope, have to copy link = None msg = "copying files to %s..." % base_dir if not files: log.warn("no files to distribute -- empty manifest?") else: log.info(msg) for file in files: if not os.path.isfile(file): log.warn("'%s' not a regular file -- skipping", file) else: dest = os.path.join(base_dir, file) self.copy_file(file, dest, link=link) self.distribution.metadata.write_pkg_info(base_dir) def make_distribution(self): """Create the source distribution(s). First, we create the release tree with 'make_release_tree()'; then, we create all required archive files (according to 'self.formats') from the release tree. Finally, we clean up by blowing away the release tree (unless 'self.keep_temp' is true). The list of archive files created is stored so it can be retrieved later by 'get_archive_files()'. """ # Don't warn about missing meta-data here -- should be (and is!) # done elsewhere. base_dir = self.distribution.get_fullname() base_name = os.path.join(self.dist_dir, base_dir) self.make_release_tree(base_dir, self.filelist.files) archive_files = [] # remember names of files we create # tar archive must be created last to avoid overwrite and remove if 'tar' in self.formats: self.formats.append(self.formats.pop(self.formats.index('tar'))) for fmt in self.formats: file = self.make_archive(base_name, fmt, base_dir=base_dir, owner=self.owner, group=self.group) archive_files.append(file) self.distribution.dist_files.append(('sdist', '', file)) self.archive_files = archive_files if not self.keep_temp: dir_util.remove_tree(base_dir, dry_run=self.dry_run) def get_archive_files(self): """Return the list of archive files created when the command was run, or None if the command hasn't run yet. """ return self.archive_files
class sdist(Command): description = "create a source distribution (tarball, zip file, etc.)" def checking_metadata(self): """Callable used for the check sub-command. Placed here so user_options can view it""" return self.metadata_check user_options = [ ('template=', 't', "name of manifest template file [default: MANIFEST.in]"), ('manifest=', 'm', "name of manifest file [default: MANIFEST]"), ('use-defaults', None, "include the default file set in the manifest " "[default; disable with --no-defaults]"), ('no-defaults', None, "don't include the default file set"), ('prune', None, "specifically exclude files/directories that should not be " "distributed (build tree, RCS/CVS dirs, etc.) " "[default; disable with --no-prune]"), ('no-prune', None, "don't automatically exclude anything"), ('manifest-only', 'o', "just regenerate the manifest and then stop " "(implies --force-manifest)"), ('force-manifest', 'f', "forcibly regenerate the manifest and carry on as usual. " "Deprecated: now the manifest is always regenerated."), ('formats=', None, "formats for source distribution (comma-separated list)"), ('keep-temp', 'k', "keep the distribution tree around after creating " + "archive file(s)"), ('dist-dir=', 'd', "directory to put the source distribution archive(s) in " "[default: dist]"), ('medata-check', None, "Ensure that all required elements of meta-data " "are supplied. Warn if any missing. [default]"), ('owner=', 'u', "Owner name used when creating a tar file [default: current user]"), ('group=', 'g', "Group name used when creating a tar file [default: current group]"), ] boolean_options = [ 'use-defaults', 'prune', 'manifest-only', 'force-manifest', 'keep-temp', 'metadata-check' ] help_options = [ ('help-formats', None, "list available distribution formats", show_formats), ] negative_opt = {'no-defaults': 'use-defaults', 'no-prune': 'prune'} default_format = {'posix': 'gztar', 'nt': 'zip'} sub_commands = [('check', checking_metadata)] def initialize_options(self): # 'template' and 'manifest' are, respectively, the names of # the manifest template and manifest file. self.template = None self.manifest = None # 'use_defaults': if true, we will include the default file set # in the manifest self.use_defaults = 1 self.prune = 1 self.manifest_only = 0 self.force_manifest = 0 self.formats = None self.keep_temp = 0 self.dist_dir = None self.archive_files = None self.metadata_check = 1 self.owner = None self.group = None def finalize_options(self): if self.manifest is None: self.manifest = "MANIFEST" if self.template is None: self.template = "MANIFEST.in" self.ensure_string_list('formats') if self.formats is None: try: self.formats = [self.default_format[os.name]] except KeyError: raise DistutilsPlatformError, \ "don't know how to create source distributions " + \ "on platform %s" % os.name bad_format = archive_util.check_archive_formats(self.formats) if bad_format: raise DistutilsOptionError, \ "unknown archive format '%s'" % bad_format if self.dist_dir is None: self.dist_dir = "dist" def run(self): # 'filelist' contains the list of files that will make up the # manifest self.filelist = FileList() # Run sub commands for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) # Do whatever it takes to get the list of files to process # (process the manifest template, read an existing manifest, # whatever). File list is accumulated in 'self.filelist'. self.get_file_list() # If user just wanted us to regenerate the manifest, stop now. if self.manifest_only: return # Otherwise, go ahead and create the source distribution tarball, # or zipfile, or whatever. self.make_distribution() def check_metadata(self): """Deprecated API.""" warn( "distutils.command.sdist.check_metadata is deprecated, \ use the check command instead", PendingDeprecationWarning) check = self.distribution.get_command_obj('check') check.ensure_finalized() check.run() def get_file_list(self): """Figure out the list of files to include in the source distribution, and put it in 'self.filelist'. This might involve reading the manifest template (and writing the manifest), or just reading the manifest, or just using the default file set -- it all depends on the user's options. """ # new behavior: # 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. template_exists = os.path.isfile(self.template) if not template_exists: self.warn(("manifest template '%s' does not exist " + "(using default file list)") % self.template) self.filelist.findall() if self.use_defaults: self.add_defaults() if template_exists: self.read_template() if self.prune: self.prune_file_list() self.filelist.sort() self.filelist.remove_duplicates() self.write_manifest() def add_defaults(self): """Add all the default files to self.filelist: - README or README.txt - setup.py - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. - all files defined as scripts. - all C sources listed as part of extensions or C libraries in the setup script (doesn't catch C headers!) Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ standards = [('README', 'README.txt'), self.distribution.script_name] for fn in standards: if isinstance(fn, tuple): alts = fn got_it = 0 for fn in alts: if os.path.exists(fn): got_it = 1 self.filelist.append(fn) break if not got_it: self.warn("standard file not found: should have one of " + string.join(alts, ', ')) else: if os.path.exists(fn): self.filelist.append(fn) else: self.warn("standard file '%s' not found" % fn) optional = ['test/test*.py', 'setup.cfg'] for pattern in optional: files = filter(os.path.isfile, glob(pattern)) if files: self.filelist.extend(files) # build_py is used to get: # - python modules # - files defined in package_data build_py = self.get_finalized_command('build_py') # getting python files if self.distribution.has_pure_modules(): self.filelist.extend(build_py.get_source_files()) # getting package_data files # (computed in build_py.data_files by build_py.finalize_options) for pkg, src_dir, build_dir, filenames in build_py.data_files: for filename in filenames: self.filelist.append(os.path.join(src_dir, filename)) # getting distribution.data_files if self.distribution.has_data_files(): for item in self.distribution.data_files: if isinstance(item, str): # plain file item = convert_path(item) if os.path.isfile(item): self.filelist.append(item) else: # a (dirname, filenames) tuple dirname, filenames = item for f in filenames: f = convert_path(f) if os.path.isfile(f): self.filelist.append(f) if self.distribution.has_ext_modules(): build_ext = self.get_finalized_command('build_ext') self.filelist.extend(build_ext.get_source_files()) if self.distribution.has_c_libraries(): build_clib = self.get_finalized_command('build_clib') self.filelist.extend(build_clib.get_source_files()) if self.distribution.has_scripts(): build_scripts = self.get_finalized_command('build_scripts') self.filelist.extend(build_scripts.get_source_files()) def read_template(self): """Read and parse manifest template file named by self.template. (usually "MANIFEST.in") The parsing and processing is done by 'self.filelist', which updates itself accordingly. """ log.info("reading manifest template '%s'", self.template) template = TextFile(self.template, strip_comments=1, skip_blanks=1, join_lines=1, lstrip_ws=1, rstrip_ws=1, collapse_join=1) while 1: line = template.readline() if line is None: # end of file break try: self.filelist.process_template_line(line) except DistutilsTemplateError, msg: self.warn("%s, line %d: %s" % (template.filename, template.current_line, msg))