ScriptCollection 3.5.1__py3-none-any.whl → 3.5.3__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/Executables.py +5 -4
- ScriptCollection/ProgramRunnerBase.py +10 -5
- ScriptCollection/ProgramRunnerEpew.py +10 -10
- ScriptCollection/ProgramRunnerPopen.py +12 -9
- ScriptCollection/ScriptCollectionCore.py +475 -252
- ScriptCollection/TasksForCommonProjectStructure.py +34 -20
- {ScriptCollection-3.5.1.dist-info → ScriptCollection-3.5.3.dist-info}/METADATA +5 -5
- ScriptCollection-3.5.3.dist-info/RECORD +14 -0
- ScriptCollection-3.5.1.dist-info/RECORD +0 -14
- {ScriptCollection-3.5.1.dist-info → ScriptCollection-3.5.3.dist-info}/WHEEL +0 -0
- {ScriptCollection-3.5.1.dist-info → ScriptCollection-3.5.3.dist-info}/entry_points.txt +0 -0
- {ScriptCollection-3.5.1.dist-info → ScriptCollection-3.5.3.dist-info}/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
import binascii
|
|
5
5
|
import filecmp
|
|
6
6
|
import hashlib
|
|
7
|
-
from io import BytesIO
|
|
7
|
+
from io import BufferedReader, BytesIO
|
|
8
8
|
import itertools
|
|
9
9
|
import math
|
|
10
10
|
import os
|
|
@@ -28,8 +28,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
|
|
|
28
28
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
29
29
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
version = "3.5.1"
|
|
31
|
+
version = "3.5.3"
|
|
33
32
|
__version__ = version
|
|
34
33
|
|
|
35
34
|
|
|
@@ -59,7 +58,8 @@ class ScriptCollectionCore:
|
|
|
59
58
|
errorsonly_argument = ""
|
|
60
59
|
else:
|
|
61
60
|
errorsonly_argument = " --errors-only"
|
|
62
|
-
(exit_code, stdout, stderr, _) = self.run_program("pylint", filename+
|
|
61
|
+
(exit_code, stdout, stderr, _) = self.run_program("pylint", filename +
|
|
62
|
+
errorsonly_argument, working_directory, throw_exception_if_exitcode_is_not_zero=False)
|
|
63
63
|
if (exit_code != 0):
|
|
64
64
|
errors.append(f"Linting-issues of {file}:")
|
|
65
65
|
errors.append(f"Pylint-exitcode: {exit_code}")
|
|
@@ -73,15 +73,18 @@ class ScriptCollectionCore:
|
|
|
73
73
|
|
|
74
74
|
@GeneralUtilities.check_arguments
|
|
75
75
|
def replace_version_in_dockerfile_file(self, dockerfile: str, new_version_value: str) -> None:
|
|
76
|
-
GeneralUtilities.write_text_to_file(dockerfile, re.sub(
|
|
76
|
+
GeneralUtilities.write_text_to_file(dockerfile, re.sub(
|
|
77
|
+
"ARG Version=\"\\d+\\.\\d+\\.\\d+\"", f"ARG Version=\"{new_version_value}\"", GeneralUtilities.read_text_from_file(dockerfile)))
|
|
77
78
|
|
|
78
79
|
@GeneralUtilities.check_arguments
|
|
79
80
|
def replace_version_in_python_file(self, file: str, new_version_value: str):
|
|
80
|
-
GeneralUtilities.write_text_to_file(file, re.sub(
|
|
81
|
+
GeneralUtilities.write_text_to_file(file, re.sub(
|
|
82
|
+
"version = \"\\d+\\.\\d+\\.\\d+\"", f"version = \"{new_version_value}\"", GeneralUtilities.read_text_from_file(file)))
|
|
81
83
|
|
|
82
84
|
@GeneralUtilities.check_arguments
|
|
83
85
|
def replace_version_in_ini_file(self, file: str, new_version_value: str):
|
|
84
|
-
GeneralUtilities.write_text_to_file(file, re.sub(
|
|
86
|
+
GeneralUtilities.write_text_to_file(file, re.sub(
|
|
87
|
+
"version = \\d+\\.\\d+\\.\\d+", f"version = {new_version_value}", GeneralUtilities.read_text_from_file(file)))
|
|
85
88
|
|
|
86
89
|
@GeneralUtilities.check_arguments
|
|
87
90
|
def replace_version_in_nuspec_file(self, nuspec_file: str, new_version: str) -> None:
|
|
@@ -90,9 +93,11 @@ class ScriptCollectionCore:
|
|
|
90
93
|
versiononlyregex = f"^{versionregex}$"
|
|
91
94
|
pattern = re.compile(versiononlyregex)
|
|
92
95
|
if pattern.match(new_version):
|
|
93
|
-
GeneralUtilities.write_text_to_file(nuspec_file, re.sub(
|
|
96
|
+
GeneralUtilities.write_text_to_file(nuspec_file, re.sub(
|
|
97
|
+
f"<version>{versionregex}<\\/version>", f"<version>{new_version}</version>", GeneralUtilities.read_text_from_file(nuspec_file)))
|
|
94
98
|
else:
|
|
95
|
-
raise ValueError(
|
|
99
|
+
raise ValueError(
|
|
100
|
+
f"Version '{new_version}' does not match version-regex '{versiononlyregex}'")
|
|
96
101
|
|
|
97
102
|
@GeneralUtilities.check_arguments
|
|
98
103
|
def replace_version_in_csproj_file(self, csproj_file: str, current_version: str):
|
|
@@ -101,35 +106,44 @@ class ScriptCollectionCore:
|
|
|
101
106
|
pattern = re.compile(versiononlyregex)
|
|
102
107
|
if pattern.match(current_version):
|
|
103
108
|
for tag in ["Version", "AssemblyVersion", "FileVersion"]:
|
|
104
|
-
GeneralUtilities.write_text_to_file(csproj_file, re.sub(
|
|
109
|
+
GeneralUtilities.write_text_to_file(csproj_file, re.sub(
|
|
110
|
+
f"<{tag}>{versionregex}(.\\d+)?<\\/{tag}>", f"<{tag}>{current_version}</{tag}>", GeneralUtilities.read_text_from_file(csproj_file)))
|
|
105
111
|
else:
|
|
106
|
-
raise ValueError(
|
|
112
|
+
raise ValueError(
|
|
113
|
+
f"Version '{current_version}' does not match version-regex '{versiononlyregex}'")
|
|
107
114
|
|
|
108
115
|
@GeneralUtilities.check_arguments
|
|
109
116
|
def push_nuget_build_artifact(self, nupkg_file: str, registry_address: str, api_key: str, verbosity: int = 1):
|
|
110
117
|
nupkg_file_name = os.path.basename(nupkg_file)
|
|
111
118
|
nupkg_file_folder = os.path.dirname(nupkg_file)
|
|
112
|
-
self.run_program(
|
|
119
|
+
self.run_program(
|
|
120
|
+
"dotnet", f"nuget push {nupkg_file_name} --force-english-output --source {registry_address} --api-key {api_key}", nupkg_file_folder, verbosity)
|
|
113
121
|
|
|
114
122
|
@GeneralUtilities.check_arguments
|
|
115
123
|
def dotnet_build(self, repository_folder: str, projectname: str, configuration: str):
|
|
116
|
-
self.run_program(
|
|
117
|
-
|
|
124
|
+
self.run_program(
|
|
125
|
+
"dotnet", f"clean -c {configuration}", repository_folder)
|
|
126
|
+
self.run_program(
|
|
127
|
+
"dotnet", f"build {projectname}/{projectname}.csproj -c {configuration}", repository_folder)
|
|
118
128
|
|
|
119
129
|
@GeneralUtilities.check_arguments
|
|
120
130
|
def find_file_by_extension(self, folder: str, extension: str):
|
|
121
|
-
result = [file for file in GeneralUtilities.get_direct_files_of_folder(
|
|
131
|
+
result = [file for file in GeneralUtilities.get_direct_files_of_folder(
|
|
132
|
+
folder) if file.endswith(f".{extension}")]
|
|
122
133
|
result_length = len(result)
|
|
123
134
|
if result_length == 0:
|
|
124
|
-
raise FileNotFoundError(
|
|
135
|
+
raise FileNotFoundError(
|
|
136
|
+
f"No file available in folder '{folder}' with extension '{extension}'.")
|
|
125
137
|
if result_length == 1:
|
|
126
138
|
return result[0]
|
|
127
139
|
else:
|
|
128
|
-
raise ValueError(
|
|
140
|
+
raise ValueError(
|
|
141
|
+
f"Multiple values available in folder '{folder}' with extension '{extension}'.")
|
|
129
142
|
|
|
130
143
|
@GeneralUtilities.check_arguments
|
|
131
144
|
def commit_is_signed_by_key(self, repository_folder: str, revision_identifier: str, key: str) -> bool:
|
|
132
|
-
result = self.run_program(
|
|
145
|
+
result = self.run_program(
|
|
146
|
+
"git", f"verify-commit {revision_identifier}", repository_folder, throw_exception_if_exitcode_is_not_zero=False)
|
|
133
147
|
if (result[0] != 0):
|
|
134
148
|
return False
|
|
135
149
|
if (not GeneralUtilities.contains_line(result[1].splitlines(), f"gpg\\:\\ using\\ [A-Za-z0-9]+\\ key\\ [A-Za-z0-9]+{key}")):
|
|
@@ -151,8 +165,10 @@ class ScriptCollectionCore:
|
|
|
151
165
|
subfolder_argument = ""
|
|
152
166
|
else:
|
|
153
167
|
subfolder_argument = f" -- {subfolder}"
|
|
154
|
-
log_result = self.run_program(
|
|
155
|
-
|
|
168
|
+
log_result = self.run_program(
|
|
169
|
+
"git", f'log --pretty=%aN{space_character}%aE%n%cN{space_character}%cE HEAD{subfolder_argument}', repository_folder, verbosity=0)
|
|
170
|
+
plain_content: list[str] = list(
|
|
171
|
+
set([line for line in log_result[1].split("\n") if len(line) > 0]))
|
|
156
172
|
result: list[tuple[str, str]] = []
|
|
157
173
|
for item in plain_content:
|
|
158
174
|
if len(re.findall(space_character, item)) == 1:
|
|
@@ -166,9 +182,11 @@ class ScriptCollectionCore:
|
|
|
166
182
|
def get_commit_ids_between_dates(self, repository_folder: str, since: datetime, until: datetime, ignore_commits_which_are_not_in_history_of_head: bool = True) -> None:
|
|
167
183
|
since_as_string = self.__datetime_to_string_for_git(since)
|
|
168
184
|
until_as_string = self.__datetime_to_string_for_git(until)
|
|
169
|
-
result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program(
|
|
185
|
+
result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program(
|
|
186
|
+
"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", ""))
|
|
170
187
|
if ignore_commits_which_are_not_in_history_of_head:
|
|
171
|
-
result = [commit_id for commit_id in result if self.git_commit_is_ancestor(
|
|
188
|
+
result = [commit_id for commit_id in result if self.git_commit_is_ancestor(
|
|
189
|
+
repository_folder, commit_id)]
|
|
172
190
|
return result
|
|
173
191
|
|
|
174
192
|
@GeneralUtilities.check_arguments
|
|
@@ -177,17 +195,20 @@ class ScriptCollectionCore:
|
|
|
177
195
|
|
|
178
196
|
@GeneralUtilities.check_arguments
|
|
179
197
|
def git_commit_is_ancestor(self, repository_folder: str, ancestor: str, descendant: str = "HEAD") -> bool:
|
|
180
|
-
exit_code = self.run_program_argsasarray(
|
|
198
|
+
exit_code = self.run_program_argsasarray(
|
|
199
|
+
"git", ["merge-base", "--is-ancestor", ancestor, descendant], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0]
|
|
181
200
|
if exit_code == 0:
|
|
182
201
|
return True
|
|
183
202
|
elif exit_code == 1:
|
|
184
203
|
return False
|
|
185
204
|
else:
|
|
186
|
-
raise ValueError(
|
|
205
|
+
raise ValueError(
|
|
206
|
+
f"Can not calculate if {ancestor} is an ancestor of {descendant} in repository {repository_folder}.")
|
|
187
207
|
|
|
188
208
|
@GeneralUtilities.check_arguments
|
|
189
209
|
def __git_changes_helper(self, repository_folder: str, arguments_as_array: list[str]) -> bool:
|
|
190
|
-
lines = GeneralUtilities.string_to_lines(self.run_program_argsasarray(
|
|
210
|
+
lines = GeneralUtilities.string_to_lines(self.run_program_argsasarray(
|
|
211
|
+
"git", arguments_as_array, repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)[1], False)
|
|
191
212
|
for line in lines:
|
|
192
213
|
if GeneralUtilities.string_has_content(line):
|
|
193
214
|
return True
|
|
@@ -223,36 +244,43 @@ class ScriptCollectionCore:
|
|
|
223
244
|
|
|
224
245
|
@GeneralUtilities.check_arguments
|
|
225
246
|
def git_get_commit_id(self, repository_folder: str, commit: str = "HEAD") -> str:
|
|
226
|
-
result: tuple[int, str, str, int] = self.run_program_argsasarray(
|
|
247
|
+
result: tuple[int, str, str, int] = self.run_program_argsasarray(
|
|
248
|
+
"git", ["rev-parse", "--verify", commit], repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
227
249
|
return result[1].replace('\n', '')
|
|
228
250
|
|
|
229
251
|
@GeneralUtilities.check_arguments
|
|
230
252
|
def git_get_commit_date(self, repository_folder: str, commit: str = "HEAD") -> datetime:
|
|
231
|
-
result: tuple[int, str, str, int] = self.run_program_argsasarray(
|
|
253
|
+
result: tuple[int, str, str, int] = self.run_program_argsasarray(
|
|
254
|
+
"git", ["show", "-s", "--format=%ci", commit], repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
232
255
|
date_as_string = result[1].replace('\n', '')
|
|
233
256
|
result = datetime.strptime(date_as_string, '%Y-%m-%d %H:%M:%S %z')
|
|
234
257
|
return result
|
|
235
258
|
|
|
236
259
|
@GeneralUtilities.check_arguments
|
|
237
260
|
def git_fetch(self, folder: str, remotename: str = "--all") -> None:
|
|
238
|
-
self.run_program_argsasarray("git", ["fetch", remotename, "--tags", "--prune"],
|
|
261
|
+
self.run_program_argsasarray("git", ["fetch", remotename, "--tags", "--prune"],
|
|
262
|
+
folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
239
263
|
|
|
240
264
|
@GeneralUtilities.check_arguments
|
|
241
265
|
def git_fetch_in_bare_repository(self, folder: str, remotename, localbranch: str, remotebranch: str) -> None:
|
|
242
|
-
self.run_program_argsasarray("git", [
|
|
266
|
+
self.run_program_argsasarray("git", [
|
|
267
|
+
"fetch", remotename, f"{remotebranch}:{localbranch}"], folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
243
268
|
|
|
244
269
|
@GeneralUtilities.check_arguments
|
|
245
270
|
def git_remove_branch(self, folder: str, branchname: str) -> None:
|
|
246
|
-
self.run_program("git", f"branch -D {branchname}", folder,
|
|
271
|
+
self.run_program("git", f"branch -D {branchname}", folder,
|
|
272
|
+
throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
247
273
|
|
|
248
274
|
@GeneralUtilities.check_arguments
|
|
249
275
|
def git_push(self, folder: str, remotename: str, localbranchname: str, remotebranchname: str, forcepush: bool = False, pushalltags: bool = True, verbosity: int = 0) -> None:
|
|
250
|
-
argument = ["push", "--recurse-submodules=on-demand",
|
|
276
|
+
argument = ["push", "--recurse-submodules=on-demand",
|
|
277
|
+
remotename, f"{localbranchname}:{remotebranchname}"]
|
|
251
278
|
if (forcepush):
|
|
252
279
|
argument.append("--force")
|
|
253
280
|
if (pushalltags):
|
|
254
281
|
argument.append("--tags")
|
|
255
|
-
result: tuple[int, str, str, int] = self.run_program_argsasarray("git", argument, folder, throw_exception_if_exitcode_is_not_zero=True,
|
|
282
|
+
result: tuple[int, str, str, int] = self.run_program_argsasarray("git", argument, folder, throw_exception_if_exitcode_is_not_zero=True,
|
|
283
|
+
verbosity=verbosity, print_errors_as_information=True)
|
|
256
284
|
return result[1].replace('\r', '').replace('\n', '')
|
|
257
285
|
|
|
258
286
|
@GeneralUtilities.check_arguments
|
|
@@ -266,11 +294,13 @@ class ScriptCollectionCore:
|
|
|
266
294
|
args.append("--remote-submodules")
|
|
267
295
|
if mirror:
|
|
268
296
|
args.append("--mirror")
|
|
269
|
-
self.run_program_argsasarray("git", args, os.getcwd(
|
|
297
|
+
self.run_program_argsasarray("git", args, os.getcwd(
|
|
298
|
+
), throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
270
299
|
|
|
271
300
|
@GeneralUtilities.check_arguments
|
|
272
301
|
def git_get_all_remote_names(self, directory: str) -> list[str]:
|
|
273
|
-
result = GeneralUtilities.string_to_lines(self.run_program_argsasarray(
|
|
302
|
+
result = GeneralUtilities.string_to_lines(self.run_program_argsasarray(
|
|
303
|
+
"git", ["remote"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)[1], False)
|
|
274
304
|
return result
|
|
275
305
|
|
|
276
306
|
@GeneralUtilities.check_arguments
|
|
@@ -286,36 +316,45 @@ class ScriptCollectionCore:
|
|
|
286
316
|
@GeneralUtilities.check_arguments
|
|
287
317
|
def git_add_or_set_remote_address(self, directory: str, remote_name: str, remote_address: str) -> None:
|
|
288
318
|
if (self.repository_has_remote_with_specific_name(directory, remote_name)):
|
|
289
|
-
self.run_program_argsasarray("git", ['remote', 'set-url', 'remote_name', remote_address],
|
|
319
|
+
self.run_program_argsasarray("git", ['remote', 'set-url', 'remote_name', remote_address],
|
|
320
|
+
directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
290
321
|
else:
|
|
291
|
-
self.run_program_argsasarray("git", ['remote', 'add', remote_name, remote_address],
|
|
322
|
+
self.run_program_argsasarray("git", ['remote', 'add', remote_name, remote_address],
|
|
323
|
+
directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
292
324
|
|
|
293
325
|
@GeneralUtilities.check_arguments
|
|
294
326
|
def git_stage_all_changes(self, directory: str) -> None:
|
|
295
|
-
self.run_program_argsasarray("git", [
|
|
327
|
+
self.run_program_argsasarray("git", [
|
|
328
|
+
"add", "-A"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
296
329
|
|
|
297
330
|
@GeneralUtilities.check_arguments
|
|
298
331
|
def git_unstage_all_changes(self, directory: str) -> None:
|
|
299
|
-
self.run_program_argsasarray("git", [
|
|
332
|
+
self.run_program_argsasarray("git", [
|
|
333
|
+
"reset"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
300
334
|
|
|
301
335
|
@GeneralUtilities.check_arguments
|
|
302
336
|
def git_stage_file(self, directory: str, file: str) -> None:
|
|
303
|
-
self.run_program_argsasarray("git", [
|
|
337
|
+
self.run_program_argsasarray("git", [
|
|
338
|
+
'stage', file], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
304
339
|
|
|
305
340
|
@GeneralUtilities.check_arguments
|
|
306
341
|
def git_unstage_file(self, directory: str, file: str) -> None:
|
|
307
|
-
self.run_program_argsasarray("git", [
|
|
342
|
+
self.run_program_argsasarray("git", [
|
|
343
|
+
'reset', file], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
308
344
|
|
|
309
345
|
@GeneralUtilities.check_arguments
|
|
310
346
|
def git_discard_unstaged_changes_of_file(self, directory: str, file: str) -> None:
|
|
311
347
|
"""Caution: This method works really only for 'changed' files yet. So this method does not work properly for new or renamed files."""
|
|
312
|
-
self.run_program_argsasarray("git", [
|
|
348
|
+
self.run_program_argsasarray("git", [
|
|
349
|
+
'checkout', file], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
313
350
|
|
|
314
351
|
@GeneralUtilities.check_arguments
|
|
315
352
|
def git_discard_all_unstaged_changes(self, directory: str) -> None:
|
|
316
353
|
"""Caution: This function executes 'git clean -df'. This can delete files which maybe should not be deleted. Be aware of that."""
|
|
317
|
-
self.run_program_argsasarray("git", [
|
|
318
|
-
|
|
354
|
+
self.run_program_argsasarray("git", [
|
|
355
|
+
'clean', '-df'], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
356
|
+
self.run_program_argsasarray("git", [
|
|
357
|
+
'checkout', '.'], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
319
358
|
|
|
320
359
|
@GeneralUtilities.check_arguments
|
|
321
360
|
def git_commit(self, directory: str, message: str, author_name: str = None, author_email: str = None, stage_all_changes: bool = True,
|
|
@@ -328,7 +367,8 @@ class ScriptCollectionCore:
|
|
|
328
367
|
argument = ['commit', '--quiet', '--allow-empty', '--message', message]
|
|
329
368
|
if (GeneralUtilities.string_has_content(author_name)):
|
|
330
369
|
argument.append(f'--author="{author_name} <{author_email}>"')
|
|
331
|
-
git_repository_has_uncommitted_changes = self.git_repository_has_uncommitted_changes(
|
|
370
|
+
git_repository_has_uncommitted_changes = self.git_repository_has_uncommitted_changes(
|
|
371
|
+
directory)
|
|
332
372
|
|
|
333
373
|
if git_repository_has_uncommitted_changes:
|
|
334
374
|
do_commit = True
|
|
@@ -336,17 +376,22 @@ class ScriptCollectionCore:
|
|
|
336
376
|
self.git_stage_all_changes(directory)
|
|
337
377
|
else:
|
|
338
378
|
if no_changes_behavior == 0:
|
|
339
|
-
GeneralUtilities.write_message_to_stdout(
|
|
379
|
+
GeneralUtilities.write_message_to_stdout(
|
|
380
|
+
f"Commit '{message}' will not be done because there are no changes to commit in repository '{directory}'")
|
|
340
381
|
do_commit = False
|
|
341
382
|
if no_changes_behavior == 1:
|
|
342
|
-
GeneralUtilities.write_message_to_stdout(
|
|
383
|
+
GeneralUtilities.write_message_to_stdout(
|
|
384
|
+
f"There are no changes to commit in repository '{directory}'. Commit '{message}' will be done anyway.")
|
|
343
385
|
do_commit = True
|
|
344
386
|
if no_changes_behavior == 2:
|
|
345
|
-
raise RuntimeError(
|
|
387
|
+
raise RuntimeError(
|
|
388
|
+
f"There are no changes to commit in repository '{directory}'. Commit '{message}' will not be done.")
|
|
346
389
|
|
|
347
390
|
if do_commit:
|
|
348
|
-
GeneralUtilities.write_message_to_stdout(
|
|
349
|
-
|
|
391
|
+
GeneralUtilities.write_message_to_stdout(
|
|
392
|
+
f"Commit changes in '{directory}'")
|
|
393
|
+
self.run_program_argsasarray(
|
|
394
|
+
"git", argument, directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
350
395
|
|
|
351
396
|
return self.git_get_commit_id(directory)
|
|
352
397
|
|
|
@@ -357,20 +402,25 @@ class ScriptCollectionCore:
|
|
|
357
402
|
if message is None:
|
|
358
403
|
message = f"Created {target_for_tag}"
|
|
359
404
|
argument.extend(["-s", '-m', message])
|
|
360
|
-
self.run_program_argsasarray(
|
|
405
|
+
self.run_program_argsasarray(
|
|
406
|
+
"git", argument, directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
361
407
|
|
|
362
408
|
@GeneralUtilities.check_arguments
|
|
363
409
|
def git_delete_tag(self, directory: str, tag: str) -> None:
|
|
364
|
-
self.run_program_argsasarray("git", [
|
|
410
|
+
self.run_program_argsasarray("git", [
|
|
411
|
+
"tag", "--delete", tag], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
365
412
|
|
|
366
413
|
@GeneralUtilities.check_arguments
|
|
367
414
|
def git_checkout(self, directory: str, branch: str) -> None:
|
|
368
|
-
self.run_program_argsasarray("git", [
|
|
369
|
-
|
|
415
|
+
self.run_program_argsasarray("git", [
|
|
416
|
+
"checkout", branch], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
417
|
+
self.run_program_argsasarray("git", ["submodule", "update", "--recursive"],
|
|
418
|
+
directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
370
419
|
|
|
371
420
|
@GeneralUtilities.check_arguments
|
|
372
421
|
def git_merge_abort(self, directory: str) -> None:
|
|
373
|
-
self.run_program_argsasarray("git", [
|
|
422
|
+
self.run_program_argsasarray("git", [
|
|
423
|
+
"merge", "--abort"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
374
424
|
|
|
375
425
|
@GeneralUtilities.check_arguments
|
|
376
426
|
def git_merge(self, directory: str, sourcebranch: str, targetbranch: str, fastforward: bool = True, commit: bool = True, commit_message: str = None) -> str:
|
|
@@ -384,7 +434,8 @@ class ScriptCollectionCore:
|
|
|
384
434
|
args.append("-m")
|
|
385
435
|
args.append(commit_message)
|
|
386
436
|
args.append(sourcebranch)
|
|
387
|
-
self.run_program_argsasarray(
|
|
437
|
+
self.run_program_argsasarray(
|
|
438
|
+
"git", args, directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
388
439
|
return self.git_get_commit_id(directory)
|
|
389
440
|
|
|
390
441
|
@GeneralUtilities.check_arguments
|
|
@@ -405,7 +456,8 @@ class ScriptCollectionCore:
|
|
|
405
456
|
self.git_fetch(target_directory)
|
|
406
457
|
else:
|
|
407
458
|
# clone
|
|
408
|
-
self.git_clone(target_repository, source_repository,
|
|
459
|
+
self.git_clone(target_repository, source_repository,
|
|
460
|
+
include_submodules=True, mirror=True)
|
|
409
461
|
|
|
410
462
|
def get_git_submodules(self, folder: str) -> list[str]:
|
|
411
463
|
e = self.run_program("git", "submodule status", folder)
|
|
@@ -422,32 +474,39 @@ class ScriptCollectionCore:
|
|
|
422
474
|
|
|
423
475
|
@GeneralUtilities.check_arguments
|
|
424
476
|
def file_is_git_ignored(self, file_in_repository: str, repositorybasefolder: str) -> None:
|
|
425
|
-
exit_code = self.run_program_argsasarray(
|
|
477
|
+
exit_code = self.run_program_argsasarray(
|
|
478
|
+
"git", ['check-ignore', file_in_repository], repositorybasefolder, throw_exception_if_exitcode_is_not_zero=False, verbosity=0)[0]
|
|
426
479
|
if (exit_code == 0):
|
|
427
480
|
return True
|
|
428
481
|
if (exit_code == 1):
|
|
429
482
|
return False
|
|
430
|
-
raise ValueError(
|
|
483
|
+
raise ValueError(
|
|
484
|
+
f"Unable to calculate whether '{file_in_repository}' in repository '{repositorybasefolder}' is ignored due to git-exitcode {exit_code}.")
|
|
431
485
|
|
|
432
486
|
@GeneralUtilities.check_arguments
|
|
433
487
|
def git_discard_all_changes(self, repository: str) -> None:
|
|
434
|
-
self.run_program_argsasarray("git", [
|
|
435
|
-
|
|
488
|
+
self.run_program_argsasarray("git", [
|
|
489
|
+
"reset", "HEAD", "."], repository, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
490
|
+
self.run_program_argsasarray("git", [
|
|
491
|
+
"checkout", "."], repository, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
436
492
|
|
|
437
493
|
@GeneralUtilities.check_arguments
|
|
438
494
|
def git_get_current_branch_name(self, repository: str) -> str:
|
|
439
|
-
result = self.run_program_argsasarray(
|
|
495
|
+
result = self.run_program_argsasarray(
|
|
496
|
+
"git", ["rev-parse", "--abbrev-ref", "HEAD"], repository, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
440
497
|
return result[1].replace("\r", "").replace("\n", "")
|
|
441
498
|
|
|
442
499
|
@GeneralUtilities.check_arguments
|
|
443
500
|
def git_get_commitid_of_tag(self, repository: str, tag: str) -> str:
|
|
444
|
-
stdout = self.run_program_argsasarray(
|
|
501
|
+
stdout = self.run_program_argsasarray(
|
|
502
|
+
"git", ["rev-list", "-n", "1", tag], repository, verbosity=0)
|
|
445
503
|
result = stdout[1].replace("\r", "").replace("\n", "")
|
|
446
504
|
return result
|
|
447
505
|
|
|
448
506
|
@GeneralUtilities.check_arguments
|
|
449
507
|
def git_get_tags(self, repository: str) -> list[str]:
|
|
450
|
-
tags = [line.replace("\r", "") for line in self.run_program_argsasarray(
|
|
508
|
+
tags = [line.replace("\r", "") for line in self.run_program_argsasarray(
|
|
509
|
+
"git", ["tag"], repository)[1].split("\n") if len(line) > 0]
|
|
451
510
|
return tags
|
|
452
511
|
|
|
453
512
|
@GeneralUtilities.check_arguments
|
|
@@ -457,43 +516,53 @@ class ScriptCollectionCore:
|
|
|
457
516
|
counter = 0
|
|
458
517
|
for tag in tags:
|
|
459
518
|
counter = counter+1
|
|
460
|
-
GeneralUtilities.write_message_to_stdout(
|
|
461
|
-
|
|
519
|
+
GeneralUtilities.write_message_to_stdout(
|
|
520
|
+
f"Process tag {counter}/{tags_count}.")
|
|
521
|
+
# tag is on source-branch
|
|
522
|
+
if self.git_commit_is_ancestor(repository, tag, tag_source_branch):
|
|
462
523
|
commit_id_old = self.git_get_commitid_of_tag(repository, tag)
|
|
463
|
-
commit_date: datetime = self.git_get_commit_date(
|
|
524
|
+
commit_date: datetime = self.git_get_commit_date(
|
|
525
|
+
repository, commit_id_old)
|
|
464
526
|
date_as_string = self.__datetime_to_string_for_git(commit_date)
|
|
465
|
-
search_commit_result = self.run_program_argsasarray("git", ["log", f'--after="{date_as_string}"', f'--before="{date_as_string}"',
|
|
527
|
+
search_commit_result = self.run_program_argsasarray("git", ["log", f'--after="{date_as_string}"', f'--before="{date_as_string}"',
|
|
528
|
+
"--pretty=format:%H", tag_target_branch], repository, throw_exception_if_exitcode_is_not_zero=False)
|
|
466
529
|
if search_commit_result[0] != 0 or not GeneralUtilities.string_has_nonwhitespace_content(search_commit_result[1]):
|
|
467
|
-
raise ValueError(
|
|
530
|
+
raise ValueError(
|
|
531
|
+
f"Can not calculate corresponding commit for tag '{tag}'.")
|
|
468
532
|
commit_id_new = search_commit_result[1]
|
|
469
533
|
self.git_delete_tag(repository, tag)
|
|
470
|
-
self.git_create_tag(
|
|
534
|
+
self.git_create_tag(
|
|
535
|
+
repository, commit_id_new, tag, sign, message)
|
|
471
536
|
|
|
472
537
|
@GeneralUtilities.check_arguments
|
|
473
538
|
def get_current_git_branch_has_tag(self, repository_folder: str) -> bool:
|
|
474
|
-
result = self.run_program_argsasarray(
|
|
539
|
+
result = self.run_program_argsasarray(
|
|
540
|
+
"git", ["describe", "--tags", "--abbrev=0"], repository_folder, verbosity=0, throw_exception_if_exitcode_is_not_zero=False)
|
|
475
541
|
return result[0] == 0
|
|
476
542
|
|
|
477
543
|
@GeneralUtilities.check_arguments
|
|
478
544
|
def get_latest_git_tag(self, repository_folder: str) -> str:
|
|
479
|
-
result = self.run_program_argsasarray(
|
|
545
|
+
result = self.run_program_argsasarray(
|
|
546
|
+
"git", ["describe", "--tags", "--abbrev=0"], repository_folder, verbosity=0)
|
|
480
547
|
result = result[1].replace("\r", "").replace("\n", "")
|
|
481
548
|
return result
|
|
482
549
|
|
|
483
550
|
@GeneralUtilities.check_arguments
|
|
484
551
|
def get_staged_or_committed_git_ignored_files(self, repository_folder: str) -> list[str]:
|
|
485
|
-
tresult = self.run_program_argsasarray(
|
|
552
|
+
tresult = self.run_program_argsasarray(
|
|
553
|
+
"git", ["ls-files", "-i", "-c", "--exclude-standard"], repository_folder, verbosity=0)
|
|
486
554
|
tresult = tresult[1].replace("\r", "")
|
|
487
|
-
result=[line for line in tresult.split("\n") if len(line)>0]
|
|
555
|
+
result = [line for line in tresult.split("\n") if len(line) > 0]
|
|
488
556
|
return result
|
|
489
557
|
|
|
490
558
|
@GeneralUtilities.check_arguments
|
|
491
|
-
def git_repository_has_commits(self,repository_folder: str) -> bool:
|
|
492
|
-
return self.run_program_argsasarray("git",["rev-parse","--verify","HEAD"],repository_folder,throw_exception_if_exitcode_is_not_zero=False)[0]==0
|
|
559
|
+
def git_repository_has_commits(self, repository_folder: str) -> bool:
|
|
560
|
+
return self.run_program_argsasarray("git", ["rev-parse", "--verify", "HEAD"], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0] == 0
|
|
493
561
|
|
|
494
562
|
@GeneralUtilities.check_arguments
|
|
495
563
|
def export_filemetadata(self, folder: str, target_file: str, encoding: str = "utf-8", filter_function=None) -> None:
|
|
496
|
-
folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(
|
|
564
|
+
folder = GeneralUtilities.resolve_relative_path_from_current_working_directory(
|
|
565
|
+
folder)
|
|
497
566
|
lines = list()
|
|
498
567
|
path_prefix = len(folder)+1
|
|
499
568
|
items = dict()
|
|
@@ -504,10 +573,12 @@ class ScriptCollectionCore:
|
|
|
504
573
|
for file_or_folder, item_type in items.items():
|
|
505
574
|
truncated_file = file_or_folder[path_prefix:]
|
|
506
575
|
if (filter_function is None or filter_function(folder, truncated_file)):
|
|
507
|
-
owner_and_permisssion = self.get_file_owner_and_file_permission(
|
|
576
|
+
owner_and_permisssion = self.get_file_owner_and_file_permission(
|
|
577
|
+
file_or_folder)
|
|
508
578
|
user = owner_and_permisssion[0]
|
|
509
579
|
permissions = owner_and_permisssion[1]
|
|
510
|
-
lines.append(
|
|
580
|
+
lines.append(
|
|
581
|
+
f"{truncated_file};{item_type};{user};{permissions}")
|
|
511
582
|
lines = sorted(lines, key=str.casefold)
|
|
512
583
|
with open(target_file, "w", encoding=encoding) as file_object:
|
|
513
584
|
file_object.write("\n".join(lines))
|
|
@@ -527,12 +598,14 @@ class ScriptCollectionCore:
|
|
|
527
598
|
foldername = os.path.basename(subfolder)
|
|
528
599
|
if ".git" in foldername:
|
|
529
600
|
new_name = foldername.replace(".git", ".gitx")
|
|
530
|
-
subfolder2 = os.path.join(
|
|
601
|
+
subfolder2 = os.path.join(
|
|
602
|
+
str(Path(subfolder).parent), new_name)
|
|
531
603
|
os.rename(subfolder, subfolder2)
|
|
532
604
|
renamed_items[subfolder2] = subfolder
|
|
533
605
|
else:
|
|
534
606
|
subfolder2 = subfolder
|
|
535
|
-
self.__escape_git_repositories_in_folder_internal(
|
|
607
|
+
self.__escape_git_repositories_in_folder_internal(
|
|
608
|
+
subfolder2, renamed_items)
|
|
536
609
|
return renamed_items
|
|
537
610
|
|
|
538
611
|
def deescape_git_repositories_in_folder(self, renamed_items: dict[str, str]):
|
|
@@ -554,14 +627,17 @@ class ScriptCollectionCore:
|
|
|
554
627
|
lines.sort(key=self.__sort_fmd)
|
|
555
628
|
for line in lines:
|
|
556
629
|
splitted: list = line.split(";")
|
|
557
|
-
full_path_of_file_or_folder: str = os.path.join(
|
|
630
|
+
full_path_of_file_or_folder: str = os.path.join(
|
|
631
|
+
folder, splitted[0])
|
|
558
632
|
filetype: str = splitted[1]
|
|
559
633
|
user: str = splitted[2]
|
|
560
634
|
permissions: str = splitted[3]
|
|
561
635
|
if filetype == "d" and create_folder_is_not_exist and not os.path.isdir(full_path_of_file_or_folder):
|
|
562
|
-
GeneralUtilities.ensure_directory_exists(
|
|
636
|
+
GeneralUtilities.ensure_directory_exists(
|
|
637
|
+
full_path_of_file_or_folder)
|
|
563
638
|
if (filetype == "f" and os.path.isfile(full_path_of_file_or_folder)) or (filetype == "d" and os.path.isdir(full_path_of_file_or_folder)):
|
|
564
|
-
self.set_owner(full_path_of_file_or_folder,
|
|
639
|
+
self.set_owner(full_path_of_file_or_folder,
|
|
640
|
+
user, os.name != 'nt')
|
|
565
641
|
self.set_permission(full_path_of_file_or_folder, permissions)
|
|
566
642
|
else:
|
|
567
643
|
if strict:
|
|
@@ -569,27 +645,34 @@ class ScriptCollectionCore:
|
|
|
569
645
|
filetype_full = "File"
|
|
570
646
|
if filetype == "d":
|
|
571
647
|
filetype_full = "Directory"
|
|
572
|
-
raise ValueError(
|
|
648
|
+
raise ValueError(
|
|
649
|
+
f"{filetype_full} '{full_path_of_file_or_folder}' does not exist")
|
|
573
650
|
|
|
574
651
|
@GeneralUtilities.check_arguments
|
|
575
652
|
def __calculate_lengh_in_seconds(self, filename: str, folder: str) -> float:
|
|
576
|
-
argument = ['-v', 'error', '-show_entries', 'format=duration',
|
|
577
|
-
|
|
653
|
+
argument = ['-v', 'error', '-show_entries', 'format=duration',
|
|
654
|
+
'-of', 'default=noprint_wrappers=1:nokey=1', filename]
|
|
655
|
+
result = self.run_program_argsasarray(
|
|
656
|
+
"ffprobe", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
|
578
657
|
return float(result[1].replace('\n', ''))
|
|
579
658
|
|
|
580
659
|
@GeneralUtilities.check_arguments
|
|
581
660
|
def __create_thumbnails(self, filename: str, fps: str, folder: str, tempname_for_thumbnails: str) -> None:
|
|
582
|
-
argument = ['-i', filename, '-r', str(fps), '-vf', 'scale=-1:120',
|
|
583
|
-
|
|
661
|
+
argument = ['-i', filename, '-r', str(fps), '-vf', 'scale=-1:120',
|
|
662
|
+
'-vcodec', 'png', f'{tempname_for_thumbnails}-%002d.png']
|
|
663
|
+
self.run_program_argsasarray(
|
|
664
|
+
"ffmpeg", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
|
584
665
|
|
|
585
666
|
@GeneralUtilities.check_arguments
|
|
586
667
|
def __create_thumbnail(self, outputfilename: str, folder: str, length_in_seconds: float, tempname_for_thumbnails: str, amount_of_images: int) -> None:
|
|
587
668
|
duration = timedelta(seconds=length_in_seconds)
|
|
588
669
|
info = GeneralUtilities.timedelta_to_simple_string(duration)
|
|
589
|
-
next_square_number = str(
|
|
670
|
+
next_square_number = str(
|
|
671
|
+
int(math.sqrt(GeneralUtilities.get_next_square_number(amount_of_images))))
|
|
590
672
|
argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{next_square_number}x{next_square_number}',
|
|
591
673
|
f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
|
|
592
|
-
self.run_program_argsasarray(
|
|
674
|
+
self.run_program_argsasarray(
|
|
675
|
+
"montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
|
|
593
676
|
|
|
594
677
|
@GeneralUtilities.check_arguments
|
|
595
678
|
def roundup(self, x: float, places: int) -> int:
|
|
@@ -604,13 +687,15 @@ class ScriptCollectionCore:
|
|
|
604
687
|
if tempname_for_thumbnails is None:
|
|
605
688
|
tempname_for_thumbnails = "t"+str(uuid.uuid4())
|
|
606
689
|
|
|
607
|
-
file = GeneralUtilities.resolve_relative_path_from_current_working_directory(
|
|
690
|
+
file = GeneralUtilities.resolve_relative_path_from_current_working_directory(
|
|
691
|
+
file)
|
|
608
692
|
filename = os.path.basename(file)
|
|
609
693
|
folder = os.path.dirname(file)
|
|
610
694
|
filename_without_extension = Path(file).stem
|
|
611
695
|
|
|
612
696
|
try:
|
|
613
|
-
length_in_seconds = self.__calculate_lengh_in_seconds(
|
|
697
|
+
length_in_seconds = self.__calculate_lengh_in_seconds(
|
|
698
|
+
filename, folder)
|
|
614
699
|
if (frames_per_second.endswith("fps")):
|
|
615
700
|
# frames per second, example: frames_per_second="20fps" => 20 frames per second
|
|
616
701
|
x = self.roundup(float(frames_per_second[:-3]), 2)
|
|
@@ -619,9 +704,12 @@ class ScriptCollectionCore:
|
|
|
619
704
|
else:
|
|
620
705
|
# concrete amount of frame, examples: frames_per_second="16" => 16 frames for entire video
|
|
621
706
|
amounf_of_previewframes = int(float(frames_per_second))
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
self.
|
|
707
|
+
# self.roundup((amounf_of_previewframes-2)/length_in_seconds, 2)
|
|
708
|
+
frames_per_secondx = f"{amounf_of_previewframes-2}/{length_in_seconds}"
|
|
709
|
+
self.__create_thumbnails(
|
|
710
|
+
filename, frames_per_secondx, folder, tempname_for_thumbnails)
|
|
711
|
+
self.__create_thumbnail(filename_without_extension, folder,
|
|
712
|
+
length_in_seconds, tempname_for_thumbnails, amounf_of_previewframes)
|
|
625
713
|
finally:
|
|
626
714
|
for thumbnail_to_delete in Path(folder).rglob(tempname_for_thumbnails+"-*"):
|
|
627
715
|
file = str(thumbnail_to_delete)
|
|
@@ -701,13 +789,16 @@ class ScriptCollectionCore:
|
|
|
701
789
|
|
|
702
790
|
@GeneralUtilities.check_arguments
|
|
703
791
|
def SCCreateSimpleMergeWithoutRelease(self, repository: str, sourcebranch: str, targetbranch: str, remotename: str, remove_source_branch: bool) -> None:
|
|
704
|
-
commitid = self.git_merge(
|
|
792
|
+
commitid = self.git_merge(
|
|
793
|
+
repository, sourcebranch, targetbranch, False, True)
|
|
705
794
|
self.git_merge(repository, targetbranch, sourcebranch, True, True)
|
|
706
795
|
created_version = self.get_semver_version_from_gitversion(repository)
|
|
707
796
|
self.git_create_tag(repository, commitid, f"v{created_version}", True)
|
|
708
|
-
self.git_push(repository, remotename, targetbranch,
|
|
797
|
+
self.git_push(repository, remotename, targetbranch,
|
|
798
|
+
targetbranch, False, True)
|
|
709
799
|
if (GeneralUtilities.string_has_nonwhitespace_content(remotename)):
|
|
710
|
-
self.git_push(repository, remotename, sourcebranch,
|
|
800
|
+
self.git_push(repository, remotename, sourcebranch,
|
|
801
|
+
sourcebranch, False, True)
|
|
711
802
|
if (remove_source_branch):
|
|
712
803
|
self.git_remove_branch(repository, sourcebranch)
|
|
713
804
|
|
|
@@ -739,7 +830,8 @@ class ScriptCollectionCore:
|
|
|
739
830
|
|
|
740
831
|
# sort lines if desired
|
|
741
832
|
if sort:
|
|
742
|
-
lines = sorted(lines, key=lambda singleline: self.__adapt_line_for_sorting(
|
|
833
|
+
lines = sorted(lines, key=lambda singleline: self.__adapt_line_for_sorting(
|
|
834
|
+
singleline, ignored_start_character))
|
|
743
835
|
|
|
744
836
|
# reinsert first line
|
|
745
837
|
if ignore_first_line:
|
|
@@ -750,7 +842,8 @@ class ScriptCollectionCore:
|
|
|
750
842
|
|
|
751
843
|
return 0
|
|
752
844
|
else:
|
|
753
|
-
GeneralUtilities.write_message_to_stdout(
|
|
845
|
+
GeneralUtilities.write_message_to_stdout(
|
|
846
|
+
f"File '{file}' does not exist")
|
|
754
847
|
return 1
|
|
755
848
|
|
|
756
849
|
@GeneralUtilities.check_arguments
|
|
@@ -779,7 +872,8 @@ class ScriptCollectionCore:
|
|
|
779
872
|
|
|
780
873
|
@GeneralUtilities.check_arguments
|
|
781
874
|
def __process_file(self, file: str, substringInFilename: str, newSubstringInFilename: str, conflictResolveMode: str) -> None:
|
|
782
|
-
new_filename = os.path.join(os.path.dirname(file), os.path.basename(
|
|
875
|
+
new_filename = os.path.join(os.path.dirname(file), os.path.basename(
|
|
876
|
+
file).replace(substringInFilename, newSubstringInFilename))
|
|
783
877
|
if file != new_filename:
|
|
784
878
|
if os.path.isfile(new_filename):
|
|
785
879
|
if filecmp.cmp(file, new_filename):
|
|
@@ -804,12 +898,14 @@ class ScriptCollectionCore:
|
|
|
804
898
|
@GeneralUtilities.check_arguments
|
|
805
899
|
def SCReplaceSubstringsInFilenames(self, folder: str, substringInFilename: str, newSubstringInFilename: str, conflictResolveMode: str) -> None:
|
|
806
900
|
for file in GeneralUtilities.absolute_file_paths(folder):
|
|
807
|
-
self.__process_file(file, substringInFilename,
|
|
901
|
+
self.__process_file(file, substringInFilename,
|
|
902
|
+
newSubstringInFilename, conflictResolveMode)
|
|
808
903
|
|
|
809
904
|
@GeneralUtilities.check_arguments
|
|
810
905
|
def __check_file(self, file: str, searchstring: str) -> None:
|
|
811
906
|
bytes_ascii = bytes(searchstring, "ascii")
|
|
812
|
-
|
|
907
|
+
# often called "unicode-encoding"
|
|
908
|
+
bytes_utf16 = bytes(searchstring, "utf-16")
|
|
813
909
|
bytes_utf8 = bytes(searchstring, "utf-8")
|
|
814
910
|
with open(file, mode='rb') as file_object:
|
|
815
911
|
content = file_object.read()
|
|
@@ -828,7 +924,8 @@ class ScriptCollectionCore:
|
|
|
828
924
|
@GeneralUtilities.check_arguments
|
|
829
925
|
def __print_qr_code_by_csv_line(self, displayname: str, website: str, emailaddress: str, key: str, period: str) -> None:
|
|
830
926
|
qrcode_content = f"otpauth://totp/{website}:{emailaddress}?secret={key}&issuer={displayname}&period={period}"
|
|
831
|
-
GeneralUtilities.write_message_to_stdout(
|
|
927
|
+
GeneralUtilities.write_message_to_stdout(
|
|
928
|
+
f"{displayname} ({emailaddress}):")
|
|
832
929
|
GeneralUtilities.write_message_to_stdout(qrcode_content)
|
|
833
930
|
qr = qrcode.QRCode()
|
|
834
931
|
qr.add_data(qrcode_content)
|
|
@@ -844,29 +941,35 @@ class ScriptCollectionCore:
|
|
|
844
941
|
lines.sort(key=lambda items: ''.join(items).lower())
|
|
845
942
|
for line in lines:
|
|
846
943
|
GeneralUtilities.write_message_to_stdout(separator_line)
|
|
847
|
-
self.__print_qr_code_by_csv_line(
|
|
944
|
+
self.__print_qr_code_by_csv_line(
|
|
945
|
+
line[0], line[1], line[2], line[3], line[4])
|
|
848
946
|
GeneralUtilities.write_message_to_stdout(separator_line)
|
|
849
947
|
|
|
850
948
|
@GeneralUtilities.check_arguments
|
|
851
949
|
def SCUploadFileToFileHost(self, file: str, host: str) -> int:
|
|
852
950
|
try:
|
|
853
|
-
GeneralUtilities.write_message_to_stdout(
|
|
951
|
+
GeneralUtilities.write_message_to_stdout(
|
|
952
|
+
self.upload_file_to_file_host(file, host))
|
|
854
953
|
return 0
|
|
855
954
|
except Exception as exception:
|
|
856
|
-
GeneralUtilities.write_exception_to_stderr_with_traceback(
|
|
955
|
+
GeneralUtilities.write_exception_to_stderr_with_traceback(
|
|
956
|
+
exception, traceback)
|
|
857
957
|
return 1
|
|
858
958
|
|
|
859
959
|
@GeneralUtilities.check_arguments
|
|
860
960
|
def SCFileIsAvailableOnFileHost(self, file: str) -> int:
|
|
861
961
|
try:
|
|
862
962
|
if self.file_is_available_on_file_host(file):
|
|
863
|
-
GeneralUtilities.write_message_to_stdout(
|
|
963
|
+
GeneralUtilities.write_message_to_stdout(
|
|
964
|
+
f"'{file}' is available")
|
|
864
965
|
return 0
|
|
865
966
|
else:
|
|
866
|
-
GeneralUtilities.write_message_to_stdout(
|
|
967
|
+
GeneralUtilities.write_message_to_stdout(
|
|
968
|
+
f"'{file}' is not available")
|
|
867
969
|
return 1
|
|
868
970
|
except Exception as exception:
|
|
869
|
-
GeneralUtilities.write_exception_to_stderr_with_traceback(
|
|
971
|
+
GeneralUtilities.write_exception_to_stderr_with_traceback(
|
|
972
|
+
exception, traceback)
|
|
870
973
|
return 2
|
|
871
974
|
|
|
872
975
|
@GeneralUtilities.check_arguments
|
|
@@ -878,7 +981,8 @@ class ScriptCollectionCore:
|
|
|
878
981
|
# timestamp: "51eb505a"
|
|
879
982
|
# target: "c1910018"
|
|
880
983
|
# nonce: "de19b302"
|
|
881
|
-
header = str(block_version_number + previousblockhash +
|
|
984
|
+
header = str(block_version_number + previousblockhash +
|
|
985
|
+
transactionsmerkleroot + timestamp + target + nonce)
|
|
882
986
|
return binascii.hexlify(hashlib.sha256(hashlib.sha256(binascii.unhexlify(header)).digest()).digest()[::-1]).decode('utf-8')
|
|
883
987
|
|
|
884
988
|
@GeneralUtilities.check_arguments
|
|
@@ -918,11 +1022,14 @@ class ScriptCollectionCore:
|
|
|
918
1022
|
full_path = os.path.join(root, file)
|
|
919
1023
|
with (open(full_path, "rb").read()) as text_io_wrapper:
|
|
920
1024
|
content = text_io_wrapper
|
|
921
|
-
path_in_iso = '/' + files_directory +
|
|
1025
|
+
path_in_iso = '/' + files_directory + \
|
|
1026
|
+
self.__adjust_folder_name(
|
|
1027
|
+
full_path[len(folder)::1]).upper()
|
|
922
1028
|
if path_in_iso not in created_directories:
|
|
923
1029
|
iso.add_directory(path_in_iso)
|
|
924
1030
|
created_directories.append(path_in_iso)
|
|
925
|
-
iso.add_fp(BytesIO(content), len(content),
|
|
1031
|
+
iso.add_fp(BytesIO(content), len(content),
|
|
1032
|
+
path_in_iso + '/' + file.upper() + ';1')
|
|
926
1033
|
iso.write(iso_file)
|
|
927
1034
|
iso.close()
|
|
928
1035
|
|
|
@@ -932,8 +1039,10 @@ class ScriptCollectionCore:
|
|
|
932
1039
|
namemappingfile = "name_map.csv"
|
|
933
1040
|
files_directory = inputfolder
|
|
934
1041
|
files_directory_obf = f"{files_directory}_Obfuscated"
|
|
935
|
-
self.SCObfuscateFilesFolder(
|
|
936
|
-
|
|
1042
|
+
self.SCObfuscateFilesFolder(
|
|
1043
|
+
inputfolder, printtableheadline, namemappingfile, extensions)
|
|
1044
|
+
os.rename(namemappingfile, os.path.join(
|
|
1045
|
+
files_directory_obf, namemappingfile))
|
|
937
1046
|
if createisofile:
|
|
938
1047
|
self.__create_iso(files_directory_obf, outputfile)
|
|
939
1048
|
shutil.rmtree(files_directory_obf)
|
|
@@ -947,13 +1056,15 @@ class ScriptCollectionCore:
|
|
|
947
1056
|
obfuscate_file_extensions = extensions.split(",")
|
|
948
1057
|
|
|
949
1058
|
if (os.path.isdir(inputfolder)):
|
|
950
|
-
printtableheadline = GeneralUtilities.string_to_boolean(
|
|
1059
|
+
printtableheadline = GeneralUtilities.string_to_boolean(
|
|
1060
|
+
printtableheadline)
|
|
951
1061
|
files = []
|
|
952
1062
|
if not os.path.isfile(namemappingfile):
|
|
953
1063
|
with open(namemappingfile, "a", encoding="utf-8"):
|
|
954
1064
|
pass
|
|
955
1065
|
if printtableheadline:
|
|
956
|
-
GeneralUtilities.append_line_to_file(
|
|
1066
|
+
GeneralUtilities.append_line_to_file(
|
|
1067
|
+
namemappingfile, "Original filename;new filename;SHA2-hash of file")
|
|
957
1068
|
for file in GeneralUtilities.absolute_file_paths(inputfolder):
|
|
958
1069
|
if os.path.isfile(os.path.join(inputfolder, file)):
|
|
959
1070
|
if obfuscate_all_files or self.__extension_matchs(file, obfuscate_file_extensions):
|
|
@@ -962,9 +1073,11 @@ class ScriptCollectionCore:
|
|
|
962
1073
|
hash_value = GeneralUtilities.get_sha256_of_file(file)
|
|
963
1074
|
extension = Path(file).suffix
|
|
964
1075
|
new_file_name_without_path = str(uuid.uuid4())[0:8] + extension
|
|
965
|
-
new_file_name = os.path.join(
|
|
1076
|
+
new_file_name = os.path.join(
|
|
1077
|
+
os.path.dirname(file), new_file_name_without_path)
|
|
966
1078
|
os.rename(file, new_file_name)
|
|
967
|
-
GeneralUtilities.append_line_to_file(namemappingfile, os.path.basename(
|
|
1079
|
+
GeneralUtilities.append_line_to_file(namemappingfile, os.path.basename(
|
|
1080
|
+
file) + ";" + new_file_name_without_path + ";" + hash_value)
|
|
968
1081
|
else:
|
|
969
1082
|
raise ValueError(f"Directory not found: '{inputfolder}'")
|
|
970
1083
|
|
|
@@ -981,12 +1094,15 @@ class ScriptCollectionCore:
|
|
|
981
1094
|
for line in reversed(lines):
|
|
982
1095
|
if not GeneralUtilities.string_is_none_or_whitespace(line):
|
|
983
1096
|
if "RunningHealthy (" in line: # TODO use regex
|
|
984
|
-
GeneralUtilities.write_message_to_stderr(
|
|
1097
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1098
|
+
f"Healthy running due to line '{line}' in file '{file}'.")
|
|
985
1099
|
return 0
|
|
986
1100
|
else:
|
|
987
|
-
GeneralUtilities.write_message_to_stderr(
|
|
1101
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1102
|
+
f"Not healthy running due to line '{line}' in file '{file}'.")
|
|
988
1103
|
return 1
|
|
989
|
-
GeneralUtilities.write_message_to_stderr(
|
|
1104
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1105
|
+
f"No valid line found for healthycheck in file '{file}'.")
|
|
990
1106
|
return 2
|
|
991
1107
|
|
|
992
1108
|
@GeneralUtilities.check_arguments
|
|
@@ -1006,7 +1122,8 @@ class ScriptCollectionCore:
|
|
|
1006
1122
|
self.SCChangeHashOfProgram(file)
|
|
1007
1123
|
os.remove(file)
|
|
1008
1124
|
os.rename(file + ".modified", file)
|
|
1009
|
-
self.SCFilenameObfuscator(
|
|
1125
|
+
self.SCFilenameObfuscator(
|
|
1126
|
+
inputfolder, printtableheadline, namemappingfile, extensions)
|
|
1010
1127
|
else:
|
|
1011
1128
|
raise ValueError(f"Directory not found: '{inputfolder}'")
|
|
1012
1129
|
|
|
@@ -1022,10 +1139,13 @@ class ScriptCollectionCore:
|
|
|
1022
1139
|
package_url: str = f"https://deb.torproject.org/torproject.org/dists/{debian_version}/main/binary-amd64/Packages"
|
|
1023
1140
|
r = requests.get(package_url, timeout=5)
|
|
1024
1141
|
if r.status_code != 200:
|
|
1025
|
-
raise ValueError(
|
|
1026
|
-
|
|
1142
|
+
raise ValueError(
|
|
1143
|
+
f"Checking for latest tor package resulted in HTTP-response-code {r.status_code}.")
|
|
1144
|
+
lines = GeneralUtilities.string_to_lines(
|
|
1145
|
+
GeneralUtilities.bytes_to_string(r.content))
|
|
1027
1146
|
version_line_prefix = "Version: "
|
|
1028
|
-
version_content_line = [
|
|
1147
|
+
version_content_line = [
|
|
1148
|
+
line for line in lines if line.startswith(version_line_prefix)][1]
|
|
1029
1149
|
version_with_overhead = version_content_line[len(version_line_prefix):]
|
|
1030
1150
|
tor_version = version_with_overhead.split("~")[0]
|
|
1031
1151
|
return tor_version
|
|
@@ -1071,10 +1191,13 @@ class ScriptCollectionCore:
|
|
|
1071
1191
|
def run_testcases_for_python_project(self, repository_folder: str):
|
|
1072
1192
|
self.run_program("coverage", "run -m pytest", repository_folder)
|
|
1073
1193
|
self.run_program("coverage", "xml", repository_folder)
|
|
1074
|
-
GeneralUtilities.ensure_directory_exists(
|
|
1075
|
-
|
|
1194
|
+
GeneralUtilities.ensure_directory_exists(
|
|
1195
|
+
os.path.join(repository_folder, "Other/TestCoverage"))
|
|
1196
|
+
coveragefile = os.path.join(
|
|
1197
|
+
repository_folder, "Other/TestCoverage/TestCoverage.xml")
|
|
1076
1198
|
GeneralUtilities.ensure_file_does_not_exist(coveragefile)
|
|
1077
|
-
os.rename(os.path.join(repository_folder,
|
|
1199
|
+
os.rename(os.path.join(repository_folder,
|
|
1200
|
+
"coverage.xml"), coveragefile)
|
|
1078
1201
|
|
|
1079
1202
|
@GeneralUtilities.check_arguments
|
|
1080
1203
|
def get_file_permission(self, file: str) -> str:
|
|
@@ -1110,7 +1233,8 @@ class ScriptCollectionCore:
|
|
|
1110
1233
|
splitted = ' '.join(ls_output.split()).split(' ')
|
|
1111
1234
|
return f"{splitted[2]}:{splitted[3]}"
|
|
1112
1235
|
except Exception as exception:
|
|
1113
|
-
raise ValueError(
|
|
1236
|
+
raise ValueError(
|
|
1237
|
+
f"ls-output '{ls_output}' not parsable") from exception
|
|
1114
1238
|
|
|
1115
1239
|
@GeneralUtilities.check_arguments
|
|
1116
1240
|
def get_file_owner_and_file_permission(self, file: str) -> str:
|
|
@@ -1120,10 +1244,13 @@ class ScriptCollectionCore:
|
|
|
1120
1244
|
@GeneralUtilities.check_arguments
|
|
1121
1245
|
def __ls(self, file: str) -> str:
|
|
1122
1246
|
file = file.replace("\\", "/")
|
|
1123
|
-
GeneralUtilities.assert_condition(os.path.isfile(file) or os.path.isdir(
|
|
1247
|
+
GeneralUtilities.assert_condition(os.path.isfile(file) or os.path.isdir(
|
|
1248
|
+
file), f"Can not execute 'ls' because '{file}' does not exist")
|
|
1124
1249
|
result = self.run_program_argsasarray("ls", ["-ld", file])
|
|
1125
|
-
GeneralUtilities.assert_condition(
|
|
1126
|
-
|
|
1250
|
+
GeneralUtilities.assert_condition(
|
|
1251
|
+
result[0] == 0, f"'ls -ld {file}' resulted in exitcode {str(result[0])}. StdErr: {result[2]}")
|
|
1252
|
+
GeneralUtilities.assert_condition(not GeneralUtilities.string_is_none_or_whitespace(
|
|
1253
|
+
result[1]), f"'ls' of '{file}' had an empty output. StdErr: '{result[2]}'")
|
|
1127
1254
|
return result[1]
|
|
1128
1255
|
|
|
1129
1256
|
@GeneralUtilities.check_arguments
|
|
@@ -1151,7 +1278,7 @@ class ScriptCollectionCore:
|
|
|
1151
1278
|
# <run programs>
|
|
1152
1279
|
|
|
1153
1280
|
@GeneralUtilities.check_arguments
|
|
1154
|
-
def __run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, custom_argument: object = None) -> Popen:
|
|
1281
|
+
def __run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, custom_argument: object = None, interactive: bool = False) -> Popen:
|
|
1155
1282
|
# Verbosity:
|
|
1156
1283
|
# 0=Quiet (No output will be printed.)
|
|
1157
1284
|
# 1=Normal (If the exitcode of the executed program is not 0 then the StdErr will be printed.)
|
|
@@ -1174,16 +1301,24 @@ class ScriptCollectionCore:
|
|
|
1174
1301
|
GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
|
|
1175
1302
|
|
|
1176
1303
|
if isinstance(self.program_runner, ProgramRunnerEpew):
|
|
1177
|
-
custom_argument = CustomEpewArgument(
|
|
1178
|
-
|
|
1304
|
+
custom_argument = CustomEpewArgument(
|
|
1305
|
+
print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, verbosity, arguments_for_log)
|
|
1306
|
+
popen: Popen = self.program_runner.run_program_argsasarray_async_helper(
|
|
1307
|
+
program, arguments_as_array, working_directory, custom_argument, interactive)
|
|
1179
1308
|
return popen
|
|
1180
1309
|
|
|
1181
1310
|
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
1182
1311
|
|
|
1183
1312
|
@GeneralUtilities.check_arguments
|
|
1184
|
-
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
1313
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
1314
|
+
# verbosity 1: No output will be logged.
|
|
1315
|
+
# verbosity 2: If the exitcode of the executed program is not 0 then the StdErr will be logged. This is supposed to be the default verbosity-level.
|
|
1316
|
+
# verbosity 3: Logs and prints StdOut and StdErr of the executed program in realtime.
|
|
1317
|
+
# verbosity 4: Same as loglevel 3 but with some more overhead-information.
|
|
1185
1318
|
try:
|
|
1186
|
-
|
|
1319
|
+
arguments_as_str = ' '.join(arguments_as_array)
|
|
1320
|
+
mock_loader_result = self.__try_load_mock(
|
|
1321
|
+
program, arguments_as_str, working_directory)
|
|
1187
1322
|
if mock_loader_result[0]:
|
|
1188
1323
|
return mock_loader_result[1]
|
|
1189
1324
|
|
|
@@ -1192,83 +1327,137 @@ class ScriptCollectionCore:
|
|
|
1192
1327
|
|
|
1193
1328
|
arguments_for_exception_as_string = ' '.join(arguments_for_log)
|
|
1194
1329
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
stdout_lines=list[str]()
|
|
1199
|
-
stderr_lines=list[str]()
|
|
1200
|
-
|
|
1201
|
-
live_console_output_printing=1<verbosity
|
|
1202
|
-
|
|
1203
|
-
log_to_file=log_file is not None
|
|
1204
|
-
if log_to_file:
|
|
1205
|
-
GeneralUtilities.ensure_file_exists(log_file)
|
|
1206
|
-
def stream_process(process):
|
|
1207
|
-
try:
|
|
1208
|
-
|
|
1209
|
-
go = process.poll() is None
|
|
1210
|
-
for line in process.stdout:
|
|
1211
|
-
line_str=GeneralUtilities.bytes_to_string(line).strip().replace('\r', '').replace('\n', '')
|
|
1212
|
-
stdout_lines.append(line_str)
|
|
1213
|
-
if live_console_output_printing:
|
|
1214
|
-
GeneralUtilities.write_message_to_stdout(line_str)
|
|
1215
|
-
if log_to_file:
|
|
1216
|
-
GeneralUtilities.append_line_to_file(log_file, line_str)
|
|
1217
|
-
for line in process.stderr:
|
|
1218
|
-
line_str=GeneralUtilities.bytes_to_string(line).strip().replace('\r', '').replace('\n', '')
|
|
1219
|
-
stderr_lines.append(line_str)
|
|
1220
|
-
if live_console_output_printing:
|
|
1221
|
-
if print_errors_as_information:
|
|
1222
|
-
GeneralUtilities.write_message_to_stdout(line_str)
|
|
1223
|
-
else:
|
|
1224
|
-
GeneralUtilities.write_message_to_stderr(line_str)
|
|
1225
|
-
if log_to_file:
|
|
1226
|
-
GeneralUtilities.append_line_to_file(log_file, line_str)
|
|
1227
|
-
return go
|
|
1228
|
-
except Exception:
|
|
1229
|
-
return None
|
|
1230
|
-
while stream_process(process):
|
|
1231
|
-
time.sleep(0.1)
|
|
1232
|
-
|
|
1233
|
-
exit_code = process.poll()
|
|
1234
|
-
stdout = '\n'.join(stdout_lines)
|
|
1235
|
-
stderr = '\n'.join(stderr_lines)
|
|
1236
|
-
|
|
1237
|
-
if arguments_for_exception_as_string is None:
|
|
1238
|
-
arguments_for_exception_as_string = ' '.join(arguments_as_array)
|
|
1239
|
-
else:
|
|
1240
|
-
arguments_for_exception_as_string = ' '.join(arguments_for_log)
|
|
1330
|
+
arguments_for_log_as_string = ' '.join(arguments_for_log)
|
|
1331
|
+
cmd = f'{working_directory}>{program} {arguments_for_log_as_string}'
|
|
1241
1332
|
|
|
1333
|
+
if GeneralUtilities.string_is_none_or_whitespace(title):
|
|
1334
|
+
info_for_log = cmd
|
|
1335
|
+
else:
|
|
1336
|
+
info_for_log = title
|
|
1337
|
+
|
|
1338
|
+
if verbosity >= 3:
|
|
1339
|
+
GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
|
|
1340
|
+
|
|
1341
|
+
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:
|
|
1342
|
+
pid = process.pid
|
|
1343
|
+
|
|
1344
|
+
stdout_lines = list[str]()
|
|
1345
|
+
stderr_lines = list[str]()
|
|
1346
|
+
|
|
1347
|
+
live_console_output_printing = 2 < verbosity and interactive
|
|
1348
|
+
|
|
1349
|
+
log_to_file = log_file is not None
|
|
1350
|
+
if log_to_file:
|
|
1351
|
+
GeneralUtilities.ensure_file_exists(log_file)
|
|
1352
|
+
|
|
1353
|
+
if interactive:
|
|
1354
|
+
# there are 2 issues in this part:
|
|
1355
|
+
# 1.: ctrl+c
|
|
1356
|
+
# 2.: sometimes this function does not terminate even if the started process exited
|
|
1357
|
+
def stream_process(process) -> bool:
|
|
1358
|
+
try:
|
|
1359
|
+
go: bool = process.poll() is None
|
|
1360
|
+
|
|
1361
|
+
stdoutreader: BufferedReader = process.stdout
|
|
1362
|
+
if stdoutreader.readable():
|
|
1363
|
+
stdoutresultb: bytes = stdoutreader.read()
|
|
1364
|
+
stdoutresult = GeneralUtilities.bytes_to_string(
|
|
1365
|
+
stdoutresultb)
|
|
1366
|
+
stdoutlines = GeneralUtilities.string_to_lines(
|
|
1367
|
+
stdoutresult)
|
|
1368
|
+
for line in stdoutlines:
|
|
1369
|
+
line_stripped = line.replace(
|
|
1370
|
+
"\r", "").strip()
|
|
1371
|
+
if len(line_stripped) > 0:
|
|
1372
|
+
line_str = line_stripped
|
|
1373
|
+
stdout_lines.append(line_str)
|
|
1374
|
+
if live_console_output_printing:
|
|
1375
|
+
GeneralUtilities.write_message_to_stdout(
|
|
1376
|
+
line_str)
|
|
1377
|
+
if log_to_file:
|
|
1378
|
+
GeneralUtilities.append_line_to_file(
|
|
1379
|
+
log_file, line_str)
|
|
1380
|
+
|
|
1381
|
+
stderrreader: BufferedReader = process.stderr
|
|
1382
|
+
if stderrreader.readable():
|
|
1383
|
+
stderrresultb: bytes = stderrreader.read()
|
|
1384
|
+
stderrresult = GeneralUtilities.bytes_to_string(
|
|
1385
|
+
stderrresultb)
|
|
1386
|
+
stderrlines = GeneralUtilities.string_to_lines(
|
|
1387
|
+
stderrresult)
|
|
1388
|
+
for line in stderrlines:
|
|
1389
|
+
line_stripped = line.replace(
|
|
1390
|
+
"\r", "").strip()
|
|
1391
|
+
if len(line_stripped) > 0:
|
|
1392
|
+
line_str = line_stripped
|
|
1393
|
+
stderr_lines.append(line_str)
|
|
1394
|
+
if live_console_output_printing:
|
|
1395
|
+
if print_errors_as_information:
|
|
1396
|
+
GeneralUtilities.write_message_to_stdout(
|
|
1397
|
+
line_str)
|
|
1398
|
+
else:
|
|
1399
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1400
|
+
line_str)
|
|
1401
|
+
if log_to_file:
|
|
1402
|
+
GeneralUtilities.append_line_to_file(
|
|
1403
|
+
log_file, line_str)
|
|
1404
|
+
|
|
1405
|
+
return go
|
|
1406
|
+
except Exception:
|
|
1407
|
+
return False
|
|
1408
|
+
|
|
1409
|
+
while stream_process(process):
|
|
1410
|
+
time.sleep(0.1)
|
|
1411
|
+
|
|
1412
|
+
exit_code = process.poll()
|
|
1413
|
+
stdout = '\n'.join(stdout_lines)
|
|
1414
|
+
stderr = '\n'.join(stderr_lines)
|
|
1415
|
+
else:
|
|
1416
|
+
stdout, stderr = process.communicate()
|
|
1417
|
+
exit_code = process.wait()
|
|
1418
|
+
stdout = GeneralUtilities.bytes_to_string(
|
|
1419
|
+
stdout).replace('\r', '')
|
|
1420
|
+
stderr = GeneralUtilities.bytes_to_string(
|
|
1421
|
+
stderr).replace('\r', '')
|
|
1422
|
+
|
|
1423
|
+
if arguments_for_exception_as_string is None:
|
|
1424
|
+
arguments_for_exception_as_string = ' '.join(
|
|
1425
|
+
arguments_as_array)
|
|
1426
|
+
else:
|
|
1427
|
+
arguments_for_exception_as_string = ' '.join(
|
|
1428
|
+
arguments_for_log)
|
|
1242
1429
|
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1430
|
+
if throw_exception_if_exitcode_is_not_zero and exit_code != 0:
|
|
1431
|
+
arguments_for_exception_as_string = ' '.join(
|
|
1432
|
+
arguments_for_log)
|
|
1433
|
+
raise ValueError(
|
|
1434
|
+
f"Program '{working_directory}>{program} {arguments_for_exception_as_string}' resulted in exitcode {exit_code}. (StdOut: '{stdout}', StdErr: '{stderr}')")
|
|
1246
1435
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1436
|
+
result = (exit_code, stdout, stderr, pid)
|
|
1437
|
+
return result
|
|
1249
1438
|
except Exception as e:
|
|
1250
1439
|
raise e
|
|
1251
1440
|
|
|
1252
1441
|
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
1253
1442
|
@GeneralUtilities.check_arguments
|
|
1254
|
-
def run_program(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
1255
|
-
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, throw_exception_if_exitcode_is_not_zero, custom_argument)
|
|
1443
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
1444
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, throw_exception_if_exitcode_is_not_zero, custom_argument, interactive)
|
|
1256
1445
|
|
|
1257
1446
|
# Return-values program_runner: Pid
|
|
1258
1447
|
@GeneralUtilities.check_arguments
|
|
1259
|
-
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, custom_argument: object = None) -> int:
|
|
1260
|
-
mock_loader_result = self.__try_load_mock(
|
|
1448
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
1449
|
+
mock_loader_result = self.__try_load_mock(
|
|
1450
|
+
program, ' '.join(arguments_as_array), working_directory)
|
|
1261
1451
|
if mock_loader_result[0]:
|
|
1262
1452
|
return mock_loader_result[1]
|
|
1263
|
-
|
|
1264
|
-
|
|
1453
|
+
process: Popen = self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information,
|
|
1454
|
+
log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive)
|
|
1265
1455
|
return process.pid
|
|
1266
1456
|
|
|
1267
1457
|
# Return-values program_runner: Pid
|
|
1268
1458
|
@GeneralUtilities.check_arguments
|
|
1269
|
-
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1,
|
|
1270
|
-
|
|
1271
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument)
|
|
1459
|
+
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
1460
|
+
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive)
|
|
1272
1461
|
|
|
1273
1462
|
@GeneralUtilities.check_arguments
|
|
1274
1463
|
def __try_load_mock(self, program: str, arguments: str, working_directory: str) -> tuple[bool, tuple[int, str, str, int]]:
|
|
@@ -1326,7 +1515,8 @@ class ScriptCollectionCore:
|
|
|
1326
1515
|
result = mock_call
|
|
1327
1516
|
break
|
|
1328
1517
|
if result is None:
|
|
1329
|
-
raise LookupError(
|
|
1518
|
+
raise LookupError(
|
|
1519
|
+
f"Tried to execute mock-call '{workingdirectory}>{program} {argument}' but no mock-call was defined for that execution")
|
|
1330
1520
|
else:
|
|
1331
1521
|
self.__mocked_program_calls.remove(result)
|
|
1332
1522
|
return (result.exit_code, result.stdout, result.stderr, result.pid)
|
|
@@ -1375,7 +1565,8 @@ class ScriptCollectionCore:
|
|
|
1375
1565
|
|
|
1376
1566
|
@GeneralUtilities.check_arguments
|
|
1377
1567
|
def check_system_time_with_default_tolerance(self) -> None:
|
|
1378
|
-
self.check_system_time(
|
|
1568
|
+
self.check_system_time(
|
|
1569
|
+
self.__get_default_tolerance_for_system_time_equals_internet_time())
|
|
1379
1570
|
|
|
1380
1571
|
@GeneralUtilities.check_arguments
|
|
1381
1572
|
def __get_default_tolerance_for_system_time_equals_internet_time(self) -> timedelta:
|
|
@@ -1384,7 +1575,8 @@ class ScriptCollectionCore:
|
|
|
1384
1575
|
@GeneralUtilities.check_arguments
|
|
1385
1576
|
def increment_version(self, input_version: str, increment_major: bool, increment_minor: bool, increment_patch: bool) -> str:
|
|
1386
1577
|
splitted = input_version.split(".")
|
|
1387
|
-
GeneralUtilities.assert_condition(len(
|
|
1578
|
+
GeneralUtilities.assert_condition(len(
|
|
1579
|
+
splitted) == 3, f"Version '{input_version}' does not have the 'major.minor.patch'-pattern.")
|
|
1388
1580
|
major = int(splitted[0])
|
|
1389
1581
|
minor = int(splitted[1])
|
|
1390
1582
|
patch = int(splitted[2])
|
|
@@ -1398,17 +1590,20 @@ class ScriptCollectionCore:
|
|
|
1398
1590
|
|
|
1399
1591
|
@GeneralUtilities.check_arguments
|
|
1400
1592
|
def get_semver_version_from_gitversion(self, repository_folder: str) -> str:
|
|
1401
|
-
if(self.git_repository_has_commits(repository_folder)):
|
|
1402
|
-
result = self.get_version_from_gitversion(
|
|
1593
|
+
if (self.git_repository_has_commits(repository_folder)):
|
|
1594
|
+
result = self.get_version_from_gitversion(
|
|
1595
|
+
repository_folder, "MajorMinorPatch")
|
|
1403
1596
|
if self.git_repository_has_uncommitted_changes(repository_folder):
|
|
1404
1597
|
if self.get_current_git_branch_has_tag(repository_folder):
|
|
1405
|
-
id_of_latest_tag = self.git_get_commitid_of_tag(
|
|
1598
|
+
id_of_latest_tag = self.git_get_commitid_of_tag(
|
|
1599
|
+
repository_folder, self.get_latest_git_tag(repository_folder))
|
|
1406
1600
|
current_commit = self.git_get_commit_id(repository_folder)
|
|
1407
1601
|
current_commit_is_on_latest_tag = id_of_latest_tag == current_commit
|
|
1408
1602
|
if current_commit_is_on_latest_tag:
|
|
1409
|
-
result = self.increment_version(
|
|
1603
|
+
result = self.increment_version(
|
|
1604
|
+
result, False, False, True)
|
|
1410
1605
|
else:
|
|
1411
|
-
result="0.1.0"
|
|
1606
|
+
result = "0.1.0"
|
|
1412
1607
|
return result
|
|
1413
1608
|
|
|
1414
1609
|
@staticmethod
|
|
@@ -1419,8 +1614,10 @@ class ScriptCollectionCore:
|
|
|
1419
1614
|
@GeneralUtilities.check_arguments
|
|
1420
1615
|
def get_version_from_gitversion(self, folder: str, variable: str) -> str:
|
|
1421
1616
|
# called twice as workaround for issue 1877 in gitversion ( https://github.com/GitTools/GitVersion/issues/1877 )
|
|
1422
|
-
result = self.run_program_argsasarray(
|
|
1423
|
-
|
|
1617
|
+
result = self.run_program_argsasarray(
|
|
1618
|
+
"gitversion", ["/showVariable", variable], folder, verbosity=0)
|
|
1619
|
+
result = self.run_program_argsasarray(
|
|
1620
|
+
"gitversion", ["/showVariable", variable], folder, verbosity=0)
|
|
1424
1621
|
result = GeneralUtilities.strip_new_line_character(result[1])
|
|
1425
1622
|
|
|
1426
1623
|
return result
|
|
@@ -1432,7 +1629,8 @@ class ScriptCollectionCore:
|
|
|
1432
1629
|
days_until_expire = 1825
|
|
1433
1630
|
if password is None:
|
|
1434
1631
|
password = GeneralUtilities.generate_password()
|
|
1435
|
-
self.run_program(
|
|
1632
|
+
self.run_program(
|
|
1633
|
+
"openssl", f'req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days {days_until_expire} -nodes -x509 -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={name}/OU={subj_ou} -passout pass:{password} -keyout {name}.key -out {name}.crt', folder)
|
|
1436
1634
|
|
|
1437
1635
|
@GeneralUtilities.check_arguments
|
|
1438
1636
|
def generate_certificate(self, folder: str, domain: str, filename: str, subj_c: str, subj_st: str, subj_l: str, subj_o: str, subj_ou: str, days_until_expire: int = None, password: str = None) -> None:
|
|
@@ -1441,10 +1639,14 @@ class ScriptCollectionCore:
|
|
|
1441
1639
|
if password is None:
|
|
1442
1640
|
password = GeneralUtilities.generate_password()
|
|
1443
1641
|
rsa_key_length = 4096
|
|
1444
|
-
self.run_program(
|
|
1445
|
-
|
|
1446
|
-
self.run_program(
|
|
1447
|
-
|
|
1642
|
+
self.run_program(
|
|
1643
|
+
"openssl", f'genrsa -out {filename}.key {rsa_key_length}', folder)
|
|
1644
|
+
self.run_program(
|
|
1645
|
+
"openssl", f'req -new -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou} -x509 -key {filename}.key -out {filename}.unsigned.crt -days {days_until_expire}', folder)
|
|
1646
|
+
self.run_program(
|
|
1647
|
+
"openssl", f'pkcs12 -export -out {filename}.selfsigned.pfx -password pass:{password} -inkey {filename}.key -in {filename}.unsigned.crt', folder)
|
|
1648
|
+
GeneralUtilities.write_text_to_file(
|
|
1649
|
+
os.path.join(folder, f"{filename}.password"), password)
|
|
1448
1650
|
GeneralUtilities.write_text_to_file(os.path.join(folder, f"{filename}.san.conf"), f"""[ req ]
|
|
1449
1651
|
default_bits = {rsa_key_length}
|
|
1450
1652
|
distinguished_name = req_distinguished_name
|
|
@@ -1470,7 +1672,8 @@ DNS = {domain}
|
|
|
1470
1672
|
|
|
1471
1673
|
@GeneralUtilities.check_arguments
|
|
1472
1674
|
def generate_certificate_sign_request(self, folder: str, domain: str, filename: str, subj_c: str, subj_st: str, subj_l: str, subj_o: str, subj_ou: str) -> None:
|
|
1473
|
-
self.run_program(
|
|
1675
|
+
self.run_program(
|
|
1676
|
+
"openssl", f'req -new -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou} -key {filename}.key -out {filename}.csr -config {filename}.san.conf', folder)
|
|
1474
1677
|
|
|
1475
1678
|
@GeneralUtilities.check_arguments
|
|
1476
1679
|
def sign_certificate(self, folder: str, ca_folder: str, ca_name: str, domain: str, filename: str, days_until_expire: int = None) -> None:
|
|
@@ -1479,15 +1682,18 @@ DNS = {domain}
|
|
|
1479
1682
|
ca = os.path.join(ca_folder, ca_name)
|
|
1480
1683
|
password_file = os.path.join(folder, f"{filename}.password")
|
|
1481
1684
|
password = GeneralUtilities.read_text_from_file(password_file)
|
|
1482
|
-
self.run_program(
|
|
1483
|
-
|
|
1685
|
+
self.run_program(
|
|
1686
|
+
"openssl", f'x509 -req -in {filename}.csr -CA {ca}.crt -CAkey {ca}.key -CAcreateserial -CAserial {ca}.srl -out {filename}.crt -days {days_until_expire} -sha256 -extensions v3_req -extfile {filename}.san.conf', folder)
|
|
1687
|
+
self.run_program(
|
|
1688
|
+
"openssl", f'pkcs12 -export -out {filename}.pfx -inkey {filename}.key -in {filename}.crt -password pass:{password}', folder)
|
|
1484
1689
|
|
|
1485
1690
|
@GeneralUtilities.check_arguments
|
|
1486
1691
|
def update_dependencies_of_python_in_requirementstxt_file(self, file: str, verbosity: int):
|
|
1487
1692
|
lines = GeneralUtilities.read_lines_from_file(file)
|
|
1488
1693
|
new_lines = []
|
|
1489
1694
|
for line in lines:
|
|
1490
|
-
new_lines.append(
|
|
1695
|
+
new_lines.append(
|
|
1696
|
+
self.__get_updated_line_for_python_requirements(line.strip()))
|
|
1491
1697
|
GeneralUtilities.write_lines_to_file(file, new_lines)
|
|
1492
1698
|
|
|
1493
1699
|
@GeneralUtilities.check_arguments
|
|
@@ -1500,7 +1706,8 @@ DNS = {domain}
|
|
|
1500
1706
|
# (something like "cyclonedx-bom>=3.11.0" for example)
|
|
1501
1707
|
package = line.split(">")[0]
|
|
1502
1708
|
operator = ">=" if ">=" in line else ">"
|
|
1503
|
-
response = requests.get(
|
|
1709
|
+
response = requests.get(
|
|
1710
|
+
f'https://pypi.org/pypi/{package}/json', timeout=5)
|
|
1504
1711
|
latest_version = response.json()['info']['version']
|
|
1505
1712
|
return package+operator+latest_version
|
|
1506
1713
|
except:
|
|
@@ -1531,14 +1738,18 @@ DNS = {domain}
|
|
|
1531
1738
|
def update_dependencies_of_dotnet_project(self, csproj_file: str, verbosity: int):
|
|
1532
1739
|
folder = os.path.dirname(csproj_file)
|
|
1533
1740
|
csproj_filename = os.path.basename(csproj_file)
|
|
1534
|
-
GeneralUtilities.write_message_to_stderr(
|
|
1535
|
-
|
|
1741
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1742
|
+
f"Check for updates in {csproj_filename}")
|
|
1743
|
+
result = self.run_program(
|
|
1744
|
+
"dotnet", f"list {csproj_filename} package --outdated", folder)
|
|
1536
1745
|
for line in result[1].replace("\r", "").split("\n"):
|
|
1537
1746
|
# Relevant output-lines are something like " > NJsonSchema 10.7.0 10.7.0 10.9.0"
|
|
1538
1747
|
if ">" in line:
|
|
1539
1748
|
package_name = line.replace(">", "").strip().split(" ")[0]
|
|
1540
|
-
GeneralUtilities.write_message_to_stderr(
|
|
1541
|
-
|
|
1749
|
+
GeneralUtilities.write_message_to_stderr(
|
|
1750
|
+
f"Update package {package_name}")
|
|
1751
|
+
self.run_program(
|
|
1752
|
+
"dotnet", f"add {csproj_filename} package {package_name}", folder)
|
|
1542
1753
|
|
|
1543
1754
|
@GeneralUtilities.check_arguments
|
|
1544
1755
|
def create_deb_package(self, toolname: str, binary_folder: str, control_file_content: str,
|
|
@@ -1554,24 +1765,30 @@ DNS = {domain}
|
|
|
1554
1765
|
# create folder
|
|
1555
1766
|
GeneralUtilities.ensure_directory_exists(temp_folder)
|
|
1556
1767
|
control_content_folder_name = "controlcontent"
|
|
1557
|
-
packagecontent_control_folder = os.path.join(
|
|
1768
|
+
packagecontent_control_folder = os.path.join(
|
|
1769
|
+
temp_folder, control_content_folder_name)
|
|
1558
1770
|
GeneralUtilities.ensure_directory_exists(packagecontent_control_folder)
|
|
1559
1771
|
data_content_folder_name = "datacontent"
|
|
1560
|
-
packagecontent_data_folder = os.path.join(
|
|
1772
|
+
packagecontent_data_folder = os.path.join(
|
|
1773
|
+
temp_folder, data_content_folder_name)
|
|
1561
1774
|
GeneralUtilities.ensure_directory_exists(packagecontent_data_folder)
|
|
1562
1775
|
entireresult_content_folder_name = "entireresultcontent"
|
|
1563
|
-
packagecontent_entireresult_folder = os.path.join(
|
|
1564
|
-
|
|
1776
|
+
packagecontent_entireresult_folder = os.path.join(
|
|
1777
|
+
temp_folder, entireresult_content_folder_name)
|
|
1778
|
+
GeneralUtilities.ensure_directory_exists(
|
|
1779
|
+
packagecontent_entireresult_folder)
|
|
1565
1780
|
|
|
1566
1781
|
# create "debian-binary"-file
|
|
1567
|
-
debianbinary_file = os.path.join(
|
|
1782
|
+
debianbinary_file = os.path.join(
|
|
1783
|
+
packagecontent_entireresult_folder, "debian-binary")
|
|
1568
1784
|
GeneralUtilities.ensure_file_exists(debianbinary_file)
|
|
1569
1785
|
GeneralUtilities.write_text_to_file(debianbinary_file, "2.0\n")
|
|
1570
1786
|
|
|
1571
1787
|
# create control-content
|
|
1572
1788
|
|
|
1573
1789
|
# conffiles
|
|
1574
|
-
conffiles_file = os.path.join(
|
|
1790
|
+
conffiles_file = os.path.join(
|
|
1791
|
+
packagecontent_control_folder, "conffiles")
|
|
1575
1792
|
GeneralUtilities.ensure_file_exists(conffiles_file)
|
|
1576
1793
|
|
|
1577
1794
|
# postinst-script
|
|
@@ -1600,53 +1817,58 @@ DNS = {domain}
|
|
|
1600
1817
|
# copy binaries
|
|
1601
1818
|
usr_bin_folder = os.path.join(packagecontent_data_folder, "usr/bin")
|
|
1602
1819
|
GeneralUtilities.ensure_directory_exists(usr_bin_folder)
|
|
1603
|
-
usr_bin_content_folder = os.path.join(
|
|
1604
|
-
|
|
1820
|
+
usr_bin_content_folder = os.path.join(
|
|
1821
|
+
usr_bin_folder, tool_content_folder_name)
|
|
1822
|
+
GeneralUtilities.copy_content_of_folder(
|
|
1823
|
+
bin_folder, usr_bin_content_folder)
|
|
1605
1824
|
|
|
1606
1825
|
# create debfile
|
|
1607
1826
|
deb_filename = f"{toolname}.deb"
|
|
1608
|
-
self.run_program_argsasarray("tar", [
|
|
1609
|
-
|
|
1610
|
-
self.run_program_argsasarray("
|
|
1611
|
-
|
|
1827
|
+
self.run_program_argsasarray("tar", [
|
|
1828
|
+
"czf", f"../{entireresult_content_folder_name}/control.tar.gz", "*"], packagecontent_control_folder, verbosity=verbosity)
|
|
1829
|
+
self.run_program_argsasarray("tar", [
|
|
1830
|
+
"czf", f"../{entireresult_content_folder_name}/data.tar.gz", "*"], packagecontent_data_folder, verbosity=verbosity)
|
|
1831
|
+
self.run_program_argsasarray("ar", ["r", deb_filename, "debian-binary", "control.tar.gz",
|
|
1832
|
+
"data.tar.gz"], packagecontent_entireresult_folder, verbosity=verbosity)
|
|
1833
|
+
result_file = os.path.join(
|
|
1834
|
+
packagecontent_entireresult_folder, deb_filename)
|
|
1612
1835
|
shutil.copy(result_file, os.path.join(deb_output_folder, deb_filename))
|
|
1613
1836
|
|
|
1614
1837
|
# cleanup
|
|
1615
1838
|
GeneralUtilities.ensure_directory_does_not_exist(temp_folder)
|
|
1616
1839
|
|
|
1617
|
-
|
|
1618
1840
|
@GeneralUtilities.check_arguments
|
|
1619
1841
|
def update_year_in_copyright_tags(self, file: str) -> None:
|
|
1620
|
-
current_year=str(datetime.now().year)
|
|
1621
|
-
lines=GeneralUtilities.read_lines_from_file(file)
|
|
1622
|
-
lines_result=[]
|
|
1842
|
+
current_year = str(datetime.now().year)
|
|
1843
|
+
lines = GeneralUtilities.read_lines_from_file(file)
|
|
1844
|
+
lines_result = []
|
|
1623
1845
|
for line in lines:
|
|
1624
1846
|
if match := re.search("(.*<[Cc]opyright>.*)\\d\\d\\d\\d(.*<\\/[Cc]opyright>.*)", line):
|
|
1625
1847
|
part1 = match.group(1)
|
|
1626
1848
|
part2 = match.group(2)
|
|
1627
|
-
adapted=part1+current_year+part2
|
|
1849
|
+
adapted = part1+current_year+part2
|
|
1628
1850
|
else:
|
|
1629
|
-
adapted=line
|
|
1851
|
+
adapted = line
|
|
1630
1852
|
lines_result.append(adapted)
|
|
1631
|
-
GeneralUtilities.write_lines_to_file(file,lines_result)
|
|
1853
|
+
GeneralUtilities.write_lines_to_file(file, lines_result)
|
|
1632
1854
|
|
|
1633
1855
|
@GeneralUtilities.check_arguments
|
|
1634
1856
|
def update_year_in_first_line_of_file(self, file: str) -> None:
|
|
1635
|
-
current_year=str(datetime.now().year)
|
|
1636
|
-
lines=GeneralUtilities.read_lines_from_file(file)
|
|
1637
|
-
lines[0]=re.sub("\\d\\d\\d\\d",current_year,lines[0])
|
|
1638
|
-
GeneralUtilities.write_lines_to_file(file,lines)
|
|
1857
|
+
current_year = str(datetime.now().year)
|
|
1858
|
+
lines = GeneralUtilities.read_lines_from_file(file)
|
|
1859
|
+
lines[0] = re.sub("\\d\\d\\d\\d", current_year, lines[0])
|
|
1860
|
+
GeneralUtilities.write_lines_to_file(file, lines)
|
|
1639
1861
|
|
|
1640
1862
|
@GeneralUtilities.check_arguments
|
|
1641
1863
|
def get_external_ip(self, proxy: str) -> str:
|
|
1642
|
-
information=self.get_externalnetworkinformation_as_json_string(proxy)
|
|
1643
|
-
parsed=json.loads(information)
|
|
1864
|
+
information = self.get_externalnetworkinformation_as_json_string(proxy)
|
|
1865
|
+
parsed = json.loads(information)
|
|
1644
1866
|
return parsed.ip
|
|
1645
1867
|
|
|
1646
1868
|
@GeneralUtilities.check_arguments
|
|
1647
1869
|
def get_country_of_external_ip(self, proxy: str) -> str:
|
|
1648
|
-
information=self.get_externalnetworkinformation_as_json_string(proxy)
|
|
1649
|
-
parsed=json.loads(information)
|
|
1870
|
+
information = self.get_externalnetworkinformation_as_json_string(proxy)
|
|
1871
|
+
parsed = json.loads(information)
|
|
1650
1872
|
return parsed.country
|
|
1651
1873
|
|
|
1652
1874
|
@GeneralUtilities.check_arguments
|
|
@@ -1654,7 +1876,8 @@ DNS = {domain}
|
|
|
1654
1876
|
proxies = None
|
|
1655
1877
|
if GeneralUtilities.string_has_content(proxy):
|
|
1656
1878
|
proxies = {"http": proxy}
|
|
1657
|
-
response = requests.get('https://ipinfo.io',
|
|
1658
|
-
|
|
1879
|
+
response = requests.get('https://ipinfo.io',
|
|
1880
|
+
proxies=proxies, timeout=5)
|
|
1881
|
+
network_information_as_json_string = GeneralUtilities.bytes_to_string(
|
|
1882
|
+
response.content)
|
|
1659
1883
|
return network_information_as_json_string
|
|
1660
|
-
|