OSDN Git Service

DRC23
[android-x86/build.git] / tools / releasetools / amend_generator.py
1 # Copyright (C) 2009 The Android Open Source Project
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 import os
16
17 import common
18
19 class AmendGenerator(object):
20   """Class to generate scripts in the 'amend' recovery script language
21   used up through cupcake."""
22
23   def __init__(self):
24     self.script = ['assert compatible_with("0.2") == "true"']
25     self.included_files = set()
26
27   def MakeTemporary(self):
28     """Make a temporary script object whose commands can latter be
29     appended to the parent script with AppendScript().  Used when the
30     caller wants to generate script commands out-of-order."""
31     x = AmendGenerator()
32     x.script = []
33     x.included_files = self.included_files
34     return x
35
36   @staticmethod
37   def _FileRoot(fn):
38     """Convert a file path to the 'root' notation used by amend."""
39     if fn.startswith("/system/"):
40       return "SYSTEM:" + fn[8:]
41     elif fn == "/system":
42       return "SYSTEM:"
43     elif fn.startswith("/tmp/"):
44       return "CACHE:.." + fn
45     else:
46       raise ValueError("don't know root for \"%s\"" % (fn,))
47
48   @staticmethod
49   def _PartitionRoot(partition):
50     """Convert a partition name to the 'root' notation used by amend."""
51     if partition == "userdata":
52       return "DATA:"
53     else:
54       return partition.upper() + ":"
55
56   def AppendScript(self, other):
57     """Append the contents of another script (which should be created
58     with temporary=True) to this one."""
59     self.script.extend(other.script)
60     self.included_files.update(other.included_files)
61
62   def AssertSomeFingerprint(self, *fp):
63     """Assert that the current fingerprint is one of *fp."""
64     x = [('file_contains("SYSTEM:build.prop", '
65           '"ro.build.fingerprint=%s") == "true"') % i for i in fp]
66     self.script.append("assert %s" % (" || ".join(x),))
67
68   def AssertOlderBuild(self, timestamp):
69     """Assert that the build on the device is older (or the same as)
70     the given timestamp."""
71     self.script.append("run_program PACKAGE:check_prereq %s" % (timestamp,))
72     self.included_files.add("check_prereq")
73
74   def AssertDevice(self, device):
75     """Assert that the device identifier is the given string."""
76     self.script.append('assert getprop("ro.product.device") == "%s" || '
77                        'getprop("ro.build.product") == "%s"' % (device, device))
78
79   def AssertSomeBootloader(self, *bootloaders):
80     """Asert that the bootloader version is one of *bootloaders."""
81     self.script.append("assert " +
82                   " || ".join(['getprop("ro.bootloader") == "%s"' % (b,)
83                                for b in bootloaders]))
84
85   def ShowProgress(self, frac, dur):
86     """Update the progress bar, advancing it over 'frac' over the next
87     'dur' seconds."""
88     self.script.append("show_progress %f %d" % (frac, int(dur)))
89
90   def PatchCheck(self, filename, *sha1):
91     """Check that the given file (or MTD reference) has one of the
92     given *sha1 hashes."""
93     out = ["run_program PACKAGE:applypatch -c %s" % (filename,)]
94     for i in sha1:
95       out.append(" " + i)
96     self.script.append("".join(out))
97     self.included_files.add("applypatch")
98
99   def CacheFreeSpaceCheck(self, amount):
100     """Check that there's at least 'amount' space that can be made
101     available on /cache."""
102     self.script.append("run_program PACKAGE:applypatch -s %d" % (amount,))
103     self.included_files.add("applypatch")
104
105   def Mount(self, kind, what, path):
106     # no-op; amend uses it's 'roots' system to automatically mount
107     # things when they're referred to
108     pass
109
110   def UnpackPackageDir(self, src, dst):
111     """Unpack a given directory from the OTA package into the given
112     destination directory."""
113     dst = self._FileRoot(dst)
114     self.script.append("copy_dir PACKAGE:%s %s" % (src, dst))
115
116   def Comment(self, comment):
117     """Write a comment into the update script."""
118     self.script.append("")
119     for i in comment.split("\n"):
120       self.script.append("# " + i)
121     self.script.append("")
122
123   def Print(self, message):
124     """Log a message to the screen (if the logs are visible)."""
125     # no way to do this from amend; substitute a script comment instead
126     self.Comment(message)
127
128   def FormatPartition(self, partition):
129     """Format the given MTD partition."""
130     self.script.append("format %s" % (self._PartitionRoot(partition),))
131
132   def DeleteFiles(self, file_list):
133     """Delete all files in file_list."""
134     line = []
135     t = 0
136     for i in file_list:
137       i = self._FileRoot(i)
138       line.append(i)
139       t += len(i) + 1
140       if t > 80:
141         self.script.append("delete " + " ".join(line))
142         line = []
143         t = 0
144     if line:
145       self.script.append("delete " + " ".join(line))
146
147   def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
148     """Apply binary patches (in *patchpairs) to the given srcfile to
149     produce tgtfile (which may be "-" to indicate overwriting the
150     source file."""
151     if len(patchpairs) % 2 != 0:
152       raise ValueError("bad patches given to ApplyPatch")
153     self.script.append(
154         ("run_program PACKAGE:applypatch %s %s %s %d " %
155          (srcfile, tgtfile, tgtsha1, tgtsize)) +
156         " ".join(["%s:%s" % patchpairs[i:i+2]
157                   for i in range(0, len(patchpairs), 2)]))
158     self.included_files.add("applypatch")
159
160   def WriteFirmwareImage(self, kind, fn):
161     """Arrange to update the given firmware image (kind must be
162     "hboot" or "radio") when recovery finishes."""
163     self.script.append("write_%s_image PACKAGE:%s" % (kind, fn))
164
165   def WriteRawImage(self, partition, fn):
166     """Write the given file into the given MTD partition."""
167     self.script.append("write_raw_image PACKAGE:%s %s" %
168                        (fn, self._PartitionRoot(partition)))
169
170   def SetPermissions(self, fn, uid, gid, mode):
171     """Set file ownership and permissions."""
172     fn = self._FileRoot(fn)
173     self.script.append("set_perm %d %d 0%o %s" % (uid, gid, mode, fn))
174
175   def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode):
176     """Recursively set path ownership and permissions."""
177     fn = self._FileRoot(fn)
178     self.script.append("set_perm_recursive %d %d 0%o 0%o %s" %
179                        (uid, gid, dmode, fmode, fn))
180
181   def MakeSymlinks(self, symlink_list):
182     """Create symlinks, given a list of (dest, link) pairs."""
183     self.script.extend(["symlink %s %s" % (i[0], self._FileRoot(i[1]))
184                         for i in sorted(symlink_list)])
185
186   def AppendExtra(self, extra):
187     """Append text verbatim to the output script."""
188     self.script.append(extra)
189
190   def AddToZip(self, input_zip, output_zip, input_path=None):
191     """Write the accumulated script to the output_zip file.  input_zip
192     is used as the source for any ancillary binaries needed by the
193     script.  If input_path is not None, it will be used as a local
194     path for binaries instead of input_zip."""
195     common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-script",
196                        "\n".join(self.script) + "\n")
197     for i in self.included_files:
198       try:
199         if input_path is None:
200           data = input_zip.read(os.path.join("OTA/bin", i))
201         else:
202           data = open(os.path.join(input_path, i)).read()
203         common.ZipWriteStr(output_zip, i, data, perms=0755)
204       except (IOError, KeyError), e:
205         raise ExternalError("unable to include binary %s: %s" % (i, e))