Ticket #87: 124.patch

File 124.patch, 127.4 kB (added by dustin, 9 months ago)

all #124 bugs in properties branch

  • old-124/buildbot/buildset.py

    old new  
    1  
    21from buildbot.process import base 
    32from buildbot.status import builder 
     3from buildbot.process.properties import Properties 
    44 
    55 
    66class BuildSet: 
     
    1111    (source.changes=list).""" 
    1212 
    1313    def __init__(self, builderNames, source, reason=None, bsid=None, 
    14                  scheduler=None, custom_props=None): 
     14                 properties=None): 
    1515        """ 
    1616        @param source: a L{buildbot.sourcestamp.SourceStamp} 
    1717        """ 
     
    1919        self.source = source 
    2020        self.reason = reason 
    2121 
    22         if not custom_props: custom_props = {} 
    23         self.custom_props = custom_props 
     22        self.properties = Properties() 
     23        if properties: self.properties.updateFromProperties(properties) 
    2424 
    2525        self.stillHopeful = True 
    2626        self.status = bss = builder.BuildSetStatus(source, reason, 
    2727                                                   builderNames, bsid) 
    28         self.scheduler = scheduler 
    2928 
    3029    def waitUntilSuccess(self): 
    3130        return self.status.waitUntilSuccess() 
     
    4140        # create the requests 
    4241        for b in builders: 
    4342            req = base.BuildRequest(self.reason, self.source, b.name,  
    44                                     scheduler=self.scheduler, 
    45                                     custom_props=self.custom_props) 
     43                                    properties=self.properties) 
    4644            reqs.append((b, req)) 
    4745            self.requests.append(req) 
    4846            d = req.waitUntilFinished() 
  • old-124/buildbot/buildslave.py

    old new  
    1111from buildbot.status.builder import SlaveStatus 
    1212from buildbot.status.mail import MailNotifier 
    1313from buildbot.interfaces import IBuildSlave 
     14from buildbot.process.properties import Properties 
    1415 
    1516class BuildSlave(NewCredPerspective, service.MultiService): 
    1617    """This is the master-side representative for a remote buildbot slave. 
     
    2627    implements(IBuildSlave) 
    2728 
    2829    def __init__(self, name, password, max_builds=None, 
    29                  notify_on_missing=[], missing_timeout=3600): 
     30                 notify_on_missing=[], missing_timeout=3600, 
     31                 properties={}): 
    3032        """ 
    3133        @param name: botname this machine will supply when it connects 
    3234        @param password: password this machine will supply when 
     
    3436        @param max_builds: maximum number of simultaneous builds that will 
    3537                           be run concurrently on this buildslave (the 
    3638                           default is None for no limit) 
     39        @param properties: properties that will be applied to builds run on  
     40                           this slave 
     41        @type properties: dictionary 
    3742        """ 
    3843        service.MultiService.__init__(self) 
    3944        self.slavename = name 
     
    4449        self.slave_commands = None 
    4550        self.slavebuilders = [] 
    4651        self.max_builds = max_builds 
     52 
     53        self.properties = Properties() 
     54        self.properties.update(properties, "BuildSlave") 
     55        self.properties.setProperty("slavename", name, "BuildSlave") 
     56 
    4757        self.lastMessageReceived = 0 
    4858        if isinstance(notify_on_missing, str): 
    4959            notify_on_missing = [notify_on_missing] 
  • old-124/buildbot/clients/debug.py

    old new  
    105105            if revision == '': 
    106106                revision = None 
    107107        reason = "debugclient 'Request Build' button pushed" 
    108         custom_props = {} 
     108        properties = {} 
    109109        d = self.remote.callRemote("requestBuild", 
    110                                    name, reason, branch, revision, custom_props) 
     110                                   name, reason, branch, revision, properties) 
    111111        d.addErrback(self.err) 
    112112 
    113113    def do_ping(self, widget): 
  • old-124/buildbot/interfaces.py

    old new  
    3838class IScheduler(Interface): 
    3939    """I watch for Changes in the source tree and decide when to trigger 
    4040    Builds. I create BuildSet objects and submit them to the BuildMaster. I 
    41     am a service, and the BuildMaster is always my parent.""" 
     41    am a service, and the BuildMaster is always my parent. 
     42     
     43    @ivar properties: properties to be applied to all builds started by this 
     44    scheduler 
     45    @type properties: L<buildbot.process.properties.Properties> 
     46    """ 
    4247 
    4348    def addChange(change): 
    4449        """A Change has just been dispatched by one of the ChangeSources. 
  • old-124/buildbot/master.py

    old new  
    2727from buildbot.sourcestamp import SourceStamp 
    2828from buildbot.buildslave import BuildSlave 
    2929from buildbot import interfaces 
     30from buildbot.process.properties import Properties 
    3031 
    3132######################################## 
    3233 
     
    227228    def detached(self, mind): 
    228229        pass 
    229230 
    230     def perspective_requestBuild(self, buildername, reason, branch, revision, custom_props): 
    231         assert isinstance(custom_props, dict), \ 
    232                "custom_props must be a dict (not %r)" % (custom_props,) 
    233  
    234         # Provide default values for any custom build properties the 
    235         # client did not send. 
    236         for propertyDict in (self.master.customBuildProperties or []): 
    237             custom_props.setdefault(propertyDict['propertyName'], "") 
    238  
     231    def perspective_requestBuild(self, buildername, reason, branch, revision, properties={}): 
    239232        c = interfaces.IControl(self.master) 
    240233        bc = c.getBuilder(buildername) 
    241234        ss = SourceStamp(branch, revision) 
    242         br = BuildRequest(reason, ss, builderName=buildername, custom_props=custom_props) 
     235        properties = Properties() 
     236        properties.update(properties, "remote requestBuild") 
     237        br = BuildRequest(reason, ss, builderName=buildername, properties=properties) 
    243238        bc.requestBuild(br) 
    244239 
    245240    def perspective_pingBuilder(self, buildername): 
     
    347342    projectURL = None 
    348343    buildbotURL = None 
    349344    change_svc = None 
    350     customBuildProperties = None 
     345    properties = Properties() 
    351346 
    352347    def __init__(self, basedir, configFileName="master.cfg"): 
    353348        service.MultiService.__init__(self) 
     
    503498                      "schedulers", "builders", 
    504499                      "slavePortnum", "debugPassword", "manhole", 
    505500                      "status", "projectName", "projectURL", "buildbotURL", 
    506                       "customBuildProperties" 
     501                      "properties" 
    507502                      ) 
    508503        for k in config.keys(): 
    509504            if k not in known_keys: 
     
    531526            projectName = config.get('projectName') 
    532527            projectURL = config.get('projectURL') 
    533528            buildbotURL = config.get('buildbotURL') 
    534             customBuildProperties = config.get('customBuildProperties'
     529            properties = config.get('properties', {}
    535530 
    536531        except KeyError, e: 
    537532            log.msg("config dictionary is missing a required parameter") 
     
    663658                    else: 
    664659                        locks[l.name] = l 
    665660 
     661        if not isinstance(properties, dict): 
     662            raise ValueError("c['properties'] must be a dictionary") 
     663 
    666664        # slavePortnum supposed to be a strports specification 
    667665        if type(slavePortnum) is int: 
    668666            slavePortnum = "tcp:%d" % slavePortnum 
     
    677675        self.projectName = projectName 
    678676        self.projectURL = projectURL 
    679677        self.buildbotURL = buildbotURL 
    680         self.customBuildProperties = customBuildProperties 
     678         
     679        self.properties = Properties() 
     680        self.properties.update(properties, self.configFileName) 
    681681 
    682682        # self.slaves: Disconnect any that were attached and removed from the 
    683683        # list. Update self.checker with the new list of passwords, including 
  • old-124/buildbot/process/base.py

    old new  
    1111from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, EXCEPTION 
    1212from buildbot.status.builder import Results, BuildRequestStatus 
    1313from buildbot.status.progress import BuildProgress 
     14from buildbot.process.properties import Properties 
    1415 
    1516class BuildRequest: 
    1617    """I represent a request to a specific Builder to run a single build. 
     
    3940                  provide this, but for forced builds the user requesting the 
    4041                  build will provide a string. 
    4142 
    42     @type custom_props: dictionary. 
    43     @ivar custom_props: custom user properties. 
     43    @type properties: Properties object 
     44    @ivar properties: properties that should be applied to this build 
    4445 
    4546    @ivar status: the IBuildStatus object which tracks our status 
    4647 
     
    5253    source = None 
    5354    builder = None 
    5455    startCount = 0 # how many times we have tried to start this build 
    55     custom_props = {} 
    5656 
    5757    implements(interfaces.IBuildRequestControl) 
    5858 
    59     def __init__(self, reason, source, builderName=None, scheduler=None, custom_props=None): 
     59    def __init__(self, reason, source, builderName=None, properties=None): 
    6060        # TODO: remove the =None on builderName, it is there so I don't have 
    6161        # to change a lot of tests that create BuildRequest objects 
    6262        assert interfaces.ISourceStamp(source, None) 
    6363        self.reason = reason 
    6464        self.source = source 
    65         self.scheduler = scheduler 
    6665 
    67         if not custom_props: custom_props = {} 
    68         self.custom_props = custom_props 
    69         assert isinstance(self.custom_props, dict), \ 
    70                "custom_props must be a dict (not %r)" % (self.custom_props,) 
     66        self.properties = Properties() 
     67        if properties: 
     68            self.properties.updateFromProperties(properties) 
    7169 
    7270        self.start_watchers = [] 
    7371        self.finish_watchers = [] 
     
    9593        self.finish_watchers.append(d) 
    9694        return d 
    9795 
    98     def customProps(self): 
    99      return self.custom_props 
    100  
    10196    # these are called by the Builder 
    10297 
    10398    def requestSubmitted(self, builder): 
     
    182177        # build a source stamp 
    183178        self.source = requests[0].mergeWith(requests[1:]) 
    184179        self.reason = requests[0].mergeReasons(requests[1:]) 
    185         self.scheduler = requests[0].scheduler 
    186  
    187         # Set custom properties. 
    188         self.custom_properties = requests[0].customProps() 
    189  
    190         #self.abandoned = False 
    191180 
    192181        self.progress = None 
    193182        self.currentStep = None 
     
    207196    def getSourceStamp(self): 
    208197        return self.source 
    209198 
    210     def setProperty(self, propname, value): 
     199    def setProperty(self, propname, value, source): 
    211200        """Set a property on this build. This may only be called after the 
    212201        build has started, so that it has a BuildStatus object where the 
    213202        properties can live.""" 
    214         self.build_status.setProperty(propname, value
     203        self.build_status.setProperty(propname, value, source
    215204 
    216     def getCustomProperties(self): 
    217         return self.custom_properties 
     205    def getProperties(self): 
     206        return self.build_status.getProperties() 
    218207 
    219208    def getProperty(self, propname): 
    220         return self.build_status.properties[propname] 
     209        return self.build_status.getProperty(propname) 
    221210 
    222211    def allChanges(self): 
    223212        return self.source.changes 
     
    275264    def getSlaveName(self): 
    276265        return self.slavebuilder.slave.slavename 
    277266 
    278     def setupStatus(self, build_status): 
    279         self.build_status = build_status 
    280         self.setProperty("buildername", self.builder.name) 
    281         self.setProperty("buildnumber", self.build_status.number) 
    282         self.setProperty("branch", self.source.branch) 
    283         self.setProperty("revision", self.source.revision) 
    284         if self.scheduler is None: 
    285             self.setProperty("scheduler", "none") 
    286         else: 
    287             self.setProperty("scheduler", self.scheduler.name) 
    288         for key, userProp in self.custom_properties.items(): 
    289             self.setProperty(key, userProp) 
     267    def setupProperties(self): 
     268        props = self.getProperties() 
     269 
     270        # start with global properties from the configuration 
     271        buildmaster = self.builder.botmaster.parent 
     272        props.updateFromProperties(buildmaster.properties) 
     273 
     274        # get any properties from requests (this is the path through 
     275        # which schedulers will send us properties) 
     276        for rq in self.requests: 
     277            props.updateFromProperties(rq.properties) 
     278 
     279        # now set some properties of our own, corresponding to the 
     280        # build itself 
     281        props.setProperty("buildername", self.builder.name, "Build") 
     282        props.setProperty("buildnumber", self.build_status.number, "Build") 
     283        props.setProperty("branch", self.source.branch, "Build") 
     284        props.setProperty("revision", self.source.revision, "Build") 
    290285 
    291286    def setupSlaveBuilder(self, slavebuilder): 
    292287        self.slavebuilder = slavebuilder 
     288 
     289        # navigate our way back to the L{buildbot.buildslave.BuildSlave} 
     290        # object that came from the config, and get its properties 
     291        buildslave_properties = slavebuilder.slave.properties 
     292        self.getProperties().updateFromProperties(buildslave_properties) 
     293 
    293294        self.slavename = slavebuilder.slave.slavename 
    294295        self.build_status.setSlavename(self.slavename) 
    295         self.setProperty("slavename", self.slavename) 
    296296 
    297297    def startBuild(self, build_status, expectations, slavebuilder): 
    298298        """This method sets up the build, then starts it by invoking the 
     
    305305        # the Deferred returned by this method. 
    306306 
    307307        log.msg("%s.startBuild" % self) 
    308         self.setupStatus(build_status) 
     308        self.build_status = build_status 
    309309        # now that we have a build_status, we can set properties 
     310        self.setupProperties() 
    310311        self.setupSlaveBuilder(slavebuilder) 
    311312 
    312313        # convert all locks into their real forms 
  • old-124/buildbot/process/builder.py

    old new  
    253253    @type building: list of L{buildbot.process.base.Build} 
    254254    @ivar building: Builds that are actively running 
    255255 
     256    @type slaves: list of L{buildbot.buildslave.BuildSlave} objects 
     257    @ivar slaves: the slaves currently available for building 
    256258    """ 
    257259 
    258260    expectations = None # this is created the first time we get a good build 
     
    445447        """This is invoked by the BuildSlave when the self.slavename bot 
    446448        registers their builder. 
    447449 
    448         @type  slave: L{buildbot.master.BuildSlave} 
     450        @type  slave: L{buildbot.buildslave.BuildSlave} 
    449451        @param slave: the BuildSlave that represents the buildslave as a whole 
    450452        @type  remote: L{twisted.spread.pb.RemoteReference} 
    451453        @param remote: a reference to the L{buildbot.slave.bot.SlaveBuilder} 
  • old-124/buildbot/process/buildstep.py

    old new  
    632632    def getProperty(self, propname): 
    633633        return self.build.getProperty(propname) 
    634634 
    635     def setProperty(self, propname, value): 
    636         self.build.setProperty(propname, value
     635    def setProperty(self, propname, value, source): 
     636        self.build.setProperty(propname, value, source
    637637 
    638638    def startStep(self, remote): 
    639639        """Begin the step. This returns a Deferred that will fire when the 
     
    10921092        self.step_status.setText(self.getText(cmd, results)) 
    10931093        self.step_status.setText2(self.maybeGetText2(cmd, results)) 
    10941094 
    1095 class _BuildPropertyMapping: 
    1096     def __init__(self, build): 
    1097         self.build = build 
    1098     def __getitem__(self, name): 
    1099         p = self.build.getProperty(name) 
    1100         if p is None: 
    1101             p = "" 
    1102         return p 
    1103  
    1104 class WithProperties(util.ComparableMixin): 
    1105     """This is a marker class, used in ShellCommand's command= argument to 
    1106     indicate that we want to interpolate a build property. 
    1107     """ 
    1108  
    1109     compare_attrs = ('fmtstring', 'args') 
    1110  
    1111     def __init__(self, fmtstring, *args): 
    1112         self.fmtstring = fmtstring 
    1113         self.args = args 
    1114  
    1115     def render(self, build): 
    1116         pmap = _BuildPropertyMapping(build) 
    1117         if self.args: 
    1118             strings = [] 
    1119             for name in self.args: 
    1120                 strings.append(pmap[name]) 
    1121             s = self.fmtstring % tuple(strings) 
    1122         else: 
    1123             s = self.fmtstring % pmap 
    1124         return s 
    1125  
    1126 def render_properties(s, build): 
    1127     """Return a string based on s and build that is suitable for use 
    1128     in a running BuildStep.  If s is a string, return s.  If s is a 
    1129     WithProperties object, return the result of s.render(build). 
    1130     Otherwise, return str(s). 
    1131     """ 
    1132     if isinstance(s, (str, unicode)): 
    1133         return s 
    1134     elif isinstance(s, WithProperties): 
    1135         return s.render(build) 
    1136     else: 
    1137         return str(s) 
     1095# (WithProeprties used to be available in this module) 
     1096from buildbot.process.properties import WithProperties 
  • old-124/buildbot/process/properties.py

    old new  
     1from zope.interface import implements 
     2from buildbot import util 
     3from twisted.python import log 
     4from twisted.python.failure import Failure 
     5 
     6class Properties(util.ComparableMixin): 
     7    """ 
     8    I represent a set of properties that can be interpolated into various 
     9    strings in buildsteps. 
     10 
     11    @ivar properties: dictionary mapping property values to tuples  
     12        (value, source), where source is a string identifing the source 
     13        of the property. 
     14 
     15    Objects of this class can be read like a dictionary -- in this case, 
     16    only the property value is returned. 
     17 
     18    As a special case, a property value of None is returned as an empty  
     19    string when used as a mapping. 
     20    """ 
     21 
     22    compare_attrs = ('properties') 
     23 
     24    def __init__(self, **kwargs): 
     25        """ 
     26        @param kwargs: initial property values (for testing) 
     27        """ 
     28        self.properties = {} 
     29        if kwargs: self.update(kwargs, "TEST") 
     30 
     31    def __getitem__(self, name): 
     32        """Just get the value for this property, special-casing None -> ''""" 
     33        rv = self.properties[name][0] 
     34        if rv is None: rv = '' 
     35        return rv 
     36 
     37    def has_key(self, name): 
     38        return self.properties.has_key(name) 
     39 
     40    def getProperty(self, name, default=None): 
     41        """Get the value for the given property, with no None -> '' special case""" 
     42        return self.properties.get(name, (default,))[0] 
     43 
     44    def getPropertySource(self, name): 
     45        return self.properties[name][1] 
     46 
     47    def asList(self): 
     48        """Return the properties as a sorted list of (name, value, source)""" 
     49        l = [ (k, v[0], v[1]) for k,v in self.properties.items() ] 
     50        l.sort() 
     51        return l 
     52 
     53    def __repr__(self): 
     54        return repr(dict([ (k,v[0]) for k,v in self.properties.iteritems() ])) 
     55 
     56    def setProperty(self, name, value, source): 
     57        self.properties[name] = (value, source) 
     58 
     59    def update(self, dict, source): 
     60        """Update this object from a dictionary, with an explicit source specified.""" 
     61        for k, v in dict.items(): 
     62            self.properties[k] = (v, source) 
     63 
     64    def updateFromProperties(self, other): 
     65        """Update this object based on another object; the other object's """ 
     66        self.properties.update(other.properties) 
     67 
     68    def render(self, value): 
     69        """ 
     70        Return a variant of value that has any WithProperties objects 
     71        substituted.  This recurses into Python's compound data types. 
     72        """ 
     73        if isinstance(value, (str, unicode)): 
     74            return value 
     75        elif isinstance(value, WithProperties): 
     76            return value.render(self) 
     77        elif isinstance(value, list): 
     78            return [ self.render(e) for e in value ] 
     79        elif isinstance(value, tuple): 
     80            return tuple([ self.render(e) for e in value ]) 
     81        elif isinstance(value, dict): 
     82            return dict([ (self.render(k), self.render(v)) for k,v in value.iteritems() ]) 
     83        else: 
     84            return value 
     85 
     86class WithProperties(util.ComparableMixin): 
     87    """This is a marker class, used in ShellCommand's command= argument to 
     88    indicate that we want to interpolate a build property. 
     89    """ 
     90 
     91    compare_attrs = ('fmtstring', 'args') 
     92 
     93    def __init__(self, fmtstring, *args): 
     94        self.fmtstring = fmtstring 
     95        self.args = args 
     96 
     97    def render(self, properties): 
     98        if self.args: 
     99            strings = [] 
     100            for name in self.args: 
     101                strings.append(properties[name]) 
     102            s = self.fmtstring % tuple(strings) 
     103        else: 
     104            s = self.fmtstring % properties 
     105        return s 
  • old-124/buildbot/scheduler.py

    old new  
    1414from buildbot.status import builder 
    1515from buildbot.sourcestamp import SourceStamp 
    1616from buildbot.changes.maildir import MaildirService 
     17from buildbot.process.properties import Properties 
    1718 
    1819 
    1920class BaseScheduler(service.MultiService, util.ComparableMixin): 
     21    """ 
     22    A Schduler creates BuildSets and submits them to the BuildMaster. 
     23 
     24    @ivar name: name of the scheduler 
     25 
     26    @ivar properties: additional properties specified in this  
     27        scheduler's configuration 
     28    @type properties: Properties object 
     29    """ 
    2030    implements(interfaces.IScheduler) 
    2131 
    22     def __init__(self, name): 
     32    def __init__(self, name, properties={}): 
     33        """ 
     34        @param name: name for this scheduler 
     35 
     36        @param properties: properties to be propagated from this scheduler 
     37        @type properties: dict 
     38        """ 
    2339        service.MultiService.__init__(self) 
    2440        self.name = name 
     41        self.properties = Properties() 
     42        self.properties.update(properties, "Scheduler") 
     43        self.properties.setProperty("scheduler", name, "Scheduler") 
    2544 
    2645    def __repr__(self): 
    2746        # TODO: why can't id() return a positive number? %d is ugly. 
    2847        return "<Scheduler '%s' at %d>" % (self.name, id(self)) 
    2948 
    30     def submit(self, bs): 
     49    def submitBuildSet(self, bs): 
    3150        self.parent.submitBuildSet(bs) 
    3251 
    3352    def addChange(self, change): 
     
    3655class BaseUpstreamScheduler(BaseScheduler): 
    3756    implements(interfaces.IUpstreamScheduler) 
    3857 
    39     def __init__(self, name): 
    40         BaseScheduler.__init__(self, name
     58    def __init__(self, name, properties={}): 
     59        BaseScheduler.__init__(self, name, properties
    4160        self.successWatchers = [] 
    4261 
    4362    def subscribeToSuccessfulBuilds(self, watcher): 
     
    4564    def unsubscribeToSuccessfulBuilds(self, watcher): 
    4665        self.successWatchers.remove(watcher) 
    4766 
    48     def submit(self, bs): 
     67    def submitBuildSet(self, bs): 
    4968        d = bs.waitUntilFinished() 
    5069        d.addCallback(self.buildSetFinished) 
    51         self.parent.submitBuildSet(bs) 
     70        BaseScheduler.submitBuildSet(self, bs) 
    5271 
    5372    def buildSetFinished(self, bss): 
    5473        if not self.running: 
     
    6988 
    7089    fileIsImportant = None 
    7190    compare_attrs = ('name', 'treeStableTimer', 'builderNames', 'branch', 
    72                      'fileIsImportant'
     91                     'fileIsImportant', 'properties'
    7392     
    7493    def __init__(self, name, branch, treeStableTimer, builderNames, 
    75                  fileIsImportant=None): 
     94                 fileIsImportant=None, properties={}): 
    7695        """ 
    7796        @param name: the name of this Scheduler 
    7897        @param branch: The branch name that the Scheduler should pay 
     
    94113                                build is triggered by an important change. 
    95114                                The default value of None means that all 
    96115                                Changes are important. 
     116 
     117        @param properties: properties to apply to all builds started from this  
     118                           scheduler 
    97119        """ 
    98120 
    99         BaseUpstreamScheduler.__init__(self, name
     121        BaseUpstreamScheduler.__init__(self, name, properties
    100122        self.treeStableTimer = treeStableTimer 
    101123        errmsg = ("The builderNames= argument to Scheduler must be a list " 
    102124                  "of Builder description names (i.e. the 'name' key of the " 
     
    171193        # create a BuildSet, submit it to the BuildMaster 
    172194        bs = buildset.BuildSet(self.builderNames, 
    173195                               SourceStamp(changes=changes), 
    174                                scheduler=self
    175         self.submit(bs) 
     196                               properties=self.properties
     197        self.submitBuildSet(bs) 
    176198 
    177199    def stopService(self): 
    178200        self.stopTimer() 
     
    188210    fileIsImportant = None 
    189211 
    190212    compare_attrs = ('name', 'branches', 'treeStableTimer', 'builderNames', 
    191                      'fileIsImportant'
     213                     'fileIsImportant', 'properties'
    192214 
    193215    def __init__(self, name, branches, treeStableTimer, builderNames, 
    194                  fileIsImportant=None): 
     216                 fileIsImportant=None, properties={}): 
    195217        """ 
    196218        @param name: the name of this Scheduler 
    197219        @param branches: The branch names that the Scheduler should pay 
     
    216238                                build is triggered by an important change. 
    217239                                The default value of None means that all 
    218240                                Changes are important. 
     241 
     242        @param properties: properties to apply to all builds started from this  
     243                           scheduler 
    219244        """ 
    220245 
    221         BaseUpstreamScheduler.__init__(self, name
     246        BaseUpstreamScheduler.__init__(self, name, properties
    222247        self.treeStableTimer = treeStableTimer 
    223248        for b in builderNames: 
    224249            assert isinstance(b, str) 
     
    272297            self.schedulers[branch] = s 
    273298        s.addChange(change) 
    274299 
    275     def submitBuildSet(self, bs): 
    276         self.parent.submitBuildSet(bs) 
    277  
    278300 
    279301class Dependent(BaseUpstreamScheduler): 
    280302    """This scheduler runs some set of 'downstream' builds when the 
    281303    'upstream' scheduler has completed successfully.""" 
    282304 
    283     compare_attrs = ('name', 'upstream', 'builders'
     305    compare_attrs = ('name', 'upstream', 'builders', 'properties'
    284306 
    285     def __init__(self, name, upstream, builderNames): 
     307    def __init__(self, name, upstream, builderNames, properties={}): 
    286308        assert interfaces.IUpstreamScheduler.providedBy(upstream) 
    287         BaseUpstreamScheduler.__init__(self, name
     309        BaseUpstreamScheduler.__init__(self, name, properties
    288310        self.upstream = upstream 
    289311        self.builderNames = builderNames 
    290312 
     
    305327        return d 
    306328 
    307329    def upstreamBuilt(self, ss): 
    308         bs = buildset.BuildSet(self.builderNames, ss, scheduler=self) 
    309         self.submit(bs) 
     330        bs = buildset.BuildSet(self.builderNames, ss, 
     331                    properties=self.properties) 
     332        self.submitBuildSet(bs) 
    310333 
    311334 
    312335 
     
    319342    # TODO: consider having this watch another (changed-based) scheduler and 
    320343    # merely enforce a minimum time between builds. 
    321344 
    322     compare_attrs = ('name', 'builderNames', 'periodicBuildTimer', 'branch'
     345    compare_attrs = ('name', 'builderNames', 'periodicBuildTimer', 'branch', 'properties'
    323346 
    324347    def __init__(self, name, builderNames, periodicBuildTimer, 
    325                  branch=None): 
    326         BaseUpstreamScheduler.__init__(self, name
     348                 branch=None, properties={}): 
     349        BaseUpstreamScheduler.__init__(self, name, properties
    327350        self.builderNames = builderNames 
    328351        self.periodicBuildTimer = periodicBuildTimer 
    329352        self.branch = branch 
     
    344367    def doPeriodicBuild(self): 
    345368        bs = buildset.BuildSet(self.builderNames, 
    346369                               SourceStamp(branch=self.branch), 
    347                                self.reason, scheduler=self) 
    348         self.submit(bs) 
     370                               self.reason, 
     371                               properties=self.properties) 
     372        self.submitBuildSet(bs) 
    349373 
    350374 
    351375 
     
    389413 
    390414    compare_attrs = ('name', 'builderNames', 
    391415                     'minute', 'hour', 'dayOfMonth', 'month', 
    392                      'dayOfWeek', 'branch'
     416                     'dayOfWeek', 'branch', 'properties'
    393417 
    394418    def __init__(self, name, builderNames, minute=0, hour='*', 
    395419                 dayOfMonth='*', month='*', dayOfWeek='*', 
    396                  branch=None): 
     420                 branch=None, properties={}): 
    397421        # Setting minute=0 really makes this an 'Hourly' scheduler. This 
    398422        # seemed like a better default than minute='*', which would result in 
    399423        # a build every 60 seconds. 
    400         BaseUpstreamScheduler.__init__(self, name
     424        BaseUpstreamScheduler.__init__(self, name, properties
    401425        self.builderNames = builderNames 
    402426        self.minute = minute 
    403427        self.hour = hour 
     
    502526        # And trigger a build 
    503527        bs = buildset.BuildSet(self.builderNames, 
    504528                               SourceStamp(branch=self.branch), 
    505                                self.reason, scheduler=self) 
    506         self.submit(bs) 
     529                               self.reason, 
     530                               properties=self.properties) 
     531        self.submitBuildSet(bs) 
    507532 
    508533    def addChange(self, change): 
    509534        pass 
    510535 
    511536 
    512537 
    513 class TryBase(service.MultiService, util.ComparableMixin): 
    514     implements(interfaces.IScheduler) 
    515  
    516     def __init__(self, name, builderNames): 
    517         service.MultiService.__init__(self) 
    518         self.name = name 
     538class TryBase(BaseScheduler): 
     539    def __init__(self, name, builderNames, properties={}): 
     540        BaseScheduler.__init__(self, name, properties) 
    519541        self.builderNames = builderNames 
    520542 
    521543    def listBuilderNames(self): 
     
    546568        self.error = True 
    547569 
    548570class Try_Jobdir(TryBase): 
    549     compare_attrs = ["name", "builderNames", "jobdir"] 
     571    compare_attrs = ( 'name', 'builderNames', 'jobdir', 'properties' ) 
    550572 
    551     def __init__(self, name, builderNames, jobdir): 
    552         TryBase.__init__(self, name, builderNames
     573    def __init__(self, name, builderNames, jobdir, properties={}): 
     574        TryBase.__init__(self, name, builderNames, properties
    553575        self.jobdir = jobdir 
    554576        self.watcher = MaildirService() 
    555577        self.watcher.setServiceParent(self) 
     
    624646                return 
    625647 
    626648        reason = "'try' job" 
    627         bs = buildset.BuildSet(builderNames, ss, reason=reason, bsid=bsid, scheduler=self) 
    628         self.parent.submitBuildSet(bs) 
     649        bs = buildset.BuildSet(builderNames, ss, reason=reason,  
     650                    bsid=bsid, properties=self.properties) 
     651        self.submitBuildSet(bs) 
    629652 
    630653class Try_Userpass(TryBase): 
    631     compare_attrs = ["name", "builderNames", "port", "userpass"] 
     654    compare_attrs = ( 'name', 'builderNames', 'port', 'userpass', 'properties' ) 
    632655    implements(portal.IRealm) 
    633656 
    634     def __init__(self, name, builderNames, port, userpass): 
    635         TryBase.__init__(self, name, builderNames
     657    def __init__(self, name, builderNames, port, userpass, properties={}): 
     658        TryBase.__init__(self, name, builderNames, properties
    636659        if type(port) is int: 
    637660            port = "tcp:%d" % port 
    638661        self.port = port 
     
    657680        p = Try_Userpass_Perspective(self, avatarID) 
    658681        return (pb.IPerspective, p, lambda: None) 
    659682 
    660     def submitBuildSet(self, bs): 
    661         return self.parent.submitBuildSet(bs) 
    662  
    663683class Try_Userpass_Perspective(pbutil.NewCredPerspective): 
    664684    def __init__(self, parent, username): 
    665685        self.parent = parent 
    666686        self.username = username 
    667687 
    668     def perspective_try(self, branch, revision, patch, builderNames, 
    669                         custom_props): 
     688    def perspective_try(self, branch, revision, patch, builderNames, properties={}): 
    670689        log.msg("user %s requesting build on builders %s" % (self.username, 
    671690                                                             builderNames)) 
    672691        for b in builderNames: 
     
    678697        ss = SourceStamp(branch, revision, patch) 
    679698        reason = "'try' job from user %s" % self.username 
    680699 
     700        # roll the specified props in with our inherited props 
     701        combined_props = Properties() 
     702        combined_props.updateFromProperties(self.parent.properties) 
     703        combined_props.update(properties, "try build") 
     704 
    681705        bs = buildset.BuildSet(builderNames,  
    682706                               ss, 
    683707                               reason=reason,  
    684                                scheduler=self, 
    685                                custom_props=custom_props) 
     708                               properties=combined_props) 
    686709 
    687710        self.parent.submitBuildSet(bs) 
    688711 
     
    696719    the builds that I fire have finished. 
    697720    """ 
    698721 
    699     def __init__(self, name, builderNames): 
    700         BaseUpstreamScheduler.__init__(self, name) 
     722    compare_attrs = ('name', 'builderNames', 'properties') 
     723 
     724    def __init__(self, name, builderNames, properties={}): 
     725        BaseUpstreamScheduler.__init__(self, name, properties) 
    701726        self.builderNames = builderNames 
    702727 
    703728    def listBuilderNames(self): 
     
    706731    def getPendingBuildTimes(self): 
    707732        return [] 
    708733 
    709     def trigger(self, ss, custom_props={}): 
     734    def trigger(self, ss, set_props=None): 
    710735        """Trigger this scheduler. Returns a deferred that will fire when the 
    711736        buildset is finished. 
    712737        """ 
    713         bs = buildset.BuildSet(self.builderNames, ss, scheduler=self, custom_props=custom_props) 
     738 
     739        # properties for this buildset are composed of our own properties, 
     740        # potentially overridden by anything from the triggering build 
     741        props = Properties() 
     742        props.updateFromProperties(self.properties) 
     743        if set_props: props.updateFromProperties(set_props) 
     744 
     745        bs = buildset.BuildSet(self.builderNames, ss, properties=props) 
    714746        d = bs.waitUntilFinished() 
    715         self.submit(bs) 
     747        self.submitBuildSet(bs) 
    716748        return d 
  • old-124/buildbot/scripts/runner.py

    old new  
    763763 
    764764        ["builder", "b", None, 
    765765         "Run the trial build on this Builder. Can be used multiple times."], 
    766         ["customproperties", None, None, 
    767          "A set of custom properties made available in the build environment, format:prop=value,propb=valueb..."], 
     766        ["properties", None, None, 
     767         "A set of properties made available in the build environment, format:prop=value,propb=valueb..."], 
    768768        ] 
    769769 
    770770    optFlags = [ 
     
    774774    def __init__(self): 
    775775        super(TryOptions, self).__init__() 
    776776        self['builders'] = [] 
    777         self['custom_props'] = {} 
     777        self['properties'] = {} 
    778778 
    779779    def opt_builder(self, option): 
    780780        self['builders'].append(option) 
    781781 
    782     def opt_customproperties(self, option): 
    783         # We need to split the value of this option into a dictionary of custom 
    784         # properties 
    785         custom_props = {} 
     782    def opt_properties(self, option): 
     783        # We need to split the value of this option into a dictionary of properties 
     784        properties = {} 
    786785        propertylist = option.split(",") 
    787786        for i in range(0,len(propertylist)): 
    788787            print propertylist[i] 
    789788            splitproperty = propertylist[i].split("=") 
    790             custom_props[splitproperty[0]] = splitproperty[1] 
    791         self['custom_props'] = custom_prop
     789            properties[splitproperty[0]] = splitproperty[1] 
     790        self['properties'] = propertie
    792791 
    793792    def opt_patchlevel(self, option): 
    794793        self['patchlevel'] = int(option) 
  • old-124/buildbot/scripts/tryclient.py

    old new  
    448448                              ss.revision, 
    449449                              ss.patch, 
    450450                              self.builderNames, 
    451                               self.config.get('custom_props', {})) 
     451                              self.config.get('properties', {})) 
    452452        d.addCallback(self._deliverJob_pb2) 
    453453        return d 
    454454    def _deliverJob_pb2(self, status): 
  • old-124/buildbot/status/builder.py

    <
    old new  
    55from twisted.persisted import styles 
    66from twisted.internet import reactor, defer 
    77from twisted.protocols import basic 
     8from buildbot.process.properties import Properties 
    89 
    910import os, shutil, sys, re, urllib, itertools 
    1011from cPickle import load, dump 
     
    888889 
    889890class BuildStatus(styles.Versioned): 
    890891    implements(interfaces.IBuildStatus, interfaces.IStatusEvent) 
    891     persistenceVersion = 2 
     892    persistenceVersion = 3 
    892893 
    893894    source = None 
    894895    reason = None 
     
    924925        self.finishedWatchers = [] 
    925926        self.steps = [] 
    926927        self.testResults = {} 
    927         self.properties = {} 
     928        self.properties = Properties() 
    928929 
    929930    # IBuildStatus 
    930931 
     
    937938    def getProperty(self, propname):