Extract .redo dir state management stuff into its own file.
In preparation for changing the on-disk format eventually, as well as making the main code more readable.
This commit is contained in:
parent
81356931a4
commit
dc3efb69cc
5 changed files with 158 additions and 97 deletions
126
state.py
Normal file
126
state.py
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
import sys, os, errno
|
||||
import vars
|
||||
from helpers import unlink, relpath, debug2
|
||||
|
||||
|
||||
def _sname(typ, t, fromdir=None):
|
||||
# FIXME: t.replace(...) is non-reversible and non-unique here!
|
||||
if fromdir:
|
||||
t = os.path.join(fromdir, t)
|
||||
tnew = relpath(t, vars.BASE)
|
||||
v = vars.BASE + ('/.redo/%s^%s' % (typ, tnew.replace('/', '^')))
|
||||
debug2('sname: (%r) %r -> %r\n' % (os.getcwd(), t, tnew))
|
||||
return v
|
||||
|
||||
|
||||
def add_dep(t, mode, dep):
|
||||
debug2('add-dep(%r)\n' % t)
|
||||
open(_sname('dep', t), 'a').write('%s %s\n'
|
||||
% (mode, relpath(dep, vars.BASE)))
|
||||
|
||||
|
||||
def deps(t, fromdir=None):
|
||||
for line in open(_sname('dep', t, fromdir)).readlines():
|
||||
assert(line[0] in ('c','m'))
|
||||
assert(line[1] == ' ')
|
||||
assert(line[-1] == '\n')
|
||||
mode = line[0]
|
||||
name = line[2:-1]
|
||||
yield mode,name
|
||||
|
||||
|
||||
def _stampname(t, fromdir=None):
|
||||
return _sname('stamp', t, fromdir)
|
||||
|
||||
|
||||
def stamp(t):
|
||||
stampfile = _stampname(t)
|
||||
newstampfile = _sname('stamp' + str(os.getpid()), t)
|
||||
depfile = _sname('dep', t)
|
||||
if not os.path.exists(vars.BASE + '/.redo'):
|
||||
# .redo might not exist in a 'make clean' target
|
||||
return
|
||||
open(newstampfile, 'w').close()
|
||||
try:
|
||||
mtime = os.stat(t).st_mtime
|
||||
except OSError:
|
||||
mtime = 0
|
||||
os.utime(newstampfile, (mtime, mtime))
|
||||
os.rename(newstampfile, stampfile)
|
||||
open(depfile, 'a').close()
|
||||
|
||||
|
||||
def unstamp(t, fromdir=None):
|
||||
unlink(_stampname(t, fromdir))
|
||||
|
||||
|
||||
def stamped(t, fromdir=None):
|
||||
try:
|
||||
stamptime = os.stat(_stampname(t, fromdir)).st_mtime
|
||||
except OSError, e:
|
||||
if e.errno == errno.ENOENT:
|
||||
return None
|
||||
else:
|
||||
raise
|
||||
return stamptime
|
||||
|
||||
|
||||
def is_generated(t):
|
||||
return os.path.exists(_sname('gen', t))
|
||||
|
||||
|
||||
def start(t):
|
||||
open(_sname('dep', t), 'w').close()
|
||||
open(_sname('gen', t), 'w').close() # it's definitely a generated file
|
||||
|
||||
|
||||
class Lock:
|
||||
def __init__(self, t):
|
||||
self.lockname = _sname('lock', t)
|
||||
self.owned = False
|
||||
|
||||
def __del__(self):
|
||||
if self.owned:
|
||||
self.unlock()
|
||||
|
||||
def lock(self):
|
||||
try:
|
||||
os.mkfifo(self.lockname, 0600)
|
||||
self.owned = True
|
||||
except OSError, e:
|
||||
if e.errno == errno.EEXIST:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def unlock(self):
|
||||
if not self.owned:
|
||||
raise Exception("can't unlock %r - we don't own it"
|
||||
% self.lockname)
|
||||
fd = None
|
||||
try:
|
||||
fd = os.open(self.lockname, os.O_WRONLY|os.O_NONBLOCK)
|
||||
except OSError, e:
|
||||
if e.errno == errno.ENXIO: # no readers open; that's ok
|
||||
pass
|
||||
elif e.errno == errno.ENOENT: # 'make clean' might do this
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
unlink(self.lockname) # make sure no new readers can connect
|
||||
if fd != None: os.close(fd) # now unlock any existing readers
|
||||
self.owned = False
|
||||
|
||||
def wait(self):
|
||||
if self.owned:
|
||||
raise Exception("can't wait on %r - we own it" % self.lockname)
|
||||
try:
|
||||
# open() will finish only when a writer exists and does close()
|
||||
os.close(os.open(self.lockname, os.O_RDONLY))
|
||||
#sys.stderr.write('lock %r waited ok\n' % self.lockname)
|
||||
except OSError, e:
|
||||
if e.errno == errno.ENOENT:
|
||||
#sys.stderr.write('lock %r missing\n' % self.lockname)
|
||||
pass # it's not even unlocked or was unlocked earlier
|
||||
else:
|
||||
raise
|
||||
Loading…
Add table
Add a link
Reference in a new issue