blob: 77f99df29d53b1d6b60fd3cda8ed993843058b00 [file] [log] [blame]
Mike Frysingerf6013762019-06-13 02:30:51 -04001# -*- coding:utf-8 -*-
Julien Camperguedd654222014-01-09 16:21:37 +01002#
3# Copyright (C) 2014 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17from color import Coloring
18from command import PagedCommand
19from manifest_xml import XmlManifest
20
David Pursehouse819827a2020-02-12 15:20:19 +090021
Julien Camperguedd654222014-01-09 16:21:37 +010022class _Coloring(Coloring):
23 def __init__(self, config):
24 Coloring.__init__(self, config, "status")
25
David Pursehouse819827a2020-02-12 15:20:19 +090026
Julien Camperguedd654222014-01-09 16:21:37 +010027class Diffmanifests(PagedCommand):
28 """ A command to see logs in projects represented by manifests
29
30 This is used to see deeper differences between manifests. Where a simple
31 diff would only show a diff of sha1s for example, this command will display
32 the logs of the project between both sha1s, allowing user to see diff at a
33 deeper level.
34 """
35
36 common = True
37 helpSummary = "Manifest diff utility"
38 helpUsage = """%prog manifest1.xml [manifest2.xml] [options]"""
39
40 helpDescription = """
41The %prog command shows differences between project revisions of manifest1 and
42manifest2. if manifest2 is not specified, current manifest.xml will be used
43instead. Both absolute and relative paths may be used for manifests. Relative
44paths start from project's ".repo/manifests" folder.
45
46The --raw option Displays the diff in a way that facilitates parsing, the
47project pattern will be <status> <path> <revision from> [<revision to>] and the
48commit pattern will be <status> <onelined log> with status values respectively :
49
50 A = Added project
51 R = Removed project
52 C = Changed project
53 U = Project with unreachable revision(s) (revision(s) not found)
54
55for project, and
56
57 A = Added commit
58 R = Removed commit
59
60for a commit.
61
62Only changed projects may contain commits, and commit status always starts with
63a space, and are part of last printed project.
64Unreachable revisions may occur if project is not up to date or if repo has not
65been initialized with all the groups, in which case some projects won't be
66synced and their revisions won't be found.
67
68"""
69
70 def _Options(self, p):
71 p.add_option('--raw',
72 dest='raw', action='store_true',
73 help='Display raw diff.')
74 p.add_option('--no-color',
75 dest='color', action='store_false', default=True,
76 help='does not display the diff in color.')
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +020077 p.add_option('--pretty-format',
78 dest='pretty_format', action='store',
79 metavar='<FORMAT>',
80 help='print the log using a custom git pretty format string')
Julien Camperguedd654222014-01-09 16:21:37 +010081
82 def _printRawDiff(self, diff):
83 for project in diff['added']:
84 self.printText("A %s %s" % (project.relpath, project.revisionExpr))
85 self.out.nl()
86
87 for project in diff['removed']:
88 self.printText("R %s %s" % (project.relpath, project.revisionExpr))
89 self.out.nl()
90
91 for project, otherProject in diff['changed']:
92 self.printText("C %s %s %s" % (project.relpath, project.revisionExpr,
93 otherProject.revisionExpr))
94 self.out.nl()
95 self._printLogs(project, otherProject, raw=True, color=False)
96
97 for project, otherProject in diff['unreachable']:
98 self.printText("U %s %s %s" % (project.relpath, project.revisionExpr,
99 otherProject.revisionExpr))
100 self.out.nl()
101
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200102 def _printDiff(self, diff, color=True, pretty_format=None):
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']:
108 self.printProject('\t%s' % (project.relpath))
109 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']:
118 self.printProject('\t%s' % (project.relpath))
119 self.printText(' at revision ')
120 self.printRevision(project.revisionExpr)
121 self.out.nl()
122
123 if diff['changed']:
124 self.out.nl()
125 self.printText('changed projects : \n')
126 self.out.nl()
127 for project, otherProject in diff['changed']:
128 self.printProject('\t%s' % (project.relpath))
129 self.printText(' changed from ')
130 self.printRevision(project.revisionExpr)
131 self.printText(' to ')
132 self.printRevision(otherProject.revisionExpr)
133 self.out.nl()
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200134 self._printLogs(project, otherProject, raw=False, color=color,
135 pretty_format=pretty_format)
Julien Camperguedd654222014-01-09 16:21:37 +0100136 self.out.nl()
137
138 if diff['unreachable']:
139 self.out.nl()
140 self.printText('projects with unreachable revisions : \n')
141 self.out.nl()
142 for project, otherProject in diff['unreachable']:
143 self.printProject('\t%s ' % (project.relpath))
144 self.printRevision(project.revisionExpr)
145 self.printText(' or ')
146 self.printRevision(otherProject.revisionExpr)
147 self.printText(' not found')
148 self.out.nl()
149
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200150 def _printLogs(self, project, otherProject, raw=False, color=True,
151 pretty_format=None):
152
153 logs = project.getAddedAndRemovedLogs(otherProject,
154 oneline=(pretty_format is None),
155 color=color,
156 pretty_format=pretty_format)
Julien Camperguedd654222014-01-09 16:21:37 +0100157 if logs['removed']:
158 removedLogs = logs['removed'].split('\n')
159 for log in removedLogs:
160 if log.strip():
161 if raw:
162 self.printText(' R ' + log)
163 self.out.nl()
164 else:
165 self.printRemoved('\t\t[-] ')
166 self.printText(log)
167 self.out.nl()
168
169 if logs['added']:
170 addedLogs = logs['added'].split('\n')
171 for log in addedLogs:
172 if log.strip():
173 if raw:
174 self.printText(' A ' + log)
175 self.out.nl()
176 else:
177 self.printAdded('\t\t[+] ')
178 self.printText(log)
179 self.out.nl()
180
Mike Frysingerae6cb082019-08-27 01:10:59 -0400181 def ValidateOptions(self, opt, args):
Julien Camperguedd654222014-01-09 16:21:37 +0100182 if not args or len(args) > 2:
Mike Frysingerae6cb082019-08-27 01:10:59 -0400183 self.OptionParser.error('missing manifests to diff')
Julien Camperguedd654222014-01-09 16:21:37 +0100184
Mike Frysingerae6cb082019-08-27 01:10:59 -0400185 def Execute(self, opt, args):
Julien Camperguedd654222014-01-09 16:21:37 +0100186 self.out = _Coloring(self.manifest.globalConfig)
187 self.printText = self.out.nofmt_printer('text')
188 if opt.color:
David Pursehousee5913ae2020-02-12 13:56:59 +0900189 self.printProject = self.out.nofmt_printer('project', attr='bold')
190 self.printAdded = self.out.nofmt_printer('green', fg='green', attr='bold')
191 self.printRemoved = self.out.nofmt_printer('red', fg='red', attr='bold')
192 self.printRevision = self.out.nofmt_printer('revision', fg='yellow')
Julien Camperguedd654222014-01-09 16:21:37 +0100193 else:
194 self.printProject = self.printAdded = self.printRemoved = self.printRevision = self.printText
195
196 manifest1 = XmlManifest(self.manifest.repodir)
Basil Gelloc7453502018-05-25 20:23:52 +0300197 manifest1.Override(args[0], load_local_manifests=False)
Julien Camperguedd654222014-01-09 16:21:37 +0100198 if len(args) == 1:
199 manifest2 = self.manifest
200 else:
201 manifest2 = XmlManifest(self.manifest.repodir)
Basil Gelloc7453502018-05-25 20:23:52 +0300202 manifest2.Override(args[1], load_local_manifests=False)
Julien Camperguedd654222014-01-09 16:21:37 +0100203
204 diff = manifest1.projectsDiff(manifest2)
205 if opt.raw:
206 self._printRawDiff(diff)
207 else:
Sebastian Schuberth7ecccf62016-03-29 14:11:20 +0200208 self._printDiff(diff, color=opt.color, pretty_format=opt.pretty_format)