def build(self): debug3('running build job for %r\n', self.target.name) (dodir, dofile, basedir, basename, ext) = ( self.dodir, self.dofile, self.dobasedir, self.dobasename, self.doext) # this will run in the dofile's directory, so use only basenames here if vars.OLD_ARGS: arg1 = basename # target name (no extension) arg2 = ext # extension (if any), including leading dot else: arg1 = basename + ext # target name (including extension) arg2 = basename # target name (without extension) argv = ['sh', '-e', dofile, arg1, arg2, # temp output file name os.path.relpath(self.tmpname_arg3, dodir), ] if vars.VERBOSE: argv[1] += 'v' if vars.XTRACE: argv[1] += 'x' if vars.VERBOSE or vars.XTRACE: log_e('\n') firstline = open(os.path.join(dodir, dofile)).readline().strip() if firstline.startswith('#!.../'): _, _, interp_argv = firstline.partition("/") interp_argv = interp_argv.split(' ') interpreter = _find_interpreter(self.dodir, interp_argv[0]) if not interpreter: err('%s unable to find interpreter %s.\n', self.dofile, interp_argv[0]) os._exit(208) self.target.add_dep(state.File(interpreter)) argv[0:2] = [interpreter] + interp_argv[1:] elif firstline.startswith('#!/'): argv[0:2] = firstline[2:].split(' ') log('%s\n', self.target.printable_name()) log_cmd("redo", self.target.name + "\n") try: dn = dodir os.environ['REDO_PWD'] = os.path.join(vars.PWD, dn) os.environ['REDO_TARGET'] = basename + ext os.environ['REDO_DEPTH'] = vars.DEPTH + ' ' if dn: os.chdir(dn) l = logger.Logger(self.log_fd, self.tmp_sout_fd) l.fork() os.close(self.tmp_sout_fd) close_on_exec(1, False) if vars.VERBOSE or vars.XTRACE: log_e('* %s\n' % ' '.join(argv)) os.execvp(argv[0], argv) except: import traceback sys.stderr.write(traceback.format_exc()) err('internal exception - see above\n') raise finally: # returns only if there's an exception (exec in other case) os._exit(127)
def done(self, t, rv): assert self.target.dolock().owned == state.LOCK_EX log_cmd("redo_done", self.target.name + "\n") try: after_t = _try_stat(self.target.name) st1 = os.fstat(self.tmp_sout_f.fileno()) st2 = _try_stat(self.tmpname_arg3) if ( after_t and (not self.before_t or self.before_t.st_ctime != after_t.st_ctime) and not stat.S_ISDIR(after_t.st_mode) ): err("%s modified %s directly!\n", self.dofile, self.target.name) err("...you should update $3 (a temp file) or stdout, not $1.\n") rv = 206 elif vars.OLD_STDOUT and st2 and st1.st_size > 0: err("%s wrote to stdout *and* created $3.\n", self.dofile) err("...you should write status messages to stderr, not stdout.\n") rv = 207 elif vars.WARN_STDOUT and st1.st_size > 0: err("%s wrote to stdout, this is not longer supported.\n", self.dofile) err("...you should write status messages to stderr, not stdout.\n") err('...you should write target content to $3 using for example \'exec >"$3"`.\n') if not vars.OLD_STDOUT: rv = 207 if rv == 0: if st2: os.rename(self.tmpname_arg3, self.target.name) os.unlink(self.tmpname_sout) elif vars.OLD_STDOUT and st1.st_size > 0: try: os.rename(self.tmpname_sout, self.target.name) except OSError, e: if e.errno == errno.ENOENT: unlink(self.target.name) else: raise else: # no output generated at all; that's ok unlink(self.tmpname_sout) unlink(self.target.name) if vars.VERBOSE or vars.XTRACE or vars.DEBUG: log("%s (done)\n\n", self.target.printable_name()) else: