rpm.py
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:13k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. """SCons.Tool.Packaging.rpm
  2. The rpm packager.
  3. """
  4. #
  5. # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining
  8. # a copy of this software and associated documentation files (the
  9. # "Software"), to deal in the Software without restriction, including
  10. # without limitation the rights to use, copy, modify, merge, publish,
  11. # distribute, sublicense, and/or sell copies of the Software, and to
  12. # permit persons to whom the Software is furnished to do so, subject to
  13. # the following conditions:
  14. #
  15. # The above copyright notice and this permission notice shall be included
  16. # in all copies or substantial portions of the Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  19. # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20. # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  22. # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  23. # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  24. # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. #
  26. __revision__ = "src/engine/SCons/Tool/packaging/rpm.py 3057 2008/06/09 22:21:00 knight"
  27. import os
  28. import string
  29. import SCons.Builder
  30. from SCons.Environment import OverrideEnvironment
  31. from SCons.Tool.packaging import stripinstallbuilder, src_targz
  32. from SCons.Errors import UserError
  33. def package(env, target, source, PACKAGEROOT, NAME, VERSION,
  34.             PACKAGEVERSION, DESCRIPTION, SUMMARY, X_RPM_GROUP, LICENSE,
  35.             **kw):
  36.     # initialize the rpm tool
  37.     SCons.Tool.Tool('rpm').generate(env)
  38.     bld = env['BUILDERS']['Rpm']
  39.     # Generate a UserError whenever the target name has been set explicitly,
  40.     # since rpm does not allow for controlling it. This is detected by
  41.     # checking if the target has been set to the default by the Package()
  42.     # Environment function.
  43.     if str(target[0])!="%s-%s"%(NAME, VERSION):
  44.         raise UserError( "Setting target is not supported for rpm." )
  45.     else:
  46.         # This should be overridable from the construction environment,
  47.         # which it is by using ARCHITECTURE=.
  48.         # Guessing based on what os.uname() returns at least allows it
  49.         # to work for both i386 and x86_64 Linux systems.
  50.         archmap = {
  51.             'i686'  : 'i386',
  52.             'i586'  : 'i386',
  53.             'i486'  : 'i386',
  54.         }
  55.         buildarchitecture = os.uname()[4]
  56.         buildarchitecture = archmap.get(buildarchitecture, buildarchitecture)
  57.         if kw.has_key('ARCHITECTURE'):
  58.             buildarchitecture = kw['ARCHITECTURE']
  59.         fmt = '%s-%s-%s.%s.rpm'
  60.         srcrpm = fmt % (NAME, VERSION, PACKAGEVERSION, 'src')
  61.         binrpm = fmt % (NAME, VERSION, PACKAGEVERSION, buildarchitecture)
  62.         target = [ srcrpm, binrpm ]
  63.     # get the correct arguments into the kw hash
  64.     loc=locals()
  65.     del loc['kw']
  66.     kw.update(loc)
  67.     del kw['source'], kw['target'], kw['env']
  68.     # if no "SOURCE_URL" tag is given add a default one.
  69.     if not kw.has_key('SOURCE_URL'):
  70.         #kw['SOURCE_URL']=(str(target[0])+".tar.gz").replace('.rpm', '')
  71.         kw['SOURCE_URL']=string.replace(str(target[0])+".tar.gz", '.rpm', '')
  72.     # mangle the source and target list for the rpmbuild
  73.     env = OverrideEnvironment(env, kw)
  74.     target, source = stripinstallbuilder(target, source, env)
  75.     target, source = addspecfile(target, source, env)
  76.     target, source = collectintargz(target, source, env)
  77.     # now call the rpm builder to actually build the packet.
  78.     return apply(bld, [env, target, source], kw)
  79. def collectintargz(target, source, env):
  80.     """ Puts all source files into a tar.gz file. """
  81.     # the rpm tool depends on a source package, until this is chagned
  82.     # this hack needs to be here that tries to pack all sources in.
  83.     sources = env.FindSourceFiles()
  84.     # filter out the target we are building the source list for.
  85.     #sources = [s for s in sources if not (s in target)]
  86.     sources = filter(lambda s, t=target: not (s in t), sources)
  87.     # find the .spec file for rpm and add it since it is not necessarily found
  88.     # by the FindSourceFiles function.
  89.     #sources.extend( [s for s in source if str(s).rfind('.spec')!=-1] )
  90.     spec_file = lambda s: string.rfind(str(s), '.spec') != -1
  91.     sources.extend( filter(spec_file, source) )
  92.     # as the source contains the url of the source package this rpm package
  93.     # is built from, we extract the target name
  94.     #tarball = (str(target[0])+".tar.gz").replace('.rpm', '')
  95.     tarball = string.replace(str(target[0])+".tar.gz", '.rpm', '')
  96.     try:
  97.         #tarball = env['SOURCE_URL'].split('/')[-1]
  98.         tarball = string.split(env['SOURCE_URL'], '/')[-1]
  99.     except KeyError, e:
  100.         raise SCons.Errors.UserError( "Missing PackageTag '%s' for RPM packager" % e.args[0] )
  101.     tarball = src_targz.package(env, source=sources, target=tarball,
  102.                                 PACKAGEROOT=env['PACKAGEROOT'], )
  103.     return (target, tarball)
  104. def addspecfile(target, source, env):
  105.     specfile = "%s-%s" % (env['NAME'], env['VERSION'])
  106.     bld = SCons.Builder.Builder(action         = build_specfile,
  107.                                 suffix         = '.spec',
  108.                                 target_factory = SCons.Node.FS.File)
  109.     source.extend(bld(env, specfile, source))
  110.     return (target,source)
  111. def build_specfile(target, source, env):
  112.     """ Builds a RPM specfile from a dictionary with string metadata and
  113.     by analyzing a tree of nodes.
  114.     """
  115.     file = open(target[0].abspath, 'w')
  116.     str  = ""
  117.     try:
  118.         file.write( build_specfile_header(env) )
  119.         file.write( build_specfile_sections(env) )
  120.         file.write( build_specfile_filesection(env, source) )
  121.         file.close()
  122.         # call a user specified function
  123.         if env.has_key('CHANGE_SPECFILE'):
  124.             env['CHANGE_SPECFILE'](target, source)
  125.     except KeyError, e:
  126.         raise SCons.Errors.UserError( '"%s" package field for RPM is missing.' % e.args[0] )
  127. #
  128. # mandatory and optional package tag section
  129. #
  130. def build_specfile_sections(spec):
  131.     """ Builds the sections of a rpm specfile.
  132.     """
  133.     str = ""
  134.     mandatory_sections = {
  135.         'DESCRIPTION'  : 'n%%descriptionn%snn', }
  136.     str = str + SimpleTagCompiler(mandatory_sections).compile( spec )
  137.     optional_sections = {
  138.         'DESCRIPTION_'        : '%%description -l %sn%snn',
  139.         'CHANGELOG'           : '%%changelogn%snn',
  140.         'X_RPM_PREINSTALL'    : '%%pren%snn',
  141.         'X_RPM_POSTINSTALL'   : '%%postn%snn',
  142.         'X_RPM_PREUNINSTALL'  : '%%preunn%snn',
  143.         'X_RPM_POSTUNINSTALL' : '%%postunn%snn',
  144.         'X_RPM_VERIFY'        : '%%verifyn%snn',
  145.         # These are for internal use but could possibly be overriden
  146.         'X_RPM_PREP'          : '%%prepn%snn',
  147.         'X_RPM_BUILD'         : '%%buildn%snn',
  148.         'X_RPM_INSTALL'       : '%%installn%snn',
  149.         'X_RPM_CLEAN'         : '%%cleann%snn',
  150.         }
  151.     # Default prep, build, install and clean rules
  152.     # TODO: optimize those build steps, to not compile the project a second time
  153.     if not spec.has_key('X_RPM_PREP'):
  154.         spec['X_RPM_PREP'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"' + 'n%setup -q'
  155.     if not spec.has_key('X_RPM_BUILD'):
  156.         spec['X_RPM_BUILD'] = 'mkdir "$RPM_BUILD_ROOT"'
  157.     if not spec.has_key('X_RPM_INSTALL'):
  158.         spec['X_RPM_INSTALL'] = 'scons --install-sandbox="$RPM_BUILD_ROOT" "$RPM_BUILD_ROOT"'
  159.     if not spec.has_key('X_RPM_CLEAN'):
  160.         spec['X_RPM_CLEAN'] = '[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT"'
  161.     str = str + SimpleTagCompiler(optional_sections, mandatory=0).compile( spec )
  162.     return str
  163. def build_specfile_header(spec):
  164.     """ Builds all section but the %file of a rpm specfile
  165.     """
  166.     str = ""
  167.     # first the mandatory sections
  168.     mandatory_header_fields = {
  169.         'NAME'           : '%%define name %snName: %%{name}n',
  170.         'VERSION'        : '%%define version %snVersion: %%{version}n',
  171.         'PACKAGEVERSION' : '%%define release %snRelease: %%{release}n',
  172.         'X_RPM_GROUP'    : 'Group: %sn',
  173.         'SUMMARY'        : 'Summary: %sn',
  174.         'LICENSE'        : 'License: %sn', }
  175.     str = str + SimpleTagCompiler(mandatory_header_fields).compile( spec )
  176.     # now the optional tags
  177.     optional_header_fields = {
  178.         'VENDOR'              : 'Vendor: %sn',
  179.         'X_RPM_URL'           : 'Url: %sn',
  180.         'SOURCE_URL'          : 'Source: %sn',
  181.         'SUMMARY_'            : 'Summary(%s): %sn',
  182.         'X_RPM_DISTRIBUTION'  : 'Distribution: %sn',
  183.         'X_RPM_ICON'          : 'Icon: %sn',
  184.         'X_RPM_PACKAGER'      : 'Packager: %sn',
  185.         'X_RPM_GROUP_'        : 'Group(%s): %sn',
  186.         'X_RPM_REQUIRES'      : 'Requires: %sn',
  187.         'X_RPM_PROVIDES'      : 'Provides: %sn',
  188.         'X_RPM_CONFLICTS'     : 'Conflicts: %sn',
  189.         'X_RPM_BUILDREQUIRES' : 'BuildRequires: %sn',
  190.         'X_RPM_SERIAL'        : 'Serial: %sn',
  191.         'X_RPM_EPOCH'         : 'Epoch: %sn',
  192.         'X_RPM_AUTOREQPROV'   : 'AutoReqProv: %sn',
  193.         'X_RPM_EXCLUDEARCH'   : 'ExcludeArch: %sn',
  194.         'X_RPM_EXCLUSIVEARCH' : 'ExclusiveArch: %sn',
  195.         'X_RPM_PREFIX'        : 'Prefix: %sn',
  196.         'X_RPM_CONFLICTS'     : 'Conflicts: %sn',
  197.         # internal use
  198.         'X_RPM_BUILDROOT'     : 'BuildRoot: %sn', }
  199.     # fill in default values:
  200.     # Adding a BuildRequires renders the .rpm unbuildable under System, which
  201.     # are not managed by rpm, since the database to resolve this dependency is
  202.     # missing (take Gentoo as an example)
  203. #    if not s.has_key('x_rpm_BuildRequires'):
  204. #        s['x_rpm_BuildRequires'] = 'scons'
  205.     if not spec.has_key('X_RPM_BUILDROOT'):
  206.         spec['X_RPM_BUILDROOT'] = '%{_tmppath}/%{name}-%{version}-%{release}'
  207.     str = str + SimpleTagCompiler(optional_header_fields, mandatory=0).compile( spec )
  208.     return str
  209. #
  210. # mandatory and optional file tags
  211. #
  212. def build_specfile_filesection(spec, files):
  213.     """ builds the %file section of the specfile
  214.     """
  215.     str  = '%filesn'
  216.     if not spec.has_key('X_RPM_DEFATTR'):
  217.         spec['X_RPM_DEFATTR'] = '(-,root,root)'
  218.     str = str + '%%defattr %sn' % spec['X_RPM_DEFATTR']
  219.     supported_tags = {
  220.         'PACKAGING_CONFIG'           : '%%config %s',
  221.         'PACKAGING_CONFIG_NOREPLACE' : '%%config(noreplace) %s',
  222.         'PACKAGING_DOC'              : '%%doc %s',
  223.         'PACKAGING_UNIX_ATTR'        : '%%attr %s',
  224.         'PACKAGING_LANG_'            : '%%lang(%s) %s',
  225.         'PACKAGING_X_RPM_VERIFY'     : '%%verify %s',
  226.         'PACKAGING_X_RPM_DIR'        : '%%dir %s',
  227.         'PACKAGING_X_RPM_DOCDIR'     : '%%docdir %s',
  228.         'PACKAGING_X_RPM_GHOST'      : '%%ghost %s', }
  229.     for file in files:
  230.         # build the tagset
  231.         tags = {}
  232.         for k in supported_tags.keys():
  233.             try:
  234.                 tags[k]=getattr(file, k)
  235.             except AttributeError:
  236.                 pass
  237.         # compile the tagset
  238.         str = str + SimpleTagCompiler(supported_tags, mandatory=0).compile( tags )
  239.         str = str + ' '
  240.         str = str + file.PACKAGING_INSTALL_LOCATION
  241.         str = str + 'nn'
  242.     return str
  243. class SimpleTagCompiler:
  244.     """ This class is a simple string substition utility:
  245.     the replacement specfication is stored in the tagset dictionary, something
  246.     like:
  247.      { "abc"  : "cdef %s ",
  248.        "abc_" : "cdef %s %s" }
  249.     the compile function gets a value dictionary, which may look like:
  250.     { "abc"    : "ghij",
  251.       "abc_gh" : "ij" }
  252.     The resulting string will be:
  253.      "cdef ghij cdef gh ij"
  254.     """
  255.     def __init__(self, tagset, mandatory=1):
  256.         self.tagset    = tagset
  257.         self.mandatory = mandatory
  258.     def compile(self, values):
  259.         """ compiles the tagset and returns a str containing the result
  260.         """
  261.         def is_international(tag):
  262.             #return tag.endswith('_')
  263.             return tag[-1:] == '_'
  264.         def get_country_code(tag):
  265.             return tag[-2:]
  266.         def strip_country_code(tag):
  267.             return tag[:-2]
  268.         replacements = self.tagset.items()
  269.         str = ""
  270.         #domestic = [ (k,v) for k,v in replacements if not is_international(k) ]
  271.         domestic = filter(lambda t, i=is_international: not i(t[0]), replacements)
  272.         for key, replacement in domestic:
  273.             try:
  274.                 str = str + replacement % values[key]
  275.             except KeyError, e:
  276.                 if self.mandatory:
  277.                     raise e
  278.         #international = [ (k,v) for k,v in replacements if is_international(k) ]
  279.         international = filter(lambda t, i=is_international: i(t[0]), replacements)
  280.         for key, replacement in international:
  281.             try:
  282.                 #int_values_for_key = [ (get_country_code(k),v) for k,v in values.items() if strip_country_code(k) == key ]
  283.                 x = filter(lambda t,key=key,s=strip_country_code: s(t[0]) == key, values.items())
  284.                 int_values_for_key = map(lambda t,g=get_country_code: (g(t[0]),t[1]), x)
  285.                 for v in int_values_for_key:
  286.                     str = str + replacement % v
  287.             except KeyError, e:
  288.                 if self.mandatory:
  289.                     raise e
  290.         return str