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 os
12import re
13from string import Template
14
15from hdf_tool_exception import HdfToolException
16from command_line.hdf_command_error_code import CommandErrorCode
17import hdf_utils
18
19
20class HdfManagerConfigFile(object):
21    def __init__(self, file_path):
22        self.file_path = file_path
23        self.file_dir = os.path.dirname(self.file_path)
24        self.host_pattern = r'%s\s*::\s*host\s*{'
25        self.hdf_manager_pattern = r'device_info\s*{'
26        self.contents = ''
27        self._read_contents()
28
29    def _read_contents(self):
30        if os.path.exists(self.file_path):
31            self.contents = hdf_utils.read_file(self.file_path)
32        else:
33            self.contents = ''
34
35    def check_and_create(self):
36        if self.contents:
37            return
38        template_str = \
39            hdf_utils.get_template('hdf_driver_manager_config.template')
40        self.contents = Template(template_str).safe_substitute({})
41        if not os.path.exists(self.file_dir):
42            os.makedirs(self.file_dir)
43        hdf_utils.write_file(self.file_path, self.contents)
44
45    def _find_range(self, pattern):
46        match_obj = re.search(pattern, self.contents)
47        if not match_obj:
48            return False
49        start = match_obj.start()
50        if start == -1:
51            return False
52        braces = []
53        start += len(match_obj.group(0)) - 1
54        end = start
55        for i in range(start, len(self.contents)):
56            if '{' == self.contents[i]:
57                braces.append('{')
58            elif '}' == self.contents[i]:
59                count = len(braces)
60                if count == 0:
61                    return False
62                if count == 1:
63                    end = i
64                    break
65                braces.pop()
66        if end != start:
67            while end > start + 1:
68                end -= 1
69                if self.contents[end] not in [' ', '\t']:
70                    break
71            return hdf_utils.SectionRange(start, end)
72        return False
73
74    @staticmethod
75    def _begin_end(module, driver):
76        dev_id = hdf_utils.get_id(module, driver)
77        device_begin = '\n/* <begin %s */\n' % dev_id
78        device_end = '\n/* %s end> */\n' % dev_id
79        return device_begin, device_end
80
81    def _create_device(self, module, driver):
82        drv_converter = hdf_utils.WordsConverter(driver)
83        data_model = {
84            'driver_lower_case': drv_converter.lower_case(),
85            'driver_lower_camel_case': drv_converter.lower_camel_case()
86        }
87        template_str = \
88            hdf_utils.get_template('hdf_driver_manager_config_device.template')
89        contents = Template(template_str).safe_substitute(data_model)
90        begin, end = self._begin_end(module, driver)
91        return hdf_utils.SectionContent(begin, contents, end)
92
93    def _get_host_range(self):
94        pattern = self.host_pattern % 'common'
95        host_range = self._find_range(pattern)
96        if not host_range:
97            self.add_host('common')
98            self._read_contents()
99            host_range = self._find_range(pattern)
100        return host_range
101
102    def add_device(self, module, driver):
103        device_config = self._create_device(module, driver)
104        old_device_range = hdf_utils.find_section(self.contents, device_config)
105        if old_device_range:
106            hdf_utils.replace_and_save(self.contents, self.file_path,
107                                       old_device_range, device_config)
108            return
109        host_range = self._get_host_range()
110        last_brace_range = hdf_utils.SectionRange(host_range.end_pos,
111                                                  host_range.end_pos)
112        hdf_utils.add_after_and_save(self.contents, self.file_path,
113                                     last_brace_range, device_config)
114
115    def delete_device(self, module, driver):
116        begin, end = self._begin_end(module, driver)
117        empty_device = hdf_utils.SectionContent(begin, '', end)
118        old_range = hdf_utils.find_section(self.contents, empty_device)
119        if old_range:
120            hdf_utils.delete_and_save(self.contents, self.file_path, old_range)
121
122    def _create_host(self, module):
123        template_str = \
124            hdf_utils.get_template('hdf_driver_manager_config_host.template')
125        mod_converter = hdf_utils.WordsConverter(module)
126        data_model = {
127            'module_lower_case': mod_converter.lower_case()
128        }
129        host_content = Template(template_str).safe_substitute(data_model)
130        begin, end = self._begin_end(module, module)
131        return hdf_utils.SectionContent(begin, host_content, end)
132
133    def add_host(self, module):
134        manager_range = self._find_range(self.hdf_manager_pattern)
135        if not manager_range:
136            raise HdfToolException('file: %s format wrong, no hdf_manager node'
137                                   ' found' % self.file_path,
138                                   CommandErrorCode.FILE_FORMAT_WRONG)
139        host_section = self._create_host(module)
140        last_brace = hdf_utils.SectionRange(manager_range.end_pos,
141                                            manager_range.end_pos)
142        hdf_utils.add_after_and_save(self.contents, self.file_path,
143                                     last_brace, host_section)
144
145    def delete_host(self, module):
146        begin, end = self._begin_end(module, module)
147        empty_section = hdf_utils.SectionContent(begin, "", end)
148        host_range = hdf_utils.find_section(self.contents, empty_section)
149        if not host_range:
150            return
151        hdf_utils.delete_and_save(self.contents, self.file_path, host_range)
152