Home | History | Annotate | Download | only in releasetools
      1 #!/usr/bin/env python
      2 #
      3 # Copyright (C) 2008 The Android Open Source Project
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #      http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """
     18 Given a target-files zipfile, produces an image zipfile suitable for
     19 use with 'fastboot update'.
     20 
     21 Usage:  img_from_target_files [flags] input_target_files output_image_zip
     22 
     23   -z  (--bootable_zip)
     24       Include only the bootable images (eg 'boot' and 'recovery') in
     25       the output.
     26 
     27 """
     28 
     29 import sys
     30 
     31 if sys.hexversion < 0x02070000:
     32   print >> sys.stderr, "Python 2.7 or newer is required."
     33   sys.exit(1)
     34 
     35 import os
     36 import shutil
     37 import zipfile
     38 
     39 import common
     40 
     41 OPTIONS = common.OPTIONS
     42 
     43 
     44 def CopyInfo(output_zip):
     45   """Copy the android-info.txt file from the input to the output."""
     46   common.ZipWrite(
     47       output_zip, os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
     48       "android-info.txt")
     49 
     50 
     51 def main(argv):
     52   bootable_only = [False]
     53 
     54   def option_handler(o, _):
     55     if o in ("-z", "--bootable_zip"):
     56       bootable_only[0] = True
     57     else:
     58       return False
     59     return True
     60 
     61   args = common.ParseOptions(argv, __doc__,
     62                              extra_opts="z",
     63                              extra_long_opts=["bootable_zip"],
     64                              extra_option_handler=option_handler)
     65 
     66   bootable_only = bootable_only[0]
     67 
     68   if len(args) != 2:
     69     common.Usage(__doc__)
     70     sys.exit(1)
     71 
     72   OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
     73   output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
     74   CopyInfo(output_zip)
     75 
     76   try:
     77     done = False
     78     images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
     79     if os.path.exists(images_path):
     80       # If this is a new target-files, it already contains the images,
     81       # and all we have to do is copy them to the output zip.
     82       images = os.listdir(images_path)
     83       if images:
     84         for image in images:
     85           if bootable_only and image not in ("boot.img", "recovery.img"):
     86             continue
     87           if not image.endswith(".img"):
     88             continue
     89           common.ZipWrite(
     90               output_zip, os.path.join(images_path, image), image)
     91         done = True
     92 
     93     if not done:
     94       # We have an old target-files that doesn't already contain the
     95       # images, so build them.
     96       import add_img_to_target_files
     97 
     98       OPTIONS.info_dict = common.LoadInfoDict(input_zip)
     99 
    100       # If this image was originally labelled with SELinux contexts,
    101       # make sure we also apply the labels in our new image. During
    102       # building, the "file_contexts" is in the out/ directory tree,
    103       # but for repacking from target-files.zip it's in the root
    104       # directory of the ramdisk.
    105       if "selinux_fc" in OPTIONS.info_dict:
    106         OPTIONS.info_dict["selinux_fc"] = os.path.join(
    107             OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
    108 
    109       boot_image = common.GetBootableImage(
    110           "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
    111       if boot_image:
    112         boot_image.AddToZip(output_zip)
    113       recovery_image = common.GetBootableImage(
    114           "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
    115       if recovery_image:
    116         recovery_image.AddToZip(output_zip)
    117 
    118       def banner(s):
    119         print "\n\n++++ " + s + " ++++\n\n"
    120 
    121       if not bootable_only:
    122         banner("AddSystem")
    123         add_img_to_target_files.AddSystem(output_zip, prefix="")
    124         try:
    125           input_zip.getinfo("VENDOR/")
    126           banner("AddVendor")
    127           add_img_to_target_files.AddVendor(output_zip, prefix="")
    128         except KeyError:
    129           pass   # no vendor partition for this device
    130         banner("AddUserdata")
    131         add_img_to_target_files.AddUserdata(output_zip, prefix="")
    132         banner("AddCache")
    133         add_img_to_target_files.AddCache(output_zip, prefix="")
    134 
    135   finally:
    136     print "cleaning up..."
    137     common.ZipClose(output_zip)
    138     shutil.rmtree(OPTIONS.input_tmp)
    139 
    140   print "done."
    141 
    142 
    143 if __name__ == '__main__':
    144   try:
    145     common.CloseInheritedPipes()
    146     main(sys.argv[1:])
    147   except common.ExternalError as e:
    148     print
    149     print "   ERROR: %s" % (e,)
    150     print
    151     sys.exit(1)
    152