PyXR

c:\python24\lib \ distutils \ command \ bdist_rpm.py



0001 """distutils.command.bdist_rpm
0002 
0003 Implements the Distutils 'bdist_rpm' command (create RPM source and binary
0004 distributions)."""
0005 
0006 # This module should be kept compatible with Python 1.5.2.
0007 
0008 __revision__ = "$Id: bdist_rpm.py,v 1.45 2004/09/17 08:34:12 jafo Exp $"
0009 
0010 import sys, os, string
0011 import glob
0012 from types import *
0013 from distutils.core import Command
0014 from distutils.debug import DEBUG
0015 from distutils.util import get_platform
0016 from distutils.file_util import write_file
0017 from distutils.errors import *
0018 from distutils import log
0019 
0020 class bdist_rpm (Command):
0021 
0022     description = "create an RPM distribution"
0023 
0024     user_options = [
0025         ('bdist-base=', None,
0026          "base directory for creating built distributions"),
0027         ('rpm-base=', None,
0028          "base directory for creating RPMs (defaults to \"rpm\" under "
0029          "--bdist-base; must be specified for RPM 2)"),
0030         ('dist-dir=', 'd',
0031          "directory to put final RPM files in "
0032          "(and .spec files if --spec-only)"),
0033         ('python=', None,
0034          "path to Python interpreter to hard-code in the .spec file "
0035          "(default: \"python\")"),
0036         ('fix-python', None,
0037          "hard-code the exact path to the current Python interpreter in "
0038          "the .spec file"),
0039         ('spec-only', None,
0040          "only regenerate spec file"),
0041         ('source-only', None,
0042          "only generate source RPM"),
0043         ('binary-only', None,
0044          "only generate binary RPM"),
0045         ('use-bzip2', None,
0046          "use bzip2 instead of gzip to create source distribution"),
0047 
0048         # More meta-data: too RPM-specific to put in the setup script,
0049         # but needs to go in the .spec file -- so we make these options
0050         # to "bdist_rpm".  The idea is that packagers would put this
0051         # info in setup.cfg, although they are of course free to
0052         # supply it on the command line.
0053         ('distribution-name=', None,
0054          "name of the (Linux) distribution to which this "
0055          "RPM applies (*not* the name of the module distribution!)"),
0056         ('group=', None,
0057          "package classification [default: \"Development/Libraries\"]"),
0058         ('release=', None,
0059          "RPM release number"),
0060         ('serial=', None,
0061          "RPM serial number"),
0062         ('vendor=', None,
0063          "RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "
0064          "[default: maintainer or author from setup script]"),
0065         ('packager=', None,
0066          "RPM packager (eg. \"Jane Doe <jane@example.net>\")"
0067          "[default: vendor]"),
0068         ('doc-files=', None,
0069          "list of documentation files (space or comma-separated)"),
0070         ('changelog=', None,
0071          "RPM changelog"),
0072         ('icon=', None,
0073          "name of icon file"),
0074         ('provides=', None,
0075          "capabilities provided by this package"),
0076         ('requires=', None,
0077          "capabilities required by this package"),
0078         ('conflicts=', None,
0079          "capabilities which conflict with this package"),
0080         ('build-requires=', None,
0081          "capabilities required to build this package"),
0082         ('obsoletes=', None,
0083          "capabilities made obsolete by this package"),
0084         ('no-autoreq', None,
0085          "do not automatically calculate dependencies"),
0086 
0087         # Actions to take when building RPM
0088         ('keep-temp', 'k',
0089          "don't clean up RPM build directory"),
0090         ('no-keep-temp', None,
0091          "clean up RPM build directory [default]"),
0092         ('use-rpm-opt-flags', None,
0093          "compile with RPM_OPT_FLAGS when building from source RPM"),
0094         ('no-rpm-opt-flags', None,
0095          "do not pass any RPM CFLAGS to compiler"),
0096         ('rpm3-mode', None,
0097          "RPM 3 compatibility mode (default)"),
0098         ('rpm2-mode', None,
0099          "RPM 2 compatibility mode"),
0100 
0101         # Add the hooks necessary for specifying custom scripts
0102         ('prep-script=', None,
0103          "Specify a script for the PREP phase of RPM building"),
0104         ('build-script=', None,
0105          "Specify a script for the BUILD phase of RPM building"),
0106 
0107         ('pre-install=', None,
0108          "Specify a script for the pre-INSTALL phase of RPM building"),
0109         ('install-script=', None,
0110          "Specify a script for the INSTALL phase of RPM building"),
0111         ('post-install=', None,
0112          "Specify a script for the post-INSTALL phase of RPM building"),
0113 
0114         ('pre-uninstall=', None,
0115          "Specify a script for the pre-UNINSTALL phase of RPM building"),
0116         ('post-uninstall=', None,
0117          "Specify a script for the post-UNINSTALL phase of RPM building"),
0118 
0119         ('clean-script=', None,
0120          "Specify a script for the CLEAN phase of RPM building"),
0121 
0122         ('verify-script=', None,
0123          "Specify a script for the VERIFY phase of the RPM build"),
0124 
0125         # Allow a packager to explicitly force an architecture
0126         ('force-arch=', None,
0127          "Force an architecture onto the RPM build process"),
0128        ]
0129 
0130     boolean_options = ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode',
0131                        'no-autoreq']
0132 
0133     negative_opt = {'no-keep-temp': 'keep-temp',
0134                     'no-rpm-opt-flags': 'use-rpm-opt-flags',
0135                     'rpm2-mode': 'rpm3-mode'}
0136 
0137 
0138     def initialize_options (self):
0139         self.bdist_base = None
0140         self.rpm_base = None
0141         self.dist_dir = None
0142         self.python = None
0143         self.fix_python = None
0144         self.spec_only = None
0145         self.binary_only = None
0146         self.source_only = None
0147         self.use_bzip2 = None
0148 
0149         self.distribution_name = None
0150         self.group = None
0151         self.release = None
0152         self.serial = None
0153         self.vendor = None
0154         self.packager = None
0155         self.doc_files = None
0156         self.changelog = None
0157         self.icon = None
0158 
0159         self.prep_script = None
0160         self.build_script = None
0161         self.install_script = None
0162         self.clean_script = None
0163         self.verify_script = None
0164         self.pre_install = None
0165         self.post_install = None
0166         self.pre_uninstall = None
0167         self.post_uninstall = None
0168         self.prep = None
0169         self.provides = None
0170         self.requires = None
0171         self.conflicts = None
0172         self.build_requires = None
0173         self.obsoletes = None
0174 
0175         self.keep_temp = 0
0176         self.use_rpm_opt_flags = 1
0177         self.rpm3_mode = 1
0178         self.no_autoreq = 0
0179 
0180         self.force_arch = None
0181 
0182     # initialize_options()
0183 
0184 
0185     def finalize_options (self):
0186         self.set_undefined_options('bdist', ('bdist_base', 'bdist_base'))
0187         if self.rpm_base is None:
0188             if not self.rpm3_mode:
0189                 raise DistutilsOptionError, \
0190                       "you must specify --rpm-base in RPM 2 mode"
0191             self.rpm_base = os.path.join(self.bdist_base, "rpm")
0192 
0193         if self.python is None:
0194             if self.fix_python:
0195                 self.python = sys.executable
0196             else:
0197                 self.python = "python"
0198         elif self.fix_python:
0199             raise DistutilsOptionError, \
0200                   "--python and --fix-python are mutually exclusive options"
0201 
0202         if os.name != 'posix':
0203             raise DistutilsPlatformError, \
0204                   ("don't know how to create RPM "
0205                    "distributions on platform %s" % os.name)
0206         if self.binary_only and self.source_only:
0207             raise DistutilsOptionError, \
0208                   "cannot supply both '--source-only' and '--binary-only'"
0209 
0210         # don't pass CFLAGS to pure python distributions
0211         if not self.distribution.has_ext_modules():
0212             self.use_rpm_opt_flags = 0
0213 
0214         self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
0215         self.finalize_package_data()
0216 
0217     # finalize_options()
0218 
0219     def finalize_package_data (self):
0220         self.ensure_string('group', "Development/Libraries")
0221         self.ensure_string('vendor',
0222                            "%s <%s>" % (self.distribution.get_contact(),
0223                                         self.distribution.get_contact_email()))
0224         self.ensure_string('packager')
0225         self.ensure_string_list('doc_files')
0226         if type(self.doc_files) is ListType:
0227             for readme in ('README', 'README.txt'):
0228                 if os.path.exists(readme) and readme not in self.doc_files:
0229                     self.doc_files.append(readme)
0230 
0231         self.ensure_string('release', "1")
0232         self.ensure_string('serial')   # should it be an int?
0233 
0234         self.ensure_string('distribution_name')
0235 
0236         self.ensure_string('changelog')
0237           # Format changelog correctly
0238         self.changelog = self._format_changelog(self.changelog)
0239 
0240         self.ensure_filename('icon')
0241 
0242         self.ensure_filename('prep_script')
0243         self.ensure_filename('build_script')
0244         self.ensure_filename('install_script')
0245         self.ensure_filename('clean_script')
0246         self.ensure_filename('verify_script')
0247         self.ensure_filename('pre_install')
0248         self.ensure_filename('post_install')
0249         self.ensure_filename('pre_uninstall')
0250         self.ensure_filename('post_uninstall')
0251 
0252         # XXX don't forget we punted on summaries and descriptions -- they
0253         # should be handled here eventually!
0254 
0255         # Now *this* is some meta-data that belongs in the setup script...
0256         self.ensure_string_list('provides')
0257         self.ensure_string_list('requires')
0258         self.ensure_string_list('conflicts')
0259         self.ensure_string_list('build_requires')
0260         self.ensure_string_list('obsoletes')
0261 
0262         self.ensure_string('force_arch')
0263     # finalize_package_data ()
0264 
0265 
0266     def run (self):
0267 
0268         if DEBUG:
0269             print "before _get_package_data():"
0270             print "vendor =", self.vendor
0271             print "packager =", self.packager
0272             print "doc_files =", self.doc_files
0273             print "changelog =", self.changelog
0274 
0275         # make directories
0276         if self.spec_only:
0277             spec_dir = self.dist_dir
0278             self.mkpath(spec_dir)
0279         else:
0280             rpm_dir = {}
0281             for d in ('SOURCES', 'SPECS', 'BUILD', 'RPMS', 'SRPMS'):
0282                 rpm_dir[d] = os.path.join(self.rpm_base, d)
0283                 self.mkpath(rpm_dir[d])
0284             spec_dir = rpm_dir['SPECS']
0285 
0286         # Spec file goes into 'dist_dir' if '--spec-only specified',
0287         # build/rpm.<plat> otherwise.
0288         spec_path = os.path.join(spec_dir,
0289                                  "%s.spec" % self.distribution.get_name())
0290         self.execute(write_file,
0291                      (spec_path,
0292                       self._make_spec_file()),
0293                      "writing '%s'" % spec_path)
0294 
0295         if self.spec_only: # stop if requested
0296             return
0297 
0298         # Make a source distribution and copy to SOURCES directory with
0299         # optional icon.
0300         sdist = self.reinitialize_command('sdist')
0301         if self.use_bzip2:
0302             sdist.formats = ['bztar']
0303         else:
0304             sdist.formats = ['gztar']
0305         self.run_command('sdist')
0306 
0307         source = sdist.get_archive_files()[0]
0308         source_dir = rpm_dir['SOURCES']
0309         self.copy_file(source, source_dir)
0310 
0311         if self.icon:
0312             if os.path.exists(self.icon):
0313                 self.copy_file(self.icon, source_dir)
0314             else:
0315                 raise DistutilsFileError, \
0316                       "icon file '%s' does not exist" % self.icon
0317 
0318 
0319         # build package
0320         log.info("building RPMs")
0321         rpm_cmd = ['rpm']
0322         if os.path.exists('/usr/bin/rpmbuild') or \
0323            os.path.exists('/bin/rpmbuild'):
0324             rpm_cmd = ['rpmbuild']
0325         if self.source_only: # what kind of RPMs?
0326             rpm_cmd.append('-bs')
0327         elif self.binary_only:
0328             rpm_cmd.append('-bb')
0329         else:
0330             rpm_cmd.append('-ba')
0331         if self.rpm3_mode:
0332             rpm_cmd.extend(['--define',
0333                              '_topdir %s' % os.path.abspath(self.rpm_base)])
0334         if not self.keep_temp:
0335             rpm_cmd.append('--clean')
0336         rpm_cmd.append(spec_path)
0337         self.spawn(rpm_cmd)
0338 
0339         # XXX this is a nasty hack -- we really should have a proper way to
0340         # find out the names of the RPM files created; also, this assumes
0341         # that RPM creates exactly one source and one binary RPM.
0342         if not self.dry_run:
0343             if not self.binary_only:
0344                 srpms = glob.glob(os.path.join(rpm_dir['SRPMS'], "*.rpm"))
0345                 assert len(srpms) == 1, \
0346                        "unexpected number of SRPM files found: %s" % srpms
0347                 self.move_file(srpms[0], self.dist_dir)
0348 
0349             if not self.source_only:
0350                 rpms = glob.glob(os.path.join(rpm_dir['RPMS'], "*/*.rpm"))
0351                 debuginfo = glob.glob(os.path.join(rpm_dir['RPMS'], \
0352                                                    "*/*debuginfo*.rpm"))
0353                 if debuginfo:
0354                     rpms.remove(debuginfo[0])
0355                 assert len(rpms) == 1, \
0356                        "unexpected number of RPM files found: %s" % rpms
0357                 self.move_file(rpms[0], self.dist_dir)
0358                 if debuginfo:
0359                     self.move_file(debuginfo[0], self.dist_dir)
0360     # run()
0361 
0362 
0363     def _make_spec_file(self):
0364         """Generate the text of an RPM spec file and return it as a
0365         list of strings (one per line).
0366         """
0367         # definitions and headers
0368         spec_file = [
0369             '%define name ' + self.distribution.get_name(),
0370             '%define version ' + self.distribution.get_version().replace('-','_'),
0371             '%define release ' + self.release.replace('-','_'),
0372             '',
0373             'Summary: ' + self.distribution.get_description(),
0374             ]
0375 
0376         # put locale summaries into spec file
0377         # XXX not supported for now (hard to put a dictionary
0378         # in a config file -- arg!)
0379         #for locale in self.summaries.keys():
0380         #    spec_file.append('Summary(%s): %s' % (locale,
0381         #                                          self.summaries[locale]))
0382 
0383         spec_file.extend([
0384             'Name: %{name}',
0385             'Version: %{version}',
0386             'Release: %{release}',])
0387 
0388         # XXX yuck! this filename is available from the "sdist" command,
0389         # but only after it has run: and we create the spec file before
0390         # running "sdist", in case of --spec-only.
0391         if self.use_bzip2:
0392             spec_file.append('Source0: %{name}-%{version}.tar.bz2')
0393         else:
0394             spec_file.append('Source0: %{name}-%{version}.tar.gz')
0395 
0396         spec_file.extend([
0397             'License: ' + self.distribution.get_license(),
0398             'Group: ' + self.group,
0399             'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot',
0400             'Prefix: %{_prefix}', ])
0401 
0402         if not self.force_arch:
0403             # noarch if no extension modules
0404             if not self.distribution.has_ext_modules():
0405                 spec_file.append('BuildArch: noarch')
0406         else:
0407             spec_file.append( 'BuildArch: %s' % self.force_arch )
0408 
0409         for field in ('Vendor',
0410                       'Packager',
0411                       'Provides',
0412                       'Requires',
0413                       'Conflicts',
0414                       'Obsoletes',
0415                       ):
0416             val = getattr(self, string.lower(field))
0417             if type(val) is ListType:
0418                 spec_file.append('%s: %s' % (field, string.join(val)))
0419             elif val is not None:
0420                 spec_file.append('%s: %s' % (field, val))
0421 
0422 
0423         if self.distribution.get_url() != 'UNKNOWN':
0424             spec_file.append('Url: ' + self.distribution.get_url())
0425 
0426         if self.distribution_name:
0427             spec_file.append('Distribution: ' + self.distribution_name)
0428 
0429         if self.build_requires:
0430             spec_file.append('BuildRequires: ' +
0431                              string.join(self.build_requires))
0432 
0433         if self.icon:
0434             spec_file.append('Icon: ' + os.path.basename(self.icon))
0435 
0436         if self.no_autoreq:
0437             spec_file.append('AutoReq: 0')
0438 
0439         spec_file.extend([
0440             '',
0441             '%description',
0442             self.distribution.get_long_description()
0443             ])
0444 
0445         # put locale descriptions into spec file
0446         # XXX again, suppressed because config file syntax doesn't
0447         # easily support this ;-(
0448         #for locale in self.descriptions.keys():
0449         #    spec_file.extend([
0450         #        '',
0451         #        '%description -l ' + locale,
0452         #        self.descriptions[locale],
0453         #        ])
0454 
0455         # rpm scripts
0456         # figure out default build script
0457         def_build = "%s setup.py build" % self.python
0458         if self.use_rpm_opt_flags:
0459             def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build
0460 
0461         # insert contents of files
0462 
0463         # XXX this is kind of misleading: user-supplied options are files
0464         # that we open and interpolate into the spec file, but the defaults
0465         # are just text that we drop in as-is.  Hmmm.
0466 
0467         script_options = [
0468             ('prep', 'prep_script', "%setup"),
0469             ('build', 'build_script', def_build),
0470             ('install', 'install_script',
0471              ("%s setup.py install "
0472               "--root=$RPM_BUILD_ROOT "
0473               "--record=INSTALLED_FILES") % self.python),
0474             ('clean', 'clean_script', "rm -rf $RPM_BUILD_ROOT"),
0475             ('verifyscript', 'verify_script', None),
0476             ('pre', 'pre_install', None),
0477             ('post', 'post_install', None),
0478             ('preun', 'pre_uninstall', None),
0479             ('postun', 'post_uninstall', None),
0480         ]
0481 
0482         for (rpm_opt, attr, default) in script_options:
0483             # Insert contents of file referred to, if no file is referred to
0484             # use 'default' as contents of script
0485             val = getattr(self, attr)
0486             if val or default:
0487                 spec_file.extend([
0488                     '',
0489                     '%' + rpm_opt,])
0490                 if val:
0491                     spec_file.extend(string.split(open(val, 'r').read(), '\n'))
0492                 else:
0493                     spec_file.append(default)
0494 
0495 
0496         # files section
0497         spec_file.extend([
0498             '',
0499             '%files -f INSTALLED_FILES',
0500             '%defattr(-,root,root)',
0501             ])
0502 
0503         if self.doc_files:
0504             spec_file.append('%doc ' + string.join(self.doc_files))
0505 
0506         if self.changelog:
0507             spec_file.extend([
0508                 '',
0509                 '%changelog',])
0510             spec_file.extend(self.changelog)
0511 
0512         return spec_file
0513 
0514     # _make_spec_file ()
0515 
0516     def _format_changelog(self, changelog):
0517         """Format the changelog correctly and convert it to a list of strings
0518         """
0519         if not changelog:
0520             return changelog
0521         new_changelog = []
0522         for line in string.split(string.strip(changelog), '\n'):
0523             line = string.strip(line)
0524             if line[0] == '*':
0525                 new_changelog.extend(['', line])
0526             elif line[0] == '-':
0527                 new_changelog.append(line)
0528             else:
0529                 new_changelog.append('  ' + line)
0530 
0531         # strip trailing newline inserted by first changelog entry
0532         if not new_changelog[0]:
0533             del new_changelog[0]
0534 
0535         return new_changelog
0536 
0537     # _format_changelog()
0538 
0539 # class bdist_rpm
0540 

Generated by PyXR 0.9.4
SourceForge.net Logo