Package buildbot :: Package steps :: Package source :: Module base
[frames] | no frames]

Source Code for Module buildbot.steps.source.base

  1  # This file is part of Buildbot.  Buildbot is free software: you can 
  2  # redistribute it and/or modify it under the terms of the GNU General Public 
  3  # License as published by the Free Software Foundation, version 2. 
  4  # 
  5  # This program is distributed in the hope that it will be useful, but WITHOUT 
  6  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
  8  # details. 
  9  # 
 10  # You should have received a copy of the GNU General Public License along with 
 11  # this program; if not, write to the Free Software Foundation, Inc., 51 
 12  # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 13  # 
 14  # Copyright Buildbot Team Members 
 15   
 16   
 17  from twisted.python import log 
 18  from buildbot.process.buildstep import LoggingBuildStep 
 19  from buildbot.status.builder import SKIPPED, FAILURE 
 20   
21 -class Source(LoggingBuildStep):
22 """This is a base class to generate a source tree in the buildslave. 23 Each version control system has a specialized subclass, and is expected 24 to override __init__ and implement computeSourceRevision() and 25 startVC(). The class as a whole builds up the self.args dictionary, then 26 starts a RemoteCommand with those arguments. 27 """ 28 29 renderables = LoggingBuildStep.renderables + [ 30 'description', 'descriptionDone', 'descriptionSuffix', 31 'workdir' ] 32 33 description = None # set this to a list of short strings to override 34 descriptionDone = None # alternate description when the step is complete 35 descriptionSuffix = None # extra information to append to suffix 36 37 # if the checkout fails, there's no point in doing anything else 38 haltOnFailure = True 39 flunkOnFailure = True 40 notReally = False 41 42 branch = None # the default branch, should be set in __init__ 43
44 - def __init__(self, workdir=None, mode='update', alwaysUseLatest=False, 45 timeout=20*60, retry=None, env=None, logEnviron=True, 46 description=None, descriptionDone=None, descriptionSuffix=None, 47 codebase='', **kwargs):
48 """ 49 @type workdir: string 50 @param workdir: local directory (relative to the Builder's root) 51 where the tree should be placed 52 53 @type alwaysUseLatest: boolean 54 @param alwaysUseLatest: whether to always update to the most 55 recent available sources for this build. 56 57 Normally the Source step asks its Build for a list of all 58 Changes that are supposed to go into the build, then computes a 59 'source stamp' (revision number or timestamp) that will cause 60 exactly that set of changes to be present in the checked out 61 tree. This is turned into, e.g., 'cvs update -D timestamp', or 62 'svn update -r revnum'. If alwaysUseLatest=True, bypass this 63 computation and always update to the latest available sources 64 for each build. 65 66 The source stamp helps avoid a race condition in which someone 67 commits a change after the master has decided to start a build 68 but before the slave finishes checking out the sources. At best 69 this results in a build which contains more changes than the 70 buildmaster thinks it has (possibly resulting in the wrong 71 person taking the blame for any problems that result), at worst 72 is can result in an incoherent set of sources (splitting a 73 non-atomic commit) which may not build at all. 74 75 @type logEnviron: boolean 76 @param logEnviron: If this option is true (the default), then the 77 step's logfile will describe the environment 78 variables on the slave. In situations where the 79 environment is not relevant and is long, it may 80 be easier to set logEnviron=False. 81 82 @type codebase: string 83 @param codebase: Specifies which changes in a build are processed by 84 the step. The default codebase value is ''. The codebase must correspond 85 to a codebase assigned by the codebaseGenerator. If no codebaseGenerator 86 is defined in the master then codebase doesn't need to be set, the 87 default value will then match all changes. 88 """ 89 90 LoggingBuildStep.__init__(self, **kwargs) 91 92 # This will get added to args later, after properties are rendered 93 self.workdir = workdir 94 95 self.sourcestamp = None 96 97 self.codebase = codebase 98 if self.codebase: 99 self.name = ' '.join((self.name, self.codebase)) 100 101 self.alwaysUseLatest = alwaysUseLatest 102 103 self.logEnviron = logEnviron 104 self.env = env 105 self.timeout = timeout 106 107 descriptions_for_mode = { 108 "clobber": "checkout", 109 "export": "exporting"} 110 descriptionDones_for_mode = { 111 "clobber": "checkout", 112 "export": "export"} 113 if description: 114 self.description = description 115 else: 116 self.description = [ 117 descriptions_for_mode.get(mode, "updating")] 118 if isinstance(self.description, str): 119 self.description = [self.description] 120 121 if descriptionDone: 122 self.descriptionDone = descriptionDone 123 else: 124 self.descriptionDone = [ 125 descriptionDones_for_mode.get(mode, "update")] 126 if isinstance(self.descriptionDone, str): 127 self.descriptionDone = [self.descriptionDone] 128 129 if descriptionSuffix: 130 self.descriptionSuffix = descriptionSuffix 131 else: 132 self.descriptionSuffix = self.codebase or None # want None in lieu of '' 133 if isinstance(self.descriptionSuffix, str): 134 self.descriptionSuffix = [self.descriptionSuffix]
135
136 - def updateSourceProperty(self, name, value, source=''):
137 """ 138 Update a property, indexing the proeprty by codebase if codebase is not 139 ''. Source steps should generally use this instead of setProperty. 140 """ 141 # pick a decent source name 142 if source == '': 143 source = self.__class__.__name__ 144 145 if self.codebase != '': 146 assert not isinstance(self.getProperty(name, None), str), \ 147 "Sourcestep %s has a codebase, other sourcesteps don't" \ 148 % self.name 149 property_dict = self.getProperty(name, {}) 150 property_dict[self.codebase] = value 151 LoggingBuildStep.setProperty(self, name, property_dict, source) 152 else: 153 assert not isinstance(self.getProperty(name, None), dict), \ 154 "Sourcestep %s does not have a codebase, other sourcesteps do" \ 155 % self.name 156 LoggingBuildStep.setProperty(self, name, value, source)
157
158 - def setStepStatus(self, step_status):
160
161 - def setDefaultWorkdir(self, workdir):
162 self.workdir = self.workdir or workdir
163
164 - def describe(self, done=False):
165 desc = self.descriptionDone if done else self.description 166 if self.descriptionSuffix: 167 desc = desc[:] 168 desc.extend(self.descriptionSuffix) 169 return desc
170
171 - def computeSourceRevision(self, changes):
172 """Each subclass must implement this method to do something more 173 precise than -rHEAD every time. For version control systems that use 174 repository-wide change numbers (SVN, P4), this can simply take the 175 maximum such number from all the changes involved in this build. For 176 systems that do not (CVS), it needs to create a timestamp based upon 177 the latest Change, the Build's treeStableTimer, and an optional 178 self.checkoutDelay value.""" 179 return None
180
181 - def start(self):
182 if self.notReally: 183 log.msg("faking %s checkout/update" % self.name) 184 self.step_status.setText(["fake", self.name, "successful"]) 185 self.addCompleteLog("log", 186 "Faked %s checkout/update 'successful'\n" \ 187 % self.name) 188 return SKIPPED 189 190 if not self.alwaysUseLatest: 191 # what source stamp would this step like to use? 192 s = self.build.getSourceStamp(self.codebase) 193 self.sourcestamp = s 194 195 if self.sourcestamp: 196 # if branch is None, then use the Step's "default" branch 197 branch = s.branch or self.branch 198 # if revision is None, use the latest sources (-rHEAD) 199 revision = s.revision 200 if not revision: 201 revision = self.computeSourceRevision(s.changes) 202 # the revision property is currently None, so set it to something 203 # more interesting 204 if revision is not None: 205 self.updateSourceProperty('revision', str(revision)) 206 207 # if patch is None, then do not patch the tree after checkout 208 209 # 'patch' is None or a tuple of (patchlevel, diff, root) 210 # root is optional. 211 patch = s.patch 212 if patch: 213 self.addCompleteLog("patch", patch[1]) 214 else: 215 log.msg("No sourcestamp found in build for codebase '%s'" % self.codebase) 216 self.step_status.setText(["Codebase", '%s' % self.codebase ,"not", "in", "build" ]) 217 self.addCompleteLog("log", 218 "No sourcestamp found in build for codebase '%s'" \ 219 % self.codebase) 220 self.finished(FAILURE) 221 return FAILURE 222 223 else: 224 revision = None 225 branch = self.branch 226 patch = None 227 228 self.startVC(branch, revision, patch)
229