• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2021 Huawei Device Co., Ltd.
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"""
18The tool for making updater package.
19
20positional arguments:
21  target_package        Target package file path.
22  update_package        Update package file path.
23
24optional arguments:
25  -h, --help            show this help message and exit
26  -s SOURCE_PACKAGE, --source_package SOURCE_PACKAGE
27                        Source package file path.
28  -nz, --no_zip         No zip mode,
29                        which means to output the update package without zip.
30  -pf PARTITION_FILE, --partition_file PARTITION_FILE
31                        Variable partition mode, Partition list file path.
32  -sa {ECC,RSA}, --signing_algorithm {ECC,RSA}
33                        The signing algorithms
34                        supported by the tool include ['ECC', 'RSA'].
35  -ha {sha256,sha384}, --hash_algorithm {sha256,sha384}
36                        The hash algorithms
37                        supported by the tool include ['sha256', 'sha384'].
38  -pk PRIVATE_KEY, --private_key PRIVATE_KEY
39                        Private key file path.
40  -nl2, --not_l2        Not L2 mode, Distinguish between L1 and L2.
41  -sl {256,384}, --signing_length {256,384}
42                        The signing content length
43                        supported by the tool include ['256', '384'].
44  -xp, --xml_path       XML file path.
45  -sc, --sd_card        SD Card mode, Create update package for SD Card.
46"""
47import filecmp
48import os
49import argparse
50import subprocess
51
52import xmltodict
53
54import patch_package_process
55
56from gigraph_process import GigraphProcess
57from image_class import FullUpdateImage
58from image_class import is_sparse_image
59from image_class import IncUpdateImage
60from transfers_manager import TransfersManager
61from log_exception import UPDATE_LOGGER
62from script_generator import PreludeScript
63from script_generator import VerseScript
64from script_generator import RefrainScript
65from script_generator import EndingScript
66from update_package import build_update_package
67from utils import OPTIONS_MANAGER
68from utils import UPDATER_CONFIG
69from utils import parse_partition_file_xml
70from utils import unzip_package
71from utils import clear_resource
72from utils import PRODUCT
73from utils import XML_FILE_PATH
74from utils import get_update_info
75from utils import SCRIPT_KEY_LIST
76from utils import PER_BLOCK_SIZE
77from vendor_script import create_vendor_script_class
78
79
80def type_check(arg):
81    """
82    Argument check, which is used to check whether the specified arg is a file.
83    :param arg: the arg to check
84    :return:  Check result, which is False if the arg is invalid.
85    """
86    if arg is not None and not os.path.exists(arg):
87        UPDATE_LOGGER.print_log(
88            "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
89        return False
90    return arg
91
92
93def private_key_check(arg):
94    """
95    Argument check, which is used to check whether
96    the specified arg is a private_key.
97    :param arg:  The arg to check.
98    :return: Check result, which is False if the arg is invalid.
99    """
100    if arg != "ON_SERVER" and not os.path.isfile(arg):
101        UPDATE_LOGGER.print_log(
102            "FileNotFoundError, path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
103        return False
104    return arg
105
106
107def check_update_package(arg):
108    """
109    Argument check, which is used to check whether
110    the update package path exists.
111    :param arg: The arg to check.
112    :return: Check result
113    """
114    make_dir_path = None
115    if os.path.exists(arg):
116        if os.path.isfile(arg):
117            UPDATE_LOGGER.print_log(
118                "Update package must be a dir path, not a file path. "
119                "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
120            return False
121    else:
122        try:
123            UPDATE_LOGGER.print_log(
124                "Update package path does  not exist. The dir will be created!"
125                "path: %s" % arg, UPDATE_LOGGER.WARNING_LOG)
126            os.makedirs(arg)
127            make_dir_path = arg
128        except OSError:
129            UPDATE_LOGGER.print_log(
130                "Make update package path dir failed! "
131                "path: %s" % arg, UPDATE_LOGGER.ERROR_LOG)
132            return False
133    if make_dir_path is not None:
134        OPTIONS_MANAGER.make_dir_path = make_dir_path
135    return arg
136
137
138def create_entrance_args():
139    """
140    Arguments for the tool to create an update package
141    :return source_package : source version package
142            target_package : target version package
143            update_package : update package output path
144            no_zip : whether to enable the update package zip function.
145            partition_file : partition table XML file
146            signing_algorithm : signature algorithm (ECC and RSA (default))
147            private_key : path of the private key file
148    """
149    description = "Tool for creating update package."
150    parser = argparse.ArgumentParser(description=description)
151    parser.add_argument("-s", "--source_package", type=type_check,
152                        default=None, help="Source package file path.")
153    parser.add_argument("target_package", type=type_check,
154                        help="Target package file path.")
155    parser.add_argument("update_package", type=check_update_package,
156                        help="Update package file path.")
157    parser.add_argument("-nz", "--no_zip", action='store_true',
158                        help="No zip mode, Output update package without zip.")
159    parser.add_argument("-pf", "--partition_file", default=None,
160                        help="Variable partition mode, "
161                             "Partition list file path.")
162    parser.add_argument("-sa", "--signing_algorithm", default='RSA',
163                        choices=['ECC', 'RSA'],
164                        help="The signing algorithm "
165                             "supported by the tool include ['ECC', 'RSA'].")
166    parser.add_argument("-ha", "--hash_algorithm", default='sha256',
167                        choices=['sha256', 'sha384'],
168                        help="The hash algorithm "
169                             "supported by the tool include "
170                             "['sha256', 'sha384'].")
171    parser.add_argument("-pk", "--private_key", type=private_key_check,
172                        default=None, help="Private key file path.")
173    parser.add_argument("-nl2", "--not_l2", action='store_true',
174                        help="Not L2 mode, Distinguish between L1 and L2.")
175    parser.add_argument("-sl", "--signing_length", default='256',
176                        choices=['256', '384'],
177                        help="The signing content length "
178                             "supported by the tool include "
179                             "['256', '384'].")
180    parser.add_argument("-xp", "--xml_path", type=private_key_check,
181                        default=None, help="XML file path.")
182    parser.add_argument("-sc", "--sd_card", action='store_true',
183                        help="SD Card mode, "
184                             "Create update package for SD Card.")
185
186    args = parser.parse_args()
187    source_package = args.source_package
188    OPTIONS_MANAGER.source_package = source_package
189    target_package = args.target_package
190    OPTIONS_MANAGER.target_package = target_package
191    update_package = args.update_package
192    OPTIONS_MANAGER.update_package = update_package
193    no_zip = args.no_zip
194    OPTIONS_MANAGER.no_zip = no_zip
195    partition_file = args.partition_file
196    OPTIONS_MANAGER.partition_file = partition_file
197    signing_algorithm = args.signing_algorithm
198    OPTIONS_MANAGER.signing_algorithm = signing_algorithm
199    hash_algorithm = args.hash_algorithm
200    OPTIONS_MANAGER.hash_algorithm = hash_algorithm
201    private_key = args.private_key
202    OPTIONS_MANAGER.private_key = private_key
203
204    not_l2 = args.not_l2
205    OPTIONS_MANAGER.not_l2 = not_l2
206    signing_length = int(args.signing_length)
207    OPTIONS_MANAGER.signing_length = signing_length
208    xml_path = args.xml_path
209    OPTIONS_MANAGER.xml_path = xml_path
210    sd_card = args.sd_card
211    OPTIONS_MANAGER.sd_card = sd_card
212
213    ret_args = [source_package, target_package, update_package,
214                no_zip, not_l2, partition_file, signing_algorithm,
215                hash_algorithm, private_key]
216    return ret_args
217
218
219def get_script_obj():
220    """
221    Obtain Opera script object
222    :return:
223    """
224    script_obj_list = create_vendor_script_class()
225    if script_obj_list == [None] * len(SCRIPT_KEY_LIST):
226        prelude_script = PreludeScript()
227        verse_script = VerseScript()
228        refrain_script = RefrainScript()
229        ending_script = EndingScript()
230    else:
231        UPDATE_LOGGER.print_log(
232            "Get vendor extension object completed!"
233            "The vendor extension script will be generated.")
234        prelude_script = script_obj_list[0]
235        verse_script = script_obj_list[1]
236        refrain_script = script_obj_list[2]
237        ending_script = script_obj_list[3]
238    return prelude_script, verse_script, refrain_script, ending_script
239
240
241def check_incremental_args(no_zip, partition_file, source_package,
242                           incremental_img_list):
243    """
244    When the incremental list is not empty, incremental processing is required.
245    In this case, check related arguments.
246    :param no_zip: no zip mode
247    :param partition_file:
248    :param source_package:
249    :param incremental_img_list:
250    :return:
251    """
252    if "boot" in incremental_img_list:
253        UPDATE_LOGGER.print_log(
254            "boot cannot be incrementally processed!",
255            UPDATE_LOGGER.ERROR_LOG)
256        clear_resource(err_clear=True)
257        return False
258    if source_package is None:
259        UPDATE_LOGGER.print_log(
260            "The source package is missing, "
261            "cannot be incrementally processed!",
262            UPDATE_LOGGER.ERROR_LOG)
263        clear_resource(err_clear=True)
264        return False
265    if no_zip:
266        UPDATE_LOGGER.print_log(
267            "No ZIP mode, cannot be incrementally processed!",
268            UPDATE_LOGGER.ERROR_LOG)
269        clear_resource(err_clear=True)
270        return False
271    if partition_file is not None:
272        UPDATE_LOGGER.print_log(
273            "Partition file is not None, "
274            "cannot be incrementally processed!",
275            UPDATE_LOGGER.ERROR_LOG)
276        clear_resource(err_clear=True)
277        return False
278
279    OPTIONS_MANAGER.source_package_temp_obj, \
280        OPTIONS_MANAGER.source_package_dir = \
281        unzip_package(source_package, origin='source')
282    xml_path = ''
283    if OPTIONS_MANAGER.source_package_dir is not False:
284        xml_path = os.path.join(OPTIONS_MANAGER.source_package_dir,
285                                UPDATER_CONFIG, XML_FILE_PATH)
286    if OPTIONS_MANAGER.source_package_dir is False:
287        OPTIONS_MANAGER.source_package_temp_obj = None
288        OPTIONS_MANAGER.source_package_dir = None
289    if os.path.exists(xml_path):
290        with open(xml_path, 'r') as xml_file:
291            xml_str = xml_file.read()
292    else:
293        UPDATE_LOGGER.print_log("XML file does not exist! xml path: %s" %
294                                xml_path, UPDATE_LOGGER.ERROR_LOG)
295        return False
296    xml_content_dict = xmltodict.parse(xml_str, encoding='utf-8')
297    package_dict = xml_content_dict.get('package', {})
298    head_dict = package_dict.get('head', {}).get('info')
299    OPTIONS_MANAGER.source_package_version = head_dict.get("@softVersion")
300    if check_package_version(OPTIONS_MANAGER.target_package_version,
301                             OPTIONS_MANAGER.source_package_version) is False:
302        clear_resource(err_clear=True)
303        return False
304    return True
305
306
307def check_userdata_image():
308    """
309    Check the userdata image. Updating this image is prohibited.
310    :return:
311    """
312    if 'userdata' in OPTIONS_MANAGER.full_img_list or \
313            'userdata' in OPTIONS_MANAGER.incremental_img_list:
314        UPDATE_LOGGER.print_log(
315            "userdata image does not participate in update!"
316            "Please check xml config, path: %s!" %
317            os.path.join(OPTIONS_MANAGER.target_package_config_dir,
318                         XML_FILE_PATH),
319            UPDATE_LOGGER.ERROR_LOG)
320        clear_resource(err_clear=True)
321        return False
322    return True
323
324
325def check_images_list():
326    """
327    Check full_img_list and incremental_img_list.
328    If their lengths are 0, an error will be logged.
329    :return:
330    """
331    if len(OPTIONS_MANAGER.full_img_list) == 0 and \
332            len(OPTIONS_MANAGER.incremental_img_list) == 0:
333        UPDATE_LOGGER.print_log(
334            "The image list is empty!"
335            "Please check xml config, path: %s!" %
336            os.path.join(OPTIONS_MANAGER.target_package_config_dir,
337                         XML_FILE_PATH),
338            UPDATE_LOGGER.ERROR_LOG)
339        clear_resource(err_clear=True)
340        return False
341    return True
342
343
344def check_target_package_path(target_package):
345    """
346    Check the target_package path.
347    :param target_package: target package path
348    :return:
349    """
350    if os.path.isdir(target_package):
351        OPTIONS_MANAGER.target_package_dir = target_package
352        temp_dir_list = os.listdir(target_package)
353        if UPDATER_CONFIG in temp_dir_list:
354            OPTIONS_MANAGER.target_package_config_dir = \
355                os.path.join(target_package, UPDATER_CONFIG)
356        else:
357            UPDATE_LOGGER.print_log(
358                "Exception's target package path! path: %s" %
359                target_package, UPDATE_LOGGER.ERROR_LOG)
360            return False
361    elif target_package.endswith('.zip'):
362        # Decompress the target package.
363        tmp_dir_obj, unzip_dir = unzip_package(target_package)
364        if tmp_dir_obj is False or unzip_dir is False:
365            clear_resource(err_clear=True)
366            return False
367        OPTIONS_MANAGER.target_package_dir = unzip_dir
368        OPTIONS_MANAGER.target_package_temp_obj = tmp_dir_obj
369        OPTIONS_MANAGER.target_package_config_dir = \
370            os.path.join(unzip_dir, UPDATER_CONFIG)
371    else:
372        UPDATE_LOGGER.print_log(
373            "Input Update Package type exception! path: %s" %
374            target_package, UPDATE_LOGGER.ERROR_LOG)
375        clear_resource(err_clear=True)
376        return False
377    return True
378
379
380def check_miss_private_key(private_key):
381    """
382    Check private key.
383    :param private_key:
384    :return:
385    """
386    if private_key is None:
387        UPDATE_LOGGER.print_log(
388            "Private key is None, update package cannot be signed! "
389            "Please specify the signature private key by -pk.",
390            UPDATE_LOGGER.ERROR_LOG)
391        clear_resource(err_clear=True)
392        return False
393    return True
394
395
396def check_package_version(target_ver, source_ver):
397    """
398    target_ver: target version
399    source_ver: source version
400    return:
401    """
402    try:
403        target_num = ''.join(target_ver.split(' ')[-1].split('.')[1:3])
404        source_num = ''.join(source_ver.split(' ')[-1].split('.')[1:3])
405        if int(target_num) <= int(source_num):
406            UPDATE_LOGGER.print_log(
407                'Target package version %s <= Source package version!'
408                'Unable to make updater package!',
409                UPDATE_LOGGER.ERROR_LOG)
410            return False
411    except ValueError:
412        UPDATE_LOGGER.print_log('your package version number is not compliant.'
413                                'Please check your package version number!',
414                                UPDATE_LOGGER.ERROR_LOG)
415        return False
416    return True
417
418
419def increment_image_processing(
420        verse_script, incremental_img_list, source_package_dir,
421        target_package_dir):
422    """
423    Incremental image processing
424    :param verse_script: verse script
425    :param incremental_img_list: incremental image list
426    :param source_package_dir: source package path
427    :param target_package_dir: target package path
428    :return:
429    """
430    script_check_cmd_list = []
431    script_write_cmd_list = []
432    patch_process = None
433    for each_img in incremental_img_list:
434        each_src_image_path = \
435            os.path.join(source_package_dir,
436                         '%s.img' % each_img)
437        each_src_map_path = \
438            os.path.join(source_package_dir,
439                         '%s.map' % each_img)
440        each_tgt_image_path = \
441            os.path.join(target_package_dir,
442                         '%s.img' % each_img)
443        each_tgt_map_path = \
444            os.path.join(target_package_dir,
445                         '%s.map' % each_img)
446        if not os.path.exists(each_src_image_path):
447            UPDATE_LOGGER.print_log(
448                "The source %s.img file is missing from the source package, "
449                "the component: %s cannot be incrementally processed. "
450                "path: %s!" %
451                (each_img, each_img,
452                 os.path.join(source_package_dir, UPDATER_CONFIG,
453                              XML_FILE_PATH)),
454                UPDATE_LOGGER.ERROR_LOG)
455            clear_resource(err_clear=True)
456            return False
457
458        src_is_sparse = is_sparse_image(each_src_image_path)
459        tgt_is_sparse = is_sparse_image(each_tgt_image_path)
460        check_make_map_path(each_img)
461        cmd = ["e2fsdroid", "-B", each_src_map_path,
462               "-a", "/%s" % each_img, each_src_image_path]
463        if not src_is_sparse:
464            cmd.append("-e")
465        sub_p = subprocess.Popen(
466            cmd, shell=False, stdout=subprocess.PIPE,
467            stderr=subprocess.STDOUT)
468        sub_p.wait()
469
470        if not os.path.exists(each_tgt_image_path):
471            UPDATE_LOGGER.print_log(
472                "The target %s.img file is missing from the target package, "
473                "the component: %s cannot be incrementally processed. "
474                "Please check xml config, path: %s!" %
475                (each_img, each_img,
476                 os.path.join(target_package_dir, UPDATER_CONFIG,
477                              XML_FILE_PATH)),
478                UPDATE_LOGGER.ERROR_LOG)
479            clear_resource(err_clear=True)
480            return False
481
482        cmd = ["e2fsdroid", "-B", each_tgt_map_path,
483               "-a", "/%s" % each_img, each_tgt_image_path]
484        if not tgt_is_sparse:
485            cmd.append("-e")
486        sub_p = subprocess.Popen(
487            cmd, shell=False, stdout=subprocess.PIPE,
488            stderr=subprocess.STDOUT)
489        sub_p.wait()
490
491        if filecmp.cmp(each_src_image_path, each_tgt_image_path):
492            UPDATE_LOGGER.print_log(
493                "Source Image is the same as Target Image!"
494                "src image path: %s, tgt image path: %s" %
495                (each_src_image_path, each_tgt_image_path),
496                UPDATE_LOGGER.ERROR_LOG)
497            clear_resource(err_clear=True)
498            return False
499        if not src_is_sparse and not tgt_is_sparse:
500            src_image_class = \
501                IncUpdateImage(each_src_image_path, each_src_map_path)
502            tgt_image_class = \
503                IncUpdateImage(each_tgt_image_path, each_tgt_map_path)
504        else:
505            raise RuntimeError
506
507        transfers_manager = TransfersManager(
508            each_img, tgt_image_class, src_image_class)
509        transfers_manager.find_process_needs()
510        actions_list = transfers_manager.get_action_list()
511
512        graph_process = GigraphProcess(actions_list, src_image_class,
513                                       tgt_image_class)
514        actions_list = graph_process.actions_list
515        patch_process = \
516            patch_package_process.PatchProcess(
517                each_img, tgt_image_class, src_image_class, actions_list)
518        patch_process.patch_process()
519        patch_process.package_patch_zip.package_patch_zip()
520        patch_process.write_script(each_img, script_check_cmd_list,
521                                   script_write_cmd_list, verse_script)
522    if not check_patch_file(patch_process):
523        UPDATE_LOGGER.print_log(
524            'Verify the incremental result failed!',
525            UPDATE_LOGGER.ERROR_LOG)
526        raise RuntimeError
527    UPDATE_LOGGER.print_log(
528            'Verify the incremental result successfully!',
529            UPDATE_LOGGER.INFO_LOG)
530
531    verse_script.add_command(
532        "\n# ---- start incremental check here ----\n")
533    for each_check_cmd in script_check_cmd_list:
534        verse_script.add_command(each_check_cmd)
535    verse_script.add_command(
536        "\n# ---- start incremental write here ----\n")
537    for each_write_cmd in script_write_cmd_list:
538        verse_script.add_command(each_write_cmd)
539    return True
540
541
542def check_patch_file(patch_process):
543    new_dat_file_obj, patch_dat_file_obj, transfer_list_file_obj = \
544        patch_process.package_patch_zip.get_file_obj()
545    with open(transfer_list_file_obj.name) as f_t:
546        num = 0
547        diff_str = None
548        diff_num = 0
549        for line in f_t:
550            if line.startswith('new '):
551                each_line_list = \
552                    line.strip().replace("new ", "").split(",")[1:]
553                for idx in range(0, len(each_line_list), 2):
554                    num += \
555                        int(each_line_list[idx + 1]) - int(each_line_list[idx])
556                continue
557            if line.startswith('bsdiff ') or line.startswith('pkgdiff '):
558                diff_str = line
559        if diff_str:
560            diff_list = diff_str.split('\n')[0].split(' ')
561            diff_num = int(diff_list[1]) + int(diff_list[2])
562    check_flag = \
563        (os.path.getsize(new_dat_file_obj.name) == num * PER_BLOCK_SIZE) and \
564        (os.path.getsize(patch_dat_file_obj.name) == diff_num)
565    return check_flag
566
567
568def check_make_map_path(each_img):
569    """
570    If env does not exist, the command for map generation does not exist
571    in the environment variable, and False will be returned.
572    """
573    try:
574        cmd = ["e2fsdroid", " -h"]
575        subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE,
576                         stderr=subprocess.STDOUT)
577    except FileNotFoundError:
578        UPDATE_LOGGER.print_log(
579            "Command not found, need check the env! "
580            "Make %s.map failed!" % each_img,
581            UPDATE_LOGGER.ERROR_LOG)
582        clear_resource(err_clear=True)
583        raise RuntimeError
584    return True
585
586
587def incremental_processing(no_zip, partition_file, source_package,
588                           verse_script):
589    """
590    Incremental processing.
591    :param no_zip: no zip mode
592    :param partition_file: partition xml file path
593    :param source_package: source package path
594    :param verse_script: verse script obj
595    :return : processing result
596    """
597    if len(OPTIONS_MANAGER.incremental_img_list) != 0:
598        if check_incremental_args(no_zip, partition_file, source_package,
599                                  OPTIONS_MANAGER.incremental_img_list) \
600                is False:
601            return False
602        if increment_image_processing(
603                verse_script, OPTIONS_MANAGER.incremental_img_list,
604                OPTIONS_MANAGER.source_package_dir,
605                OPTIONS_MANAGER.target_package_dir) is False:
606            return False
607    else:
608        if source_package is not None:
609            UPDATE_LOGGER.print_log(
610                "There is no incremental image, "
611                "the - S parameter is not required!",
612                UPDATE_LOGGER.ERROR_LOG)
613            raise RuntimeError
614
615
616def check_args(private_key, source_package, target_package, update_package):
617    """
618    Input args check.
619    :param private_key: private key path
620    :param source_package: source package path
621    :param target_package: target package path
622    :param update_package: output package path
623    :return : Judgment result
624    """
625    if source_package is False or private_key is False or \
626            target_package is False or update_package is False:
627        return False
628    if check_miss_private_key(private_key) is False:
629        return False
630    if check_target_package_path(target_package) is False:
631        return False
632    if get_update_info() is False:
633        return False
634    if check_images_list() is False:
635        return False
636    return True
637
638
639def main():
640    """
641    Entry function.
642    """
643    OPTIONS_MANAGER.product = PRODUCT
644
645    source_package, target_package, update_package, no_zip, not_l2, \
646        partition_file, signing_algorithm, hash_algorithm, private_key = \
647        create_entrance_args()
648    if not_l2:
649        no_zip = True
650    if OPTIONS_MANAGER.sd_card:
651        if source_package is not None or \
652                OPTIONS_MANAGER.xml_path is not None or \
653                partition_file is not None:
654            UPDATE_LOGGER.print_log(
655                "SD Card updater, "
656                "the -S/-xp/-pf parameter is not required!",
657                UPDATE_LOGGER.ERROR_LOG)
658            raise RuntimeError
659    if check_args(private_key, source_package,
660                  target_package, update_package) is False:
661        clear_resource(err_clear=True)
662        return
663
664    if not OPTIONS_MANAGER.sd_card:
665        if check_userdata_image() is False:
666            clear_resource(err_clear=True)
667            return
668
669    # Create a Script object.
670    prelude_script, verse_script, refrain_script, ending_script = \
671        get_script_obj()
672
673    # Create partition.
674    if partition_file is not None:
675        verse_script.add_command("\n# ---- do updater partitions ----\n")
676        updater_partitions_cmd = verse_script.updater_partitions()
677        verse_script.add_command(updater_partitions_cmd)
678
679        partition_file_obj, partitions_list, partitions_file_path_list = \
680            parse_partition_file_xml(partition_file)
681        if partition_file_obj is False:
682            clear_resource(err_clear=True)
683            return False
684        OPTIONS_MANAGER.partition_file_obj = partition_file_obj
685        OPTIONS_MANAGER.full_img_list = partitions_list
686        OPTIONS_MANAGER.full_image_path_list = partitions_file_path_list
687        OPTIONS_MANAGER.two_step = False
688
689    # Upgrade the updater image.
690    if OPTIONS_MANAGER.two_step:
691        get_status_cmd = verse_script.get_status()
692        set_status_0_cmd = verse_script.set_status('0')
693        set_status_1_cmd = verse_script.set_status('1')
694        reboot_now_cmd = verse_script.reboot_now()
695        create_updater_script_command = \
696            '\n# ---- do updater partitions ----\n\n' \
697            'if ({get_status_cmd} == 0){{\nUPDATER_WRITE_FLAG\n' \
698            '    {set_status_1_cmd}    {reboot_now_cmd}}}\n' \
699            'else{{    \nALL_WRITE_FLAG\n    {set_status_0_cmd}}}'.format(
700                get_status_cmd=get_status_cmd,
701                set_status_1_cmd=set_status_1_cmd,
702                set_status_0_cmd=set_status_0_cmd,
703                reboot_now_cmd=reboot_now_cmd)
704        verse_script.add_command(create_updater_script_command)
705
706    if incremental_processing(
707            no_zip, partition_file, source_package, verse_script) is False:
708        clear_resource(err_clear=True)
709        return
710
711    # Full processing
712    if len(OPTIONS_MANAGER.full_img_list) != 0:
713        verse_script.add_command("\n# ---- full image ----\n")
714        full_image_content_len_list, full_image_file_obj_list = \
715            FullUpdateImage(OPTIONS_MANAGER.target_package_dir,
716                            OPTIONS_MANAGER.full_img_list, verse_script,
717                            OPTIONS_MANAGER.full_image_path_list,
718                            no_zip=OPTIONS_MANAGER.no_zip).\
719            update_full_image()
720        if full_image_content_len_list is False or \
721                full_image_file_obj_list is False:
722            clear_resource(err_clear=True)
723            return
724        OPTIONS_MANAGER.full_image_content_len_list, \
725            OPTIONS_MANAGER.full_image_file_obj_list = \
726            full_image_content_len_list, full_image_file_obj_list
727
728    # Generate the update package.
729    build_re = build_update_package(no_zip, update_package,
730                                    prelude_script, verse_script,
731                                    refrain_script, ending_script)
732    if build_re is False:
733        clear_resource(err_clear=True)
734        return
735    # Clear resources.
736    clear_resource()
737
738
739if __name__ == '__main__':
740    main()
741