26
26
lazy_import(globals(), """
27
27
from bzrlib import (
39
def subprocess_invoker(executable, args, cleanup):
40
retcode = subprocess.call([executable] + args)
45
_WIN32_PATH_EXT = [unicode(ext.lower())
46
for ext in os.getenv('PATHEXT', '').split(os.pathsep)]
49
class MergeTool(object):
51
def __init__(self, name, command_line):
52
"""Initializes the merge tool with a name and a command-line."""
54
self.command_line = command_line
57
return '<%s(%s, %s)>' % (self.__class__, self.name, self.command_line)
59
def _get_command_line(self):
60
return self._command_line
62
def _set_command_line(self, command_line):
63
self._command_line = command_line
64
self._cmd_list = cmdline.split(self.command_line)
66
command_line = property(_get_command_line, _set_command_line)
68
def is_available(self):
69
exe = self._cmd_list[0]
70
if sys.platform == 'win32':
71
if os.path.isabs(exe):
72
base, ext = os.path.splitext(exe)
73
return os.path.exists(exe) and ext in _WIN32_PATH_EXT
75
return osutils.find_executable_on_path(exe) is not None
77
return (os.access(exe, os.X_OK)
78
or osutils.find_executable_on_path(exe) is not None)
80
def invoke(self, filename, invoker=None):
82
invoker = subprocess_invoker
83
args, tmp_file = self._subst_filename(self._cmd_list, filename)
85
if tmp_file is not None:
86
if retcode == 0: # on success, replace file with temp file
87
shutil.move(tmp_file, filename)
88
else: # otherwise, delete temp file
90
return invoker(args[0], args[1:], cleanup)
92
def _subst_filename(self, args, filename):
94
u'base': filename + u'.BASE',
95
u'this': filename + u'.THIS',
96
u'other': filename + u'.OTHER',
102
if u'{this_temp}' in arg and not 'this_temp' in subst_names:
103
tmp_file = tempfile.mktemp(u"_bzr_mergetools_%s.THIS" %
104
os.path.basename(filename))
105
shutil.copy(filename + u".THIS", tmp_file)
106
subst_names['this_temp'] = tmp_file
107
arg = arg.format(**subst_names)
108
subst_args.append(arg)
109
return subst_args, tmp_file
112
35
known_merge_tools = {
113
36
'bcompare': 'bcompare {this} {other} {base} {result}',
114
37
'kdiff3': 'kdiff3 {base} {this} {other} -o {result}',
117
40
'opendiff': 'opendiff {this} {other} -ancestor {base} -merge {result}',
118
41
'winmergeu': 'winmergeu {result}',
45
def check_availability(command_line):
46
cmd_list = cmdline.split(command_line)
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
55
return osutils.find_executable_on_path(exe) is not None
57
return (os.access(exe, os.X_OK)
58
or osutils.find_executable_on_path(exe) is not None)
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
68
invoker = subprocess_invoker
69
cmd_list = cmdline.split(command_line)
70
args, tmp_file = _subst_filename(cmd_list, filename)
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
77
return invoker(args[0], args[1:], cleanup)
80
def _subst_filename(args, filename):
82
u'base': filename + u'.BASE',
83
u'this': filename + u'.THIS',
84
u'other': filename + u'.OTHER',
90
if u'{this_temp}' in arg and not 'this_temp' in subst_names:
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)
95
shutil.copy(filename + u".THIS", tmp_file)
96
subst_names['this_temp'] = tmp_file
97
arg = arg.format(**subst_names)
98
subst_args.append(arg)
99
return subst_args, tmp_file
102
def subprocess_invoker(executable, args, cleanup):
103
retcode = subprocess.call([executable] + args)