2018-10-29 07:21:12 +00:00
|
|
|
import sys, os, errno, random, stat, signal, time
|
2018-10-30 23:23:04 -04:00
|
|
|
import vars, jwack, state, paths
|
2010-12-19 05:47:38 -08:00
|
|
|
from helpers import unlink, close_on_exec, join
|
2010-12-11 18:32:40 -08:00
|
|
|
from log import log, log_, debug, debug2, err, warn
|
2010-11-19 07:21:09 -08:00
|
|
|
|
|
|
|
|
|
2010-11-21 03:34:32 -08:00
|
|
|
def _nice(t):
|
2010-12-09 03:29:34 -08:00
|
|
|
return state.relpath(t, vars.STARTDIR)
|
2010-11-21 03:34:32 -08:00
|
|
|
|
|
|
|
|
|
2010-11-22 04:40:54 -08:00
|
|
|
def _try_stat(filename):
|
|
|
|
|
try:
|
2018-10-06 00:14:02 -04:00
|
|
|
return os.lstat(filename)
|
2010-11-22 04:40:54 -08:00
|
|
|
except OSError, e:
|
|
|
|
|
if e.errno == errno.ENOENT:
|
|
|
|
|
return None
|
|
|
|
|
else:
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
2010-12-10 20:53:31 -08:00
|
|
|
class ImmediateReturn(Exception):
|
|
|
|
|
def __init__(self, rv):
|
|
|
|
|
Exception.__init__(self, "immediate return with exit code %d" % rv)
|
|
|
|
|
self.rv = rv
|
|
|
|
|
|
|
|
|
|
|
2010-11-21 23:33:11 -08:00
|
|
|
class BuildJob:
|
2010-12-10 02:58:13 -08:00
|
|
|
def __init__(self, t, sf, lock, shouldbuildfunc, donefunc):
|
|
|
|
|
self.t = t # original target name, not relative to vars.BASE
|
|
|
|
|
self.sf = sf
|
2011-03-22 22:09:56 -07:00
|
|
|
tmpbase = t
|
|
|
|
|
while not os.path.isdir(os.path.dirname(tmpbase) or '.'):
|
|
|
|
|
ofs = tmpbase.rfind('/')
|
|
|
|
|
assert(ofs >= 0)
|
|
|
|
|
tmpbase = tmpbase[:ofs] + '__' + tmpbase[ofs+1:]
|
|
|
|
|
self.tmpname1 = '%s.redo1.tmp' % tmpbase
|
|
|
|
|
self.tmpname2 = '%s.redo2.tmp' % tmpbase
|
2010-11-21 23:33:11 -08:00
|
|
|
self.lock = lock
|
|
|
|
|
self.shouldbuildfunc = shouldbuildfunc
|
|
|
|
|
self.donefunc = donefunc
|
2010-11-22 04:40:54 -08:00
|
|
|
self.before_t = _try_stat(self.t)
|
2010-11-21 23:33:11 -08:00
|
|
|
|
|
|
|
|
def start(self):
|
2010-11-22 00:03:43 -08:00
|
|
|
assert(self.lock.owned)
|
2010-12-10 20:53:31 -08:00
|
|
|
try:
|
2018-10-30 23:03:46 -04:00
|
|
|
try:
|
|
|
|
|
dirty = self.shouldbuildfunc(self.t)
|
|
|
|
|
except state.CyclicDependencyError:
|
|
|
|
|
err('cyclic dependency while checking %s\n' % _nice(self.t))
|
|
|
|
|
raise ImmediateReturn(208)
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
if not dirty:
|
2010-12-10 20:53:31 -08:00
|
|
|
# target doesn't need to be built; skip the whole task
|
|
|
|
|
return self._after2(0)
|
|
|
|
|
except ImmediateReturn, e:
|
|
|
|
|
return self._after2(e.rv)
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
|
2010-12-11 05:50:29 -08:00
|
|
|
if vars.NO_OOB or dirty == True:
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
self._start_do()
|
|
|
|
|
else:
|
2010-12-19 01:19:52 -08:00
|
|
|
self._start_unlocked(dirty)
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
|
|
|
|
|
def _start_do(self):
|
|
|
|
|
assert(self.lock.owned)
|
|
|
|
|
t = self.t
|
|
|
|
|
sf = self.sf
|
2010-12-10 22:42:33 -08:00
|
|
|
newstamp = sf.read_stamp()
|
|
|
|
|
if (sf.is_generated and
|
|
|
|
|
newstamp != state.STAMP_MISSING and
|
|
|
|
|
(sf.stamp != newstamp or sf.is_override)):
|
2010-12-19 02:31:40 -08:00
|
|
|
state.warn_override(_nice(t))
|
2018-10-12 05:01:07 -04:00
|
|
|
if not sf.is_override:
|
|
|
|
|
warn('%s - old: %r\n' % (_nice(t), sf.stamp))
|
|
|
|
|
warn('%s - new: %r\n' % (_nice(t), newstamp))
|
|
|
|
|
sf.set_override()
|
2010-12-10 22:42:33 -08:00
|
|
|
sf.set_checked()
|
|
|
|
|
sf.save()
|
|
|
|
|
return self._after2(0)
|
2011-03-05 18:11:20 -08:00
|
|
|
if (os.path.exists(t) and not os.path.isdir(t + '/.')
|
2010-12-10 02:58:13 -08:00
|
|
|
and not sf.is_generated):
|
2010-12-06 03:12:53 -08:00
|
|
|
# an existing source file that was not generated by us.
|
|
|
|
|
# This step is mentioned by djb in his notes.
|
|
|
|
|
# For example, a rule called default.c.do could be used to try
|
|
|
|
|
# to produce hello.c, but we don't want that to happen if
|
|
|
|
|
# hello.c was created by the end user.
|
2010-12-07 02:17:22 -08:00
|
|
|
debug2("-- static (%r)\n" % t)
|
2010-12-10 02:58:13 -08:00
|
|
|
sf.set_static()
|
|
|
|
|
sf.save()
|
2010-11-22 00:03:43 -08:00
|
|
|
return self._after2(0)
|
2010-12-11 22:59:55 -08:00
|
|
|
sf.zap_deps1()
|
2018-10-30 23:23:04 -04:00
|
|
|
(dodir, dofile, basedir, basename, ext) = paths.find_do_file(sf)
|
2010-11-22 00:03:43 -08:00
|
|
|
if not dofile:
|
2010-11-24 02:18:19 -08:00
|
|
|
if os.path.exists(t):
|
2010-12-10 02:58:13 -08:00
|
|
|
sf.set_static()
|
|
|
|
|
sf.save()
|
2010-11-24 02:18:19 -08:00
|
|
|
return self._after2(0)
|
|
|
|
|
else:
|
|
|
|
|
err('no rule to make %r\n' % t)
|
|
|
|
|
return self._after2(1)
|
2010-12-11 00:29:04 -08:00
|
|
|
unlink(self.tmpname1)
|
|
|
|
|
unlink(self.tmpname2)
|
|
|
|
|
ffd = os.open(self.tmpname1, os.O_CREAT|os.O_RDWR|os.O_EXCL, 0666)
|
2010-11-22 03:21:17 -08:00
|
|
|
close_on_exec(ffd, True)
|
2010-11-22 01:48:02 -08:00
|
|
|
self.f = os.fdopen(ffd, 'w+')
|
2010-11-22 00:03:43 -08:00
|
|
|
# this will run in the dofile's directory, so use only basenames here
|
2016-11-27 12:29:43 -08:00
|
|
|
arg1 = basename + ext # target name (including extension)
|
|
|
|
|
arg2 = basename # target name (without extension)
|
2010-11-22 00:03:43 -08:00
|
|
|
argv = ['sh', '-e',
|
2010-12-19 05:47:38 -08:00
|
|
|
dofile,
|
2011-12-31 02:45:38 -05:00
|
|
|
arg1,
|
|
|
|
|
arg2,
|
2011-03-22 22:09:56 -07:00
|
|
|
# temp output file name
|
|
|
|
|
state.relpath(os.path.abspath(self.tmpname2), dodir),
|
2010-11-22 00:03:43 -08:00
|
|
|
]
|
|
|
|
|
if vars.VERBOSE: argv[1] += 'v'
|
|
|
|
|
if vars.XTRACE: argv[1] += 'x'
|
|
|
|
|
if vars.VERBOSE or vars.XTRACE: log_('\n')
|
2011-01-15 15:56:43 -08:00
|
|
|
firstline = open(os.path.join(dodir, dofile)).readline().strip()
|
2011-01-01 22:00:14 -08:00
|
|
|
if firstline.startswith('#!/'):
|
|
|
|
|
argv[0:2] = firstline[2:].split(' ')
|
2010-11-22 00:03:43 -08:00
|
|
|
log('%s\n' % _nice(t))
|
2010-12-19 05:47:38 -08:00
|
|
|
self.dodir = dodir
|
|
|
|
|
self.basename = basename
|
|
|
|
|
self.ext = ext
|
2010-11-22 00:03:43 -08:00
|
|
|
self.argv = argv
|
2010-12-10 02:58:13 -08:00
|
|
|
sf.is_generated = True
|
|
|
|
|
sf.save()
|
2011-01-17 23:53:35 -08:00
|
|
|
dof = state.File(name=os.path.join(dodir, dofile))
|
2010-12-07 02:17:22 -08:00
|
|
|
dof.set_static()
|
|
|
|
|
dof.save()
|
2010-12-09 02:44:33 -08:00
|
|
|
state.commit()
|
2010-11-22 00:03:43 -08:00
|
|
|
jwack.start_job(t, self._do_subproc, self._after)
|
|
|
|
|
|
2010-12-19 01:19:52 -08:00
|
|
|
def _start_unlocked(self, dirty):
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
# out-of-band redo of some sub-objects. This happens when we're not
|
2010-12-19 01:19:52 -08:00
|
|
|
# quite sure if t needs to be built or not (because some children
|
|
|
|
|
# look dirty, but might turn out to be clean thanks to checksums).
|
|
|
|
|
# We have to call redo-unlocked to figure it all out.
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
#
|
2010-12-19 01:19:52 -08:00
|
|
|
# Note: redo-unlocked will handle all the updating of sf, so we
|
|
|
|
|
# don't have to do it here, nor call _after1. However, we have to
|
|
|
|
|
# hold onto the lock because otherwise we would introduce a race
|
|
|
|
|
# condition; that's why it's called redo-unlocked, because it doesn't
|
|
|
|
|
# grab a lock.
|
|
|
|
|
argv = ['redo-unlocked', self.sf.name] + [d.name for d in dirty]
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
log('(%s)\n' % _nice(self.t))
|
|
|
|
|
state.commit()
|
|
|
|
|
def run():
|
|
|
|
|
os.chdir(vars.BASE)
|
|
|
|
|
os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
|
2013-06-28 01:48:41 +00:00
|
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL) # python ignores SIGPIPE
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
os.execvp(argv[0], argv)
|
|
|
|
|
assert(0)
|
|
|
|
|
# returns only if there's an exception
|
|
|
|
|
def after(t, rv):
|
|
|
|
|
return self._after2(rv)
|
|
|
|
|
jwack.start_job(self.t, run, after)
|
|
|
|
|
|
2010-11-22 00:03:43 -08:00
|
|
|
def _do_subproc(self):
|
2010-11-25 06:35:22 -08:00
|
|
|
# careful: REDO_PWD was the PWD relative to the STARTPATH at the time
|
|
|
|
|
# we *started* building the current target; but that target ran
|
|
|
|
|
# redo-ifchange, and it might have done it from a different directory
|
2010-12-07 02:17:22 -08:00
|
|
|
# than we started it in. So os.getcwd() might be != REDO_PWD right
|
|
|
|
|
# now.
|
2018-10-06 04:36:24 -04:00
|
|
|
assert(state.is_flushed())
|
2010-12-19 05:47:38 -08:00
|
|
|
dn = self.dodir
|
2010-11-25 06:35:22 -08:00
|
|
|
newp = os.path.realpath(dn)
|
|
|
|
|
os.environ['REDO_PWD'] = state.relpath(newp, vars.STARTDIR)
|
2010-12-19 05:47:38 -08:00
|
|
|
os.environ['REDO_TARGET'] = self.basename + self.ext
|
2010-11-22 00:12:56 -08:00
|
|
|
os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
|
2016-11-27 23:35:28 -08:00
|
|
|
vars.add_lock(str(self.lock.fid))
|
2010-11-22 00:12:56 -08:00
|
|
|
if dn:
|
|
|
|
|
os.chdir(dn)
|
|
|
|
|
os.dup2(self.f.fileno(), 1)
|
|
|
|
|
os.close(self.f.fileno())
|
2010-11-22 03:21:17 -08:00
|
|
|
close_on_exec(1, False)
|
2013-06-28 01:48:41 +00:00
|
|
|
signal.signal(signal.SIGPIPE, signal.SIG_DFL) # python ignores SIGPIPE
|
2010-12-06 02:47:24 -08:00
|
|
|
if vars.VERBOSE or vars.XTRACE: log_('* %s\n' % ' '.join(self.argv))
|
2010-11-22 00:12:56 -08:00
|
|
|
os.execvp(self.argv[0], self.argv)
|
2010-11-22 01:48:02 -08:00
|
|
|
assert(0)
|
2010-11-22 00:12:56 -08:00
|
|
|
# returns only if there's an exception
|
2010-11-22 00:03:43 -08:00
|
|
|
|
|
|
|
|
def _after(self, t, rv):
|
2010-11-22 03:21:17 -08:00
|
|
|
try:
|
2010-12-09 03:01:26 -08:00
|
|
|
state.check_sane()
|
2010-11-22 04:40:54 -08:00
|
|
|
rv = self._after1(t, rv)
|
2010-12-09 05:53:30 -08:00
|
|
|
state.commit()
|
2010-11-22 03:21:17 -08:00
|
|
|
finally:
|
|
|
|
|
self._after2(rv)
|
|
|
|
|
|
|
|
|
|
def _after1(self, t, rv):
|
2010-11-22 00:03:43 -08:00
|
|
|
f = self.f
|
2010-11-22 04:40:54 -08:00
|
|
|
before_t = self.before_t
|
|
|
|
|
after_t = _try_stat(t)
|
2010-12-11 00:29:04 -08:00
|
|
|
st1 = os.fstat(f.fileno())
|
|
|
|
|
st2 = _try_stat(self.tmpname2)
|
2011-03-10 14:17:35 -08:00
|
|
|
if (after_t and
|
2016-11-27 10:31:19 -08:00
|
|
|
(not before_t or before_t.st_mtime != after_t.st_mtime) and
|
2010-12-21 04:19:50 -08:00
|
|
|
not stat.S_ISDIR(after_t.st_mode)):
|
2010-12-11 00:29:04 -08:00
|
|
|
err('%s modified %s directly!\n' % (self.argv[2], t))
|
|
|
|
|
err('...you should update $3 (a temp file) or stdout, not $1.\n')
|
2010-11-22 04:40:54 -08:00
|
|
|
rv = 206
|
2010-12-11 00:29:04 -08:00
|
|
|
elif st2 and st1.st_size > 0:
|
|
|
|
|
err('%s wrote to stdout *and* created $3.\n' % self.argv[2])
|
2010-11-22 04:40:54 -08:00
|
|
|
err('...you should write status messages to stderr, not stdout.\n')
|
|
|
|
|
rv = 207
|
2010-11-22 00:03:43 -08:00
|
|
|
if rv==0:
|
2010-12-11 00:29:04 -08:00
|
|
|
if st2:
|
2018-10-06 02:38:32 -04:00
|
|
|
try:
|
|
|
|
|
os.rename(self.tmpname2, t)
|
|
|
|
|
except OSError, e:
|
|
|
|
|
dnt = os.path.dirname(t)
|
|
|
|
|
if not os.path.exists(dnt):
|
|
|
|
|
err('%s: target dir %r does not exist!\n' % (t, dnt))
|
|
|
|
|
else:
|
|
|
|
|
err('%s: rename %s: %s\n' % (t, self.tmpname2, e))
|
|
|
|
|
raise
|
2010-12-11 00:29:04 -08:00
|
|
|
os.unlink(self.tmpname1)
|
|
|
|
|
elif st1.st_size > 0:
|
2010-12-11 21:10:57 -08:00
|
|
|
try:
|
|
|
|
|
os.rename(self.tmpname1, t)
|
|
|
|
|
except OSError, e:
|
|
|
|
|
if e.errno == errno.ENOENT:
|
|
|
|
|
unlink(t)
|
|
|
|
|
else:
|
2014-05-01 21:23:22 -04:00
|
|
|
err('%s: can\'t save stdout to %r: %s\n' %
|
|
|
|
|
(self.argv[2], t, e.strerror))
|
|
|
|
|
rv = 1000
|
2010-12-11 00:29:04 -08:00
|
|
|
if st2:
|
|
|
|
|
os.unlink(self.tmpname2)
|
|
|
|
|
else: # no output generated at all; that's ok
|
|
|
|
|
unlink(self.tmpname1)
|
|
|
|
|
unlink(t)
|
2010-12-10 02:58:13 -08:00
|
|
|
sf = self.sf
|
2010-12-11 02:17:51 -08:00
|
|
|
sf.refresh()
|
2010-12-10 22:42:33 -08:00
|
|
|
sf.is_generated = True
|
2010-12-11 02:17:51 -08:00
|
|
|
sf.is_override = False
|
|
|
|
|
if sf.is_checked() or sf.is_changed():
|
|
|
|
|
# it got checked during the run; someone ran redo-stamp.
|
|
|
|
|
# update_stamp would call set_changed(); we don't want that
|
|
|
|
|
sf.stamp = sf.read_stamp()
|
|
|
|
|
else:
|
|
|
|
|
sf.csum = None
|
|
|
|
|
sf.update_stamp()
|
|
|
|
|
sf.set_changed()
|
2010-11-22 00:03:43 -08:00
|
|
|
else:
|
2010-12-11 00:29:04 -08:00
|
|
|
unlink(self.tmpname1)
|
|
|
|
|
unlink(self.tmpname2)
|
2010-12-10 02:58:13 -08:00
|
|
|
sf = self.sf
|
2010-12-10 20:53:31 -08:00
|
|
|
sf.set_failed()
|
2010-12-11 22:59:55 -08:00
|
|
|
sf.zap_deps2()
|
|
|
|
|
sf.save()
|
2010-11-22 00:03:43 -08:00
|
|
|
f.close()
|
|
|
|
|
if rv != 0:
|
2014-05-01 21:23:22 -04:00
|
|
|
err('%s: exit code %r\n' % (_nice(t),rv))
|
2010-11-22 00:03:43 -08:00
|
|
|
else:
|
2010-12-11 22:59:55 -08:00
|
|
|
if vars.VERBOSE or vars.XTRACE or vars.DEBUG:
|
2010-11-22 00:03:43 -08:00
|
|
|
log('%s (done)\n\n' % _nice(t))
|
2010-11-22 04:40:54 -08:00
|
|
|
return rv
|
2010-11-21 23:33:11 -08:00
|
|
|
|
2010-11-22 00:03:43 -08:00
|
|
|
def _after2(self, rv):
|
2010-11-22 03:21:17 -08:00
|
|
|
try:
|
|
|
|
|
self.donefunc(self.t, rv)
|
|
|
|
|
assert(self.lock.owned)
|
|
|
|
|
finally:
|
|
|
|
|
self.lock.unlock()
|
2010-11-21 23:33:11 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(targets, shouldbuildfunc):
|
2010-11-19 07:21:09 -08:00
|
|
|
retcode = [0] # a list so that it can be reassigned from done()
|
|
|
|
|
if vars.SHUFFLE:
|
2010-12-09 04:54:40 -08:00
|
|
|
import random
|
2010-11-19 07:21:09 -08:00
|
|
|
random.shuffle(targets)
|
|
|
|
|
|
|
|
|
|
locked = []
|
|
|
|
|
|
|
|
|
|
def done(t, rv):
|
|
|
|
|
if rv:
|
|
|
|
|
retcode[0] = 1
|
|
|
|
|
|
2010-11-21 22:46:20 -08:00
|
|
|
# In the first cycle, we just build as much as we can without worrying
|
|
|
|
|
# about any lock contention. If someone else has it locked, we move on.
|
2010-12-14 02:19:08 -08:00
|
|
|
seen = {}
|
2011-02-21 03:55:18 -08:00
|
|
|
lock = None
|
2010-11-19 07:21:09 -08:00
|
|
|
for t in targets:
|
2018-11-03 03:36:13 -04:00
|
|
|
if not t:
|
|
|
|
|
err('cannot build the empty target ("").\n')
|
|
|
|
|
retcode[0] = 204
|
|
|
|
|
break
|
2018-10-06 04:36:24 -04:00
|
|
|
assert(state.is_flushed())
|
2010-12-14 02:19:08 -08:00
|
|
|
if t in seen:
|
|
|
|
|
continue
|
|
|
|
|
seen[t] = 1
|
2010-12-09 05:53:30 -08:00
|
|
|
if not jwack.has_token():
|
|
|
|
|
state.commit()
|
2010-11-19 07:21:09 -08:00
|
|
|
jwack.get_token(t)
|
2010-11-21 07:10:48 -08:00
|
|
|
if retcode[0] and not vars.KEEP_GOING:
|
|
|
|
|
break
|
2010-12-09 03:01:26 -08:00
|
|
|
if not state.check_sane():
|
|
|
|
|
err('.redo directory disappeared; cannot continue.\n')
|
2010-11-22 03:34:37 -08:00
|
|
|
retcode[0] = 205
|
|
|
|
|
break
|
2010-12-10 02:58:13 -08:00
|
|
|
f = state.File(name=t)
|
|
|
|
|
lock = state.Lock(f.id)
|
The second half of redo-stamp: out-of-order building.
If a depends on b depends on c, and c is dirty but b uses redo-stamp
checksums, then 'redo-ifchange a' is indeterminate: we won't know if we need
to run a.do unless we first build b, but the script that *normally* runs
'redo-ifchange b' is a.do, and we don't want to run that yet, because we
don't know for sure if b is dirty, and we shouldn't build a unless one of
its dependencies is dirty. Eek!
Luckily, there's a safe solution. If we *know* a is dirty - eg. because
a.do or one of its children has definitely changed - then we can just run
a.do immediately and there's no problem, even if b is indeterminate, because
we were going to run a.do anyhow.
If a's dependencies are *not* definitely dirty, and all we have is
indeterminate ones like b, then that means a's build process *hasn't
changed*, which means its tree of dependencies still includes b, which means
we can deduce that if we *did* run a.do, it would end up running b.do.
Since we know that anyhow, we can safely just run b.do, which will either
b.set_checked() or b.set_changed(). Once that's done, we can re-parse a's
dependencies and this time conclusively tell if it needs to be redone or
not. Even if it does, b is already up-to-date, so the 'redo-ifchange b'
line in a.do will be fast.
...now take all the above and do it recursively to handle nested
dependencies, etc, and you're done.
2010-12-11 04:40:05 -08:00
|
|
|
if vars.UNLOCKED:
|
|
|
|
|
lock.owned = True
|
|
|
|
|
else:
|
|
|
|
|
lock.trylock()
|
2010-11-19 07:21:09 -08:00
|
|
|
if not lock.owned:
|
2010-11-21 06:23:41 -08:00
|
|
|
if vars.DEBUG_LOCKS:
|
|
|
|
|
log('%s (locked...)\n' % _nice(t))
|
2010-12-10 02:58:13 -08:00
|
|
|
locked.append((f.id,t))
|
2010-11-19 07:21:09 -08:00
|
|
|
else:
|
2018-10-13 01:30:42 -04:00
|
|
|
# We had to create f before we had a lock, because we need f.id
|
|
|
|
|
# to make the lock. But someone may have updated the state
|
|
|
|
|
# between then and now.
|
|
|
|
|
# FIXME: separate obtaining the fid from creating the File.
|
|
|
|
|
# FIXME: maybe integrate locking into the File object?
|
|
|
|
|
f.refresh()
|
2010-12-10 02:58:13 -08:00
|
|
|
BuildJob(t, f, lock, shouldbuildfunc, done).start()
|
2018-10-06 04:36:24 -04:00
|
|
|
state.commit()
|
|
|
|
|
assert(state.is_flushed())
|
2015-01-15 16:13:35 -05:00
|
|
|
lock = None
|
2010-11-21 22:46:20 -08:00
|
|
|
|
2010-12-14 02:19:08 -08:00
|
|
|
del lock
|
|
|
|
|
|
2010-11-21 22:46:20 -08:00
|
|
|
# Now we've built all the "easy" ones. Go back and just wait on the
|
2010-12-10 04:31:22 -08:00
|
|
|
# remaining ones one by one. There's no reason to do it any more
|
|
|
|
|
# efficiently, because if these targets were previously locked, that
|
|
|
|
|
# means someone else was building them; thus, we probably won't need to
|
|
|
|
|
# do anything. The only exception is if we're invoked as redo instead
|
|
|
|
|
# of redo-ifchange; then we have to redo it even if someone else already
|
|
|
|
|
# did. But that should be rare.
|
2010-11-19 07:21:09 -08:00
|
|
|
while locked or jwack.running():
|
2010-12-09 05:53:30 -08:00
|
|
|
state.commit()
|
2010-11-19 07:21:09 -08:00
|
|
|
jwack.wait_all()
|
2010-11-21 23:33:11 -08:00
|
|
|
# at this point, we don't have any children holding any tokens, so
|
|
|
|
|
# it's okay to block below.
|
2010-11-21 07:10:48 -08:00
|
|
|
if retcode[0] and not vars.KEEP_GOING:
|
|
|
|
|
break
|
2010-11-19 07:21:09 -08:00
|
|
|
if locked:
|
2010-12-09 03:01:26 -08:00
|
|
|
if not state.check_sane():
|
|
|
|
|
err('.redo directory disappeared; cannot continue.\n')
|
2010-11-22 03:34:37 -08:00
|
|
|
retcode[0] = 205
|
|
|
|
|
break
|
2010-12-10 02:58:13 -08:00
|
|
|
fid,t = locked.pop(0)
|
|
|
|
|
lock = state.Lock(fid)
|
2018-10-29 07:21:12 +00:00
|
|
|
backoff = 0.01
|
2010-12-10 04:31:22 -08:00
|
|
|
lock.trylock()
|
2010-12-10 23:04:46 -08:00
|
|
|
while not lock.owned:
|
2018-10-29 07:21:12 +00:00
|
|
|
# Don't spin with 100% CPU while we fight for the lock.
|
|
|
|
|
import random
|
|
|
|
|
time.sleep(random.random() * min(backoff, 1.0))
|
|
|
|
|
backoff *= 2
|
2010-12-10 22:37:39 -08:00
|
|
|
if vars.DEBUG_LOCKS:
|
2010-12-10 04:31:22 -08:00
|
|
|
warn('%s (WAITING)\n' % _nice(t))
|
2016-11-27 23:35:28 -08:00
|
|
|
try:
|
Cyclic dependency checker: don't give up token in common case.
The way the code was written, we'd give up our token, detect a cyclic
dependency, and then try to get our token back before exiting. Even
with -j1, the temporary token release allowed any parent up the tree to
continue running jobs, so it would take an arbitrary amount of time
before we could exit (and report an error code to the parent).
There was no visible symptom of this except that, with -j1, t/355-deps-cyclic
would not finish until some of the later tests finished, which was
surprising.
To fix it, let's just check for a cyclic dependency first, then release
the token only once we're sure things are sane.
2018-11-13 06:54:31 -05:00
|
|
|
lock.check()
|
2016-11-27 23:35:28 -08:00
|
|
|
except state.CyclicDependencyError:
|
|
|
|
|
err('cyclic dependency while building %s\n' % _nice(t))
|
|
|
|
|
retcode[0] = 208
|
|
|
|
|
return retcode[0]
|
Cyclic dependency checker: don't give up token in common case.
The way the code was written, we'd give up our token, detect a cyclic
dependency, and then try to get our token back before exiting. Even
with -j1, the temporary token release allowed any parent up the tree to
continue running jobs, so it would take an arbitrary amount of time
before we could exit (and report an error code to the parent).
There was no visible symptom of this except that, with -j1, t/355-deps-cyclic
would not finish until some of the later tests finished, which was
surprising.
To fix it, let's just check for a cyclic dependency first, then release
the token only once we're sure things are sane.
2018-11-13 06:54:31 -05:00
|
|
|
# this sequence looks a little silly, but the idea is to
|
|
|
|
|
# give up our personal token while we wait for the lock to
|
|
|
|
|
# be released; but we should never run get_token() while
|
|
|
|
|
# holding a lock, or we could cause deadlocks.
|
|
|
|
|
jwack.release_mine()
|
|
|
|
|
lock.waitlock()
|
2010-12-10 23:04:46 -08:00
|
|
|
lock.unlock()
|
|
|
|
|
jwack.get_token(t)
|
|
|
|
|
lock.trylock()
|
2010-11-19 07:21:09 -08:00
|
|
|
assert(lock.owned)
|
2010-11-21 06:23:41 -08:00
|
|
|
if vars.DEBUG_LOCKS:
|
|
|
|
|
log('%s (...unlocked!)\n' % _nice(t))
|
2010-12-10 20:53:31 -08:00
|
|
|
if state.File(name=t).is_failed():
|
2010-11-21 03:34:32 -08:00
|
|
|
err('%s: failed in another thread\n' % _nice(t))
|
2010-11-19 07:21:09 -08:00
|
|
|
retcode[0] = 2
|
|
|
|
|
lock.unlock()
|
|
|
|
|
else:
|
2010-12-10 02:58:13 -08:00
|
|
|
BuildJob(t, state.File(id=fid), lock,
|
|
|
|
|
shouldbuildfunc, done).start()
|
2015-01-15 16:13:35 -05:00
|
|
|
lock = None
|
2010-12-09 02:44:33 -08:00
|
|
|
state.commit()
|
2010-11-19 07:21:09 -08:00
|
|
|
return retcode[0]
|