ScriptCollection 3.5.118__py3-none-any.whl → 3.5.120__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ScriptCollection/CertificateUpdater.py +5 -2
- ScriptCollection/GeneralUtilities.py +56 -11
- ScriptCollection/ImageUpdater.py +477 -0
- ScriptCollection/SCLog.py +31 -18
- ScriptCollection/ScriptCollectionCore.py +19 -63
- ScriptCollection/TasksForCommonProjectStructure.py +31 -29
- {scriptcollection-3.5.118.dist-info → scriptcollection-3.5.120.dist-info}/METADATA +1 -1
- scriptcollection-3.5.120.dist-info/RECORD +17 -0
- {scriptcollection-3.5.118.dist-info → scriptcollection-3.5.120.dist-info}/WHEEL +1 -1
- scriptcollection-3.5.118.dist-info/RECORD +0 -16
- {scriptcollection-3.5.118.dist-info → scriptcollection-3.5.120.dist-info}/entry_points.txt +0 -0
- {scriptcollection-3.5.118.dist-info → scriptcollection-3.5.120.dist-info}/top_level.txt +0 -0
@@ -24,7 +24,7 @@ class CertificateUpdater:
|
|
24
24
|
|
25
25
|
def __init__(self, domains: list[str], email: str, current_file: str, arguments: list[str]):
|
26
26
|
self.__sc = ScriptCollectionCore()
|
27
|
-
self.maximal_age_of_certificates_in_days =
|
27
|
+
self.maximal_age_of_certificates_in_days = 15
|
28
28
|
self.__domains = domains
|
29
29
|
self.__email = email
|
30
30
|
self.__current_folder = current_file
|
@@ -126,7 +126,7 @@ class CertificateUpdater:
|
|
126
126
|
def __get_last_certificate_update_date(self) -> datetime:
|
127
127
|
if os.path.exists(self.__last_update_timestamp_file):
|
128
128
|
filecontent = GeneralUtilities.read_text_from_file(self.__last_update_timestamp_file)
|
129
|
-
return GeneralUtilities.string_to_datetime(filecontent.replace("\r",
|
129
|
+
return GeneralUtilities.string_to_datetime(filecontent.replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string))
|
130
130
|
else:
|
131
131
|
return datetime(year=1970, month=1, day=1)
|
132
132
|
|
@@ -142,5 +142,8 @@ class CertificateUpdater:
|
|
142
142
|
args = parser.parse_args(self.__arguments)
|
143
143
|
now = datetime.now()
|
144
144
|
if (self.__get_last_certificate_update_date()+timedelta(days=self.maximal_age_of_certificates_in_days)) < now or args.force:
|
145
|
+
GeneralUtilities.write_message_to_stdout(f"Update certificates...")
|
145
146
|
self.__update_certificates()
|
146
147
|
self.__set_last_certificate_update_date(now)
|
148
|
+
else:
|
149
|
+
GeneralUtilities.write_message_to_stdout(f"Certificates are already up to date.")
|
@@ -38,6 +38,8 @@ class GeneralUtilities:
|
|
38
38
|
__datetime_format: str = "%Y-%m-%dT%H:%M:%S"
|
39
39
|
__date_format: str = "%Y-%m-%d"
|
40
40
|
|
41
|
+
empty_string: str = ""
|
42
|
+
|
41
43
|
@staticmethod
|
42
44
|
def get_modest_dark_url() -> str:
|
43
45
|
return "https://aniondev.github.io/CDN/ScriptCollectionDesigns/ModestDark/Style.css"
|
@@ -46,6 +48,10 @@ class GeneralUtilities:
|
|
46
48
|
def is_generic(t: typing.Type):
|
47
49
|
return hasattr(t, "__origin__")
|
48
50
|
|
51
|
+
@staticmethod
|
52
|
+
def is_debugger_attached():
|
53
|
+
return sys.gettrace() is not None
|
54
|
+
|
49
55
|
@staticmethod
|
50
56
|
def check_arguments(function):
|
51
57
|
def __check_function(*args, **named_args):
|
@@ -234,6 +240,32 @@ class GeneralUtilities:
|
|
234
240
|
text = GeneralUtilities.replace_underscores_in_text(text, replacements)
|
235
241
|
GeneralUtilities.write_text_to_file(file, text, encoding)
|
236
242
|
|
243
|
+
@staticmethod
|
244
|
+
def print_text(text: str, print_to_stdout: bool = True):
|
245
|
+
GeneralUtilities.__print_text_to_console(text, print_to_stdout)
|
246
|
+
|
247
|
+
@staticmethod
|
248
|
+
def print_text_in_green(text: str, print_to_stdout: bool = True):
|
249
|
+
GeneralUtilities.__print_text_to_console(f"\033[32m{text}\033[0m", print_to_stdout)
|
250
|
+
|
251
|
+
@staticmethod
|
252
|
+
def print_text_in_yellow(text: str, print_to_stdout: bool = True):
|
253
|
+
GeneralUtilities.__print_text_to_console(f"\033[33m{text}\033[0m", print_to_stdout)
|
254
|
+
|
255
|
+
@staticmethod
|
256
|
+
def print_text_in_red(text: str, print_to_stdout: bool = True):
|
257
|
+
GeneralUtilities.__print_text_to_console(f"\033[31m{text}\033[0m", print_to_stdout)
|
258
|
+
|
259
|
+
@staticmethod
|
260
|
+
def print_text_in_cyan(text: str, print_to_stdout: bool = True):
|
261
|
+
GeneralUtilities.__print_text_to_console(f"\033[36m{text}\033[0m", print_to_stdout)
|
262
|
+
|
263
|
+
@staticmethod
|
264
|
+
def __print_text_to_console(text: str, print_to_stdout: bool = True):
|
265
|
+
output = sys.stdout if print_to_stdout else sys.stderr
|
266
|
+
output.write(text)
|
267
|
+
output.flush()
|
268
|
+
|
237
269
|
@staticmethod
|
238
270
|
@check_arguments
|
239
271
|
def reconfigure_standrd_input_and_outputs():
|
@@ -243,16 +275,29 @@ class GeneralUtilities:
|
|
243
275
|
|
244
276
|
@staticmethod
|
245
277
|
@check_arguments
|
246
|
-
def
|
247
|
-
|
248
|
-
|
278
|
+
def write_message_to_stdout_advanced(message: str, add_empty_lines: bool = True, adapt_lines: bool = True, append_linebreak: bool = True):
|
279
|
+
new_line_character: str = "\n" if append_linebreak else ""
|
280
|
+
for line in GeneralUtilities.string_to_lines(message, add_empty_lines, adapt_lines):
|
281
|
+
sys.stdout.write(GeneralUtilities.str_none_safe(line)+new_line_character)
|
249
282
|
sys.stdout.flush()
|
250
283
|
|
284
|
+
@staticmethod
|
285
|
+
@check_arguments
|
286
|
+
def write_message_to_stdout(message: str):
|
287
|
+
GeneralUtilities.write_message_to_stdout_advanced(message, True, True, True)
|
288
|
+
|
289
|
+
@staticmethod
|
290
|
+
@check_arguments
|
291
|
+
def write_message_to_stderr_advanced(message: str, add_empty_lines: bool = True, adapt_lines: bool = True, append_linebreak: bool = True):
|
292
|
+
new_line_character: str = "\n" if append_linebreak else ""
|
293
|
+
for line in GeneralUtilities.string_to_lines(message, add_empty_lines, adapt_lines):
|
294
|
+
sys.stderr.write(GeneralUtilities.str_none_safe(line)+new_line_character)
|
295
|
+
sys.stderr.flush()
|
296
|
+
|
251
297
|
@staticmethod
|
252
298
|
@check_arguments
|
253
299
|
def write_message_to_stderr(message: str):
|
254
|
-
|
255
|
-
sys.stderr.flush()
|
300
|
+
GeneralUtilities.write_message_to_stderr_advanced(message, True, True, True)
|
256
301
|
|
257
302
|
@staticmethod
|
258
303
|
@check_arguments
|
@@ -260,7 +305,7 @@ class GeneralUtilities:
|
|
260
305
|
if GeneralUtilities.string_has_content(os_error.filename2):
|
261
306
|
secondpath = f" {os_error.filename2}"
|
262
307
|
else:
|
263
|
-
secondpath =
|
308
|
+
secondpath = GeneralUtilities.empty_string
|
264
309
|
return f"Related path(s): {os_error.filename}{secondpath}"
|
265
310
|
|
266
311
|
@staticmethod
|
@@ -315,7 +360,7 @@ class GeneralUtilities:
|
|
315
360
|
return True
|
316
361
|
type_of_argument = type(argument)
|
317
362
|
if type_of_argument == str:
|
318
|
-
return argument ==
|
363
|
+
return argument == GeneralUtilities.empty_string
|
319
364
|
else:
|
320
365
|
raise ValueError(f"expected string-variable in argument of string_is_none_or_empty but the type was '{str(type_of_argument)}'")
|
321
366
|
|
@@ -325,7 +370,7 @@ class GeneralUtilities:
|
|
325
370
|
if GeneralUtilities.string_is_none_or_empty(string):
|
326
371
|
return True
|
327
372
|
else:
|
328
|
-
return string.strip() ==
|
373
|
+
return string.strip() == GeneralUtilities.empty_string
|
329
374
|
|
330
375
|
@staticmethod
|
331
376
|
@check_arguments
|
@@ -378,7 +423,7 @@ class GeneralUtilities:
|
|
378
423
|
if GeneralUtilities.file_ends_with_content(file):
|
379
424
|
return "\n"
|
380
425
|
else:
|
381
|
-
return
|
426
|
+
return GeneralUtilities.empty_string
|
382
427
|
|
383
428
|
@staticmethod
|
384
429
|
@check_arguments
|
@@ -861,7 +906,7 @@ class GeneralUtilities:
|
|
861
906
|
result = list()
|
862
907
|
if list_as_string is not None:
|
863
908
|
list_as_string = list_as_string.strip()
|
864
|
-
if list_as_string ==
|
909
|
+
if list_as_string == GeneralUtilities.empty_string:
|
865
910
|
pass
|
866
911
|
elif separator in list_as_string:
|
867
912
|
for item in list_as_string.split(separator):
|
@@ -922,7 +967,7 @@ class GeneralUtilities:
|
|
922
967
|
if positive:
|
923
968
|
return "✅"
|
924
969
|
else:
|
925
|
-
return
|
970
|
+
return GeneralUtilities.empty_string
|
926
971
|
|
927
972
|
@staticmethod
|
928
973
|
@check_arguments
|
@@ -0,0 +1,477 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from enum import Enum
|
3
|
+
import json
|
4
|
+
import re
|
5
|
+
from urllib.parse import quote
|
6
|
+
import yaml
|
7
|
+
import requests
|
8
|
+
from packaging import version as ve
|
9
|
+
from packaging.version import Version
|
10
|
+
from .GeneralUtilities import GeneralUtilities
|
11
|
+
|
12
|
+
|
13
|
+
class VersionEcholon(Enum):
|
14
|
+
Patch = 0
|
15
|
+
LatestPatchOrLatestMinor = 1
|
16
|
+
LatestPatchOrLatestMinorOrNextMajor = 2
|
17
|
+
Newest = 3
|
18
|
+
|
19
|
+
|
20
|
+
class ImageUpdaterHelper:
|
21
|
+
|
22
|
+
@staticmethod
|
23
|
+
@GeneralUtilities.check_arguments
|
24
|
+
def _internal_filter_for_major_and_minor_versions(versions: list[Version], major: int, minor: int) -> Version:
|
25
|
+
return [v for v in versions if v.major == major and v.minor == minor]
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
@GeneralUtilities.check_arguments
|
29
|
+
def _internal_filter_for_major_versions(versions: list[Version], major: int) -> Version:
|
30
|
+
return [v for v in versions if v.major == major]
|
31
|
+
|
32
|
+
@staticmethod
|
33
|
+
@GeneralUtilities.check_arguments
|
34
|
+
def _internal_get_latest_patch_version(newer_versions: list[Version], current_version: Version) -> Version:
|
35
|
+
candidates = ImageUpdaterHelper._internal_filter_for_major_and_minor_versions(newer_versions, current_version.major, current_version.minor)
|
36
|
+
if len(candidates) == 0:
|
37
|
+
return current_version
|
38
|
+
result = ImageUpdaterHelper.get_latest_version(candidates)
|
39
|
+
return result
|
40
|
+
|
41
|
+
@staticmethod
|
42
|
+
@GeneralUtilities.check_arguments
|
43
|
+
def _internal_get_latest_patch_or_latest_minor_version(newer_versions: list[Version], current_version: Version) -> Version:
|
44
|
+
candidates = ImageUpdaterHelper._internal_filter_for_major_versions(newer_versions, current_version.major)
|
45
|
+
if len(candidates) == 0:
|
46
|
+
return current_version
|
47
|
+
result = ImageUpdaterHelper.get_latest_version(candidates)
|
48
|
+
return result
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
@GeneralUtilities.check_arguments
|
52
|
+
def _internal_get_latest_patch_or_latest_minor_or_next_major_version(newer_versions: list[Version], current_version: Version) -> Version:
|
53
|
+
candidates = ImageUpdaterHelper._internal_filter_for_major_versions(newer_versions, current_version.major+1)
|
54
|
+
if 0 < len(candidates):
|
55
|
+
result = ImageUpdaterHelper.get_latest_version(candidates)
|
56
|
+
return result
|
57
|
+
else:
|
58
|
+
candidates = ImageUpdaterHelper._internal_filter_for_major_versions(newer_versions, current_version.major)
|
59
|
+
if len(candidates) == 0:
|
60
|
+
return current_version
|
61
|
+
result = ImageUpdaterHelper.get_latest_version(candidates)
|
62
|
+
return result
|
63
|
+
|
64
|
+
@staticmethod
|
65
|
+
@GeneralUtilities.check_arguments
|
66
|
+
def filter_considering_echolog(newer_versions: list[Version], current_version: Version, version_echolon: VersionEcholon) -> Version:
|
67
|
+
if version_echolon == VersionEcholon.Patch:
|
68
|
+
return ImageUpdaterHelper._internal_get_latest_patch_version(newer_versions, current_version)
|
69
|
+
elif version_echolon == VersionEcholon.LatestPatchOrLatestMinor:
|
70
|
+
return ImageUpdaterHelper._internal_get_latest_patch_or_latest_minor_version(newer_versions, current_version)
|
71
|
+
elif version_echolon == VersionEcholon.LatestPatchOrLatestMinorOrNextMajor:
|
72
|
+
return ImageUpdaterHelper._internal_get_latest_patch_or_latest_minor_or_next_major_version(newer_versions, current_version)
|
73
|
+
elif version_echolon == VersionEcholon.Newest:
|
74
|
+
return ImageUpdaterHelper.get_latest_version(newer_versions)
|
75
|
+
else:
|
76
|
+
raise ValueError(f"Unknown version-echolon")
|
77
|
+
|
78
|
+
@staticmethod
|
79
|
+
@GeneralUtilities.check_arguments
|
80
|
+
def get_latest_version(versions: list[Version]) -> Version:
|
81
|
+
result = max(versions)
|
82
|
+
return result
|
83
|
+
|
84
|
+
@staticmethod
|
85
|
+
@GeneralUtilities.check_arguments
|
86
|
+
def get_latest_version_from_versiontrings(version_strings: list[str]) -> str:
|
87
|
+
parsed = [ve.parse(v) for v in version_strings]
|
88
|
+
result = max(parsed)
|
89
|
+
return str(result)
|
90
|
+
|
91
|
+
@staticmethod
|
92
|
+
@GeneralUtilities.check_arguments
|
93
|
+
def filter_for_newer_versions(comparison_version: Version, versions_to_filter: list[Version]) -> list[Version]:
|
94
|
+
result = [v for v in versions_to_filter if comparison_version < v]
|
95
|
+
return result
|
96
|
+
|
97
|
+
@staticmethod
|
98
|
+
@GeneralUtilities.check_arguments
|
99
|
+
def get_versions_in_docker_hub(image: str, search_string: str, filter_regex: str, maximal_amount_of_items_to_load: int = 250) -> list[Version]:
|
100
|
+
if "/" not in image:
|
101
|
+
image = f"library/{image}"
|
102
|
+
response = requests.get(f"https://hub.docker.com/v2/repositories/{quote(image)}/tags?name={quote(search_string)}&ordering=last_updated&page=1&page_size={str(maximal_amount_of_items_to_load)}", timeout=20, headers={'Cache-Control': 'no-cache'})
|
103
|
+
if response.status_code != 200:
|
104
|
+
raise ValueError(f"Failed to fetch data from Docker Hub: {response.status_code}")
|
105
|
+
response_text = response.text
|
106
|
+
data = json.loads(response_text)
|
107
|
+
tags: list[str] = [tag["name"] for tag in data["results"] if re.match(filter_regex, tag["name"])]
|
108
|
+
versions = [tag.split("-")[0] for tag in tags]
|
109
|
+
result = [ve.parse(v) for v in versions]
|
110
|
+
return result
|
111
|
+
|
112
|
+
|
113
|
+
class ConcreteImageUpdater:
|
114
|
+
|
115
|
+
@abstractmethod
|
116
|
+
@GeneralUtilities.check_arguments
|
117
|
+
def version_to_tag(self, version: Version) -> str:
|
118
|
+
raise NotImplementedError
|
119
|
+
|
120
|
+
@abstractmethod
|
121
|
+
@GeneralUtilities.check_arguments
|
122
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
123
|
+
raise NotImplementedError
|
124
|
+
|
125
|
+
@abstractmethod
|
126
|
+
@GeneralUtilities.check_arguments
|
127
|
+
def get_supported_images(self) -> list[str]:
|
128
|
+
raise NotImplementedError
|
129
|
+
|
130
|
+
@abstractmethod
|
131
|
+
@GeneralUtilities.check_arguments
|
132
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
133
|
+
raise NotImplementedError
|
134
|
+
|
135
|
+
|
136
|
+
class ConcreteImageUpdaterForNginx(ConcreteImageUpdater):
|
137
|
+
|
138
|
+
@GeneralUtilities.check_arguments
|
139
|
+
def version_to_tag(self, version: Version) -> str:
|
140
|
+
raise NotImplementedError
|
141
|
+
|
142
|
+
@GeneralUtilities.check_arguments
|
143
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
144
|
+
raise NotImplementedError
|
145
|
+
|
146
|
+
@GeneralUtilities.check_arguments
|
147
|
+
def get_supported_images(self) -> list[str]:
|
148
|
+
return ["nginx"]
|
149
|
+
|
150
|
+
@GeneralUtilities.check_arguments
|
151
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
152
|
+
raise NotImplementedError
|
153
|
+
|
154
|
+
|
155
|
+
class ConcreteImageUpdaterForGitLab(ConcreteImageUpdater):
|
156
|
+
|
157
|
+
@GeneralUtilities.check_arguments
|
158
|
+
def version_to_tag(self, version: Version) -> str:
|
159
|
+
raise NotImplementedError
|
160
|
+
|
161
|
+
@GeneralUtilities.check_arguments
|
162
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
163
|
+
raise NotImplementedError
|
164
|
+
|
165
|
+
@GeneralUtilities.check_arguments
|
166
|
+
def get_supported_images(self) -> list[str]:
|
167
|
+
return ["gitlab/gitlab-ce", "gitlab/gitlab-ee"]
|
168
|
+
|
169
|
+
@GeneralUtilities.check_arguments
|
170
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
171
|
+
raise NotImplementedError
|
172
|
+
|
173
|
+
|
174
|
+
class ConcreteImageUpdaterForRegistry(ConcreteImageUpdater):
|
175
|
+
|
176
|
+
@GeneralUtilities.check_arguments
|
177
|
+
def version_to_tag(self, version: Version) -> str:
|
178
|
+
raise NotImplementedError
|
179
|
+
|
180
|
+
@GeneralUtilities.check_arguments
|
181
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
182
|
+
raise NotImplementedError
|
183
|
+
|
184
|
+
@abstractmethod
|
185
|
+
@GeneralUtilities.check_arguments
|
186
|
+
def get_supported_images(self) -> list[str]:
|
187
|
+
return [] # TODO
|
188
|
+
|
189
|
+
@GeneralUtilities.check_arguments
|
190
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
191
|
+
raise NotImplementedError
|
192
|
+
|
193
|
+
|
194
|
+
class ConcreteImageUpdaterForPrometheus(ConcreteImageUpdater):
|
195
|
+
|
196
|
+
@GeneralUtilities.check_arguments
|
197
|
+
def version_to_tag(self, version: Version) -> str:
|
198
|
+
raise NotImplementedError
|
199
|
+
|
200
|
+
@GeneralUtilities.check_arguments
|
201
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
202
|
+
raise NotImplementedError
|
203
|
+
|
204
|
+
@GeneralUtilities.check_arguments
|
205
|
+
def get_supported_images(self) -> list[str]:
|
206
|
+
return [] # TODO
|
207
|
+
|
208
|
+
@GeneralUtilities.check_arguments
|
209
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
210
|
+
raise NotImplementedError
|
211
|
+
|
212
|
+
|
213
|
+
class ConcreteImageUpdaterForPrometheusBlackboxExporter(ConcreteImageUpdater):
|
214
|
+
|
215
|
+
@GeneralUtilities.check_arguments
|
216
|
+
def version_to_tag(self, version: Version) -> str:
|
217
|
+
raise NotImplementedError
|
218
|
+
|
219
|
+
@GeneralUtilities.check_arguments
|
220
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
221
|
+
raise NotImplementedError
|
222
|
+
|
223
|
+
@GeneralUtilities.check_arguments
|
224
|
+
def get_supported_images(self) -> list[str]:
|
225
|
+
return [] # TODO
|
226
|
+
|
227
|
+
@GeneralUtilities.check_arguments
|
228
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
229
|
+
raise NotImplementedError
|
230
|
+
|
231
|
+
|
232
|
+
class ConcreteImageUpdaterForPrometheusNginxExporter(ConcreteImageUpdater):
|
233
|
+
|
234
|
+
@GeneralUtilities.check_arguments
|
235
|
+
def version_to_tag(self, version: Version) -> str:
|
236
|
+
raise NotImplementedError
|
237
|
+
|
238
|
+
@GeneralUtilities.check_arguments
|
239
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
240
|
+
raise NotImplementedError
|
241
|
+
|
242
|
+
@GeneralUtilities.check_arguments
|
243
|
+
def get_supported_images(self) -> list[str]:
|
244
|
+
return [] # TODO
|
245
|
+
|
246
|
+
@GeneralUtilities.check_arguments
|
247
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
248
|
+
raise NotImplementedError
|
249
|
+
|
250
|
+
|
251
|
+
class ConcreteImageUpdaterForPrometheusNodeExporter(ConcreteImageUpdater):
|
252
|
+
|
253
|
+
@GeneralUtilities.check_arguments
|
254
|
+
def version_to_tag(self, version: Version) -> str:
|
255
|
+
raise NotImplementedError
|
256
|
+
|
257
|
+
@GeneralUtilities.check_arguments
|
258
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
259
|
+
raise NotImplementedError
|
260
|
+
|
261
|
+
@GeneralUtilities.check_arguments
|
262
|
+
def get_supported_images(self) -> list[str]:
|
263
|
+
return [] # TODO
|
264
|
+
|
265
|
+
@GeneralUtilities.check_arguments
|
266
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
267
|
+
raise NotImplementedError
|
268
|
+
|
269
|
+
|
270
|
+
class ConcreteImageUpdaterForKeycloak(ConcreteImageUpdater):
|
271
|
+
|
272
|
+
@GeneralUtilities.check_arguments
|
273
|
+
def version_to_tag(self, version: Version) -> str:
|
274
|
+
raise NotImplementedError
|
275
|
+
|
276
|
+
@GeneralUtilities.check_arguments
|
277
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
278
|
+
raise NotImplementedError
|
279
|
+
|
280
|
+
@GeneralUtilities.check_arguments
|
281
|
+
def get_supported_images(self) -> list[str]:
|
282
|
+
return [] # TODO
|
283
|
+
|
284
|
+
@GeneralUtilities.check_arguments
|
285
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
286
|
+
raise NotImplementedError
|
287
|
+
|
288
|
+
|
289
|
+
class ConcreteImageUpdaterForMariaDB(ConcreteImageUpdater):
|
290
|
+
|
291
|
+
@GeneralUtilities.check_arguments
|
292
|
+
def version_to_tag(self, version: Version) -> str:
|
293
|
+
return f"{version.major}.{version.minor}.{version.micro}"
|
294
|
+
|
295
|
+
@GeneralUtilities.check_arguments
|
296
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
297
|
+
versions = ImageUpdaterHelper.get_versions_in_docker_hub(image, ".", "^\\d+\\.\\d+\\.\\d+$", 999)
|
298
|
+
newer_versions = ImageUpdaterHelper.filter_for_newer_versions(current_version, versions)
|
299
|
+
result = ImageUpdaterHelper.filter_considering_echolog(newer_versions, current_version, version_echolon)
|
300
|
+
return result
|
301
|
+
|
302
|
+
@GeneralUtilities.check_arguments
|
303
|
+
def get_supported_images(self) -> list[str]:
|
304
|
+
return ["mariadb"]
|
305
|
+
|
306
|
+
@GeneralUtilities.check_arguments
|
307
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
308
|
+
return ve.parse(tag)
|
309
|
+
|
310
|
+
|
311
|
+
class ConcreteImageUpdaterForPostgreSQL(ConcreteImageUpdater):
|
312
|
+
|
313
|
+
@GeneralUtilities.check_arguments
|
314
|
+
def version_to_tag(self, version: Version) -> str:
|
315
|
+
raise NotImplementedError
|
316
|
+
|
317
|
+
@GeneralUtilities.check_arguments
|
318
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
319
|
+
raise NotImplementedError
|
320
|
+
|
321
|
+
@GeneralUtilities.check_arguments
|
322
|
+
def get_supported_images(self) -> list[str]:
|
323
|
+
return [] # TODO
|
324
|
+
|
325
|
+
@GeneralUtilities.check_arguments
|
326
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
327
|
+
raise NotImplementedError
|
328
|
+
|
329
|
+
|
330
|
+
class ConcreteImageUpdaterForAdminer(ConcreteImageUpdater):
|
331
|
+
|
332
|
+
@GeneralUtilities.check_arguments
|
333
|
+
def version_to_tag(self, version: Version) -> str:
|
334
|
+
return f"{version.major}.{version.minor}.{version.micro}"
|
335
|
+
|
336
|
+
@GeneralUtilities.check_arguments
|
337
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> Version:
|
338
|
+
versions = ImageUpdaterHelper.get_versions_in_docker_hub(image, ".", "^\\d+\\.\\d+\\.\\d+$", 999)
|
339
|
+
newer_versions = ImageUpdaterHelper.filter_for_newer_versions(current_version, versions)
|
340
|
+
result = ImageUpdaterHelper.filter_considering_echolog(newer_versions, current_version, version_echolon)
|
341
|
+
return result
|
342
|
+
|
343
|
+
@GeneralUtilities.check_arguments
|
344
|
+
def get_supported_images(self) -> list[str]:
|
345
|
+
return ["adminer"]
|
346
|
+
|
347
|
+
@GeneralUtilities.check_arguments
|
348
|
+
def get_version_from_tag(self, image: str, tag: str) -> Version:
|
349
|
+
return ve.parse(tag)
|
350
|
+
|
351
|
+
|
352
|
+
class ImageUpdater:
|
353
|
+
|
354
|
+
updater: list[ConcreteImageUpdater] = None
|
355
|
+
|
356
|
+
def __init__(self):
|
357
|
+
self.updater = list[ConcreteImageUpdater]()
|
358
|
+
|
359
|
+
def add_default_mapper(self) -> None:
|
360
|
+
self.updater.append(ConcreteImageUpdaterForNginx())
|
361
|
+
self.updater.append(ConcreteImageUpdaterForGitLab())
|
362
|
+
self.updater.append(ConcreteImageUpdaterForRegistry())
|
363
|
+
self.updater.append(ConcreteImageUpdaterForPrometheus())
|
364
|
+
self.updater.append(ConcreteImageUpdaterForPrometheusBlackboxExporter())
|
365
|
+
self.updater.append(ConcreteImageUpdaterForPrometheusNginxExporter())
|
366
|
+
self.updater.append(ConcreteImageUpdaterForPrometheusNodeExporter())
|
367
|
+
self.updater.append(ConcreteImageUpdaterForKeycloak())
|
368
|
+
self.updater.append(ConcreteImageUpdaterForMariaDB())
|
369
|
+
self.updater.append(ConcreteImageUpdaterForPostgreSQL())
|
370
|
+
self.updater.append(ConcreteImageUpdaterForAdminer())
|
371
|
+
|
372
|
+
@GeneralUtilities.check_arguments
|
373
|
+
def check_service_for_newest_version(self, dockercompose_file: str, service_name: str) -> bool:
|
374
|
+
imagename, existing_tag, existing_version = self.get_current_version_of_service_from_docker_compose_file(dockercompose_file, service_name) # pylint:disable=unused-variable
|
375
|
+
newest_version, newest_tag = self.get_latest_version_of_image(imagename, VersionEcholon.Newest, existing_version) # pylint:disable=unused-variable
|
376
|
+
if existing_version < newest_version:
|
377
|
+
GeneralUtilities.write_message_to_stdout(f"Service {service_name} with image {imagename} uses tag {existing_version}. The newest available version of this image is {newest_version}.")
|
378
|
+
return True
|
379
|
+
else:
|
380
|
+
return False
|
381
|
+
|
382
|
+
@GeneralUtilities.check_arguments
|
383
|
+
def check_for_newest_version(self, dockercompose_file: str, excluded_services: list[str] = []) -> bool:
|
384
|
+
all_services = self.get_services_from_docker_compose_file(dockercompose_file)
|
385
|
+
services_to_check = [service for service in all_services if service not in all_services]
|
386
|
+
newer_version_available: bool = False
|
387
|
+
for service_to_check in services_to_check:
|
388
|
+
if self.check_service_for_newest_version(dockercompose_file, service_to_check):
|
389
|
+
newer_version_available = True
|
390
|
+
return newer_version_available
|
391
|
+
|
392
|
+
@GeneralUtilities.check_arguments
|
393
|
+
def update_all_services_in_docker_compose_file(self, dockercompose_file: str, version_echolon: VersionEcholon, except_services: list[str] = []):
|
394
|
+
all_services = self.get_services_from_docker_compose_file(dockercompose_file)
|
395
|
+
services_to_update = [service for service in all_services if service not in except_services]
|
396
|
+
self.update_services_in_docker_compose_file(dockercompose_file, services_to_update, version_echolon)
|
397
|
+
|
398
|
+
@GeneralUtilities.check_arguments
|
399
|
+
def update_services_in_docker_compose_file(self, dockercompose_file: str, service_names: list[str], version_echolon: VersionEcholon):
|
400
|
+
for service_name in service_names:
|
401
|
+
if self.service_has_image_information(dockercompose_file, service_name):
|
402
|
+
self.update_service_in_docker_compose_file(dockercompose_file, service_name, version_echolon)
|
403
|
+
|
404
|
+
@GeneralUtilities.check_arguments
|
405
|
+
def service_has_image_information(self, dockercompose_file: str, service_name: str) -> bool:
|
406
|
+
with open(dockercompose_file, 'r', encoding="utf-8") as file:
|
407
|
+
compose_data = yaml.safe_load(file)
|
408
|
+
service = compose_data.get('services', {}).get(service_name, {})
|
409
|
+
image = service.get('image', None)
|
410
|
+
return image is not None
|
411
|
+
|
412
|
+
@GeneralUtilities.check_arguments
|
413
|
+
def update_service_in_docker_compose_file(self, dockercompose_file: str, service_name: str, version_echolon: VersionEcholon):
|
414
|
+
imagename, existing_tag, existing_version = self.get_current_version_of_service_from_docker_compose_file(dockercompose_file, service_name) # pylint:disable=unused-variable
|
415
|
+
result = self.get_latest_version_of_image(imagename, version_echolon, existing_version)
|
416
|
+
newest_version = result[0]
|
417
|
+
newest_tag = result[1]
|
418
|
+
if existing_version < newest_version:
|
419
|
+
|
420
|
+
with open(dockercompose_file, 'r', encoding="utf-8") as f:
|
421
|
+
compose_data = yaml.safe_load(f)
|
422
|
+
|
423
|
+
services = compose_data.get("services", {})
|
424
|
+
if service_name not in services:
|
425
|
+
raise ValueError(f"Service '{service_name}' not found.")
|
426
|
+
|
427
|
+
image = services[service_name].get("image")
|
428
|
+
if not image:
|
429
|
+
raise ValueError(f"Service '{service_name}' does not have an image-field.")
|
430
|
+
|
431
|
+
imagename = image.split(":")[0]
|
432
|
+
services[service_name]["image"] = imagename+":"+newest_tag
|
433
|
+
|
434
|
+
with open(dockercompose_file, 'w', encoding="utf-8") as f:
|
435
|
+
yaml.dump(compose_data, f, default_flow_style=False)
|
436
|
+
|
437
|
+
@GeneralUtilities.check_arguments
|
438
|
+
def get_current_version_of_service_from_docker_compose_file(self, dockercompose_file: str, service_name: str) -> tuple[str, str, Version]: # returns (image,existing_tag,existing_version)
|
439
|
+
with open(dockercompose_file, 'r', encoding="utf-8") as file:
|
440
|
+
compose_data = yaml.safe_load(file)
|
441
|
+
service = compose_data.get('services', {}).get(service_name, {})
|
442
|
+
image = str(service.get('image', None))
|
443
|
+
if image:
|
444
|
+
if ':' in image:
|
445
|
+
name, tag = image.rsplit(':', 1)
|
446
|
+
else:
|
447
|
+
name, tag = image, 'latest'
|
448
|
+
return name, tag, self.get_docker_version_from_tag(name, tag)
|
449
|
+
else:
|
450
|
+
raise ValueError(f"Service '{service_name}' in '{dockercompose_file}'")
|
451
|
+
|
452
|
+
@GeneralUtilities.check_arguments
|
453
|
+
def __get_updater_for_image(self, image: str) -> str:
|
454
|
+
for updater in self.updater:
|
455
|
+
if image in updater.get_supported_images():
|
456
|
+
return updater
|
457
|
+
raise ValueError(f"No updater available for image '{image}'")
|
458
|
+
|
459
|
+
@GeneralUtilities.check_arguments
|
460
|
+
def get_docker_version_from_tag(self, image: str, tag: str) -> Version:
|
461
|
+
updater: ImageUpdater = self.__get_updater_for_image(image)
|
462
|
+
return updater.get_version_from_tag(image, tag)
|
463
|
+
|
464
|
+
@GeneralUtilities.check_arguments
|
465
|
+
def get_latest_version_of_image(self, image: str, version_echolon: VersionEcholon, current_version: Version) -> tuple[Version, str]:
|
466
|
+
updater: ImageUpdater = self.__get_updater_for_image(image)
|
467
|
+
newest_version: Version = updater.get_latest_version_of_image(image, version_echolon, current_version)
|
468
|
+
newest_tag: str = updater.version_to_tag(newest_version)
|
469
|
+
return (newest_version, newest_tag)
|
470
|
+
|
471
|
+
@GeneralUtilities.check_arguments
|
472
|
+
def get_services_from_docker_compose_file(self, dockercompose_file: str) -> list[str]:
|
473
|
+
with open(dockercompose_file, 'r', encoding="utf-8") as f:
|
474
|
+
compose_data = yaml.safe_load(f)
|
475
|
+
services = compose_data.get('services', {})
|
476
|
+
result = list(services.keys())
|
477
|
+
return result
|
ScriptCollection/SCLog.py
CHANGED
@@ -29,42 +29,55 @@ class SCLog:
|
|
29
29
|
self.log(f"Exception: {message}; Exception-details: {str(ex)}; Traceback: {current_traceback.format_exc()}", LogLevel.Error)
|
30
30
|
|
31
31
|
@GeneralUtilities.check_arguments
|
32
|
-
def log(self, message: str, loglevel: LogLevel):
|
32
|
+
def log(self, message: str, loglevel: LogLevel = None):
|
33
|
+
for line in GeneralUtilities.string_to_lines(message, True, False):
|
34
|
+
self.__log_line(line, loglevel)
|
35
|
+
|
36
|
+
@GeneralUtilities.check_arguments
|
37
|
+
def __log_line(self, message: str, loglevel: LogLevel = None):
|
33
38
|
if loglevel is None:
|
34
39
|
loglevel = LogLevel.Information
|
35
40
|
|
36
41
|
if int(loglevel) > int(self.loglevel):
|
37
42
|
return
|
38
43
|
|
44
|
+
part1: str = ""
|
45
|
+
part2: str = ""
|
46
|
+
part3: str = message
|
47
|
+
|
39
48
|
if loglevel == LogLevel.Warning:
|
40
|
-
|
49
|
+
part3 = f"Warning: {message}"
|
41
50
|
if loglevel == LogLevel.Debug:
|
42
|
-
|
51
|
+
part3 = f"Debug: {message}"
|
43
52
|
if self.add_overhead:
|
44
|
-
|
45
|
-
|
53
|
+
part1 = f"[{GeneralUtilities.datetime_to_string_for_logfile_entry(datetime.now())}] ["
|
54
|
+
if loglevel == LogLevel.Information:
|
55
|
+
part2 = f"Information"
|
56
|
+
elif loglevel == LogLevel.Error:
|
57
|
+
part2 = f"Error"
|
46
58
|
elif loglevel == LogLevel.Warning:
|
47
|
-
|
59
|
+
part2 = f"Warning"
|
48
60
|
elif loglevel == LogLevel.Debug:
|
49
|
-
|
50
|
-
elif loglevel == LogLevel.Information:
|
51
|
-
message = f"[Information] {message}"
|
61
|
+
part2 = f"Debug"
|
52
62
|
else:
|
53
63
|
raise ValueError("Unknown loglevel.")
|
64
|
+
part3 = f"] {message}"
|
54
65
|
|
55
|
-
|
56
|
-
|
57
|
-
if
|
58
|
-
|
66
|
+
print_to_std_out: bool = loglevel in (LogLevel.Debug, LogLevel.Information)
|
67
|
+
GeneralUtilities.print_text(part1, print_to_std_out)
|
68
|
+
# if the control-characters for colors cause problems then maybe it can be checked with sys.stdout.isatty() if colors should be printed
|
69
|
+
if loglevel == LogLevel.Information:
|
70
|
+
GeneralUtilities.print_text_in_green(part2, print_to_std_out)
|
71
|
+
elif loglevel == LogLevel.Error:
|
72
|
+
GeneralUtilities.print_text_in_red(part2, print_to_std_out)
|
59
73
|
elif loglevel == LogLevel.Warning:
|
60
|
-
GeneralUtilities.
|
74
|
+
GeneralUtilities.print_text_in_yellow(part2, print_to_std_out)
|
61
75
|
elif loglevel == LogLevel.Debug:
|
62
|
-
GeneralUtilities.
|
63
|
-
elif loglevel == LogLevel.Information:
|
64
|
-
GeneralUtilities.write_message_to_stdout(message)
|
76
|
+
GeneralUtilities.print_text_in_cyan(part2, print_to_std_out)
|
65
77
|
else:
|
66
78
|
raise ValueError("Unknown loglevel.")
|
79
|
+
GeneralUtilities.print_text(part3+"\n", print_to_std_out)
|
67
80
|
|
68
81
|
if self.log_file is not None:
|
69
82
|
GeneralUtilities.ensure_file_exists(self.log_file)
|
70
|
-
GeneralUtilities.append_line_to_file(self.log_file,
|
83
|
+
GeneralUtilities.append_line_to_file(self.log_file, part1+part2+part3)
|
@@ -28,12 +28,12 @@ import qrcode
|
|
28
28
|
import pycdlib
|
29
29
|
import send2trash
|
30
30
|
from pypdf import PdfReader, PdfWriter
|
31
|
-
from .GeneralUtilities import GeneralUtilities
|
31
|
+
from .GeneralUtilities import GeneralUtilities
|
32
32
|
from .ProgramRunnerBase import ProgramRunnerBase
|
33
33
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
34
34
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
35
35
|
|
36
|
-
version = "3.5.
|
36
|
+
version = "3.5.120"
|
37
37
|
__version__ = version
|
38
38
|
|
39
39
|
|
@@ -63,7 +63,7 @@ class ScriptCollectionCore:
|
|
63
63
|
errors = list()
|
64
64
|
filename = os.path.relpath(file, working_directory)
|
65
65
|
if treat_warnings_as_errors:
|
66
|
-
errorsonly_argument =
|
66
|
+
errorsonly_argument = GeneralUtilities.empty_string
|
67
67
|
else:
|
68
68
|
errorsonly_argument = " --errors-only"
|
69
69
|
(exit_code, stdout, stderr, _) = self.run_program("pylint", filename + errorsonly_argument, working_directory, throw_exception_if_exitcode_is_not_zero=False)
|
@@ -167,14 +167,14 @@ class ScriptCollectionCore:
|
|
167
167
|
@GeneralUtilities.check_arguments
|
168
168
|
def get_parent_commit_ids_of_commit(self, repository_folder: str, commit_id: str) -> str:
|
169
169
|
self.assert_is_git_repository(repository_folder)
|
170
|
-
return self.run_program("git", f'log --pretty=%P -n 1 "{commit_id}"', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].replace("\r",
|
170
|
+
return self.run_program("git", f'log --pretty=%P -n 1 "{commit_id}"', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string).split(" ")
|
171
171
|
|
172
172
|
@GeneralUtilities.check_arguments
|
173
173
|
def get_all_authors_and_committers_of_repository(self, repository_folder: str, subfolder: str = None, verbosity: int = 1) -> list[tuple[str, str]]:
|
174
174
|
self.assert_is_git_repository(repository_folder)
|
175
175
|
space_character = "_"
|
176
176
|
if subfolder is None:
|
177
|
-
subfolder_argument =
|
177
|
+
subfolder_argument = GeneralUtilities.empty_string
|
178
178
|
else:
|
179
179
|
subfolder_argument = f" -- {subfolder}"
|
180
180
|
log_result = self.run_program("git", f'log --pretty=%aN{space_character}%aE%n%cN{space_character}%cE HEAD{subfolder_argument}', repository_folder, verbosity=0)
|
@@ -194,7 +194,7 @@ class ScriptCollectionCore:
|
|
194
194
|
self.assert_is_git_repository(repository_folder)
|
195
195
|
since_as_string = self.__datetime_to_string_for_git(since)
|
196
196
|
until_as_string = self.__datetime_to_string_for_git(until)
|
197
|
-
result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program("git", f'log --since "{since_as_string}" --until "{until_as_string}" --pretty=format:"%H" --no-patch', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].split("\n").replace("\r",
|
197
|
+
result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program("git", f'log --since "{since_as_string}" --until "{until_as_string}" --pretty=format:"%H" --no-patch', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].split("\n").replace("\r", GeneralUtilities.empty_string))
|
198
198
|
if ignore_commits_which_are_not_in_history_of_head:
|
199
199
|
result = [commit_id for commit_id in result if self.git_commit_is_ancestor(repository_folder, commit_id)]
|
200
200
|
return result
|
@@ -557,19 +557,19 @@ class ScriptCollectionCore:
|
|
557
557
|
def git_get_current_branch_name(self, repository: str) -> str:
|
558
558
|
self.assert_is_git_repository(repository)
|
559
559
|
result = self.run_program_argsasarray("git", ["rev-parse", "--abbrev-ref", "HEAD"], repository, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
560
|
-
return result[1].replace("\r",
|
560
|
+
return result[1].replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string)
|
561
561
|
|
562
562
|
@GeneralUtilities.check_arguments
|
563
563
|
def git_get_commitid_of_tag(self, repository: str, tag: str) -> str:
|
564
564
|
self.assert_is_git_repository(repository)
|
565
565
|
stdout = self.run_program_argsasarray("git", ["rev-list", "-n", "1", tag], repository, verbosity=0)
|
566
|
-
result = stdout[1].replace("\r",
|
566
|
+
result = stdout[1].replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string)
|
567
567
|
return result
|
568
568
|
|
569
569
|
@GeneralUtilities.check_arguments
|
570
570
|
def git_get_tags(self, repository: str) -> list[str]:
|
571
571
|
self.assert_is_git_repository(repository)
|
572
|
-
tags = [line.replace("\r",
|
572
|
+
tags = [line.replace("\r", GeneralUtilities.empty_string) for line in self.run_program_argsasarray(
|
573
573
|
"git", ["tag"], repository)[1].split("\n") if len(line) > 0]
|
574
574
|
return tags
|
575
575
|
|
@@ -604,14 +604,14 @@ class ScriptCollectionCore:
|
|
604
604
|
def get_latest_git_tag(self, repository_folder: str) -> str:
|
605
605
|
self.assert_is_git_repository(repository_folder)
|
606
606
|
result = self.run_program_argsasarray("git", ["describe", "--tags", "--abbrev=0"], repository_folder, verbosity=0)
|
607
|
-
result = result[1].replace("\r",
|
607
|
+
result = result[1].replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string)
|
608
608
|
return result
|
609
609
|
|
610
610
|
@GeneralUtilities.check_arguments
|
611
611
|
def get_staged_or_committed_git_ignored_files(self, repository_folder: str) -> list[str]:
|
612
612
|
self.assert_is_git_repository(repository_folder)
|
613
613
|
temp_result = self.run_program_argsasarray("git", ["ls-files", "-i", "-c", "--exclude-standard"], repository_folder, verbosity=0)
|
614
|
-
temp_result = temp_result[1].replace("\r",
|
614
|
+
temp_result = temp_result[1].replace("\r", GeneralUtilities.empty_string)
|
615
615
|
result = [line for line in temp_result.split("\n") if len(line) > 0]
|
616
616
|
return result
|
617
617
|
|
@@ -1243,7 +1243,7 @@ class ScriptCollectionCore:
|
|
1243
1243
|
def __adjust_folder_name(self, folder: str) -> str:
|
1244
1244
|
result = os.path.dirname(folder).replace("\\", "/")
|
1245
1245
|
if result == "/":
|
1246
|
-
return
|
1246
|
+
return GeneralUtilities.empty_string
|
1247
1247
|
else:
|
1248
1248
|
return result
|
1249
1249
|
|
@@ -1449,7 +1449,7 @@ class ScriptCollectionCore:
|
|
1449
1449
|
GeneralUtilities.assert_condition(not GeneralUtilities.string_is_none_or_whitespace(ls_result[1]), f"'ls -ld' of '{file_or_folder}' had an empty output. StdErr: '{ls_result[2]}'")
|
1450
1450
|
GeneralUtilities.write_message_to_stdout(ls_result[1])
|
1451
1451
|
output = ls_result[1]
|
1452
|
-
result = output.replace("\n",
|
1452
|
+
result = output.replace("\n", GeneralUtilities.empty_string)
|
1453
1453
|
result = ' '.join(result.split()) # reduce multiple whitespaces to one
|
1454
1454
|
return result
|
1455
1455
|
|
@@ -1538,7 +1538,7 @@ class ScriptCollectionCore:
|
|
1538
1538
|
try:
|
1539
1539
|
while not q_stdout.empty():
|
1540
1540
|
out_line: str = q_stdout.get_nowait()
|
1541
|
-
out_line = out_line.replace("\r",
|
1541
|
+
out_line = out_line.replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string)
|
1542
1542
|
if GeneralUtilities.string_has_content(out_line):
|
1543
1543
|
stdout_result.append(out_line)
|
1544
1544
|
reading_stdout_last_time_resulted_in_exception = False
|
@@ -1552,7 +1552,7 @@ class ScriptCollectionCore:
|
|
1552
1552
|
try:
|
1553
1553
|
while not q_stderr.empty():
|
1554
1554
|
err_line: str = q_stderr.get_nowait()
|
1555
|
-
err_line = err_line.replace("\r",
|
1555
|
+
err_line = err_line.replace("\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string)
|
1556
1556
|
if GeneralUtilities.string_has_content(err_line):
|
1557
1557
|
stderr_result.append(err_line)
|
1558
1558
|
reading_stderr_last_time_resulted_in_exception = False
|
@@ -1600,8 +1600,8 @@ class ScriptCollectionCore:
|
|
1600
1600
|
GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
|
1601
1601
|
|
1602
1602
|
exit_code: int = None
|
1603
|
-
stdout: str =
|
1604
|
-
stderr: str =
|
1603
|
+
stdout: str = GeneralUtilities.empty_string
|
1604
|
+
stderr: str = GeneralUtilities.empty_string
|
1605
1605
|
pid: int = None
|
1606
1606
|
|
1607
1607
|
with self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive) as process:
|
@@ -1971,10 +1971,10 @@ DNS = {domain}
|
|
1971
1971
|
csproj_filename = os.path.basename(csproj_file)
|
1972
1972
|
GeneralUtilities.write_message_to_stdout(f"Check for updates in {csproj_filename}")
|
1973
1973
|
result = self.run_program_with_retry("dotnet", f"list {csproj_filename} package --outdated", folder, print_errors_as_information=True)
|
1974
|
-
for line in result[1].replace("\r",
|
1974
|
+
for line in result[1].replace("\r", GeneralUtilities.empty_string).split("\n"):
|
1975
1975
|
# Relevant output-lines are something like " > NJsonSchema 10.7.0 10.7.0 10.9.0"
|
1976
1976
|
if ">" in line:
|
1977
|
-
package_name = line.replace(">",
|
1977
|
+
package_name = line.replace(">", GeneralUtilities.empty_string).strip().split(" ")[0]
|
1978
1978
|
if not (package_name in ignored_dependencies):
|
1979
1979
|
GeneralUtilities.write_message_to_stdout(f"Update package {package_name}...")
|
1980
1980
|
self.run_program("dotnet", f"add {csproj_filename} package {package_name}", folder, print_errors_as_information=True)
|
@@ -2330,47 +2330,3 @@ TXDX
|
|
2330
2330
|
@GeneralUtilities.check_arguments
|
2331
2331
|
def install_requirementstxt_file(self, requirements_txt_file: str, folder: str, verbosity: int):
|
2332
2332
|
self.run_program_argsasarray("pip", ["install", "-r", requirements_txt_file], folder, verbosity=verbosity)
|
2333
|
-
|
2334
|
-
@GeneralUtilities.check_arguments
|
2335
|
-
def update_all_services_in_docker_compose_file(self, dockercompose_file: str, version_echolon: VersionEcholon):
|
2336
|
-
raise ValueError("not implemented yet")
|
2337
|
-
|
2338
|
-
@GeneralUtilities.check_arguments
|
2339
|
-
def update_service_in_docker_compose_file(self, dockercompose_file: str, service_name: str, version_echolon: VersionEcholon):
|
2340
|
-
raise ValueError("not implemented yet")
|
2341
|
-
|
2342
|
-
@GeneralUtilities.check_arguments
|
2343
|
-
def get_current_version_of_service_from_docker_compose_file(self, dockercompose_file: str, service_name: str):
|
2344
|
-
raise ValueError("not implemented yet")
|
2345
|
-
|
2346
|
-
@GeneralUtilities.check_arguments
|
2347
|
-
def get_services_from_docker_compose_file(self, dockercompose_file: str):
|
2348
|
-
raise ValueError("not implemented yet")
|
2349
|
-
|
2350
|
-
@GeneralUtilities.check_arguments
|
2351
|
-
def get_next_version_for_nginx(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
|
2352
|
-
raise ValueError("not implemented yet")
|
2353
|
-
|
2354
|
-
@GeneralUtilities.check_arguments
|
2355
|
-
def get_next_version_for_prometheus(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
|
2356
|
-
raise ValueError("not implemented yet")
|
2357
|
-
|
2358
|
-
@GeneralUtilities.check_arguments
|
2359
|
-
def get_next_version_for_blackbox_exporter(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
|
2360
|
-
raise ValueError("not implemented yet")
|
2361
|
-
|
2362
|
-
@GeneralUtilities.check_arguments
|
2363
|
-
def get_next_version_for_gitlab(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
|
2364
|
-
raise ValueError("not implemented yet")
|
2365
|
-
|
2366
|
-
@GeneralUtilities.check_arguments
|
2367
|
-
def get_next_version_for_nextcloud(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
|
2368
|
-
raise ValueError("not implemented yet")
|
2369
|
-
|
2370
|
-
@GeneralUtilities.check_arguments
|
2371
|
-
def get_next_version_for_genericservice(self, registry_address: str, current_version: str, version_echolon: VersionEcholon, tag_prefix: str):
|
2372
|
-
raise ValueError("not implemented yet")
|
2373
|
-
|
2374
|
-
@GeneralUtilities.check_arguments
|
2375
|
-
def get_all_available_tags(self, registry_address: str, service: str):
|
2376
|
-
raise ValueError("not implemented yet")
|
@@ -340,15 +340,15 @@ class TasksForCommonProjectStructure:
|
|
340
340
|
filename = os.path.basename(wheel_file)
|
341
341
|
|
342
342
|
if gpg_identity is None:
|
343
|
-
gpg_identity_argument =
|
343
|
+
gpg_identity_argument = GeneralUtilities.empty_string
|
344
344
|
else:
|
345
|
-
gpg_identity_argument =
|
345
|
+
gpg_identity_argument = GeneralUtilities.empty_string # f" --sign --identity {gpg_identity}"
|
346
346
|
# disabled due to https://blog.pypi.org/posts/2023-05-23-removing-pgp/
|
347
347
|
|
348
348
|
if verbosity > 2:
|
349
349
|
verbose_argument = " --verbose"
|
350
350
|
else:
|
351
|
-
verbose_argument =
|
351
|
+
verbose_argument = GeneralUtilities.empty_string
|
352
352
|
|
353
353
|
twine_argument = f"upload{gpg_identity_argument} --repository {repository} --non-interactive {filename} --disable-progress-bar"
|
354
354
|
twine_argument = f"{twine_argument} --username __token__ --password {api_key}{verbose_argument}"
|
@@ -649,8 +649,8 @@ class TasksForCommonProjectStructure:
|
|
649
649
|
filename = os.path.basename(csproj_file)
|
650
650
|
GeneralUtilities.write_message_to_stdout(f"Check {filename}...")
|
651
651
|
file_content = GeneralUtilities.read_text_from_file(csproj_file)
|
652
|
-
regex = regex.replace("\r",
|
653
|
-
file_content = file_content.replace("\r",
|
652
|
+
regex = regex.replace("\r", GeneralUtilities.empty_string).replace("\n", "\\n")
|
653
|
+
file_content = file_content.replace("\r", GeneralUtilities.empty_string)
|
654
654
|
match = re.match(regex, file_content)
|
655
655
|
return match is not None
|
656
656
|
|
@@ -972,13 +972,13 @@ class TasksForCommonProjectStructure:
|
|
972
972
|
diff_target_file = os.path.join(diff_target_folder, "DiffReport.html")
|
973
973
|
title = (f'Reference of codeunit {codeunitname} {codeunit_version_identifier} (contained in project <a href="{public_repository_url}">{projectname}</a> {project_version_identifier})')
|
974
974
|
if public_repository_url is None:
|
975
|
-
repo_url_html =
|
975
|
+
repo_url_html = GeneralUtilities.empty_string
|
976
976
|
else:
|
977
977
|
repo_url_html = f'<a href="{public_repository_url}/tree/{branch}/{codeunitname}">Source-code</a>'
|
978
978
|
if codeunit_has_testcases:
|
979
979
|
coverage_report_link = '<a href="./TestCoverageReport/index.html">Test-coverage-report</a><br>'
|
980
980
|
else:
|
981
|
-
coverage_report_link =
|
981
|
+
coverage_report_link = GeneralUtilities.empty_string
|
982
982
|
index_file_for_reference = os.path.join(target_folder, "index.html")
|
983
983
|
|
984
984
|
design_file = None
|
@@ -987,7 +987,7 @@ class TasksForCommonProjectStructure:
|
|
987
987
|
design_file = GeneralUtilities.get_modest_dark_url()
|
988
988
|
# TODO make designs from customizable sources be available by a customizable name and outsource this to a class-property because this is duplicated code.
|
989
989
|
if design_file is None:
|
990
|
-
design_html =
|
990
|
+
design_html = GeneralUtilities.empty_string
|
991
991
|
else:
|
992
992
|
design_html = f'<link type="text/css" rel="stylesheet" href="{design_file}" />'
|
993
993
|
|
@@ -1095,7 +1095,7 @@ class TasksForCommonProjectStructure:
|
|
1095
1095
|
if version_identifier_of_project == "Latest":
|
1096
1096
|
latest_version_hint = f" (v{project_version})"
|
1097
1097
|
else:
|
1098
|
-
latest_version_hint =
|
1098
|
+
latest_version_hint = GeneralUtilities.empty_string
|
1099
1099
|
reference_versions_html_lines.append(f' <h2>{version_identifier_of_project}{latest_version_hint}</h2>')
|
1100
1100
|
reference_versions_html_lines.append(" Contained codeunits:<br/>")
|
1101
1101
|
reference_versions_html_lines.append(" <ul>")
|
@@ -1113,7 +1113,7 @@ class TasksForCommonProjectStructure:
|
|
1113
1113
|
design_file = GeneralUtilities.get_modest_dark_url()
|
1114
1114
|
# TODO make designs from customizable sources be available by a customizable name and outsource this to a class-property because this is duplicated code.
|
1115
1115
|
if design_file is None:
|
1116
|
-
design_html =
|
1116
|
+
design_html = GeneralUtilities.empty_string
|
1117
1117
|
else:
|
1118
1118
|
design_html = f'<link type="text/css" rel="stylesheet" href="{design_file}" />'
|
1119
1119
|
|
@@ -1423,7 +1423,7 @@ class TasksForCommonProjectStructure:
|
|
1423
1423
|
self.__sc.format_xml_file(sbom_folder+f"/{codeunitname}.{codeunitversion}.sbom.xml")
|
1424
1424
|
|
1425
1425
|
@GeneralUtilities.check_arguments
|
1426
|
-
def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, verbosity: int, push_readme: bool, commandline_arguments: list[str], repository_folder_name: str) -> None:
|
1426
|
+
def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, verbosity: int, push_readme: bool, commandline_arguments: list[str], repository_folder_name: str,image_name:str=None) -> None:
|
1427
1427
|
folder_of_this_file = os.path.dirname(push_artifacts_file)
|
1428
1428
|
filename = os.path.basename(push_artifacts_file)
|
1429
1429
|
codeunitname_regex: str = "([a-zA-Z0-9]+)"
|
@@ -1441,15 +1441,17 @@ class TasksForCommonProjectStructure:
|
|
1441
1441
|
image_file = sc.find_file_by_extension(applicationimage_folder, "tar")
|
1442
1442
|
image_filename = os.path.basename(image_file)
|
1443
1443
|
codeunit_version = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
|
1444
|
-
|
1445
|
-
|
1444
|
+
if image_name is None:
|
1445
|
+
image_name = codeunitname
|
1446
|
+
image_name=image_name.lower()
|
1447
|
+
repo = f"{registry}/{image_name}"
|
1446
1448
|
image_latest = f"{repo}:latest"
|
1447
1449
|
image_version = f"{repo}:{codeunit_version}"
|
1448
1450
|
GeneralUtilities.write_message_to_stdout("Load image...")
|
1449
1451
|
sc.run_program("docker", f"load --input {image_filename}", applicationimage_folder, verbosity=verbosity)
|
1450
1452
|
GeneralUtilities.write_message_to_stdout("Tag image...")
|
1451
|
-
sc.run_program("docker", f"tag {
|
1452
|
-
sc.run_program("docker", f"tag {
|
1453
|
+
sc.run_program("docker", f"tag {image_name}:{codeunit_version} {image_latest}", verbosity=verbosity)
|
1454
|
+
sc.run_program("docker", f"tag {image_name}:{codeunit_version} {image_version}", verbosity=verbosity)
|
1453
1455
|
GeneralUtilities.write_message_to_stdout("Push image...")
|
1454
1456
|
sc.run_program("docker", f"push {image_latest}", verbosity=verbosity)
|
1455
1457
|
sc.run_program("docker", f"push {image_version}", verbosity=verbosity)
|
@@ -1940,7 +1942,7 @@ class TasksForCommonProjectStructure:
|
|
1940
1942
|
def set_constant(self, codeunit_folder: str, constantname: str, constant_value: str, documentationsummary: str = None, constants_valuefile: str = None) -> None:
|
1941
1943
|
self.assert_is_codeunit_folder(codeunit_folder)
|
1942
1944
|
if documentationsummary is None:
|
1943
|
-
documentationsummary =
|
1945
|
+
documentationsummary = GeneralUtilities.empty_string
|
1944
1946
|
constants_folder = os.path.join(codeunit_folder, "Other", "Resources", "Constants")
|
1945
1947
|
GeneralUtilities.ensure_directory_exists(constants_folder)
|
1946
1948
|
constants_metafile = os.path.join(constants_folder, f"{constantname}.constant.xml")
|
@@ -2259,7 +2261,7 @@ class TasksForCommonProjectStructure:
|
|
2259
2261
|
codeunit_file = os.path.join(codeunit_folder, f"{codeunit_name}.codeunit.xml")
|
2260
2262
|
root: etree._ElementTree = etree.parse(codeunit_file)
|
2261
2263
|
ignoreddependencies = root.xpath('//cps:codeunit/cps:properties/cps:updatesettings/cps:ignoreddependencies/cps:ignoreddependency', namespaces=namespaces)
|
2262
|
-
result = [x.text.replace("\\n",
|
2264
|
+
result = [x.text.replace("\\n", GeneralUtilities.empty_string).replace("\\r", GeneralUtilities.empty_string).replace("\n", GeneralUtilities.empty_string).replace("\r", GeneralUtilities.empty_string).strip() for x in ignoreddependencies]
|
2263
2265
|
if print_warnings_for_ignored_dependencies and len(result) > 0:
|
2264
2266
|
GeneralUtilities.write_message_to_stderr(f"Warning: Codeunit {codeunit_name} contains the following dependencies which will are ignoed for automatic updates: "+', '.join(result))
|
2265
2267
|
return result
|
@@ -2346,7 +2348,7 @@ class TasksForCommonProjectStructure:
|
|
2346
2348
|
sc: ScriptCollectionCore = ScriptCollectionCore()
|
2347
2349
|
workspace_file: str = sc.find_file_by_extension(repository_folder, "code-workspace")
|
2348
2350
|
task_file: str = os.path.join(repository_folder, "Taskfile.yml")
|
2349
|
-
lines: list[str] = ["version: '3'",
|
2351
|
+
lines: list[str] = ["version: '3'", GeneralUtilities.empty_string, "tasks:", GeneralUtilities.empty_string]
|
2350
2352
|
workspace_file_content: str = GeneralUtilities.read_text_from_file(workspace_file)
|
2351
2353
|
jsoncontent = json.loads(workspace_file_content)
|
2352
2354
|
tasks = jsoncontent["tasks"]["tasks"]
|
@@ -2389,7 +2391,7 @@ class TasksForCommonProjectStructure:
|
|
2389
2391
|
aliases = task["aliases"]
|
2390
2392
|
for alias in aliases:
|
2391
2393
|
lines.append(f' - {alias}')
|
2392
|
-
lines.append(
|
2394
|
+
lines.append(GeneralUtilities.empty_string)
|
2393
2395
|
GeneralUtilities.write_lines_to_file(task_file, lines)
|
2394
2396
|
|
2395
2397
|
@GeneralUtilities.check_arguments
|
@@ -2860,21 +2862,21 @@ class TasksForCommonProjectStructure:
|
|
2860
2862
|
|
2861
2863
|
description = self.get_codeunit_description(codeunit_file)
|
2862
2864
|
|
2863
|
-
lines.append(
|
2865
|
+
lines.append(GeneralUtilities.empty_string)
|
2864
2866
|
lines.append(f"[{codeunitname}]")
|
2865
2867
|
lines.append(f"note as {codeunitname}Note")
|
2866
2868
|
lines.append(f" {description}")
|
2867
2869
|
lines.append(f"end note")
|
2868
2870
|
lines.append(f"{codeunitname} .. {codeunitname}Note")
|
2869
2871
|
|
2870
|
-
lines.append(
|
2872
|
+
lines.append(GeneralUtilities.empty_string)
|
2871
2873
|
for codeunitname in codeunits:
|
2872
2874
|
codeunit_file: str = os.path.join(repository_folder, codeunitname, f"{codeunitname}.codeunit.xml")
|
2873
2875
|
dependent_codeunits = self.get_dependent_code_units(codeunit_file)
|
2874
2876
|
for dependent_codeunit in dependent_codeunits:
|
2875
2877
|
lines.append(f"{codeunitname} --> {dependent_codeunit}")
|
2876
2878
|
|
2877
|
-
lines.append(
|
2879
|
+
lines.append(GeneralUtilities.empty_string)
|
2878
2880
|
lines.append("@enduml")
|
2879
2881
|
|
2880
2882
|
GeneralUtilities.write_lines_to_file(target_file, lines)
|
@@ -3015,15 +3017,15 @@ class TasksForCommonProjectStructure:
|
|
3015
3017
|
build_folder = os.path.join(other_folder, "Build")
|
3016
3018
|
quality_folder = os.path.join(other_folder, "QualityCheck")
|
3017
3019
|
reference_folder = os.path.join(other_folder, "Reference")
|
3018
|
-
additional_arguments_c: str =
|
3019
|
-
additional_arguments_b: str =
|
3020
|
-
additional_arguments_r: str =
|
3021
|
-
additional_arguments_l: str =
|
3022
|
-
additional_arguments_g: str =
|
3023
|
-
additional_arguments_f: str =
|
3020
|
+
additional_arguments_c: str = GeneralUtilities.empty_string
|
3021
|
+
additional_arguments_b: str = GeneralUtilities.empty_string
|
3022
|
+
additional_arguments_r: str = GeneralUtilities.empty_string
|
3023
|
+
additional_arguments_l: str = GeneralUtilities.empty_string
|
3024
|
+
additional_arguments_g: str = GeneralUtilities.empty_string
|
3025
|
+
additional_arguments_f: str = GeneralUtilities.empty_string
|
3024
3026
|
general_argument = f' --overwrite_verbosity {str(verbosity)} --overwrite_targetenvironmenttype {target_environmenttype}'
|
3025
3027
|
|
3026
|
-
c_additionalargumentsfile_argument =
|
3028
|
+
c_additionalargumentsfile_argument = GeneralUtilities.empty_string
|
3027
3029
|
|
3028
3030
|
if is_pre_merge:
|
3029
3031
|
general_argument = general_argument+" --overwrite_is_pre_merge true"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ScriptCollection/CertificateUpdater.py,sha256=OAxrG21k_o3W3niOOGNSZzUPJlvolOWc1lRB2dMhc3g,9212
|
2
|
+
ScriptCollection/Executables.py,sha256=ht-RZFu4g34Sr09b_L0c2QpKcjLWX-wFtKSMDMZYqsw,32266
|
3
|
+
ScriptCollection/GeneralUtilities.py,sha256=hqAKRF99uu2RCSBgjX4qjYn3IlImwm6rehRvt8hbNFQ,46407
|
4
|
+
ScriptCollection/ImageUpdater.py,sha256=lel1nevTN7fgdoCDE6Xg8YY6XPsZaOQiCIyWXbmVnh0,20882
|
5
|
+
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
6
|
+
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
7
|
+
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
8
|
+
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
9
|
+
ScriptCollection/SCLog.py,sha256=lTNw2Th5xvjf9V_pQw6DSsZPdeLAdqOelfZPW8fCC-s,3063
|
10
|
+
ScriptCollection/ScriptCollectionCore.py,sha256=9kyDdGMDZNKR7j579zjUSt3vvTLHA-vPw4_Sd2YhWmc,130059
|
11
|
+
ScriptCollection/TasksForCommonProjectStructure.py,sha256=4aEuIf89jbgKE4uMYm4DlPDe9Iu1Zujo8wPOzDld09w,234867
|
12
|
+
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
scriptcollection-3.5.120.dist-info/METADATA,sha256=PbbVXi9-z9CwClIIuMdlLWkxve1wKz53TMNJYiLsdMA,7694
|
14
|
+
scriptcollection-3.5.120.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
15
|
+
scriptcollection-3.5.120.dist-info/entry_points.txt,sha256=3qMbfZEMhc_VTJj-bcLwB8AWcn9iXSB3l0AWpuu52Bs,3689
|
16
|
+
scriptcollection-3.5.120.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
17
|
+
scriptcollection-3.5.120.dist-info/RECORD,,
|
@@ -1,16 +0,0 @@
|
|
1
|
-
ScriptCollection/CertificateUpdater.py,sha256=pJopWFcwaLAEVljtC4O3SVrlpIpoJNUhT1V4mgiqLvE,8970
|
2
|
-
ScriptCollection/Executables.py,sha256=ht-RZFu4g34Sr09b_L0c2QpKcjLWX-wFtKSMDMZYqsw,32266
|
3
|
-
ScriptCollection/GeneralUtilities.py,sha256=VO4a7xctkjN5dcBXc32gz0x9U07DEagasjvYVKqLmdM,44173
|
4
|
-
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
5
|
-
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
6
|
-
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
7
|
-
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
8
|
-
ScriptCollection/SCLog.py,sha256=5qjOBYiliyHV57GY8Y5dgUek512EVI8AzBF288R4fn4,2377
|
9
|
-
ScriptCollection/ScriptCollectionCore.py,sha256=dzrgJteantFqcasor86q7GnhWyfuXk9QX6oWrFCpegg,131693
|
10
|
-
ScriptCollection/TasksForCommonProjectStructure.py,sha256=OfCJsg-FLdde6Duhy4FjBcfwLr-9iLhQAimRa1ZgRyE,234045
|
11
|
-
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
scriptcollection-3.5.118.dist-info/METADATA,sha256=S2GhphsHV1AG2Skb0k11jlesHhedCLWHWUldstjE3Io,7694
|
13
|
-
scriptcollection-3.5.118.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
14
|
-
scriptcollection-3.5.118.dist-info/entry_points.txt,sha256=3qMbfZEMhc_VTJj-bcLwB8AWcn9iXSB3l0AWpuu52Bs,3689
|
15
|
-
scriptcollection-3.5.118.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
16
|
-
scriptcollection-3.5.118.dist-info/RECORD,,
|
File without changes
|
File without changes
|