Basic locking infrastructure.
So that more than one redo doesn't try to build the same thing at the same time. Kind of dumb, though, since it currently wipes out all the locks at the toplevel, so running more than one at a time won't give accurate results, but the -j option doesn't do anything yet.
This commit is contained in:
parent
534dd9813f
commit
ae3b6ee363
2 changed files with 44 additions and 5 deletions
47
redo.py
47
redo.py
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/python
|
||||
import sys, os, subprocess
|
||||
import sys, os, subprocess, glob, time
|
||||
import options
|
||||
|
||||
optspec = """
|
||||
|
|
@ -30,12 +30,21 @@ if not os.environ.get('REDO_BASE', ''):
|
|||
os.environ['REDO_BASE'] = base
|
||||
os.environ['REDO_STARTDIR'] = os.getcwd()
|
||||
|
||||
# FIXME: just wiping out all the locks is kind of cheating. But we
|
||||
# only do this from the toplevel redo process, so unless the user
|
||||
# deliberately starts more than one redo on the same repository, it's
|
||||
# sort of ok.
|
||||
for f in glob.glob('%s/lock.*' % base):
|
||||
unlink(f)
|
||||
|
||||
import vars
|
||||
from helpers import *
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
pass
|
||||
class BuildLocked(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def find_do_file(t):
|
||||
|
|
@ -71,7 +80,7 @@ def _preexec(t):
|
|||
os.chdir(dn)
|
||||
|
||||
|
||||
def build(t):
|
||||
def _build(t):
|
||||
unlink(sname('dep', t))
|
||||
open(sname('dep', t), 'w').close()
|
||||
dofile = find_do_file(t)
|
||||
|
|
@ -110,6 +119,23 @@ def build(t):
|
|||
raise BuildError('%s: exit code %d' % (t,rv))
|
||||
|
||||
|
||||
def build(t):
|
||||
lockname = sname('lock', t)
|
||||
try:
|
||||
fd = os.open(lockname, os.O_CREAT|os.O_EXCL)
|
||||
except OSError, e:
|
||||
if e.errno == errno.EEXIST:
|
||||
log('%s (locked...)\n' % relpath(t, vars.STARTDIR))
|
||||
raise BuildLocked(t)
|
||||
else:
|
||||
raise
|
||||
os.close(fd)
|
||||
try:
|
||||
return _build(t)
|
||||
finally:
|
||||
unlink(lockname)
|
||||
|
||||
|
||||
if not vars.DEPTH:
|
||||
# toplevel call to redo
|
||||
exenames = [os.path.abspath(sys.argv[0]), os.path.realpath(sys.argv[0])]
|
||||
|
|
@ -120,18 +146,31 @@ if not vars.DEPTH:
|
|||
|
||||
try:
|
||||
retcode = 0
|
||||
startdir = os.getcwd()
|
||||
locked = {}
|
||||
for t in targets:
|
||||
if os.path.exists('%s/all.do' % t):
|
||||
# t is a directory, but it has a default target
|
||||
t = '%s/all' % t
|
||||
mkdirp('%s/.redo' % vars.BASE)
|
||||
os.chdir(startdir)
|
||||
try:
|
||||
build(t)
|
||||
except BuildError, e:
|
||||
err('%s\n' % e)
|
||||
retcode = 1
|
||||
except BuildLocked, e:
|
||||
locked[t] = 1
|
||||
while locked:
|
||||
for l in locked.keys():
|
||||
lockname = sname('lock', t)
|
||||
stampname = sname('stamp', t)
|
||||
if not os.path.exists(lockname):
|
||||
relp = relpath(t, vars.STARTDIR)
|
||||
log('%s (...unlocked!)\n' % relp)
|
||||
if not os.path.exists(stampname):
|
||||
err('%s: failed in another thread\n' % relp)
|
||||
retcode = 2
|
||||
del locked[l]
|
||||
time.sleep(0.2)
|
||||
sys.exit(retcode)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(200)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue