diff options
Diffstat (limited to 'engine/SCons/Tool/packaging/__init__.py')
-rw-r--r-- | engine/SCons/Tool/packaging/__init__.py | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/engine/SCons/Tool/packaging/__init__.py b/engine/SCons/Tool/packaging/__init__.py new file mode 100644 index 0000000..7d191dd --- /dev/null +++ b/engine/SCons/Tool/packaging/__init__.py @@ -0,0 +1,314 @@ +"""SCons.Tool.Packaging + +SCons Packaging Tool. +""" + +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 The SCons Foundation +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "src/engine/SCons/Tool/packaging/__init__.py 4577 2009/12/27 19:43:56 scons" + +import SCons.Environment +from SCons.Variables import * +from SCons.Errors import * +from SCons.Util import is_List, make_path_relative +from SCons.Warnings import warn, Warning + +import os, imp +import SCons.Defaults + +__all__ = [ 'src_targz', 'src_tarbz2', 'src_zip', 'tarbz2', 'targz', 'zip', 'rpm', 'msi', 'ipk' ] + +# +# Utility and Builder function +# +def Tag(env, target, source, *more_tags, **kw_tags): + """ Tag a file with the given arguments, just sets the accordingly named + attribute on the file object. + + TODO: FIXME + """ + if not target: + target=source + first_tag=None + else: + first_tag=source + + if first_tag: + kw_tags[first_tag[0]] = '' + + if len(kw_tags) == 0 and len(more_tags) == 0: + raise UserError, "No tags given." + + # XXX: sanity checks + for x in more_tags: + kw_tags[x] = '' + + if not SCons.Util.is_List(target): + target=[target] + else: + # hmm, sometimes the target list, is a list of a list + # make sure it is flattened prior to processing. + # TODO: perhaps some bug ?!? + target=env.Flatten(target) + + for t in target: + for (k,v) in kw_tags.items(): + # all file tags have to start with PACKAGING_, so we can later + # differentiate between "normal" object attributes and the + # packaging attributes. As the user should not be bothered with + # that, the prefix will be added here if missing. + #if not k.startswith('PACKAGING_'): + if k[:10] != 'PACKAGING_': + k='PACKAGING_'+k + setattr(t, k, v) + +def Package(env, target=None, source=None, **kw): + """ Entry point for the package tool. + """ + # check if we need to find the source files ourself + if not source: + source = env.FindInstalledFiles() + + if len(source)==0: + raise UserError, "No source for Package() given" + + # decide which types of packages shall be built. Can be defined through + # four mechanisms: command line argument, keyword argument, + # environment argument and default selection( zip or tar.gz ) in that + # order. + try: kw['PACKAGETYPE']=env['PACKAGETYPE'] + except KeyError: pass + + if not kw.get('PACKAGETYPE'): + from SCons.Script import GetOption + kw['PACKAGETYPE'] = GetOption('package_type') + + if kw['PACKAGETYPE'] == None: + if env['BUILDERS'].has_key('Tar'): + kw['PACKAGETYPE']='targz' + elif env['BUILDERS'].has_key('Zip'): + kw['PACKAGETYPE']='zip' + else: + raise UserError, "No type for Package() given" + + PACKAGETYPE=kw['PACKAGETYPE'] + if not is_List(PACKAGETYPE): + PACKAGETYPE=string.split(PACKAGETYPE, ',') + + # load the needed packagers. + def load_packager(type): + try: + file,path,desc=imp.find_module(type, __path__) + return imp.load_module(type, file, path, desc) + except ImportError, e: + raise EnvironmentError("packager %s not available: %s"%(type,str(e))) + + packagers=map(load_packager, PACKAGETYPE) + + # set up targets and the PACKAGEROOT + try: + # fill up the target list with a default target name until the PACKAGETYPE + # list is of the same size as the target list. + if not target: target = [] + + size_diff = len(PACKAGETYPE)-len(target) + default_name = "%(NAME)s-%(VERSION)s" + + if size_diff>0: + default_target = default_name%kw + target.extend( [default_target]*size_diff ) + + if not kw.has_key('PACKAGEROOT'): + kw['PACKAGEROOT'] = default_name%kw + + except KeyError, e: + raise SCons.Errors.UserError( "Missing Packagetag '%s'"%e.args[0] ) + + # setup the source files + source=env.arg2nodes(source, env.fs.Entry) + + # call the packager to setup the dependencies. + targets=[] + try: + for packager in packagers: + t=[target.pop(0)] + t=apply(packager.package, [env,t,source], kw) + targets.extend(t) + + assert( len(target) == 0 ) + + except KeyError, e: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (e.args[0],packager.__name__) ) + except TypeError, e: + # this exception means that a needed argument for the packager is + # missing. As our packagers get their "tags" as named function + # arguments we need to find out which one is missing. + from inspect import getargspec + args,varargs,varkw,defaults=getargspec(packager.package) + if defaults!=None: + args=args[:-len(defaults)] # throw away arguments with default values + args.remove('env') + args.remove('target') + args.remove('source') + # now remove any args for which we have a value in kw. + #args=[x for x in args if not kw.has_key(x)] + args=filter(lambda x, kw=kw: not kw.has_key(x), args) + + if len(args)==0: + raise # must be a different error, so reraise + elif len(args)==1: + raise SCons.Errors.UserError( "Missing Packagetag '%s' for %s packager"\ + % (args[0],packager.__name__) ) + else: + raise SCons.Errors.UserError( "Missing Packagetags '%s' for %s packager"\ + % (", ".join(args),packager.__name__) ) + + target=env.arg2nodes(target, env.fs.Entry) + targets.extend(env.Alias( 'package', targets )) + return targets + +# +# SCons tool initialization functions +# + +added = None + +def generate(env): + from SCons.Script import AddOption + global added + if not added: + added = 1 + AddOption('--package-type', + dest='package_type', + default=None, + type="string", + action="store", + help='The type of package to create.') + + try: + env['BUILDERS']['Package'] + env['BUILDERS']['Tag'] + except KeyError: + env['BUILDERS']['Package'] = Package + env['BUILDERS']['Tag'] = Tag + +def exists(env): + return 1 + +# XXX +def options(opts): + opts.AddVariables( + EnumVariable( 'PACKAGETYPE', + 'the type of package to create.', + None, allowed_values=map( str, __all__ ), + ignorecase=2 + ) + ) + +# +# Internal utility functions +# + +def copy_attr(f1, f2): + """ copies the special packaging file attributes from f1 to f2. + """ + #pattrs = [x for x in dir(f1) if not hasattr(f2, x) and\ + # x.startswith('PACKAGING_')] + copyit = lambda x, f2=f2: not hasattr(f2, x) and x[:10] == 'PACKAGING_' + pattrs = filter(copyit, dir(f1)) + for attr in pattrs: + setattr(f2, attr, getattr(f1, attr)) +def putintopackageroot(target, source, env, pkgroot, honor_install_location=1): + """ Uses the CopyAs builder to copy all source files to the directory given + in pkgroot. + + If honor_install_location is set and the copied source file has an + PACKAGING_INSTALL_LOCATION attribute, the PACKAGING_INSTALL_LOCATION is + used as the new name of the source file under pkgroot. + + The source file will not be copied if it is already under the the pkgroot + directory. + + All attributes of the source file will be copied to the new file. + """ + # make sure the packageroot is a Dir object. + if SCons.Util.is_String(pkgroot): pkgroot=env.Dir(pkgroot) + if not SCons.Util.is_List(source): source=[source] + + new_source = [] + for file in source: + if SCons.Util.is_String(file): file = env.File(file) + + if file.is_under(pkgroot): + new_source.append(file) + else: + if hasattr(file, 'PACKAGING_INSTALL_LOCATION') and\ + honor_install_location: + new_name=make_path_relative(file.PACKAGING_INSTALL_LOCATION) + else: + new_name=make_path_relative(file.get_path()) + + new_file=pkgroot.File(new_name) + new_file=env.CopyAs(new_file, file)[0] + copy_attr(file, new_file) + new_source.append(new_file) + + return (target, new_source) + +def stripinstallbuilder(target, source, env): + """ strips the install builder action from the source list and stores + the final installation location as the "PACKAGING_INSTALL_LOCATION" of + the source of the source file. This effectively removes the final installed + files from the source list while remembering the installation location. + + It also warns about files which have no install builder attached. + """ + def has_no_install_location(file): + return not (file.has_builder() and\ + hasattr(file.builder, 'name') and\ + (file.builder.name=="InstallBuilder" or\ + file.builder.name=="InstallAsBuilder")) + + if len(filter(has_no_install_location, source)): + warn(Warning, "there are files to package which have no\ + InstallBuilder attached, this might lead to irreproducible packages") + + n_source=[] + for s in source: + if has_no_install_location(s): + n_source.append(s) + else: + for ss in s.sources: + n_source.append(ss) + copy_attr(s, ss) + setattr(ss, 'PACKAGING_INSTALL_LOCATION', s.get_path()) + + return (target, n_source) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: |