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
This commit is contained in:
commit
8ae62ec722
|
@ -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 @@ class DeviceSpecificParams(object):
|
|||
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()
|
||||
|
|
|
@ -59,7 +59,6 @@ import re
|
|||
import sha
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
|
@ -308,7 +307,7 @@ def MakeRecoveryPatch(output_zip, recovery_img, boot_img):
|
|||
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 @@ def WriteFullOTAPackage(input_zip, output_zip):
|
|||
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 @@ def WriteMetadata(metadata, output_zip):
|
|||
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 @@ def LoadSystemFiles(z):
|
|||
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 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||
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 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||
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 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip):
|
|||
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))
|
||||
|
|
Loading…
Reference in New Issue