15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport os
175f9996aaSopenharmony_ci
185f9996aaSopenharmony_cifrom resources.config import Config
195f9996aaSopenharmony_cifrom util.io_util import IoUtil
205f9996aaSopenharmony_cifrom util.system_util import SystemUtil
215f9996aaSopenharmony_cifrom exceptions.ohos_exception import OHOSException
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_ci
245f9996aaSopenharmony_ciclass Patch():
255f9996aaSopenharmony_ci    """Patch class for hb_internal.build --patch parameter
265f9996aaSopenharmony_ci    Install the patch based on the configuration file.
275f9996aaSopenharmony_ci    """
285f9996aaSopenharmony_ci    def __init__(self):
295f9996aaSopenharmony_ci        self.config = Config()
305f9996aaSopenharmony_ci        # Patch configuration file path
315f9996aaSopenharmony_ci        self.patch_cfg = os.path.join(self.config.product_path, 'patch.yml')
325f9996aaSopenharmony_ci
335f9996aaSopenharmony_ci    def patch_make(self, cmd_args=None, reverse=False):
345f9996aaSopenharmony_ci        """Patch installation entry function
355f9996aaSopenharmony_ci
365f9996aaSopenharmony_ci        Args:
375f9996aaSopenharmony_ci            reverse (bool, optional): True if the patch is rolled back,
385f9996aaSopenharmony_ci                                      else False. Defaults to False.
395f9996aaSopenharmony_ci
405f9996aaSopenharmony_ci        Raises:
415f9996aaSopenharmony_ci            OHOSException: if configuration file does not exist.
425f9996aaSopenharmony_ci        """
435f9996aaSopenharmony_ci        patch_cfg = self.config.patch_cache
445f9996aaSopenharmony_ci        # Check whether the rollback is in progress
455f9996aaSopenharmony_ci        if not reverse:
465f9996aaSopenharmony_ci            # Try to update patch cache and check whether rollback is required
475f9996aaSopenharmony_ci            self.patch_cache_update()
485f9996aaSopenharmony_ci            patch_cfg = self.patch_cfg
495f9996aaSopenharmony_ci
505f9996aaSopenharmony_ci        if not os.path.isfile(patch_cfg):
515f9996aaSopenharmony_ci            raise OHOSException(f'{patch_cfg} not found, '
525f9996aaSopenharmony_ci                                'which "--patch" parameter needs', '0020')
535f9996aaSopenharmony_ci
545f9996aaSopenharmony_ci        patch_cfg_dict = IoUtil.read_yaml_file(patch_cfg)
555f9996aaSopenharmony_ci        for src_path, patch_list in patch_cfg_dict.items():
565f9996aaSopenharmony_ci            self.patch_apply(src_path, patch_list, reverse)
575f9996aaSopenharmony_ci
585f9996aaSopenharmony_ci    def patch_apply(self, src_path, patch_list, reverse=False):
595f9996aaSopenharmony_ci        """Run the patch installation command.
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_ci        Args:
625f9996aaSopenharmony_ci            src_path (string): Path to which the patch needs to be installed
635f9996aaSopenharmony_ci            patch_list (list): List of paths for storing patches
645f9996aaSopenharmony_ci            reverse (bool, optional): True if the patch is rolled back,
655f9996aaSopenharmony_ci                                      else False. Defaults to False.
665f9996aaSopenharmony_ci
675f9996aaSopenharmony_ci        Raises:
685f9996aaSopenharmony_ci            OHOSException: src_path or patch_path is invalid,
695f9996aaSopenharmony_ci                           or the command fails to be executed.
705f9996aaSopenharmony_ci        """
715f9996aaSopenharmony_ci        src_path = os.path.join(self.config.root_path, src_path)
725f9996aaSopenharmony_ci        if not os.path.exists(src_path):
735f9996aaSopenharmony_ci            raise OHOSException(f'{src_path} not exist, stop applying patch', '0021')
745f9996aaSopenharmony_ci
755f9996aaSopenharmony_ci        cmd = ''
765f9996aaSopenharmony_ci        for patch_item in patch_list:
775f9996aaSopenharmony_ci            patch_path = os.path.join(self.config.root_path, patch_item)
785f9996aaSopenharmony_ci            if not os.path.isfile(patch_path):
795f9996aaSopenharmony_ci                patch_path = os.path.join(self.config.root_path,
805f9996aaSopenharmony_ci                                          src_path, patch_item)
815f9996aaSopenharmony_ci                if not os.path.isfile(patch_path):
825f9996aaSopenharmony_ci                    raise OHOSException(f'patch {patch_item} not exist for {src_path}, '
835f9996aaSopenharmony_ci                                        'stop applying patch', '0022')
845f9996aaSopenharmony_ci            if reverse:
855f9996aaSopenharmony_ci                cmd = f'patch -p1 -R < {patch_path}'
865f9996aaSopenharmony_ci            else:
875f9996aaSopenharmony_ci                cmd = f'patch -p1 < {patch_path}'
885f9996aaSopenharmony_ci            try:
895f9996aaSopenharmony_ci                SystemUtil.exec_command(cmd, log_path=self.config.log_path,
905f9996aaSopenharmony_ci                             cwd=src_path, shell=True)
915f9996aaSopenharmony_ci            except OHOSException as ohos_exception:
925f9996aaSopenharmony_ci                # Failed to roll back the patch, clear patch cache
935f9996aaSopenharmony_ci                self.config.patch_cache = None
945f9996aaSopenharmony_ci                raise ohos_exception
955f9996aaSopenharmony_ci
965f9996aaSopenharmony_ci    def patch_cache_update(self):
975f9996aaSopenharmony_ci        """Try to update patch cache and Check whether rollback is required
985f9996aaSopenharmony_ci        If patch_cache is None, no rollback is required,
995f9996aaSopenharmony_ci        otherwise roll back patch.
1005f9996aaSopenharmony_ci        """
1015f9996aaSopenharmony_ci        # patch_cache stores the configuration file of the last patch.
1025f9996aaSopenharmony_ci        if self.config.patch_cache is not None:
1035f9996aaSopenharmony_ci            self.patch_make(reverse=True)
1045f9996aaSopenharmony_ci        # Update patch cache to current path configuration file path
1055f9996aaSopenharmony_ci        self.config.patch_cache = self.patch_cfg
1065f9996aaSopenharmony_ci
1075f9996aaSopenharmony_ci
1085f9996aaSopenharmony_ciif __name__ == "__main__":
1095f9996aaSopenharmony_ci    patch = Patch()
1105f9996aaSopenharmony_ci    patch.patch_make()
111