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 errno
     36 import os
     37 import re
     38 import shutil
     39 import subprocess
     40 import tempfile
     41 import zipfile
     42 
     43 # missing in Python 2.4 and before
     44 if not hasattr(os, "SEEK_SET"):
     45   os.SEEK_SET = 0
     46 
     47 import common
     48 
     49 OPTIONS = common.OPTIONS
     50 
     51 
     52 def CopyInfo(output_zip):
     53   """Copy the android-info.txt file from the input to the output."""
     54   output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
     55                    "android-info.txt")
     56 
     57 
     58 def main(argv):
     59   bootable_only = [False]
     60 
     61   def option_handler(o, a):
     62     if o in ("-z", "--bootable_zip"):
     63       bootable_only[0] = True
     64     else:
     65       return False
     66     return True
     67 
     68   args = common.ParseOptions(argv, __doc__,
     69                              extra_opts="z",
     70                              extra_long_opts=["bootable_zip"],
     71                              extra_option_handler=option_handler)
     72 
     73   bootable_only = bootable_only[0]
     74 
     75   if len(args) != 2:
     76     common.Usage(__doc__)
     77     sys.exit(1)
     78 
     79   OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
     80   output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
     81   CopyInfo(output_zip)
     82 
     83   try:
     84     done = False
     85     images_path = os.path.join(OPTIONS.input_tmp, "IMAGES")
     86     if os.path.exists(images_path):
     87       # If this is a new target-files, it already contains the images,
     88       # and all we have to do is copy them to the output zip.
     89       images = os.listdir(images_path)
     90       if images:
     91         for i in images:
     92           if bootable_only and i not in ("boot.img", "recovery.img"): continue
     93           if not i.endswith(".img"): continue
     94           with open(os.path.join(images_path, i), "r") as f:
     95             common.ZipWriteStr(output_zip, i, f.read())
     96         done = True
     97 
     98     if not done:
     99       # We have an old target-files that doesn't already contain the
    100       # images, so build them.
    101       import add_img_to_target_files
    102 
    103       OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    104 
    105       # If this image was originally labelled with SELinux contexts,
    106       # make sure we also apply the labels in our new image. During
    107       # building, the "file_contexts" is in the out/ directory tree,
    108       # but for repacking from target-files.zip it's in the root
    109       # directory of the ramdisk.
    110       if "selinux_fc" in OPTIONS.info_dict:
    111         OPTIONS.info_dict["selinux_fc"] = os.path.join(
    112             OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts")
    113 
    114       boot_image = common.GetBootableImage(
    115           "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT")
    116       if boot_image:
    117           boot_image.AddToZip(output_zip)
    118       recovery_image = common.GetBootableImage(
    119           "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY")
    120       if recovery_image:
    121         recovery_image.AddToZip(output_zip)
    122 
    123       def banner(s):
    124         print "\n\n++++ " + s + " ++++\n\n"
    125 
    126       if not bootable_only:
    127         banner("AddSystem")
    128         add_img_to_target_files.AddSystem(output_zip, prefix="")
    129         try:
    130           input_zip.getinfo("VENDOR/")
    131           banner("AddVendor")
    132           add_img_to_target_files.AddVendor(output_zip, prefix="")
    133         except KeyError:
    134           pass   # no vendor partition for this device
    135         banner("AddUserdata")
    136         add_img_to_target_files.AddUserdata(output_zip, prefix="")
    137         banner("AddCache")
    138         add_img_to_target_files.AddCache(output_zip, prefix="")
    139 
    140   finally:
    141     print "cleaning up..."
    142     output_zip.close()
    143     shutil.rmtree(OPTIONS.input_tmp)
    144 
    145   print "done."
    146 
    147 
    148 if __name__ == '__main__':
    149   try:
    150     common.CloseInheritedPipes()
    151     main(sys.argv[1:])
    152   except common.ExternalError, e:
    153     print
    154     print "   ERROR: %s" % (e,)
    155     print
    156     sys.exit(1)
    157