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 patch is not None: 45 assert len(patch) == 2 46 assert int(patch[0]) != -1 47 self.branch = branch 48 self.patch = patch 49 self.project = project 50 self.repository = repository 51 if changes: 52 self.changes = tuple(changes) 53 # set branch and revision to most recent change 54 self.branch = changes[-1].branch 55 revision = changes[-1].revision 56 if not self.project and hasattr(changes[-1], 'project'): 57 self.project = changes[-1].project 58 if not self.repository and hasattr(changes[-1], 'repository'): 59 self.repository = changes[-1].repository 60 61 if revision is not None: 62 if isinstance(revision, int): 63 revision = str(revision) 64 65 self.revision = revision
66
67 - def canBeMergedWith(self, other):
68 if other.repository != self.repository: 69 return False 70 if other.branch != self.branch: 71 return False # the builds are completely unrelated 72 if other.project != self.project: 73 return False 74 75 if self.changes and other.changes: 76 # TODO: consider not merging these. It's a tradeoff between 77 # minimizing the number of builds and obtaining finer-grained 78 # results. 79 return True 80 elif self.changes and not other.changes: 81 return False # we're using changes, they aren't 82 elif not self.changes and other.changes: 83 return False # they're using changes, we aren't 84 85 if self.patch or other.patch: 86 return False # you can't merge patched builds with anything 87 if self.revision == other.revision: 88 # both builds are using the same specific revision, so they can 89 # be merged. It might be the case that revision==None, so they're 90 # both building HEAD. 91 return True 92 93 return False
94
95 - def mergeWith(self, others):
96 """Generate a SourceStamp for the merger of me and all the other 97 BuildRequests. This is called by a Build when it starts, to figure 98 out what its sourceStamp should be.""" 99 100 # either we're all building the same thing (changes==None), or we're 101 # all building changes (which can be merged) 102 changes = [] 103 changes.extend(self.changes) 104 for req in others: 105 assert self.canBeMergedWith(req) # should have been checked already 106 changes.extend(req.changes) 107 newsource = SourceStamp(branch=self.branch, 108 revision=self.revision, 109 patch=self.patch, 110 project=self.project, 111 repository=self.repository, 112 changes=changes) 113 return newsource
114
115 - def getAbsoluteSourceStamp(self, got_revision):
116 return SourceStamp(branch=self.branch, revision=got_revision, 117 patch=self.patch, repository=self.repository, 118 project=self.project, changes=self.changes)
119
120 - def getText(self):
121 # note: this won't work for VC systems with huge 'revision' strings 122 text = [] 123 if self.project: 124 text.append("for %s" % self.project) 125 if self.repository: 126 text.append("in %s" % self.repository) 127 if self.revision is None: 128 return text + [ "latest" ] 129 text.append(str(self.revision)) 130 if self.branch: 131 text.append("in '%s'" % self.branch) 132 if self.patch: 133 text.append("[patch]") 134 return text
135
136 - def asDict(self):
137 result = {} 138 # Constant 139 result['revision'] = self.revision 140 # TODO(maruel): Make the patch content a suburl. 141 result['hasPatch'] = self.patch is not None 142 result['branch'] = self.branch 143 result['changes'] = [c.asDict() for c in getattr(self, 'changes', [])] 144 result['project'] = self.project 145 result['repository'] = self.repository 146 return result
147
148 - def upgradeToVersion1(self):
149 # version 0 was untyped; in version 1 and later, types matter. 150 if self.branch is not None and not isinstance(self.branch, str): 151 self.branch = str(self.branch) 152 if self.revision is not None and not isinstance(self.revision, str): 153 self.revision = str(self.revision) 154 if self.patch is not None: 155 self.patch = ( int(self.patch[0]), str(self.patch[1]) )
156
157 - def upgradeToVersion2(self):
158 # version 1 did not have project or repository; just set them to a default '' 159 self.project = '' 160 self.repository = ''
161 162 # vim: set ts=4 sts=4 sw=4 et: 163