blob: 4f9f5b0f293222787c0e6523507c529a2efd906b [file] [log] [blame]
Julien Camperguedd654222014-01-09 16:21:37 +01001# Copyright (C) 2014 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from color import Coloring
16from command import PagedCommand
Mike Frysinger8c1e9cb2020-09-06 14:53:18 -040017from manifest_xml import RepoClient
Julien Camperguedd654222014-01-09 16:21:37 +010018
David Pursehouse819827a2020-02-12 15:20:19 +090019
Julien Camperguedd654222014-01-09 16:21:37 +010020class _Coloring(Coloring):
21 def __init__(self, config):
22 Coloring.__init__(self, config, "status")
23
David Pursehouse819827a2020-02-12 15:20:19 +090024
Julien Camperguedd654222014-01-09 16:21:37 +010025class Diffmanifests(PagedCommand):
26 """ A command to see logs in projects represented by manifests
27
28 This is used to see deeper differences between manifests. Where a simple
29 diff would only show a diff of sha1s for example, this command will display
30 the logs of the project between both sha1s, allowing user to see diff at a
31 deeper level.
32 """
33
Mike Frysinger4f210542021-06-14 16:05:19 -040034 COMMON = True
Julien Camperguedd654222014-01-09 16:21:37 +010035 helpSummary = "Manifest diff utility"
36 helpUsage = """%prog manifest1.xml [manifest2.xml] [options]"""
37
38 helpDescription = """
39The %prog command shows differences between project revisions of manifest1 and
40manifest2. if manifest2 is not specified, current manifest.xml will be used
41instead. Both absolute and relative paths may be used for manifests. Relative
42paths start from project's ".repo/manifests" folder.
43
44The --raw option Displays the diff in a way that facilitates parsing, the
45project pattern will be <status> <path> <revision from> [<revision to>] and the
46commit pattern will be <status> <onelined log> with status values respectively :
47
48 A = Added project
49 R = Removed project
50 C = Changed project
51 U = Project with unreachable revision(s) (revision(s) not found)
52
53for project, and
54
55 A = Added commit
56 R = Removed commit
57
58for a commit.
59
60Only changed projects may contain commits, and commit status always starts with
61a space, and are part of last printed project.
62Unreachable revisions may occur if project is not up to date or if repo has not
63been initialized with all the groups, in which case some projects won't be
64synced and their revisions won't be found.
65
66"""
67
68 def _Options(self, p):
69 p.add_option('--raw',
70 dest='raw', action='store_true',
Mike Frysingerc177f942021-05-04 08:06:36 -040071 help='display raw diff')
Julien Camperguedd654222014-01-09 16:21:37 +010072 p.add_option('--no-color',
73 dest='color', action='store_false', default=True,
Mike Frysingerc177f942021-05-04 08:06:36 -040074 help='does not display the diff in color')
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +020075 p.add_option('--pretty-format',
76 dest='pretty_format', action='store',
77 metavar='<FORMAT>',
78 help='print the log using a custom git pretty format string')
Julien Camperguedd654222014-01-09 16:21:37 +010079
LaMont Jonesbee4efb2022-09-30 17:46:52 +000080 def _printRawDiff(self, diff, pretty_format=None, local=False):
81 _RelPath = lambda p: p.RelPath(local=local)
Julien Camperguedd654222014-01-09 16:21:37 +010082 for project in diff['added']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +000083 self.printText("A %s %s" % (_RelPath(project), project.revisionExpr))
Julien Camperguedd654222014-01-09 16:21:37 +010084 self.out.nl()
85
86 for project in diff['removed']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +000087 self.printText("R %s %s" % (_RelPath(project), project.revisionExpr))
Julien Camperguedd654222014-01-09 16:21:37 +010088 self.out.nl()
89
90 for project, otherProject in diff['changed']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +000091 self.printText("C %s %s %s" % (_RelPath(project), project.revisionExpr,
Julien Camperguedd654222014-01-09 16:21:37 +010092 otherProject.revisionExpr))
93 self.out.nl()
Connor Newton8b40c002020-03-11 17:25:20 +000094 self._printLogs(project, otherProject, raw=True, color=False, pretty_format=pretty_format)
Julien Camperguedd654222014-01-09 16:21:37 +010095
96 for project, otherProject in diff['unreachable']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +000097 self.printText("U %s %s %s" % (_RelPath(project), project.revisionExpr,
Julien Camperguedd654222014-01-09 16:21:37 +010098 otherProject.revisionExpr))
99 self.out.nl()
100
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000101 def _printDiff(self, diff, color=True, pretty_format=None, local=False):
102 _RelPath = lambda p: p.RelPath(local=local)
Julien Camperguedd654222014-01-09 16:21:37 +0100103 if diff['added']:
104 self.out.nl()
105 self.printText('added projects : \n')
106 self.out.nl()
107 for project in diff['added']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000108 self.printProject('\t%s' % (_RelPath(project)))
Julien Camperguedd654222014-01-09 16:21:37 +0100109 self.printText(' at revision ')
110 self.printRevision(project.revisionExpr)
111 self.out.nl()
112
113 if diff['removed']:
114 self.out.nl()
115 self.printText('removed projects : \n')
116 self.out.nl()
117 for project in diff['removed']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000118 self.printProject('\t%s' % (_RelPath(project)))
Julien Camperguedd654222014-01-09 16:21:37 +0100119 self.printText(' at revision ')
120 self.printRevision(project.revisionExpr)
121 self.out.nl()
122
Shashank Devaraj4ba29c42022-09-05 12:05:47 +0530123 if diff['missing']:
124 self.out.nl()
125 self.printText('missing projects : \n')
126 self.out.nl()
127 for project in diff['missing']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000128 self.printProject('\t%s' % (_RelPath(project)))
Shashank Devaraj4ba29c42022-09-05 12:05:47 +0530129 self.printText(' at revision ')
130 self.printRevision(project.revisionExpr)
131 self.out.nl()
132
Julien Camperguedd654222014-01-09 16:21:37 +0100133 if diff['changed']:
134 self.out.nl()
135 self.printText('changed projects : \n')
136 self.out.nl()
137 for project, otherProject in diff['changed']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000138 self.printProject('\t%s' % (_RelPath(project)))
Julien Camperguedd654222014-01-09 16:21:37 +0100139 self.printText(' changed from ')
140 self.printRevision(project.revisionExpr)
141 self.printText(' to ')
142 self.printRevision(otherProject.revisionExpr)
143 self.out.nl()
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200144 self._printLogs(project, otherProject, raw=False, color=color,
145 pretty_format=pretty_format)
Julien Camperguedd654222014-01-09 16:21:37 +0100146 self.out.nl()
147
148 if diff['unreachable']:
149 self.out.nl()
150 self.printText('projects with unreachable revisions : \n')
151 self.out.nl()
152 for project, otherProject in diff['unreachable']:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000153 self.printProject('\t%s ' % (_RelPath(project)))
Julien Camperguedd654222014-01-09 16:21:37 +0100154 self.printRevision(project.revisionExpr)
155 self.printText(' or ')
156 self.printRevision(otherProject.revisionExpr)
157 self.printText(' not found')
158 self.out.nl()
159
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200160 def _printLogs(self, project, otherProject, raw=False, color=True,
161 pretty_format=None):
162
163 logs = project.getAddedAndRemovedLogs(otherProject,
164 oneline=(pretty_format is None),
165 color=color,
166 pretty_format=pretty_format)
Julien Camperguedd654222014-01-09 16:21:37 +0100167 if logs['removed']:
168 removedLogs = logs['removed'].split('\n')
169 for log in removedLogs:
170 if log.strip():
171 if raw:
172 self.printText(' R ' + log)
173 self.out.nl()
174 else:
175 self.printRemoved('\t\t[-] ')
176 self.printText(log)
177 self.out.nl()
178
179 if logs['added']:
180 addedLogs = logs['added'].split('\n')
181 for log in addedLogs:
182 if log.strip():
183 if raw:
184 self.printText(' A ' + log)
185 self.out.nl()
186 else:
187 self.printAdded('\t\t[+] ')
188 self.printText(log)
189 self.out.nl()
190
Mike Frysingerae6cb082019-08-27 01:10:59 -0400191 def ValidateOptions(self, opt, args):
Julien Camperguedd654222014-01-09 16:21:37 +0100192 if not args or len(args) > 2:
Mike Frysingerae6cb082019-08-27 01:10:59 -0400193 self.OptionParser.error('missing manifests to diff')
LaMont Jonescc879a92021-11-18 22:40:18 +0000194 if opt.this_manifest_only is False:
195 raise self.OptionParser.error(
196 '`diffmanifest` only supports the current tree')
Julien Camperguedd654222014-01-09 16:21:37 +0100197
Mike Frysingerae6cb082019-08-27 01:10:59 -0400198 def Execute(self, opt, args):
Mike Frysinger8c1e9cb2020-09-06 14:53:18 -0400199 self.out = _Coloring(self.client.globalConfig)
Julien Camperguedd654222014-01-09 16:21:37 +0100200 self.printText = self.out.nofmt_printer('text')
201 if opt.color:
David Pursehousee5913ae2020-02-12 13:56:59 +0900202 self.printProject = self.out.nofmt_printer('project', attr='bold')
203 self.printAdded = self.out.nofmt_printer('green', fg='green', attr='bold')
204 self.printRemoved = self.out.nofmt_printer('red', fg='red', attr='bold')
205 self.printRevision = self.out.nofmt_printer('revision', fg='yellow')
Julien Camperguedd654222014-01-09 16:21:37 +0100206 else:
207 self.printProject = self.printAdded = self.printRemoved = self.printRevision = self.printText
208
Mike Frysingere3315bb2021-02-09 23:45:28 -0500209 manifest1 = RepoClient(self.repodir)
Basil Gelloc7453502018-05-25 20:23:52 +0300210 manifest1.Override(args[0], load_local_manifests=False)
Julien Camperguedd654222014-01-09 16:21:37 +0100211 if len(args) == 1:
212 manifest2 = self.manifest
213 else:
Mike Frysingere3315bb2021-02-09 23:45:28 -0500214 manifest2 = RepoClient(self.repodir)
Basil Gelloc7453502018-05-25 20:23:52 +0300215 manifest2.Override(args[1], load_local_manifests=False)
Julien Camperguedd654222014-01-09 16:21:37 +0100216
217 diff = manifest1.projectsDiff(manifest2)
218 if opt.raw:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000219 self._printRawDiff(diff, pretty_format=opt.pretty_format,
220 local=opt.this_manifest_only)
Julien Camperguedd654222014-01-09 16:21:37 +0100221 else:
LaMont Jonesbee4efb2022-09-30 17:46:52 +0000222 self._printDiff(diff, color=opt.color, pretty_format=opt.pretty_format,
223 local=opt.this_manifest_only)