1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2020-2021 Huawei Device Co., Ltd.
5#
6# HDF is dual licensed: you can use it either under the terms of
7# the GPL, or the BSD license, at your option.
8# See the LICENSE file in the root of this repository for complete details.
9
10
11import configparser
12import json
13import os
14import shutil
15from string import Template
16
17import hdf_utils
18from hdf_tool_exception import HdfToolException
19from .hdf_command_error_code import CommandErrorCode
20from .hdf_command_handler_base import HdfCommandHandlerBase
21from .hdf_defconfig_patch import HdfDefconfigAndPatch
22from .hdf_device_info_hcs import HdfDeviceInfoHcsFile
23from .hdf_get_handler import HdfGetHandler
24from .hdf_vendor_build_file import HdfVendorBuildFile
25from .hdf_vendor_kconfig_file import HdfVendorKconfigFile
26from .hdf_vendor_makefile import HdfVendorMakeFile
27from .hdf_vendor_mk_file import HdfVendorMkFile
28from .hdf_module_kconfig_file import HdfModuleKconfigFile
29from .hdf_module_mk_file import HdfModuleMkFile
30from .hdf_driver_config_file import HdfDriverConfigFile
31
32
33class HdfDeleteHandler(HdfCommandHandlerBase):
34    def __init__(self, args):
35        super(HdfDeleteHandler, self).__init__()
36        self.cmd = 'delete'
37        self.handlers = {
38            'vendor': self._delete_vendor_handler,
39            'module': self._delete_module_handler,
40            'driver': self._delete_driver_handler,
41            'module_driver': self._delete_module_driver_handler,
42        }
43        self.parser.add_argument("--action_type",
44                                 help=' '.join(self.handlers.keys()),
45                                 required=True)
46        self.parser.add_argument("--root_dir", required=True)
47        self.parser.add_argument("--vendor_name")
48        self.parser.add_argument("--module_name")
49        self.parser.add_argument("--driver_name")
50        self.parser.add_argument("--board_name")
51        self.parser.add_argument("--kernel_name")
52        self.parser.add_argument("--device_name")
53        self.args_original = args
54        self.args = self.parser.parse_args(args)
55
56    def config_delete_operation_liteos(
57            self, driver_name, driver_config_index, temp_file, file_path):
58        key_list = list(filter(
59            lambda x: x.endswith(driver_name.upper()),
60            driver_config_index.keys()))
61        if key_list:
62            key_name = key_list[0]
63            res = temp_file.get_driver_config_str(
64                driver_index=driver_config_index[key_name])
65            temp_info = hdf_utils.read_file(file_path)
66            hdf_utils.write_file(file_path, "".join(temp_info.split(res)))
67
68    def config_delete_operation_linux(
69            self, driver_name, driver_config_index, file_path):
70        key_list = list(filter(
71            lambda x: x.endswith(driver_name.upper()),
72            driver_config_index.keys()))
73        if key_list:
74            key_name = key_list[0]
75            res = driver_config_index[key_name].rstrip("endif")
76            temp_info = hdf_utils.read_file(file_path)
77            hdf_utils.write_file(file_path, "".join(temp_info.split(res)))
78
79    def linux_liteos_common(self, file_name, file_path,
80                            module_name, driver_name):
81        root, _, module, _, _, kernel, device = self.get_args()
82        if file_name == "Kconfig":
83            config_re_str = r"DRIVERS_HDF_(?P<name>.+[A-Z0-9])"
84            flag_re = r"config"
85            temp_file = hdf_utils.MakefileAndKconfigFileParse(
86                file_path=file_path, flag_str=flag_re, re_name=config_re_str)
87            driver_config_index = temp_file.split_driver_start_to_end()
88            self.config_delete_operation_linux(
89                driver_name, driver_config_index, file_path)
90        elif file_name.endswith("hcs"):
91            HdfDeviceInfoHcsFile(
92                root=root, vendor="", module="",
93                board="", driver=" ", path=file_path). \
94                delete_driver(module=driver_name, temp_flag="device")
95        elif file_name.endswith("dot_configs"):
96            if module_name == "sensor":
97                temp_res = self.sensor_device_rely(module, kernel, device)
98            else:
99                temp_res = []
100            for dot_path in file_path:
101                if dot_path.split(".")[-1] == "config":
102                    template_string = \
103                        "LOSCFG_DRIVERS_HDF_${module_upper}_${driver_upper}=y\n"
104                else:
105                    template_string = \
106                        "CONFIG_DRIVERS_HDF_${module_upper}_${driver_upper}=y\n"
107                new_demo_config = Template(template_string). \
108                    substitute({
109                        "module_upper": module_name.upper(),
110                        "driver_upper": driver_name.upper(),
111                    })
112                temp_res.append(new_demo_config)
113                defconfig_patch = HdfDefconfigAndPatch(
114                    root=root, vendor="", kernel="", board="",
115                    data_model="", new_demo_config=temp_res)
116                defconfig_patch.delete_module(
117                    path=os.path.join(root, dot_path))
118
119    def sensor_device_rely(self, module, kernel, device):
120        templates_dir_path = hdf_utils.get_templates_lite_dir()
121        templates_model_dir = []
122        for path, dir_name, _ in os.walk(templates_dir_path):
123            if dir_name:
124                templates_model_dir.extend(dir_name)
125        temp_templates_model_dir = list(
126            filter(
127                lambda model_dir: module in model_dir,
128                templates_model_dir))
129        config_file = [
130            name for name in os.listdir(
131                os.path.join(
132                    templates_dir_path,
133                    temp_templates_model_dir[0])) if name.endswith(".ini")]
134        if config_file:
135            config_path = os.path.join(
136                templates_dir_path,
137                temp_templates_model_dir[0],
138                config_file[0])
139            config = configparser.ConfigParser()
140            config.read(config_path)
141            section_list = config.options(section=kernel)
142            if device in section_list:
143                device_enable_config, _ = hdf_utils.ini_file_read_operation(
144                    section_name=kernel,
145                    node_name=device, path=config_path)
146            else:
147                if kernel == "linux":
148                    device_enable_config = [
149                        "CONFIG_DRIVERS_HDF_SENSOR_ACCEL=y\n"]
150                else:
151                    device_enable_config = [
152                        "LOSCFG_DRIVERS_HDF_SENSOR_ACCEL=y\n"]
153        else:
154            device_enable_config = [""]
155        return device_enable_config
156
157    def _delete_vendor_handler(self):
158        self.check_arg_raise_if_not_exist("vendor_name")
159        self.check_arg_raise_if_not_exist("board_name")
160        root, vendor, _, _, _ = self.get_args()
161        vendor_hdf_dir = hdf_utils.get_vendor_hdf_dir(root, vendor)
162        if not os.path.exists(vendor_hdf_dir):
163            return
164        for module in os.listdir(vendor_hdf_dir):
165            mod_dir = os.path.join(vendor_hdf_dir, module)
166            if os.path.isdir(mod_dir):
167                pass
168        shutil.rmtree(vendor_hdf_dir)
169
170    def _delete_module(self, root, model, model_info):
171        for key, path_value in model_info.items():
172            if key.split("_")[-1] == "name":
173                pass
174            elif key == "driver_file_path":
175                split_str = '/%s/driver' % model
176                driver_file = os.path.join(
177                    root, path_value.rsplit(split_str, 1)[0], model)
178                if os.path.exists(driver_file):
179                    shutil.rmtree(driver_file)
180            else:
181                self._delete_file_func(root, key, model_info, model)
182        create_model_data = self._delete_model_info()
183        delete_model_info = hdf_utils.get_create_model_info(
184            root=root, create_data=json.dumps(create_model_data))
185        return delete_model_info
186
187    def _delete_model_info(self):
188        self.check_arg_raise_if_not_exist("root_dir")
189        self.check_arg_raise_if_not_exist("module_name")
190        root, _, module, _, _, _, _ = self.get_args()
191        create_file_save_path = hdf_utils.module_save_file_info(root)
192        data = hdf_utils.read_file(create_file_save_path)
193        write_data = json.loads(data)
194        write_data.pop(module)
195        hdf_utils.write_file(create_file_save_path,
196                             json.dumps(write_data, indent=4))
197        return write_data
198
199    def _delete_module_handler(self):
200        self.check_arg_raise_if_not_exist("root_dir")
201        self.check_arg_raise_if_not_exist("module_name")
202        root, _, module, _, _, _, _ = self.get_args()
203        create_file_save_path = hdf_utils.module_save_file_info(root)
204        data = hdf_utils.read_file(create_file_save_path)
205        file_info = json.loads(data)
206        model_info = file_info.get(module, None)
207        if model_info is None:
208            raise HdfToolException(
209                ' delete model "%s" not exist' %
210                module, CommandErrorCode.TARGET_NOT_EXIST)
211        else:
212            return self._delete_module(root, module, model_info)
213
214    def _delete_driver(self, module, driver):
215        root, vendor, _, _, board, kernel = self.get_args()
216        drv_dir = hdf_utils.get_drv_dir(root, vendor, module, driver)
217        if os.path.exists(drv_dir):
218            shutil.rmtree(drv_dir)
219        k_path = hdf_utils.get_module_kconfig_path(root, vendor, module)
220        HdfModuleKconfigFile(root, module, k_path).delete_driver(driver)
221        HdfModuleMkFile(root, vendor, module).delete_driver(driver)
222        HdfDriverConfigFile(root, board, module, driver, kernel).delete_driver()
223
224    def _delete_driver_handler(self):
225        self.check_arg_raise_if_not_exist("vendor_name")
226        self.check_arg_raise_if_not_exist("module_name")
227        self.check_arg_raise_if_not_exist("driver_name")
228        self.check_arg_raise_if_not_exist("board_name")
229        _, _, module, driver, _ = self.get_args()
230        self._delete_driver(module, driver)
231
232    def _delete_file_func(self, root, key, model_info, model):
233        if key.startswith("module_level_config"):
234            for key_name, value in model_info[key].items():
235                self._delete_config_operation(
236                    key_name, value, temp_root=root, temp_model=model)
237
238        elif key == "module_path":
239            for file_name, module_value in model_info[key].items():
240                self._delete_module_file(root, model, file_name, module_value)
241
242    def _delete_module_file(self, root, model, file_name, module_value):
243        if file_name.startswith("adapter"):
244            file_path = os.path.join(root, module_value)
245            file_info = hdf_utils.read_file_lines(file_path)
246            delete_info = "libhdf_%s_hotplug" % model
247
248            for index, line_info in enumerate(file_info):
249                if line_info.find(delete_info) > 0:
250                    file_info.pop(index)
251                    hdf_utils.write_file_lines(file_path, file_info)
252                    break
253        elif file_name == "group" or file_name == "passwd":
254            file_path = os.path.join(root, module_value)
255            file_info = hdf_utils.read_file_lines(file_path)
256            for index, line in enumerate(file_info):
257                if line.find(model) != -1:
258                    file_info.pop(index)
259            hdf_utils.write_file_lines(file_path, file_info)
260        else:
261            if module_value.endswith("hcs"):
262                hcs_path = os.path.join(root, module_value)
263                HdfDeviceInfoHcsFile(
264                    root=root, vendor="", module="",
265                    board="", driver=" ", path=hcs_path). \
266                    delete_driver(module=model)
267            else:
268                if not module_value:
269                    return
270                file_path = os.path.join(root, module_value)
271                if os.path.exists(file_path):
272                    os.remove(file_path)
273                model_dir_path = "/".join(file_path.split("/")[:-1])
274                if not os.path.exists(model_dir_path):
275                    return
276                file_list = os.listdir(model_dir_path)
277                if not file_list:
278                    shutil.rmtree(model_dir_path)
279
280    def _delete_config_operation(self, key_name, value, temp_root, temp_model):
281        if key_name == "%s_Makefile" % temp_model:
282            HdfVendorMakeFile(
283                temp_root, vendor="", kernel="",
284                path=os.path.join(temp_root, value)).delete_module(temp_model)
285        elif key_name == "%s_Kconfig" % temp_model:
286            HdfVendorKconfigFile(
287                temp_root, vendor="", kernel="",
288                path=os.path.join(temp_root, value)).delete_module(temp_model)
289        elif key_name == "%sBuild" % temp_model:
290            HdfVendorBuildFile(
291                temp_root, vendor="").delete_module(
292                file_path=os.path.join(temp_root, value), model=temp_model)
293        elif key_name == "%s_hdf_lite" % temp_model:
294            HdfVendorMkFile(
295                temp_root, vendor="").delete_module(
296                file_path=os.path.join(temp_root, value), module=temp_model)
297        elif key_name == "%s_dot_configs" % temp_model:
298            for dot_path in value:
299                if dot_path.split(".")[-1] == "config":
300                    template_string = \
301                        "LOSCFG_DRIVERS_HDF_${module_upper_case}=y\n"
302                else:
303                    template_string = \
304                        "CONFIG_DRIVERS_HDF_${module_upper_case}=y\n"
305                new_demo_config = Template(template_string). \
306                    substitute({"module_upper_case": temp_model.upper()})
307                defconfig_patch = HdfDefconfigAndPatch(
308                    root=temp_root, vendor="", kernel="", board="",
309                    data_model="", new_demo_config=new_demo_config)
310                defconfig_patch.delete_module(
311                    path=os.path.join(temp_root, dot_path))
312
313    def _delete_module_driver_handler(self):
314        self.check_arg_raise_if_not_exist("root_dir")
315        self.check_arg_raise_if_not_exist("kernel_name")
316        self.check_arg_raise_if_not_exist("module_name")
317        self.check_arg_raise_if_not_exist("driver_name")
318        self.check_arg_raise_if_not_exist("board_name")
319        self.check_arg_raise_if_not_exist("device_name")
320        root, _, module, driver, board, kernel, device = self.get_args()
321        get_board = HdfGetHandler(self.args_original)
322        section_res = get_board.judgement_device_in_model(device)
323        board_module_driver = get_board.delete_module_driver_list()
324        res_json_format = json.loads(board_module_driver)
325        board_name_list = list(res_json_format.keys())
326        temp_board_info = ""
327        for board_name in board_name_list:
328            board_driver = res_json_format[board_name]
329            temp_board_name = board_name.rstrip("_kernel")
330            if temp_board_name == board and kernel == "liteos":
331                self._delete_liteos_driver_config(
332                    root, model_info=board_driver, module_name=module,
333                    driver_name=driver)
334                temp_board_info = board_name
335            elif temp_board_name == board:
336                self._delete_linux_driver_config(
337                    model_info=board_driver, module_name=module,
338                    driver_name=driver)
339                temp_board_info = board_name
340            if len(board_driver) <= 1:
341                del res_json_format[board_name]
342        temp_driver_name = "-".join([device, driver])
343        if temp_board_info:
344            get_board.format_delete_driver_file(
345                model_name=module, board_name=temp_board_info,
346                driver_name=temp_driver_name)
347        get_board.delete_device_operation(device, *section_res)
348        res_driver = get_board.judge_create_driver_exist()
349        return res_driver
350
351    def _delete_liteos_driver_config(self, root, model_info, module_name, driver_name):
352        model_info_key_list = list(model_info.keys())
353        for key_name in model_info_key_list:
354            file_list = list(model_info[key_name].keys())
355            for file_name in file_list:
356                file_path = model_info[key_name][file_name]
357                if file_name == "Makefile":
358                    mk_re_str = r"ifeq.+LOSCFG_DRIVERS_HDF_(?P<name>.+[A-Z0-9])"
359                    temp_file = hdf_utils.GnMkFileParse(
360                        file_path=file_path, temp_re=mk_re_str)
361                    driver_config_index = temp_file.split_driver_start_to_end(
362                        flag_str="endif")
363                    self.config_delete_operation_liteos(
364                        driver_name, driver_config_index, temp_file, file_path)
365                elif file_name == "BUILD.gn":
366                    mk_re_str = r"if.+LOSCFG_DRIVERS_HDF_(?P<name>.+\w)"
367                    temp_file = hdf_utils.GnMkFileParse(
368                        file_path=file_path, temp_re=mk_re_str)
369                    driver_config_index = temp_file.split_driver_start_to_end(
370                        flag_str="}")
371                    self.config_delete_operation_liteos(
372                        driver_name, driver_config_index, temp_file, file_path)
373                if file_name == driver_name:
374                    self._delete_driver_file(file_path=file_path)
375                    del model_info[key_name][file_name]
376                    if not model_info[key_name]:
377                        del model_info[key_name]
378                else:
379                    self.linux_liteos_common(
380                        file_name, file_path, module_name, driver_name)
381
382    def _delete_linux_driver_config(
383            self, model_info, module_name, driver_name):
384        model_info_key_list = list(model_info.keys())
385        for key_name in model_info_key_list:
386            file_list = list(model_info[key_name].keys())
387            for file_name in file_list:
388                file_path = model_info[key_name][file_name]
389                if file_name == "Makefile":
390                    mk_re_str = r"CONFIG_DRIVERS_HDF_(?P<name>.+[A-Z0-9])"
391                    flag_re = r"obj"
392                    temp_file = hdf_utils.MakefileAndKconfigFileParse(
393                        file_path=file_path, flag_str=flag_re, re_name=mk_re_str)
394                    driver_config_index = temp_file.split_driver_start_to_end()
395                    self.config_delete_operation_linux(
396                        driver_name, driver_config_index, file_path)
397                elif file_name == driver_name:
398                    self._delete_driver_file(file_path=file_path)
399                    del model_info[key_name][file_name]
400                    if not model_info[key_name]:
401                        del model_info[key_name]
402                else:
403                    self.linux_liteos_common(
404                        file_name, file_path, module_name, driver_name)
405
406    def _delete_driver_file(self, file_path):
407        for file_path_info in file_path:
408            path_temp = file_path_info
409            while os.path.exists(path_temp):
410                if os.path.isfile(path_temp):
411                    os.remove(path_temp)
412                elif os.path.isdir(path_temp) and (not os.listdir(path_temp)):
413                    os.rmdir(path_temp)
414                else:
415                    break
416                path_temp = os.path.dirname(path_temp)
417