5321.1.69
by Gordon Tyler
Fixed line-endings to be Unix. |
1 |
# Copyright (C) 2010 Canonical Ltd.
|
2 |
#
|
|
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
7 |
#
|
|
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
#
|
|
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
16 |
||
6379.6.7
by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear. |
17 |
"""Utility functions for managing external merge tools such as kdiff3."""
|
18 |
||
6379.6.3
by Jelmer Vernooij
Use absolute_import. |
19 |
from __future__ import absolute_import |
20 |
||
5321.1.69
by Gordon Tyler
Fixed line-endings to be Unix. |
21 |
import os |
22 |
import shutil |
|
23 |
import subprocess |
|
24 |
import sys |
|
25 |
import tempfile |
|
26 |
||
27 |
from bzrlib.lazy_import import lazy_import |
|
28 |
lazy_import(globals(), """ |
|
29 |
from bzrlib import (
|
|
30 |
cmdline,
|
|
5321.1.83
by Gordon Tyler
Use osutils.find_executable_on_path in is_available instead. |
31 |
osutils,
|
5321.1.69
by Gordon Tyler
Fixed line-endings to be Unix. |
32 |
trace,
|
33 |
)
|
|
34 |
""") |
|
35 |
||
36 |
||
5321.1.108
by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools. |
37 |
known_merge_tools = { |
5321.2.8
by Vincent Ladeuil
_KNOWN_MERGE_TOOLS should be a dict (there is an hidden assumption that the merg tool is unique anyway). |
38 |
'bcompare': 'bcompare {this} {other} {base} {result}', |
39 |
'kdiff3': 'kdiff3 {base} {this} {other} -o {result}', |
|
40 |
'xdiff': 'xxdiff -m -O -M {result} {this} {base} {other}', |
|
41 |
'meld': 'meld {base} {this_temp} {other}', |
|
42 |
'opendiff': 'opendiff {this} {other} -ancestor {base} -merge {result}', |
|
43 |
'winmergeu': 'winmergeu {result}', |
|
44 |
}
|
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
45 |
|
46 |
||
47 |
def check_availability(command_line): |
|
48 |
cmd_list = cmdline.split(command_line) |
|
49 |
exe = cmd_list[0] |
|
50 |
if sys.platform == 'win32': |
|
6437.44.1
by Gordon Tyler
Backport of fix for bug 939605 to bzr 2.5 series. |
51 |
exe = _get_executable_path(exe) |
52 |
if exe is None: |
|
53 |
return False |
|
54 |
base, ext = os.path.splitext(exe) |
|
55 |
path_ext = [unicode(s.lower()) |
|
56 |
for s in os.getenv('PATHEXT', '').split(os.pathsep)] |
|
57 |
return os.path.exists(exe) and ext in path_ext |
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
58 |
else: |
59 |
return (os.access(exe, os.X_OK) |
|
60 |
or osutils.find_executable_on_path(exe) is not None) |
|
61 |
||
62 |
||
63 |
def invoke(command_line, filename, invoker=None): |
|
64 |
"""Invokes the given merge tool command line, substituting the given
|
|
65 |
filename according to the embedded substitution markers. Optionally, it
|
|
66 |
will use the given invoker function instead of the default
|
|
67 |
subprocess_invoker.
|
|
68 |
"""
|
|
69 |
if invoker is None: |
|
70 |
invoker = subprocess_invoker |
|
71 |
cmd_list = cmdline.split(command_line) |
|
6437.44.1
by Gordon Tyler
Backport of fix for bug 939605 to bzr 2.5 series. |
72 |
exe = _get_executable_path(cmd_list[0]) |
73 |
if exe is not None: |
|
74 |
cmd_list[0] = exe |
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
75 |
args, tmp_file = _subst_filename(cmd_list, filename) |
76 |
def cleanup(retcode): |
|
77 |
if tmp_file is not None: |
|
78 |
if retcode == 0: # on success, replace file with temp file |
|
79 |
shutil.move(tmp_file, filename) |
|
80 |
else: # otherwise, delete temp file |
|
81 |
os.remove(tmp_file) |
|
82 |
return invoker(args[0], args[1:], cleanup) |
|
83 |
||
84 |
||
6437.44.1
by Gordon Tyler
Backport of fix for bug 939605 to bzr 2.5 series. |
85 |
def _get_executable_path(exe): |
86 |
if os.path.isabs(exe): |
|
87 |
return exe |
|
88 |
return osutils.find_executable_on_path(exe) |
|
89 |
||
90 |
||
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
91 |
def _subst_filename(args, filename): |
92 |
subst_names = { |
|
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
93 |
'base': filename + u'.BASE', |
94 |
'this': filename + u'.THIS', |
|
95 |
'other': filename + u'.OTHER', |
|
96 |
'result': filename, |
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
97 |
}
|
98 |
tmp_file = None |
|
99 |
subst_args = [] |
|
100 |
for arg in args: |
|
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
101 |
if '{this_temp}' in arg and not 'this_temp' in subst_names: |
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
102 |
fh, tmp_file = tempfile.mkstemp(u"_bzr_mergetools_%s.THIS" % |
103 |
os.path.basename(filename)) |
|
104 |
trace.mutter('fh=%r, tmp_file=%r', fh, tmp_file) |
|
105 |
os.close(fh) |
|
106 |
shutil.copy(filename + u".THIS", tmp_file) |
|
107 |
subst_names['this_temp'] = tmp_file |
|
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
108 |
arg = _format_arg(arg, subst_names) |
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
109 |
subst_args.append(arg) |
110 |
return subst_args, tmp_file |
|
111 |
||
112 |
||
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
113 |
# This would be better implemented using format() from python 2.6
|
114 |
def _format_arg(arg, subst_names): |
|
115 |
arg = arg.replace('{base}', subst_names['base']) |
|
116 |
arg = arg.replace('{this}', subst_names['this']) |
|
117 |
arg = arg.replace('{other}', subst_names['other']) |
|
118 |
arg = arg.replace('{result}', subst_names['result']) |
|
119 |
if subst_names.has_key('this_temp'): |
|
120 |
arg = arg.replace('{this_temp}', subst_names['this_temp']) |
|
121 |
return arg |
|
122 |
||
123 |
||
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
124 |
def subprocess_invoker(executable, args, cleanup): |
125 |
retcode = subprocess.call([executable] + args) |
|
126 |
cleanup(retcode) |
|
127 |
return retcode |