• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 json
12import os
13import platform
14import re
15from string import Template
16
17import hdf_utils
18from hdf_tool_exception import HdfToolException
19from .hdf_command_error_code import CommandErrorCode
20
21
22class HdfLinuxScan(object):
23    def __init__(self, root, vendor, board):
24        self.root = root
25        self.vendor = vendor
26        self.board = board
27        self.kernel = "linux"
28
29        self.makefile_path = hdf_utils.get_vendor_makefile_path(
30            root, kernel="linux")
31        if not os.path.exists(self.makefile_path):
32            raise HdfToolException(
33                'Makefile: %s not exist' % self.makefile_path,
34                CommandErrorCode.TARGET_NOT_EXIST)
35
36        self.framework_dir = hdf_utils.get_module_dir(self.root)
37        if not os.path.exists(self.framework_dir):
38            raise HdfToolException(
39                'file: %s not exist' % self.framework_dir,
40                CommandErrorCode.TARGET_NOT_EXIST)
41
42        self.hcs_path = hdf_utils.get_hcs_file_path(
43            self.root, self.vendor, self.board)
44        if not os.path.exists(self.hcs_path):
45            raise HdfToolException('file: %s not exist' % self.hcs_path,
46                                   CommandErrorCode.TARGET_NOT_EXIST)
47        self.contents = hdf_utils.read_file_lines(self.makefile_path)
48        self.driver_configs_list = ['Kconfig', 'Makefile']
49        self.re_temp1_model = r'model/[a-z _ 0-9]+'
50        self.re_temp2_obj = r"^obj-"
51        self.re_temp3_enable = r"CONFIG_DRIVERS_[A-Z _ 0-9]+"
52        self.re_temp4_include = r"^include"
53        self.re_temp_prefix0 = r"^../[. /]+"
54        self.re_temp_prefix1 = r"\$\(HDF_DIR_PREFIX\)"
55        self.re_temp_prefix2 = r"\$\(KHDF_AUDIO_BASE_ROOT_DIR\)"
56        self.re_temp_current = r"^\.\/"
57        self.te_temp5 = r"^[a-z]"
58        if platform.system().lower() == 'windows':
59            self.platform = "windows"
60        elif platform.system().lower() == 'linux':
61            self.platform = "linux"
62
63    def scan_makefile(self):
64        model_enable_dict = {}
65        for index, lines in enumerate(self.contents):
66            temp_list = []
67            obj_result = re.search(self.re_temp2_obj, lines.strip())
68            if obj_result:
69                enable_name_result = re.search(
70                    self.re_temp3_enable, lines.strip())
71                model_path = lines.split("+=")[-1].strip()
72                model_name_result = re.search(
73                    self.re_temp1_model, model_path)
74                if model_name_result:
75                    model_name = enable_name_result.group()
76                    if self.platform == "windows":
77                        model_path =\
78                            os.path.join('\\'.join(self.makefile_path.
79                                        split('\\')[:-1]), model_path)
80                    elif self.platform == "linux":
81                        model_path = \
82                            os.path.join('/'.join(
83                            self.makefile_path.split('/')[:-1]), model_path)
84                    temp_list.append(model_path)
85                    if os.path.exists(model_path):
86                        if model_enable_dict.get(model_name, None):
87                            model_enable_dict[model_name] =\
88                                temp_list + model_enable_dict.get(model_name)
89                        else:
90                            model_enable_dict[model_name] = temp_list
91        return model_enable_dict
92
93    def get_config_path(self):
94        model_defconfig_list = []
95        config_path = hdf_utils.\
96            get_config_config_path(root=self.root, kernel=self.kernel)
97        for roots, dirs, files in os.walk(config_path):
98            for file_name in files:
99                if file_name.strip() == "hi3516dv300_small_defconfig":
100                    model_defconfig_list.append(os.path.join(roots, file_name))
101        return model_defconfig_list
102
103    def enable_scan(self):
104        enable_list = []
105        judge_enable_dict = self.scan_makefile()
106        defconfig_path = self.get_config_path()[0]
107        config_enable_lines = hdf_utils.read_file_lines(defconfig_path)
108        for enable_name, model_path in judge_enable_dict.items():
109            # 先去判断使能文件中是否使能(获取使能配置文件路径)
110            if ('%s=y\n' % enable_name) in config_enable_lines:
111                if "Makefile" in os.listdir(model_path[0]):
112                    if os.path.join(model_path[0],
113                                    'Makefile') not in enable_list:
114                        enable_list.append(
115                            os.path.join(model_path[0], 'Makefile'))
116        return enable_list
117
118    def _get_model_file_dict(self):
119        model_file_dict = {}
120        for model_name in self.scan_makefile():
121            model_file_dict[model_name] = []
122            path = os.path.join(self.framework_dir, model_name)
123            for root_path, dirs, files in os.walk(path):
124                for file_name in files:
125                    model_file_dict.get(model_name).append(
126                        os.path.join(root_path, file_name))
127        return model_file_dict
128
129    def _get_model_name(self, model_makefile_path):
130        parent_path = "/".join(model_makefile_path.split("/")[:-1])
131        config_file_path = []
132        for i in os.listdir(parent_path):
133            if i in self.driver_configs_list:
134                config_file_path.append(os.path.join(parent_path, i))
135        model_name = re.search(
136            self.re_temp1_model, model_makefile_path).group().split("/")[-1]
137        return model_name
138
139    def scan_enable_dict(self, lines, test_dict, names):
140        re_temp3 = "CONFIG_[A-Z _ 0-9]+"
141
142        list1_12 = []
143        for index, line in enumerate(lines):
144            if re.search("^ifeq", line):
145                list1_12.append(index)
146            elif re.search("^endif", line):
147                list1_12.append(index + 1)
148        obj_list = self.get_obj(lines)
149
150        if list1_12:
151            obj_list.extend(list1_12)
152            obj_list.sort()
153            obj_list = list(filter(
154                lambda x: x >= list1_12[1] or x <= list1_12[0], obj_list))
155            if obj_list == list1_12:
156                obj_list.clear()
157
158        obj_list = self.split_list(obj_list)
159        if list1_12 in obj_list:
160            obj_list.remove(list1_12)
161
162        if list1_12:
163            names = re.search(re_temp3, lines[list1_12[0]].strip()).group()
164            test2_dict = {}
165            test_dict[names] = self.scan_enable_dict\
166                (lines[list1_12[0] + 1:list1_12[1] - 1], test2_dict, names)
167            temp_lines = lines
168        else:
169            temp_lines = lines
170        temp_list00 = []
171        for i in obj_list:
172            if i[0] == i[1]:
173                continue
174            temp_result = re.search(re_temp3, temp_lines[i[0]].strip())
175            temp_list2 = []
176            if temp_result is not None:
177                key_name = temp_result.group()
178                temp_list00.append(key_name)
179            else:
180                key_name = names
181            for j in temp_lines[i[0]: i[1]]:
182                if j.strip().strip("\\").strip().split(".")[-1] == "o":
183                    temp_list2.append(j.strip().strip("\\").strip())
184            if key_name is None:
185                key_name = temp_list00[-1]
186
187            if test_dict.get(key_name, None):
188                if isinstance((test_dict[key_name]), list):
189                    test_dict[key_name] = test_dict[key_name] + temp_list2
190                else:
191                    test_dict[key_name] = test_dict[key_name][key_name] + temp_list2
192            else:
193                test_dict[key_name] = temp_list2
194
195        return test_dict
196
197    def get_obj(self, lines):
198        # 查找所有 obj 的开头和结尾
199        re_temp2 = "^obj-"
200        re_temp1 = "^ccflags"
201        status = 0
202        list1 = []
203        for index, line in enumerate(lines):
204            temp_result_obj = re.search(re_temp2, line.strip())
205            if temp_result_obj:
206                status = 1
207                list1.append(index)
208            temp_result_flag = re.search(re_temp1, line.strip())
209            if temp_result_flag and status == 1:
210                status = 2
211                list1.append(index)
212                break
213        #  如果status 为1时说明没有找到结尾,将整个长度的结尾
214        if status == 1:
215            list1.append(len(lines))
216        return list1
217
218    def split_list(self, src_list):
219        test_list1 = []
220        for i in range(len(src_list) - 1):
221            test_list1.append([src_list[i], src_list[i + 1]])
222        return test_list1
223
224    def get_model_scan(self):
225        enable_model_path_list = self.enable_scan()
226        result_dict00 = {}
227        for model_makefile_path in enable_model_path_list:
228            model_name = self._get_model_name(model_makefile_path)
229            model_makefile_lines = hdf_utils.\
230                read_file_lines(model_makefile_path)
231            enable_dict = {}
232            config_enable_lines = hdf_utils.\
233                read_file_lines(self.get_config_path()[0])
234            result = self.scan_enable_dict(
235                model_makefile_lines, enable_dict, names=None)
236            name_split_dict, enable_list = \
237                self.name_split_func(result, config_enable_lines)
238            enable_dict = self.path_replace(
239                lines=model_makefile_lines,
240                enable_list=enable_list,
241                makefile_path=model_makefile_path)
242            result = self._prefix_template_replace(
243                name_split_dict, enable_dict,
244                makefile_path=model_makefile_path)
245            if result_dict00.get(model_name, None):
246                result_dict00.get(model_name).update(result)
247            else:
248                result_dict00[model_name] = result
249        result_dict00["deconfig"] = self.get_config_path()[0]
250        result_dict00["makefile_path"] = self.makefile_path
251        result_dict00["hcs_path"] = self.hcs_path
252        return json.dumps(result_dict00, indent=4)
253
254    def scann_driver_configs(self, makefile_path):
255        driver_configs_list = ['Kconfig', 'Makefile']
256        parent_path = "/".join(makefile_path.split("/")[:-1])
257        config_file_path = []
258        for i in os.listdir(parent_path):
259            if i in driver_configs_list:
260                if self.platform == "windows":
261                    config_file_path.append(
262                        os.path.join(parent_path, i).replace("/", "\\"))
263                elif self.platform == "linux":
264                    config_file_path.append(os.path.join(parent_path, i))
265        return config_file_path
266
267    def _prefix_template_replace(self,
268                                 name_split_dict, enable_dict,
269                                 makefile_path):
270        config_file_path = self.scann_driver_configs(makefile_path)
271        return_dict = {}
272        temp_template = Template(json.dumps(name_split_dict))
273        dict000 = json.loads(temp_template.substitute(enable_dict))
274        for k0, v0 in dict000.items():
275            if isinstance(v0, dict):
276                return_dict[k0] = {}
277                for k01, v01 in v0.items():
278                    drivers_sources = []
279                    for i in v01:
280                        i = i.replace(".o", ".c")
281                        prefix4_field = re.search(self.re_temp_current, i)
282                        prefix5_field = re.search(self.te_temp5, i)
283
284                        if prefix4_field or prefix5_field:
285                            replace_field = "/".join(
286                                makefile_path.replace("\\", '/').
287                                    split("/")[:-1]
288                            ) + "/"
289                            if prefix4_field:
290                                i = i.replace(prefix4_field.group(),
291                                              replace_field).strip()
292                            elif prefix5_field:
293                                i = os.path.join(replace_field, i)
294                        if os.path.exists(i):
295                            drivers_sources.append(i)
296                    return_dict.get(k0)[k01] = {
297                        "driver_configs": config_file_path,
298                        "drivers_sources": drivers_sources,
299                    }
300            else:
301                return_dict[k0] = {}
302                drivers_sources = []
303                for i in v0:
304                    i = i.replace(".o", ".c")
305                    prefix5_field = re.search(self.te_temp5, i)
306                    prefix4_field = re.search(self.re_temp_current, i)
307                    if prefix4_field or prefix5_field:
308                        replace_field = "/".join(
309                            makefile_path.replace("\\", '/').
310                                split("/")[:-1]
311                        ) + "/"
312                        if prefix4_field:
313                            i = i.replace(prefix4_field.group(),
314                                          replace_field).strip()
315                        elif prefix5_field:
316                            i = os.path.join(replace_field, i)
317                    if i.find("=") != -1:
318                        i = i.split("=")[-1].strip()
319                    if os.path.exists(i):
320                        drivers_sources.append(i)
321                return_dict[k0] = {
322                    "driver_configs": config_file_path,
323                    "drivers_sources": drivers_sources,
324                }
325        return return_dict
326
327    def path_replace(self, lines, enable_list, makefile_path):
328        enable_dict = {}
329        include_list = []
330        for line in lines:
331            if re.search(self.re_temp4_include, line):
332                include_list.append(
333                    os.path.join(makefile_path.strip("Makefile"),
334                                 line.strip().split("/")[-1]))
335        include_lines = []
336        for include_file in include_list:
337            if os.path.exists(include_file):
338                with open(include_file, "r") as f:
339                    include_lines = f.readlines()
340        if include_lines:
341            lines.extend(include_lines)
342
343        for key_enable in list(set(enable_list)):
344            re_enable = '^%s' % key_enable
345            for line in lines:
346                result = re.search(re_enable, line)
347                if result:
348                    line = line.strip().split("=")[-1].strip()
349                    result_replace_field = re.search(
350                        self.re_temp_prefix0, line)
351                    prefix1_field = re.search(self.re_temp_prefix1, line)
352                    prefix2_field = re.search(self.re_temp_prefix2, line)
353                    prefix3_field = re.search(self.re_temp_current, line)
354                    if result_replace_field or \
355                            prefix1_field or \
356                            prefix2_field or \
357                            prefix3_field:
358                        if result_replace_field:
359                            enable_dict[key_enable] = \
360                                "/".join(
361                                    [self.root,
362                                        line.replace(result_replace_field.group(),
363                                                     "drivers/").strip()])
364                        if prefix1_field:
365                            enable_dict[key_enable] = \
366                                "/".join(
367                                    [self.root,
368                                     line.replace(prefix1_field.group(),
369                                                  "drivers").strip()]
370                                )
371                        if prefix2_field:
372                            enable_dict[key_enable] = \
373                                "/".join(
374                                    [self.root,
375                                    line.strip(prefix2_field.group() + "/").
376                                        strip()]
377                                )
378                        if prefix3_field:
379                            replace_field = \
380                                "/".join(
381                                    makefile_path.replace("\\", '/').
382                                        split("/")[:-1]
383                                )
384                            enable_dict[key_enable] = \
385                                line.replace(prefix3_field.group(),
386                                             replace_field).strip()
387                    else:
388                        enable_dict[key_enable] = line.split("=")[-1].strip()
389        return enable_dict
390
391    def name_split_func(self, result, config_enable_lines):
392        enable_list = []
393        name_split_dict = {}
394        for enable_key, enable_value in result.items():
395            key = "%s=y\n" % enable_key
396            if key in config_enable_lines:
397                if isinstance(enable_value, dict):
398                    # 先判断第一级的使能(没有使能的话直接下一个文件)
399                    if enable_key.find("HDF") != -1:
400                        child_enable_key = ''.join(
401                            ["HDF", enable_key.split("HDF")[-1]]
402                        ).lower()
403                    else:
404                        child_enable_key = enable_key.lower()
405                    name_split_dict[child_enable_key] = {}
406                    for k1, v1 in enable_value.items():
407                        if k1.find("HDF") != -1:
408                            grand_enable_key = ''.join(
409                                ["HDF", k1.split("HDF")[-1]]
410                            ).lower()
411                        else:
412                            grand_enable_key = k1.lower()
413                        # 先判断第二级的使能(没有使能的话直接下一个文件)
414                        key1 = "%s=y\n" % k1
415                        if key1 in config_enable_lines:
416                            name_split_dict.get(child_enable_key)[grand_enable_key] = []
417                            for name in v1:
418                                # 分为 几种情况
419                                if name.find("+=") != -1:
420                                    child_enable_list, str1 = \
421                                        self.get_name(
422                                            str1=name.split("+=")[-1].strip()
423                                        )
424                                else:
425                                    child_enable_list, str1 = \
426                                        self.get_name(str1=name.strip())
427                                enable_list.extend(child_enable_list)
428                                name_split_dict.get(child_enable_key).get(grand_enable_key).append(str1)
429                        else:
430                            continue
431                elif isinstance(enable_value, list):
432                    if enable_key.find("HDF") != -1:
433                        k2 = ''.join(
434                            ["HDF", enable_key.split("HDF")[-1]]
435                        ).lower()
436                    else:
437                        k2 = enable_key.lower()
438                    name_split_dict[k2] = []
439                    for name in enable_value:
440                        if name.find("+=") != -1:
441                            child_enable_list, str1 = \
442                                self.get_name(
443                                    str1=name.split("+=")[-1].strip())
444                        else:
445                            child_enable_list, str1 = \
446                                self.get_name(str1=name.strip())
447                        enable_list.extend(child_enable_list)
448                        name_split_dict.get(k2).append(str1)
449            else:
450                continue
451        return name_split_dict, enable_list
452
453    def get_name(self, str1):
454        temp_re = "[A-Z _ 0-9]+"
455        list1 = str1.split("/")
456        list2 = []
457        for i in list1:
458            if i.find('$(') != -1:
459                temp_name = re.search(temp_re, i)
460                if temp_name:
461                    list2.append(temp_name.group())
462        dict1 = {"$(": "${", ")": "}"}
463        for k, v in dict1.items():
464            str1 = str1.replace(k, v)
465        return list2, str1
466