summaryrefslogtreecommitdiff
path: root/apexer/apexer.py
diff options
context:
space:
mode:
authorJiyong Park <jiyong@google.com>2019-06-03 21:36:53 +0900
committerJiyong Park <jiyong@google.com>2019-06-03 21:52:47 +0900
commit34c821c86d0b054f687cd6eaf86eeeaf7e80beb1 (patch)
treef24d5d4fa0f6246d9daf2ab56e774389552e2a20 /apexer/apexer.py
parent361fed27e39378072baf6afcffeb6d0cb4f3fbe2 (diff)
Run pyformat on apexer
Test: presubmit tests Change-Id: Ifa233810fb0b78933c69a19c30f17379853c3de6
Diffstat (limited to 'apexer/apexer.py')
-rw-r--r--apexer/apexer.py208
1 files changed, 123 insertions, 85 deletions
diff --git a/apexer/apexer.py b/apexer/apexer.py
index e09e053..2fe2b7f 100644
--- a/apexer/apexer.py
+++ b/apexer/apexer.py
@@ -13,10 +13,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-
-"""
-apexer is a command line tool for creating an APEX file, a package format
-for system components.
+"""apexer is a command line tool for creating an APEX file, a package format for system components.
Typical usage: apexer input_dir output.apex
@@ -38,54 +35,81 @@ from apex_manifest import ApexManifestError
tool_path_list = None
BLOCK_SIZE = 4096
+
def ParseArgs(argv):
parser = argparse.ArgumentParser(description='Create an APEX file')
- parser.add_argument('-f', '--force', action='store_true',
- help='force overwriting output')
- parser.add_argument('-v', '--verbose', action='store_true',
- help='verbose execution')
- parser.add_argument('--manifest', default='apex_manifest.json',
- help='path to the APEX manifest file')
- parser.add_argument('--android_manifest',
- help='path to the AndroidManifest file. If omitted, a default one is created and used')
- parser.add_argument('--file_contexts',
- help='selinux file contexts file. Required for "image" APEXs.')
- parser.add_argument('--canned_fs_config',
- help='canned_fs_config specifies uid/gid/mode of files. Required for ' +
- '"image" APEXS.')
- parser.add_argument('--key',
- help='path to the private key file. Required for "image" APEXs.')
- parser.add_argument('--pubkey',
- help='path to the public key file. Used to bundle the public key in APEX for testing.')
- parser.add_argument('input_dir', metavar='INPUT_DIR',
- help='the directory having files to be packaged')
- parser.add_argument('output', metavar='OUTPUT',
- help='name of the APEX file')
- parser.add_argument('--payload_type', metavar='TYPE', required=False, default="image",
- choices=["zip", "image"],
- help='type of APEX payload being built "zip" or "image"')
- parser.add_argument('--override_apk_package_name', required=False,
- help='package name of the APK container. Default is the apex name in --manifest.')
- parser.add_argument('--android_jar_path', required=False,
- default="prebuilts/sdk/current/public/android.jar",
- help='path to use as the source of the android API.')
- apexer_path_in_environ = "APEXER_TOOL_PATH" in os.environ
- parser.add_argument('--apexer_tool_path', required=not apexer_path_in_environ,
- default=os.environ['APEXER_TOOL_PATH'].split(":") if apexer_path_in_environ else None,
- type=lambda s: s.split(":"),
- help="""A list of directories containing all the tools used by apexer (e.g.
+ parser.add_argument(
+ '-f', '--force', action='store_true', help='force overwriting output')
+ parser.add_argument(
+ '-v', '--verbose', action='store_true', help='verbose execution')
+ parser.add_argument(
+ '--manifest',
+ default='apex_manifest.json',
+ help='path to the APEX manifest file')
+ parser.add_argument(
+ '--android_manifest',
+ help='path to the AndroidManifest file. If omitted, a default one is created and used'
+ )
+ parser.add_argument(
+ '--file_contexts',
+ help='selinux file contexts file. Required for "image" APEXs.')
+ parser.add_argument(
+ '--canned_fs_config',
+ help='canned_fs_config specifies uid/gid/mode of files. Required for ' +
+ '"image" APEXS.')
+ parser.add_argument(
+ '--key', help='path to the private key file. Required for "image" APEXs.')
+ parser.add_argument(
+ '--pubkey',
+ help='path to the public key file. Used to bundle the public key in APEX for testing.'
+ )
+ parser.add_argument(
+ 'input_dir',
+ metavar='INPUT_DIR',
+ help='the directory having files to be packaged')
+ parser.add_argument('output', metavar='OUTPUT', help='name of the APEX file')
+ parser.add_argument(
+ '--payload_type',
+ metavar='TYPE',
+ required=False,
+ default='image',
+ choices=['zip', 'image'],
+ help='type of APEX payload being built "zip" or "image"')
+ parser.add_argument(
+ '--override_apk_package_name',
+ required=False,
+ help='package name of the APK container. Default is the apex name in --manifest.'
+ )
+ parser.add_argument(
+ '--android_jar_path',
+ required=False,
+ default='prebuilts/sdk/current/public/android.jar',
+ help='path to use as the source of the android API.')
+ apexer_path_in_environ = 'APEXER_TOOL_PATH' in os.environ
+ parser.add_argument(
+ '--apexer_tool_path',
+ required=not apexer_path_in_environ,
+ default=os.environ['APEXER_TOOL_PATH'].split(':')
+ if apexer_path_in_environ else None,
+ type=lambda s: s.split(':'),
+ help="""A list of directories containing all the tools used by apexer (e.g.
mke2fs, avbtool, etc.) separated by ':'. Can also be set using the
APEXER_TOOL_PATH environment variable""")
- parser.add_argument('--target_sdk_version', required=False,
- help='Default target SDK version to use for AndroidManifest.xml')
+ parser.add_argument(
+ '--target_sdk_version',
+ required=False,
+ help='Default target SDK version to use for AndroidManifest.xml')
return parser.parse_args(argv)
+
def FindBinaryPath(binary):
for path in tool_path_list:
binary_path = os.path.join(path, binary)
if os.path.exists(binary_path):
return binary_path
- raise Exception("Failed to find binary " + binary + " in path " + ":".join(tool_path_list))
+ raise Exception('Failed to find binary ' + binary + ' in path ' +
+ ':'.join(tool_path_list))
+
def RunCommand(cmd, verbose=False, env=None):
env = env or {}
@@ -94,7 +118,7 @@ def RunCommand(cmd, verbose=False, env=None):
cmd[0] = FindBinaryPath(cmd[0])
if verbose:
- print("Running: " + " ".join(cmd))
+ print('Running: ' + ' '.join(cmd))
p = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
output, _ = p.communicate()
@@ -102,10 +126,11 @@ def RunCommand(cmd, verbose=False, env=None):
if verbose or p.returncode is not 0:
print(output.rstrip())
- assert p.returncode is 0, "Failed to execute: " + " ".join(cmd)
+ assert p.returncode is 0, 'Failed to execute: ' + ' '.join(cmd)
return (output, p.returncode)
+
def GetDirSize(dir_name):
size = 0
for dirpath, _, filenames in os.walk(dir_name):
@@ -114,16 +139,19 @@ def GetDirSize(dir_name):
size += RoundUp(os.path.getsize(os.path.join(dirpath, f)), BLOCK_SIZE)
return size
+
def GetFilesAndDirsCount(dir_name):
- count = 0;
+ count = 0
for root, dirs, files in os.walk(dir_name):
count += (len(dirs) + len(files))
return count
+
def RoundUp(size, unit):
assert unit & (unit - 1) == 0
return (size + unit - 1) & (~(unit - 1))
+
def PrepareAndroidManifest(package, version):
template = """\
<?xml version="1.0" encoding="utf-8"?>
@@ -135,13 +163,16 @@ def PrepareAndroidManifest(package, version):
"""
return template.format(package=package, version=version)
+
def ValidateAndroidManifest(package, android_manifest):
tree = ET.parse(android_manifest)
manifest_tag = tree.getroot()
package_in_xml = manifest_tag.attrib['package']
if package_in_xml != package:
- raise Exception("Package name '" + package_in_xml + "' in '" + android_manifest +
- " differ from package name '" + package + "' in the apex_manifest.json")
+ raise Exception("Package name '" + package_in_xml + "' in '" +
+ android_manifest + " differ from package name '" + package +
+ "' in the apex_manifest.json")
+
def ValidateArgs(args):
if not os.path.exists(args.manifest):
@@ -154,11 +185,13 @@ def ValidateArgs(args):
if args.android_manifest is not None:
if not os.path.exists(args.android_manifest):
- print("Android Manifest file '" + args.android_manifest + "' does not exist")
+ print("Android Manifest file '" + args.android_manifest +
+ "' does not exist")
return False
if not os.path.isfile(args.android_manifest):
- print("Android Manifest file '" + args.android_manifest + "' is not a file")
+ print("Android Manifest file '" + args.android_manifest +
+ "' is not a file")
return False
if not os.path.exists(args.input_dir):
@@ -173,30 +206,31 @@ def ValidateArgs(args):
print(args.output + ' already exists. Use --force to overwrite.')
return False
- if args.payload_type == "image":
+ if args.payload_type == 'image':
if not args.key:
- print("Missing --key {keyfile} argument!")
+ print('Missing --key {keyfile} argument!')
return False
if not args.file_contexts:
- print("Missing --file_contexts {contexts} argument!")
+ print('Missing --file_contexts {contexts} argument!')
return False
if not args.canned_fs_config:
- print("Missing --canned_fs_config {config} argument!")
+ print('Missing --canned_fs_config {config} argument!')
return False
return True
+
def CreateApex(args, work_dir):
if not ValidateArgs(args):
return False
if args.verbose:
- print "Using tools from " + str(tool_path_list)
+ print 'Using tools from ' + str(tool_path_list)
try:
- with open(args.manifest, "r") as f:
+ with open(args.manifest, 'r') as f:
manifest_raw = f.read()
manifest_apex = ValidateApexManifest(manifest_raw)
except ApexManifestError as err:
@@ -209,7 +243,7 @@ def CreateApex(args, work_dir):
# create an empty ext4 image that is sufficiently big
# sufficiently big = size + 16MB margin
- size_in_mb = (GetDirSize(args.input_dir) / (1024*1024)) + 16
+ size_in_mb = (GetDirSize(args.input_dir) / (1024 * 1024)) + 16
content_dir = os.path.join(work_dir, 'content')
os.mkdir(content_dir)
@@ -228,7 +262,8 @@ def CreateApex(args, work_dir):
key_name = os.path.basename(os.path.splitext(args.key)[0])
if manifest_apex.name != key_name:
- print("package name '" + manifest_apex.name + "' does not match with key name '" + key_name + "'")
+ print("package name '" + manifest_apex.name +
+ "' does not match with key name '" + key_name + "'")
return False
img_file = os.path.join(content_dir, 'apex_payload.img')
@@ -241,18 +276,18 @@ def CreateApex(args, work_dir):
inode_num = GetFilesAndDirsCount(args.input_dir) + inode_num_margin
cmd = ['mke2fs']
- cmd.extend(['-O', '^has_journal']) # because image is read-only
+ cmd.extend(['-O', '^has_journal']) # because image is read-only
cmd.extend(['-b', str(BLOCK_SIZE)])
- cmd.extend(['-m', '0']) # reserved block percentage
+ cmd.extend(['-m', '0']) # reserved block percentage
cmd.extend(['-t', 'ext4'])
- cmd.extend(['-I', '256']) # inode size
+ cmd.extend(['-I', '256']) # inode size
cmd.extend(['-N', str(inode_num)])
- uu = str(uuid.uuid5(uuid.NAMESPACE_URL, "www.android.com"))
+ uu = str(uuid.uuid5(uuid.NAMESPACE_URL, 'www.android.com'))
cmd.extend(['-U', uu])
cmd.extend(['-E', 'hash_seed=' + uu])
cmd.append(img_file)
cmd.append(str(size_in_mb) + 'M')
- RunCommand(cmd, args.verbose, {"E2FSPROGS_FAKE_TIME": "1"})
+ RunCommand(cmd, args.verbose, {'E2FSPROGS_FAKE_TIME': '1'})
# Compile the file context into the binary form
compiled_file_contexts = os.path.join(work_dir, 'file_contexts.bin')
@@ -263,38 +298,37 @@ def CreateApex(args, work_dir):
# Add files to the image file
cmd = ['e2fsdroid']
- cmd.append('-e') # input is not android_sparse_file
+ cmd.append('-e') # input is not android_sparse_file
cmd.extend(['-f', args.input_dir])
- cmd.extend(['-T', '0']) # time is set to epoch
+ cmd.extend(['-T', '0']) # time is set to epoch
cmd.extend(['-S', compiled_file_contexts])
cmd.extend(['-C', args.canned_fs_config])
- cmd.append('-s') # share dup blocks
+ cmd.append('-s') # share dup blocks
cmd.append(img_file)
- RunCommand(cmd, args.verbose, {"E2FSPROGS_FAKE_TIME": "1"})
+ RunCommand(cmd, args.verbose, {'E2FSPROGS_FAKE_TIME': '1'})
cmd = ['e2fsdroid']
- cmd.append('-e') # input is not android_sparse_file
+ cmd.append('-e') # input is not android_sparse_file
cmd.extend(['-f', manifests_dir])
- cmd.extend(['-T', '0']) # time is set to epoch
+ cmd.extend(['-T', '0']) # time is set to epoch
cmd.extend(['-S', compiled_file_contexts])
cmd.extend(['-C', args.canned_fs_config])
- cmd.append('-s') # share dup blocks
+ cmd.append('-s') # share dup blocks
cmd.append(img_file)
- RunCommand(cmd, args.verbose, {"E2FSPROGS_FAKE_TIME": "1"})
+ RunCommand(cmd, args.verbose, {'E2FSPROGS_FAKE_TIME': '1'})
# Resize the image file to save space
cmd = ['resize2fs']
- cmd.append('-M') # shrink as small as possible
+ cmd.append('-M') # shrink as small as possible
cmd.append(img_file)
- RunCommand(cmd, args.verbose, {"E2FSPROGS_FAKE_TIME": "1"})
-
+ RunCommand(cmd, args.verbose, {'E2FSPROGS_FAKE_TIME': '1'})
cmd = ['avbtool']
cmd.append('add_hashtree_footer')
cmd.append('--do_not_generate_fec')
cmd.extend(['--algorithm', 'SHA256_RSA4096'])
cmd.extend(['--key', args.key])
- cmd.extend(['--prop', "apex.key:" + key_name])
+ cmd.extend(['--prop', 'apex.key:' + key_name])
# Set up the salt based on manifest content which includes name
# and version
salt = hashlib.sha256(manifest_raw).hexdigest()
@@ -304,10 +338,12 @@ def CreateApex(args, work_dir):
# Get the minimum size of the partition required.
# TODO(b/113320014) eliminate this step
- info, _ = RunCommand(['avbtool', 'info_image', '--image', img_file], args.verbose)
+ info, _ = RunCommand(['avbtool', 'info_image', '--image', img_file],
+ args.verbose)
vbmeta_offset = int(re.search('VBMeta\ offset:\ *([0-9]+)', info).group(1))
vbmeta_size = int(re.search('VBMeta\ size:\ *([0-9]+)', info).group(1))
- partition_size = RoundUp(vbmeta_offset + vbmeta_size, BLOCK_SIZE) + BLOCK_SIZE
+ partition_size = RoundUp(vbmeta_offset + vbmeta_size,
+ BLOCK_SIZE) + BLOCK_SIZE
# Resize to the minimum size
# TODO(b/113320014) eliminate this step
@@ -341,11 +377,12 @@ def CreateApex(args, work_dir):
# copy manifest to the content dir so that it is also accessible
# without mounting the image
- shutil.copyfile(args.manifest, os.path.join(content_dir, 'apex_manifest.json'))
+ shutil.copyfile(args.manifest, os.path.join(content_dir,
+ 'apex_manifest.json'))
# copy the public key, if specified
if args.pubkey:
- shutil.copyfile(args.pubkey, os.path.join(content_dir, "apex_pubkey"))
+ shutil.copyfile(args.pubkey, os.path.join(content_dir, 'apex_pubkey'))
apk_file = os.path.join(work_dir, 'apex.apk')
cmd = ['aapt2']
@@ -368,21 +405,21 @@ def CreateApex(args, work_dir):
zip_file = os.path.join(work_dir, 'apex.zip')
cmd = ['soong_zip']
- cmd.append('-d') # include directories
- cmd.extend(['-C', content_dir]) # relative root
- cmd.extend(['-D', content_dir]) # input dir
+ cmd.append('-d') # include directories
+ cmd.extend(['-C', content_dir]) # relative root
+ cmd.extend(['-D', content_dir]) # input dir
for file_ in os.listdir(content_dir):
if os.path.isfile(os.path.join(content_dir, file_)):
- cmd.extend(['-s', file_]) # don't compress any files
+ cmd.extend(['-s', file_]) # don't compress any files
cmd.extend(['-o', zip_file])
RunCommand(cmd, args.verbose)
unaligned_apex_file = os.path.join(work_dir, 'unaligned.apex')
cmd = ['merge_zips']
- cmd.append('-j') # sort
- cmd.append(unaligned_apex_file) # output
- cmd.append(apk_file) # input
- cmd.append(zip_file) # input
+ cmd.append('-j') # sort
+ cmd.append(unaligned_apex_file) # output
+ cmd.append(apk_file) # input
+ cmd.append(zip_file) # input
RunCommand(cmd, args.verbose)
# Align the files at page boundary for efficient access
@@ -400,6 +437,7 @@ def CreateApex(args, work_dir):
class TempDirectory(object):
+
def __enter__(self):
self.name = tempfile.mkdtemp()
return self.name