]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/command/bdist_rpm.py
   1 """distutils.command.bdist_rpm 
   3 Implements the Distutils 'bdist_rpm' command (create RPM source and binary 
   6 # This module should be kept compatible with Python 1.5.2. 
  10 import sys
, os
, string
 
  13 from distutils
.core 
import Command
 
  14 from distutils
.debug 
import DEBUG
 
  15 from distutils
.util 
import get_platform
 
  16 from distutils
.file_util 
import write_file
 
  17 from distutils
.errors 
import * 
  18 from distutils 
import log
 
  20 class bdist_rpm (Command
): 
  22     description 
= "create an RPM distribution" 
  26          "base directory for creating built distributions"), 
  28          "base directory for creating RPMs (defaults to \"rpm\" under " 
  29          "--bdist-base; must be specified for RPM 2)"), 
  31          "directory to put final RPM files in " 
  32          "(and .spec files if --spec-only)"), 
  34          "path to Python interpreter to hard-code in the .spec file " 
  35          "(default: \"python\")"), 
  37          "hard-code the exact path to the current Python interpreter in " 
  40          "only regenerate spec file"), 
  42          "only generate source RPM"), 
  44          "only generate binary RPM"), 
  46          "use bzip2 instead of gzip to create source distribution"), 
  48         # More meta-data: too RPM-specific to put in the setup script, 
  49         # but needs to go in the .spec file -- so we make these options 
  50         # to "bdist_rpm".  The idea is that packagers would put this 
  51         # info in setup.cfg, although they are of course free to 
  52         # supply it on the command line. 
  53         ('distribution-name=', None, 
  54          "name of the (Linux) distribution to which this " 
  55          "RPM applies (*not* the name of the module distribution!)"), 
  57          "package classification [default: \"Development/Libraries\"]"), 
  59          "RPM release number"), 
  63          "RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") " 
  64          "[default: maintainer or author from setup script]"), 
  66          "RPM packager (eg. \"Jane Doe <jane@example.net>\")" 
  69          "list of documentation files (space or comma-separated)"), 
  75          "capabilities provided by this package"), 
  77          "capabilities required by this package"), 
  79          "capabilities which conflict with this package"), 
  80         ('build-requires=', None, 
  81          "capabilities required to build this package"), 
  83          "capabilities made obsolete by this package"), 
  85         # Actions to take when building RPM 
  87          "don't clean up RPM build directory"), 
  88         ('no-keep-temp', None, 
  89          "clean up RPM build directory [default]"), 
  90         ('use-rpm-opt-flags', None, 
  91          "compile with RPM_OPT_FLAGS when building from source RPM"), 
  92         ('no-rpm-opt-flags', None, 
  93          "do not pass any RPM CFLAGS to compiler"), 
  95          "RPM 3 compatibility mode (default)"), 
  97          "RPM 2 compatibility mode"), 
 100     boolean_options 
= ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode'] 
 102     negative_opt 
= {'no-keep-temp': 'keep-temp', 
 103                     'no-rpm-opt-flags': 'use-rpm-opt-flags', 
 104                     'rpm2-mode': 'rpm3-mode'} 
 107     def initialize_options (self
): 
 108         self
.bdist_base 
= None 
 112         self
.fix_python 
= None 
 113         self
.spec_only 
= None 
 114         self
.binary_only 
= None 
 115         self
.source_only 
= None 
 116         self
.use_bzip2 
= None 
 118         self
.distribution_name 
= None 
 124         self
.doc_files 
= None 
 125         self
.changelog 
= None 
 128         self
.prep_script 
= None 
 129         self
.build_script 
= None 
 130         self
.install_script 
= None 
 131         self
.clean_script 
= None 
 132         self
.verify_script 
= None 
 133         self
.pre_install 
= None 
 134         self
.post_install 
= None 
 135         self
.pre_uninstall 
= None 
 136         self
.post_uninstall 
= None 
 140         self
.conflicts 
= None 
 141         self
.build_requires 
= None 
 142         self
.obsoletes 
= None 
 145         self
.use_rpm_opt_flags 
= 1 
 148     # initialize_options() 
 151     def finalize_options (self
): 
 152         self
.set_undefined_options('bdist', ('bdist_base', 'bdist_base')) 
 153         if self
.rpm_base 
is None: 
 154             if not self
.rpm3_mode
: 
 155                 raise DistutilsOptionError
, \
 
 156                       "you must specify --rpm-base in RPM 2 mode" 
 157             self
.rpm_base 
= os
.path
.join(self
.bdist_base
, "rpm") 
 159         if self
.python 
is None: 
 161                 self
.python 
= sys
.executable
 
 163                 self
.python 
= "python" 
 164         elif self
.fix_python
: 
 165             raise DistutilsOptionError
, \
 
 166                   "--python and --fix-python are mutually exclusive options" 
 168         if os
.name 
!= 'posix': 
 169             raise DistutilsPlatformError
, \
 
 170                   ("don't know how to create RPM " 
 171                    "distributions on platform %s" % os
.name
) 
 172         if self
.binary_only 
and self
.source_only
: 
 173             raise DistutilsOptionError
, \
 
 174                   "cannot supply both '--source-only' and '--binary-only'" 
 176         # don't pass CFLAGS to pure python distributions 
 177         if not self
.distribution
.has_ext_modules(): 
 178             self
.use_rpm_opt_flags 
= 0 
 180         self
.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) 
 181         self
.finalize_package_data() 
 185     def finalize_package_data (self
): 
 186         self
.ensure_string('group', "Development/Libraries") 
 187         self
.ensure_string('vendor', 
 188                            "%s <%s>" % (self
.distribution
.get_contact(), 
 189                                         self
.distribution
.get_contact_email())) 
 190         self
.ensure_string('packager') 
 191         self
.ensure_string_list('doc_files') 
 192         if type(self
.doc_files
) is ListType
: 
 193             for readme 
in ('README', 'README.txt'): 
 194                 if os
.path
.exists(readme
) and readme 
not in self
.doc_files
: 
 195                     self
.doc_files
.append(readme
) 
 197         self
.ensure_string('release', "1") 
 198         self
.ensure_string('serial')   # should it be an int? 
 200         self
.ensure_string('distribution_name') 
 202         self
.ensure_string('changelog') 
 203           # Format changelog correctly 
 204         self
.changelog 
= self
._format
_changelog
(self
.changelog
) 
 206         self
.ensure_filename('icon') 
 208         self
.ensure_filename('prep_script') 
 209         self
.ensure_filename('build_script') 
 210         self
.ensure_filename('install_script') 
 211         self
.ensure_filename('clean_script') 
 212         self
.ensure_filename('verify_script') 
 213         self
.ensure_filename('pre_install') 
 214         self
.ensure_filename('post_install') 
 215         self
.ensure_filename('pre_uninstall') 
 216         self
.ensure_filename('post_uninstall') 
 218         # XXX don't forget we punted on summaries and descriptions -- they 
 219         # should be handled here eventually! 
 221         # Now *this* is some meta-data that belongs in the setup script... 
 222         self
.ensure_string_list('provides') 
 223         self
.ensure_string_list('requires') 
 224         self
.ensure_string_list('conflicts') 
 225         self
.ensure_string_list('build_requires') 
 226         self
.ensure_string_list('obsoletes') 
 228     # finalize_package_data () 
 234             print "before _get_package_data():" 
 235             print "vendor =", self
.vendor
 
 236             print "packager =", self
.packager
 
 237             print "doc_files =", self
.doc_files
 
 238             print "changelog =", self
.changelog
 
 242             spec_dir 
= self
.dist_dir
 
 243             self
.mkpath(spec_dir
) 
 246             for d 
in ('SOURCES', 'SPECS', 'BUILD', 'RPMS', 'SRPMS'): 
 247                 rpm_dir
[d
] = os
.path
.join(self
.rpm_base
, d
) 
 248                 self
.mkpath(rpm_dir
[d
]) 
 249             spec_dir 
= rpm_dir
['SPECS'] 
 251         # Spec file goes into 'dist_dir' if '--spec-only specified', 
 252         # build/rpm.<plat> otherwise. 
 253         spec_path 
= os
.path
.join(spec_dir
, 
 254                                  "%s.spec" % self
.distribution
.get_name()) 
 255         self
.execute(write_file
, 
 257                       self
._make
_spec
_file
()), 
 258                      "writing '%s'" % spec_path
) 
 260         if self
.spec_only
: # stop if requested 
 263         # Make a source distribution and copy to SOURCES directory with 
 265         sdist 
= self
.reinitialize_command('sdist') 
 267             sdist
.formats 
= ['bztar'] 
 269             sdist
.formats 
= ['gztar'] 
 270         self
.run_command('sdist') 
 272         source 
= sdist
.get_archive_files()[0] 
 273         source_dir 
= rpm_dir
['SOURCES'] 
 274         self
.copy_file(source
, source_dir
) 
 277             if os
.path
.exists(self
.icon
): 
 278                 self
.copy_file(self
.icon
, source_dir
) 
 280                 raise DistutilsFileError
, \
 
 281                       "icon file '%s' does not exist" % self
.icon
 
 285         log
.info("building RPMs") 
 287         if os
.path
.exists('/usr/bin/rpmbuild') or \
 
 288            os
.path
.exists('/bin/rpmbuild'): 
 289             rpm_cmd 
= ['rpmbuild'] 
 290         if self
.source_only
: # what kind of RPMs? 
 291             rpm_cmd
.append('-bs') 
 292         elif self
.binary_only
: 
 293             rpm_cmd
.append('-bb') 
 295             rpm_cmd
.append('-ba') 
 297             rpm_cmd
.extend(['--define', 
 298                              '_topdir %s/%s' % (os
.getcwd(), self
.rpm_base
),]) 
 299         if not self
.keep_temp
: 
 300             rpm_cmd
.append('--clean') 
 301         rpm_cmd
.append(spec_path
) 
 304         # XXX this is a nasty hack -- we really should have a proper way to 
 305         # find out the names of the RPM files created; also, this assumes 
 306         # that RPM creates exactly one source and one binary RPM. 
 308             if not self
.binary_only
: 
 309                 srpms 
= glob
.glob(os
.path
.join(rpm_dir
['SRPMS'], "*.rpm")) 
 310                 assert len(srpms
) == 1, \
 
 311                        "unexpected number of SRPM files found: %s" % srpms
 
 312                 self
.move_file(srpms
[0], self
.dist_dir
) 
 314             if not self
.source_only
: 
 315                 rpms 
= glob
.glob(os
.path
.join(rpm_dir
['RPMS'], "*/*.rpm")) 
 316                 assert len(rpms
) == 1, \
 
 317                        "unexpected number of RPM files found: %s" % rpms
 
 318                 self
.move_file(rpms
[0], self
.dist_dir
) 
 323     def _make_spec_file(self
): 
 324         """Generate the text of an RPM spec file and return it as a 
 325         list of strings (one per line). 
 327         # definitions and headers 
 329             '%define name ' + self
.distribution
.get_name(), 
 330             '%define version ' + self
.distribution
.get_version(), 
 331             '%define release ' + self
.release
, 
 333             'Summary: ' + self
.distribution
.get_description(), 
 336         # put locale summaries into spec file 
 337         # XXX not supported for now (hard to put a dictionary 
 338         # in a config file -- arg!) 
 339         #for locale in self.summaries.keys(): 
 340         #    spec_file.append('Summary(%s): %s' % (locale, 
 341         #                                          self.summaries[locale])) 
 345             'Version: %{version}', 
 346             'Release: %{release}',]) 
 348         # XXX yuck! this filename is available from the "sdist" command, 
 349         # but only after it has run: and we create the spec file before 
 350         # running "sdist", in case of --spec-only. 
 352             spec_file
.append('Source0: %{name}-%{version}.tar.bz2') 
 354             spec_file
.append('Source0: %{name}-%{version}.tar.gz') 
 357             'License: ' + self
.distribution
.get_license(), 
 358             'Group: ' + self
.group
, 
 359             'BuildRoot: %{_tmppath}/%{name}-buildroot', 
 360             'Prefix: %{_prefix}', ]) 
 362         # noarch if no extension modules 
 363         if not self
.distribution
.has_ext_modules(): 
 364             spec_file
.append('BuildArchitectures: noarch') 
 366         for field 
in ('Vendor', 
 373             val 
= getattr(self
, string
.lower(field
)) 
 374             if type(val
) is ListType
: 
 375                 spec_file
.append('%s: %s' % (field
, string
.join(val
))) 
 376             elif val 
is not None: 
 377                 spec_file
.append('%s: %s' % (field
, val
)) 
 380         if self
.distribution
.get_url() != 'UNKNOWN': 
 381             spec_file
.append('Url: ' + self
.distribution
.get_url()) 
 383         if self
.distribution_name
: 
 384             spec_file
.append('Distribution: ' + self
.distribution_name
) 
 386         if self
.build_requires
: 
 387             spec_file
.append('BuildRequires: ' + 
 388                              string
.join(self
.build_requires
)) 
 391             spec_file
.append('Icon: ' + os
.path
.basename(self
.icon
)) 
 396             self
.distribution
.get_long_description() 
 399         # put locale descriptions into spec file 
 400         # XXX again, suppressed because config file syntax doesn't 
 401         # easily support this ;-( 
 402         #for locale in self.descriptions.keys(): 
 405         #        '%description -l ' + locale, 
 406         #        self.descriptions[locale], 
 410         # figure out default build script 
 411         def_build 
= "%s setup.py build" % self
.python
 
 412         if self
.use_rpm_opt_flags
: 
 413             def_build 
= 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build
 
 415         # insert contents of files 
 417         # XXX this is kind of misleading: user-supplied options are files 
 418         # that we open and interpolate into the spec file, but the defaults 
 419         # are just text that we drop in as-is.  Hmmm. 
 422             ('prep', 'prep_script', "%setup"), 
 423             ('build', 'build_script', def_build
), 
 424             ('install', 'install_script', 
 425              ("%s setup.py install " 
 426               "--root=$RPM_BUILD_ROOT " 
 427               "--record=INSTALLED_FILES") % self
.python
), 
 428             ('clean', 'clean_script', "rm -rf $RPM_BUILD_ROOT"), 
 429             ('verifyscript', 'verify_script', None), 
 430             ('pre', 'pre_install', None), 
 431             ('post', 'post_install', None), 
 432             ('preun', 'pre_uninstall', None), 
 433             ('postun', 'post_uninstall', None), 
 436         for (rpm_opt
, attr
, default
) in script_options
: 
 437             # Insert contents of file referred to, if no file is referred to 
 438             # use 'default' as contents of script 
 439             val 
= getattr(self
, attr
) 
 445                     spec_file
.extend(string
.split(open(val
, 'r').read(), '\n')) 
 447                     spec_file
.append(default
) 
 453             '%files -f INSTALLED_FILES', 
 454             '%defattr(-,root,root)', 
 458             spec_file
.append('%doc ' + string
.join(self
.doc_files
)) 
 464             spec_file
.extend(self
.changelog
) 
 470     def _format_changelog(self
, changelog
): 
 471         """Format the changelog correctly and convert it to a list of strings 
 476         for line 
in string
.split(string
.strip(changelog
), '\n'): 
 477             line 
= string
.strip(line
) 
 479                 new_changelog
.extend(['', line
]) 
 481                 new_changelog
.append(line
) 
 483                 new_changelog
.append('  ' + line
) 
 485         # strip trailing newline inserted by first changelog entry 
 486         if not new_changelog
[0]: 
 491     # _format_changelog()