~osomon/oxide/restore-error-page-unit-test

242 by Chris Coulson
Oops, add the actual script
1
#!/usr/bin/python
2
# vim:expandtab:shiftwidth=2:tabstop=2:
3
4
# Copyright (C) 2013 Canonical Ltd.
5
6
# This library is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU Lesser General Public
8
# License as published by the Free Software Foundation; either
9
# version 2.1 of the License, or (at your option) any later version.
10
11
# This library is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# Lesser General Public License for more details.
15
16
# You should have received a copy of the GNU Lesser General Public
17
# License along with this library; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
20
from __future__ import print_function
21
import optparse
22
import os.path
23
import shutil
24
from StringIO import StringIO
25
import sys
26
360 by Chris Coulson
Stop leaving pyc files everywhere
27
sys.dont_write_bytecode = True
28
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
29
242 by Chris Coulson
Oops, add the actual script
30
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "build", "python"))
539.1.6 by Chris Coulson
Checkout the ninja git repo
31
from oxide_utils import CheckCall, GetFileChecksum, CHROMIUMSRCDIR, TOPSRCDIR
242 by Chris Coulson
Oops, add the actual script
32
from patch_utils import HgPatchSeries, OldPatchSeries, SourcePatchSeries, SyncablePatchSet, SyncError
33
import subcommand
34
35
class OptionParser(optparse.OptionParser):
36
  def __init__(self):
37
    optparse.OptionParser.__init__(self)
38
39
    self.description = """
40
Tool for managing a queue of Chromium patches in Oxide.
41
"""
42
43
@subcommand.Command("sync", " [patchname]")
44
@subcommand.CommandOption("-n", "--dry-run", dest="dry_run", action="store_true",
45
                          help="Display the changes that would be made without "
46
                               "actually modifying anything")
47
def cmd_sync(options, args):
48
  """Synchronize the patch queues in Bzr and Chromium.
49
50
  This command attempts to synchronize the patch queues in Bzr and Chromium.
51
  Firstly, a 3-way merge of the series files is attempted. The active patches
52
  listed in the result of this merge are then iterated over. Any patches that
53
  have been modified in Bzr are copied to Chromium. Any patches that have been
54
  modified in Chromium are copied back to Bzr.
55
56
  Patches that are currently applied to your Chromium checkout are
57
  automatically unapplied where necessary.
58
  """
59
60
  s = SyncablePatchSet()
61
  try:
62
    s.calculate_sync()
63
    if not options.dry_run:
64
      s.do_sync()
65
      return
66
  except SyncError as e:
67
    print(e, file=sys.stderr)
68
    sys.exit(1)
69
70
  unapply_to = None
71
  if s.result.unapply_to is not None:
72
    unapply_to = s.hg_patches[s.result.unapply_to]
73
  if unapply_to != s.hg_patches.top_patch:
74
    if not unapply_to:
75
      print("The Chromium patch queue will be fully unwound")
76
    elif unapply_to.applied:
77
      print("The Chromium patch queue will be unwound to %s" %
78
            s.result.unapply_to)
79
    else:
80
      print("The Chromium patch queue will not be unwound")
81
  else:
82
    print("The Chromium patch queue will not be unwound")
83
84
  width = max(len(patch.filename) for patch in s.result.patches)
85
  print("\nFinal patch set:")
86
  print("".join((" %-*s%s\n" %
87
      (width, patch.filename,
88
      " (copy from Chromium)" if patch.result == "use-hg" else
89
      " (copy from Bzr)" if patch.result == "use-bzr" else
90
      "")) for patch in s.result.patches if patch.active))
91
92
  width = max(len(line) for line in s.result.patches.contents.splitlines())
93
  print("\nSeries file contents:\n")
94
  print("="*width)
95
  print("%s" % s.result.patches.contents)
96
  print("="*width)
97
98
  copy_list = [patch for patch in s.result.patches
99
               if patch.result == "use-bzr" or patch.result == "use-hg"]
100
  if len(copy_list) == 0:
101
    print("\nNo files to be copied")
102
  else:
103
    print("\nFiles to be copied:")
104
    for patch in copy_list:
105
      if patch.result == "use-bzr":
106
        src = os.path.join(s.src_patches.patchdir, patch.filename)
107
        dst = os.path.join(s.hg_patches.patchdir, patch.filename)
108
      else:
109
        src = os.path.join(s.hg_patches.patchdir, patch.filename)
110
        dst = os.path.join(s.src_patches.patchdir, patch.filename)
111
      print(" %s ==>\n   %s" % (src, dst))
112
113
  removal_list = s.result.files_to_remove
114
  if len(removal_list) == 0:
115
    print("\nNo files to be deleted")
116
  else:
117
    print("\nFiles to be deleted:")
118
    print("".join((" %s\n" % patch) for patch in removal_list))
119
120
@subcommand.Command("status", " <patchname>")
121
def cmd_status(options, args):
122
  """Display the status of a patch in both patch queues"""
123
  if len(args) is not 1:
124
    print("You must specify the filename of one patch", file=sys.stderr)
125
    sys.exit(1)
126
127
  # XXX: Handle full paths?
128
  filename = args[0]
129
130
  s = SourcePatchSeries()
131
  h = HgPatchSeries()
132
  o = OldPatchSeries()
133
134
  src_patch = s[filename] if filename in s else None
135
  hg_patch = h[filename] if filename in h else None
136
  old_patch = o[filename] if filename in o else None
137
138
  if not src_patch and not hg_patch and not old_patch:
139
    print("The specified patch name '%s' cannot be found" % filename,
140
          file=sys.stderr)
141
    sys.exit(1)
142
143
  print("Status of '%s':"  % filename)
144
145
  def get_status(patch):
146
    status = ""
147
    if patch:
148
      if not old_patch:
149
        status = "new"
150
      elif old_patch.checksum != patch.checksum:
151
        status = "modified"
152
      else:
153
        status = "unmodified"
154
      status += " (active)" if patch.active else " (inactive)"
155
    else:
156
      if old_patch:
157
        status = "deleted"
158
      else:
159
        status = "missing"
160
    return status
161
162
  print("Bzr:      %s" % get_status(src_patch))
163
  print("Chromium: %s" % get_status(hg_patch))
164
165
@subcommand.Command("conflicts")
166
def cmd_conflicts(options, args):
167
  """Display a list of conflicts.
168
169
  This command outputs a list of patches that "sync" cannot automatically
170
  resolve.
171
  """
172
173
  try:
174
    s = SyncablePatchSet()
175
    s.calculate_sync()
176
  except SyncError:
177
    pass
178
  else:
179
    print("There are no conflicts")
180
    return
181
182
  if not s.result:
183
    print("The series files could not be merged, please see the results of "
184
          "the attempted merge below:")
185
    try:
186
      print("")
187
      CheckCall(["diff3", "--merge",
188
                 s.src_patches.series,
189
                 os.path.join(s.hg_patches.patchdir, ".series.orig"),
190
                 s.hg_patches.series])
191
      print("")
192
    except:
193
      pass
194
    return
195
196
  print("The following patches have been modified in both Chromium and Bzr, "
197
        "so it is not possible to determine which copy to keep:")
198
  print("".join((" %s\n" % conflict) for conflict in s.result.conflicts))
199
200
@subcommand.Command("resolve", " [patchname]")
201
@subcommand.CommandOption("--use-bzr", dest="use_bzr", action="store_true",
202
                          help="Save the copy of the specified patch that is "
203
                               "stored in Bzr")
204
@subcommand.CommandOption("--use-chromium", dest="use_chromium",
205
                          action="store_true",
206
                          help="Save the copy of the specified patch that is "
207
                               "stored in your Chromium checkout")
208
def cmd_resolve(options, args):
209
  """Resolve a conflict.
210
211
  Manually specify a resolution for a conflict.
212
  """
213
214
  if not options.use_bzr and not options.use_chromium:
215
    print("You must specify either --use-bzr or --use-chromium",
216
          file=sys.stderr)
217
    sys.exit(1)
218
219
  if len(args) != 1:
220
    print("Please specify the name of one patch", file=sys.stderr)
221
    sys.exit(1)
222
223
  try:
224
    s = SyncablePatchSet()
225
    s.calculate_sync()
226
  except:
227
    pass
228
  else:
229
    print("There are no conflicts to resolve", file=sys.stderr)
230
    sys.exit(1)
231
232
  if not s.result:
233
    print("This tool can currently only resolve conflicts in individual "
234
          "patches", file=sys.stderr)
235
    sys.exit(1)
236
237
  patch = None
238
  for filename in s.result.conflicts:
239
    if filename != args[0]:
240
      continue
241
242
    patch = s.result.patches[filename]
243
    break
244
245
  if not patch:
246
    print("The specified patch was not in the list of conflicts",
247
          file=sys.stderr)
248
    sys.exit(1)
249
250
  if options.use_chromium:
251
    src_file = os.path.join(s.hg_patches.patchdir, filename)
252
    dst = s.src_patches.patchdir
253
  else:
254
    assert options.use_bzr
255
    src_file = os.path.join(s.src_patches.patchdir, filename)
256
    dst = s.hg_patches.patchdir
257
    hg_patch = s.hg_patches[filename] if filename in s.hg_patches else None
258
    if hg_patch.applied:
259
      index = s.hg_patches.index(hg_patch) - 1
260
      s.hg_patches.top_patch = None if index == -1 else s.hg_patches[index]
261
262
  shutil.copy2(src_file, dst)
263
  new_checksum = GetFileChecksum(src_file)
264
265
  checksum_content = StringIO()
266
  for patch in s.old_patches:
267
    checksum_content.write("%s:%s\n" %
268
        (patch.filename,
269
         patch.checksum if patch.filename != filename else new_checksum))
270
271
  checksum_content.seek(0)
272
  with open(os.path.join(s.hg_patches.patchdir,
273
                         ".series.checksums"), "w") as fd:
274
    fd.write(checksum_content.read())
275
276
def main():
277
  return subcommand.Dispatcher.execute(sys.argv[1:], OptionParser())
278
279
if __name__ == "__main__":
280
  sys.exit(main())