Mercurial > public > mercurial-scm > hg
comparison mercurial/logcmdutil.py @ 51139:204af2aa4931
logcmdutil: return structured diffstat data for json
author | zegervdv <zeger@vandevan.net> |
---|---|
date | Thu, 07 Sep 2023 08:39:21 +0200 |
parents | dcb2581e33be |
children | d6e5bec550f1 |
comparison
equal
deleted
inserted
replaced
51138:c845479fc64d | 51139:204af2aa4931 |
---|---|
96 return wctx | 96 return wctx |
97 else: | 97 else: |
98 return ctx.p1() | 98 return ctx.p1() |
99 | 99 |
100 | 100 |
101 def get_diff_chunks( | |
102 ui, | |
103 repo, | |
104 diffopts, | |
105 ctx1, | |
106 ctx2, | |
107 match, | |
108 changes=None, | |
109 stat=False, | |
110 prefix=b'', | |
111 root=b'', | |
112 hunksfilterfn=None, | |
113 ): | |
114 if root: | |
115 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root) | |
116 else: | |
117 relroot = b'' | |
118 copysourcematch = None | |
119 | |
120 def compose(f, g): | |
121 return lambda x: f(g(x)) | |
122 | |
123 def pathfn(f): | |
124 return posixpath.join(prefix, f) | |
125 | |
126 if relroot != b'': | |
127 # XXX relative roots currently don't work if the root is within a | |
128 # subrepo | |
129 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) | |
130 uirelroot = uipathfn(pathfn(relroot)) | |
131 relroot += b'/' | |
132 for matchroot in match.files(): | |
133 if not matchroot.startswith(relroot): | |
134 ui.warn( | |
135 _(b'warning: %s not inside relative root %s\n') | |
136 % (uipathfn(pathfn(matchroot)), uirelroot) | |
137 ) | |
138 | |
139 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path') | |
140 match = matchmod.intersectmatchers(match, relrootmatch) | |
141 copysourcematch = relrootmatch | |
142 | |
143 checkroot = repo.ui.configbool( | |
144 b'devel', b'all-warnings' | |
145 ) or repo.ui.configbool(b'devel', b'check-relroot') | |
146 | |
147 def relrootpathfn(f): | |
148 if checkroot and not f.startswith(relroot): | |
149 raise AssertionError( | |
150 b"file %s doesn't start with relroot %s" % (f, relroot) | |
151 ) | |
152 return f[len(relroot) :] | |
153 | |
154 pathfn = compose(relrootpathfn, pathfn) | |
155 | |
156 if stat: | |
157 diffopts = diffopts.copy(context=0, noprefix=False) | |
158 # If an explicit --root was given, don't respect ui.relative-paths | |
159 if not relroot: | |
160 pathfn = compose(scmutil.getuipathfn(repo), pathfn) | |
161 | |
162 return ctx2.diff( | |
163 ctx1, | |
164 match, | |
165 changes, | |
166 opts=diffopts, | |
167 pathfn=pathfn, | |
168 copysourcematch=copysourcematch, | |
169 hunksfilterfn=hunksfilterfn, | |
170 ) | |
171 | |
172 | |
101 def diffordiffstat( | 173 def diffordiffstat( |
102 ui, | 174 ui, |
103 repo, | 175 repo, |
104 diffopts, | 176 diffopts, |
105 ctx1, | 177 ctx1, |
113 root=b'', | 185 root=b'', |
114 listsubrepos=False, | 186 listsubrepos=False, |
115 hunksfilterfn=None, | 187 hunksfilterfn=None, |
116 ): | 188 ): |
117 '''show diff or diffstat.''' | 189 '''show diff or diffstat.''' |
118 if root: | 190 |
119 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root) | 191 chunks = get_diff_chunks( |
120 else: | 192 ui, |
121 relroot = b'' | 193 repo, |
122 copysourcematch = None | 194 diffopts, |
123 | 195 ctx1, |
124 def compose(f, g): | 196 ctx2, |
125 return lambda x: f(g(x)) | 197 match, |
126 | 198 changes=changes, |
127 def pathfn(f): | 199 stat=stat, |
128 return posixpath.join(prefix, f) | 200 prefix=prefix, |
129 | 201 root=root, |
130 if relroot != b'': | 202 hunksfilterfn=hunksfilterfn, |
131 # XXX relative roots currently don't work if the root is within a | 203 ) |
132 # subrepo | |
133 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True) | |
134 uirelroot = uipathfn(pathfn(relroot)) | |
135 relroot += b'/' | |
136 for matchroot in match.files(): | |
137 if not matchroot.startswith(relroot): | |
138 ui.warn( | |
139 _(b'warning: %s not inside relative root %s\n') | |
140 % (uipathfn(pathfn(matchroot)), uirelroot) | |
141 ) | |
142 | |
143 relrootmatch = scmutil.match(ctx2, pats=[relroot], default=b'path') | |
144 match = matchmod.intersectmatchers(match, relrootmatch) | |
145 copysourcematch = relrootmatch | |
146 | |
147 checkroot = repo.ui.configbool( | |
148 b'devel', b'all-warnings' | |
149 ) or repo.ui.configbool(b'devel', b'check-relroot') | |
150 | |
151 def relrootpathfn(f): | |
152 if checkroot and not f.startswith(relroot): | |
153 raise AssertionError( | |
154 b"file %s doesn't start with relroot %s" % (f, relroot) | |
155 ) | |
156 return f[len(relroot) :] | |
157 | |
158 pathfn = compose(relrootpathfn, pathfn) | |
159 | 204 |
160 if stat: | 205 if stat: |
161 diffopts = diffopts.copy(context=0, noprefix=False) | 206 diffopts = diffopts.copy(context=0, noprefix=False) |
162 width = 80 | 207 width = 80 |
163 if not ui.plain(): | 208 if not ui.plain(): |
164 width = ui.termwidth() - graphwidth | 209 width = ui.termwidth() - graphwidth |
165 # If an explicit --root was given, don't respect ui.relative-paths | |
166 if not relroot: | |
167 pathfn = compose(scmutil.getuipathfn(repo), pathfn) | |
168 | |
169 chunks = ctx2.diff( | |
170 ctx1, | |
171 match, | |
172 changes, | |
173 opts=diffopts, | |
174 pathfn=pathfn, | |
175 copysourcematch=copysourcematch, | |
176 hunksfilterfn=hunksfilterfn, | |
177 ) | |
178 | 210 |
179 if fp is not None or ui.canwritewithoutlabels(): | 211 if fp is not None or ui.canwritewithoutlabels(): |
180 out = fp or ui | 212 out = fp or ui |
181 if stat: | 213 if stat: |
182 chunks = [patch.diffstat(util.iterlines(chunks), width=width)] | 214 chunks = [patch.diffstat(util.iterlines(chunks), width=width)] |
247 stat=stat, | 279 stat=stat, |
248 graphwidth=graphwidth, | 280 graphwidth=graphwidth, |
249 hunksfilterfn=self._makehunksfilter(ctx), | 281 hunksfilterfn=self._makehunksfilter(ctx), |
250 ) | 282 ) |
251 | 283 |
284 def getdiffstats(self, ui, ctx, diffopts, stat=False): | |
285 chunks = get_diff_chunks( | |
286 ui, | |
287 ctx.repo(), | |
288 diffopts, | |
289 diff_parent(ctx), | |
290 ctx, | |
291 match=self._makefilematcher(ctx), | |
292 stat=stat, | |
293 hunksfilterfn=self._makehunksfilter(ctx), | |
294 ) | |
295 | |
296 diffdata = [] | |
297 for filename, additions, removals, binary in patch.diffstatdata( | |
298 util.iterlines(chunks) | |
299 ): | |
300 diffdata.append( | |
301 { | |
302 b"name": filename, | |
303 b"additions": additions, | |
304 b"removals": removals, | |
305 b"binary": binary, | |
306 } | |
307 ) | |
308 | |
309 return diffdata | |
310 | |
252 | 311 |
253 def changesetlabels(ctx): | 312 def changesetlabels(ctx): |
254 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()] | 313 labels = [b'log.changeset', b'changeset.%s' % ctx.phasestr()] |
255 if ctx.obsolete(): | 314 if ctx.obsolete(): |
256 labels.append(b'changeset.obsolete') | 315 labels.append(b'changeset.obsolete') |
523 fm.data( | 582 fm.data( |
524 copies=fm.formatdict(copies or {}, key=b'name', value=b'source') | 583 copies=fm.formatdict(copies or {}, key=b'name', value=b'source') |
525 ) | 584 ) |
526 | 585 |
527 if self._includestat or b'diffstat' in datahint: | 586 if self._includestat or b'diffstat' in datahint: |
528 self.ui.pushbuffer() | 587 data = self._differ.getdiffstats( |
529 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True) | 588 self.ui, ctx, self._diffopts, stat=True |
530 fm.data(diffstat=self.ui.popbuffer()) | 589 ) |
590 fm.data(diffstat=fm.formatlist(data, name=b'diffstat')) | |
531 if self._includediff or b'diff' in datahint: | 591 if self._includediff or b'diff' in datahint: |
532 self.ui.pushbuffer() | 592 self.ui.pushbuffer() |
533 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False) | 593 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False) |
534 fm.data(diff=self.ui.popbuffer()) | 594 fm.data(diff=self.ui.popbuffer()) |
535 | 595 |