Merge lp:~doxxx/bzr/bug939605-2.5 into lp:bzr/2.5

Proposed by Gordon Tyler
Status: Merged
Approved by: Martin Packman
Approved revision: no longer in the source branch.
Merged at revision: 6485
Proposed branch: lp:~doxxx/bzr/bug939605-2.5
Merge into: lp:bzr/2.5
Diff against target: 155 lines (+53/-21)
5 files modified
bzrlib/mergetools.py (+16/-7)
bzrlib/osutils.py (+12/-9)
bzrlib/tests/test_mergetools.py (+14/-5)
bzrlib/tests/test_osutils.py (+8/-0)
doc/en/release-notes/bzr-2.5.txt (+3/-0)
To merge this branch: bzr merge lp:~doxxx/bzr/bug939605-2.5
Reviewer Review Type Date Requested Status
Martin Packman (community) Approve
Review via email: mp+94909@code.launchpad.net

Commit message

Locate applications using the windows registry in addition to the PATH envvar

Description of the change

Backport of fix for bug 939605 to bzr 2.5 series.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

Changes look good.

+ # Internt Explorer is always registered in the App Path
+ self.assertTrue(osutils.find_executable_on_path('iexplore') is not None)

I wonder a little if one of those people who purge IE from their system will ever run our test suite. Not worrying about that seems correct, the test looks fine (though 'is not None' is perhaps not useful).

See earlier mp for initial reviews:

<https://code.launchpad.net/~doxxx/bzr/bug939605/+merge/94488>

review: Approve
Revision history for this message
Martin Packman (gz) wrote :

sent to pqm by email

Revision history for this message
Gordon Tyler (doxxx) wrote :

As I understand it, if you purge IE from Windows, it breaks in mysterious ways. That may have changed in more recent versions but it certainly was true a few years ago.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/mergetools.py'
2--- bzrlib/mergetools.py 2011-12-19 13:23:58 +0000
3+++ bzrlib/mergetools.py 2012-02-28 05:06:17 +0000
4@@ -48,13 +48,13 @@
5 cmd_list = cmdline.split(command_line)
6 exe = cmd_list[0]
7 if sys.platform == 'win32':
8- if os.path.isabs(exe):
9- base, ext = os.path.splitext(exe)
10- path_ext = [unicode(s.lower())
11- for s in os.getenv('PATHEXT', '').split(os.pathsep)]
12- return os.path.exists(exe) and ext in path_ext
13- else:
14- return osutils.find_executable_on_path(exe) is not None
15+ exe = _get_executable_path(exe)
16+ if exe is None:
17+ return False
18+ base, ext = os.path.splitext(exe)
19+ path_ext = [unicode(s.lower())
20+ for s in os.getenv('PATHEXT', '').split(os.pathsep)]
21+ return os.path.exists(exe) and ext in path_ext
22 else:
23 return (os.access(exe, os.X_OK)
24 or osutils.find_executable_on_path(exe) is not None)
25@@ -69,6 +69,9 @@
26 if invoker is None:
27 invoker = subprocess_invoker
28 cmd_list = cmdline.split(command_line)
29+ exe = _get_executable_path(cmd_list[0])
30+ if exe is not None:
31+ cmd_list[0] = exe
32 args, tmp_file = _subst_filename(cmd_list, filename)
33 def cleanup(retcode):
34 if tmp_file is not None:
35@@ -79,6 +82,12 @@
36 return invoker(args[0], args[1:], cleanup)
37
38
39+def _get_executable_path(exe):
40+ if os.path.isabs(exe):
41+ return exe
42+ return osutils.find_executable_on_path(exe)
43+
44+
45 def _subst_filename(args, filename):
46 subst_names = {
47 'base': filename + u'.BASE',
48
49=== modified file 'bzrlib/osutils.py'
50--- bzrlib/osutils.py 2012-02-01 12:31:53 +0000
51+++ bzrlib/osutils.py 2012-02-28 05:06:17 +0000
52@@ -2473,10 +2473,6 @@
53 :param name: The base name of the executable.
54 :return: The path to the executable found or None.
55 """
56- path = os.environ.get('PATH')
57- if path is None:
58- return None
59- path = path.split(os.pathsep)
60 if sys.platform == 'win32':
61 exts = os.environ.get('PATHEXT', '').split(os.pathsep)
62 exts = [ext.lower() for ext in exts]
63@@ -2488,11 +2484,18 @@
64 exts = [ext]
65 else:
66 exts = ['']
67- for ext in exts:
68- for d in path:
69- f = os.path.join(d, name) + ext
70- if os.access(f, os.X_OK):
71- return f
72+ path = os.environ.get('PATH')
73+ if path is not None:
74+ path = path.split(os.pathsep)
75+ for ext in exts:
76+ for d in path:
77+ f = os.path.join(d, name) + ext
78+ if os.access(f, os.X_OK):
79+ return f
80+ if sys.platform == 'win32':
81+ app_path = win32utils.get_app_path(name)
82+ if app_path != name:
83+ return app_path
84 return None
85
86
87
88=== modified file 'bzrlib/tests/test_mergetools.py'
89--- bzrlib/tests/test_mergetools.py 2011-06-30 21:00:38 +0000
90+++ bzrlib/tests/test_mergetools.py 2012-02-28 05:06:17 +0000
91@@ -81,11 +81,7 @@
92 self.assertTrue(mergetools.check_availability(sys.executable))
93
94 def test_exe_on_path(self):
95- if sys.platform == 'win32':
96- exe = 'cmd.exe'
97- else:
98- exe = 'sh'
99- self.assertTrue(mergetools.check_availability(exe))
100+ self.assertTrue(mergetools.check_availability('python'))
101
102 def test_nonexistent(self):
103 self.assertFalse(mergetools.check_availability('DOES NOT EXIST'))
104@@ -112,6 +108,19 @@
105 ('test.txt.OTHER', 'other stuff'),
106 ))
107
108+ def test_invoke_expands_exe_path(self):
109+ self.overrideEnv('PATH', os.path.dirname(sys.executable))
110+ def dummy_invoker(exe, args, cleanup):
111+ self._exe = exe
112+ self._args = args
113+ cleanup(0)
114+ return 0
115+ command = '%s {result}' % os.path.basename(sys.executable)
116+ retcode = mergetools.invoke(command, 'test.txt', dummy_invoker)
117+ self.assertEqual(0, retcode)
118+ self.assertEqual(sys.executable, self._exe)
119+ self.assertEqual(['test.txt'], self._args)
120+
121 def test_success(self):
122 def dummy_invoker(exe, args, cleanup):
123 self._exe = exe
124
125=== modified file 'bzrlib/tests/test_osutils.py'
126--- bzrlib/tests/test_osutils.py 2012-02-01 12:32:26 +0000
127+++ bzrlib/tests/test_osutils.py 2012-02-28 05:06:17 +0000
128@@ -2225,6 +2225,14 @@
129 self.assertTrue(
130 osutils.find_executable_on_path('THIS SHOULD NOT EXIST') is None)
131 self.assertTrue(osutils.find_executable_on_path('file.txt') is None)
132+
133+ def test_windows_app_path(self):
134+ if sys.platform != 'win32':
135+ raise tests.TestSkipped('test requires win32')
136+ # Override PATH env var so that exe can only be found on App Path
137+ self.overrideEnv('PATH', '')
138+ # Internt Explorer is always registered in the App Path
139+ self.assertTrue(osutils.find_executable_on_path('iexplore') is not None)
140
141 def test_other(self):
142 if sys.platform == 'win32':
143
144=== modified file 'doc/en/release-notes/bzr-2.5.txt'
145--- doc/en/release-notes/bzr-2.5.txt 2012-02-26 19:21:01 +0000
146+++ doc/en/release-notes/bzr-2.5.txt 2012-02-28 05:06:17 +0000
147@@ -32,6 +32,9 @@
148 .. Fixes for situations where bzr would previously crash or give incorrect
149 or undesirable results.
150
151+* Fixed merge tool availability checking and invocation to search the
152+ Windows App Path registry in addition to the PATH. (Gordon Tyler, #939605)
153+
154 Documentation
155 *************
156

Subscribers

People subscribed via source and target branches