Package buildbot :: Module sourcestamp
[frames] | no frames]

Source Code for Module buildbot.sourcestamp

  1  # -*- test-case-name: buildbot.test.test_sourcestamp -*- 
  2   
  3  from zope.interface import implements 
  4  from twisted.persisted import styles 
  5  from buildbot import util, interfaces 
  6   
7 -class SourceStamp(util.ComparableMixin, styles.Versioned):
8 """This is a tuple of (branch, revision, patchspec, changes, project, repository). 9 10 C{branch} is always valid, although it may be None to let the Source 11 step use its default branch. There are three possibilities for the 12 remaining elements: 13 - (revision=REV, patchspec=None, changes=None): build REV. If REV is 14 None, build the HEAD revision from the given branch. Note that REV 15 must always be a string: SVN, Perforce, and other systems which use 16 integers should provide a string here, but the Source checkout step 17 will integerize it when making comparisons. 18 - (revision=REV, patchspec=(LEVEL, DIFF), changes=None): checkout REV, 19 then apply a patch to the source, with C{patch -pPATCHLEVEL <DIFF}. 20 If REV is None, checkout HEAD and patch it. 21 - (revision=None, patchspec=None, changes=[CHANGES]): let the Source 22 step check out the latest revision indicated by the given Changes. 23 CHANGES is a tuple of L{buildbot.changes.changes.Change} instances, 24 and all must be on the same branch. 25 """ 26 27 persistenceVersion = 2 28 29 # all six of these are publically visible attributes 30 branch = None 31 revision = None 32 patch = None 33 changes = () 34 project = '' 35 repository = '' 36 ssid = None # filled in by db.get_sourcestampid() 37 38 compare_attrs = ('branch', 'revision', 'patch', 'changes', 'project', 'repository') 39 40 implements(interfaces.ISourceStamp) 41
42 - def __init__(self, branch=None, revision=None, patch=None, 43 changes=None, project='', repository=''):
44 if revision is not None: 45 if isinstance(revision, int): 46 revision = str(revision) 47 if patch is not None: 48 patch_level = patch[0] 49 patch_level = int(patch_level) 50 patch_diff = patch[1] 51 if len(patch) > 2: 52 patch_subdir = patch[2] 53 self.branch = branch 54 self.revision = revision 55 self.patch = patch 56 self.project = project 57 self.repository = repository 58 if changes: 59 self.changes = tuple(changes) 60 # set branch and revision to most recent change 61 self.branch = changes[-1].branch 62 self.revision = str(changes[-1].revision) 63 if not self.project: 64 self.project = changes[-1].project 65 if not self.repository: 66 self.repository = changes[-1].repository
67
68 - def canBeMergedWith(self, other):
69 if other.repository != self.repository: 70 return False 71 if other.branch != self.branch: 72 return False # the builds are completely unrelated 73 if other.project != self.project: 74 return False 75 76 if self.changes and other.changes: 77 # TODO: consider not merging these. It's a tradeoff between 78 # minimizing the number of builds and obtaining finer-grained 79 # results. 80 return True 81 elif self.changes and not other.changes: 82 return False # we're using changes, they aren't 83 elif not self.changes and other.changes: 84 return False # they're using changes, we aren't 85 86 if self.patch or other.patch: 87 return False # you can't merge patched builds with anything 88 if self.revision == other.revision: 89 # both builds are using the same specific revision, so they can 90 # be merged. It might be the case that revision==None, so they're 91 # both building HEAD. 92 return True 93 94 return False
95
96 - def mergeWith(self, others):
97 """Generate a SourceStamp for the merger of me and all the other 98 BuildRequests. This is called by a Build when it starts, to figure 99 out what its sourceStamp should be.""" 100 101 # either we're all building the same thing (changes==None), or we're 102 # all building changes (which can be merged) 103 changes = [] 104 changes.extend(self.changes) 105 for req in others: 106 assert self.canBeMergedWith(req) # should have been checked already 107 changes.extend(req.changes) 108 newsource = SourceStamp(branch=self.branch, 109 revision=self.revision, 110 patch=self.patch, 111 project=self.project, 112 repository=self.repository, 113 changes=changes) 114 return newsource
115
116 - def getAbsoluteSourceStamp(self, got_revision):
117 return SourceStamp(branch=self.branch, revision=got_revision, 118 patch=self.patch, repository=self.repository, 119 project=self.project)
120
121 - def getText(self):
122 # note: this won't work for VC systems with huge 'revision' strings 123 text = [] 124 if self.project: 125 text.append("for %s" % self.project) 126 if self.repository: 127 text.append("in %s" % self.repository) 128 if self.revision is None: 129 return text + [ "latest" ] 130 text.append(str(self.revision)) 131 if self.branch: 132 text.append("in '%s'" % self.branch) 133 if self.patch: 134 text.append("[patch]") 135 return text
136
137 - def asDict(self):
138 result = {} 139 # Constant 140 result['revision'] = self.revision 141 # TODO(maruel): Make the patch content a suburl. 142 result['hasPatch']= self.patch is not None 143 result['branch'] = self.branch 144 result['changes'] = [c.asDict() for c in getattr(self, 'changes', [])] 145 result['project'] = self.project 146 result['repository'] = self.repository 147 return result
148
149 - def upgradeToVersion1(self):
150 # version 0 was untyped; in version 1 and later, types matter. 151 if self.branch is not None and not isinstance(self.branch, str): 152 self.branch = str(self.branch) 153 if self.revision is not None and not isinstance(self.revision, str): 154 self.revision = str(self.revision) 155 if self.patch is not None: 156 self.patch = ( int(self.patch[0]), str(self.patch[1]) )
157
158 - def upgradeToVersion2(self):
159 # version 1 did not have project or repository; just set them to a default '' 160 self.project = '' 161 self.repository = ''
162 163 # vim: set ts=4 sts=4 sw=4 et: 164