man pages: Bugfixed man pages for --sign and --ack flags; e.g., for stg-new
[stgit] / stgit / gitmergeonefile.py
CommitLineData
3659ef88
CM
1"""Performs a 3-way merge for GIT files
2"""
3
4__copyright__ = """
5Copyright (C) 2006, Catalin Marinas <catalin.marinas@gmail.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
21import sys, os
87c93eab 22from stgit.exception import *
170f576b 23from stgit import basedir
f7ed76a9 24from stgit.config import config, file_extensions, ConfigOption
5e888f30
KH
25from stgit.utils import append_string
26from stgit.out import *
f0de3f92 27from stgit.run import *
3659ef88 28
87c93eab 29class GitMergeException(StgException):
3659ef88
CM
30 pass
31
32
33#
34# Options
35#
29197bc0 36autoimerge = ConfigOption('stgit', 'autoimerge')
eee7283e 37keeporig = ConfigOption('stgit', 'keeporig')
3659ef88
CM
38
39#
40# Utility functions
41#
42def __str2none(x):
43 if x == '':
44 return None
45 else:
46 return x
47
f0de3f92
KH
48class MRun(Run):
49 exc = GitMergeException # use a custom exception class on errors
3659ef88 50
29197bc0
CM
51def __checkout_stages(filename):
52 """Check-out the merge stages in the index for the give file
3659ef88 53 """
1e075406 54 extensions = file_extensions()
29197bc0
CM
55 line = MRun('git', 'checkout-index', '--stage=all', '--', filename
56 ).output_one_line()
57 stages, path = line.split('\t')
58 stages = dict(zip(['ancestor', 'current', 'patched'],
59 stages.split(' ')))
60
61 for stage, fn in stages.iteritems():
62 if stages[stage] == '.':
63 stages[stage] = None
64 else:
65 newname = filename + extensions[stage]
66 if os.path.exists(newname):
67 # remove the stage if it is already checked out
68 os.remove(newname)
69 os.rename(stages[stage], newname)
70 stages[stage] = newname
1e075406 71
29197bc0 72 return stages
8d415553 73
29197bc0
CM
74def __remove_stages(filename):
75 """Remove the merge stages from the working directory
3659ef88 76 """
29197bc0
CM
77 extensions = file_extensions()
78 for ext in extensions.itervalues():
79 fn = filename + ext
80 if os.path.isfile(fn):
81 os.remove(fn)
3659ef88 82
29197bc0
CM
83def interactive_merge(filename):
84 """Run the interactive merger on the given file. Stages will be
85 removed according to stgit.keeporig. If successful and stages
86 kept, they will be removed via git.resolved().
3659ef88 87 """
29197bc0 88 stages = __checkout_stages(filename)
3659ef88 89
c5bd7632 90 try:
c5bd7632
KH
91 # Check whether we have all the files for the merge.
92 if not (stages['current'] and stages['patched']):
93 raise GitMergeException('Cannot run the interactive merge')
94
95 if stages['ancestor']:
96 three_way = True
97 files_dict = {'branch1': stages['current'],
98 'ancestor': stages['ancestor'],
99 'branch2': stages['patched'],
100 'output': filename}
101 imerger = config.get('stgit.i3merge')
102 else:
103 three_way = False
104 files_dict = {'branch1': stages['current'],
105 'branch2': stages['patched'],
106 'output': filename}
107 imerger = config.get('stgit.i2merge')
108
109 if not imerger:
110 raise GitMergeException, 'No interactive merge command configured'
111
112 mtime = os.path.getmtime(filename)
113
114 out.start('Trying the interactive %s merge'
115 % (three_way and 'three-way' or 'two-way'))
116 err = os.system(imerger % files_dict)
117 out.done()
118 if err != 0:
119 raise GitMergeException, 'The interactive merge failed'
120 if not os.path.isfile(filename):
121 raise GitMergeException, 'The "%s" file is missing' % filename
122 if mtime == os.path.getmtime(filename):
123 raise GitMergeException, 'The "%s" file was not modified' % filename
124 finally:
29197bc0
CM
125 # keep the merge stages?
126 if str(keeporig) != 'yes':
127 __remove_stages(filename)
f7ed76a9 128
29197bc0
CM
129def clean_up(filename):
130 """Remove merge conflict stages if they were generated.
3659ef88 131 """
29197bc0
CM
132 if str(keeporig) == 'yes':
133 __remove_stages(filename)
f7ed76a9 134
29197bc0
CM
135def merge(filename):
136 """Merge one file if interactive is allowed or check out the stages
137 if keeporig is set.
138 """
139 if str(autoimerge) == 'yes':
140 try:
141 interactive_merge(filename)
142 except GitMergeException, ex:
143 out.error(str(ex))
144 return False
145 return True
146
147 if str(keeporig) == 'yes':
148 __checkout_stages(filename)
149
150 return False