blob: 05998681444d3f9536fd140303e814ac71608b95 [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.')
74
75 def _printRawDiff(self, diff):
76 for project in diff['added']:
77 self.printText("A %s %s" % (project.relpath, project.revisionExpr))
78 self.out.nl()
79
80 for project in diff['removed']:
81 self.printText("R %s %s" % (project.relpath, project.revisionExpr))
82 self.out.nl()
83
84 for project, otherProject in diff['changed']:
85 self.printText("C %s %s %s" % (project.relpath, project.revisionExpr,
86 otherProject.revisionExpr))
87 self.out.nl()
88 self._printLogs(project, otherProject, raw=True, color=False)
89
90 for project, otherProject in diff['unreachable']:
91 self.printText("U %s %s %s" % (project.relpath, project.revisionExpr,
92 otherProject.revisionExpr))
93 self.out.nl()
94
95 def _printDiff(self, diff, color=True):
96 if diff['added']:
97 self.out.nl()
98 self.printText('added projects : \n')
99 self.out.nl()
100 for project in diff['added']:
101 self.printProject('\t%s' % (project.relpath))
102 self.printText(' at revision ')
103 self.printRevision(project.revisionExpr)
104 self.out.nl()
105
106 if diff['removed']:
107 self.out.nl()
108 self.printText('removed projects : \n')
109 self.out.nl()
110 for project in diff['removed']:
111 self.printProject('\t%s' % (project.relpath))
112 self.printText(' at revision ')
113 self.printRevision(project.revisionExpr)
114 self.out.nl()
115
116 if diff['changed']:
117 self.out.nl()
118 self.printText('changed projects : \n')
119 self.out.nl()
120 for project, otherProject in diff['changed']:
121 self.printProject('\t%s' % (project.relpath))
122 self.printText(' changed from ')
123 self.printRevision(project.revisionExpr)
124 self.printText(' to ')
125 self.printRevision(otherProject.revisionExpr)
126 self.out.nl()
127 self._printLogs(project, otherProject, raw=False, color=color)
128 self.out.nl()
129
130 if diff['unreachable']:
131 self.out.nl()
132 self.printText('projects with unreachable revisions : \n')
133 self.out.nl()
134 for project, otherProject in diff['unreachable']:
135 self.printProject('\t%s ' % (project.relpath))
136 self.printRevision(project.revisionExpr)
137 self.printText(' or ')
138 self.printRevision(otherProject.revisionExpr)
139 self.printText(' not found')
140 self.out.nl()
141
142 def _printLogs(self, project, otherProject, raw=False, color=True):
143 logs = project.getAddedAndRemovedLogs(otherProject, oneline=True,
144 color=color)
145 if logs['removed']:
146 removedLogs = logs['removed'].split('\n')
147 for log in removedLogs:
148 if log.strip():
149 if raw:
150 self.printText(' R ' + log)
151 self.out.nl()
152 else:
153 self.printRemoved('\t\t[-] ')
154 self.printText(log)
155 self.out.nl()
156
157 if logs['added']:
158 addedLogs = logs['added'].split('\n')
159 for log in addedLogs:
160 if log.strip():
161 if raw:
162 self.printText(' A ' + log)
163 self.out.nl()
164 else:
165 self.printAdded('\t\t[+] ')
166 self.printText(log)
167 self.out.nl()
168
169 def Execute(self, opt, args):
170 if not args or len(args) > 2:
171 self.Usage()
172
173 self.out = _Coloring(self.manifest.globalConfig)
174 self.printText = self.out.nofmt_printer('text')
175 if opt.color:
176 self.printProject = self.out.nofmt_printer('project', attr = 'bold')
177 self.printAdded = self.out.nofmt_printer('green', fg = 'green', attr = 'bold')
178 self.printRemoved = self.out.nofmt_printer('red', fg = 'red', attr = 'bold')
179 self.printRevision = self.out.nofmt_printer('revision', fg = 'yellow')
180 else:
181 self.printProject = self.printAdded = self.printRemoved = self.printRevision = self.printText
182
183 manifest1 = XmlManifest(self.manifest.repodir)
184 manifest1.Override(args[0])
185 if len(args) == 1:
186 manifest2 = self.manifest
187 else:
188 manifest2 = XmlManifest(self.manifest.repodir)
189 manifest2.Override(args[1])
190
191 diff = manifest1.projectsDiff(manifest2)
192 if opt.raw:
193 self._printRawDiff(diff)
194 else:
195 self._printDiff(diff, color=opt.color)