diff options
author | Gregory P. Smith <greg@mad-scientist.com> | 2000-05-13 03:11:40 (GMT) |
---|---|---|
committer | Gregory P. Smith <greg@mad-scientist.com> | 2000-05-13 03:11:40 (GMT) |
commit | 86ee81e34bcd223c94de2a65ed7b88f976989410 (patch) | |
tree | 8eea7f6c317aeb59960a4c5c9f95ef10e51fbaf7 /Lib | |
parent | 21b9e910a5b2a53b57b5fc48a898f92c4c810096 (diff) | |
download | cpython-86ee81e34bcd223c94de2a65ed7b88f976989410.zip cpython-86ee81e34bcd223c94de2a65ed7b88f976989410.tar.gz cpython-86ee81e34bcd223c94de2a65ed7b88f976989410.tar.bz2 |
Contribution from Harry Henry Gebel: the 'bdist_rpm' command.
(Completely uninspected and untested by me, this is just to
get the code into CVS!)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/distutils/command/bdist_rpm.py | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/Lib/distutils/command/bdist_rpm.py b/Lib/distutils/command/bdist_rpm.py new file mode 100644 index 0000000..9c3aca3 --- /dev/null +++ b/Lib/distutils/command/bdist_rpm.py @@ -0,0 +1,390 @@ +"""distutils.command.bdist_rpm + +Implements the Distutils 'bdist_rpm' command (create RPM source and binary +distributions.""" + +# created 2000/04/25, by Harry Henry Gebel + +__revision__ = "$Id$" + +from os.path import exists, basename +import os +from distutils.core import Command +from distutils.util import mkpath, write_file, copy_file +from distutils.errors import * +from string import join, lower +from types import StringType, DictType, LongType, FloatType, IntType, \ + ListType, TupleType + +class bdist_rpm (Command): + + description = "create an RPM distribution" + + user_options = [ + ('spec-only', None, + "Only regenerate spec file"), + ('source-only', None, + "Only generate source RPM"), + ('binary-only', None, + "Only generate binary RPM"), + ('use-bzip2', None, + "Use bzip2 instead of gzip to create source distribution"), + ('no-clean', None, + "Do not clean RPM build directory"), + ('no-rpm-opt-flags', None, + "Do not pass any RPM CFLAGS to compiler") + ] + + + def initialize_options (self): + self.spec_only = None + self.binary_only = None + self.source_only = None + self.use_bzip2 = None + self.no_clean = None + self.no_rpm_opt_flags = None + + # initialize_options() + + + def finalize_options (self): + if os.name != 'posix': + raise DistutilsPlatformError, \ + ("don't know how to create RPM " + "distributions on platform %s" % os.name) + if self.binary_only and self.source_only: + raise DistutilsOptionsError, \ + "Cannot supply both '--source-only' and '--binary-only'" + # don't pass CFLAGS to pure python distributions + if not self.distribution.has_ext_modules(): + self.no_rpm_opt_flags = 1 + + # finalize_options() + + + def run (self): + self._get_package_data() # get packaging info + + + # make directories + if self.spec_only: + self.execute(mkpath, ('redhat',), "Created './redhat' directory") + else: + self.execute(mkpath, ('build/rpm/SOURCES',), + "Created RPM source directory") + self.execute(mkpath, ('build/rpm/SPECS',), + "Created RPM source directory") + self.execute(mkpath, ('build/rpm/BUILD',), + "Created RPM source directory") + self.execute(mkpath, ('build/rpm/RPMS',), + "Created RPM source directory") + self.execute(mkpath, ('build/rpm/SRPMS',), + "Created RPM source directory") + + # spec file goes into .redhat directory if '--spec-only specified', + # into build/rpm/spec otherwisu + if self.spec_only: + spec_path = './redhat/%s.spec' % self.distribution.get_name() + else: + spec_path = ('build/rpm/SPECS/%s.spec' % + self.distribution.get_name()) + self.execute(write_file, + (spec_path, + self._make_spec_file()), + 'Writing .spec file') + + if self.spec_only: # stop if requested + return + + # make a source distribution and copy to SOURCES directory with + # optional icon + sdist = self.find_peer ('sdist') + if self.use_bzip2: + sdist.formats = ['bztar'] + else: + sdist.formats = ['gztar'] + self.run_peer('sdist') + if self.use_bzip2: + source = self.distribution.get_fullname() + '.tar.bz2' + else: + source = self.distribution.get_fullname() + '.tar.gz' + self.execute(copy_file, (source, 'build/rpm/SOURCES'), + 'Copying source distribution to SOURCES') + if self.icon: + if exists(self.icon): + self.execute(copy_file, (self.icon, 'build/rpm/SOURCES'), + 'Copying icon to SOURCES') + else: + raise DistutilsFileError, \ + "Unable to find icon file '%s'" % self.icon + + + # build package + self.announce('Building RPMs') + rpm_args = ['rpm',] + if self.source_only: # what kind of RPMs? + rpm_args.append('-bs') + elif self.binary_only: + rpm_args.append('-bb') + else: + rpm_args.append('-ba') + topdir = os.getcwd() + 'build/rpm' + rpm_args.extend(['--define', + '_topdir ' + os.getcwd() + '/build/rpm',]) + if not self.no_clean: + rpm_args.append('--clean') + rpm_args.append(spec_path) + self.spawn(rpm_args) + + # run() + + + def _get_package_data(self): + ''' Get data needed to generate spec file, first from the + DistributionMetadata class, then from the package_data file, which is + Python code read with execfile() ''' + + package_type = 'rpm' + + # read in package data, if any + if exists('package_data'): + try: + exec(open('package_data')) + except: + raise DistutilsOptionError, 'Unable to parse package data file' + + # set instance variables, supplying default value if not provided in + # package data file + self.package_data = locals() + + # the following variables must be {string (len() = 2): string} + self.summaries = self._check_string_dict('summaries') + self.descriptions = self._check_string_dict('descriptions') + + # The following variable must be an ordinary number or a string + self.release = self._check_number_or_string('release', '1') + self.serial = self._check_number_or_string('serial') + + # The following variables must be strings + self.group = self._check_string('group', 'Development/Libraries') + self.vendor = self._check_string('vendor') + self.packager = self._check_string('packager') + self.changelog = self._check_string('changelog') + self.icon = self._check_string('icon') + self.distribution_name = self._check_string('distribution_name') + self.pre = self._check_string('pre') + self.post = self._check_string('post') + self.preun = self._check_string('preun') + self.postun = self._check_string('postun') + self.prep = self._check_string('prep', '%setup') + if not self.no_rpm_opt_flags: + self.build = (self._check_string( + 'build', + 'env CFLAGS="$RPM_OPT_FLAGS" python setup.py build')) + else: + self.build = (self._check_string('build', 'python setup.py build')) + self.install = self._check_string( + 'install', + 'python setup.py install --root=$RPM_BUILD_ROOT --record') + self.clean = self._check_string( + 'clean', + 'rm -rf $RPM_BUILD_ROOT') + + # The following variables must be a list or tuple of strings, or a + # string + self.doc = self._check_string_list('doc') + if type(self.doc) == ListType: + for readme in ('README', 'README.txt'): + if exists(readme) and readme not in self.doc: + self.doc.append(readme) + self.doc = join(self.doc) + self.provides = join(self._check_string_list('provides')) + self.requires = join(self._check_string_list('requires')) + self.conflicts = join(self._check_string_list('conflicts')) + self.build_requires = join(self._check_string_list('build_requires')) + self.obsoletes = join(self._check_string_list('obsoletes')) + + def _make_spec_file(self): + ''' Generate an RPM spec file ''' + + # definitons and headers + spec_file = [ + '%define name ' + self.distribution.get_name(), + '%define version ' + self.distribution.get_version(), + '%define release ' + self.release, + '', + 'Summary: ' + self.distribution.get_description(), + ] + + # put locale summaries into spec file + for locale in self.summaries.keys(): + spec_file.append('Summary(%s): %s' % (locale, + self.summaries[locale])) + + spec_file.extend([ + 'Name: %{name}', + 'Version: %{version}', + 'Release: %{release}',]) + if self.use_bzip2: + spec_file.append('Source0: %{name}-%{version}.tar.bz2') + else: + spec_file.append('Source0: %{name}-%{version}.tar.gz') + spec_file.extend([ + 'Copyright: ' + self.distribution.get_licence(), + 'Group: ' + self.group, + 'BuildRoot: %{_tmppath}/%{name}-buildroot', + 'Prefix: %{_prefix}', ]) + + # noarch if no extension modules + if not self.distribution.has_ext_modules(): + spec_file.append('BuildArchitectures: noarch') + + for field in ('Vendor', + 'Packager', + 'Provides', + 'Requires', + 'Conflicts', + 'Obsoletes', + ): + if getattr(self, lower(field)): + spec_file.append('%s: %s' % (field, getattr(self, + lower(field)))) + + if self.distribution.get_url() != 'UNKNOWN': + spec_file.append('Url: ' + self.distribution.get_url()) + + if self.distribution_name: + spec_file.append('Distribution: ' + self.distribution_name) + + if self.build_requires: + spec_file.append('BuildRequires: ' + self.build_requires) + + if self.icon: + spec_file.append('Icon: ' + basename(self.icon)) + + spec_file.extend([ + '', + '%description', + self.distribution.get_long_description() + ]) + + # put locale descriptions into spec file + for locale in self.descriptions.keys(): + spec_file.extend([ + '', + '%description -l ' + locale, + self.descriptions[locale], + ]) + + # rpm scripts + for script in ('prep', + 'build', + 'install', + 'clean', + 'pre', + 'post', + 'preun', + 'postun', + ): + if getattr(self, script): + spec_file.extend([ + '', + '%' + script, + getattr(self, script), + ]) + + + # files section + spec_file.extend([ + '', + '%files -f INSTALLED_FILES', + '%defattr(-,root,root)', + ]) + + if self.doc: + spec_file.append('%doc ' + self.doc) + + if self.changelog: + spec_file.extend([ + '', + '%changelog', + self.changelog + ]) + + return spec_file + + def _check_string_dict(self, var_name, default_value = {}): + ''' Tests a wariable to determine if it is {string: string}, + var_name is the name of the wariable. Return the value if it is valid, + returns default_value if the variable does not exist, raises + DistutilsOptionError if the variable is not valid''' + if self.package_data.has_key(var_name): + pass_test = 1 # set to 0 if fails test + value = self.package_data[var_name] + if type(value) == DictType: + for locale in value.keys(): + if (type(locale) != StringType) or (type(value[locale]) != + StringType): + pass_test = 0 + break + if pass_test: + return test_me + raise DistutilsOptionError, \ + ("Error in package_data: '%s' must be dictionary: " + '{string: string}' % var_name) + else: + return default_value + + def _check_string(self, var_name, default_value = None): + ''' Tests a variable in package_data to determine if it is a string, + var_name is the name of the wariable. Return the value if it is a + string, returns default_value if the variable does not exist, raises + DistutilsOptionError if the variable is not a string''' + if self.package_data.has_key(var_name): + if type(self.package_data[var_name]) == StringType: + return self.package_data[var_name] + else: + raise DistutilsOptionError, \ + "Error in package_data: '%s' must be a string" % var_name + else: + return default_value + + def _check_number_or_string(self, var_name, default_value = None): + ''' Tests a variable in package_data to determine if it is a number or + a string, var_name is the name of the wariable. Return the value if it + is valid, returns default_value if the variable does not exist, raises + DistutilsOptionError if the variable is not valid''' + if self.package_data.has_key(var_name): + if type(self.package_data[var_name]) in (StringType, LongType, + IntType, FloatType): + return str(self.package_data[var_name]) + else: + raise DistutilsOptionError, \ + ("Error in package_data: '%s' must be a string or a " + 'number' % var_name) + else: + return default_value + + def _check_string_list(self, var_name, default_value = []): + ''' Tests a variable in package_data to determine if it is a string or + a list or tuple of strings, var_name is the name of the wariable. + Return the value as a string or a list if it is valid, returns + default_value if the variable does not exist, raises + DistutilsOptionError if the variable is not valid''' + if self.package_data.has_key(var_name): + value = self.package_data[var_name] + pass_test = 1 + if type(value) == StringType: + return value + elif type(value) in (ListType, TupleType): + for item in value: + if type(item) != StringType: + pass_test = 0 + break + if pass_test: + return list(value) + raise DistutilsOptionError, \ + ("Error in package_data: '%s' must be a string or a " + 'list or tuple of strings' % var_name) + else: + return default_value |