Search parent directories for default*.do.
Previously, we would only search for default*.do in the same directory in the target; now we search parent directories as well. Let's say we're in a/b/ and trying to build foo.o. If we find ../../default.o.do, then we'll run cd ../..; sh default.o.do a/b/foo .o $TMPNAME In other words, we still always chdir to the same directory as the .do file. But now $1 might have a path in it, not just a basename.
This commit is contained in:
parent
e207b723b4
commit
0dcc3f61b6
16 changed files with 117 additions and 32 deletions
63
builder.py
63
builder.py
|
|
@ -1,32 +1,48 @@
|
||||||
import sys, os, errno, stat
|
import sys, os, errno, stat
|
||||||
import vars, jwack, state
|
import vars, jwack, state
|
||||||
from helpers import unlink, close_on_exec
|
from helpers import unlink, close_on_exec, join
|
||||||
from log import log, log_, debug, debug2, err, warn
|
from log import log, log_, debug, debug2, err, warn
|
||||||
|
|
||||||
|
|
||||||
def _possible_do_files(t):
|
def _default_do_files(filename):
|
||||||
t = os.path.join(vars.BASE, t)
|
|
||||||
yield "%s.do" % t, t, ''
|
|
||||||
dirname,filename = os.path.split(t)
|
|
||||||
l = filename.split('.')
|
l = filename.split('.')
|
||||||
l[0] = os.path.join(dirname, l[0])
|
|
||||||
for i in range(1,len(l)+1):
|
for i in range(1,len(l)+1):
|
||||||
basename = '.'.join(l[:i])
|
basename = join('.', l[:i])
|
||||||
ext = '.'.join(l[i:])
|
ext = join('.', l[i:])
|
||||||
if ext: ext = '.' + ext
|
if ext: ext = '.' + ext
|
||||||
yield (os.path.join(dirname, "default%s.do" % ext),
|
yield ("default%s.do" % ext), basename, ext
|
||||||
os.path.join(dirname, basename), ext)
|
|
||||||
|
|
||||||
|
def _possible_do_files(t):
|
||||||
|
dirname,filename = os.path.split(t)
|
||||||
|
yield os.path.join(vars.BASE, dirname), "%s.do" % filename, filename, ''
|
||||||
|
|
||||||
|
# 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):
|
||||||
|
yield basedir, dofile, os.path.join(subdir, basename), ext
|
||||||
|
|
||||||
|
|
||||||
def _find_do_file(f):
|
def _find_do_file(f):
|
||||||
for dofile,basename,ext in _possible_do_files(f.name):
|
for dodir,dofile,basename,ext in _possible_do_files(f.name):
|
||||||
debug2('%s: %s ?\n' % (f.name, dofile))
|
dopath = os.path.join(dodir, dofile)
|
||||||
if os.path.exists(dofile):
|
debug2('%s: %s:%s ?\n' % (f.name, dodir, dofile))
|
||||||
f.add_dep('m', dofile)
|
if os.path.exists(dopath):
|
||||||
return dofile,basename,ext
|
f.add_dep('m', dopath)
|
||||||
|
return dodir,dofile,basename,ext
|
||||||
else:
|
else:
|
||||||
f.add_dep('c', dofile)
|
f.add_dep('c', dopath)
|
||||||
return None,None,None
|
return None,None,None,None
|
||||||
|
|
||||||
|
|
||||||
def _nice(t):
|
def _nice(t):
|
||||||
|
|
@ -104,7 +120,7 @@ class BuildJob:
|
||||||
sf.save()
|
sf.save()
|
||||||
return self._after2(0)
|
return self._after2(0)
|
||||||
sf.zap_deps1()
|
sf.zap_deps1()
|
||||||
(dofile, basename, ext) = _find_do_file(sf)
|
(dodir, dofile, basename, ext) = _find_do_file(sf)
|
||||||
if not dofile:
|
if not dofile:
|
||||||
if os.path.exists(t):
|
if os.path.exists(t):
|
||||||
sf.set_static()
|
sf.set_static()
|
||||||
|
|
@ -120,8 +136,8 @@ class BuildJob:
|
||||||
self.f = os.fdopen(ffd, 'w+')
|
self.f = os.fdopen(ffd, 'w+')
|
||||||
# this will run in the dofile's directory, so use only basenames here
|
# this will run in the dofile's directory, so use only basenames here
|
||||||
argv = ['sh', '-e',
|
argv = ['sh', '-e',
|
||||||
os.path.basename(dofile),
|
dofile,
|
||||||
os.path.basename(basename), # target name (extension removed)
|
basename, # target name (no extension)
|
||||||
ext, # extension (if any), including leading dot
|
ext, # extension (if any), including leading dot
|
||||||
os.path.basename(self.tmpname2) # randomized output file name
|
os.path.basename(self.tmpname2) # randomized output file name
|
||||||
]
|
]
|
||||||
|
|
@ -129,6 +145,9 @@ class BuildJob:
|
||||||
if vars.XTRACE: argv[1] += 'x'
|
if vars.XTRACE: argv[1] += 'x'
|
||||||
if vars.VERBOSE or vars.XTRACE: log_('\n')
|
if vars.VERBOSE or vars.XTRACE: log_('\n')
|
||||||
log('%s\n' % _nice(t))
|
log('%s\n' % _nice(t))
|
||||||
|
self.dodir = dodir
|
||||||
|
self.basename = basename
|
||||||
|
self.ext = ext
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
sf.is_generated = True
|
sf.is_generated = True
|
||||||
sf.save()
|
sf.save()
|
||||||
|
|
@ -168,10 +187,10 @@ class BuildJob:
|
||||||
# redo-ifchange, and it might have done it from a different directory
|
# redo-ifchange, and it might have done it from a different directory
|
||||||
# than we started it in. So os.getcwd() might be != REDO_PWD right
|
# than we started it in. So os.getcwd() might be != REDO_PWD right
|
||||||
# now.
|
# now.
|
||||||
dn = os.path.dirname(self.t)
|
dn = self.dodir
|
||||||
newp = os.path.realpath(dn)
|
newp = os.path.realpath(dn)
|
||||||
os.environ['REDO_PWD'] = state.relpath(newp, vars.STARTDIR)
|
os.environ['REDO_PWD'] = state.relpath(newp, vars.STARTDIR)
|
||||||
os.environ['REDO_TARGET'] = os.path.basename(self.t)
|
os.environ['REDO_TARGET'] = self.basename + self.ext
|
||||||
os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
|
os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
|
||||||
if dn:
|
if dn:
|
||||||
os.chdir(dn)
|
os.chdir(dn)
|
||||||
|
|
|
||||||
2
state.py
2
state.py
|
|
@ -261,7 +261,7 @@ class File(object):
|
||||||
|
|
||||||
def add_dep(self, mode, dep):
|
def add_dep(self, mode, dep):
|
||||||
src = File(name=dep)
|
src = File(name=dep)
|
||||||
debug2('add-dep: %r < %s %r\n' % (self.name, mode, src.name))
|
debug3('add-dep: "%s" < %s "%s"\n' % (self.name, mode, src.name))
|
||||||
assert(self.id != src.id)
|
assert(self.id != src.id)
|
||||||
_write("insert or replace into Deps "
|
_write("insert or replace into Deps "
|
||||||
" (target, mode, source, delete_me) values (?,?,?,?)",
|
" (target, mode, source, delete_me) values (?,?,?,?)",
|
||||||
|
|
|
||||||
6
t/.gitignore
vendored
6
t/.gitignore
vendored
|
|
@ -1,9 +1,3 @@
|
||||||
c
|
|
||||||
c.c
|
|
||||||
c.c.c
|
|
||||||
c.c.c.b
|
|
||||||
c.c.c.b.b
|
|
||||||
d
|
|
||||||
test.args
|
test.args
|
||||||
test2.args
|
test2.args
|
||||||
/passfail
|
/passfail
|
||||||
|
|
|
||||||
4
t/all.do
4
t/all.do
|
|
@ -1,2 +1,2 @@
|
||||||
redo-ifchange hello yellow bellow defaults-flat/all example/all
|
redo-ifchange hello yellow bellow defaults-flat/all defaults-nested/all \
|
||||||
|
example/all
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
redo example/clean curse/clean deps/clean "space dir/clean" stamp/clean \
|
redo example/clean curse/clean deps/clean "space dir/clean" stamp/clean \
|
||||||
defaults-flat/clean
|
defaults-flat/clean defaults-nested/clean
|
||||||
rm -f mode1 makedir.log chdir1 deltest2 \
|
rm -f mode1 makedir.log chdir1 deltest2 \
|
||||||
hello [by]ellow *.o *~ .*~ *.log CC LD passfail silence silence.do \
|
hello [by]ellow *.o *~ .*~ *.log CC LD passfail silence silence.do \
|
||||||
touch1 touch1.do always1 ifcreate[12].dep ifcreate[12]
|
touch1 touch1.do always1 ifcreate[12].dep ifcreate[12]
|
||||||
|
|
|
||||||
6
t/defaults-flat/.gitignore
vendored
Normal file
6
t/defaults-flat/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
c
|
||||||
|
c.c
|
||||||
|
c.c.c
|
||||||
|
c.c.c.b
|
||||||
|
c.c.c.b.b
|
||||||
|
d
|
||||||
15
t/defaults-nested/.gitignore
vendored
Normal file
15
t/defaults-nested/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
/a/b/file
|
||||||
|
/a/b/file.x.y.z
|
||||||
|
/a/b/file.y.z
|
||||||
|
/a/b/file.z
|
||||||
|
/a/d/file
|
||||||
|
/a/d/file.x.y.z
|
||||||
|
/a/d/file.y.z
|
||||||
|
/a/d/file.z
|
||||||
|
/a/file
|
||||||
|
/a/file.x.y.z
|
||||||
|
/a/file.y.z
|
||||||
|
/a/file.z
|
||||||
|
/file.x.y.z
|
||||||
|
/file.z
|
||||||
|
/file
|
||||||
1
t/defaults-nested/a/b/default.y.z.do
Normal file
1
t/defaults-nested/a/b/default.y.z.do
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
echo default.y.z $1 $2
|
||||||
1
t/defaults-nested/a/b/file.x.y.z.do
Normal file
1
t/defaults-nested/a/b/file.x.y.z.do
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
echo file $1 $2
|
||||||
1
t/defaults-nested/a/d/default.do
Normal file
1
t/defaults-nested/a/d/default.do
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
echo default $1 $2
|
||||||
2
t/defaults-nested/a/default.x.y.z.do
Normal file
2
t/defaults-nested/a/default.x.y.z.do
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
echo default.x.y.z $1 $2
|
||||||
|
|
||||||
1
t/defaults-nested/a/default.z.do
Normal file
1
t/defaults-nested/a/default.z.do
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
echo default.z $1 $2
|
||||||
1
t/defaults-nested/all.do
Normal file
1
t/defaults-nested/all.do
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
redo test
|
||||||
6
t/defaults-nested/clean.do
Normal file
6
t/defaults-nested/clean.do
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
exec >&2
|
||||||
|
find -name '*~' -exec rm -f {} \;
|
||||||
|
rm -f a/b/file a/b/file.x.y.z a/b/file.y.z a/b/file.z \
|
||||||
|
a/d/file a/d/file.x.y.z a/d/file.y.z a/d/file.z \
|
||||||
|
a/file a/file.x.y.z a/file.y.z a/file.z \
|
||||||
|
file.x.y.z file.z file
|
||||||
2
t/defaults-nested/default.do
Normal file
2
t/defaults-nested/default.do
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
echo root $1 $2
|
||||||
|
|
||||||
36
t/defaults-nested/test.do
Normal file
36
t/defaults-nested/test.do
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
exec >&2
|
||||||
|
redo-ifchange \
|
||||||
|
file.x.y.z file.z file \
|
||||||
|
a/b/file.x.y.z a/b/file.y.z a/b/file.z a/b/file \
|
||||||
|
a/d/file.x.y.z a/d/file.y.z a/d/file.z a/d/file
|
||||||
|
|
||||||
|
(cd a/b && redo-ifchange ../file.x.y.z ../file.y.z ../file.z ../file)
|
||||||
|
|
||||||
|
check()
|
||||||
|
{
|
||||||
|
if [ "$(cat $1)" != "$2" ]; then
|
||||||
|
echo "$1 should contain '$2'"
|
||||||
|
echo " ...got '$(cat $1)'"
|
||||||
|
exit 44
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check file.x.y.z "root file.x.y.z"
|
||||||
|
check file.z "root file.z"
|
||||||
|
check file "root file"
|
||||||
|
|
||||||
|
check a/file.x.y.z "default.x.y.z file .x.y.z"
|
||||||
|
check a/file.y.z "default.z file.y .z"
|
||||||
|
check a/file.z "default.z file .z"
|
||||||
|
check a/file "root a/file"
|
||||||
|
|
||||||
|
check a/b/file.x.y.z "file file.x.y.z"
|
||||||
|
check a/b/file.y.z "default.y.z file .y.z"
|
||||||
|
check a/b/file.z "default.z b/file .z"
|
||||||
|
check a/b/file "root a/b/file"
|
||||||
|
|
||||||
|
check a/d/file.x.y.z "default file.x.y.z"
|
||||||
|
check a/d/file.y.z "default file.y.z"
|
||||||
|
check a/d/file.z "default file.z"
|
||||||
|
check a/d/file "default file"
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue