FreeCAD

Форк
0
/
addonmanager_devmode_metadata_checker.py 
184 строки · 8.0 Кб
1
# SPDX-License-Identifier: LGPL-2.1-or-later
2
# ***************************************************************************
3
# *                                                                         *
4
# *   Copyright (c) 2022 FreeCAD Project Association                        *
5
# *                                                                         *
6
# *   This file is part of FreeCAD.                                         *
7
# *                                                                         *
8
# *   FreeCAD is free software: you can redistribute it and/or modify it    *
9
# *   under the terms of the GNU Lesser General Public License as           *
10
# *   published by the Free Software Foundation, either version 2.1 of the  *
11
# *   License, or (at your option) any later version.                       *
12
# *                                                                         *
13
# *   FreeCAD is distributed in the hope that it will be useful, but        *
14
# *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
15
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
16
# *   Lesser General Public License for more details.                       *
17
# *                                                                         *
18
# *   You should have received a copy of the GNU Lesser General Public      *
19
# *   License along with FreeCAD. If not, see                               *
20
# *   <https://www.gnu.org/licenses/>.                                      *
21
# *                                                                         *
22
# ***************************************************************************
23

24
""" Metadata validation functions """
25

26
from typing import List
27

28
import FreeCAD
29

30
from Addon import Addon
31
from addonmanager_metadata import Metadata
32
import NetworkManager
33

34

35
class MetadataValidators:
36
    """A collection of tools for validating various pieces of metadata. Prints
37
    validation information to the console."""
38

39
    def validate_all(self, repos):
40
        """Developer tool: check all repos for validity and print report"""
41

42
        FreeCAD.Console.PrintMessage("\n\nADDON MANAGER DEVELOPER MODE CHECKS\n")
43
        FreeCAD.Console.PrintMessage("-----------------------------------\n")
44

45
        counter = 0
46
        for addon in repos:
47
            counter += 1
48
            if addon.metadata is not None:
49
                self.validate_package_xml(addon)
50
            elif addon.repo_type == Addon.Kind.MACRO:
51
                if addon.macro.parsed:
52
                    if len(addon.macro.icon) == 0 and len(addon.macro.xpm) == 0:
53
                        FreeCAD.Console.PrintMessage(
54
                            f"Macro '{addon.name}' does not have an icon\n"
55
                        )
56
            else:
57
                FreeCAD.Console.PrintMessage(
58
                    f"Addon '{addon.name}' does not have a package.xml file\n"
59
                )
60

61
        FreeCAD.Console.PrintMessage("-----------------------------------\n\n")
62

63
    def validate_package_xml(self, addon: Addon):
64
        """Check the package.xml file for the specified Addon"""
65
        if addon.metadata is None:
66
            return
67

68
        # The package.xml standard has some required elements that the basic XML
69
        # reader is not actually checking for. In developer mode, actually make sure
70
        # that all the rules are being followed for each element.
71

72
        errors = []
73

74
        errors.extend(self.validate_top_level(addon))
75
        errors.extend(self.validate_content(addon))
76

77
        if len(errors) > 0:
78
            FreeCAD.Console.PrintError(f"Errors found in package.xml file for '{addon.name}'\n")
79
            for error in errors:
80
                FreeCAD.Console.PrintError(f"   * {error}\n")
81

82
    def validate_content(self, addon: Addon) -> List[str]:
83
        """Validate the Content items for this Addon"""
84
        errors = []
85
        contents = addon.metadata.content
86

87
        missing_icon = True
88
        if addon.metadata.icon and len(addon.metadata.icon) > 0:
89
            missing_icon = False
90
        else:
91
            if "workbench" in contents:
92
                wb = contents["workbench"][0]
93
                if wb.icon:
94
                    missing_icon = False
95
        if missing_icon:
96
            errors.append("No <icon> element found, or <icon> element is invalid")
97

98
        if "workbench" in contents:
99
            for wb in contents["workbench"]:
100
                errors.extend(self.validate_workbench_metadata(wb))
101

102
        if "preferencepack" in contents:
103
            for wb in contents["preferencepack"]:
104
                errors.extend(self.validate_preference_pack_metadata(wb))
105

106
        return errors
107

108
    def validate_top_level(self, addon: Addon) -> List[str]:
109
        """Check for the presence of the required top-level elements"""
110
        errors = []
111
        if not addon.metadata.name or len(addon.metadata.name) == 0:
112
            errors.append("No top-level <name> element found, or <name> element is empty")
113
        if not addon.metadata.version:
114
            errors.append("No top-level <version> element found, or <version> element is invalid")
115
        if not addon.metadata.description or len(addon.metadata.description) == 0:
116
            errors.append(
117
                "No top-level <description> element found, or <description> element " "is invalid"
118
            )
119

120
        maintainers = addon.metadata.maintainer
121
        if len(maintainers) == 0:
122
            errors.append("No top-level <maintainers> found, at least one is required")
123
        for maintainer in maintainers:
124
            if len(maintainer.email) == 0:
125
                errors.append(f"No email address specified for maintainer '{maintainer.name}'")
126

127
        licenses = addon.metadata.license
128
        if len(licenses) == 0:
129
            errors.append("No top-level <license> found, at least one is required")
130

131
        urls = addon.metadata.url
132
        errors.extend(self.validate_urls(urls))
133
        return errors
134

135
    @staticmethod
136
    def validate_urls(urls) -> List[str]:
137
        """Check the URLs provided by the addon"""
138
        errors = []
139
        if len(urls) == 0:
140
            errors.append("No <url> elements found, at least a repo url must be provided")
141
        else:
142
            found_repo = False
143
            found_readme = False
144
            for url in urls:
145
                if url.type == "repository":
146
                    found_repo = True
147
                    if len(url.branch) == 0:
148
                        errors.append("<repository> element is missing the 'branch' attribute")
149
                elif url.type == "readme":
150
                    found_readme = True
151
                    location = url.location
152
                    p = NetworkManager.AM_NETWORK_MANAGER.blocking_get(location)
153
                    if not p:
154
                        errors.append(f"Could not access specified readme at {location}")
155
                    else:
156
                        p = p.data().decode("utf8")
157
                        if "<html" in p or "<!DOCTYPE html>" in p:
158
                            pass
159
                        else:
160
                            errors.append(
161
                                f"Readme data found at {location}"
162
                                " does not appear to be rendered HTML"
163
                            )
164
            if not found_repo:
165
                errors.append("No repo url specified")
166
            if not found_readme:
167
                errors.append("No readme url specified (not required, but highly recommended)")
168
        return errors
169

170
    @staticmethod
171
    def validate_workbench_metadata(workbench: Metadata) -> List[str]:
172
        """Validate the required element(s) for a workbench"""
173
        errors = []
174
        if not workbench.classname or len(workbench.classname) == 0:
175
            errors.append("No <classname> specified for workbench")
176
        return errors
177

178
    @staticmethod
179
    def validate_preference_pack_metadata(pack: Metadata) -> List[str]:
180
        """Validate the required element(s) for a preference pack"""
181
        errors = []
182
        if not pack.name or len(pack.name) == 0:
183
            errors.append("No <name> specified for preference pack")
184
        return errors
185

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.