bug 1280220 - find_program should append an exe extension to absolute paths on Windows. r=glandium
authorTed Mielczarek <ted@mielczarek.org>
Thu, 16 Jun 2016 12:05:12 +0100
changeset 303019 9b1fcf3bae37b9b9da2338fc0f97a91a7f990e3a
parent 303018 cf1089793debba142296ec204fce66e60e8ae492
child 303020 4b555450a4d80e208e33342620d27294ee900d59
push id19811
push usercbook@mozilla.com
push dateWed, 29 Jun 2016 14:22:11 +0000
treeherderfx-team@eeb6862f960c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1280220
milestone50.0a1
bug 1280220 - find_program should append an exe extension to absolute paths on Windows. r=glandium MozReview-Commit-ID: 2gaLnL5x2zR
build/moz.configure/util.configure
python/mozbuild/mozbuild/test/configure/common.py
python/mozbuild/mozbuild/test/configure/test_checks_configure.py
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -65,19 +65,20 @@ def normsep(path):
 # 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')
 @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:
+        if is_absolute_or_relative(file):
+            return normsep(which(os.path.basename(file),
+                                 [os.path.dirname(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:
--- a/python/mozbuild/mozbuild/test/configure/common.py
+++ b/python/mozbuild/mozbuild/test/configure/common.py
@@ -3,32 +3,39 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import copy
 import errno
 import os
 import subprocess
+import sys
 import tempfile
 import unittest
 
 from mozbuild.configure import ConfigureSandbox
 from mozbuild.util import ReadOnlyNamespace
 from mozpack import path as mozpath
 
 from StringIO import StringIO
 from which import WhichError
 
 from buildconfig import (
     topobjdir,
     topsrcdir,
 )
 
 
+def ensure_exe_extension(path):
+    if sys.platform.startswith('win'):
+        return path + '.exe'
+    return path
+
+
 class ConfigureTestVFS(object):
     def __init__(self, paths):
         self._paths = set(mozpath.abspath(p) for p in paths)
 
     def exists(self, path):
         path = mozpath.abspath(path)
         if path in self._paths:
             return True
@@ -112,19 +119,20 @@ class ConfigureTestSandbox(ConfigureSand
 
         if what == 'os.environ':
             return self._environ
 
         return super(ConfigureTestSandbox, self)._get_one_import(what)
 
     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
+            c = mozpath.abspath(mozpath.join(parent, command))
+            for candidate in (c, ensure_exe_extension(c)):
+                if self.OS.path.exists(candidate):
+                    return candidate
         raise WhichError()
 
     def Popen(self, args, stdin=None, stdout=None, stderr=None, **kargs):
         try:
             program = self.which(args[0])
         except WhichError:
             raise OSError(errno.ENOENT, 'File not found')
 
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -1,30 +1,31 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 from StringIO import StringIO
 import os
+import sys
 import textwrap
 import unittest
 
 from mozunit import main
 
 from mozbuild.configure import (
     ConfigureError,
     ConfigureSandbox,
 )
 from mozbuild.util import exec_
 from mozpack import path as mozpath
 
 from buildconfig import topsrcdir
-from common import ConfigureTestSandbox
+from common import ConfigureTestSandbox, ensure_exe_extension
 
 
 class TestChecksConfigure(unittest.TestCase):
     def test_checking(self):
         out = StringIO()
         sandbox = ConfigureSandbox({}, stdout=out, stderr=out)
         base_dir = os.path.join(topsrcdir, 'build', 'moz.configure')
         sandbox.include_file(os.path.join(base_dir, 'checks.configure'))
@@ -118,20 +119,20 @@ class TestChecksConfigure(unittest.TestC
         out.truncate(0)
         foo('foo')
         self.assertEqual(out.getvalue(), 'checking for a thing... foo\n')
 
         out.truncate(0)
         foo(['foo', 'bar'])
         self.assertEqual(out.getvalue(), 'checking for a thing... foo bar\n')
 
-    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')
+    KNOWN_A = ensure_exe_extension(mozpath.abspath('/usr/bin/known-a'))
+    KNOWN_B = ensure_exe_extension(mozpath.abspath('/usr/local/bin/known-b'))
+    KNOWN_C = ensure_exe_extension(mozpath.abspath('/home/user/bin/known c'))
+    OTHER_A = ensure_exe_extension(mozpath.abspath('/lib/other/known-a'))
 
     def get_result(self, command='', args=[], environ={},
                    prog='/bin/configure', extra_paths=None,
                    includes=('util.configure', 'checks.configure')):
         config = {}
         out = StringIO()
         paths = {
             self.KNOWN_A: None,
@@ -202,16 +203,33 @@ class TestChecksConfigure(unittest.TestC
 
         config, out, status = self.get_result(
             'check_prog("FOO", ("unknown", "unknown-2", "unknown 3"), '
             'allow_missing=True)')
         self.assertEqual(status, 0)
         self.assertEqual(config, {'FOO': ':'})
         self.assertEqual(out, 'checking for foo... not found\n')
 
+    @unittest.skipIf(not sys.platform.startswith('win'), 'Windows-only test')
+    def test_check_prog_exe(self):
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))',
+            ['FOO=known-a.exe'])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': self.KNOWN_A})
+        self.assertEqual(out, 'checking for foo... %s\n' % self.KNOWN_A)
+
+        config, out, status = self.get_result(
+            'check_prog("FOO", ("unknown", "known-b", "known c"))',
+            ['FOO=%s' % os.path.splitext(self.KNOWN_A)[0]])
+        self.assertEqual(status, 0)
+        self.assertEqual(config, {'FOO': self.KNOWN_A})
+        self.assertEqual(out, 'checking for foo... %s\n' % self.KNOWN_A)
+
+
     def test_check_prog_with_args(self):
         config, out, status = self.get_result(
             'check_prog("FOO", ("unknown", "known-b", "known c"))',
             ['FOO=known-a'])
         self.assertEqual(status, 0)
         self.assertEqual(config, {'FOO': self.KNOWN_A})
         self.assertEqual(out, 'checking for foo... %s\n' % self.KNOWN_A)