builder.py: atomically replace the log for a given target.
Previously we were truncating the log if it existed. This would cause redo-log to produce invalid output if you had the following (admittedly rare) sequence in a single session: - start building X - redo-log starts showing the log for X - finish building X - redo-log has not finished showing the log for X yet - start building X again for some reason - redo-log sees a truncated logfile. Now, redo-log can finish reading the original file (which no longer has a filename since it was overwritten) while the new file is being created.
This commit is contained in:
parent
8a97b0cb2c
commit
63230a1ae3
2 changed files with 14 additions and 4 deletions
|
|
@ -1,3 +1,3 @@
|
||||||
exec >&2
|
exec >&2
|
||||||
redo-ifchange ../redo/version/all ../redo/py list redo-sh
|
redo-ifchange ../redo/version/all ../redo/py ../redo/sh list
|
||||||
xargs redo-ifchange <list
|
xargs redo-ifchange <list
|
||||||
|
|
|
||||||
|
|
@ -229,10 +229,20 @@ class _BuildJob(object):
|
||||||
firstline = open(os.path.join(dodir, dofile)).readline().strip()
|
firstline = open(os.path.join(dodir, dofile)).readline().strip()
|
||||||
if firstline.startswith('#!/'):
|
if firstline.startswith('#!/'):
|
||||||
argv[0:2] = firstline[2:].split(' ')
|
argv[0:2] = firstline[2:].split(' ')
|
||||||
# make sure to create the logfile *before* writing the meta() about it.
|
# make sure to create the logfile *before* writing the meta() about
|
||||||
# that way redo-log won't trace into an obsolete logfile.
|
# it. that way redo-log won't trace into an obsolete logfile.
|
||||||
|
#
|
||||||
|
# We open a temp file and atomically rename it into place here.
|
||||||
|
# This guarantees that redo-log will never experience a file that
|
||||||
|
# gets truncated halfway through reading (eg. if we build the same
|
||||||
|
# target more than once in a run). Similarly, we don't want to
|
||||||
|
# actually unlink() the file in case redo-log is about to start
|
||||||
|
# reading a previous instance created during this session. It
|
||||||
|
# should always see either the old or new instance.
|
||||||
if env.v.LOG:
|
if env.v.LOG:
|
||||||
open(state.logname(self.sf.id), 'w')
|
lfd, lfname = tempfile.mkstemp(prefix='redo.', suffix='.log.tmp')
|
||||||
|
os.fdopen(lfd, 'w')
|
||||||
|
os.rename(lfname, state.logname(self.sf.id))
|
||||||
dof = state.File(name=os.path.join(dodir, dofile))
|
dof = state.File(name=os.path.join(dodir, dofile))
|
||||||
dof.set_static()
|
dof.set_static()
|
||||||
dof.save()
|
dof.save()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue