def setGlobalOption(self, key, value): """ Set a global value for an option Called internally from L{propertysupport.setGlobalOption} and does not need to be called directly """ if not key in _definedOptions: raise BuildException("Cannot specify value for option that has not been defined \"%s\"" % key) if key in self._globalOptions: log.warn("Resetting global option %s to %s at %s", key, value, BuildFileLocation().getLineString()) else: log.info("Setting global option %s to %s at %s", key, value, BuildFileLocation().getLineString()) self._globalOptions[key] = value
def definePropertiesFromFile(propertiesFile, prefix=None, excludeLines=None, conditions=None): """ Defines a set of properties from a .properties file @param propertiesFile: The file to include properties from (can include ${...} variables) @param prefix: if specified, this prefix will be added to the start of all property names from this file @param excludeLines: a string of list of strings to search for, any KEY containing these strings will be ignored @param conditions: an optional list of string conditions that can appear in property keys e.g. "FOO<condition>=bar" where lines with no condition in this list are ignored. Conditions are typically lowercase. """ if conditions: assert not isinstance( conditions, basestring), 'conditions parameter must be a list' __log.info('Defining properties from file: %s', propertiesFile) context = getBuildInitializationContext() propertiesFile = context.getFullPath( propertiesFile, BuildFileLocation(raiseOnError=True).buildDir) try: f = open(propertiesFile, 'r') except Exception, e: raise BuildException('Failed to open properties file "%s"' % (propertiesFile), causedBy=True)
def __init__(self, dir, excludes=None, includes=None): """ @param dir: base directory to search (relative or absolute, may contain ${...} variables). May be a simple string, or a DirGeneratedByTarget to glob under a directory generated as part of the build. @param includes: a list of glob patterns for the files to include (excluding all others) @param excludes: a list of glob patterns to exclude after processing any includes. """ self.__dir = dir self.includes = flatten(includes) self.excludes = flatten(excludes) bad = [ x for x in (self.includes + self.excludes) if ('//' in x or x.startswith('/') or x.startswith('/') or '\\' in x or '${' in x) ] if bad: raise BuildException( 'Invalid includes/excludes pattern in FindPaths - must not contain \\, begin or end with /, or contain substitution variables: "%s"' % bad[0]) if isinstance( dir, basestring ) and '\\' in dir: # avoid silly mistakes, and enforce consistency raise BuildException( 'Invalid base directory for FindPaths - must not contain \\ (always use forward slashes)' ) self.location = BuildFileLocation() self.__lock = threading.Lock() self.__cached = None
def __init__(self, name, dependencies): """ Normal constructor, should only be called from sub-classes since this is a stub. @param name: a unique name for this target (may contain unexpanded ${...} variables). Should correspond to the file or directory which is created as a result of running this target. @param dependencies: a list of dependencies, which may need to be flattened/expanded by the build system; may be any combination of strings, PathSets and lists and may also contain unexpanded variables. """ self._optionsTargetOverridesUnresolved = { } # for target-specific option overrides. for internal use (by buildcontext), do not use self.__optionsResolved = None # gets assigned during end of initialization phase if isinstance(name, basestring): if '//' in name: raise BuildException( 'Invalid target name: double slashes are not permitted: %s' % name) if '\\' in name: raise BuildException( 'Invalid target name: backslashes are not permitted: %s' % name) self.__name = str(name) self.__path_src = name self.__tags = ['all'] self.__priority = 0.0 # default so we can go bigger or smaller self.log = logging.getLogger(self.__class__.__name__) init = getBuildInitializationContext() if not init: # doc-test mode self.location = BuildFileLocation(raiseOnError=False) else: self.location = BuildFileLocation(raiseOnError=True) init.registerTarget(self) # should ensure changes to the build file cause a rebuild? probs no need # PathSet will perform all necessary flattening etc self.__dependencies = PathSet(dependencies) self.__path = None # set by _resolveTargetPath self.__workDir = None
def __init__(self, message, location=None, causedBy=False): """ BuildExceptions thrown during loading of the build config files will include the build file location (from their call stack) in the message. BuildExceptions thrown during operations on a target (dep resolution, execution, cleaning) will have information about that target added by xpybuild when it is logged, so there is usually no reason to explicitly add the target name into the message. To avoid losing essential diagnostic information, do not catch arbitrary non-BuildException classes and wrap in a BuildException. The location can optionally be specified explicitly (e.g. for pathsets with delayed evaluation). @param message: the error cause (does not need to include the target name) @param location: usually None, or else a BuildFileLocation object for the source line that caused the problem. This is useful if the build file location associated with the exception is something other than a target, e.g. a PathSet. @param causedBy: if True, takes the exception currently on the stack as the caused of this exception, and adds it to the build exception message. If the cause is not a BuildException, then its stack trace will be captured if this is True. """ assert message self.__msg = message.strip() if causedBy: causedBy = sys.exc_info() causedByExc = causedBy[1] if isinstance(causedByExc, BuildException): causedByMsg = causedByExc.__msg if not location: location = causedByExc.__location self.__causedByTraceback = None # tracebacks not needed for BuildException, by definition else: causedByMsg = '%s'%causedByExc self.__causedByTraceback = traceback.format_exc(causedBy) if (causedByMsg not in self.__msg): self.__msg += (': %s'%causedByMsg) else: assert causedBy==False self.__causedByTraceback = None # keep things simple by using None instead of an empty BuildFileLocation object if (not location or not location.buildFile) and BuildFileLocation._currentBuildFile: # only do this if we're parsing build files at the moment, otherwise it's # more reliable to keep it blank and let the scheduler use the target's location location = BuildFileLocation(raiseOnError=False) if not location.buildFile: location = None self.__location = location Exception.__init__(self, self.__msg)
def __init__(self, dirTargetName): """ @param dirTargetName: The directory that another target will generate. """ BasePathSet.__init__(self) assert isinstance(dirTargetName, basestring) assert dirTargetName.endswith('/') self.__target = dirTargetName self.__location = BuildFileLocation() if '\\' in dirTargetName: # avoid silly mistakes, and enforce consistency raise BuildException( 'Invalid directory target - must not contain \\ (always use forward slashes)' )
def _coerceToValidValue(value): value = getBuildInitializationContext().expandPropertyValues(value) if not os.path.isabs(value): # must absolutize this, as otherwise it might be used from a build # file in a different location, resulting in the same property # resolving to different effective values in different places value = BuildFileLocation(raiseOnError=True).buildDir + '/' + value value = normpath(value).rstrip('/\\') if mustExist and not os.path.exists(value): raise BuildException( 'Invalid path property value for "%s" - path "%s" does not exist' % (name, value)) return value
def __init__(self, dir, *children): """ @param dir: the base directory, which may include substitution variables. When fully expanded, it is essential that dir ends with a '/'. May be a string or a DirGeneratedByTarget. @param children: strings defining the child files or dirs, which may include ${...} variables but not '*' expansions. Can be specified nested inside tuples or lists if desired. If any of the child strings contains a ${...[]} variable, it will be expanded early and split around the ',' character. """ self.__dir = dir self.__children = flatten(children) self.__location = BuildFileLocation()
def __init__(self, targetTag, allowDirectories=False, walkDirectories=False): """ @param targetTag: the tag name @param allowDirectories: set this to True to allow directories to be specified (by default this is False to avoid errors where a directory is used in a Copy without FindPaths, and therefore ends up empty) @param walkDirectories: implies allowDirectories. Recursively enumerate the contents of the directory at build time. """ self.__targetTag = targetTag self.__location = BuildFileLocation() self.__allowDirectories = allowDirectories or walkDirectories self.__walkDirectories = walkDirectories
def __init__(self, *inputs): """ Construct a PathSet from the specified strings and other pathsets. @param inputs: contains strings, targets and PathSet objects, nested as deeply as you like within lists and tuples. The strings must be absolute paths, or paths relative to the build file where this PathSet is defined, in which case the PathSet must be instantiated during the build file parsing phase (relative paths cannot be used in a PathSet that is instantiated while building or resolving dependencies for a target). Paths may not contain the '*' character, and directory paths must end with an explicit '/'. >>> str(PathSet('a', [('b/', PathSet('1/2/3/', '4/5/6/'), ['d/e'])], 'e/f/${x}').resolveWithDestinations(BaseContext({'x':'X/'}))).replace('\\\\\\\\','/') "[('BUILD_DIR/a', 'a'), ('BUILD_DIR/b/', 'b/'), ('BUILD_DIR/1/2/3/', '3/'), ('BUILD_DIR/4/5/6/', '6/'), ('BUILD_DIR/d/e', 'e'), ('BUILD_DIR/e/f/X/', 'X/')]" >>> str(PathSet('a', [('b/', PathSet('1/2/3/', '4/5/6/'), ['d/e'])], 'e/f/${x}').resolve(BaseContext({'x':'X/'}))).replace('\\\\\\\\','/') "['BUILD_DIR/a', 'BUILD_DIR/b/', 'BUILD_DIR/1/2/3/', 'BUILD_DIR/4/5/6/', 'BUILD_DIR/d/e', 'BUILD_DIR/e/f/X/']" >>> str(PathSet('a', [('b/', PathSet('1/2/3/', '4/5/6/'), ['d/e'])], 'e/f/${x}')) 'PathSet("a", "b/", PathSet("1/2/3/", "4/5/6/"), "d/e", "e/f/${x}")' >>> str(PathSet('a', [[PathSet('1/2/3/', DirGeneratedByTarget('4/5/6/'), '7/8/')]], DirGeneratedByTarget('9/'))._resolveUnderlyingDependencies(BaseContext({}))).replace('\\\\\\\\','/') "['BUILD_DIR/a', 'BUILD_DIR/1/2/3/', 'BUILD_DIR/4/5/6/', 'BUILD_DIR/7/8/', 'BUILD_DIR/9/']" >>> PathSet('a/*').resolve(BaseContext({})) #doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... BuildException: """ super(BasePathSet, self).__init__() self.contents = flatten(inputs) self.__location = None for x in self.contents: if not (isinstance(x, basestring) or isinstance(x, BasePathSet) or hasattr(x, 'resolveToString')): raise BuildException( 'PathSet may contain only strings, PathSets, Composables, targets and lists - cannot accept %s (%s)' % (x, x.__class__)) self.__location = BuildFileLocation()
def __init__(self, archivePath, includes=None, excludes=None, destMapper=None): """ @param archivePath: The archive to unpack; either a string or a singleton PathSet @param destMapper: A functor that takes a (context, destPath) where destPath is an archive-relative path (guaranteed to contain / not \\), and returns the desired destination relative path string. The functor should have a deterministic and user-friendly __str__ implementation. @param includes: a list of include patterns (if provided excludes all non-matching files) @param excludes: a list of exclude patterns (processed after includes) """ self.__path = PathSet(archivePath) self.__destMapper = destMapper self.__includes = flatten(includes) self.__excludes = flatten(excludes) self.__location = BuildFileLocation() self.__isResolved = False
def __init__(self, replacementToken, filepath): self.replacementToken, self.filepath = replacementToken, filepath self.baseDir = BuildFileLocation().buildDir