Package buildslave :: Package commands :: Module p4
[frames] | no frames]

Source Code for Module buildslave.commands.p4

  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  import os, re 
 17   
 18  from twisted.python import log 
 19   
 20  from buildslave.commands.base import SourceBaseCommand 
 21  from buildslave import runprocess 
 22  from buildslave.util import Obfuscated 
 23   
 24   
25 -class P4Base(SourceBaseCommand):
26 """Base class for P4 source-updaters 27 28 ['p4port'] (required): host:port for server to access 29 ['p4user'] (optional): user to use for access 30 ['p4passwd'] (optional): passwd to try for the user 31 ['p4client'] (optional): client spec to use 32 """
33 - def setup(self, args):
34 SourceBaseCommand.setup(self, args) 35 self.p4port = args['p4port'] 36 self.p4client = args['p4client'] 37 self.p4user = args['p4user'] 38 self.p4passwd = args['p4passwd']
39
40 - def parseGotRevision(self):
41 # Executes a p4 command that will give us the latest changelist number 42 # of any file under the current (or default) client: 43 command = ['p4'] 44 if self.p4port: 45 command.extend(['-p', self.p4port]) 46 if self.p4user: 47 command.extend(['-u', self.p4user]) 48 if self.p4passwd: 49 command.extend(['-P', Obfuscated(self.p4passwd, "XXXXXXXX")]) 50 if self.p4client: 51 command.extend(['-c', self.p4client]) 52 # add '-s submitted' for bug #626 53 command.extend(['changes', '-s', 'submitted', '-m', '1', '#have']) 54 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 55 environ=self.env, timeout=self.timeout, 56 maxTime=self.maxTime, sendStdout=True, 57 sendRC=False, keepStdout=True, 58 usePTY=False, logEnviron=self.logEnviron) 59 self.command = c 60 d = c.start() 61 62 def _parse(res): 63 # 'p4 -c clien-name change -m 1 "#have"' will produce an output like: 64 # "Change 28147 on 2008/04/07 by p4user@hostname..." 65 # The number after "Change" is the one we want. 66 m = re.match('Change\s+(\d+)\s+', c.stdout) 67 if m: 68 return m.group(1) 69 return None
70 d.addCallback(_parse) 71 return d
72 73
74 -class P4(P4Base):
75 """A P4 source-updater. 76 77 ['p4port'] (required): host:port for server to access 78 ['p4user'] (required): user to use for access 79 ['p4passwd'] (required): passwd to try for the user 80 ['p4client'] (required): client spec to use 81 ['p4extra_views'] (required): additional client views to use 82 ['p4base'] (required): view into the Perforce depot without branch name or trailing "..." 83 ['p4line_end'] (optional): value of the LineEnd client specification property 84 """ 85 86 header = "p4" 87
88 - def setup(self, args):
89 P4Base.setup(self, args) 90 self.p4base = args['p4base'] 91 self.p4extra_views = args['p4extra_views'] 92 self.p4line_end = args.get('p4line_end', None) 93 self.p4mode = args['mode'] 94 self.p4branch = args['branch'] 95 96 # sourcedata is encoded to utf-8, since otherwise unicode strings 97 # appear with a leading "u", causing comparisons to fail. In 98 # retrospect, comparing str() output is not the best technique! 99 def enc(x): 100 if isinstance(x, unicode): 101 return x.encode('utf8') 102 return x
103 self.sourcedata = str([ 104 enc(x) for x in [ 105 # Perforce server. 106 self.p4port, 107 108 # Client spec. 109 self.p4client, 110 111 # Depot side of view spec. 112 self.p4base, 113 self.p4branch, 114 self.p4extra_views, 115 self.p4line_end, 116 117 # Local side of view spec (srcdir is made from these). 118 self.builder.basedir, 119 self.mode, 120 self.workdir 121 ]])
122 123
124 - def sourcedirIsUpdateable(self):
125 # We assume our client spec is still around. 126 # We just say we aren't updateable if the dir doesn't exist so we 127 # don't get ENOENT checking the sourcedata. 128 return (not self.sourcedirIsPatched() and 129 os.path.isdir(os.path.join(self.builder.basedir, 130 self.srcdir)))
131
132 - def doVCUpdate(self):
133 return self._doP4Sync(force=False)
134
135 - def _doP4Sync(self, force):
136 command = ['p4'] 137 138 if self.p4port: 139 command.extend(['-p', self.p4port]) 140 if self.p4user: 141 command.extend(['-u', self.p4user]) 142 if self.p4passwd: 143 command.extend(['-P', Obfuscated(self.p4passwd, "XXXXXXXX")]) 144 if self.p4client: 145 command.extend(['-c', self.p4client]) 146 command.extend(['sync']) 147 if force: 148 command.extend(['-f']) 149 if self.revision: 150 command.extend(['@' + str(self.revision)]) 151 env = {} 152 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 153 environ=env, sendRC=False, timeout=self.timeout, 154 maxTime=self.maxTime, usePTY=False, 155 logEnviron=self.logEnviron) 156 self.command = c 157 d = c.start() 158 d.addCallback(self._abandonOnFailure) 159 return d
160 161
162 - def doVCFull(self):
163 env = {} 164 command = ['p4'] 165 client_spec = '' 166 client_spec += "Client: %s\n\n" % self.p4client 167 client_spec += "Owner: %s\n\n" % self.p4user 168 client_spec += "Description:\n\tCreated by %s\n\n" % self.p4user 169 client_spec += "Root:\t%s\n\n" % self.builder.basedir 170 client_spec += "Options:\tallwrite rmdir\n\n" 171 if self.p4line_end: 172 client_spec += "LineEnd:\t%s\n\n" % self.p4line_end 173 else: 174 client_spec += "LineEnd:\tlocal\n\n" 175 176 # Setup a view 177 client_spec += "View:\n\t%s" % (self.p4base) 178 if self.p4branch: 179 client_spec += "%s/" % (self.p4branch) 180 client_spec += "... //%s/%s/...\n" % (self.p4client, self.srcdir) 181 if self.p4extra_views: 182 for k, v in self.p4extra_views: 183 client_spec += "\t%s/... //%s/%s%s/...\n" % (k, self.p4client, 184 self.srcdir, v) 185 if self.p4port: 186 command.extend(['-p', self.p4port]) 187 if self.p4user: 188 command.extend(['-u', self.p4user]) 189 if self.p4passwd: 190 command.extend(['-P', Obfuscated(self.p4passwd, "XXXXXXXX")]) 191 command.extend(['client', '-i']) 192 log.msg(client_spec) 193 194 # from bdbaddog in github comments: 195 # I'm pretty sure the issue is that perforce client specs can't be 196 # non-ascii (unless you configure at initial config to be unicode). I 197 # floated a question to perforce mailing list. From reading the 198 # internationalization notes.. 199 # http://www.perforce.com/perforce/doc.092/user/i18nnotes.txt 200 # I'm 90% sure that's the case. 201 # (http://github.com/bdbaddog/buildbot/commit/8420149b2b804efcf5f81a13e18aa62da0424d21) 202 203 # Clean client spec to plain ascii 204 client_spec=client_spec.encode('ascii','ignore') 205 206 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 207 environ=env, sendRC=False, timeout=self.timeout, 208 maxTime=self.maxTime, initialStdin=client_spec, 209 usePTY=False, logEnviron=self.logEnviron) 210 self.command = c 211 d = c.start() 212 d.addCallback(self._abandonOnFailure) 213 d.addCallback(lambda _: self._doP4Sync(force=True)) 214 return d
215
216 - def parseGotRevision(self):
217 if self.revision: 218 return str(self.revision) 219 else: 220 return P4Base.parseGotRevision(self)
221 222
223 -class P4Sync(P4Base):
224 """A partial P4 source-updater. Requires manual setup of a per-slave P4 225 environment. The only thing which comes from the master is P4PORT. 226 'mode' is required to be 'copy'. 227 228 ['p4port'] (required): host:port for server to access 229 ['p4user'] (optional): user to use for access 230 ['p4passwd'] (optional): passwd to try for the user 231 ['p4client'] (optional): client spec to use 232 """ 233 234 header = "p4 sync" 235
236 - def setup(self, args):
237 P4Base.setup(self, args)
238
239 - def sourcedirIsUpdateable(self):
240 return True
241
242 - def _doVC(self, force):
243 d = os.path.join(self.builder.basedir, self.srcdir) 244 command = [self.getCommand('p4')] 245 if self.p4port: 246 command.extend(['-p', self.p4port]) 247 if self.p4user: 248 command.extend(['-u', self.p4user]) 249 if self.p4passwd: 250 command.extend(['-P', Obfuscated(self.p4passwd, "XXXXXXXX")]) 251 if self.p4client: 252 command.extend(['-c', self.p4client]) 253 command.extend(['sync']) 254 if force: 255 command.extend(['-f']) 256 if self.revision: 257 command.extend(['@' + self.revision]) 258 env = {} 259 c = runprocess.RunProcess(self.builder, command, d, environ=env, 260 sendRC=False, timeout=self.timeout, 261 maxTime=self.maxTime, usePTY=False, 262 logEnviron=self.logEnviron) 263 self.command = c 264 return c.start()
265
266 - def doVCUpdate(self):
267 return self._doVC(force=False)
268
269 - def doVCFull(self):
270 return self._doVC(force=True)
271
272 - def parseGotRevision(self):
273 if self.revision: 274 return str(self.revision) 275 else: 276 return P4Base.parseGotRevision(self)
277