< prev index next >

vcs/src/main/resources/ext.py

Print this page

 12 # accompanied this code).
 13 #
 14 # You should have received a copy of the GNU General Public License version
 15 # 2 along with this work; if not, write to the Free Software Foundation,
 16 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 17 #
 18 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 19 # or visit www.oracle.com if you need additional information or have any
 20 # questions.
 21 
 22 import mercurial
 23 import mercurial.patch
 24 import mercurial.mdiff
 25 import mercurial.util
 26 import mercurial.hg
 27 import mercurial.node
 28 import difflib
 29 import sys
 30 
 31 # space separated version list
 32 testedwith = '4.9.2 5.0.2'
 33 
 34 def mode(fctx):
 35     flags = fctx.flags()
 36     if flags == '': return '100644'
 37     if flags == 'x': return '100755'
 38     if flags == 'l': return '120000'
 39 
 40 def ratio(a, b, threshold):
 41     s = difflib.SequenceMatcher(None, a, b)
 42     if s.real_quick_ratio() < threshold:
 43         return 0
 44     if s.quick_ratio() < threshold:
 45         return 0
 46     ratio = s.ratio()
 47     if ratio < threshold:
 48         return 0
 49     return ratio
 50 
 51 def encode(s):
 52     return s.decode('utf-8').encode('utf-8')
 53 
 54 def write(s):
 55     sys.stdout.write(encode(s))



 56 
 57 def writeln(s):
 58     write(s)
 59     sys.stdout.write(encode('\n'))



 60 
 61 def _match_exact(root, cwd, files, badfn=None):
 62     """
 63     Wrapper for mercurial.match.exact that ignores some arguments based on the used version
 64     """
 65     if mercurial.util.version().startswith("5"):
 66         return mercurial.match.exact(files, badfn)
 67     else:
 68         return mercurial.match.exact(root, cwd, files, badfn)
 69 
 70 def _diff_git_raw(repo, ctx1, ctx2, modified, added, removed, showPatch):
 71     nullHash = '0' * 40
 72     removed_copy = set(removed)
 73 
 74     for path in added:
 75         fctx = ctx2.filectx(path)
 76         if fctx.renamed():
 77             parent = fctx.p1()
 78             old_path, _ = fctx.renamed()
 79             if old_path in removed:
 80                 removed_copy.discard(old_path)
 81 
 82     for path in sorted(modified | added | removed_copy):
 83         if path in modified:
 84             fctx = ctx2.filectx(path)
 85             writeln(':{} {} {} {} M\t{}'.format(mode(ctx1.filectx(path)), mode(fctx), nullHash, nullHash, fctx.path()))
 86         elif path in added:
 87             fctx = ctx2.filectx(path)
 88             if not fctx.renamed():
 89                 writeln(':000000 {} {} {} A\t{}'.format(mode(fctx), nullHash, nullHash, fctx.path()))
 90             else:
 91                 parent = fctx.p1()
 92                 score = int(ratio(parent.data(), fctx.data(), 0.5) * 100)
 93                 old_path, _ = fctx.renamed()
 94 
 95                 if old_path in removed:
 96                     operation = 'R'
 97                 else:
 98                     operation = 'C'
 99 
100                 writeln(':{} {} {} {} {}{}\t{}\t{}'.format(mode(parent), mode(fctx), nullHash, nullHash, operation, score, old_path, path))

101         elif path in removed_copy:
102             fctx = ctx1.filectx(path)
103             writeln(':{} 000000 {} {} D\t{}'.format(mode(fctx), nullHash, nullHash, path))
104 
105     if showPatch:
106         writeln('')
107 
108         match = _match_exact(repo.root, repo.getcwd(), list(modified) + list(added) + list(removed_copy))
109         opts = mercurial.mdiff.diffopts(git=True, nodates=True, context=0, showfunc=True)
110         for d in mercurial.patch.diff(repo, ctx1.node(), ctx2.node(), match=match, opts=opts):
111             sys.stdout.write(d)
112 
113 def really_differs(repo, p1, p2, ctx, files):
114     # workaround bug in hg (present since forever):
115     # `hg status` can, for merge commits, report a file as modififed between one parent
116     # and the merge even though it isn't. `hg diff` works correctly, so remove any "modified"
117     # that has an empty diff against one of its parents
118     differs = set()
119     for path in files:
120         match = _match_exact(repo.root, repo.getcwd(), [path])
121         opts = mercurial.mdiff.diffopts(git=True, nodates=True, context=0, showfunc=True)
122 
123         diff1 = mercurial.patch.diff(repo, p1.node(), ctx.node(), match=match, opts=opts)
124         diff2 = mercurial.patch.diff(repo, p2.node(), ctx.node(), match=match, opts=opts)
125         if len(list(diff1)) > 0 and len(list(diff2)) > 0:
126             differs.add(path)
127 
128     return differs
129 
130 cmdtable = {}
131 if hasattr(mercurial, 'registrar') and hasattr(mercurial.registrar, 'command'):

134     command = mercurial.cmdutil.command(cmdtable)
135 else:
136     def command(name, options, synopsis):
137         def decorator(func):
138             cmdtable[name] = func, list(options), synopsis
139             return func
140         return decorator
141 
142 if hasattr(mercurial, 'utils') and hasattr(mercurial.utils, 'dateutil'):
143     datestr = mercurial.utils.dateutil.datestr
144 else:
145     datestr = mercurial.util.datestr
146 
147 if hasattr(mercurial, 'scmutil'):
148     revsingle = mercurial.scmutil.revsingle
149     revrange = mercurial.scmutil.revrange
150 else:
151     revsingle = mercurial.cmdutil.revsingle
152     revrange = mercurial.cmdutil.revrange
153 
154 @command('diff-git-raw', [('', 'patch', False, '')], 'hg diff-git-raw rev1 [rev2]')
155 def diff_git_raw(ui, repo, rev1, rev2=None, **opts):
156     ctx1 = revsingle(repo, rev1)
157 
158     if rev2 != None:
159         ctx2 = revsingle(repo, rev2)
160         status = repo.status(ctx1, ctx2)
161     else:
162         ctx2 = mercurial.context.workingctx(repo)
163         status = repo.status(ctx1)
164 
165     modified, added, removed = [set(l) for l in status[:3]]
166     _diff_git_raw(repo, ctx1, ctx2, modified, added, removed, opts['patch'])
167 
168 @command('log-git', [('', 'reverse', False, ''), ('l', 'limit', -1, '')],  'hg log-git <revisions>')
169 def log_git(ui, repo, revs=None, **opts):
170     if len(repo) == 0:
171         return
172 
173     if revs == None:
174         if opts['reverse']:
175             revs = '0:tip'
176         else:
177             revs = 'tip:0'
178 
179     limit = opts['limit']
180     i = 0
181     for r in revrange(repo, [revs]):
182         ctx = repo[r]
183 
184         __dump_metadata(ctx)
185         parents = ctx.parents()
186 
187         if len(parents) == 1:
188             modified, added, removed = [set(l) for l in repo.status(parents[0], ctx)[:3]]
189             _diff_git_raw(repo, parents[0], ctx, modified, added, removed, True)
190         else:
191             p1 = parents[0]
192             p2 = parents[1]
193 
194             modified_p1, added_p1, removed_p1 = [set(l) for l in repo.status(p1, ctx)[:3]]
195             modified_p2, added_p2, removed_p2 = [set(l) for l in repo.status(p2, ctx)[:3]]
196 
197             added_both = added_p1 & added_p2
198             modified_both = modified_p1 & modified_p2
199             removed_both = removed_p1 & removed_p2
200 
201             combined_modified_p1 = modified_both | (modified_p1 & added_p2)
202             combined_added_p1 = added_both | (added_p1 & modified_p2)
203             combined_modified_p2 = modified_both | (modified_p2 & added_p1)
204             combined_added_p2 = added_both | (added_p2 & modified_p1)
205 
206             combined_modified_p1 = really_differs(repo, p1, p2, ctx, combined_modified_p1)
207             combined_added_p1 = really_differs(repo, p1, p2, ctx, combined_added_p1)
208             combined_modified_p2 = really_differs(repo, p1, p2, ctx, combined_modified_p2)
209             combined_added_p2 = really_differs(repo, p1, p2, ctx, combined_added_p2)
210 
211             _diff_git_raw(repo, p1, ctx, combined_modified_p1, combined_added_p1, removed_both, True)
212             writeln('#@!_-=&')
213             _diff_git_raw(repo, p2, ctx, combined_modified_p2, combined_added_p2, removed_both, True)
214 
215         i += 1
216         if i == limit:
217             break
218 
219 def __dump_metadata(ctx):
220         writeln('#@!_-=&')
221         writeln(ctx.hex())
222         writeln(str(ctx.rev()))
223         writeln(ctx.branch())
224 
225         parents = ctx.parents()
226         writeln(' '.join([str(p.hex()) for p in parents]))
227         writeln(' '.join([str(p.rev()) for p in parents]))
228 
229         writeln(ctx.user())
230         date = datestr(ctx.date(), format='%Y-%m-%d %H:%M:%S%z')
231         writeln(date)
232 
233         description = encode(ctx.description())
234         writeln(str(len(description)))
235         write(description)
236 
237 def __dump(repo, start, end):
238     for rev in xrange(start, end):
239         ctx = revsingle(repo, rev)
240 
241         __dump_metadata(ctx)
242         parents = ctx.parents()
243 
244         modified, added, removed = repo.status(parents[0], ctx)[:3]
245         writeln(str(len(modified)))
246         writeln(str(len(added)))
247         writeln(str(len(removed)))
248 
249         for filename in added + modified:
250             fctx = ctx.filectx(filename)
251 
252             writeln(filename)
253             writeln(' '.join(fctx.flags()))
254 
255             content = fctx.data()
256             writeln(str(len(content)))
257             sys.stdout.write(content)
258 
259         for filename in removed:
260             writeln(filename)
261 
262 def pretxnclose(ui, repo, **kwargs):
263     start = revsingle(repo, kwargs['node'])
264     end = revsingle(repo, kwargs['node_last'])
265     __dump(repo, start.rev(), end.rev() + 1)
266 
267 @command('dump', [],  'hg dump')
268 def dump(ui, repo, **opts):
269     __dump(repo, 0, len(repo))
270 
271 @command('metadata', [],  'hg metadata')
272 def dump(ui, repo, revs=None, **opts):
273     if revs == None:
274         revs = "0:tip"
275 
276     for r in revrange(repo, [revs]):
277         ctx = repo[r]
278         __dump_metadata(ctx)
279 
280 @command('ls-tree', [],  'hg ls-tree')
281 def ls_tree(ui, repo, rev, **opts):
282     nullHash = '0' * 40
283     ctx = revsingle(repo, rev)
284     for filename in ctx.manifest():
285         fctx = ctx.filectx(filename)
286         if 'x' in fctx.flags():
287             write('100755 blob ')
288         else:
289             write('100644 blob ')
290         write(nullHash)
291         write('\t')
292         writeln(filename)
293 
294 @command('ls-remote', [],  'hg ls-remote PATH')
295 def ls_remote(ui, repo, path, **opts):
296     peer = mercurial.hg.peer(ui or repo, opts, ui.expandpath(path))
297     for branch, heads in peer.branchmap().iteritems():
298         for head in heads:
299             write(mercurial.node.hex(head))
300             write("\t")
301             writeln(branch)

 12 # accompanied this code).
 13 #
 14 # You should have received a copy of the GNU General Public License version
 15 # 2 along with this work; if not, write to the Free Software Foundation,
 16 # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 17 #
 18 # Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 19 # or visit www.oracle.com if you need additional information or have any
 20 # questions.
 21 
 22 import mercurial
 23 import mercurial.patch
 24 import mercurial.mdiff
 25 import mercurial.util
 26 import mercurial.hg
 27 import mercurial.node
 28 import difflib
 29 import sys
 30 
 31 # space separated version list
 32 testedwith = '4.9.2 5.0.2 5.2.1'
 33 
 34 def mode(fctx):
 35     flags = fctx.flags()
 36     if flags == b'': return b'100644'
 37     if flags == b'x': return b'100755'
 38     if flags == b'l': return b'120000'
 39 
 40 def ratio(a, b, threshold):
 41     s = difflib.SequenceMatcher(None, a, b)
 42     if s.real_quick_ratio() < threshold:
 43         return 0
 44     if s.quick_ratio() < threshold:
 45         return 0
 46     ratio = s.ratio()
 47     if ratio < threshold:
 48         return 0
 49     return ratio
 50 



 51 def write(s):
 52     if sys.version_info >= (3, 0):
 53         sys.stdout.buffer.write(s)
 54     else:
 55         sys.stdout.write(s)
 56 
 57 def writeln(s):
 58     write(s)
 59     write(b'\n')
 60 
 61 def int_to_str(i):
 62     return str(i).encode('ascii')
 63 
 64 def _match_exact(root, cwd, files, badfn=None):
 65     """
 66     Wrapper for mercurial.match.exact that ignores some arguments based on the used version
 67     """
 68     if mercurial.util.version().startswith(b"5"):
 69         return mercurial.match.exact(files, badfn)
 70     else:
 71         return mercurial.match.exact(root, cwd, files, badfn)
 72 
 73 def _diff_git_raw(repo, ctx1, ctx2, modified, added, removed, showPatch):
 74     nullHash = b'0' * 40
 75     removed_copy = set(removed)
 76 
 77     for path in added:
 78         fctx = ctx2.filectx(path)
 79         if fctx.renamed():
 80             parent = fctx.p1()
 81             old_path, _ = fctx.renamed()
 82             if old_path in removed:
 83                 removed_copy.discard(old_path)
 84 
 85     for path in sorted(modified | added | removed_copy):
 86         if path in modified:
 87             fctx = ctx2.filectx(path)
 88             writeln(b':' + mode(ctx1.filectx(path)) + b' ' + mode(fctx) + b' ' + nullHash + b' ' + nullHash + b' M\t' + fctx.path())
 89         elif path in added:
 90             fctx = ctx2.filectx(path)
 91             if not fctx.renamed():
 92                 writeln(b':000000 ' + mode(fctx) + b' ' + nullHash + b' ' + nullHash + b' A\t' + fctx.path())
 93             else:
 94                 parent = fctx.p1()
 95                 score = int_to_str(int(ratio(parent.data(), fctx.data(), 0.5) * 100))
 96                 old_path, _ = fctx.renamed()
 97 
 98                 if old_path in removed:
 99                     operation = b'R'
100                 else:
101                     operation = b'C'
102 
103                 write(b':' + mode(parent) + b' ' + mode(fctx) + b' ' + nullHash + b' ' + nullHash + b' ')
104                 writeln(operation + score + b'\t' + old_path + b'\t' + path)
105         elif path in removed_copy:
106             fctx = ctx1.filectx(path)
107             writeln(b':' + mode(fctx) + b' 000000 ' + nullHash + b' ' + nullHash + b' D\t' + path)
108 
109     if showPatch:
110         writeln(b'')
111 
112         match = _match_exact(repo.root, repo.getcwd(), list(modified) + list(added) + list(removed_copy))
113         opts = mercurial.mdiff.diffopts(git=True, nodates=True, context=0, showfunc=True)
114         for d in mercurial.patch.diff(repo, ctx1.node(), ctx2.node(), match=match, opts=opts):
115             write(d)
116 
117 def really_differs(repo, p1, p2, ctx, files):
118     # workaround bug in hg (present since forever):
119     # `hg status` can, for merge commits, report a file as modififed between one parent
120     # and the merge even though it isn't. `hg diff` works correctly, so remove any "modified"
121     # that has an empty diff against one of its parents
122     differs = set()
123     for path in files:
124         match = _match_exact(repo.root, repo.getcwd(), [path])
125         opts = mercurial.mdiff.diffopts(git=True, nodates=True, context=0, showfunc=True)
126 
127         diff1 = mercurial.patch.diff(repo, p1.node(), ctx.node(), match=match, opts=opts)
128         diff2 = mercurial.patch.diff(repo, p2.node(), ctx.node(), match=match, opts=opts)
129         if len(list(diff1)) > 0 and len(list(diff2)) > 0:
130             differs.add(path)
131 
132     return differs
133 
134 cmdtable = {}
135 if hasattr(mercurial, 'registrar') and hasattr(mercurial.registrar, 'command'):

138     command = mercurial.cmdutil.command(cmdtable)
139 else:
140     def command(name, options, synopsis):
141         def decorator(func):
142             cmdtable[name] = func, list(options), synopsis
143             return func
144         return decorator
145 
146 if hasattr(mercurial, 'utils') and hasattr(mercurial.utils, 'dateutil'):
147     datestr = mercurial.utils.dateutil.datestr
148 else:
149     datestr = mercurial.util.datestr
150 
151 if hasattr(mercurial, 'scmutil'):
152     revsingle = mercurial.scmutil.revsingle
153     revrange = mercurial.scmutil.revrange
154 else:
155     revsingle = mercurial.cmdutil.revsingle
156     revrange = mercurial.cmdutil.revrange
157 
158 @command(b'diff-git-raw', [(b'', b'patch', False, b'')], b'hg diff-git-raw rev1 [rev2]')
159 def diff_git_raw(ui, repo, rev1, rev2=None, **opts):
160     ctx1 = revsingle(repo, rev1)
161 
162     if rev2 != None:
163         ctx2 = revsingle(repo, rev2)
164         status = repo.status(ctx1, ctx2)
165     else:
166         ctx2 = mercurial.context.workingctx(repo)
167         status = repo.status(ctx1)
168 
169     modified, added, removed = [set(l) for l in status[:3]]
170     _diff_git_raw(repo, ctx1, ctx2, modified, added, removed, opts['patch'])
171 
172 @command(b'log-git', [(b'', b'reverse', False, b''), (b'l', b'limit', -1, b'')],  b'hg log-git <revisions>')
173 def log_git(ui, repo, revs=None, **opts):
174     if len(repo) == 0:
175         return
176 
177     if revs == None:
178         if opts['reverse']:
179             revs = b'0:tip'
180         else:
181             revs = b'tip:0'
182 
183     limit = opts['limit']
184     i = 0
185     for r in revrange(repo, [revs]):
186         ctx = repo[r]
187 
188         __dump_metadata(ctx)
189         parents = ctx.parents()
190 
191         if len(parents) == 1:
192             modified, added, removed = [set(l) for l in repo.status(parents[0], ctx)[:3]]
193             _diff_git_raw(repo, parents[0], ctx, modified, added, removed, True)
194         else:
195             p1 = parents[0]
196             p2 = parents[1]
197 
198             modified_p1, added_p1, removed_p1 = [set(l) for l in repo.status(p1, ctx)[:3]]
199             modified_p2, added_p2, removed_p2 = [set(l) for l in repo.status(p2, ctx)[:3]]
200 
201             added_both = added_p1 & added_p2
202             modified_both = modified_p1 & modified_p2
203             removed_both = removed_p1 & removed_p2
204 
205             combined_modified_p1 = modified_both | (modified_p1 & added_p2)
206             combined_added_p1 = added_both | (added_p1 & modified_p2)
207             combined_modified_p2 = modified_both | (modified_p2 & added_p1)
208             combined_added_p2 = added_both | (added_p2 & modified_p1)
209 
210             combined_modified_p1 = really_differs(repo, p1, p2, ctx, combined_modified_p1)
211             combined_added_p1 = really_differs(repo, p1, p2, ctx, combined_added_p1)
212             combined_modified_p2 = really_differs(repo, p1, p2, ctx, combined_modified_p2)
213             combined_added_p2 = really_differs(repo, p1, p2, ctx, combined_added_p2)
214 
215             _diff_git_raw(repo, p1, ctx, combined_modified_p1, combined_added_p1, removed_both, True)
216             writeln(b'#@!_-=&')
217             _diff_git_raw(repo, p2, ctx, combined_modified_p2, combined_added_p2, removed_both, True)
218 
219         i += 1
220         if i == limit:
221             break
222 
223 def __dump_metadata(ctx):
224         writeln(b'#@!_-=&')
225         writeln(ctx.hex())
226         writeln(int_to_str(ctx.rev()))
227         writeln(ctx.branch())
228 
229         parents = ctx.parents()
230         writeln(b' '.join([p.hex() for p in parents]))
231         writeln(b' '.join([int_to_str(p.rev()) for p in parents]))
232 
233         writeln(ctx.user())
234         date = datestr(ctx.date(), format=b'%Y-%m-%d %H:%M:%S%z')
235         writeln(date)
236 
237         description = ctx.description()
238         writeln(int_to_str(len(description)))
239         write(description)
240 
241 def __dump(repo, start, end):
242     for rev in range(start, end):
243         ctx = revsingle(repo, rev)
244 
245         __dump_metadata(ctx)
246         parents = ctx.parents()
247 
248         modified, added, removed = repo.status(parents[0], ctx)[:3]
249         writeln(int_to_str(len(modified)))
250         writeln(int_to_str(len(added)))
251         writeln(int_to_str(len(removed)))
252 
253         for filename in added + modified:
254             fctx = ctx.filectx(filename)
255 
256             writeln(filename)
257             writeln(b' '.join(fctx.flags()))
258 
259             content = fctx.data()
260             writeln(int_to_str(len(content)))
261             write(content)
262 
263         for filename in removed:
264             writeln(filename)
265 
266 def pretxnclose(ui, repo, **kwargs):
267     start = revsingle(repo, kwargs['node'])
268     end = revsingle(repo, kwargs['node_last'])
269     __dump(repo, start.rev(), end.rev() + 1)
270 
271 @command(b'dump', [], b'hg dump')
272 def dump(ui, repo, **opts):
273     __dump(repo, 0, len(repo))
274 
275 @command(b'metadata', [], b'hg metadata')
276 def dump(ui, repo, revs=None, **opts):
277     if revs == None:
278         revs = b"0:tip"
279 
280     for r in revrange(repo, [revs]):
281         ctx = repo[r]
282         __dump_metadata(ctx)
283 
284 @command(b'ls-tree', [], b'hg ls-tree')
285 def ls_tree(ui, repo, rev, **opts):
286     nullHash = b'0' * 40
287     ctx = revsingle(repo, rev)
288     for filename in ctx.manifest():
289         fctx = ctx.filectx(filename)
290         if b'x' in fctx.flags():
291             write(b'100755 blob ')
292         else:
293             write(b'100644 blob ')
294         write(nullHash)
295         write(b'\t')
296         writeln(filename)
297 
298 @command(b'ls-remote', [], b'hg ls-remote PATH')
299 def ls_remote(ui, repo, path, **opts):
300     peer = mercurial.hg.peer(ui or repo, opts, ui.expandpath(path))
301     for branch, heads in peer.branchmap().iteritems():
302         for head in heads:
303             write(mercurial.node.hex(head))
304             write(b"\t")
305             writeln(branch)
< prev index next >