edify_generator.py revision 14833605d26bf970cd5335c02af4354b68d93348
1c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Copyright (C) 2009 The Android Open Source Project
2c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
3c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Licensed under the Apache License, Version 2.0 (the "License");
4c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# you may not use this file except in compliance with the License.
5c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# You may obtain a copy of the License at
6c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
7c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#      http://www.apache.org/licenses/LICENSE-2.0
8c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
9c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Unless required by applicable law or agreed to in writing, software
10c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# distributed under the License is distributed on an "AS IS" BASIS,
11c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# See the License for the specific language governing permissions and
13c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# limitations under the License.
14c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
15c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport os
16c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport re
17c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
18c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport common
19c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
20c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerclass EdifyGenerator(object):
21c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  """Class to generate scripts in the 'edify' recovery script language
22c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  used from donut onwards."""
23c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
24c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def __init__(self, version):
25c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script = []
26c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.mounts = set()
27c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.version = version
28c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
29c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def MakeTemporary(self):
30c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Make a temporary script object whose commands can latter be
31c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    appended to the parent script with AppendScript().  Used when the
32c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    caller wants to generate script commands out-of-order."""
33c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    x = EdifyGenerator(self.version)
34c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    x.mounts = self.mounts
35c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    return x
36c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
37c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  @staticmethod
38c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def _WordWrap(cmd, linelen=80):
39c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """'cmd' should be a function call with null characters after each
40c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    parameter (eg, "somefun(foo,\0bar,\0baz)").  This function wraps cmd
41c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    to a given line length, replacing nulls with spaces and/or newlines
42c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    to format it nicely."""
43c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    indent = cmd.index("(")+1
44c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    out = []
45c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    first = True
46c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    x = re.compile("^(.{,%d})\0" % (linelen-indent,))
47c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    while True:
48c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      if not first:
49c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        out.append(" " * indent)
50c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      first = False
51c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      m = x.search(cmd)
52c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      if not m:
53c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        parts = cmd.split("\0", 1)
54c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        out.append(parts[0]+"\n")
55c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        if len(parts) == 1:
56c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          break
57c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        else:
58c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          cmd = parts[1]
59c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          continue
60c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      out.append(m.group(1)+"\n")
61c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      cmd = cmd[m.end():]
62c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
63c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    return "".join(out).replace("\0", " ").rstrip("\n")
64c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
65c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AppendScript(self, other):
66c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Append the contents of another script (which should be created
67c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    with temporary=True) to this one."""
68c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.extend(other.script)
69c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
70c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertSomeFingerprint(self, *fp):
71c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the current system build fingerprint is one of *fp."""
72c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if not fp:
73c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      raise ValueError("must specify some fingerprints")
74c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ('assert(' +
75c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           ' ||\0'.join([('file_getprop("/system/build.prop", '
76c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         '"ro.build.fingerprint") == "%s"')
77c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                        % i for i in fp]) +
78c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           ');')
79c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
80c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
81c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertOlderBuild(self, timestamp):
82c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the build on the device is older (or the same as)
83c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    the given timestamp."""
84c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(('assert(!less_than_int(%s, '
85c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                        'getprop("ro.build.date.utc")));') % (timestamp,))
86c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
87c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertDevice(self, device):
88c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the device identifier is the given string."""
89c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ('assert(getprop("ro.product.device") == "%s" ||\0'
90c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           'getprop("ro.build.product") == "%s");' % (device, device))
91c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
92c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
93c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertSomeBootloader(self, *bootloaders):
94c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Asert that the bootloader version is one of *bootloaders."""
95c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ("assert(" +
96c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,)
97c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         for b in bootloaders]) +
98c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           ");")
99c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
100c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
101c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def ShowProgress(self, frac, dur):
102c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Update the progress bar, advancing it over 'frac' over the next
103881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    'dur' seconds.  'dur' may be zero to advance it via SetProgress
104881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    commands instead of by time."""
105c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("show_progress(%f, %d);" % (frac, int(dur)))
106c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
107881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  def SetProgress(self, frac):
108881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    """Set the position of the progress bar within the chunk defined
109881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    by the most recent ShowProgress call.  'frac' should be in
110881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    [0,1]."""
111881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    self.script.append("set_progress(%f);" % (frac,))
112881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
113c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def PatchCheck(self, filename, *sha1):
114c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Check that the given file (or MTD reference) has one of the
115c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    given *sha1 hashes."""
116c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('assert(apply_patch_check("%s"' % (filename,) +
117c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       "".join([', "%s"' % (i,) for i in sha1]) +
118c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       '));')
119c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
120c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def CacheFreeSpaceCheck(self, amount):
121c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Check that there's at least 'amount' space that can be made
122c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    available on /cache."""
123c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("assert(apply_patch_space(%d));" % (amount,))
124c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
125c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def Mount(self, kind, what, path):
126c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Mount the given 'what' at the given path.  'what' should be a
127c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    partition name if kind is "MTD", or a block device if kind is
128c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    "vfat".  No other values of 'kind' are supported."""
129c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('mount("%s", "%s", "%s");' % (kind, what, path))
130c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.mounts.add(path)
131c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
132c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def UnpackPackageDir(self, src, dst):
133c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Unpack a given directory from the OTA package into the given
134c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    destination directory."""
135c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('package_extract_dir("%s", "%s");' % (src, dst))
136c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
137c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def Comment(self, comment):
138c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Write a comment into the update script."""
139c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("")
140c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for i in comment.split("\n"):
141c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append("# " + i)
142c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("")
143c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
144c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def Print(self, message):
145c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Log a message to the screen (if the logs are visible)."""
146c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('ui_print("%s");' % (message,))
147c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
148c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def FormatPartition(self, partition):
149c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Format the given MTD partition."""
150c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('format("MTD", "%s");' % (partition,))
151c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
152c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def DeleteFiles(self, file_list):
153c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Delete all files in file_list."""
154c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if not file_list: return
155c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");"
156c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
157c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
158c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
159c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Apply binary patches (in *patchpairs) to the given srcfile to
160c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    produce tgtfile (which may be "-" to indicate overwriting the
161c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    source file."""
162c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if len(patchpairs) % 2 != 0 or len(patchpairs) == 0:
163c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      raise ValueError("bad patches given to ApplyPatch")
164c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d'
165c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           % (srcfile, tgtfile, tgtsha1, tgtsize)]
166c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for i in range(0, len(patchpairs), 2):
167c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      cmd.append(',\0"%s:%s"' % patchpairs[i:i+2])
168c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd.append(');')
169c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = "".join(cmd)
170c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
171c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
172c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def WriteFirmwareImage(self, kind, fn):
173c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Arrange to update the given firmware image (kind must be
174c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    "hboot" or "radio") when recovery finishes."""
175c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if self.version == 1:
176c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append(
177c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          ('assert(package_extract_file("%(fn)s", "/tmp/%(kind)s.img"),\n'
178c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           '       write_firmware_image("/tmp/%(kind)s.img", "%(kind)s"));')
179c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          % {'kind': kind, 'fn': fn})
180c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    else:
181c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append(
182c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          'write_firmware_image("PACKAGE:%s", "%s");' % (fn, kind))
183c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
184c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def WriteRawImage(self, partition, fn):
185c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Write the given package file into the given MTD partition."""
186c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(
187c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        ('assert(package_extract_file("%(fn)s", "/tmp/%(partition)s.img"),\n'
188c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker         '       write_raw_image("/tmp/%(partition)s.img", "%(partition)s"),\n'
189c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker         '       delete("/tmp/%(partition)s.img"));')
190c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        % {'partition': partition, 'fn': fn})
191c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
192c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def SetPermissions(self, fn, uid, gid, mode):
193c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Set file ownership and permissions."""
194c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn))
195c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
196c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode):
197c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Recursively set path ownership and permissions."""
198c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");'
199c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       % (uid, gid, dmode, fmode, fn))
200c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
201c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def MakeSymlinks(self, symlink_list):
202c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Create symlinks, given a list of (dest, link) pairs."""
203c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    by_dest = {}
204c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for d, l in symlink_list:
205c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      by_dest.setdefault(d, []).append(l)
206c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
207c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for dest, links in sorted(by_dest.iteritems()):
208c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      cmd = ('symlink("%s", ' % (dest,) +
209c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker             ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
210c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append(self._WordWrap(cmd))
211c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
212c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AppendExtra(self, extra):
213c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Append text verbatim to the output script."""
214c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(extra)
215c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
21614833605d26bf970cd5335c02af4354b68d93348Doug Zongker  def UnmountAll(self):
21714833605d26bf970cd5335c02af4354b68d93348Doug Zongker    for p in sorted(self.mounts):
21814833605d26bf970cd5335c02af4354b68d93348Doug Zongker      self.script.append('unmount("%s");' % (p,))
21914833605d26bf970cd5335c02af4354b68d93348Doug Zongker    self.mounts = set()
22014833605d26bf970cd5335c02af4354b68d93348Doug Zongker
221c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AddToZip(self, input_zip, output_zip, input_path=None):
222c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Write the accumulated script to the output_zip file.  input_zip
223c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    is used as the source for the 'updater' binary needed to run
224c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.  If input_path is not None, it will be used as a local
225c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    path for the binary instead of input_zip."""
226c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
22714833605d26bf970cd5335c02af4354b68d93348Doug Zongker    self.UnmountAll()
228c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
229c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
230c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       "\n".join(self.script) + "\n")
231c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
232c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if input_path is None:
233c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      data = input_zip.read("OTA/bin/updater")
234c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    else:
235c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      data = open(os.path.join(input_path, "updater")).read()
236c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
237c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       data, perms=0755)
238