#!/usr/local/bin/python from _util import * import logging _log = logging.getLogger('product.py') def toFullLibName(n): global isDarwin, isWindows '''Platform-specific naming of dynamic libraries (.dylib or .so)''' if isWindows: return '%s.dll' % n if isDarwin: return 'lib%s.dylib' % n return 'lib%s.so' % n class ProductBase: '''Base of all products (also used for misc_products).''' stepAtts = ['_dir', '_name'] allTags = ['misc', 'exe', 'lib', 'jar', 'py'] def __init__(self, xmlTemplate, target): self.name = str(xmlTemplate.attributes['name'].value) self.target = target for c in StepEnum.names: for attSuffix in ProductBase.stepAtts: att = c + attSuffix self.__dict__[att] = str(xmlTemplate.attributes.get(att, dummyAtt).value) self.appears_when = StepEnum.toNumber(xmlTemplate.attributes.get('appears_when', DummyAtt('build')).value) self.last_used_when = StepEnum.toNumber(xmlTemplate.attributes.get('last_used_when', DummyAtt('install')).value) def getNameAtStep(self, step, checkShouldOccur = True): '''Product's name at at the step given by "step".''' if checkShouldOccur and not self.shouldOccur(step): return '' return self.__dict__[StepEnum.toString(step) + '_name'] or self.name def getRelativeDirAtStep(self, step, checkShouldOccur = True): '''Product's directory relative to it's target's directory at the step given by "step".''' if checkShouldOccur and not self.shouldOccur(step): return '' parAtt = StepEnum.toString(step) + '_' + self.tag + '_dir' p = expandMacro(self.target.__dict__.get(parAtt, '')) or self.getDefaultRelativeDir(step) return os.path.join(p, self.__dict__.get(StepEnum.toString(step) + '_dir', '')) def getDefaultRelativeDir(self, step): '''Default directory for this type of product (relative to it's target's directory) at the step given by "step".''' return '' def getNativeFileName(self, step, checkShouldOccur = True): '''product name as it will appear on the current platform.''' if checkShouldOccur and not self.shouldOccur(step): return '' return self.getNameAtStep(step, checkShouldOccur) def getNativeRelativePath(self, step, checkShouldOccur = True): if checkShouldOccur and not self.shouldOccur(step): return '' return os.path.join(self.getRelativeDirAtStep(step, checkShouldOccur), self.getNativeFileName(step, checkShouldOccur)) def getNativeAbsPath(self, step, checkShouldOccur = True): if checkShouldOccur and not self.shouldOccur(step): return '' return os.path.join(self.target.getAbsPath(step), self.getNativeRelativePath(step, checkShouldOccur)) def shouldOccur(self, step): '''Returns True if the product is expected at the step "step"''' return step >= self.appears_when and step <= self.last_used_when def isCompleted(self, step): '''Returns True if the product is not expected at the step "step" or the product exists.''' if not self.shouldOccur(step): return True full = self.getNativeAbsPath(step) _log.debug('step=%s checking for%s (which should exist between %s and %s steps)' % (StepEnum.toString(step), full, StepEnum.toString(self.appears_when), StepEnum.toString(self.last_used_when))) return os.path.exists(full) def __str__(self): atts = [] if self.appears_when != StepEnum.build: atts.append('appears_when="%s"' % StepEnum.toString(self.appears_when)) if self.last_used_when != StepEnum.install: atts.append('last_used_when="%s"' % StepEnum.toString(self.last_used_when)) for c in StepEnum.names: for attSuffix in ProductBase.stepAtts: a = c + attSuffix v = self.__dict__[a] if v: atts.append('%s="%s"' % (a, v)) return '<%s_product name="%s" %s/>' % (self.getTag(), self.name, ' '.join(atts)) def addEnvVar(self, environ, addedEnv, step): pass def getTag(self): return 'misc' def stage(self): '''Uses shutil.copy or copytree to clone the build product to the stage location''' if not self.shouldOccur(StepEnum.stage): return fullBuildPath = self.getNativeAbsPath(StepEnum.build, False) if not self.isCompleted(StepEnum.build): raise ValueError, 'The built product %s, was not found' % fullBuildPath fullDestination = self.getNativeAbsPath(StepEnum.stage) destDir, destName = os.path.split(fullDestination) if not os.path.exists(destDir): os.makedirs(destDir) _log.info('copying %s -> %s' %(fullBuildPath, fullDestination)) notReplaced = copyTreeIfNewer(fullBuildPath, fullDestination) if notReplaced: _log.warn('A newer version(s) of the following stage product(s) were found at the destination location: \n\t%s\nThese paths were not replaced' % '\n\t'.join(notReplaced)) tag = property(getTag) class JarProduct(ProductBase): def getDefaultRelativeDir(self, step): if step == StepEnum.build: return '' return 'lib' def addEnvVar(self, environ, addedEnv, step): '''Makes sure the path is in the CLASSPATH''' if self.shouldOccur(step): appendEnv(environ, addedEnv, True, CLASSPATH = self.getNativeAbsPath(step)) def getTag(self): return 'jar' tag = property(getTag) class ExeProduct(ProductBase): def getDefaultRelativeDir(self, step): if step == StepEnum.build: return '' return 'bin' def addEnvVar(self, environ, addedEnv, step): '''Makes sure the path is in the PATH''' if step > StepEnum.build and self.shouldOccur(step): toAdd = os.path.split(self.getNativeAbsPath(step))[0] appendEnv(environ, addedEnv, True, PATH = toAdd) def getTag(self): return 'exe' tag = property(getTag) class PyProduct(ProductBase): def getDefaultRelativeDir(self, step): if step == StepEnum.build: return '' return os.path.join('lib', 'python', 'site-packages') def getTag(self): return 'py' def addEnvVar(self, environ, addedEnv, step): '''Makes sure that the parent directory is in the PYTHONPATH''' if self.shouldOccur(step): fullParent = os.path.split(self.getNativeAbsPath(step))[0] appendEnv(environ, addedEnv, True, PYTHONPATH = fullParent) tag = property(getTag) class LibProduct(ProductBase): def getNativeFileName(self, step, checkShouldOccur): if checkShouldOccur and not self.shouldOccur(step): return '' return toFullLibName(ProductBase.getNativeFileName(self, step)) def getDefaultRelativeDir(self, step): if step == 'build': return '' return isWindows and 'bin' or 'lib' def addEnvVar(self, environ, addedEnv, step): global isDarwin, isWindows if isWindows: return '''Makes sure that the parent directory is in the LD_LIBRARY_PATH''' if self.shouldOccur(step): fullParent = os.path.split( self.getNativeAbsPath(step))[0] appendEnv(environ, addedEnv, True, LD_LIBRARY_PATH = fullParent) if isDarwin: appendEnv(environ, addedEnv, True, DYLD_LIBRARY_PATH = fullParent) def getTag(self): return 'lib' tag = property(getTag) def Product(xmlTemplate, target): if xmlTemplate.nodeName.startswith('jar'): return JarProduct(xmlTemplate, target) if xmlTemplate.nodeName.startswith('exe'): return ExeProduct(xmlTemplate, target) if xmlTemplate.nodeName.startswith('lib'): return LibProduct(xmlTemplate, target) if xmlTemplate.nodeName.startswith('py'): return PyProduct(xmlTemplate, target) return ProductBase(xmlTemplate, target)