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

Source Code for Module buildslave.commands.fs

  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 
 17  import sys 
 18  import shutil 
 19   
 20  from twisted.internet import defer 
 21  from twisted.python import runtime, log 
 22   
 23  from buildslave import runprocess 
 24  from buildslave.commands import base, utils 
 25   
26 -class MakeDirectory(base.Command):
27 """This is a Command which creates a directory. The args dict contains 28 the following keys: 29 30 - ['dir'] (required): subdirectory which the command will create, 31 relative to the builder dir 32 33 MakeDirectory creates the following status messages: 34 - {'rc': rc} : when the process has terminated 35 """ 36 37 header = "mkdir" 38
39 - def start(self):
40 args = self.args 41 # args['dir'] is relative to Builder directory, and is required. 42 assert args['dir'] is not None 43 dirname = os.path.join(self.builder.basedir, args['dir']) 44 45 try: 46 if not os.path.isdir(dirname): 47 os.makedirs(dirname) 48 self.sendStatus({'rc': 0}) 49 except: 50 self.sendStatus({'rc': 1})
51
52 -class RemoveDirectory(base.Command):
53 """This is a Command which removes a directory. The args dict contains 54 the following keys: 55 56 - ['dir'] (required): subdirectory which the command will create, 57 relative to the builder dir 58 59 - ['timeout']: seconds of silence tolerated before we kill off the 60 command 61 62 - ['maxTime']: seconds before we kill off the command 63 64 65 RemoveDirectory creates the following status messages: 66 - {'rc': rc} : when the process has terminated 67 """ 68 69 header = "rmdir" 70
71 - def start(self):
72 args = self.args 73 # args['dir'] is relative to Builder directory, and is required. 74 assert args['dir'] is not None 75 dirname = args['dir'] 76 77 self.timeout = args.get('timeout', 120) 78 self.maxTime = args.get('maxTime', None) 79 80 # TODO: remove the old tree in the background 81 self.dir = os.path.join(self.builder.basedir, dirname) 82 if runtime.platformType != "posix": 83 # if we're running on w32, use rmtree instead. It will block, 84 # but hopefully it won't take too long. 85 utils.rmdirRecursive(self.dir) 86 d = defer.succeed(0) 87 else: 88 d = self._clobber(None) 89 90 # always add the RC, regardless of platform 91 d.addCallbacks(self._sendRC, self._checkAbandoned) 92 return d
93
94 - def _clobber(self, dummy, chmodDone = False):
95 command = ["rm", "-rf", self.dir] 96 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 97 sendRC=0, timeout=self.timeout, maxTime=self.maxTime, 98 usePTY=False) 99 100 self.command = c 101 # sendRC=0 means the rm command will send stdout/stderr to the 102 # master, but not the rc=0 when it finishes. That job is left to 103 # _sendRC 104 d = c.start() 105 # The rm -rf may fail if there is a left-over subdir with chmod 000 106 # permissions. So if we get a failure, we attempt to chmod suitable 107 # permissions and re-try the rm -rf. 108 if chmodDone: 109 d.addCallback(self._abandonOnFailure) 110 else: 111 d.addCallback(self._tryChmod) 112 return d
113
114 - def _tryChmod(self, rc):
115 assert isinstance(rc, int) 116 if rc == 0: 117 return defer.succeed(0) 118 # Attempt a recursive chmod and re-try the rm -rf after. 119 120 command = ["chmod", "-Rf", "u+rwx", os.path.join(self.builder.basedir, self.dir)] 121 if sys.platform.startswith('freebsd'): 122 # Work around a broken 'chmod -R' on FreeBSD (it tries to recurse into a 123 # directory for which it doesn't have permission, before changing that 124 # permission) by running 'find' instead 125 command = ["find", os.path.join(self.builder.basedir, self.dir), 126 '-exec', 'chmod', 'u+rwx', '{}', ';' ] 127 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 128 sendRC=0, timeout=self.timeout, maxTime=self.maxTime, 129 usePTY=False) 130 131 self.command = c 132 d = c.start() 133 d.addCallback(self._abandonOnFailure) 134 d.addCallback(lambda dummy: self._clobber(dummy, True)) 135 return d
136
137 -class CopyDirectory(base.Command):
138 """This is a Command which copies a directory. The args dict contains 139 the following keys: 140 141 - ['fromdir'] (required): subdirectory which the command will copy, 142 relative to the builder dir 143 - ['todir'] (required): subdirectory which the command will create, 144 relative to the builder dir 145 146 - ['timeout']: seconds of silence tolerated before we kill off the 147 command 148 149 - ['maxTime']: seconds before we kill off the command 150 151 152 CopyDirectory creates the following status messages: 153 - {'rc': rc} : when the process has terminated 154 """ 155 156 header = "rmdir" 157
158 - def start(self):
159 args = self.args 160 # args['todir'] is relative to Builder directory, and is required. 161 # args['fromdir'] is relative to Builder directory, and is required. 162 assert args['todir'] is not None 163 assert args['fromdir'] is not None 164 165 fromdir = os.path.join(self.builder.basedir, args['fromdir']) 166 todir = os.path.join(self.builder.basedir, args['todir']) 167 168 self.timeout = args.get('timeout', 120) 169 self.maxTime = args.get('maxTime', None) 170 171 if runtime.platformType != "posix": 172 self.sendStatus({'header': "Since we're on a non-POSIX platform, " 173 "we're not going to try to execute cp in a subprocess, but instead " 174 "use shutil.copytree(), which will block until it is complete. " 175 "fromdir: %s, todir: %s\n" % (fromdir, todir)}) 176 shutil.copytree(fromdir, todir) 177 d = defer.succeed(0) 178 else: 179 if not os.path.exists(os.path.dirname(todir)): 180 os.makedirs(os.path.dirname(todir)) 181 if os.path.exists(todir): 182 # I don't think this happens, but just in case.. 183 log.msg("cp target '%s' already exists -- cp will not do what you think!" % todir) 184 185 command = ['cp', '-R', '-P', '-p', fromdir, todir] 186 c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 187 sendRC=False, timeout=self.timeout, maxTime=self.maxTime, 188 usePTY=False) 189 self.command = c 190 d = c.start() 191 d.addCallback(self._abandonOnFailure) 192 193 # always set the RC, regardless of platform 194 d.addCallbacks(self._sendRC, self._checkAbandoned) 195 return d
196
197 -class StatFile(base.Command):
198 """This is a command which stats a file on the slave. The args dict contains the following keys: 199 200 - ['file'] (required): file to stat 201 202 StatFile creates the following status messages: 203 - {'rc': rc} : 0 if the file is found, 1 otherwise 204 - {'stat': stat} : if the files is found, stat contains the result of os.stat 205 """ 206 207 header = "stat" 208
209 - def start(self):
210 args = self.args 211 # args['dir'] is relative to Builder directory, and is required. 212 assert args['file'] is not None 213 filename = os.path.join(self.builder.basedir, args['file']) 214 215 try: 216 stat = os.stat(filename) 217 self.sendStatus({'stat': tuple(stat)}) 218 self.sendStatus({'rc': 0}) 219 except: 220 self.sendStatus({'rc': 1})
221