diff options
Diffstat (limited to 'lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/base.py')
-rw-r--r-- | lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/base.py | 453 |
1 files changed, 0 insertions, 453 deletions
diff --git a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/base.py b/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/base.py deleted file mode 100644 index 4b18f935..00000000 --- a/lib/python2.7/site-packages/buildbot-0.8.8-py2.7.egg/buildbot/schedulers/base.py +++ /dev/null @@ -1,453 +0,0 @@ -# This file is part of Buildbot. Buildbot is free software: you can -# redistribute it and/or modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 -# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Copyright Buildbot Team Members - -from zope.interface import implements -from twisted.python import failure, log -from twisted.application import service -from twisted.internet import defer -from buildbot.process.properties import Properties -from buildbot.util import ComparableMixin -from buildbot import config, interfaces -from buildbot.util.state import StateMixin - -class BaseScheduler(service.MultiService, ComparableMixin, StateMixin): - """ - Base class for all schedulers; this provides the equipment to manage - reconfigurations and to handle basic scheduler state. It also provides - utility methods to begin various sorts of builds. - - Subclasses should add any configuration-derived attributes to - C{base.Scheduler.compare_attrs}. - """ - - implements(interfaces.IScheduler) - - DefaultCodebases = {'':{}} - - compare_attrs = ('name', 'builderNames', 'properties', 'codebases') - - def __init__(self, name, builderNames, properties, - codebases = DefaultCodebases): - """ - Initialize a Scheduler. - - @param name: name of this scheduler (used as a key for state) - @type name: unicode - - @param builderNames: list of builders this scheduler may start - @type builderNames: list of unicode - - @param properties: properties to add to builds triggered by this - scheduler - @type properties: dictionary - - @param codebases: codebases that are necessary to process the changes - @type codebases: dict with following struct: - key: '<codebase>' - value: {'repository':'<repo>', 'branch':'<br>', 'revision:'<rev>'} - - @param consumeChanges: true if this scheduler wishes to be informed - about the addition of new changes. Defaults to False. This should - be passed explicitly from subclasses to indicate their interest in - consuming changes. - @type consumeChanges: boolean - """ - service.MultiService.__init__(self) - self.name = name - "name of this scheduler; used to identify replacements on reconfig" - - ok = True - if not isinstance(builderNames, (list, tuple)): - ok = False - else: - for b in builderNames: - if not isinstance(b, basestring): - ok = False - if not ok: - config.error( - "The builderNames argument to a scheduler must be a list " - "of Builder names.") - - self.builderNames = builderNames - "list of builder names to start in each buildset" - - self.properties = Properties() - "properties that are contributed to each buildset" - self.properties.update(properties, "Scheduler") - self.properties.setProperty("scheduler", name, "Scheduler") - - self.objectid = None - - self.master = None - - # Set the codebases that are necessary to process the changes - # These codebases will always result in a sourcestamp with or without changes - if codebases is not None: - if not isinstance(codebases, dict): - config.error("Codebases must be a dict of dicts") - for codebase, codebase_attrs in codebases.iteritems(): - if not isinstance(codebase_attrs, dict): - config.error("Codebases must be a dict of dicts") - if (codebases != BaseScheduler.DefaultCodebases and - 'repository' not in codebase_attrs): - config.error("The key 'repository' is mandatory in codebases") - else: - config.error("Codebases cannot be None") - - self.codebases = codebases - - # internal variables - self._change_subscription = None - self._change_consumption_lock = defer.DeferredLock() - - ## service handling - - def startService(self): - service.MultiService.startService(self) - - def findNewSchedulerInstance(self, new_config): - return new_config.schedulers[self.name] # should exist! - - def stopService(self): - d = defer.maybeDeferred(self._stopConsumingChanges) - d.addCallback(lambda _ : service.MultiService.stopService(self)) - return d - - - ## status queries - - # TODO: these aren't compatible with distributed schedulers - - def listBuilderNames(self): - "Returns the list of builder names" - return self.builderNames - - def getPendingBuildTimes(self): - "Returns a list of the next times that builds are scheduled, if known." - return [] - - ## change handling - - def startConsumingChanges(self, fileIsImportant=None, change_filter=None, - onlyImportant=False): - """ - Subclasses should call this method from startService to register to - receive changes. The BaseScheduler class will take care of filtering - the changes (using change_filter) and (if fileIsImportant is not None) - classifying them. See L{gotChange}. Returns a Deferred. - - @param fileIsImportant: a callable provided by the user to distinguish - important and unimportant changes - @type fileIsImportant: callable - - @param change_filter: a filter to determine which changes are even - considered by this scheduler, or C{None} to consider all changes - @type change_filter: L{buildbot.changes.filter.ChangeFilter} instance - - @param onlyImportant: If True, only important changes, as specified by - fileIsImportant, will be added to the buildset. - @type onlyImportant: boolean - - """ - assert fileIsImportant is None or callable(fileIsImportant) - - # register for changes with master - assert not self._change_subscription - def changeCallback(change): - # ignore changes delivered while we're not running - if not self._change_subscription: - return - - if change_filter and not change_filter.filter_change(change): - return - if change.codebase not in self.codebases: - log.msg(format='change contains codebase %(codebase)s that is' - 'not processed by scheduler %(scheduler)s', - codebase=change.codebase, name=self.name) - return - if fileIsImportant: - try: - important = fileIsImportant(change) - if not important and onlyImportant: - return - except: - log.err(failure.Failure(), - 'in fileIsImportant check for %s' % change) - return - else: - important = True - - # use change_consumption_lock to ensure the service does not stop - # while this change is being processed - d = self._change_consumption_lock.run(self.gotChange, change, important) - d.addErrback(log.err, 'while processing change') - self._change_subscription = self.master.subscribeToChanges(changeCallback) - - return defer.succeed(None) - - def _stopConsumingChanges(self): - # (note: called automatically in stopService) - - # acquire the lock change consumption lock to ensure that any change - # consumption is complete before we are done stopping consumption - def stop(): - if self._change_subscription: - self._change_subscription.unsubscribe() - self._change_subscription = None - return self._change_consumption_lock.run(stop) - - def gotChange(self, change, important): - """ - Called when a change is received; returns a Deferred. If the - C{fileIsImportant} parameter to C{startConsumingChanges} was C{None}, - then all changes are considered important. - The C{codebase} of the change has always an entry in the C{codebases} - dictionary of the scheduler. - - @param change: the new change object - @type change: L{buildbot.changes.changes.Change} instance - @param important: true if this is an important change, according to - C{fileIsImportant}. - @type important: boolean - @returns: Deferred - """ - raise NotImplementedError - - ## starting bulids - - @defer.inlineCallbacks - def addBuildsetForLatest(self, reason='', external_idstring=None, - branch=None, repository='', project='', - builderNames=None, properties=None): - """ - Add a buildset for the 'latest' source in the given branch, - repository, and project. This will create a relative sourcestamp for - the buildset. - - This method will add any properties provided to the scheduler - constructor to the buildset, and will call the master's addBuildset - method with the appropriate parameters. - - @param reason: reason for this buildset - @type reason: unicode string - @param external_idstring: external identifier for this buildset, or None - @param branch: branch to build (note that None often has a special meaning) - @param repository: repository name for sourcestamp - @param project: project name for sourcestamp - @param builderNames: builders to name in the buildset (defaults to - C{self.builderNames}) - @param properties: a properties object containing initial properties for - the buildset - @type properties: L{buildbot.process.properties.Properties} - @returns: (buildset ID, buildrequest IDs) via Deferred - """ - # Define setid for this set of changed repositories - setid = yield self.master.db.sourcestampsets.addSourceStampSet() - - # add a sourcestamp for each codebase - for codebase, cb_info in self.codebases.iteritems(): - ss_repository = cb_info.get('repository', repository) - ss_branch = cb_info.get('branch', branch) - ss_revision = cb_info.get('revision', None) - yield self.master.db.sourcestamps.addSourceStamp( - codebase=codebase, - repository=ss_repository, - branch=ss_branch, - revision=ss_revision, - project=project, - changeids=set(), - sourcestampsetid=setid) - - bsid,brids = yield self.addBuildsetForSourceStamp( - setid=setid, reason=reason, - external_idstring=external_idstring, - builderNames=builderNames, - properties=properties) - - defer.returnValue((bsid,brids)) - - - @defer.inlineCallbacks - def addBuildsetForSourceStampDetails(self, reason='', external_idstring=None, - branch=None, repository='', project='', revision=None, - builderNames=None, properties=None): - """ - Given details about the source code to build, create a source stamp and - then add a buildset for it. - - @param reason: reason for this buildset - @type reason: unicode string - @param external_idstring: external identifier for this buildset, or None - @param branch: branch to build (note that None often has a special meaning) - @param repository: repository name for sourcestamp - @param project: project name for sourcestamp - @param revision: revision to build - default is latest - @param builderNames: builders to name in the buildset (defaults to - C{self.builderNames}) - @param properties: a properties object containing initial properties for - the buildset - @type properties: L{buildbot.process.properties.Properties} - @returns: (buildset ID, buildrequest IDs) via Deferred - """ - # Define setid for this set of changed repositories - setid = yield self.master.db.sourcestampsets.addSourceStampSet() - - yield self.master.db.sourcestamps.addSourceStamp( - branch=branch, revision=revision, repository=repository, - project=project, sourcestampsetid=setid) - - rv = yield self.addBuildsetForSourceStamp( - setid=setid, reason=reason, - external_idstring=external_idstring, - builderNames=builderNames, - properties=properties) - defer.returnValue(rv) - - - @defer.inlineCallbacks - def addBuildsetForSourceStampSetDetails(self, reason, sourcestamps, - properties, builderNames=None): - if sourcestamps is None: - sourcestamps = {} - - # Define new setid for this set of sourcestamps - new_setid = yield self.master.db.sourcestampsets.addSourceStampSet() - - # Merge codebases with the passed list of sourcestamps - # This results in a new sourcestamp for each codebase - for codebase in self.codebases: - ss = self.codebases[codebase].copy() - # apply info from passed sourcestamps onto the configured default - # sourcestamp attributes for this codebase. - ss.update(sourcestamps.get(codebase,{})) - - # add sourcestamp to the new setid - yield self.master.db.sourcestamps.addSourceStamp( - codebase=codebase, - repository=ss.get('repository', ''), - branch=ss.get('branch', None), - revision=ss.get('revision', None), - project=ss.get('project', ''), - changeids=[c['number'] for c in ss.get('changes', [])], - patch_body=ss.get('patch_body', None), - patch_level=ss.get('patch_level', None), - patch_author=ss.get('patch_author', None), - patch_comment=ss.get('patch_comment', None), - sourcestampsetid=new_setid) - - rv = yield self.addBuildsetForSourceStamp( - setid=new_setid, reason=reason, - properties=properties, - builderNames=builderNames) - - defer.returnValue(rv) - - - @defer.inlineCallbacks - def addBuildsetForChanges(self, reason='', external_idstring=None, - changeids=[], builderNames=None, properties=None): - changesByCodebase = {} - - def get_last_change_for_codebase(codebase): - return max(changesByCodebase[codebase],key = lambda change: change["changeid"]) - - # Define setid for this set of changed repositories - setid = yield self.master.db.sourcestampsets.addSourceStampSet() - - # Changes are retrieved from database and grouped by their codebase - for changeid in changeids: - chdict = yield self.master.db.changes.getChange(changeid) - # group change by codebase - changesByCodebase.setdefault(chdict["codebase"], []).append(chdict) - - for codebase in self.codebases: - args = {'codebase': codebase, 'sourcestampsetid': setid } - if codebase not in changesByCodebase: - # codebase has no changes - # create a sourcestamp that has no changes - args['repository'] = self.codebases[codebase]['repository'] - args['branch'] = self.codebases[codebase].get('branch', None) - args['revision'] = self.codebases[codebase].get('revision', None) - args['changeids'] = set() - args['project'] = '' - else: - #codebase has changes - args['changeids'] = [c["changeid"] for c in changesByCodebase[codebase]] - lastChange = get_last_change_for_codebase(codebase) - for key in ['repository', 'branch', 'revision', 'project']: - args[key] = lastChange[key] - - yield self.master.db.sourcestamps.addSourceStamp(**args) - - # add one buildset, this buildset is connected to the sourcestamps by the setid - bsid,brids = yield self.addBuildsetForSourceStamp( setid=setid, - reason=reason, external_idstring=external_idstring, - builderNames=builderNames, properties=properties) - - defer.returnValue((bsid,brids)) - - @defer.inlineCallbacks - def addBuildsetForSourceStamp(self, ssid=None, setid=None, reason='', external_idstring=None, - properties=None, builderNames=None): - """ - Add a buildset for the given, already-existing sourcestamp. - - This method will add any properties provided to the scheduler - constructor to the buildset, and will call the master's - L{BuildMaster.addBuildset} method with the appropriate parameters, and - return the same result. - - @param reason: reason for this buildset - @type reason: unicode string - @param external_idstring: external identifier for this buildset, or None - @param properties: a properties object containing initial properties for - the buildset - @type properties: L{buildbot.process.properties.Properties} - @param builderNames: builders to name in the buildset (defaults to - C{self.builderNames}) - @param setid: idenitification of a set of sourcestamps - @returns: (buildset ID, buildrequest IDs) via Deferred - """ - assert (ssid is None and setid is not None) \ - or (ssid is not None and setid is None), "pass a single sourcestamp OR set not both" - - # combine properties - if properties: - properties.updateFromProperties(self.properties) - else: - properties = self.properties - - # apply the default builderNames - if not builderNames: - builderNames = self.builderNames - - # translate properties object into a dict as required by the - # addBuildset method - properties_dict = properties.asDict() - - if setid == None: - if ssid is not None: - ssdict = yield self.master.db.sourcestamps.getSourceStamp(ssid) - setid = ssdict['sourcestampsetid'] - else: - # no sourcestamp and no sets - yield None - - rv = yield self.master.addBuildset(sourcestampsetid=setid, - reason=reason, properties=properties_dict, - builderNames=builderNames, - external_idstring=external_idstring) - defer.returnValue(rv) - |