blob: 20a9c64dddca1388ba296c2e9969b050c4071cdd [file] [log] [blame]
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001#!/usr/bin/env python
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
Daniel Normane5b134a2019-04-17 14:54:06 -070016"""This script merges two partial target files packages.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080017
Daniel Normane5b134a2019-04-17 14:54:06 -070018One package contains system files, and the other contains non-system files.
19It produces a complete target files package that can be used to generate an
20OTA package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080021
22Usage: merge_target_files.py [args]
23
24 --system-target-files system-target-files-zip-archive
25 The input target files package containing system bits. This is a zip
26 archive.
27
Daniel Norman2c99c5b2019-03-07 13:01:48 -080028 --system-item-list system-item-list-file
29 The optional path to a newline-separated config file that replaces the
30 contents of default_system_item_list if provided.
31
32 --system-misc-info-keys system-misc-info-keys-file
33 The optional path to a newline-separated config file that replaces the
34 contents of default_system_misc_info_keys if provided.
35
Bill Peckhame9eb5f92019-02-01 15:52:10 -080036 --other-target-files other-target-files-zip-archive
37 The input target files package containing other bits. This is a zip
38 archive.
39
Daniel Norman2c99c5b2019-03-07 13:01:48 -080040 --other-item-list other-item-list-file
41 The optional path to a newline-separated config file that replaces the
42 contents of default_other_item_list if provided.
43
Bill Peckhame9eb5f92019-02-01 15:52:10 -080044 --output-target-files output-target-files-package
Daniel Normanfdb38812019-04-15 09:47:24 -070045 If provided, the output merged target files package. Also a zip archive.
46
47 --output-dir output-directory
48 If provided, the destination directory for saving merged files. Requires
49 the --output-item-list flag.
50 Can be provided alongside --output-target-files, or by itself.
51
52 --output-item-list output-item-list-file.
53 The optional path to a newline-separated config file that specifies the
54 file patterns to copy into the --output-dir. Required if providing
55 the --output-dir flag.
Daniel Normana4911da2019-03-15 14:36:21 -070056
Daniel Norman3b64ce12019-04-16 16:11:35 -070057 --output-ota output-ota-package
58 The output ota package. This is a zip archive. Use of this flag may
59 require passing the --path common flag; see common.py.
60
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070061 --output-img output-img-package
62 The output img package, suitable for use with 'fastboot update'. Use of
63 this flag may require passing the --path common flag; see common.py.
64
Daniel Normanf0318252019-04-15 11:34:56 -070065 --output-super-empty output-super-empty-image
66 If provided, creates a super_empty.img file from the merged target
67 files package and saves it at this path.
68
Daniel Normana4911da2019-03-15 14:36:21 -070069 --rebuild_recovery
70 Rebuild the recovery patch used by non-A/B devices and write it to the
71 system image.
Bill Peckham364c1cc2019-03-29 18:27:23 -070072
73 --keep-tmp
74 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080075"""
76
77from __future__ import print_function
78
Bill Peckhame9eb5f92019-02-01 15:52:10 -080079import fnmatch
80import logging
81import os
Daniel Normanfdb38812019-04-15 09:47:24 -070082import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -070083import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -080084import sys
85import zipfile
86
Bill Peckhame9eb5f92019-02-01 15:52:10 -080087import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070088import build_super_image
89import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070090import img_from_target_files
Daniel Norman3b64ce12019-04-16 16:11:35 -070091import ota_from_target_files
Bill Peckhame9eb5f92019-02-01 15:52:10 -080092
93logger = logging.getLogger(__name__)
94OPTIONS = common.OPTIONS
95OPTIONS.verbose = True
Bill Peckhamf753e152019-02-19 18:02:46 -080096OPTIONS.system_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080097OPTIONS.system_item_list = None
98OPTIONS.system_misc_info_keys = None
Bill Peckhamf753e152019-02-19 18:02:46 -080099OPTIONS.other_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800100OPTIONS.other_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800101OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700102OPTIONS.output_dir = None
103OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700104OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700105OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700106OPTIONS.output_super_empty = None
Daniel Normana4911da2019-03-15 14:36:21 -0700107OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800108OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800109
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800110# default_system_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800111# system target files package as is, meaning these items will land in the
112# output target files package exactly as they appear in the input partial
113# system target files package.
114
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800115default_system_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800116 'META/apkcerts.txt',
117 'META/filesystem_config.txt',
118 'META/root_filesystem_config.txt',
119 'META/system_manifest.xml',
120 'META/system_matrix.xml',
121 'META/update_engine_config.txt',
122 'PRODUCT/*',
123 'ROOT/*',
124 'SYSTEM/*',
125]
126
127# system_extract_special_item_list is a list of items to extract from the
128# partial system target files package that need some special processing, such
129# as some sort of combination with items from the partial other target files
130# package.
131
132system_extract_special_item_list = [
133 'META/*',
134]
135
Daniel Normane5b134a2019-04-17 14:54:06 -0700136# default_system_misc_info_keys is a list of keys to obtain from the system
137# instance of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800138
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800139default_system_misc_info_keys = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800140 'avb_system_hashtree_enable',
141 'avb_system_add_hashtree_footer_args',
142 'avb_system_key_path',
143 'avb_system_algorithm',
144 'avb_system_rollback_index_location',
145 'avb_product_hashtree_enable',
146 'avb_product_add_hashtree_footer_args',
147 'avb_product_services_hashtree_enable',
148 'avb_product_services_add_hashtree_footer_args',
149 'system_root_image',
150 'root_dir',
151 'ab_update',
152 'default_system_dev_certificate',
153 'system_size',
154]
155
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800156# default_other_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800157# other target files package as is, meaning these items will land in the output
158# target files package exactly as they appear in the input partial other target
159# files package.
160
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800161default_other_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800162 'META/boot_filesystem_config.txt',
Bill Peckham736b2232019-05-06 12:50:55 -0700163 'META/file_contexts.bin',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800164 'META/otakeys.txt',
165 'META/releasetools.py',
166 'META/vendor_filesystem_config.txt',
167 'META/vendor_manifest.xml',
168 'META/vendor_matrix.xml',
169 'BOOT/*',
170 'DATA/*',
171 'ODM/*',
172 'OTA/android-info.txt',
173 'PREBUILT_IMAGES/*',
174 'RADIO/*',
175 'VENDOR/*',
176]
177
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800178# other_extract_special_item_list is a list of items to extract from the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800179# partial other target files package that need some special processing, such as
180# some sort of combination with items from the partial system target files
181# package.
182
183other_extract_special_item_list = [
184 'META/*',
185]
186
187
188def extract_items(target_files, target_files_temp_dir, extract_item_list):
189 """Extract items from target files to temporary directory.
190
191 This function extracts from the specified target files zip archive into the
192 specified temporary directory, the items specified in the extract item list.
193
194 Args:
195 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800196 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700197 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800198 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800199 """
200
201 logger.info('extracting from %s', target_files)
202
203 # Filter the extract_item_list to remove any items that do not exist in the
204 # zip file. Otherwise, the extraction step will fail.
205
206 with zipfile.ZipFile(
Daniel Normane5b134a2019-04-17 14:54:06 -0700207 target_files, 'r', allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800208 target_files_namelist = target_files_zipfile.namelist()
209
210 filtered_extract_item_list = []
211 for pattern in extract_item_list:
212 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
213 if not matching_namelist:
214 logger.warning('no match for %s', pattern)
215 else:
216 filtered_extract_item_list.append(pattern)
217
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800218 # Extract from target_files into target_files_temp_dir the
219 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800220
Daniel Normane5b134a2019-04-17 14:54:06 -0700221 common.UnzipToDir(target_files, target_files_temp_dir,
222 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800223
224
Daniel Normanfdb38812019-04-15 09:47:24 -0700225def copy_items(from_dir, to_dir, patterns):
226 """Similar to extract_items() except uses an input dir instead of zip."""
227 file_paths = []
228 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700229 file_paths.extend(
230 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
231 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700232
233 filtered_file_paths = set()
234 for pattern in patterns:
235 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
236
237 for file_path in filtered_file_paths:
238 original_file_path = os.path.join(from_dir, file_path)
239 copied_file_path = os.path.join(to_dir, file_path)
240 copied_file_dir = os.path.dirname(copied_file_path)
241 if not os.path.exists(copied_file_dir):
242 os.makedirs(copied_file_dir)
243 if os.path.islink(original_file_path):
244 os.symlink(os.readlink(original_file_path), copied_file_path)
245 else:
246 shutil.copyfile(original_file_path, copied_file_path)
247
248
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800249def read_config_list(config_file_path):
250 """Reads a config file into a list of strings.
251
252 Expects the file to be newline-separated.
253
254 Args:
255 config_file_path: The path to the config file to open and read.
Daniel Normane5b134a2019-04-17 14:54:06 -0700256
257 Returns:
258 The list of strings in the config file.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800259 """
260 with open(config_file_path) as config_file:
261 return config_file.read().splitlines()
262
263
Daniel Normane5b134a2019-04-17 14:54:06 -0700264def validate_config_lists(system_item_list, system_misc_info_keys,
265 other_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700266 """Performs validations on the merge config lists.
267
268 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700269 system_item_list: The list of items to extract from the partial system
270 target files package as is.
271 system_misc_info_keys: A list of keys to obtain from the system instance of
272 META/misc_info.txt. The remaining keys from the other instance.
273 other_item_list: The list of items to extract from the partial other target
274 files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700275
276 Returns:
277 False if a validation fails, otherwise true.
278 """
279 default_combined_item_set = set(default_system_item_list)
280 default_combined_item_set.update(default_other_item_list)
281
282 combined_item_set = set(system_item_list)
283 combined_item_set.update(other_item_list)
284
285 # Check that the merge config lists are not missing any item specified
286 # by the default config lists.
287 difference = default_combined_item_set.difference(combined_item_set)
288 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700289 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700290 logger.error('Please ensure missing items are in either the '
291 'system-item-list or other-item-list files provided to '
292 'this script.')
293 return False
294
Daniel Norman19b9fe92019-03-19 14:48:02 -0700295 if ('dynamic_partition_list' in system_misc_info_keys) or (
296 'super_partition_groups' in system_misc_info_keys):
297 logger.error('Dynamic partition misc info keys should come from '
298 'the other instance of META/misc_info.txt.')
299 return False
300
Daniel Normane5964522019-03-19 10:32:03 -0700301 return True
302
303
Daniel Normane5b134a2019-04-17 14:54:06 -0700304def process_ab_partitions_txt(system_target_files_temp_dir,
305 other_target_files_temp_dir,
306 output_target_files_temp_dir):
307 """Perform special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800308
309 This function merges the contents of the META/ab_partitions.txt files from
310 the system directory and the other directory, placing the merged result in
311 the output directory. The precondition in that the files are already
312 extracted. The post condition is that the output META/ab_partitions.txt
313 contains the merged content. The format for each ab_partitions.txt a one
314 partition name per line. The output file contains the union of the parition
315 names.
316
317 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700318 system_target_files_temp_dir: The name of a directory containing the special
319 items extracted from the system target files package.
320 other_target_files_temp_dir: The name of a directory containing the special
321 items extracted from the other target files package.
322 output_target_files_temp_dir: The name of a directory that will be used to
323 create the output target files package after all the special cases are
324 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800325 """
326
Daniel Normane5b134a2019-04-17 14:54:06 -0700327 system_ab_partitions_txt = os.path.join(system_target_files_temp_dir, 'META',
328 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800329
Daniel Normane5b134a2019-04-17 14:54:06 -0700330 other_ab_partitions_txt = os.path.join(other_target_files_temp_dir, 'META',
331 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800332
333 with open(system_ab_partitions_txt) as f:
334 system_ab_partitions = f.read().splitlines()
335
336 with open(other_ab_partitions_txt) as f:
337 other_ab_partitions = f.read().splitlines()
338
339 output_ab_partitions = set(system_ab_partitions + other_ab_partitions)
340
Daniel Normane5b134a2019-04-17 14:54:06 -0700341 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
342 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800343
344 with open(output_ab_partitions_txt, 'w') as output:
345 for partition in sorted(output_ab_partitions):
346 output.write('%s\n' % partition)
347
348
Bill Peckham364c1cc2019-03-29 18:27:23 -0700349def append_recovery_to_filesystem_config(output_target_files_temp_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700350 """Perform special processing for META/filesystem_config.txt.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700351
352 This function appends recovery information to META/filesystem_config.txt
353 so that recovery patch regeneration will succeed.
354
355 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700356 output_target_files_temp_dir: The name of a directory that will be used to
357 create the output target files package after all the special cases are
358 processed. We find filesystem_config.txt here.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700359 """
360
Daniel Normane5b134a2019-04-17 14:54:06 -0700361 filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
362 'filesystem_config.txt')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700363
364 with open(filesystem_config_txt, 'a') as f:
365 # TODO(bpeckham) this data is hard coded. It should be generated
366 # programmatically.
Daniel Normane5b134a2019-04-17 14:54:06 -0700367 f.write('system/bin/install-recovery.sh 0 0 750 '
368 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
369 f.write('system/recovery-from-boot.p 0 0 644 '
370 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
371 f.write('system/etc/recovery.img 0 0 440 '
372 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700373
374
Daniel Normana61cde02019-05-03 14:19:13 -0700375def merge_dynamic_partition_info_dicts(system_dict,
376 other_dict,
377 include_dynamic_partition_list=True,
378 size_prefix='',
379 size_suffix='',
380 list_prefix='',
381 list_suffix=''):
382 """Merges dynamic partition info variables.
383
384 Args:
385 system_dict: The dictionary of dynamic partition info variables from the
386 partial system target files.
387 other_dict: The dictionary of dynamic partition info variables from the
388 partial other target files.
389 include_dynamic_partition_list: If true, merges the dynamic_partition_list
390 variable. Not all use cases need this variable merged.
391 size_prefix: The prefix in partition group size variables that precedes the
392 name of the partition group. For example, partition group 'group_a' with
393 corresponding size variable 'super_group_a_group_size' would have the
394 size_prefix 'super_'.
395 size_suffix: Similar to size_prefix but for the variable's suffix. For
396 example, 'super_group_a_group_size' would have size_suffix '_group_size'.
397 list_prefix: Similar to size_prefix but for the partition group's
398 partition_list variable.
399 list_suffix: Similar to size_suffix but for the partition group's
400 partition_list variable.
401
402 Returns:
403 The merged dynamic partition info dictionary.
404 """
405 merged_dict = {}
406 # Partition groups and group sizes are defined by the other (non-system)
407 # dict because these values may vary for each board that uses a shared system
408 # image.
409 merged_dict['super_partition_groups'] = other_dict['super_partition_groups']
410 if include_dynamic_partition_list:
411 system_dynamic_partition_list = system_dict.get('dynamic_partition_list',
412 '')
413 other_dynamic_partition_list = other_dict.get('dynamic_partition_list', '')
414 merged_dict['dynamic_partition_list'] = (
415 '%s %s' %
416 (system_dynamic_partition_list, other_dynamic_partition_list)).strip()
417 for partition_group in merged_dict['super_partition_groups'].split(' '):
418 # Set the partition group's size using the value from the other dict.
419 key = '%s%s%s' % (size_prefix, partition_group, size_suffix)
420 if key not in other_dict:
421 raise ValueError('Other dict does not contain required key %s.' % key)
422 merged_dict[key] = other_dict[key]
423
424 # Set the partition group's partition list using a concatenation of the
425 # system and other partition lists.
426 key = '%s%s%s' % (list_prefix, partition_group, list_suffix)
427 merged_dict[key] = (
428 '%s %s' % (system_dict.get(key, ''), other_dict.get(key, ''))).strip()
429 return merged_dict
430
431
Daniel Normane5b134a2019-04-17 14:54:06 -0700432def process_misc_info_txt(system_target_files_temp_dir,
433 other_target_files_temp_dir,
434 output_target_files_temp_dir, system_misc_info_keys):
435 """Perform special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800436
437 This function merges the contents of the META/misc_info.txt files from the
438 system directory and the other directory, placing the merged result in the
439 output directory. The precondition in that the files are already extracted.
440 The post condition is that the output META/misc_info.txt contains the merged
441 content.
442
443 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700444 system_target_files_temp_dir: The name of a directory containing the special
445 items extracted from the system target files package.
446 other_target_files_temp_dir: The name of a directory containing the special
447 items extracted from the other target files package.
448 output_target_files_temp_dir: The name of a directory that will be used to
449 create the output target files package after all the special cases are
450 processed.
451 system_misc_info_keys: A list of keys to obtain from the system instance of
452 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800453 """
454
455 def read_helper(d):
456 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt')
457 with open(misc_info_txt) as f:
458 return list(f.read().splitlines())
459
460 system_info_dict = common.LoadDictionaryFromLines(
461 read_helper(system_target_files_temp_dir))
462
463 # We take most of the misc info from the other target files.
464
465 merged_info_dict = common.LoadDictionaryFromLines(
466 read_helper(other_target_files_temp_dir))
467
468 # Replace certain values in merged_info_dict with values from
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800469 # system_info_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800470
471 for key in system_misc_info_keys:
472 merged_info_dict[key] = system_info_dict[key]
473
Daniel Norman19b9fe92019-03-19 14:48:02 -0700474 # Merge misc info keys used for Dynamic Partitions.
475 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
476 system_info_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normana61cde02019-05-03 14:19:13 -0700477 merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
478 system_dict=system_info_dict,
479 other_dict=merged_info_dict,
480 size_prefix='super_',
481 size_suffix='_group_size',
482 list_prefix='super_',
483 list_suffix='_partition_list')
484 merged_info_dict.update(merged_dynamic_partitions_dict)
Daniel Norman19b9fe92019-03-19 14:48:02 -0700485
Daniel Normane5b134a2019-04-17 14:54:06 -0700486 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
487 'misc_info.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800488 with open(output_misc_info_txt, 'w') as output:
Daniel Normana61cde02019-05-03 14:19:13 -0700489 sorted_keys = sorted(merged_info_dict.keys())
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800490 for key in sorted_keys:
491 output.write('{}={}\n'.format(key, merged_info_dict[key]))
492
493
Daniel Normana61cde02019-05-03 14:19:13 -0700494def process_dynamic_partitions_info_txt(system_target_files_dir,
495 other_target_files_dir,
496 output_target_files_dir):
497 """Perform special processing for META/dynamic_partitions_info.txt.
498
499 This function merges the contents of the META/dynamic_partitions_info.txt
500 files from the system directory and the other directory, placing the merged
501 result in the output directory.
502
503 This function does nothing if META/dynamic_partitions_info.txt from the other
504 directory does not exist.
505
506 Args:
507 system_target_files_dir: The name of a directory containing the special
508 items extracted from the system target files package.
509 other_target_files_dir: The name of a directory containing the special items
510 extracted from the other target files package.
511 output_target_files_dir: The name of a directory that will be used to create
512 the output target files package after all the special cases are processed.
513 """
514
515 if not os.path.exists(
516 os.path.join(other_target_files_dir, 'META',
517 'dynamic_partitions_info.txt')):
518 return
519
520 def read_helper(d):
521 dynamic_partitions_info_txt = os.path.join(d, 'META',
522 'dynamic_partitions_info.txt')
523 with open(dynamic_partitions_info_txt) as f:
524 return list(f.read().splitlines())
525
526 system_dynamic_partitions_dict = common.LoadDictionaryFromLines(
527 read_helper(system_target_files_dir))
528 other_dynamic_partitions_dict = common.LoadDictionaryFromLines(
529 read_helper(other_target_files_dir))
530
531 merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
532 system_dict=system_dynamic_partitions_dict,
533 other_dict=other_dynamic_partitions_dict,
534 # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
535 include_dynamic_partition_list=False,
536 size_suffix='_size',
537 list_suffix='_partition_list')
538
539 output_dynamic_partitions_info_txt = os.path.join(
540 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
541 with open(output_dynamic_partitions_info_txt, 'w') as output:
542 sorted_keys = sorted(merged_dynamic_partitions_dict.keys())
543 for key in sorted_keys:
544 output.write('{}={}\n'.format(key, merged_dynamic_partitions_dict[key]))
545
546
Bill Peckham736b2232019-05-06 12:50:55 -0700547def process_special_cases(system_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700548 other_target_files_temp_dir,
549 output_target_files_temp_dir, system_misc_info_keys,
550 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800551 """Perform special-case processing for certain target files items.
552
553 Certain files in the output target files package require special-case
554 processing. This function performs all that special-case processing.
555
556 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700557 system_target_files_temp_dir: The name of a directory containing the special
558 items extracted from the system target files package.
559 other_target_files_temp_dir: The name of a directory containing the special
560 items extracted from the other target files package.
561 output_target_files_temp_dir: The name of a directory that will be used to
562 create the output target files package after all the special cases are
563 processed.
564 system_misc_info_keys: A list of keys to obtain from the system instance of
565 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700566 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700567 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800568 """
569
Bill Peckham364c1cc2019-03-29 18:27:23 -0700570 if 'ab_update' in system_misc_info_keys:
571 process_ab_partitions_txt(
572 system_target_files_temp_dir=system_target_files_temp_dir,
573 other_target_files_temp_dir=other_target_files_temp_dir,
574 output_target_files_temp_dir=output_target_files_temp_dir)
575
576 if rebuild_recovery:
577 append_recovery_to_filesystem_config(
578 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800579
580 process_misc_info_txt(
581 system_target_files_temp_dir=system_target_files_temp_dir,
582 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800583 output_target_files_temp_dir=output_target_files_temp_dir,
584 system_misc_info_keys=system_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800585
Daniel Normana61cde02019-05-03 14:19:13 -0700586 process_dynamic_partitions_info_txt(
587 system_target_files_temp_dir=system_target_files_temp_dir,
588 other_target_files_temp_dir=other_target_files_temp_dir,
589 output_target_files_temp_dir=output_target_files_temp_dir)
590
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800591
Daniel Normane5b134a2019-04-17 14:54:06 -0700592def merge_target_files(temp_dir, system_target_files, system_item_list,
593 system_misc_info_keys, other_target_files,
594 other_item_list, output_target_files, output_dir,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700595 output_item_list, output_ota, output_img,
596 output_super_empty, rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800597 """Merge two target files packages together.
598
599 This function takes system and other target files packages as input, performs
600 various file extractions, special case processing, and finally creates a
601 merged zip archive as output.
602
603 Args:
604 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700605 input target files packages, and also a scratch directory that we use for
606 temporary files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800607 system_target_files: The name of the zip archive containing the system
Daniel Normane5b134a2019-04-17 14:54:06 -0700608 partial target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800609 system_item_list: The list of items to extract from the partial system
Daniel Normane5b134a2019-04-17 14:54:06 -0700610 target files package as is, meaning these items will land in the output
611 target files package exactly as they appear in the input partial system
612 target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800613 system_misc_info_keys: The list of keys to obtain from the system instance
Daniel Normane5b134a2019-04-17 14:54:06 -0700614 of META/misc_info.txt. The remaining keys from the other instance.
615 other_target_files: The name of the zip archive containing the other partial
616 target files package.
617 other_item_list: The list of items to extract from the partial other target
618 files package as is, meaning these items will land in the output target
619 files package exactly as they appear in the input partial other target
620 files package.
621 output_target_files: The name of the output zip archive target files package
622 created by merging system and other.
623 output_dir: The destination directory for saving merged files.
624 output_item_list: The list of items to copy into the output_dir.
Daniel Norman3b64ce12019-04-16 16:11:35 -0700625 output_ota: The name of the output zip archive ota package.
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700626 output_img: The name of the output zip archive img package.
Daniel Normanf0318252019-04-15 11:34:56 -0700627 output_super_empty: If provided, creates a super_empty.img file from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700628 merged target files package and saves it at this path.
Daniel Normana4911da2019-03-15 14:36:21 -0700629 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700630 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800631 """
632
Daniel Normane5b134a2019-04-17 14:54:06 -0700633 logger.info('starting: merge system %s and other %s into output %s',
634 system_target_files, other_target_files, output_target_files)
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800635
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800636 # Create directory names that we'll use when we extract files from system,
637 # and other, and for zipping the final output.
638
639 system_target_files_temp_dir = os.path.join(temp_dir, 'system')
640 other_target_files_temp_dir = os.path.join(temp_dir, 'other')
641 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
642
643 # Extract "as is" items from the input system partial target files package.
644 # We extract them directly into the output temporary directory since the
645 # items do not need special case processing.
646
Bill Peckham889b0c62019-02-21 18:53:37 -0800647 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800648 target_files=system_target_files,
649 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800650 extract_item_list=system_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800651
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800652 # Extract "as is" items from the input other partial target files package. We
653 # extract them directly into the output temporary directory since the items
654 # do not need special case processing.
655
Bill Peckham889b0c62019-02-21 18:53:37 -0800656 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800657 target_files=other_target_files,
658 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800659 extract_item_list=other_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800660
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800661 # Extract "special" items from the input system partial target files package.
662 # We extract these items to different directory since they require special
663 # processing before they will end up in the output directory.
664
Bill Peckham889b0c62019-02-21 18:53:37 -0800665 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800666 target_files=system_target_files,
667 target_files_temp_dir=system_target_files_temp_dir,
668 extract_item_list=system_extract_special_item_list)
669
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800670 # Extract "special" items from the input other partial target files package.
671 # We extract these items to different directory since they require special
672 # processing before they will end up in the output directory.
673
Bill Peckham889b0c62019-02-21 18:53:37 -0800674 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800675 target_files=other_target_files,
676 target_files_temp_dir=other_target_files_temp_dir,
677 extract_item_list=other_extract_special_item_list)
678
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800679 # Now that the temporary directories contain all the extracted files, perform
680 # special case processing on any items that need it. After this function
681 # completes successfully, all the files we need to create the output target
682 # files package are in place.
683
Bill Peckham889b0c62019-02-21 18:53:37 -0800684 process_special_cases(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800685 system_target_files_temp_dir=system_target_files_temp_dir,
686 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800687 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700688 system_misc_info_keys=system_misc_info_keys,
689 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800690
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800691 # Regenerate IMAGES in the temporary directory.
692
Daniel Normana4911da2019-03-15 14:36:21 -0700693 add_img_args = ['--verbose']
694 if rebuild_recovery:
695 add_img_args.append('--rebuild_recovery')
696 add_img_args.append(output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800697
698 add_img_to_target_files.main(add_img_args)
699
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700700 # Create super_empty.img using the merged misc_info.txt.
701
702 misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
703 'misc_info.txt')
704
705 def read_helper():
706 with open(misc_info_txt) as f:
707 return list(f.read().splitlines())
708
709 use_dynamic_partitions = common.LoadDictionaryFromLines(
710 read_helper()).get('use_dynamic_partitions')
711
712 if use_dynamic_partitions != 'true' and output_super_empty:
713 raise ValueError(
714 'Building super_empty.img requires use_dynamic_partitions=true.')
715 elif use_dynamic_partitions == 'true':
716 super_empty_img = os.path.join(output_target_files_temp_dir, 'IMAGES',
717 'super_empty.img')
718 build_super_image_args = [
719 misc_info_txt,
720 super_empty_img,
721 ]
722 build_super_image.main(build_super_image_args)
723
724 # Copy super_empty.img to the user-provided output_super_empty location.
725 if output_super_empty:
726 shutil.copyfile(super_empty_img, output_super_empty)
727
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700728 # Create the IMG package from the merged target files (before zipping, in
729 # order to avoid an unnecessary unzip and copy).
730
731 if output_img:
732 img_from_target_files_args = [
733 output_target_files_temp_dir,
734 output_img,
735 ]
736 img_from_target_files.main(img_from_target_files_args)
737
Daniel Normanfdb38812019-04-15 09:47:24 -0700738 # Finally, create the output target files zip archive and/or copy the
739 # output items to the output target files directory.
740
741 if output_dir:
742 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
743
744 if not output_target_files:
745 return
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800746
747 output_zip = os.path.abspath(output_target_files)
748 output_target_files_list = os.path.join(temp_dir, 'output.list')
Daniel Normane5b134a2019-04-17 14:54:06 -0700749 output_target_files_meta_dir = os.path.join(output_target_files_temp_dir,
750 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800751
Bill Peckham9662cfb2019-04-24 17:59:01 -0700752 find_command = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800753 'find',
754 output_target_files_meta_dir,
755 ]
Bill Peckham9662cfb2019-04-24 17:59:01 -0700756 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Normana61cde02019-05-03 14:19:13 -0700757 meta_content = common.RunAndCheckOutput(['sort'],
758 stdin=find_process.stdout,
Bill Peckham9662cfb2019-04-24 17:59:01 -0700759 verbose=False)
760
761 find_command = [
Daniel Normane5b134a2019-04-17 14:54:06 -0700762 'find', output_target_files_temp_dir, '-path',
763 output_target_files_meta_dir, '-prune', '-o', '-print'
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800764 ]
Bill Peckham9662cfb2019-04-24 17:59:01 -0700765 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Normana61cde02019-05-03 14:19:13 -0700766 other_content = common.RunAndCheckOutput(['sort'],
767 stdin=find_process.stdout,
Bill Peckham9662cfb2019-04-24 17:59:01 -0700768 verbose=False)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800769
770 with open(output_target_files_list, 'wb') as f:
771 f.write(meta_content)
772 f.write(other_content)
773
774 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800775 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800776 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700777 '-o',
778 output_zip,
779 '-C',
780 output_target_files_temp_dir,
781 '-l',
782 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800783 ]
784 logger.info('creating %s', output_target_files)
Bill Peckham889b0c62019-02-21 18:53:37 -0800785 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800786
Daniel Norman3b64ce12019-04-16 16:11:35 -0700787 # Create the OTA package from the merged target files package.
788
789 if output_ota:
790 ota_from_target_files_args = [
791 output_zip,
792 output_ota,
793 ]
794 ota_from_target_files.main(ota_from_target_files_args)
795
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700796
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800797def call_func_with_temp_dir(func, keep_tmp):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800798 """Manage the creation and cleanup of the temporary directory.
799
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800800 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800801 directory. It also cleans up the temporary directory.
802
803 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700804 func: The function to call. Should accept one parameter, the path to the
805 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800806 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800807 """
808
809 # Create a temporary directory. This will serve as the parent of directories
810 # we use when we extract items from the input target files packages, and also
811 # a scratch directory that we use for temporary files.
812
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800813 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
814
815 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800816 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800817 except:
818 raise
819 finally:
820 if keep_tmp:
821 logger.info('keeping %s', temp_dir)
822 else:
823 common.Cleanup()
824
825
826def main():
827 """The main function.
828
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800829 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800830 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800831 """
832
833 common.InitLogging()
834
Bill Peckhamf753e152019-02-19 18:02:46 -0800835 def option_handler(o, a):
836 if o == '--system-target-files':
837 OPTIONS.system_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800838 elif o == '--system-item-list':
839 OPTIONS.system_item_list = a
840 elif o == '--system-misc-info-keys':
841 OPTIONS.system_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800842 elif o == '--other-target-files':
843 OPTIONS.other_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800844 elif o == '--other-item-list':
845 OPTIONS.other_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800846 elif o == '--output-target-files':
847 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700848 elif o == '--output-dir':
849 OPTIONS.output_dir = a
850 elif o == '--output-item-list':
851 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700852 elif o == '--output-ota':
853 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700854 elif o == '--output-img':
855 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -0700856 elif o == '--output-super-empty':
857 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -0700858 elif o == '--rebuild_recovery':
859 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700860 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800861 OPTIONS.keep_tmp = True
862 else:
863 return False
864 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800865
Bill Peckhamf753e152019-02-19 18:02:46 -0800866 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -0700867 sys.argv[1:],
868 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -0800869 extra_long_opts=[
870 'system-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800871 'system-item-list=',
872 'system-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800873 'other-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800874 'other-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800875 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -0700876 'output-dir=',
877 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -0700878 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700879 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -0700880 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -0700881 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -0700882 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -0800883 ],
884 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800885
Daniel Normane5b134a2019-04-17 14:54:06 -0700886 if (args or OPTIONS.system_target_files is None or
887 OPTIONS.other_target_files is None or
888 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
889 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -0800890 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -0800891 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800892
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800893 if OPTIONS.system_item_list:
894 system_item_list = read_config_list(OPTIONS.system_item_list)
895 else:
896 system_item_list = default_system_item_list
897
898 if OPTIONS.system_misc_info_keys:
899 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
900 else:
901 system_misc_info_keys = default_system_misc_info_keys
902
903 if OPTIONS.other_item_list:
904 other_item_list = read_config_list(OPTIONS.other_item_list)
905 else:
906 other_item_list = default_other_item_list
907
Daniel Normanfdb38812019-04-15 09:47:24 -0700908 if OPTIONS.output_item_list:
909 output_item_list = read_config_list(OPTIONS.output_item_list)
910 else:
911 output_item_list = None
912
Daniel Normane5964522019-03-19 10:32:03 -0700913 if not validate_config_lists(
914 system_item_list=system_item_list,
Daniel Norman19b9fe92019-03-19 14:48:02 -0700915 system_misc_info_keys=system_misc_info_keys,
Daniel Normane5964522019-03-19 10:32:03 -0700916 other_item_list=other_item_list):
917 sys.exit(1)
918
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800919 call_func_with_temp_dir(
920 lambda temp_dir: merge_target_files(
921 temp_dir=temp_dir,
922 system_target_files=OPTIONS.system_target_files,
923 system_item_list=system_item_list,
924 system_misc_info_keys=system_misc_info_keys,
925 other_target_files=OPTIONS.other_target_files,
926 other_item_list=other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700927 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700928 output_dir=OPTIONS.output_dir,
929 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -0700930 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700931 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -0700932 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -0700933 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800934
935
936if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -0800937 main()