Package conary :: Package build :: Module loadrecipe
[hide private]
[frames] | no frames]

Source Code for Module conary.build.loadrecipe

   1  # 
   2  # Copyright (c) 2004-2008 rPath, Inc. 
   3  # 
   4  # This program is distributed under the terms of the Common Public License, 
   5  # version 1.0. A copy of this license should have been distributed with this 
   6  # source file in a file called LICENSE. If it is not present, the license 
   7  # is always available at http://www.rpath.com/permanent/licenses/CPL-1.0. 
   8  # 
   9  # This program is distributed in the hope that it will be useful, but 
  10  # without any warranty; without even the implied warranty of merchantability 
  11  # or fitness for a particular purpose. See the Common Public License for 
  12  # full details. 
  13  # 
  14   
  15  import copy 
  16  import imp 
  17  import inspect 
  18  import itertools 
  19  import new 
  20  import os 
  21  import string 
  22  import sys 
  23  import types 
  24  import tempfile 
  25  import traceback 
  26   
  27  from conary.repository import errors, trovesource 
  28  from conary.build import recipe, use 
  29  from conary.build import errors as builderrors 
  30  from conary.build.errors import RecipeFileError 
  31  from conary.build.factory import Factory as FactoryRecipe 
  32  from conary.conaryclient import cmdline 
  33  from conary.deps import deps 
  34  from conary.lib import graph, log, util 
  35  from conary.local import database 
  36  from conary import versions 
  37   
38 -class SubloadData(object):
39 40 # Collector for all of the data loadSuperClass and loadInstalled 41 # need; this keeps this gunk out of the Importer class directly 42
43 - def __init__(self, cfg, repos, db, buildFlavor, directory, 44 branch, name, ignoreInstalled, overrides):
45 self.cfg = cfg 46 self.repos = repos 47 self.db = db 48 self.buildFlavor = buildFlavor 49 self.parentDir = directory 50 self.branch = branch 51 self.parentPackageName = name 52 self.ignoreInstalled = ignoreInstalled 53 54 if overrides is None: 55 self.overrides = {} 56 else: 57 self.overrides = overrides
58
59 -class Importer(object):
60 61 baseModuleImports = [ 62 ('conary.build', ('build', 'action')), 63 ('conary.build.grouprecipe', 'GroupRecipe'), 64 ('conary.build.filesetrecipe', 'FilesetRecipe'), 65 ('conary.build.redirectrecipe', 'RedirectRecipe'), 66 ('conary.build.derivedrecipe', 'DerivedPackageRecipe'), 67 ('conary.build.packagerecipe', 68 ('clearBuildReqs', 'clearBuildRequires', 69 'clearCrossReqs', 'clearCrossRequires', 70 'PackageRecipe', 'BuildPackageRecipe', 71 'CPackageRecipe', 'AutoPackageRecipe')), 72 ('conary.build.inforecipe', ('UserInfoRecipe', 'GroupInfoRecipe', 73 'UserGroupInfoRecipe' )), 74 ('conary.lib', ('util',)), 75 ('os',), 76 ('re',), 77 ('sys',), 78 ('stat',), 79 ('conary.build.use', ('Arch', 'Use', ('LocalFlags', 'Flags'), 80 'PackageFlags')) ]
81 - def __init__(self, objDict = {}, fileName = 'unknownfile.py', 82 baseName = 'unknown', factory = False, 83 subloadData = None):
84 self.fileName = fileName 85 self.baseName = os.path.basename(self.fileName) 86 # can't have a '.' in a module name or import code gets confused 87 self.module = imp.new_module(self.baseName.replace('.', '-')) 88 self.subloadData = subloadData 89 self.loadedTroves = [] 90 self.loadedSpecs = {} 91 92 for args in self.baseModuleImports: 93 self._localImport(*args) 94 95 if factory: 96 self._localImport('conary.build.factory', 97 ('Factory', 'FactoryException' )) 98 99 self._copyReusedRecipes() 100 101 if objDict: 102 self.module.__dict__.update(objDict.copy()) 103 104 self.module.loadInstalled = self.loadInstalled 105 self.module.loadSuperClass = self.loadSuperClass 106 # XXX when all recipes have been migrated 107 # we can get rid of loadRecipe 108 self.module.loadRecipe = self.loadSuperClass
109
110 - def updateModuleDict(self, d):
111 self.module.__dict__.update(d)
112
113 - def _copyReusedRecipes(self):
114 # XXX HACK - get rid of this when we move the 115 # recipe classes to the repository. 116 # makes copies of some of the superclass recipes that are 117 # created in this module. (specifically, the ones with buildreqs) 118 recipeClassDict = {} 119 for recipeClass in self.module.__dict__.values(): 120 if (type(recipeClass) != type or 121 not issubclass(recipeClass, recipe.Recipe)): 122 continue 123 numParents = len(inspect.getmro(recipeClass)) 124 recipeClassDict[recipeClass.__name__] = (numParents, recipeClass) 125 # create copies of recipes by the number of parents they have 126 # a class always has more parents than its parent does, 127 # if you copy the superClasses first, the copies will. 128 recipeClasses = [ x[1] for x in sorted(recipeClassDict.values(), 129 key=lambda x: x[0]) ] 130 for recipeClass in recipeClasses: 131 className = recipeClass.__name__ 132 # when we create a new class object, it needs its superclasses. 133 # get the original superclass list and substitute in any 134 # copies 135 mro = list(inspect.getmro(recipeClass)[1:]) 136 newMro = [] 137 for superClass in mro: 138 superName = superClass.__name__ 139 newMro.append(self.module.__dict__.get(superName, superClass)) 140 141 newDict = {} 142 for name, attr in recipeClass.__dict__.iteritems(): 143 if type(attr) in [ types.ModuleType, types.MethodType, 144 types.UnboundMethodType, 145 types.FunctionType, 146 staticmethod, 147 # don't copy in flags, as they 148 # need to have their data copied out 149 use.LocalFlagCollection]: 150 newDict[name] = attr 151 else: 152 newDict[name] = copy.deepcopy(attr) 153 154 self.module.__dict__[className] = \ 155 new.classobj(className, tuple(newMro), newDict)
156
157 - def _localImport(self, package, modules=()):
158 """ 159 import a package into a non-global context. 160 161 @param d: the context to import the module 162 @type d: dict 163 @param package: the name of the module to import 164 @type package: str 165 @param modules: a sequence of modules to import from the package. 166 If a 2-tuple is in the sequence, rename the imported module to 167 the second value in the tuple. 168 @type modules: sequence of strings or tuples, or empty tuple 169 170 Examples of translated import statements:: 171 from foo import bar as baz: 172 _localImport(d, "foo", (("bar", "baz")) 173 from bar import fred, george: 174 _localImport(d, "bar", ("fred", "george")) 175 import os 176 _localImport(d, "os") 177 """ 178 m = __import__(package, {}, {}, modules) 179 if modules: 180 if isinstance(modules, str): 181 modules = (modules,) 182 for name in modules: 183 if type(name) is tuple: 184 mod = name[0] 185 name = name[1] 186 else: 187 mod = name 188 self.module.__dict__[name] = getattr(m, mod) 189 else: 190 self.module.__dict__[package] = m 191 # save a reference to the module into this context, so it won't 192 # be garbage collected until the context is deleted. 193 l = self.module.__dict__.setdefault('__localImportModules', []) 194 l.append(m)
195
196 - def _loadRecipe(self, troveSpec, label, findInstalled):
197 """ See docs for loadInstalledPackage and loadSuperClass. """ 198 loader = ChainedRecipeLoader(troveSpec, label, findInstalled, 199 self.subloadData.cfg, 200 self.subloadData.repos, 201 self.subloadData.branch, 202 self.subloadData.parentPackageName, 203 self.subloadData.parentDir, 204 self.subloadData.buildFlavor, 205 self.subloadData.ignoreInstalled, 206 self.subloadData.overrides, 207 self.subloadData.db) 208 209 for name, recipe in loader.allRecipes().items(): 210 # hide all recipes from RecipeLoader - we don't want to return 211 # a recipe that has been loaded by loadRecipe, so we treat them 212 # for these purposes as if they are abstract base classes 213 recipe.internalAbstractBaseClass = 1 214 215 self.module.__dict__[name] = recipe 216 if recipe._trove: 217 # create a tuple with the version and flavor information needed to 218 # load this trove again. You might be able to rely on the 219 # flavor that the trove was built with, but when you load a 220 # recipe that is not a superclass of the current recipe, 221 # its flavor is not assumed to be relevant to the resulting 222 # package (otherwise you might have completely irrelevant flavors 223 # showing up for any package that loads the python recipe, e.g.) 224 troveTuple = (recipe._trove.getName(), recipe._trove.getVersion(), 225 recipe._usedFlavor) 226 log.info('Loaded %s from %s=%s[%s]' % ((name,) + troveTuple)) 227 self.loadedTroves.extend(loader.getLoadedTroves()) 228 self.loadedTroves.append(troveTuple) 229 self.loadedSpecs[troveSpec] = (troveTuple, 230 loader.getLoadedSpecs()) 231 232 # stash a reference to the module in the namespace 233 # of the recipe that loaded it, or else it will be destroyed 234 self.module.__dict__[loader.recipe.__module__] = loader
235
236 - def loadSuperClass(self, troveSpec, label=None):