am ea5d7a9d: move File and Difference classes into common script
Merge commit 'ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6' into gingerbread-plus-aosp
* commit 'ea5d7a9de7660bef5b9c68f6372a92d4b2f2f1f6':
move File and Difference classes into common script
diff --git a/tools/releasetools/common.py b/tools/releasetools/common.py
index 6bb37ae..46cef11 100644
--- a/tools/releasetools/common.py
+++ b/tools/releasetools/common.py
@@ -12,16 +12,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import copy
import errno
import getopt
import getpass
import imp
import os
import re
+import sha
import shutil
import subprocess
import sys
import tempfile
+import threading
+import time
import zipfile
# missing in Python 2.4 and before
@@ -547,3 +551,124 @@
this is used to install the image for the device's baseband
processor."""
return self._DoCall("IncrementalOTA_InstallEnd")
+
+class File(object):
+ def __init__(self, name, data):
+ self.name = name
+ self.data = data
+ self.size = len(data)
+ self.sha1 = sha.sha(data).hexdigest()
+
+ def WriteToTemp(self):
+ t = tempfile.NamedTemporaryFile()
+ t.write(self.data)
+ t.flush()
+ return t
+
+ def AddToZip(self, z):
+ ZipWriteStr(z, self.name, self.data)
+
+DIFF_PROGRAM_BY_EXT = {
+ ".gz" : "imgdiff",
+ ".zip" : ["imgdiff", "-z"],
+ ".jar" : ["imgdiff", "-z"],
+ ".apk" : ["imgdiff", "-z"],
+ ".img" : "imgdiff",
+ }
+
+class Difference(object):
+ def __init__(self, tf, sf):
+ self.tf = tf
+ self.sf = sf
+ self.patch = None
+
+ def ComputePatch(self):
+ """Compute the patch (as a string of data) needed to turn sf into
+ tf. Returns the same tuple as GetPatch()."""
+
+ tf = self.tf
+ sf = self.sf
+
+ ext = os.path.splitext(tf.name)[1]
+ diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff")
+
+ ttemp = tf.WriteToTemp()
+ stemp = sf.WriteToTemp()
+
+ ext = os.path.splitext(tf.name)[1]
+
+ try:
+ ptemp = tempfile.NamedTemporaryFile()
+ if isinstance(diff_program, list):
+ cmd = copy.copy(diff_program)
+ else:
+ cmd = [diff_program]
+ cmd.append(stemp.name)
+ cmd.append(ttemp.name)
+ cmd.append(ptemp.name)
+ p = Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ _, err = p.communicate()
+ if err or p.returncode != 0:
+ print "WARNING: failure running %s:\n%s\n" % (diff_program, err)
+ return None
+ diff = ptemp.read()
+ finally:
+ ptemp.close()
+ stemp.close()
+ ttemp.close()
+
+ self.patch = diff
+ return self.tf, self.sf, self.patch
+
+
+ def GetPatch(self):
+ """Return a tuple (target_file, source_file, patch_data).
+ patch_data may be None if ComputePatch hasn't been called, or if
+ computing the patch failed."""
+ return self.tf, self.sf, self.patch
+
+
+def ComputeDifferences(diffs):
+ """Call ComputePatch on all the Difference objects in 'diffs'."""
+ print len(diffs), "diffs to compute"
+
+ # Do the largest files first, to try and reduce the long-pole effect.
+ by_size = [(i.tf.size, i) for i in diffs]
+ by_size.sort(reverse=True)
+ by_size = [i[1] for i in by_size]
+
+ lock = threading.Lock()
+ diff_iter = iter(by_size) # accessed under lock
+
+ def worker():
+ try:
+ lock.acquire()
+ for d in diff_iter:
+ lock.release()
+ start = time.time()
+ d.ComputePatch()
+ dur = time.time() - start
+ lock.acquire()
+
+ tf, sf, patch = d.GetPatch()
+ if sf.name == tf.name:
+ name = tf.name
+ else:
+ name = "%s (%s)" % (tf.name, sf.name)
+ if patch is None:
+ print "patching failed! %s" % (name,)
+ else:
+ print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % (
+ dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name)
+ lock.release()
+ except Exception, e:
+ print e
+ raise
+
+ # start worker threads; wait for them all to finish.
+ threads = [threading.Thread(target=worker)
+ for i in range(OPTIONS.worker_threads)]
+ for th in threads:
+ th.start()
+ while threads:
+ threads.pop().join()
diff --git a/tools/releasetools/ota_from_target_files b/tools/releasetools/ota_from_target_files
index 29911bb..ad7e0e4 100755
--- a/tools/releasetools/ota_from_target_files
+++ b/tools/releasetools/ota_from_target_files
@@ -59,7 +59,6 @@
import sha
import subprocess
import tempfile
-import threading
import time
import zipfile
@@ -308,7 +307,7 @@
executable.
"""
- d = Difference(recovery_img, boot_img)
+ d = common.Difference(recovery_img, boot_img)
_, _, patch = d.ComputePatch()
common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch)
Item.Get("system/recovery-from-boot.p", dir=False)
@@ -374,9 +373,9 @@
symlinks = CopySystemFiles(input_zip, output_zip)
script.MakeSymlinks(symlinks)
- boot_img = File("boot.img", common.BuildBootableImage(
+ boot_img = common.File("boot.img", common.BuildBootableImage(
os.path.join(OPTIONS.input_tmp, "BOOT")))
- recovery_img = File("recovery.img", common.BuildBootableImage(
+ recovery_img = common.File("recovery.img", common.BuildBootableImage(
os.path.join(OPTIONS.input_tmp, "RECOVERY")))
MakeRecoveryPatch(output_zip, recovery_img, boot_img)
@@ -407,21 +406,6 @@
for kv in sorted(metadata.iteritems())]))
-class File(object):
- def __init__(self, name, data):
- self.name = name
- self.data = data
- self.size = len(data)
- self.sha1 = sha.sha(data).hexdigest()
-
- def WriteToTemp(self):
- t = tempfile.NamedTemporaryFile()
- t.write(self.data)
- t.flush()
- return t
-
- def AddToZip(self, z):
- common.ZipWriteStr(z, self.name, self.data)
def LoadSystemFiles(z):
@@ -432,117 +416,10 @@
if info.filename.startswith("SYSTEM/") and not IsSymlink(info):
fn = "system/" + info.filename[7:]
data = z.read(info.filename)
- out[fn] = File(fn, data)
+ out[fn] = common.File(fn, data)
return out
-DIFF_PROGRAM_BY_EXT = {
- ".gz" : "imgdiff",
- ".zip" : ["imgdiff", "-z"],
- ".jar" : ["imgdiff", "-z"],
- ".apk" : ["imgdiff", "-z"],
- ".img" : "imgdiff",
- }
-
-
-class Difference(object):
- def __init__(self, tf, sf):
- self.tf = tf
- self.sf = sf
- self.patch = None
-
- def ComputePatch(self):
- """Compute the patch (as a string of data) needed to turn sf into
- tf. Returns the same tuple as GetPatch()."""
-
- tf = self.tf
- sf = self.sf
-
- ext = os.path.splitext(tf.name)[1]
- diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff")
-
- ttemp = tf.WriteToTemp()
- stemp = sf.WriteToTemp()
-
- ext = os.path.splitext(tf.name)[1]
-
- try:
- ptemp = tempfile.NamedTemporaryFile()
- if isinstance(diff_program, list):
- cmd = copy.copy(diff_program)
- else:
- cmd = [diff_program]
- cmd.append(stemp.name)
- cmd.append(ttemp.name)
- cmd.append(ptemp.name)
- p = common.Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- _, err = p.communicate()
- if err or p.returncode != 0:
- print "WARNING: failure running %s:\n%s\n" % (diff_program, err)
- return None
- diff = ptemp.read()
- finally:
- ptemp.close()
- stemp.close()
- ttemp.close()
-
- self.patch = diff
- return self.tf, self.sf, self.patch
-
-
- def GetPatch(self):
- """Return a tuple (target_file, source_file, patch_data).
- patch_data may be None if ComputePatch hasn't been called, or if
- computing the patch failed."""
- return self.tf, self.sf, self.patch
-
-
-def ComputeDifferences(diffs):
- """Call ComputePatch on all the Difference objects in 'diffs'."""
- print len(diffs), "diffs to compute"
-
- # Do the largest files first, to try and reduce the long-pole effect.
- by_size = [(i.tf.size, i) for i in diffs]
- by_size.sort(reverse=True)
- by_size = [i[1] for i in by_size]
-
- lock = threading.Lock()
- diff_iter = iter(by_size) # accessed under lock
-
- def worker():
- try:
- lock.acquire()
- for d in diff_iter:
- lock.release()
- start = time.time()
- d.ComputePatch()
- dur = time.time() - start
- lock.acquire()
-
- tf, sf, patch = d.GetPatch()
- if sf.name == tf.name:
- name = tf.name
- else:
- name = "%s (%s)" % (tf.name, sf.name)
- if patch is None:
- print "patching failed! %s" % (name,)
- else:
- print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % (
- dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name)
- lock.release()
- except Exception, e:
- print e
- raise
-
- # start worker threads; wait for them all to finish.
- threads = [threading.Thread(target=worker)
- for i in range(OPTIONS.worker_threads)]
- for th in threads:
- th.start()
- while threads:
- threads.pop().join()
-
-
def GetBuildProp(property, z):
"""Return the fingerprint of the build of a given target-files
ZipFile object."""
@@ -616,12 +493,12 @@
verbatim_targets.append((fn, tf.size))
elif tf.sha1 != sf.sha1:
# File is different; consider sending as a patch
- diffs.append(Difference(tf, sf))
+ diffs.append(common.Difference(tf, sf))
else:
# Target file identical to source.
pass
- ComputeDifferences(diffs)
+ common.ComputeDifferences(diffs)
for diff in diffs:
tf, sf, d = diff.GetPatch()
@@ -642,20 +519,20 @@
script.Mount("MTD", "system", "/system")
script.AssertSomeFingerprint(source_fp, target_fp)
- source_boot = File("/tmp/boot.img",
- common.BuildBootableImage(
- os.path.join(OPTIONS.source_tmp, "BOOT")))
- target_boot = File("/tmp/boot.img",
- common.BuildBootableImage(
- os.path.join(OPTIONS.target_tmp, "BOOT")))
+ source_boot = common.File("/tmp/boot.img",
+ common.BuildBootableImage(
+ os.path.join(OPTIONS.source_tmp, "BOOT")))
+ target_boot = common.File("/tmp/boot.img",
+ common.BuildBootableImage(
+ os.path.join(OPTIONS.target_tmp, "BOOT")))
updating_boot = (source_boot.data != target_boot.data)
- source_recovery = File("system/recovery.img",
- common.BuildBootableImage(
- os.path.join(OPTIONS.source_tmp, "RECOVERY")))
- target_recovery = File("system/recovery.img",
- common.BuildBootableImage(
- os.path.join(OPTIONS.target_tmp, "RECOVERY")))
+ source_recovery = common.File("system/recovery.img",
+ common.BuildBootableImage(
+ os.path.join(OPTIONS.source_tmp, "RECOVERY")))
+ target_recovery = common.File("system/recovery.img",
+ common.BuildBootableImage(
+ os.path.join(OPTIONS.target_tmp, "RECOVERY")))
updating_recovery = (source_recovery.data != target_recovery.data)
# Here's how we divide up the progress bar:
@@ -681,7 +558,7 @@
script.SetProgress(so_far / total_verify_size)
if updating_boot:
- d = Difference(target_boot, source_boot)
+ d = common.Difference(target_boot, source_boot)
_, _, d = d.ComputePatch()
print "boot target: %d source: %d diff: %d" % (
target_boot.size, source_boot.size, len(d))