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