]> git.mxchange.org Git - fba.git/blob - fba/helpers/version.py
aa0c54ff6ccf7ed4e23fd8347a8eeebf4aceb0e6
[fba.git] / fba / helpers / version.py
1 # Copyright (C) 2023 Free Software Foundation
2 #
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License as published
5 # by the Free Software Foundation, either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU Affero General Public License for more details.
12 #
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
15
16 import logging
17 import re
18
19 logging.basicConfig(level=logging.INFO)
20 logger = logging.getLogger(__name__)
21
22 # Pattern instance for version numbers
23 patterns = [
24     # semantic version number (with v|V) prefix)
25     re.compile(r"^(?P<version>v|V{0,1})(\.{0,1})(?P<major>0|[1-9]\d*)\.(?P<minor>0+|[1-9]\d*)(\.(?P<patch>0+|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)?$"),
26     # non-sematic, e.g. 1.2.3.4
27     re.compile(r"^(?P<version>v|V{0,1})(\.{0,1})(?P<major>0|[1-9]\d*)\.(?P<minor>0+|[1-9]\d*)(\.(?P<patch>0+|[1-9]\d*)(\.(?P<subpatch>0|[1-9]\d*))?)$"),
28     # non-sematic, e.g. 2023-05[-dev]
29     re.compile(r"^(?P<year>[1-9]{1}[0-9]{3})\.(?P<month>[0-9]{2})(-dev){0,1}$"),
30     # non-semantic, e.g. abcdef0
31     re.compile("^[a-f0-9]{7}$"),
32 ]
33
34 def remove(software: str) -> str:
35     logger.debug("software='%s' - CALLED!", software)
36     if "." not in software and " " not in software:
37         logger.warning("software='%s' does not contain a version number.", software)
38         return software
39
40     temp = software
41     if ";" in software:
42         temp = software.split(";")[0]
43     elif "," in software:
44         temp = software.split(",")[0]
45     elif " - " in software:
46         temp = software.split(" - ")[0]
47
48     logger.debug("software='%s'", software)
49     version = None
50     if " " in software:
51         version = temp.split(" ")[-1]
52     elif "/" in software:
53         version = temp.split("/")[-1]
54     elif "-" in software:
55         version = temp.split("-")[-1]
56     else:
57         logger.debug("Was not able to find common seperator, returning untouched software='%s' - EXIT!", software)
58         return software
59
60     match = None
61     logger.debug("Checking %d patterns ...", len(patterns))
62     for pattern in patterns:
63         # Run match()
64         match = pattern.match(version)
65
66         logger.debug("match[]='%s'", type(match))
67         if isinstance(match, re.Match):
68             logger.debug("version='%s' is matching pattern='%s'", version, pattern)
69             break
70
71     logger.debug("version[%s]='%s',match='%s'", type(version), version, match)
72     if not isinstance(match, re.Match):
73         logger.warning("version='%s' does not match regex, leaving software='%s' untouched.", version, software)
74         return software
75
76     logger.debug("Found valid version number: '%s', removing it ...", version)
77     end = len(temp) - len(version) - 1
78
79     logger.debug("end[%s]='%s'", type(end), end)
80     software = temp[0:end].strip()
81     if " version" in software:
82         logger.debug("software='%s' contains word ' version'", software)
83         software = strip_until(software, " version")
84
85     logger.debug("software='%s' - EXIT!", software)
86     return software
87
88 def strip_powered_by(software: str) -> str:
89     logger.debug("software='%s' - CALLED!", software)
90     if not isinstance(software, str):
91         raise ValueError(f"Parameter software[]='{type(software)}' is not 'str'")
92     elif software == "":
93         raise ValueError("Parameter 'software' is empty")
94     elif "powered by" not in software:
95         logger.warning("Cannot find 'powered by' in software='%s'!", software)
96         return software
97
98     start = software.find("powered by ")
99     logger.debug("start[%s]=%d", type(start), start)
100
101     software = software[start + 11:].strip()
102     logger.debug("software='%s'", software)
103
104     software = strip_until(software, " - ")
105
106     logger.debug("software='%s' - EXIT!", software)
107     return software
108
109 def strip_hosted_on(software: str) -> str:
110     logger.debug("software='%s' - CALLED!", software)
111     if not isinstance(software, str):
112         raise ValueError(f"Parameter software[]='{type(software)}' is not 'str'")
113     elif software == "":
114         raise ValueError("Parameter 'software' is empty")
115     elif "hosted on" not in software:
116         logger.warning("Cannot find 'hosted on' in sofware='%s'!", software)
117         return software
118
119     end = software.find("hosted on ")
120     logger.debug("end[%s]=%d", type(end), end)
121
122     software = software[0:end].strip()
123     logger.debug("software[%s]='%s'", type(software), software)
124
125     software = strip_until(software, " - ")
126
127     logger.debug("software='%s' - EXIT!", software)
128     return software
129
130 def strip_until(software: str, until: str) -> str:
131     logger.debug("software='%s',until='%s' - CALLED!", software, until)
132     if not isinstance(software, str):
133         raise ValueError(f"Parameter software[]='{type(software)}' is not 'str'")
134     elif software == "":
135         raise ValueError("Parameter 'software' is empty")
136     elif not isinstance(until, str):
137         raise ValueError(f"Parameter until[]='{type(until)}' is not 'str'")
138     elif until == "":
139         raise ValueError("Parameter 'until' is empty")
140     elif not until in software:
141         logger.warning("Cannot find until='%s' in software='%s'!", until, software)
142         return software
143
144     # Next, strip until part
145     end = software.find(until)
146
147     logger.debug("end[%s]=%d", type(end), end)
148     if end > 0:
149         software = software[0:end].strip()
150
151     logger.debug("software='%s' - EXIT!", software)
152     return software