Show More
@@ -42,9 +42,9 b' fast (at least faster than having to com' | |||||
42 | ''' |
|
42 | ''' | |
43 |
|
43 | |||
44 | from mercurial.i18n import _ |
|
44 | from mercurial.i18n import _ | |
45 | from mercurial.node import short |
|
45 | from mercurial.node import short, nullid | |
46 | from mercurial import cmdutil, util, commands |
|
46 | from mercurial import cmdutil, util, commands | |
47 | import os, shlex, shutil, tempfile |
|
47 | import os, shlex, shutil, tempfile, re | |
48 |
|
48 | |||
49 | def snapshot(ui, repo, files, node, tmproot): |
|
49 | def snapshot(ui, repo, files, node, tmproot): | |
50 | '''snapshot files as of some revision |
|
50 | '''snapshot files as of some revision | |
@@ -69,7 +69,7 b' def snapshot(ui, repo, files, node, tmpr' | |||||
69 | for fn in files: |
|
69 | for fn in files: | |
70 | wfn = util.pconvert(fn) |
|
70 | wfn = util.pconvert(fn) | |
71 | if not wfn in ctx: |
|
71 | if not wfn in ctx: | |
72 | # skipping new file after a merge ? |
|
72 | # File doesn't exist; could be a bogus modify | |
73 | continue |
|
73 | continue | |
74 | ui.note(' %s\n' % wfn) |
|
74 | ui.note(' %s\n' % wfn) | |
75 | dest = os.path.join(base, wfn) |
|
75 | dest = os.path.join(base, wfn) | |
@@ -96,52 +96,95 b' def dodiff(ui, repo, diffcmd, diffopts, ' | |||||
96 |
|
96 | |||
97 | revs = opts.get('rev') |
|
97 | revs = opts.get('rev') | |
98 | change = opts.get('change') |
|
98 | change = opts.get('change') | |
|
99 | args = ' '.join(diffopts) | |||
|
100 | do3way = '$parent2' in args | |||
99 |
|
101 | |||
100 | if revs and change: |
|
102 | if revs and change: | |
101 | msg = _('cannot specify --rev and --change at the same time') |
|
103 | msg = _('cannot specify --rev and --change at the same time') | |
102 | raise util.Abort(msg) |
|
104 | raise util.Abort(msg) | |
103 | elif change: |
|
105 | elif change: | |
104 | node2 = repo.lookup(change) |
|
106 | node2 = repo.lookup(change) | |
105 |
node1 = repo |
|
107 | node1a, node1b = repo.changelog.parents(node2) | |
106 | else: |
|
108 | else: | |
107 | node1, node2 = cmdutil.revpair(repo, revs) |
|
109 | node1a, node2 = cmdutil.revpair(repo, revs) | |
|
110 | if not revs: | |||
|
111 | node1b = repo.dirstate.parents()[1] | |||
|
112 | else: | |||
|
113 | node1b = nullid | |||
|
114 | ||||
|
115 | # Disable 3-way merge if there is only one parent | |||
|
116 | if do3way: | |||
|
117 | if node1b == nullid: | |||
|
118 | do3way = False | |||
108 |
|
119 | |||
109 | matcher = cmdutil.match(repo, pats, opts) |
|
120 | matcher = cmdutil.match(repo, pats, opts) | |
110 |
mod |
|
121 | mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3]) | |
111 | if not (modified or added or removed): |
|
122 | if do3way: | |
112 | return 0 |
|
123 | mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3]) | |
|
124 | else: | |||
|
125 | mod_b, add_b, rem_b = set(), set(), set() | |||
|
126 | modadd = mod_a | add_a | mod_b | add_b | |||
|
127 | common = modadd | rem_a | rem_b | |||
|
128 | if not common: | |||
|
129 | return 0 | |||
113 |
|
130 | |||
114 | tmproot = tempfile.mkdtemp(prefix='extdiff.') |
|
131 | tmproot = tempfile.mkdtemp(prefix='extdiff.') | |
115 | dir2root = '' |
|
|||
116 | try: |
|
132 | try: | |
117 | # Always make a copy of node1 |
|
133 | # Always make a copy of node1a (and node1b, if applicable) | |
118 | dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] |
|
134 | dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) | |
119 | changes = len(modified) + len(removed) + len(added) |
|
135 | dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0] | |
|
136 | if do3way: | |||
|
137 | dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) | |||
|
138 | dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0] | |||
|
139 | else: | |||
|
140 | dir1b = None | |||
|
141 | ||||
|
142 | fns_and_mtime = [] | |||
120 |
|
143 | |||
121 | # If node2 in not the wc or there is >1 change, copy it |
|
144 | # If node2 in not the wc or there is >1 change, copy it | |
122 | if node2 or changes > 1: |
|
145 | dir2root = '' | |
123 | dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) |
|
146 | if node2: | |
|
147 | dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0] | |||
|
148 | elif len(common) > 1: | |||
|
149 | #we only actually need to get the files to copy back to the working | |||
|
150 | #dir in this case (because the other cases are: diffing 2 revisions | |||
|
151 | #or single file -- in which case the file is already directly passed | |||
|
152 | #to the diff tool). | |||
|
153 | dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot) | |||
124 | else: |
|
154 | else: | |
125 | # This lets the diff tool open the changed file directly |
|
155 | # This lets the diff tool open the changed file directly | |
126 | dir2 = '' |
|
156 | dir2 = '' | |
127 | dir2root = repo.root |
|
157 | dir2root = repo.root | |
128 | fns_and_mtime = [] |
|
|||
129 |
|
158 | |||
130 | # If only one change, diff the files instead of the directories |
|
159 | # If only one change, diff the files instead of the directories | |
131 | if changes == 1 : |
|
160 | # Handle bogus modifies correctly by checking if the files exist | |
132 |
|
|
161 | if len(common) == 1: | |
133 | dir1 = os.path.join(dir1, util.localpath(modified[0])) |
|
162 | common_file = util.localpath(common.pop()) | |
134 |
|
|
163 | dir1a = os.path.join(dir1a, common_file) | |
135 | elif len(removed) : |
|
164 | if not os.path.isfile(os.path.join(tmproot, dir1a)): | |
136 | dir1 = os.path.join(dir1, util.localpath(removed[0])) |
|
165 | dir1a = os.devnull | |
137 | dir2 = os.devnull |
|
166 | if do3way: | |
138 | else: |
|
167 | dir1b = os.path.join(dir1b, common_file) | |
139 | dir1 = os.devnull |
|
168 | if not os.path.isfile(os.path.join(tmproot, dir1b)): | |
140 | dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) |
|
169 | dir1b = os.devnull | |
|
170 | dir2 = os.path.join(dir2root, dir2, common_file) | |||
141 |
|
171 | |||
142 | cmdline = ('%s %s %s %s' % |
|
172 | # Function to quote file/dir names in the argument string | |
143 | (util.shellquote(diffcmd), ' '.join(diffopts), |
|
173 | # When not operating in 3-way mode, an empty string is returned for parent2 | |
144 | util.shellquote(dir1), util.shellquote(dir2))) |
|
174 | replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b, child=dir2) | |
|
175 | def quote(match): | |||
|
176 | key = match.group()[1:] | |||
|
177 | if not do3way and key == 'parent2': | |||
|
178 | return '' | |||
|
179 | return util.shellquote(replace[key]) | |||
|
180 | ||||
|
181 | # Match parent2 first, so 'parent1?' will match both parent1 and parent | |||
|
182 | regex = '\$(parent2|parent1?|child)' | |||
|
183 | if not do3way and not re.search(regex, args): | |||
|
184 | args += ' $parent1 $child' | |||
|
185 | args = re.sub(regex, quote, args) | |||
|
186 | cmdline = util.shellquote(diffcmd) + ' ' + args | |||
|
187 | ||||
145 | ui.debug('running %r in %s\n' % (cmdline, tmproot)) |
|
188 | ui.debug('running %r in %s\n' % (cmdline, tmproot)) | |
146 | util.system(cmdline, cwd=tmproot) |
|
189 | util.system(cmdline, cwd=tmproot) | |
147 |
|
190 |
General Comments 0
You need to be logged in to leave comments.
Login now