def check_cfg_files(cfg_files, module_name): """check if the configuration files actually specify something If config files are given, give warning if they don't contain information. This may indicate a wrong module name name, for example. """ cfg = ConfigParser.SafeConfigParser() cfg.read(cfg_files) if cfg.has_section(module_name): section_items = cfg.items(module_name) else: section_items = [] default_items = cfg.items('DEFAULT') n_items = len(section_items) + len(default_items) if n_items == 0: log.warn('configuration files were specified, but no options were ' 'found in "%s" or "DEFAULT" sections.' % (module_name, ))
def check_cfg_files(cfg_files,module_name): """check if the configuration files actually specify something If config files are given, give warning if they don't contain information. This may indicate a wrong module name name, for example. """ cfg = ConfigParser.SafeConfigParser() cfg.read(cfg_files) if cfg.has_section(module_name): section_items = cfg.items(module_name) else: section_items = [] default_items = cfg.items('DEFAULT') n_items = len(section_items) + len(default_items) if n_items==0: log.warn('configuration files were specified, but no options were ' 'found in "%s" or "DEFAULT" sections.' % (module_name,) )
def _make_cfg_defaults( self, module_name=NotGiven, default_distribution=NotGiven, guess_maintainer=NotGiven, ): defaults = {} default_re = re.compile(r'^.* \(Default: (.*)\)$') for longopt, shortopt, description in stdeb_cfg_options: assert longopt.endswith('=') assert longopt.lower() == longopt key = longopt[:-1] matchobj = default_re.search(description) if matchobj is not None: # has a default value groups = matchobj.groups() assert len(groups) == 1 value = groups[0] # A few special cases if value == '<source-debianized-setup-name>': assert key == 'source' value = source_debianize_name(module_name) elif value == 'python-<debianized-setup-name>': assert key == 'package' value = 'python-' + debianize_name(module_name) elif value == '<setup-maintainer-or-author>': assert key == 'maintainer' value = guess_maintainer if key == 'suite': if default_distribution is not None: value = default_distribution log.warn('Deprecation warning: you are using the ' '--default-distribution option. ' 'Switch to the --suite option.') else: # no default value value = '' defaults[key] = value return defaults
def run(self): ############################################### # 1. setup initial variables # A. create config defaults module_name = self.distribution.get_name() if 1: # set default maintainer if ( self.distribution.get_maintainer() != "UNKNOWN" and self.distribution.get_maintainer_email() != "UNKNOWN" ): guess_maintainer = "%s <%s>" % ( self.distribution.get_maintainer(), self.distribution.get_maintainer_email(), ) elif self.distribution.get_author() != "UNKNOWN" and self.distribution.get_author_email() != "UNKNOWN": guess_maintainer = "%s <%s>" % (self.distribution.get_author(), self.distribution.get_author_email()) else: guess_maintainer = "unknown <unknown@unknown>" if self.default_maintainer is not None: log.warn( "Deprecation warning: you are using the " "--default-maintainer option. " "Switch to the --maintainer option." ) guess_maintainer = self.default_maintainer # B. find config files (if any) cfg_files = [] if self.extra_cfg_file is not None: cfg_files.append(self.extra_cfg_file) use_setuptools = True try: ei_cmd = self.distribution.get_command_obj("egg_info") except DistutilsModuleError, err: use_setuptools = False
def _make_cfg_defaults(self, module_name=NotGiven, default_distribution=NotGiven, guess_maintainer=NotGiven, ): defaults = {} default_re = re.compile(r'^.* \(Default: (.*)\)$') for longopt,shortopt,description in stdeb_cfg_options: assert longopt.endswith('=') assert longopt.lower() == longopt key = longopt[:-1] matchobj = default_re.search( description ) if matchobj is not None: # has a default value groups = matchobj.groups() assert len(groups)==1 value = groups[0] # A few special cases if value == '<source-debianized-setup-name>': assert key=='source' value = source_debianize_name(module_name) elif value == 'python-<debianized-setup-name>': assert key=='package' value = 'python-' + debianize_name(module_name) elif value == '<setup-maintainer-or-author>': assert key=='maintainer' value = guess_maintainer if key=='suite': if default_distribution is not None: value = default_distribution log.warn('Deprecation warning: you are using the ' '--default-distribution option. ' 'Switch to the --suite option.') else: # no default value value = '' defaults[key] = value return defaults
def get_debinfo(self): ############################################### # 1. setup initial variables # A. create config defaults module_name = self.distribution.get_name() if 1: # set default maintainer if (self.distribution.get_maintainer() != 'UNKNOWN' and self.distribution.get_maintainer_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>" % ( self.distribution.get_maintainer(), self.distribution.get_maintainer_email()) elif (self.distribution.get_author() != 'UNKNOWN' and self.distribution.get_author_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>" % ( self.distribution.get_author(), self.distribution.get_author_email()) else: guess_maintainer = "unknown <unknown@unknown>" if self.default_maintainer is not None: log.warn('Deprecation warning: you are using the ' '--default-maintainer option. ' 'Switch to the --maintainer option.') guess_maintainer = self.default_maintainer # B. find config files (if any) cfg_files = [] if self.extra_cfg_file is not None: cfg_files.append(self.extra_cfg_file) use_setuptools = True try: ei_cmd = self.distribution.get_command_obj('egg_info') except DistutilsModuleError, err: use_setuptools = False
def run(self): debinfo = self.get_debinfo() if debinfo.patch_file != '' and self.patch_already_applied: raise RuntimeError('A patch was already applied, but another ' 'patch is requested.') ############################################### # 2. Build source tree and rename it to be in self.dist_dir # A. create source archive in new directory repackaged_dirname = debinfo.source+'-'+debinfo.upstream_version fullpath_repackaged_dirname = os.path.join(self.dist_dir, repackaged_dirname) source_tarball = None cleanup_dirs = [] exclude_dirs = ['.svn', '.git'] # copy source tree if os.path.exists(fullpath_repackaged_dirname): shutil.rmtree(fullpath_repackaged_dirname) os.makedirs(fullpath_repackaged_dirname) orig_dir = os.path.abspath(os.curdir) for src in os.listdir(orig_dir): if src not in exclude_dirs+[self.dist_dir,'build','dist']: dst = os.path.join(fullpath_repackaged_dirname,src) if os.path.isdir(src): shutil.copytree(src, dst, symlinks=True) else: shutil.copy2(src, dst ) # remove .pyc files which dpkg-source cannot package for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): fullpath = os.path.join(root,name) os.unlink(fullpath) for name in dirs: if name in exclude_dirs: fullpath = os.path.join(root,name) shutil.rmtree(fullpath) if self.use_premade_distfile is not None: # ensure premade sdist can actually be used self.use_premade_distfile = os.path.abspath(self.use_premade_distfile) expand_dir = os.path.join(self.dist_dir,'tmp_sdist_dsc') cleanup_dirs.append(expand_dir) if os.path.exists(expand_dir): shutil.rmtree(expand_dir) if not os.path.exists(self.dist_dir): os.mkdir(self.dist_dir) os.mkdir(expand_dir) expand_sdist_file(self.use_premade_distfile,cwd=expand_dir) is_tgz=False if self.use_premade_distfile.lower().endswith('.tar.gz'): is_tgz=True # now the sdist package is expanded in expand_dir expanded_root_files = os.listdir(expand_dir) assert len(expanded_root_files)==1 distname_in_premade_distfile = expanded_root_files[0] debianized_dirname = repackaged_dirname original_dirname = os.path.split(distname_in_premade_distfile)[-1] do_repack=False if is_tgz: source_tarball = self.use_premade_distfile else: log.warn('WARNING: .orig.tar.gz will be generated from sdist ' 'archive ("%s") because it is not a .tar.gz file', self.use_premade_distfile) do_repack=True if do_repack: tmp_dir = os.path.join(self.dist_dir, 'tmp_repacking_dir' ) os.makedirs( tmp_dir ) cleanup_dirs.append(tmp_dir) source_tarball = os.path.join(tmp_dir,'repacked_sdist.tar.gz') repack_tarball_with_debianized_dirname(self.use_premade_distfile, source_tarball, debianized_dirname, original_dirname ) if source_tarball is not None: # Because we deleted all .pyc files above, if the # original source dist has them, we will have # (wrongly) deleted them. So, quit loudly rather # than fail silently. for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): raise RuntimeError('original source dist cannot ' 'contain .pyc files') else: if 0: # haven't figured out why raise NotImplementedError("the code path is broken right now") ############################################### # 3. Find all directories for pkgdir in self.distribution.packages or []: debinfo.dirlist += ' ' + pkgdir.replace('.', '/') ############################################### # 4. Build source tree and rename it to be in self.dist_dir build_dsc(debinfo, self.dist_dir, repackaged_dirname, orig_sdist=source_tarball, patch_posix = self.patch_posix, remove_expanded_source_dir=self.remove_expanded_source_dir, ) for rmdir in cleanup_dirs: shutil.rmtree(rmdir)
def build_dsc(debinfo, dist_dir, repackaged_dirname, orig_sdist=None, patch_posix=0, remove_expanded_source_dir=0): """make debian source package""" # A. Find new dirname and delete any pre-existing contents # dist_dir is usually 'deb_dist' # the location of the copied original source package (it was # re-recreated in dist_dir) fullpath_repackaged_dirname = os.path.join(dist_dir,repackaged_dirname) ############################################### # 1. make temporary original source tarball # Note that, for the final tarball, best practices suggest # using "dpkg-source -b". See # http://www.debian.org/doc/developers-reference/ch-best-pkging-practices.en.html # Create the name of the tarball that qualifies as the upstream # source. If the original was specified, we'll link to # it. Otherwise, we generate our own .tar.gz file from the output # of "python setup.py sdist" (done above) so that we avoid # packaging .svn directories, for example. repackaged_orig_tarball = ('%(source)s_%(upstream_version)s.orig.tar.gz'% debinfo.__dict__) repackaged_orig_tarball_path = os.path.join(dist_dir, repackaged_orig_tarball) if orig_sdist is not None: if os.path.exists(repackaged_orig_tarball_path): os.unlink(repackaged_orig_tarball_path) link_func(orig_sdist,repackaged_orig_tarball_path) else: make_tarball(repackaged_orig_tarball, repackaged_dirname, cwd=dist_dir) # apply patch if debinfo.patch_file != '': apply_patch(debinfo.patch_file, posix=patch_posix, level=debinfo.patch_level, cwd=fullpath_repackaged_dirname) for fname in ['Makefile','makefile']: if os.path.exists(os.path.join(fullpath_repackaged_dirname,fname)): sys.stderr.write('*'*1000 + '\n') sys.stderr.write('WARNING: a Makefile exists in this package. ' 'debhelper 7 will attempt to use this rather than ' 'setup.py to build and install the package.\n') sys.stderr.write('*'*1000 + '\n') ############################################### # 2. create debian/ directory and contents debian_dir = os.path.join(fullpath_repackaged_dirname,'debian') if not os.path.exists(debian_dir): os.mkdir(debian_dir) # A. debian/changelog fd = open( os.path.join(debian_dir,'changelog'), mode='w') fd.write("""\ %(source)s (%(full_version)s) %(distname)s; urgency=low * source package automatically created by stdeb %(stdeb_version)s -- %(maintainer)s %(date822)s\n"""%debinfo.__dict__) fd.close() # B. debian/control if debinfo.uploaders: debinfo.uploaders = 'Uploaders: %s\n' % ', '.join(debinfo.uploaders) else: debinfo.uploaders = '' control = CONTROL_FILE%debinfo.__dict__ fd = open( os.path.join(debian_dir,'control'), mode='w') fd.write(control) fd.close() # C. debian/rules debinfo.percent_symbol = '%' rules = RULES_MAIN%debinfo.__dict__ rules = rules.replace(' ','\t') rules_fname = os.path.join(debian_dir,'rules') fd = open( rules_fname, mode='w') fd.write(rules) fd.close() os.chmod(rules_fname,0755) # D. debian/compat fd = open( os.path.join(debian_dir,'compat'), mode='w') fd.write('7\n') fd.close() # E. debian/package.mime if debinfo.mime_file != '': if not os.path.exists(debinfo.mime_file): raise ValueError( 'a MIME file was specified, but does not exist: %s'%( debinfo.mime_file,)) link_func( debinfo.mime_file, os.path.join(debian_dir,debinfo.package+'.mime')) if debinfo.shared_mime_file != '': if not os.path.exists(debinfo.shared_mime_file): raise ValueError( 'a shared MIME file was specified, but does not exist: %s'%( debinfo.shared_mime_file,)) link_func( debinfo.shared_mime_file, os.path.join(debian_dir, debinfo.package+'.sharedmimeinfo')) # F. debian/copyright if debinfo.copyright_file != '': link_func( debinfo.copyright_file, os.path.join(debian_dir,'copyright')) # G. debian/<package>.preinst if debinfo.do_pycentral_removal_preinst: preinst = PREINST%debinfo.__dict__ fd = open( os.path.join(debian_dir,'%s.preinst'%debinfo.package), mode='w') fd.write(preinst) fd.close() # H. debian/<package>.install if len(debinfo.install_file_lines): fd = open( os.path.join(debian_dir,'%s.install'%debinfo.package), mode='w') fd.write('\n'.join(debinfo.install_file_lines)+'\n') fd.close() # I. debian/<package>.udev if debinfo.udev_rules != '': fname = debinfo.udev_rules if not os.path.exists(fname): raise ValueError('udev rules file specified, but does not exist') link_func(fname, os.path.join(debian_dir,'%s.udev'%debinfo.package)) ############################################### # 3. unpack original source tarball debianized_package_dirname = fullpath_repackaged_dirname+'.debianized' if os.path.exists(debianized_package_dirname): raise RuntimeError('debianized_package_dirname exists: %s' % debianized_package_dirname) # A. move debianized tree away os.rename(fullpath_repackaged_dirname, debianized_package_dirname ) if orig_sdist is not None: # B. expand repackaged original tarball tmp_dir = os.path.join(dist_dir,'tmp-expand') os.mkdir(tmp_dir) try: expand_tarball(orig_sdist,cwd=tmp_dir) orig_tarball_top_contents = os.listdir(tmp_dir) # make sure original tarball has exactly one directory assert len(orig_tarball_top_contents)==1 orig_dirname = orig_tarball_top_contents[0] fullpath_orig_dirname = os.path.join(tmp_dir,orig_dirname) # C. move original repackaged tree to .orig target = fullpath_repackaged_dirname+'.orig' if os.path.exists(target): # here from previous invocation, probably shutil.rmtree(target) os.rename(fullpath_orig_dirname,target) finally: shutil.rmtree(tmp_dir) if 1: # check versions of debhelper and python-support debhelper_version_str = get_version_str('debhelper') if len(debhelper_version_str)==0: log.warn('This version of stdeb requires debhelper >= %s, but you ' 'do not have debhelper installed. ' 'Could not check compatibility.'%DH_MIN_VERS) else: if not dpkg_compare_versions( debhelper_version_str, 'ge', DH_MIN_VERS ): log.warn('This version of stdeb requires debhelper >= %s. ' 'Use stdeb 0.3.x to generate source packages ' 'compatible with older versions of debhelper.'%( DH_MIN_VERS,)) pysupport_version_str = get_version_str('python-support') if len(pysupport_version_str)==0: log.warn('This version of stdeb requires python-support >= %s, ' 'but you do not have python-support installed. ' 'Could not check compatibility.'%PYSUPPORT_MIN_VERS) else: if not dpkg_compare_versions( pysupport_version_str, 'ge', PYSUPPORT_MIN_VERS ): log.warn('This version of stdeb requires python-support >= %s. ' 'Use stdeb 0.3.x to generate source packages ' 'compatible with older versions of python-support.'%( PYSUPPORT_MIN_VERS,)) # D. restore debianized tree os.rename(fullpath_repackaged_dirname+'.debianized', fullpath_repackaged_dirname) # Re-generate tarball using best practices see # http://www.debian.org/doc/developers-reference/ch-best-pkging-practices.en.html # call "dpkg-source -b new_dirname orig_dirname" log.info('CALLING dpkg-source -b %s %s (in dir %s)'%( repackaged_dirname, repackaged_orig_tarball, dist_dir)) dpkg_source('-b',repackaged_dirname, repackaged_orig_tarball, cwd=dist_dir) if 1: shutil.rmtree(fullpath_repackaged_dirname) if not remove_expanded_source_dir: # expand the debian source package dsc_name = debinfo.source + '_' + debinfo.dsc_version + '.dsc' dpkg_source('-x',dsc_name, cwd=dist_dir)
def __init__(self, cfg_files=NotGiven, module_name=NotGiven, default_distribution=NotGiven, default_maintainer=NotGiven, upstream_version=NotGiven, egg_module_name=NotGiven, has_ext_modules=NotGiven, description=NotGiven, long_description=NotGiven, patch_file=None, patch_level=None, install_requires=None, setup_requires=None, debian_version=None, workaround_548392=None, have_script_entry_points = None, pycentral_backwards_compatibility=None, ): if cfg_files is NotGiven: raise ValueError("cfg_files must be supplied") if module_name is NotGiven: raise ValueError( "module_name must be supplied") if default_distribution is NotGiven: raise ValueError( "default_distribution must be supplied") if default_maintainer is NotGiven: raise ValueError( "default_maintainer must be supplied") if upstream_version is NotGiven: raise ValueError( "upstream_version must be supplied") if has_ext_modules is NotGiven: raise ValueError( "has_ext_modules must be supplied") if description is NotGiven: raise ValueError( "description must be supplied") if long_description is NotGiven: raise ValueError( "long_description must be supplied") cfg_defaults = self._make_cfg_defaults( module_name=module_name, default_distribution=default_distribution, default_maintainer=default_maintainer, ) cfg = ConfigParser.SafeConfigParser(cfg_defaults) cfg.read(cfg_files) self.stdeb_version = __stdeb_version__ self.module_name = module_name self.source = parse_val(cfg,module_name,'Source') self.package = parse_val(cfg,module_name,'Package') forced_upstream_version = parse_val(cfg,module_name, 'Forced-Upstream-Version') if forced_upstream_version == '': upstream_version_prefix = parse_val(cfg,module_name, 'Upstream-Version-Prefix') upstream_version_suffix = parse_val(cfg,module_name, 'Upstream-Version-Suffix') self.upstream_version = (upstream_version_prefix+ debianize_version(upstream_version)+ upstream_version_suffix) else: if (debianize_version(forced_upstream_version) != forced_upstream_version): raise ValueError('forced upstream version ("%s") not a ' 'Debian-compatible version (e.g. "%s")'%( forced_upstream_version, debianize_version(forced_upstream_version))) self.upstream_version = forced_upstream_version self.egg_module_name = egg_module_name self.epoch = parse_val(cfg,module_name,'Epoch') if self.epoch != '' and not self.epoch.endswith(':'): self.epoch = self.epoch + ':' self.packaging_version = parse_val(cfg,module_name,'Debian-Version') if debian_version is not None: # command-line arg overrides file self.packaging_version = debian_version self.dsc_version = '%s-%s'%( self.upstream_version, self.packaging_version) self.full_version = '%s%s-%s'%( self.epoch, self.upstream_version, self.packaging_version) self.distname = parse_val(cfg,module_name,'Distribution') self.maintainer = ', '.join(parse_vals(cfg,module_name,'Maintainer')) self.uploaders = parse_vals(cfg,module_name,'Uploaders') self.date822 = get_date_822() build_deps = ['python-setuptools (>= 0.6b3)'] build_deps.extend( get_deb_depends_from_setuptools_requires(setup_requires)) depends = ['${python:Depends}', 'python-pkg-resources'] need_custom_binary_target = False self.do_pycentral_removal_preinst = pycentral_backwards_compatibility if has_ext_modules: self.architecture = 'any' depends.append('${shlibs:Depends}') build_deps.append('python-all-dev') else: self.architecture = 'all' self.copyright_file = parse_val(cfg,module_name,'Copyright-File') self.mime_file = parse_val(cfg,module_name,'MIME-File') self.shared_mime_file = parse_val(cfg,module_name,'Shared-MIME-File') if self.mime_file == '' and self.shared_mime_file == '': self.dh_installmime_line = '' else: need_custom_binary_target = True self.dh_installmime_line = '\tdh_installmime' if self.architecture == 'all': self.dh_installmime_line += ' -i' else: self.dh_installmime_line += ' -a' mime_desktop_files = parse_vals(cfg,module_name,'MIME-Desktop-Files') if len(mime_desktop_files): need_custom_binary_target = True self.dh_desktop_line = '\tdh_desktop' if self.architecture == 'all': self.dh_desktop_line += ' -i' else: self.dh_desktop_line += ' -a' else: self.dh_desktop_line = '' # E. any mime .desktop files self.install_file_lines = [] for mime_desktop_file in mime_desktop_files: self.install_file_lines.append( '%s usr/share/applications'%mime_desktop_file) depends.extend(parse_vals(cfg,module_name,'Depends') ) depends.extend(get_deb_depends_from_setuptools_requires( install_requires)) self.depends = ', '.join(depends) self.description = description if long_description != 'UNKNOWN': ld2=[] for line in long_description.split('\n'): ls = line.strip() if len(ls): ld2.append(' '+line) else: ld2.append(' .') self.long_description = '\n'.join(ld2) else: self.long_description = '' if have_script_entry_points: if workaround_548392: build_deps.append( 'debhelper (>= %s)'%DH_MIN_VERS) else: build_deps.append( 'debhelper (>= %s)'%DH_IDEAL_VERS ) else: build_deps.append( 'debhelper (>= %s)'%DH_MIN_VERS ) build_deps.append('python-support (>= %s)'%PYSUPPORT_MIN_VERS) build_deps.extend( parse_vals(cfg,module_name,'Build-Depends') ) self.build_depends = ', '.join(build_deps) self.suggests = ', '.join( parse_vals(cfg,module_name,'Suggests') ) self.recommends = ', '.join( parse_vals(cfg,module_name,'Recommends') ) self.source_stanza_extras = '' build_conflicts = parse_vals(cfg,module_name,'Build-Conflicts') if len(build_conflicts): self.source_stanza_extras += ('Build-Conflicts: '+ ', '.join( build_conflicts )+'\n') self.patch_file = parse_val(cfg,module_name,'Stdeb-Patch-File') if patch_file is not None: if self.patch_file != '': raise RuntimeError('A patch file was specified on the command ' 'line and in .cfg file.') else: self.patch_file = patch_file self.patch_level = parse_val(cfg,module_name,'Stdeb-Patch-Level') if self.patch_level != '': if patch_level is not None: raise RuntimeError('A patch level was specified on the command ' 'line and in .cfg file.') else: self.patch_level = int(self.patch_level) else: if patch_level is not None: self.patch_level = patch_level else: self.patch_level = 0 xs_python_version = parse_vals(cfg,module_name,'XS-Python-Version') if have_script_entry_points and workaround_548392: # Trap cases that might trigger Debian bug #548392 and # workaround. Disable this block once the bugfix has # become widespread and change Build-Depends: to include # sufficiently recent debhelper. if len(xs_python_version)==0: # No Python version specified. For now, just use default Python log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] else: # The user specified a Python version. Check if s/he # specified more than one. (Specifying a single # version won't trigger the bug.) pyversions_fname = '/usr/bin/pyversions' assert os.path.exists(pyversions_fname) pyversions = load_module('pyversions',pyversions_fname) vstring = ', '.join(xs_python_version) pyversions_result = pyversions.parse_versions(vstring) if ('versions' in pyversions_result and len(pyversions_result['versions'])>1): vers = list(pyversions_result['versions']) # More than one Python version specified. # This is dubious as the following comparison # happens at source build time, but what matters # is what runs when building the binary package. default_vers = pyversions.default_version(version_only=True) if default_vers in vers: log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] else: vers.sort() log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'%s\''%vers[-1]) xs_python_version = [vers[-1]] elif 'all' in pyversions_result: log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] if len(xs_python_version)!=0: self.source_stanza_extras += ('XS-Python-Version: '+ ', '.join(xs_python_version)+'\n') self.package_stanza_extras = """\ XB-Python-Version: ${python:Versions} """ dpkg_shlibdeps_params = parse_val( cfg,module_name,'dpkg-shlibdeps-params') if dpkg_shlibdeps_params: need_custom_binary_target = True self.dh_binary_lines = """\tdh binary --before dh_shlibdeps \tdh_shlibdeps -a --dpkg-shlibdeps-params=%s \tdh binary --after dh_shlibdeps"""%dpkg_shlibdeps_params else: self.dh_binary_lines = '\tdh binary' conflicts = parse_vals(cfg,module_name,'Conflicts') if len(conflicts): self.package_stanza_extras += ('Conflicts: '+ ', '.join( conflicts )+'\n') provides = parse_vals(cfg,module_name,'Provides') provides.insert(0, 'Provides: ${python:Provides}') self.package_stanza_extras += ', '.join( provides )+'\n' replaces = parse_vals(cfg,module_name,'Replaces') if len(replaces): self.package_stanza_extras += ('Replaces: ' + ', '.join( replaces )+'\n') self.dirlist = "" setup_env_vars = parse_vals(cfg,module_name,'Setup-Env-Vars') self.exports = "" if len(setup_env_vars): self.exports += '\n' self.exports += '#exports specified using stdeb Setup-Env-Vars:\n' self.exports += '\n'.join(['export %s'%v for v in setup_env_vars]) self.exports += '\n' self.udev_rules = parse_val(cfg,module_name,'Udev-Rules') if need_custom_binary_target: self.binary_target_lines = RULES_BINARY_TARGET%self.__dict__ else: self.binary_target_lines = ''
if l: emo = E.search(l) assert emo, l dmo = D.search(l) assert dmo, l eggsndebs.add((emo.group(1), dmo.group(1))) for (egginfo, debname) in eggsndebs: pydist = pkg_resources.Distribution.from_filename(egginfo) try: dd.setdefault( pydist.project_name.lower(), {}).setdefault( pydist, set()).add(debname) except ValueError, le: log.warn("I got an error parsing a .egg-info file named \"%s\" " "from Debian package \"%s\" as a pkg_resources " "Distribution: %s" % (egginfo, debname, le,)) pass # Now for each requirement, see if a Debian package satisfies it. ops = {'<':'<<','>':'>>','==':'=','<=':'<=','>=':'>='} for req in parsed_reqs: reqname = req.project_name.lower() gooddebs = set() for pydist, debs in dd.get(reqname, {}).iteritems(): if pydist in req: ## log.info("I found Debian packages \"%s\" which provides " ## "Python package \"%s\", version \"%s\", which " ## "satisfies our version requirements: \"%s\"" ## % (', '.join(debs), req.project_name, ver, req) gooddebs |= (debs)
def run(self): debinfo = self.get_debinfo() if debinfo.patch_file != '' and self.patch_already_applied: raise RuntimeError('A patch was already applied, but another ' 'patch is requested.') repackaged_dirname = debinfo.source + '-' + debinfo.upstream_version fullpath_repackaged_dirname = os.path.join(self.dist_dir, repackaged_dirname) cleanup_dirs = [] if self.use_premade_distfile is None: # generate original tarball sdist_cmd = self.distribution.get_command_obj('sdist') self.run_command('sdist') source_tarball = None for archive_file in sdist_cmd.get_archive_files(): if archive_file.endswith('.tar.gz'): source_tarball = archive_file if source_tarball is None: raise RuntimeError('sdist did not produce .tar.gz file') # make copy of source tarball in deb_dist/ local_source_tarball = os.path.split(source_tarball)[-1] shutil.copy2(source_tarball, local_source_tarball) source_tarball = local_source_tarball self.use_premade_distfile = source_tarball else: source_tarball = self.use_premade_distfile # Copy source tree assuming that package-0.1.tar.gz contains # single top-level path 'package-0.1'. The contents of this # directory are then used. if os.path.exists(fullpath_repackaged_dirname): shutil.rmtree(fullpath_repackaged_dirname) tmpdir = tempfile.mkdtemp() expand_sdist_file(os.path.abspath(source_tarball), cwd=tmpdir) expanded_base_files = os.listdir(tmpdir) assert len(expanded_base_files) == 1 actual_package_dirname = expanded_base_files[0] expected_package_dirname = debinfo.module_name + '-' + debinfo.upstream_version shutil.move(os.path.join(tmpdir, actual_package_dirname), fullpath_repackaged_dirname) # ensure premade sdist can actually be used self.use_premade_distfile = os.path.abspath(self.use_premade_distfile) expand_dir = os.path.join(self.dist_dir, 'tmp_sdist_dsc') cleanup_dirs.append(expand_dir) if os.path.exists(expand_dir): shutil.rmtree(expand_dir) if not os.path.exists(self.dist_dir): os.mkdir(self.dist_dir) os.mkdir(expand_dir) expand_sdist_file(self.use_premade_distfile, cwd=expand_dir) is_tgz = False if self.use_premade_distfile.lower().endswith('.tar.gz'): is_tgz = True # now the sdist package is expanded in expand_dir expanded_root_files = os.listdir(expand_dir) assert len(expanded_root_files) == 1 distname_in_premade_distfile = expanded_root_files[0] debianized_dirname = repackaged_dirname original_dirname = os.path.split(distname_in_premade_distfile)[-1] do_repack = False if is_tgz: source_tarball = self.use_premade_distfile else: log.warn( 'WARNING: .orig.tar.gz will be generated from sdist ' 'archive ("%s") because it is not a .tar.gz file', self.use_premade_distfile) do_repack = True if do_repack: tmp_dir = os.path.join(self.dist_dir, 'tmp_repacking_dir') os.makedirs(tmp_dir) cleanup_dirs.append(tmp_dir) source_tarball = os.path.join(tmp_dir, 'repacked_sdist.tar.gz') repack_tarball_with_debianized_dirname(self.use_premade_distfile, source_tarball, debianized_dirname, original_dirname) if source_tarball is not None: # Because we deleted all .pyc files above, if the # original source dist has them, we will have # (wrongly) deleted them. So, quit loudly rather # than fail silently. for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): raise RuntimeError('original source dist cannot ' 'contain .pyc files') ############################################### # 3. Find all directories for pkgdir in self.distribution.packages or []: debinfo.dirlist += ' ' + pkgdir.replace('.', '/') ############################################### # 4. Build source tree and rename it to be in self.dist_dir build_dsc( debinfo, self.dist_dir, repackaged_dirname, orig_sdist=source_tarball, patch_posix=self.patch_posix, remove_expanded_source_dir=self.remove_expanded_source_dir, sign_dsc=self.sign_results, extend_diff_ignore=self.extend_diff_ignore, ) for rmdir in cleanup_dirs: shutil.rmtree(rmdir)
def __init__(self, cfg_files=NotGiven, module_name=NotGiven, default_distribution=NotGiven, guess_maintainer=NotGiven, upstream_version=NotGiven, has_ext_modules=NotGiven, description=NotGiven, long_description=NotGiven, patch_file=None, patch_level=None, install_requires=None, setup_requires=None, debian_version=None, workaround_548392=None, force_buildsystem=None, have_script_entry_points = None, pycentral_backwards_compatibility=None, use_setuptools = False, guess_conflicts_provides_replaces = False, sdist_dsc_command = None, ): if cfg_files is NotGiven: raise ValueError("cfg_files must be supplied") if module_name is NotGiven: raise ValueError( "module_name must be supplied") if default_distribution is NotGiven: raise ValueError( "default_distribution must be supplied") if guess_maintainer is NotGiven: raise ValueError( "guess_maintainer must be supplied") if upstream_version is NotGiven: raise ValueError( "upstream_version must be supplied") if has_ext_modules is NotGiven: raise ValueError( "has_ext_modules must be supplied") if description is NotGiven: raise ValueError( "description must be supplied") if long_description is NotGiven: raise ValueError( "long_description must be supplied") cfg_defaults = self._make_cfg_defaults( module_name=module_name, default_distribution=default_distribution, guess_maintainer=guess_maintainer, ) if len(cfg_files): check_cfg_files(cfg_files,module_name) cfg = ConfigParser.SafeConfigParser(cfg_defaults) cfg.read(cfg_files) if sdist_dsc_command is not None: # Allow distutils commands to override config files (this lets # command line options beat file options). for longopt, shortopt, desc in stdeb_cfg_options: name = longopt[:-1] name = name.replace('-','_') value = getattr( sdist_dsc_command, name ) if value is not None: cfg.set( module_name, name, value ) self.stdeb_version = __stdeb_version__ self.module_name = module_name self.source = parse_val(cfg,module_name,'Source') self.package = parse_val(cfg,module_name,'Package') forced_upstream_version = parse_val(cfg,module_name, 'Forced-Upstream-Version') if forced_upstream_version == '': upstream_version_prefix = parse_val(cfg,module_name, 'Upstream-Version-Prefix') upstream_version_suffix = parse_val(cfg,module_name, 'Upstream-Version-Suffix') self.upstream_version = (upstream_version_prefix+ debianize_version(upstream_version)+ upstream_version_suffix) else: if (debianize_version(forced_upstream_version) != forced_upstream_version): raise ValueError('forced upstream version ("%s") not a ' 'Debian-compatible version (e.g. "%s")'%( forced_upstream_version, debianize_version(forced_upstream_version))) self.upstream_version = forced_upstream_version self.epoch = parse_val(cfg,module_name,'Epoch') if self.epoch != '' and not self.epoch.endswith(':'): self.epoch = self.epoch + ':' self.packaging_version = parse_val(cfg,module_name,'Debian-Version') if debian_version is not None: # command-line arg overrides file self.packaging_version = debian_version self.dsc_version = '%s-%s'%( self.upstream_version, self.packaging_version) self.full_version = '%s%s-%s'%( self.epoch, self.upstream_version, self.packaging_version) self.distname = parse_val(cfg,module_name,'Suite') self.maintainer = ', '.join(parse_vals(cfg,module_name,'Maintainer')) self.uploaders = parse_vals(cfg,module_name,'Uploaders') self.date822 = get_date_822() build_deps = [] if use_setuptools: build_deps.append('python-setuptools (>= 0.6b3)') if setup_requires is not None and len(setup_requires): build_deps.extend( get_deb_depends_from_setuptools_requires(setup_requires)) depends = ['${python:Depends}'] need_custom_binary_target = False self.do_pycentral_removal_preinst = pycentral_backwards_compatibility if has_ext_modules: self.architecture = 'any' depends.append('${shlibs:Depends}') build_deps.append('python-all-dev') else: self.architecture = 'all' self.copyright_file = parse_val(cfg,module_name,'Copyright-File') self.mime_file = parse_val(cfg,module_name,'MIME-File') self.shared_mime_file = parse_val(cfg,module_name,'Shared-MIME-File') if self.mime_file == '' and self.shared_mime_file == '': self.dh_installmime_line = '' else: need_custom_binary_target = True self.dh_installmime_line = '\tdh_installmime' if self.architecture == 'all': self.dh_installmime_line += ' -i' else: self.dh_installmime_line += ' -a' mime_desktop_files = parse_vals(cfg,module_name,'MIME-Desktop-Files') if len(mime_desktop_files): need_custom_binary_target = True self.dh_desktop_line = '\tdh_desktop' if self.architecture == 'all': self.dh_desktop_line += ' -i' else: self.dh_desktop_line += ' -a' else: self.dh_desktop_line = '' # E. any mime .desktop files self.install_file_lines = [] for mime_desktop_file in mime_desktop_files: self.install_file_lines.append( '%s usr/share/applications'%mime_desktop_file) depends.extend(parse_vals(cfg,module_name,'Depends') ) if install_requires is not None and len(install_requires): depends.extend(get_deb_depends_from_setuptools_requires( install_requires)) self.depends = ', '.join(depends) self.debian_section = parse_val(cfg,module_name,'Section') self.description = description if long_description != 'UNKNOWN': ld2=[] for line in long_description.split('\n'): ls = line.strip() if len(ls): ld2.append(' '+line) else: ld2.append(' .') ld2 = ld2[:20] self.long_description = '\n'.join(ld2) else: self.long_description = '' if have_script_entry_points: if workaround_548392: build_deps.append( 'debhelper (>= %s)'%DH_MIN_VERS) else: build_deps.append( 'debhelper (>= %s)'%DH_IDEAL_VERS ) else: build_deps.append( 'debhelper (>= %s)'%DH_MIN_VERS ) build_deps.append('python-support (>= %s)'%PYSUPPORT_MIN_VERS) build_deps.extend( parse_vals(cfg,module_name,'Build-Depends') ) self.build_depends = ', '.join(build_deps) suggests = ', '.join( parse_vals(cfg,module_name,'Suggests') ) recommends = ', '.join( parse_vals(cfg,module_name,'Recommends') ) self.source_stanza_extras = '' build_conflicts = parse_vals(cfg,module_name,'Build-Conflicts') if len(build_conflicts): self.source_stanza_extras += ('Build-Conflicts: '+ ', '.join( build_conflicts )+'\n') self.patch_file = parse_val(cfg,module_name,'Stdeb-Patch-File') if patch_file is not None: if self.patch_file != '': raise RuntimeError('A patch file was specified on the command ' 'line and in .cfg file.') else: self.patch_file = patch_file self.patch_level = parse_val(cfg,module_name,'Stdeb-Patch-Level') if self.patch_level != '': if patch_level is not None: raise RuntimeError('A patch level was specified on the command ' 'line and in .cfg file.') else: self.patch_level = int(self.patch_level) else: if patch_level is not None: self.patch_level = patch_level else: self.patch_level = 0 xs_python_version = parse_vals(cfg,module_name,'XS-Python-Version') if have_script_entry_points and workaround_548392: # Trap cases that might trigger Debian bug #548392 and # workaround. Disable this block once the bugfix has # become widespread and change Build-Depends: to include # sufficiently recent debhelper. if len(xs_python_version)==0: # No Python version specified. For now, just use default Python log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] else: # The user specified a Python version. Check if s/he # specified more than one. (Specifying a single # version won't trigger the bug.) pyversions_fname = '/usr/bin/pyversions' assert os.path.exists(pyversions_fname) pyversions = load_module('pyversions',pyversions_fname) vstring = ', '.join(xs_python_version) pyversions_result = pyversions.parse_versions(vstring) if ('versions' in pyversions_result and len(pyversions_result['versions'])>1): vers = list(pyversions_result['versions']) # More than one Python version specified. # This is dubious as the following comparison # happens at source build time, but what matters # is what runs when building the binary package. default_vers = pyversions.default_version(version_only=True) if default_vers in vers: log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] else: vers.sort() log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'%s\''%vers[-1]) xs_python_version = [vers[-1]] elif 'all' in pyversions_result: log.warn('working around Debian #548392, changing ' 'XS-Python-Version: to \'current\'') xs_python_version = ['current'] if len(xs_python_version)!=0: self.source_stanza_extras += ('XS-Python-Version: '+ ', '.join(xs_python_version)+'\n') self.package_stanza_extras = """\ XB-Python-Version: ${python:Versions} """ dpkg_shlibdeps_params = parse_val( cfg,module_name,'dpkg-shlibdeps-params') if dpkg_shlibdeps_params: need_custom_binary_target = True self.dh_binary_lines = """\tdh binary --before dh_shlibdeps \tdh_shlibdeps -a --dpkg-shlibdeps-params=%s \tdh binary --after dh_shlibdeps"""%dpkg_shlibdeps_params else: self.dh_binary_lines = '\tdh binary' conflicts = parse_vals(cfg,module_name,'Conflicts') provides = parse_vals(cfg,module_name,'Provides') replaces = parse_vals(cfg,module_name,'Replaces') if guess_conflicts_provides_replaces: # Find list of binaries which we will conflict/provide/replace. cpr_binaries = set() # Get original Debian information for the package named the same. for version_info in apt_cache_info('showsrc',self.package): # Remember each of the binary packages produced by the Debian source for binary in version_info['Binary']: cpr_binaries.add(binary) # TODO: do this for every version available , just the # first, or ??? break # Descend each of the original binaries and see what # packages they conflict/ provide/ replace: for orig_binary in cpr_binaries: for version_info in apt_cache_info('show',orig_binary): provides.extend( version_info['Provides']) conflicts.extend(version_info['Conflicts']) replaces.extend( version_info['Replaces']) if self.package in cpr_binaries: cpr_binaries.remove(self.package) # don't include ourself cpr_binaries = list(cpr_binaries) # convert to list conflicts.extend( cpr_binaries ) provides.extend( cpr_binaries ) replaces.extend( cpr_binaries ) # round-trip through set to get unique entries conflicts = list(set(conflicts)) provides = list(set(provides)) replaces = list(set(replaces)) if len(conflicts): self.package_stanza_extras += ('Conflicts: '+ ', '.join( conflicts )+'\n') provides.insert(0, 'Provides: ${python:Provides}') self.package_stanza_extras += ', '.join( provides )+'\n' if len(replaces): self.package_stanza_extras += ('Replaces: ' + ', '.join( replaces )+'\n') if len(recommends): self.package_stanza_extras += ('Recommends: '+recommends+'\n') if len(suggests): self.package_stanza_extras += ('Suggests: '+suggests+'\n') self.dirlist = "" setup_env_vars = parse_vals(cfg,module_name,'Setup-Env-Vars') if force_buildsystem: setup_env_vars.append('DH_OPTIONS=--buildsystem=python_distutils') self.force_buildsystem = force_buildsystem self.exports = "" if len(setup_env_vars): self.exports += '\n' self.exports += '#exports specified using stdeb Setup-Env-Vars:\n' self.exports += '\n'.join(['export %s'%v for v in setup_env_vars]) self.exports += '\n' self.udev_rules = parse_val(cfg,module_name,'Udev-Rules') if need_custom_binary_target: self.binary_target_lines = RULES_BINARY_TARGET%self.__dict__ else: self.binary_target_lines = ''
class common_debian_package_command(Command): def initialize_options(self): self.patch_already_applied = 0 self.remove_expanded_source_dir = 0 self.patch_posix = 0 self.dist_dir = None self.extra_cfg_file = None self.patch_file = None self.patch_level = None self.ignore_install_requires = None self.debian_version = None self.force_buildsystem = None self.no_backwards_compatibility = None self.guess_conflicts_provides_replaces = None # deprecated options self.default_distribution = None self.default_maintainer = None # make distutils happy by filling in default values for longopt, shortopt, description in stdeb_cfg_options: assert longopt.endswith('=') name = longopt[:-1] name = name.replace('-', '_') setattr(self, name, None) def finalize_options(self): def str_to_bool(mystr): if mystr.lower() == 'false': return False elif mystr.lower() == 'true': return True else: raise ValueError('bool string "%s" is not "true" or "false"' % mystr) if self.dist_dir is None: self.dist_dir = 'deb_dist' if self.patch_level is not None: self.patch_level = int(self.patch_level) if self.force_buildsystem is not None: self.force_buildsystem = str_to_bool(self.force_buildsystem) if self.force_buildsystem is None: self.force_buildsystem = True if self.guess_conflicts_provides_replaces is None: # the default self.guess_conflicts_provides_replaces = False else: self.guess_conflicts_provides_replaces = str_to_bool( self.guess_conflicts_provides_replaces) def get_debinfo(self): ############################################### # 1. setup initial variables # A. create config defaults module_name = self.distribution.get_name() if 1: # set default maintainer if (self.distribution.get_maintainer() != 'UNKNOWN' and self.distribution.get_maintainer_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>" % ( self.distribution.get_maintainer(), self.distribution.get_maintainer_email()) elif (self.distribution.get_author() != 'UNKNOWN' and self.distribution.get_author_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>" % ( self.distribution.get_author(), self.distribution.get_author_email()) else: guess_maintainer = "unknown <unknown@unknown>" if self.default_maintainer is not None: log.warn('Deprecation warning: you are using the ' '--default-maintainer option. ' 'Switch to the --maintainer option.') guess_maintainer = self.default_maintainer # B. find config files (if any) cfg_files = [] if self.extra_cfg_file is not None: cfg_files.append(self.extra_cfg_file) use_setuptools = True try: ei_cmd = self.distribution.get_command_obj('egg_info') except DistutilsModuleError, err: use_setuptools = False have_script_entry_points = None config_fname = 'stdeb.cfg' # Distutils fails if not run from setup.py dir, so this is OK. if os.path.exists(config_fname): cfg_files.append(config_fname) if use_setuptools: self.run_command('egg_info') egg_info_dirname = ei_cmd.egg_info # Pickup old location of stdeb.cfg config_fname = os.path.join(egg_info_dirname, 'stdeb.cfg') if os.path.exists(config_fname): log.warn('Deprecation warning: stdeb detected old location of ' 'stdeb.cfg in %s. This file will be used, but you ' 'should move it alongside setup.py.' % egg_info_dirname) cfg_files.append(config_fname) egg_module_name = egg_info_dirname[:egg_info_dirname. index('.egg-info')] egg_module_name = egg_module_name.split(os.sep)[-1] if 1: # determine whether script specifies setuptools entry_points ep_fname = os.path.join(egg_info_dirname, 'entry_points.txt') if os.path.exists(ep_fname): entry_points = open(ep_fname, 'rU').readlines() else: entry_points = '' entry_points = [ep.strip() for ep in entry_points] if ('[console_scripts]' in entry_points or '[gui_scripts]' in entry_points): have_script_entry_points = True else: # We don't have setuptools, so guess egg_info_dirname to # find old stdeb.cfg. entries = os.listdir(os.curdir) for entry in entries: if not (entry.endswith('.egg-info') and os.path.isdir(entry)): continue # Pickup old location of stdeb.cfg config_fname = os.path.join(entry, 'stdeb.cfg') if os.path.exists(config_fname): log.warn( 'Deprecation warning: stdeb detected ' 'stdeb.cfg in %s. This file will be used, but you ' 'should move it alongside setup.py.' % entry) cfg_files.append(config_fname) if have_script_entry_points is None: have_script_entry_points = self.distribution.has_scripts() test_suite = None if hasattr(self.distribution, "test_suite"): test_suite = self.distribution.test_suite debinfo = DebianInfo( cfg_files=cfg_files, module_name=module_name, default_distribution=self.default_distribution, guess_maintainer=guess_maintainer, upstream_version=self.distribution.get_version(), has_ext_modules=self.distribution.has_ext_modules(), description=self.distribution.get_description()[:60], long_description=self.distribution.get_long_description(), patch_file=self.patch_file, patch_level=self.patch_level, debian_version=self.debian_version, force_buildsystem=self.force_buildsystem, have_script_entry_points=have_script_entry_points, setup_requires=(), # XXX How do we get the setup_requires? use_setuptools=use_setuptools, guess_conflicts_provides_replaces=self. guess_conflicts_provides_replaces, sdist_dsc_command=self, test_suite=test_suite, ) return debinfo
def get_debinfo(self): ############################################### # 1. setup initial variables # A. create config defaults module_name = self.distribution.get_name() if 1: # set default maintainer if (self.distribution.get_maintainer() != 'UNKNOWN' and self.distribution.get_maintainer_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>"%( self.distribution.get_maintainer(), self.distribution.get_maintainer_email()) elif (self.distribution.get_author() != 'UNKNOWN' and self.distribution.get_author_email() != 'UNKNOWN'): guess_maintainer = "%s <%s>"%( self.distribution.get_author(), self.distribution.get_author_email()) else: guess_maintainer = "unknown <unknown@unknown>" if self.default_maintainer is not None: log.warn('Deprecation warning: you are using the ' '--default-maintainer option. ' 'Switch to the --maintainer option.') guess_maintainer = self.default_maintainer if hasattr(guess_maintainer,'decode'): # python 2 : convert (back to) unicode guess_maintainer = guess_maintainer.decode('utf-8') # B. find config files (if any) cfg_files = [] if self.extra_cfg_file is not None: cfg_files.append(self.extra_cfg_file) use_setuptools = True try: ei_cmd = self.distribution.get_command_obj('egg_info') except DistutilsModuleError as err: use_setuptools = False have_script_entry_points = None config_fname = 'stdeb.cfg' # Distutils fails if not run from setup.py dir, so this is OK. if os.path.exists(config_fname): cfg_files.append(config_fname) if use_setuptools: self.run_command('egg_info') egg_info_dirname = ei_cmd.egg_info # Pickup old location of stdeb.cfg config_fname = os.path.join(egg_info_dirname,'stdeb.cfg') if os.path.exists(config_fname): log.warn('Deprecation warning: stdeb detected old location of ' 'stdeb.cfg in %s. This file will be used, but you ' 'should move it alongside setup.py.' %egg_info_dirname) cfg_files.append(config_fname) egg_module_name = egg_info_dirname[:egg_info_dirname.index('.egg-info')] egg_module_name = egg_module_name.split(os.sep)[-1] if 1: # determine whether script specifies setuptools entry_points ep_fname = os.path.join(egg_info_dirname,'entry_points.txt') if os.path.exists(ep_fname): entry_points = open(ep_fname,'rU').readlines() else: entry_points = '' entry_points = [ep.strip() for ep in entry_points] if ('[console_scripts]' in entry_points or '[gui_scripts]' in entry_points): have_script_entry_points = True else: # We don't have setuptools, so guess egg_info_dirname to # find old stdeb.cfg. entries = os.listdir(os.curdir) for entry in entries: if not (entry.endswith('.egg-info') and os.path.isdir(entry)): continue # Pickup old location of stdeb.cfg config_fname = os.path.join(entry,'stdeb.cfg') if os.path.exists(config_fname): log.warn('Deprecation warning: stdeb detected ' 'stdeb.cfg in %s. This file will be used, but you ' 'should move it alongside setup.py.' % entry) cfg_files.append(config_fname) if have_script_entry_points is None: have_script_entry_points = self.distribution.has_scripts() upstream_version = self.distribution.get_version() bad_chars = ':_' for bad_char in bad_chars: if bad_char in upstream_version: raise ValueError("Illegal character (%r) detected in version. " "This will break the debian tools."%bad_char) description = self.distribution.get_description() if hasattr(description,'decode'): # python 2 : convert (back to) unicode description = description.decode('utf-8') description = description[:60] long_description = self.distribution.get_long_description() if hasattr(long_description,'decode'): # python 2 : convert (back to) unicode long_description = long_description.decode('utf-8') long_description = long_description debinfo = DebianInfo( cfg_files=cfg_files, module_name = module_name, default_distribution=self.default_distribution, guess_maintainer=guess_maintainer, upstream_version = upstream_version, has_ext_modules = self.distribution.has_ext_modules(), description = description, long_description = long_description, patch_file = self.patch_file, patch_level = self.patch_level, debian_version = self.debian_version, have_script_entry_points = have_script_entry_points, setup_requires = (), # XXX How do we get the setup_requires? use_setuptools = use_setuptools, guess_conflicts_provides_replaces=self.guess_conflicts_provides_replaces, sdist_dsc_command = self, with_python2 = self.with_python2, with_python3 = self.with_python3, no_python2_scripts = self.no_python2_scripts, no_python3_scripts = self.no_python3_scripts, ) return debinfo
def build_dsc( debinfo, dist_dir, repackaged_dirname, orig_sdist=None, patch_posix=0, remove_expanded_source_dir=0, debian_dir_only=False, ): """make debian source package""" # A. Find new dirname and delete any pre-existing contents # dist_dir is usually 'deb_dist' # the location of the copied original source package (it was # re-recreated in dist_dir) if debian_dir_only: fullpath_repackaged_dirname = os.path.abspath(os.curdir) else: fullpath_repackaged_dirname = os.path.join(dist_dir, repackaged_dirname) ############################################### # 1. make temporary original source tarball # Note that, for the final tarball, best practices suggest # using "dpkg-source -b". See # http://www.debian.org/doc/developers-reference/ch-best-pkging-practices.en.html # Create the name of the tarball that qualifies as the upstream # source. If the original was specified, we'll link to # it. Otherwise, we generate our own .tar.gz file from the output # of "python setup.py sdist" (done above) so that we avoid # packaging .svn directories, for example. if not debian_dir_only: repackaged_orig_tarball = ( '%(source)s_%(upstream_version)s.orig.tar.gz' % debinfo.__dict__) repackaged_orig_tarball_path = os.path.join(dist_dir, repackaged_orig_tarball) if orig_sdist is not None: if os.path.exists(repackaged_orig_tarball_path): os.unlink(repackaged_orig_tarball_path) link_func(orig_sdist, repackaged_orig_tarball_path) else: make_tarball(repackaged_orig_tarball, repackaged_dirname, cwd=dist_dir) # apply patch if debinfo.patch_file != '': apply_patch(debinfo.patch_file, posix=patch_posix, level=debinfo.patch_level, cwd=fullpath_repackaged_dirname) for fname in ['Makefile', 'makefile']: if os.path.exists(os.path.join(fullpath_repackaged_dirname, fname)): sys.stderr.write('*' * 1000 + '\n') if debinfo.force_buildsystem: sys.stderr.write('WARNING: a Makefile exists in this package. ' 'stdeb will tell debhelper 7 to use setup.py ' 'to build and install the package, and the ' 'Makefile will be ignored. You can disable ' 'this behavior with the ' '--force-buildsystem=False argument to the ' 'stdeb command.\n') else: sys.stderr.write( 'WARNING: a Makefile exists in this package. ' 'debhelper 7 will attempt to use this rather ' 'than setup.py to build and install the ' 'package. You can disable this behavior with ' 'the --force-buildsystem=True argument to the ' 'stdeb command.\n') sys.stderr.write('*' * 1000 + '\n') ############################################### # 2. create debian/ directory and contents debian_dir = os.path.join(fullpath_repackaged_dirname, 'debian') if not os.path.exists(debian_dir): os.mkdir(debian_dir) # A. debian/changelog fd = open(os.path.join(debian_dir, 'changelog'), mode='w') fd.write("""\ %(source)s (%(full_version)s) %(distname)s; urgency=low * source package automatically created by stdeb %(stdeb_version)s -- %(maintainer)s %(date822)s\n""" % debinfo.__dict__) fd.close() # B. debian/control if debinfo.uploaders: debinfo.uploaders = 'Uploaders: %s\n' % ', '.join(debinfo.uploaders) else: debinfo.uploaders = '' control = CONTROL_FILE % debinfo.__dict__ fd = open(os.path.join(debian_dir, 'control'), mode='w') fd.write(control) fd.close() # C. debian/rules debinfo.percent_symbol = '%' rules = RULES_MAIN % debinfo.__dict__ if debinfo.test_suite: rules = rules + RULES_OVERRIDE_DH_AUTO_TEST rules = rules.replace(' ', '\t') rules_fname = os.path.join(debian_dir, 'rules') fd = open(rules_fname, mode='w') fd.write(rules) fd.close() os.chmod(rules_fname, 0755) # D. debian/compat fd = open(os.path.join(debian_dir, 'compat'), mode='w') fd.write('7\n') fd.close() # E. debian/package.mime if debinfo.mime_file != '': if not os.path.exists(debinfo.mime_file): raise ValueError( 'a MIME file was specified, but does not exist: %s' % (debinfo.mime_file, )) link_func(debinfo.mime_file, os.path.join(debian_dir, debinfo.package + '.mime')) if debinfo.shared_mime_file != '': if not os.path.exists(debinfo.shared_mime_file): raise ValueError( 'a shared MIME file was specified, but does not exist: %s' % (debinfo.shared_mime_file, )) link_func( debinfo.shared_mime_file, os.path.join(debian_dir, debinfo.package + '.sharedmimeinfo')) # F. debian/copyright if debinfo.copyright_file != '': link_func(debinfo.copyright_file, os.path.join(debian_dir, 'copyright')) # H. debian/<package>.install if len(debinfo.install_file_lines): fd = open(os.path.join(debian_dir, '%s.install' % debinfo.package), mode='w') fd.write('\n'.join(debinfo.install_file_lines) + '\n') fd.close() # I. debian/<package>.udev if debinfo.udev_rules != '': fname = debinfo.udev_rules if not os.path.exists(fname): raise ValueError('udev rules file specified, but does not exist') link_func(fname, os.path.join(debian_dir, '%s.udev' % debinfo.package)) # J. debian/source/format os.mkdir(os.path.join(debian_dir, 'source')) fd = open(os.path.join(debian_dir, 'source', 'format'), mode='w') fd.write('1.0\n') fd.close() if debian_dir_only: return ############################################### # 3. unpack original source tarball debianized_package_dirname = fullpath_repackaged_dirname + '.debianized' if os.path.exists(debianized_package_dirname): raise RuntimeError('debianized_package_dirname exists: %s' % debianized_package_dirname) # A. move debianized tree away os.rename(fullpath_repackaged_dirname, debianized_package_dirname) if orig_sdist is not None: # B. expand repackaged original tarball tmp_dir = os.path.join(dist_dir, 'tmp-expand') os.mkdir(tmp_dir) try: expand_tarball(orig_sdist, cwd=tmp_dir) orig_tarball_top_contents = os.listdir(tmp_dir) # make sure original tarball has exactly one directory assert len(orig_tarball_top_contents) == 1 orig_dirname = orig_tarball_top_contents[0] fullpath_orig_dirname = os.path.join(tmp_dir, orig_dirname) # C. move original repackaged tree to .orig target = fullpath_repackaged_dirname + '.orig' if os.path.exists(target): # here from previous invocation, probably shutil.rmtree(target) os.rename(fullpath_orig_dirname, target) finally: shutil.rmtree(tmp_dir) if 1: # check versions of debhelper and python-all debhelper_version_str = get_version_str('debhelper') if len(debhelper_version_str) == 0: log.warn('This version of stdeb requires debhelper >= %s, but you ' 'do not have debhelper installed. ' 'Could not check compatibility.' % DH_MIN_VERS) else: if not dpkg_compare_versions(debhelper_version_str, 'ge', DH_MIN_VERS): log.warn('This version of stdeb requires debhelper >= %s. ' 'Use stdeb 0.3.x to generate source packages ' 'compatible with older versions of debhelper.' % (DH_MIN_VERS, )) python_defaults_version_str = get_version_str('python-all') if len(python_defaults_version_str) == 0: log.warn('This version of stdeb requires python-all >= %s, ' 'but you do not have this package installed. ' 'Could not check compatibility.' % PYTHON_ALL_MIN_VERS) else: if not dpkg_compare_versions(python_defaults_version_str, 'ge', PYTHON_ALL_MIN_VERS): log.warn( 'This version of stdeb requires python-all >= %s. ' 'Use stdeb 0.6.0 or older to generate source packages ' 'that use python-support.' % (PYTHON_ALL_MIN_VERS, )) # D. restore debianized tree os.rename(fullpath_repackaged_dirname + '.debianized', fullpath_repackaged_dirname) # Re-generate tarball using best practices see # http://www.debian.org/doc/developers-reference/ch-best-pkging-practices.en.html # call "dpkg-source -b new_dirname orig_dirname" log.info('CALLING dpkg-source -b %s %s (in dir %s)' % (repackaged_dirname, repackaged_orig_tarball, dist_dir)) dpkg_source('-b', repackaged_dirname, repackaged_orig_tarball, cwd=dist_dir) if 1: shutil.rmtree(fullpath_repackaged_dirname) if not remove_expanded_source_dir: # expand the debian source package dsc_name = debinfo.source + '_' + debinfo.dsc_version + '.dsc' dpkg_source('-x', dsc_name, cwd=dist_dir)
emo = E.search(l) assert emo, l dmo = D.search(l) assert dmo, l eggsndebs.add((emo.group(1), dmo.group(1))) for (egginfo, debname) in eggsndebs: pydist = pkg_resources.Distribution.from_filename(egginfo) try: dd.setdefault(pydist.project_name.lower(), {}).setdefault(pydist, set()).add(debname) except ValueError, le: log.warn("I got an error parsing a .egg-info file named \"%s\" " "from Debian package \"%s\" as a pkg_resources " "Distribution: %s" % ( egginfo, debname, le, )) pass # Now for each requirement, see if a Debian package satisfies it. ops = {'<': '<<', '>': '>>', '==': '=', '<=': '<=', '>=': '>='} for req in parsed_reqs: reqname = req.project_name.lower() gooddebs = set() for pydist, debs in dd.get(reqname, {}).iteritems(): if pydist in req: ## log.info("I found Debian packages \"%s\" which provides " ## "Python package \"%s\", version \"%s\", which " ## "satisfies our version requirements: \"%s\""
def run(self): debinfo = self.get_debinfo() if debinfo.patch_file != '' and self.patch_already_applied: raise RuntimeError('A patch was already applied, but another ' 'patch is requested.') repackaged_dirname = debinfo.source+'-'+debinfo.upstream_version fullpath_repackaged_dirname = os.path.join(self.dist_dir, repackaged_dirname) cleanup_dirs = [] if self.use_premade_distfile is None: # generate original tarball sdist_cmd = self.distribution.get_command_obj('sdist') self.run_command('sdist') source_tarball = None for archive_file in sdist_cmd.get_archive_files(): if archive_file.endswith('.tar.gz'): source_tarball = archive_file if source_tarball is None: raise RuntimeError('sdist did not produce .tar.gz file') # make copy of source tarball in deb_dist/ local_source_tarball = os.path.split(source_tarball)[-1] shutil.copy2( source_tarball, local_source_tarball ) source_tarball = local_source_tarball self.use_premade_distfile = source_tarball else: source_tarball = self.use_premade_distfile # Copy source tree assuming that package-0.1.tar.gz contains # single top-level path 'package-0.1'. The contents of this # directory are then used. if os.path.exists(fullpath_repackaged_dirname): shutil.rmtree(fullpath_repackaged_dirname) tmpdir = tempfile.mkdtemp() expand_sdist_file( os.path.abspath(source_tarball), cwd=tmpdir ) expanded_base_files = os.listdir(tmpdir) assert len(expanded_base_files)==1 actual_package_dirname = expanded_base_files[0] expected_package_dirname = debinfo.module_name + '-' + debinfo.upstream_version assert actual_package_dirname==expected_package_dirname shutil.move( os.path.join( tmpdir, actual_package_dirname ), fullpath_repackaged_dirname) # ensure premade sdist can actually be used self.use_premade_distfile = os.path.abspath(self.use_premade_distfile) expand_dir = os.path.join(self.dist_dir,'tmp_sdist_dsc') cleanup_dirs.append(expand_dir) if os.path.exists(expand_dir): shutil.rmtree(expand_dir) if not os.path.exists(self.dist_dir): os.mkdir(self.dist_dir) os.mkdir(expand_dir) expand_sdist_file(self.use_premade_distfile,cwd=expand_dir) is_tgz=False if self.use_premade_distfile.lower().endswith('.tar.gz'): is_tgz=True # now the sdist package is expanded in expand_dir expanded_root_files = os.listdir(expand_dir) assert len(expanded_root_files)==1 distname_in_premade_distfile = expanded_root_files[0] debianized_dirname = repackaged_dirname original_dirname = os.path.split(distname_in_premade_distfile)[-1] do_repack=False if is_tgz: source_tarball = self.use_premade_distfile else: log.warn('WARNING: .orig.tar.gz will be generated from sdist ' 'archive ("%s") because it is not a .tar.gz file', self.use_premade_distfile) do_repack=True if do_repack: tmp_dir = os.path.join(self.dist_dir, 'tmp_repacking_dir' ) os.makedirs( tmp_dir ) cleanup_dirs.append(tmp_dir) source_tarball = os.path.join(tmp_dir,'repacked_sdist.tar.gz') repack_tarball_with_debianized_dirname(self.use_premade_distfile, source_tarball, debianized_dirname, original_dirname ) if source_tarball is not None: # Because we deleted all .pyc files above, if the # original source dist has them, we will have # (wrongly) deleted them. So, quit loudly rather # than fail silently. for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): raise RuntimeError('original source dist cannot ' 'contain .pyc files') ############################################### # 3. Find all directories for pkgdir in self.distribution.packages or []: debinfo.dirlist += ' ' + pkgdir.replace('.', '/') ############################################### # 4. Build source tree and rename it to be in self.dist_dir build_dsc(debinfo, self.dist_dir, repackaged_dirname, orig_sdist=source_tarball, patch_posix = self.patch_posix, remove_expanded_source_dir=self.remove_expanded_source_dir, ) for rmdir in cleanup_dirs: shutil.rmtree(rmdir)
def run(self): ############################################### # 1. setup initial variables # A. create config defaults module_name = self.distribution.get_name() if self.default_maintainer is None: if (self.distribution.get_maintainer() != 'UNKNOWN' and self.distribution.get_maintainer_email() != 'UNKNOWN'): self.default_maintainer = "%s <%s>"%( self.distribution.get_maintainer(), self.distribution.get_maintainer_email()) elif (self.distribution.get_author() != 'UNKNOWN' and self.distribution.get_author_email() != 'UNKNOWN'): self.default_maintainer = "%s <%s>"%( self.distribution.get_author(), self.distribution.get_author_email()) else: self.default_maintainer = "unknown <unknown@unknown>" # B. find config files (if any) # find .egg-info directory ei_cmd = self.distribution.get_command_obj('egg_info') self.run_command('egg_info') egg_info_dirname = ei_cmd.egg_info config_fname = os.path.join(egg_info_dirname,'stdeb.cfg') egg_module_name = egg_info_dirname[:egg_info_dirname.index('.egg-info')] egg_module_name = egg_module_name.split(os.sep)[-1] cfg_files = [] if os.path.exists(config_fname): cfg_files.append(config_fname) if self.extra_cfg_file is not None: cfg_files.append(self.extra_cfg_file) install_requires = () try: if not self.ignore_install_requires: install_requires = open(os.path.join(egg_info_dirname,'requires.txt'),'rU').read() except EnvironmentError: pass if 1: # determinc whether script specifies setuptools entry_points ep_fname = os.path.join(egg_info_dirname,'entry_points.txt') if os.path.exists(ep_fname): entry_points = open(ep_fname,'rU').readlines() else: entry_points = '' entry_points = [ep.strip() for ep in entry_points] if ('[console_scripts]' in entry_points or '[gui_scripts]' in entry_points): have_script_entry_points = True else: have_script_entry_points = False debinfo = DebianInfo( cfg_files=cfg_files, module_name = module_name, default_distribution=self.default_distribution, default_maintainer=self.default_maintainer, upstream_version = self.distribution.get_version(), egg_module_name = egg_module_name, has_ext_modules = self.distribution.has_ext_modules(), description = self.distribution.get_description()[:60], long_description = self.distribution.get_long_description(), patch_file = self.patch_file, patch_level = self.patch_level, install_requires = install_requires, debian_version = self.debian_version, workaround_548392=self.workaround_548392, force_xs_python_version=self.xs_python_version, have_script_entry_points = have_script_entry_points, pycentral_backwards_compatibility=self.pycentral_backwards_compatibility, setup_requires = (), # XXX How do we get the setup_requires? ) if debinfo.patch_file != '' and self.patch_already_applied: raise RuntimeError('A patch was already applied, but another ' 'patch is requested.') ############################################### # 2. Build source tree and rename it to be in self.dist_dir # A. create source archive in new directory repackaged_dirname = debinfo.source+'-'+debinfo.upstream_version fullpath_repackaged_dirname = os.path.join(self.dist_dir, repackaged_dirname) source_tarball = None cleanup_dirs = [] exclude_dirs = ['.svn'] # copy source tree if os.path.exists(fullpath_repackaged_dirname): shutil.rmtree(fullpath_repackaged_dirname) os.makedirs(fullpath_repackaged_dirname) orig_dir = os.path.abspath(os.curdir) for src in os.listdir(orig_dir): if src not in exclude_dirs+[self.dist_dir,'build','dist']: dst = os.path.join(fullpath_repackaged_dirname,src) if os.path.isdir(src): shutil.copytree(src, dst, symlinks=True) else: shutil.copy2(src, dst ) # remove .pyc files which dpkg-source cannot package for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): fullpath = os.path.join(root,name) os.unlink(fullpath) for name in dirs: if name in exclude_dirs: fullpath = os.path.join(root,name) shutil.rmtree(fullpath) if self.use_premade_distfile is not None: # ensure premade sdist can actually be used self.use_premade_distfile = os.path.abspath(self.use_premade_distfile) expand_dir = os.path.join(self.dist_dir,'tmp_sdist_dsc') cleanup_dirs.append(expand_dir) if os.path.exists(expand_dir): shutil.rmtree(expand_dir) if not os.path.exists(self.dist_dir): os.mkdir(self.dist_dir) os.mkdir(expand_dir) expand_sdist_file(self.use_premade_distfile,cwd=expand_dir) is_tgz=False if self.use_premade_distfile.lower().endswith('.tar.gz'): is_tgz=True # now the sdist package is expanded in expand_dir expanded_root_files = os.listdir(expand_dir) assert len(expanded_root_files)==1 distname_in_premade_distfile = expanded_root_files[0] debianized_dirname = repackaged_dirname original_dirname = os.path.split(distname_in_premade_distfile)[-1] do_repack=False if is_tgz: source_tarball = self.use_premade_distfile else: log.warn('WARNING: .orig.tar.gz will be generated from sdist ' 'archive ("%s") because it is not a .tar.gz file', self.use_premade_distfile) do_repack=True if do_repack: tmp_dir = os.path.join(self.dist_dir, 'tmp_repacking_dir' ) os.makedirs( tmp_dir ) cleanup_dirs.append(tmp_dir) source_tarball = os.path.join(tmp_dir,'repacked_sdist.tar.gz') repack_tarball_with_debianized_dirname(self.use_premade_distfile, source_tarball, debianized_dirname, original_dirname ) if source_tarball is not None: # Because we deleted all .pyc files above, if the # original source dist has them, we will have # (wrongly) deleted them. So, quit loudly rather # than fail silently. for root, dirs, files in os.walk(fullpath_repackaged_dirname): for name in files: if name.endswith('.pyc'): raise RuntimeError('original source dist cannot ' 'contain .pyc files') else: if 0: # haven't figured out why raise NotImplementedError("the code path is broken right now") ############################################### # 3. Find all directories for pkgdir in self.distribution.packages or []: debinfo.dirlist += ' ' + pkgdir.replace('.', '/') ############################################### # 4. Build source tree and rename it to be in self.dist_dir build_dsc(debinfo, self.dist_dir, repackaged_dirname, orig_sdist=source_tarball, patch_posix = self.patch_posix, remove_expanded_source_dir=self.remove_expanded_source_dir) for rmdir in cleanup_dirs: shutil.rmtree(rmdir)