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 |
||
5321.1.104
by Gordon Tyler
Tweaked docstring for mergetools module. |
17 |
"""Utility functions for managing external merge tools such as kdiff3."""
|
5321.1.69
by Gordon Tyler
Fixed line-endings to be Unix. |
18 |
|
19 |
import os |
|
20 |
import shutil |
|
21 |
import subprocess |
|
22 |
import sys |
|
23 |
import tempfile |
|
24 |
||
25 |
from bzrlib.lazy_import import lazy_import |
|
26 |
lazy_import(globals(), """ |
|
27 |
from bzrlib import (
|
|
28 |
cmdline,
|
|
5321.1.83
by Gordon Tyler
Use osutils.find_executable_on_path in is_available instead. |
29 |
osutils,
|
5321.1.69
by Gordon Tyler
Fixed line-endings to be Unix. |
30 |
trace,
|
31 |
)
|
|
32 |
""") |
|
33 |
||
34 |
||
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. |
35 |
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). |
36 |
'bcompare': 'bcompare {this} {other} {base} {result}', |
37 |
'kdiff3': 'kdiff3 {base} {this} {other} -o {result}', |
|
38 |
'xdiff': 'xxdiff -m -O -M {result} {this} {base} {other}', |
|
39 |
'meld': 'meld {base} {this_temp} {other}', |
|
40 |
'opendiff': 'opendiff {this} {other} -ancestor {base} -merge {result}', |
|
41 |
'winmergeu': 'winmergeu {result}', |
|
42 |
}
|
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
43 |
|
44 |
||
45 |
def check_availability(command_line): |
|
46 |
cmd_list = cmdline.split(command_line) |
|
47 |
exe = cmd_list[0] |
|
48 |
if sys.platform == 'win32': |
|
49 |
if os.path.isabs(exe): |
|
50 |
base, ext = os.path.splitext(exe) |
|
51 |
path_ext = [unicode(s.lower()) |
|
52 |
for s in os.getenv('PATHEXT', '').split(os.pathsep)] |
|
53 |
return os.path.exists(exe) and ext in path_ext |
|
54 |
else: |
|
55 |
return osutils.find_executable_on_path(exe) is not None |
|
56 |
else: |
|
57 |
return (os.access(exe, os.X_OK) |
|
58 |
or osutils.find_executable_on_path(exe) is not None) |
|
59 |
||
60 |
||
61 |
def invoke(command_line, filename, invoker=None): |
|
62 |
"""Invokes the given merge tool command line, substituting the given
|
|
63 |
filename according to the embedded substitution markers. Optionally, it
|
|
64 |
will use the given invoker function instead of the default
|
|
65 |
subprocess_invoker.
|
|
66 |
"""
|
|
67 |
if invoker is None: |
|
68 |
invoker = subprocess_invoker |
|
69 |
cmd_list = cmdline.split(command_line) |
|
70 |
args, tmp_file = _subst_filename(cmd_list, filename) |
|
71 |
def cleanup(retcode): |
|
72 |
if tmp_file is not None: |
|
73 |
if retcode == 0: # on success, replace file with temp file |
|
74 |
shutil.move(tmp_file, filename) |
|
75 |
else: # otherwise, delete temp file |
|
76 |
os.remove(tmp_file) |
|
77 |
return invoker(args[0], args[1:], cleanup) |
|
78 |
||
79 |
||
80 |
def _subst_filename(args, filename): |
|
81 |
subst_names = { |
|
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
82 |
'base': filename + u'.BASE', |
83 |
'this': filename + u'.THIS', |
|
84 |
'other': filename + u'.OTHER', |
|
85 |
'result': filename, |
|
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
86 |
}
|
87 |
tmp_file = None |
|
88 |
subst_args = [] |
|
89 |
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. |
90 |
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. |
91 |
fh, tmp_file = tempfile.mkstemp(u"_bzr_mergetools_%s.THIS" % |
92 |
os.path.basename(filename)) |
|
93 |
trace.mutter('fh=%r, tmp_file=%r', fh, tmp_file) |
|
94 |
os.close(fh) |
|
95 |
shutil.copy(filename + u".THIS", tmp_file) |
|
96 |
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. |
97 |
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. |
98 |
subst_args.append(arg) |
99 |
return subst_args, tmp_file |
|
100 |
||
101 |
||
5321.1.119
by Gordon Tyler
Replace usage of format function from python 2.6 with our own very simple formatting function. |
102 |
# This would be better implemented using format() from python 2.6
|
103 |
def _format_arg(arg, subst_names): |
|
104 |
arg = arg.replace('{base}', subst_names['base']) |
|
105 |
arg = arg.replace('{this}', subst_names['this']) |
|
106 |
arg = arg.replace('{other}', subst_names['other']) |
|
107 |
arg = arg.replace('{result}', subst_names['result']) |
|
108 |
if subst_names.has_key('this_temp'): |
|
109 |
arg = arg.replace('{this_temp}', subst_names['this_temp']) |
|
110 |
return arg |
|
111 |
||
112 |
||
5321.1.116
by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class. |
113 |
def subprocess_invoker(executable, args, cleanup): |
114 |
retcode = subprocess.call([executable] + args) |
|
115 |
cleanup(retcode) |
|
116 |
return retcode |