~plane1/maus/devel_624

« back to all changes in this revision

Viewing changes to third_party/scons-2.0.1/lib/scons-2.0.1/SCons/Tool/packaging/rpm.py

  • Committer: tunnell
  • Date: 2010-09-30 13:56:05 UTC
  • Revision ID: tunnell@itchy-20100930135605-wxbkfgy75p0sndk3
add third party

Show diffs side-by-side

added added

removed removed

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