2013-06-28 01:48:41 +00:00
|
|
|
import sys, os, errno, stat, signal
|
2010-11-19 07:21:09 -08:00
|
|
|
import vars, jwack, state
|
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-12-19 05:47:38 -08:00
|
|
|
def _default_do_files(filename):
|
2010-11-19 07:21:09 -08:00
|
|
|
l = filename.split('.')
|
|
|
|
|
for i in range(1,len(l)+1):
|
2010-12-19 05:47:38 -08:00
|
|
|
basename = join('.', l[:i])
|
|
|
|
|
ext = join('.', l[i:])
|
2010-11-19 07:21:09 -08:00
|
|
|
if ext: ext = '.' + ext
|
2010-12-19 05:47:38 -08:00
|
|
|
yield ("default%s.do" % ext), basename, ext
|
|
|
|
|
|
2010-11-19 07:21:09 -08:00
|
|
|
|
2018-10-04 20:20:53 -04:00
|
|
|
def possible_do_files(t):
|
2010-12-19 05:47:38 -08:00
|
|
|
dirname,filename = os.path.split(t)
|
2011-01-18 00:40:55 -08:00
|
|
|
yield (os.path.join(vars.BASE, dirname), "%s.do" % filename,
|
|
|
|
|
'', filename, '')
|
2010-12-19 05:47:38 -08:00
|
|
|
|
|
|
|
|
# It's important to try every possibility in a directory before resorting
|
|
|
|
|
# to a parent directory. Think about nested projects: I don't want
|
|
|
|
|
# ../../default.o.do to take precedence over ../default.do, because
|
|
|
|
|
# the former one might just be an artifact of someone embedding my project
|
|
|
|
|
# into theirs as a subdir. When they do, my rules should still be used
|
|
|
|
|
# for building my project in *all* cases.
|
|
|
|
|
t = os.path.normpath(os.path.join(vars.BASE, t))
|
|
|
|
|
dirname,filename = os.path.split(t)
|
|
|
|
|
dirbits = dirname.split('/')
|
|
|
|
|
for i in range(len(dirbits), -1, -1):
|
|
|
|
|
basedir = join('/', dirbits[:i])
|
|
|
|
|
subdir = join('/', dirbits[i:])
|
|
|
|
|
for dofile,basename,ext in _default_do_files(filename):
|
2011-01-18 00:40:55 -08:00
|
|
|
yield (basedir, dofile,
|
|
|
|
|
subdir, os.path.join(subdir, basename), ext)
|
2010-12-19 05:47:38 -08:00
|
|
|
|
2010-11-19 07:21:09 -08:00
|
|
|
|
2018-10-04 20:20:53 -04:00
|
|
|
def find_do_file(f):
|
|
|
|
|
for dodir,dofile,basedir,basename,ext in possible_do_files(f.name):
|
2010-12-19 05:47:38 -08:00
|
|
|
dopath = os.path.join(dodir, dofile)
|
|
|
|
|
debug2('%s: %s:%s ?\n' % (f.name, dodir, dofile))
|
|
|
|
|
if os.path.exists(dopath):
|
|
|
|
|
f.add_dep('m', dopath)
|
2011-01-18 00:40:55 -08:00
|
|
|
return dodir,dofile,basedir,basename,ext
|
2010-11-19 07:21:09 -08:00
|
|
|
else:
|
2010-12-19 05:47:38 -08:00
|
|
|
f.add_dep('c', dopath)
|
2011-01-18 00:40:55 -08:00
|
|
|
return None,None,None,None,None
|
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:
|
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
|
|
|
dirty = self.shouldbuildfunc(self.t)
|
|
|
|
|
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))
|
2010-12-10 22:42:33 -08:00
|
|
|
sf.set_override()
|
|
|
|
|
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.
|
|
|
|
|
# FIXME: always refuse to redo any file that was modified outside
|
|
|
|
|
# of redo? That would make it easy for someone to override a
|
|
|
|
|
# file temporarily, and could be undone by deleting the file.
|
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-04 20:20:53 -04:00
|
|
|
(dodir, dofile, basedir, basename, ext) = 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 + ' '
|
|
|
|
|
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:
|
|
|
|
|
raise
|
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:
|
|
|
|
|
err('%s: exit code %d\n' % (_nice(t),rv))
|
|
|
|
|
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-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:
|
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())
|
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)
|
2010-12-10 04:31:22 -08:00
|
|
|
lock.trylock()
|
2010-12-10 23:04:46 -08:00
|
|
|
while not lock.owned:
|
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))
|
2010-12-10 23:04:46 -08: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()
|
2010-12-10 04:31:22 -08:00
|
|
|
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()
|
2010-12-09 02:44:33 -08:00
|
|
|
state.commit()
|
2010-11-19 07:21:09 -08:00
|
|
|
return retcode[0]
|