Bug 1267454 - Add a parameter to find_program and check_prog to allow searching the given paths instead of $PATH. r=glandium

MozReview-Commit-ID: F3lke9Q5rRR
This commit is contained in:
Chris Manchester 2016-05-12 11:55:57 -07:00
parent d671429ba2
commit 463051b415
4 changed files with 81 additions and 13 deletions

View File

@ -81,6 +81,10 @@ def checking(what, callback=None):
# This argument allows to use a different kind of option (possibly using a
# configure flag), or doing some pre-processing with a @depends function.
# - `allow_missing` indicates whether not finding the program is an error.
# - `paths` is a list of paths or @depends function returning a list of paths
# that will cause the given path(s) to be searched rather than $PATH. Input
# paths may either be individual paths or delimited by os.pathsep, to allow
# passing $PATH (for example) as an element.
#
# The simplest form is:
# check_prog('PROG', ('a', 'b'))
@ -90,7 +94,8 @@ def checking(what, callback=None):
@template
@imports(_from='mozbuild.shellutil', _import='quote')
@imports(_from='mozbuild.configure', _import='DependsFunction')
def check_prog(var, progs, what=None, input=None, allow_missing=False):
def check_prog(var, progs, what=None, input=None, allow_missing=False,
paths=None):
if input:
# Wrap input with type checking and normalization.
@depends(input)
@ -109,13 +114,15 @@ def check_prog(var, progs, what=None, input=None, allow_missing=False):
input = var
what = what or var.lower()
# Trick to make a @depends function out of an immediate value.
if not isinstance(progs, DependsFunction):
# Trick to make a @depends function out of an immediate value.
progs = depends('--help')(lambda h: progs)
if not isinstance(paths, DependsFunction):
paths = depends('--help')(lambda h: paths)
@depends_if(input, progs)
@depends_if(input, progs, paths)
@checking('for %s' % what, lambda x: quote(x) if x else 'not found')
def check(value, progs):
def check(value, progs, paths):
if progs is None:
progs = ()
@ -124,7 +131,7 @@ def check_prog(var, progs, what=None, input=None, allow_missing=False):
for prog in value or progs:
log.debug('%s: Trying %s', var.lower(), quote(prog))
result = find_program(prog)
result = find_program(prog, paths)
if result:
return result

View File

@ -30,14 +30,25 @@ def is_absolute_or_relative(path):
def normsep(path):
return mozpath.normsep(path)
# Locates the given program using which, or returns the given path if it
# exists.
# The `paths` parameter may be passed to search the given paths instead of
# $PATH.
@imports(_from='which', _import='which')
@imports(_from='which', _import='WhichError')
def find_program(file):
@imports('itertools')
@imports(_from='os', _import='pathsep')
def find_program(file, paths=None):
if is_absolute_or_relative(file):
return os.path.abspath(file) if os.path.isfile(file) else None
try:
return normsep(which(file))
if paths:
if not isinstance(paths, (list, tuple)):
die("Paths provided to find_program must be a list of strings, "
"not %r", paths)
paths = list(itertools.chain(
*(p.split(pathsep) for p in paths if p)))
return normsep(which(file, path=paths))
except WhichError:
return None

View File

@ -109,11 +109,11 @@ class ConfigureTestSandbox(ConfigureSandbox):
return super(ConfigureTestSandbox, self)._get_one_import(what)
def which(self, command):
for parent in self._search_path:
path = mozpath.join(parent, command)
if self.OS.path.exists(path):
return path
def which(self, command, path=None):
for parent in (path or self._search_path):
candidate = mozpath.join(parent, command)
if self.OS.path.exists(candidate):
return candidate
raise WhichError()
def Popen(self, args, stdin=None, stdout=None, stderr=None, **kargs):

View File

@ -126,6 +126,7 @@ class TestChecksConfigure(unittest.TestCase):
KNOWN_A = mozpath.abspath('/usr/bin/known-a')
KNOWN_B = mozpath.abspath('/usr/local/bin/known-b')
KNOWN_C = mozpath.abspath('/home/user/bin/known c')
OTHER_A = mozpath.abspath('/lib/other/known-a')
def get_result(self, command='', args=[], environ={},
prog='/bin/configure'):
@ -138,6 +139,7 @@ class TestChecksConfigure(unittest.TestCase):
}
environ = dict(environ)
environ['PATH'] = os.pathsep.join(os.path.dirname(p) for p in paths)
paths[self.OTHER_A] = None
sandbox = ConfigureTestSandbox(paths, config, environ, [prog] + args,
out, out)
base_dir = os.path.join(topsrcdir, 'build', 'moz.configure')
@ -396,6 +398,54 @@ class TestChecksConfigure(unittest.TestCase):
'input must resolve to a tuple or a list with a '
'single element, or a string')
def test_check_prog_with_path(self):
config, out, status = self.get_result('check_prog("A", ("known-a",), paths=["/some/path"])')
self.assertEqual(status, 1)
self.assertEqual(config, {})
self.assertEqual(out, textwrap.dedent('''\
checking for a... not found
DEBUG: a: Trying known-a
ERROR: Cannot find a
'''))
config, out, status = self.get_result('check_prog("A", ("known-a",), paths=["%s"])' %
os.path.dirname(self.OTHER_A))
self.assertEqual(status, 0)
self.assertEqual(config, {'A': self.OTHER_A})
self.assertEqual(out, textwrap.dedent('''\
checking for a... %s
''' % self.OTHER_A))
dirs = map(mozpath.dirname, (self.OTHER_A, self.KNOWN_A))
config, out, status = self.get_result(textwrap.dedent('''\
check_prog("A", ("known-a",), paths=["%s"])
''' % os.pathsep.join(dirs)))
self.assertEqual(status, 0)
self.assertEqual(config, {'A': self.OTHER_A})
self.assertEqual(out, textwrap.dedent('''\
checking for a... %s
''' % self.OTHER_A))
dirs = map(mozpath.dirname, (self.KNOWN_A, self.KNOWN_B))
config, out, status = self.get_result(textwrap.dedent('''\
check_prog("A", ("known-a",), paths=["%s", "%s"])
''' % (os.pathsep.join(dirs), self.OTHER_A)))
self.assertEqual(status, 0)
self.assertEqual(config, {'A': self.KNOWN_A})
self.assertEqual(out, textwrap.dedent('''\
checking for a... %s
''' % self.KNOWN_A))
config, out, status = self.get_result('check_prog("A", ("known-a",), paths="%s")' %
os.path.dirname(self.OTHER_A))
self.assertEqual(status, 1)
self.assertEqual(config, {})
self.assertEqual(out, textwrap.dedent('''\
checking for a...
DEBUG: a: Trying known-a
ERROR: Paths provided to find_program must be a list of strings, not %r
''' % mozpath.dirname(self.OTHER_A)))
if __name__ == '__main__':
main()