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