ScriptCollection 3.5.52__py3-none-any.whl → 3.5.54__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 +93 -0
- ScriptCollection/GeneralUtilities.py +16 -11
- ScriptCollection/ProgramRunnerBase.py +10 -5
- ScriptCollection/ProgramRunnerEpew.py +14 -10
- ScriptCollection/ProgramRunnerPopen.py +4 -0
- ScriptCollection/ScriptCollectionCore.py +115 -35
- ScriptCollection/TasksForCommonProjectStructure.py +87 -90
- {ScriptCollection-3.5.52.dist-info → ScriptCollection-3.5.54.dist-info}/METADATA +3 -3
- ScriptCollection-3.5.54.dist-info/RECORD +16 -0
- {ScriptCollection-3.5.52.dist-info → ScriptCollection-3.5.54.dist-info}/entry_points.txt +12 -0
- ScriptCollection-3.5.52.dist-info/RECORD +0 -16
- {ScriptCollection-3.5.52.dist-info → ScriptCollection-3.5.54.dist-info}/WHEEL +0 -0
- {ScriptCollection-3.5.52.dist-info → ScriptCollection-3.5.54.dist-info}/top_level.txt +0 -0
ScriptCollection/Executables.py
CHANGED
|
@@ -387,3 +387,96 @@ def CreateChangelogEntry() -> int:
|
|
|
387
387
|
folder = GeneralUtilities.resolve_relative_path(args.repositoryfolder, os.getcwd())
|
|
388
388
|
TasksForCommonProjectStructure().create_changelog_entry(folder, args.message, args.commit)
|
|
389
389
|
return 0
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def FileExists() -> int:
|
|
393
|
+
parser = argparse.ArgumentParser(description="This function returns 0 if the given file exists. Otherwise this function returns 2. If an error occurrs the exitcode is 1.")
|
|
394
|
+
parser.add_argument('-p', '--path', required=True)
|
|
395
|
+
args = parser.parse_args()
|
|
396
|
+
if os.path.isfile(args.path):
|
|
397
|
+
return 0
|
|
398
|
+
else:
|
|
399
|
+
return 2
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def FolderExists() -> int:
|
|
403
|
+
parser = argparse.ArgumentParser(description="This function returns 0 if the given folder exists. Otherwise this function returns 2. If an error occurrs the exitcode is 1.")
|
|
404
|
+
parser.add_argument('-p', '--path', required=True)
|
|
405
|
+
args = parser.parse_args()
|
|
406
|
+
if os.path.isdir(args.path):
|
|
407
|
+
return 0
|
|
408
|
+
else:
|
|
409
|
+
return 2
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def SetContentOfFile() -> int:
|
|
413
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
414
|
+
# TODO implement function
|
|
415
|
+
return 1
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def PrintFileContent() -> int:
|
|
419
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
420
|
+
# TODO implement function
|
|
421
|
+
return 1
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
def CreateFile() -> int:
|
|
425
|
+
parser = argparse.ArgumentParser(description="This function creates an empty file.")
|
|
426
|
+
parser.add_argument('-p', '--path', required=True)
|
|
427
|
+
parser.add_argument('-e', '--errorwhenexists', action='store_true', required=False, default=False)
|
|
428
|
+
parser.add_argument('-c', '--createnecessaryfolder', action='store_true', required=False, default=False)
|
|
429
|
+
args = parser.parse_args()
|
|
430
|
+
sc = ScriptCollectionCore()
|
|
431
|
+
sc.create_file(args.path, args.errorwhenexists, args.createnecessaryfolder)
|
|
432
|
+
return 0
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def CreateFolder() -> int:
|
|
436
|
+
parser = argparse.ArgumentParser(description="This function creates an empty folder.")
|
|
437
|
+
parser.add_argument('-p', '--path', required=True)
|
|
438
|
+
parser.add_argument('-e', '--errorwhenexists', action='store_true', required=False, default=False)
|
|
439
|
+
parser.add_argument('-c', '--createnecessaryfolder', action='store_true', required=False, default=False)
|
|
440
|
+
args = parser.parse_args()
|
|
441
|
+
sc = ScriptCollectionCore()
|
|
442
|
+
sc.create_folder(args.path, args.errorwhenexists, args.createnecessaryfolder)
|
|
443
|
+
return 0
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def AppendLineToFile() -> int:
|
|
447
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
448
|
+
# TODO implement function
|
|
449
|
+
# TODO add switch to set if adding new line at begin of line should be skipped if the file already ends with a new-line-character
|
|
450
|
+
# TODO add switch to enable/disable appending another new-line-character at the end of the file
|
|
451
|
+
return 1
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
def RegexReplaceInFile() -> int:
|
|
455
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
456
|
+
# TODO implement function
|
|
457
|
+
return 1
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def PrintFileSize() -> int:
|
|
461
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
462
|
+
# TODO implement function
|
|
463
|
+
return 1
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
def FileContainsContent() -> int:
|
|
467
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
468
|
+
# TODO implement function
|
|
469
|
+
# TODO add switch to set if the input pattern should be treated as regex
|
|
470
|
+
return 1
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def RemoveFile() -> int:
|
|
474
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
475
|
+
# TODO implement function
|
|
476
|
+
return 1
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def RemoveFolder() -> int:
|
|
480
|
+
GeneralUtilities.write_exception_to_stderr("This function is not implemented yet.")
|
|
481
|
+
# TODO implement function
|
|
482
|
+
return 1
|
|
@@ -5,6 +5,7 @@ import ctypes
|
|
|
5
5
|
import hashlib
|
|
6
6
|
import re
|
|
7
7
|
import os
|
|
8
|
+
import subprocess
|
|
8
9
|
import shutil
|
|
9
10
|
import urllib
|
|
10
11
|
import stat
|
|
@@ -790,8 +791,13 @@ class GeneralUtilities:
|
|
|
790
791
|
@staticmethod
|
|
791
792
|
@check_arguments
|
|
792
793
|
def epew_is_available() -> bool:
|
|
794
|
+
return GeneralUtilities.tool_is_available("epew")
|
|
795
|
+
|
|
796
|
+
@staticmethod
|
|
797
|
+
@check_arguments
|
|
798
|
+
def tool_is_available(toolname: str) -> bool:
|
|
793
799
|
try:
|
|
794
|
-
return shutil.which(
|
|
800
|
+
return shutil.which(toolname) is not None
|
|
795
801
|
except:
|
|
796
802
|
return False
|
|
797
803
|
|
|
@@ -873,7 +879,7 @@ class GeneralUtilities:
|
|
|
873
879
|
def internet_connection_is_available() -> bool:
|
|
874
880
|
# TODO add more hosts to check to return true if at least one is available
|
|
875
881
|
try:
|
|
876
|
-
with urllib.request.urlopen("https://google.com") as url_result:
|
|
882
|
+
with urllib.request.urlopen("https://www.google.com") as url_result:
|
|
877
883
|
return (url_result.code // 100) == 2
|
|
878
884
|
except:
|
|
879
885
|
pass
|
|
@@ -895,15 +901,14 @@ class GeneralUtilities:
|
|
|
895
901
|
|
|
896
902
|
@staticmethod
|
|
897
903
|
@check_arguments
|
|
898
|
-
def
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
GeneralUtilities.assert_condition(GeneralUtilities.is_git_repository(folder), f"'{folder}' is not a git-repository.")
|
|
904
|
+
def run_program_simple(program: str, arguments: list[str], cwd: str = None) -> tuple[int, str, str]:
|
|
905
|
+
if cwd is None:
|
|
906
|
+
cwd = os.getcwd()
|
|
907
|
+
cmd = [program]+arguments
|
|
908
|
+
with subprocess.Popen(cmd, cwd=cwd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
|
909
|
+
stdout, stderr = process.communicate()
|
|
910
|
+
exit_code = process.wait()
|
|
911
|
+
return (exit_code, stdout, stderr)
|
|
907
912
|
|
|
908
913
|
@staticmethod
|
|
909
914
|
@check_arguments
|
|
@@ -8,7 +8,7 @@ class ProgramRunnerBase:
|
|
|
8
8
|
# Return-values program_runner: Pid
|
|
9
9
|
@abstractmethod
|
|
10
10
|
@GeneralUtilities.check_arguments
|
|
11
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
11
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> Popen:
|
|
12
12
|
# Verbosity:
|
|
13
13
|
# 0=Quiet (No output will be printed.)
|
|
14
14
|
# 1=Normal (If the exitcode of the executed program is not 0 then the StdErr will be printed.)
|
|
@@ -25,23 +25,28 @@ class ProgramRunnerBase:
|
|
|
25
25
|
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
26
26
|
@abstractmethod
|
|
27
27
|
@GeneralUtilities.check_arguments
|
|
28
|
-
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
28
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
29
29
|
raise NotImplementedError
|
|
30
30
|
|
|
31
31
|
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
32
32
|
@abstractmethod
|
|
33
33
|
@GeneralUtilities.check_arguments
|
|
34
|
-
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
34
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
35
35
|
raise NotImplementedError
|
|
36
36
|
|
|
37
37
|
# Return-values program_runner: Pid
|
|
38
38
|
@abstractmethod
|
|
39
39
|
@GeneralUtilities.check_arguments
|
|
40
|
-
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
40
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
41
41
|
raise NotImplementedError
|
|
42
42
|
|
|
43
43
|
# Return-values program_runner: Pid
|
|
44
44
|
@abstractmethod
|
|
45
45
|
@GeneralUtilities.check_arguments
|
|
46
|
-
def run_program_async(self, program: str, arguments: str, working_directory: str, custom_argument: object, interactive:bool=False) -> int:
|
|
46
|
+
def run_program_async(self, program: str, arguments: str, working_directory: str, custom_argument: object, interactive: bool = False) -> int:
|
|
47
|
+
raise NotImplementedError
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
@GeneralUtilities.check_arguments
|
|
51
|
+
def will_be_executed_locally(self) -> bool:
|
|
47
52
|
raise NotImplementedError
|
|
@@ -39,7 +39,7 @@ class CustomEpewArgument:
|
|
|
39
39
|
class ProgramRunnerEpew(ProgramRunnerBase):
|
|
40
40
|
|
|
41
41
|
@GeneralUtilities.check_arguments
|
|
42
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
42
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> Popen:
|
|
43
43
|
if GeneralUtilities.epew_is_available():
|
|
44
44
|
custom_argument: CustomEpewArgument = custom_argument
|
|
45
45
|
args = []
|
|
@@ -67,7 +67,7 @@ class ProgramRunnerEpew(ProgramRunnerBase):
|
|
|
67
67
|
if custom_argument.addLogOverhead:
|
|
68
68
|
args.append("-g")
|
|
69
69
|
args.append("-v "+str(custom_argument.verbosity))
|
|
70
|
-
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory,custom_argument,interactive)
|
|
70
|
+
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory, custom_argument, interactive)
|
|
71
71
|
else:
|
|
72
72
|
raise ValueError("Epew is not available.")
|
|
73
73
|
|
|
@@ -85,21 +85,21 @@ class ProgramRunnerEpew(ProgramRunnerBase):
|
|
|
85
85
|
return result
|
|
86
86
|
|
|
87
87
|
@GeneralUtilities.check_arguments
|
|
88
|
-
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
89
|
-
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive)
|
|
88
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
89
|
+
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive)
|
|
90
90
|
return self.wait(process, custom_argument)
|
|
91
91
|
|
|
92
92
|
@GeneralUtilities.check_arguments
|
|
93
|
-
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
94
|
-
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
93
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
|
|
94
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument, interactive)
|
|
95
95
|
|
|
96
96
|
@GeneralUtilities.check_arguments
|
|
97
|
-
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
98
|
-
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive).pid
|
|
97
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
98
|
+
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive).pid
|
|
99
99
|
|
|
100
100
|
@GeneralUtilities.check_arguments
|
|
101
|
-
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
102
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
101
|
+
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
102
|
+
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument, interactive)
|
|
103
103
|
|
|
104
104
|
@GeneralUtilities.check_arguments
|
|
105
105
|
def __get_number_from_filecontent(self, filecontent: str) -> int:
|
|
@@ -120,3 +120,7 @@ class ProgramRunnerEpew(ProgramRunnerBase):
|
|
|
120
120
|
return content
|
|
121
121
|
else:
|
|
122
122
|
raise ValueError(f"File '{file}' does not exist")
|
|
123
|
+
|
|
124
|
+
@GeneralUtilities.check_arguments
|
|
125
|
+
def will_be_executed_locally(self) -> bool:
|
|
126
|
+
return True
|
|
@@ -51,3 +51,7 @@ class ProgramRunnerPopen(ProgramRunnerBase):
|
|
|
51
51
|
@GeneralUtilities.check_arguments
|
|
52
52
|
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
|
|
53
53
|
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument, interactive)
|
|
54
|
+
|
|
55
|
+
@GeneralUtilities.check_arguments
|
|
56
|
+
def will_be_executed_locally(self) -> bool:
|
|
57
|
+
return True
|
|
@@ -25,13 +25,13 @@ import yaml
|
|
|
25
25
|
import qrcode
|
|
26
26
|
import pycdlib
|
|
27
27
|
import send2trash
|
|
28
|
-
import
|
|
28
|
+
from pypdf import PdfReader, PdfWriter
|
|
29
29
|
from .GeneralUtilities import GeneralUtilities
|
|
30
30
|
from .ProgramRunnerBase import ProgramRunnerBase
|
|
31
31
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
32
32
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
|
33
33
|
|
|
34
|
-
version = "3.5.
|
|
34
|
+
version = "3.5.54"
|
|
35
35
|
__version__ = version
|
|
36
36
|
|
|
37
37
|
|
|
@@ -147,7 +147,7 @@ class ScriptCollectionCore:
|
|
|
147
147
|
|
|
148
148
|
@GeneralUtilities.check_arguments
|
|
149
149
|
def commit_is_signed_by_key(self, repository_folder: str, revision_identifier: str, key: str) -> bool:
|
|
150
|
-
|
|
150
|
+
self.assert_is_git_repository(repository_folder)
|
|
151
151
|
result = self.run_program("git", f"verify-commit {revision_identifier}", repository_folder, throw_exception_if_exitcode_is_not_zero=False)
|
|
152
152
|
if (result[0] != 0):
|
|
153
153
|
return False
|
|
@@ -161,12 +161,12 @@ class ScriptCollectionCore:
|
|
|
161
161
|
|
|
162
162
|
@GeneralUtilities.check_arguments
|
|
163
163
|
def get_parent_commit_ids_of_commit(self, repository_folder: str, commit_id: str) -> str:
|
|
164
|
-
|
|
164
|
+
self.assert_is_git_repository(repository_folder)
|
|
165
165
|
return self.run_program("git", f'log --pretty=%P -n 1 "{commit_id}"', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].replace("\r", "").replace("\n", "").split(" ")
|
|
166
166
|
|
|
167
167
|
@GeneralUtilities.check_arguments
|
|
168
168
|
def get_all_authors_and_committers_of_repository(self, repository_folder: str, subfolder: str = None, verbosity: int = 1) -> list[tuple[str, str]]:
|
|
169
|
-
|
|
169
|
+
self.assert_is_git_repository(repository_folder)
|
|
170
170
|
space_character = "_"
|
|
171
171
|
if subfolder is None:
|
|
172
172
|
subfolder_argument = ""
|
|
@@ -186,7 +186,7 @@ class ScriptCollectionCore:
|
|
|
186
186
|
|
|
187
187
|
@GeneralUtilities.check_arguments
|
|
188
188
|
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:
|
|
189
|
-
|
|
189
|
+
self.assert_is_git_repository(repository_folder)
|
|
190
190
|
since_as_string = self.__datetime_to_string_for_git(since)
|
|
191
191
|
until_as_string = self.__datetime_to_string_for_git(until)
|
|
192
192
|
result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program("git", f'log --since "{since_as_string}" --until "{until_as_string}" --pretty=format:"%H" --no-patch', repository_folder, throw_exception_if_exitcode_is_not_zero=True)[1].split("\n").replace("\r", ""))
|
|
@@ -201,7 +201,7 @@ class ScriptCollectionCore:
|
|
|
201
201
|
|
|
202
202
|
@GeneralUtilities.check_arguments
|
|
203
203
|
def git_commit_is_ancestor(self, repository_folder: str, ancestor: str, descendant: str = "HEAD") -> bool:
|
|
204
|
-
|
|
204
|
+
self.assert_is_git_repository(repository_folder)
|
|
205
205
|
result = self.run_program_argsasarray("git", ["merge-base", "--is-ancestor", ancestor, descendant], repository_folder, throw_exception_if_exitcode_is_not_zero=False)
|
|
206
206
|
exit_code = result[0]
|
|
207
207
|
if exit_code == 0:
|
|
@@ -213,7 +213,7 @@ class ScriptCollectionCore:
|
|
|
213
213
|
|
|
214
214
|
@GeneralUtilities.check_arguments
|
|
215
215
|
def __git_changes_helper(self, repository_folder: str, arguments_as_array: list[str]) -> bool:
|
|
216
|
-
|
|
216
|
+
self.assert_is_git_repository(repository_folder)
|
|
217
217
|
lines = GeneralUtilities.string_to_lines(self.run_program_argsasarray("git", arguments_as_array, repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)[1], False)
|
|
218
218
|
for line in lines:
|
|
219
219
|
if GeneralUtilities.string_has_content(line):
|
|
@@ -222,22 +222,22 @@ class ScriptCollectionCore:
|
|
|
222
222
|
|
|
223
223
|
@GeneralUtilities.check_arguments
|
|
224
224
|
def git_repository_has_new_untracked_files(self, repository_folder: str):
|
|
225
|
-
|
|
225
|
+
self.assert_is_git_repository(repository_folder)
|
|
226
226
|
return self.__git_changes_helper(repository_folder, ["ls-files", "--exclude-standard", "--others"])
|
|
227
227
|
|
|
228
228
|
@GeneralUtilities.check_arguments
|
|
229
229
|
def git_repository_has_unstaged_changes_of_tracked_files(self, repository_folder: str):
|
|
230
|
-
|
|
230
|
+
self.assert_is_git_repository(repository_folder)
|
|
231
231
|
return self.__git_changes_helper(repository_folder, ["--no-pager", "diff"])
|
|
232
232
|
|
|
233
233
|
@GeneralUtilities.check_arguments
|
|
234
234
|
def git_repository_has_staged_changes(self, repository_folder: str):
|
|
235
|
-
|
|
235
|
+
self.assert_is_git_repository(repository_folder)
|
|
236
236
|
return self.__git_changes_helper(repository_folder, ["--no-pager", "diff", "--cached"])
|
|
237
237
|
|
|
238
238
|
@GeneralUtilities.check_arguments
|
|
239
239
|
def git_repository_has_uncommitted_changes(self, repository_folder: str) -> bool:
|
|
240
|
-
|
|
240
|
+
self.assert_is_git_repository(repository_folder)
|
|
241
241
|
if (self.git_repository_has_unstaged_changes(repository_folder)):
|
|
242
242
|
return True
|
|
243
243
|
if (self.git_repository_has_staged_changes(repository_folder)):
|
|
@@ -246,7 +246,7 @@ class ScriptCollectionCore:
|
|
|
246
246
|
|
|
247
247
|
@GeneralUtilities.check_arguments
|
|
248
248
|
def git_repository_has_unstaged_changes(self, repository_folder: str) -> bool:
|
|
249
|
-
|
|
249
|
+
self.assert_is_git_repository(repository_folder)
|
|
250
250
|
if (self.git_repository_has_unstaged_changes_of_tracked_files(repository_folder)):
|
|
251
251
|
return True
|
|
252
252
|
if (self.git_repository_has_new_untracked_files(repository_folder)):
|
|
@@ -255,13 +255,13 @@ class ScriptCollectionCore:
|
|
|
255
255
|
|
|
256
256
|
@GeneralUtilities.check_arguments
|
|
257
257
|
def git_get_commit_id(self, repository_folder: str, commit: str = "HEAD") -> str:
|
|
258
|
-
|
|
258
|
+
self.assert_is_git_repository(repository_folder)
|
|
259
259
|
result: tuple[int, str, str, int] = self.run_program_argsasarray("git", ["rev-parse", "--verify", commit], repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
260
260
|
return result[1].replace('\n', '')
|
|
261
261
|
|
|
262
262
|
@GeneralUtilities.check_arguments
|
|
263
263
|
def git_get_commit_date(self, repository_folder: str, commit: str = "HEAD") -> datetime:
|
|
264
|
-
|
|
264
|
+
self.assert_is_git_repository(repository_folder)
|
|
265
265
|
result: tuple[int, str, str, int] = self.run_program_argsasarray("git", ["show", "-s", "--format=%ci", commit], repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
|
|
266
266
|
date_as_string = result[1].replace('\n', '')
|
|
267
267
|
result = datetime.strptime(date_as_string, '%Y-%m-%d %H:%M:%S %z')
|
|
@@ -464,7 +464,7 @@ class ScriptCollectionCore:
|
|
|
464
464
|
def git_fetch_or_clone_all_in_directory(self, source_directory: str, target_directory: str) -> None:
|
|
465
465
|
for subfolder in GeneralUtilities.get_direct_folders_of_folder(source_directory):
|
|
466
466
|
foldername = os.path.basename(subfolder)
|
|
467
|
-
if
|
|
467
|
+
if self.is_git_repository(subfolder):
|
|
468
468
|
source_repository = subfolder
|
|
469
469
|
target_repository = os.path.join(target_directory, foldername)
|
|
470
470
|
if os.path.isdir(target_directory):
|
|
@@ -534,20 +534,20 @@ class ScriptCollectionCore:
|
|
|
534
534
|
|
|
535
535
|
@GeneralUtilities.check_arguments
|
|
536
536
|
def get_current_git_branch_has_tag(self, repository_folder: str) -> bool:
|
|
537
|
-
|
|
537
|
+
self.assert_is_git_repository(repository_folder)
|
|
538
538
|
result = self.run_program_argsasarray("git", ["describe", "--tags", "--abbrev=0"], repository_folder, verbosity=0, throw_exception_if_exitcode_is_not_zero=False)
|
|
539
539
|
return result[0] == 0
|
|
540
540
|
|
|
541
541
|
@GeneralUtilities.check_arguments
|
|
542
542
|
def get_latest_git_tag(self, repository_folder: str) -> str:
|
|
543
|
-
|
|
543
|
+
self.assert_is_git_repository(repository_folder)
|
|
544
544
|
result = self.run_program_argsasarray("git", ["describe", "--tags", "--abbrev=0"], repository_folder, verbosity=0)
|
|
545
545
|
result = result[1].replace("\r", "").replace("\n", "")
|
|
546
546
|
return result
|
|
547
547
|
|
|
548
548
|
@GeneralUtilities.check_arguments
|
|
549
549
|
def get_staged_or_committed_git_ignored_files(self, repository_folder: str) -> list[str]:
|
|
550
|
-
|
|
550
|
+
self.assert_is_git_repository(repository_folder)
|
|
551
551
|
temp_result = self.run_program_argsasarray("git", ["ls-files", "-i", "-c", "--exclude-standard"], repository_folder, verbosity=0)
|
|
552
552
|
temp_result = temp_result[1].replace("\r", "")
|
|
553
553
|
result = [line for line in temp_result.split("\n") if len(line) > 0]
|
|
@@ -555,7 +555,7 @@ class ScriptCollectionCore:
|
|
|
555
555
|
|
|
556
556
|
@GeneralUtilities.check_arguments
|
|
557
557
|
def git_repository_has_commits(self, repository_folder: str) -> bool:
|
|
558
|
-
|
|
558
|
+
self.assert_is_git_repository(repository_folder)
|
|
559
559
|
return self.run_program_argsasarray("git", ["rev-parse", "--verify", "HEAD"], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0] == 0
|
|
560
560
|
|
|
561
561
|
@GeneralUtilities.check_arguments
|
|
@@ -609,6 +609,44 @@ class ScriptCollectionCore:
|
|
|
609
609
|
for renamed_item, original_name in renamed_items.items():
|
|
610
610
|
os.rename(renamed_item, original_name)
|
|
611
611
|
|
|
612
|
+
@GeneralUtilities.check_arguments
|
|
613
|
+
def is_file(self, path: str) -> bool:
|
|
614
|
+
if self.program_runner.will_be_executed_locally():
|
|
615
|
+
return os.path.isfile(path) # much more performant than always running an external program
|
|
616
|
+
else:
|
|
617
|
+
exit_code, _, stderr = self.run_program("scfileexists", ["--path", path], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
|
|
618
|
+
if exit_code == 0:
|
|
619
|
+
return True
|
|
620
|
+
elif exit_code == 1:
|
|
621
|
+
raise ValueError(f"Not calculatable whether file '{path}' exists. StdErr: '{stderr}'")
|
|
622
|
+
elif exit_code == 2:
|
|
623
|
+
return False
|
|
624
|
+
raise ValueError(f"Fatal error occurrs while checking whether file '{path}' exists. StdErr: '{stderr}'")
|
|
625
|
+
|
|
626
|
+
@GeneralUtilities.check_arguments
|
|
627
|
+
def is_folder(self, path: str) -> bool:
|
|
628
|
+
if self.program_runner.will_be_executed_locally(): # much more performant than always running an external program
|
|
629
|
+
return os.path.isdir(path)
|
|
630
|
+
else:
|
|
631
|
+
exit_code, _, stderr = self.run_program("scfolderexists", ["--path", path], throw_exception_if_exitcode_is_not_zero=False) # works platform-indepent
|
|
632
|
+
if exit_code == 0:
|
|
633
|
+
return True
|
|
634
|
+
elif exit_code == 1:
|
|
635
|
+
raise ValueError(f"Not calculatable whether folder '{path}' exists. StdErr: '{stderr}'")
|
|
636
|
+
elif exit_code == 2:
|
|
637
|
+
return False
|
|
638
|
+
raise ValueError(f"Fatal error occurrs while checking whether folder '{path}' exists. StdErr: '{stderr}'")
|
|
639
|
+
|
|
640
|
+
@GeneralUtilities.check_arguments
|
|
641
|
+
def is_git_repository(self, folder: str) -> bool:
|
|
642
|
+
combined = f"{folder}/.git"
|
|
643
|
+
# TODO consider check for bare-repositories
|
|
644
|
+
return self.is_file(combined) or self.is_folder(combined)
|
|
645
|
+
|
|
646
|
+
@GeneralUtilities.check_arguments
|
|
647
|
+
def assert_is_git_repository(self, folder: str) -> str:
|
|
648
|
+
GeneralUtilities.assert_condition(self.is_git_repository(folder), f"'{folder}' is not a git-repository.")
|
|
649
|
+
|
|
612
650
|
@GeneralUtilities.check_arguments
|
|
613
651
|
def __sort_fmd(self, line: str):
|
|
614
652
|
splitted: list = line.split(";")
|
|
@@ -715,8 +753,8 @@ class ScriptCollectionCore:
|
|
|
715
753
|
|
|
716
754
|
@GeneralUtilities.check_arguments
|
|
717
755
|
def extract_pdf_pages(self, file: str, from_page: int, to_page: int, outputfile: str) -> None:
|
|
718
|
-
pdf_reader =
|
|
719
|
-
pdf_writer =
|
|
756
|
+
pdf_reader: PdfReader = PdfReader(file)
|
|
757
|
+
pdf_writer: PdfWriter = PdfWriter()
|
|
720
758
|
start = from_page
|
|
721
759
|
end = to_page
|
|
722
760
|
while start <= end:
|
|
@@ -728,11 +766,13 @@ class ScriptCollectionCore:
|
|
|
728
766
|
@GeneralUtilities.check_arguments
|
|
729
767
|
def merge_pdf_files(self, files: list[str], outputfile: str) -> None:
|
|
730
768
|
# TODO add wildcard-option
|
|
731
|
-
pdfFileMerger =
|
|
769
|
+
pdfFileMerger: PdfWriter = PdfWriter()
|
|
732
770
|
for file in files:
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
771
|
+
with open(file, "rb") as f:
|
|
772
|
+
pdfFileMerger.append(f)
|
|
773
|
+
with open(outputfile, "wb") as output:
|
|
774
|
+
pdfFileMerger.write(output)
|
|
775
|
+
pdfFileMerger.close()
|
|
736
776
|
|
|
737
777
|
@GeneralUtilities.check_arguments
|
|
738
778
|
def pdf_to_image(self, file: str, outputfilename_without_extension: str) -> None:
|
|
@@ -1120,7 +1160,7 @@ class ScriptCollectionCore:
|
|
|
1120
1160
|
return tor_version
|
|
1121
1161
|
|
|
1122
1162
|
def run_testcases_for_python_project(self, repository_folder: str):
|
|
1123
|
-
|
|
1163
|
+
self.assert_is_git_repository(repository_folder)
|
|
1124
1164
|
self.run_program("coverage", "run -m pytest", repository_folder)
|
|
1125
1165
|
self.run_program("coverage", "xml", repository_folder)
|
|
1126
1166
|
GeneralUtilities.ensure_directory_exists(os.path.join(repository_folder, "Other/TestCoverage"))
|
|
@@ -1534,7 +1574,7 @@ class ScriptCollectionCore:
|
|
|
1534
1574
|
|
|
1535
1575
|
@GeneralUtilities.check_arguments
|
|
1536
1576
|
def get_semver_version_from_gitversion(self, repository_folder: str) -> str:
|
|
1537
|
-
|
|
1577
|
+
self.assert_is_git_repository(repository_folder)
|
|
1538
1578
|
if (self.git_repository_has_commits(repository_folder)):
|
|
1539
1579
|
result = self.get_version_from_gitversion(repository_folder, "MajorMinorPatch")
|
|
1540
1580
|
if self.git_repository_has_uncommitted_changes(repository_folder):
|
|
@@ -1569,7 +1609,7 @@ class ScriptCollectionCore:
|
|
|
1569
1609
|
if password is None:
|
|
1570
1610
|
password = GeneralUtilities.generate_password()
|
|
1571
1611
|
GeneralUtilities.ensure_directory_exists(folder)
|
|
1572
|
-
self.
|
|
1612
|
+
self.run_program_argsasarray("openssl", ['req', '-new', '-newkey', 'ec', '-pkeyopt', 'ec_paramgen_curve:prime256v1', '-days', str(days_until_expire), '-nodes', '-x509', '-subj', f'/C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={name}/OU={subj_ou}', '-passout', f'pass:{password}', '-keyout', f'{name}.key', '-out', f'{name}.crt'], folder)
|
|
1573
1613
|
|
|
1574
1614
|
@GeneralUtilities.check_arguments
|
|
1575
1615
|
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:
|
|
@@ -1578,9 +1618,9 @@ class ScriptCollectionCore:
|
|
|
1578
1618
|
if password is None:
|
|
1579
1619
|
password = GeneralUtilities.generate_password()
|
|
1580
1620
|
rsa_key_length = 4096
|
|
1581
|
-
self.
|
|
1582
|
-
self.
|
|
1583
|
-
self.
|
|
1621
|
+
self.run_program_argsasarray("openssl", ['genrsa', '-out', f'{filename}.key', f'{rsa_key_length}'], folder)
|
|
1622
|
+
self.run_program_argsasarray("openssl", ['req', '-new', '-subj', f'/C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou}', '-x509', '-key', f'{filename}.key', '-out', f'{filename}.unsigned.crt', '-days', f'{days_until_expire}'], folder)
|
|
1623
|
+
self.run_program_argsasarray("openssl", ['pkcs12', '-export', '-out', f'{filename}.selfsigned.pfx', '-password', f'pass:{password}', '-inkey', f'{filename}.key', '-in', f'{filename}.unsigned.crt'], folder)
|
|
1584
1624
|
GeneralUtilities.write_text_to_file(os.path.join(folder, f"{filename}.password"), password)
|
|
1585
1625
|
GeneralUtilities.write_text_to_file(os.path.join(folder, f"{filename}.san.conf"), f"""[ req ]
|
|
1586
1626
|
default_bits = {rsa_key_length}
|
|
@@ -1607,7 +1647,7 @@ DNS = {domain}
|
|
|
1607
1647
|
|
|
1608
1648
|
@GeneralUtilities.check_arguments
|
|
1609
1649
|
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:
|
|
1610
|
-
self.
|
|
1650
|
+
self.run_program_argsasarray("openssl", ['req', '-new', '-subj', f'/C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou}', '-key', f'{filename}.key', f'-out', f'{filename}.csr', f'-config', f'{filename}.san.conf'], folder)
|
|
1611
1651
|
|
|
1612
1652
|
@GeneralUtilities.check_arguments
|
|
1613
1653
|
def sign_certificate(self, folder: str, ca_folder: str, ca_name: str, domain: str, filename: str, days_until_expire: int = None) -> None:
|
|
@@ -1616,8 +1656,8 @@ DNS = {domain}
|
|
|
1616
1656
|
ca = os.path.join(ca_folder, ca_name)
|
|
1617
1657
|
password_file = os.path.join(folder, f"{filename}.password")
|
|
1618
1658
|
password = GeneralUtilities.read_text_from_file(password_file)
|
|
1619
|
-
self.
|
|
1620
|
-
self.
|
|
1659
|
+
self.run_program_argsasarray("openssl", ['x509', '-req', '-in', f'{filename}.csr', '-CA', f'{ca}.crt', '-CAkey', f'{ca}.key', '-CAcreateserial', '-CAserial', f'{ca}.srl', '-out', f'{filename}.crt', '-days', str(days_until_expire), '-sha256', '-extensions', 'v3_req', '-extfile', f'{filename}.san.conf'], folder)
|
|
1660
|
+
self.run_program_argsasarray("openssl", ['pkcs12', '-export', '-out', f'{filename}.pfx', f'-inkey', f'{filename}.key', '-in', f'{filename}.crt', '-password', f'pass:{password}'], folder)
|
|
1621
1661
|
|
|
1622
1662
|
@GeneralUtilities.check_arguments
|
|
1623
1663
|
def update_dependencies_of_python_in_requirementstxt_file(self, file: str, verbosity: int):
|
|
@@ -1984,3 +2024,43 @@ TXDX
|
|
|
1984
2024
|
@GeneralUtilities.check_arguments
|
|
1985
2025
|
def create_local_docker_network(self, network_name: str) -> None:
|
|
1986
2026
|
self.run_program("docker", f"network create {network_name}")
|
|
2027
|
+
|
|
2028
|
+
@GeneralUtilities.check_arguments
|
|
2029
|
+
def create_file(self, path: str, error_if_already_exists: bool, create_necessary_folder: bool) -> None:
|
|
2030
|
+
if not os.path.isabs(path):
|
|
2031
|
+
path = os.path.join(os.getcwd(), path)
|
|
2032
|
+
|
|
2033
|
+
if os.path.isfile(path) and error_if_already_exists:
|
|
2034
|
+
raise ValueError(f"File '{path}' already exists.")
|
|
2035
|
+
|
|
2036
|
+
# TODO maybe it should be checked if there is a folder with the same path which already exists.
|
|
2037
|
+
|
|
2038
|
+
folder = os.path.dirname(path)
|
|
2039
|
+
|
|
2040
|
+
if not os.path.isdir(folder):
|
|
2041
|
+
if create_necessary_folder:
|
|
2042
|
+
GeneralUtilities.ensure_directory_exists(folder) # TODO check if this also create nested folders if required
|
|
2043
|
+
else:
|
|
2044
|
+
raise ValueError(f"Folder '{folder}' does not exist.")
|
|
2045
|
+
|
|
2046
|
+
GeneralUtilities.ensure_file_exists(path)
|
|
2047
|
+
|
|
2048
|
+
@GeneralUtilities.check_arguments
|
|
2049
|
+
def create_folder(self, path: str, error_if_already_exists: bool, create_necessary_folder: bool) -> None:
|
|
2050
|
+
if not os.path.isabs(path):
|
|
2051
|
+
path = os.path.join(os.getcwd(), path)
|
|
2052
|
+
|
|
2053
|
+
if os.path.isdir(path) and error_if_already_exists:
|
|
2054
|
+
raise ValueError(f"Folder '{path}' already exists.")
|
|
2055
|
+
|
|
2056
|
+
# TODO maybe it should be checked if there is a file with the same path which already exists.
|
|
2057
|
+
|
|
2058
|
+
folder = os.path.dirname(path)
|
|
2059
|
+
|
|
2060
|
+
if not os.path.isdir(folder):
|
|
2061
|
+
if create_necessary_folder:
|
|
2062
|
+
GeneralUtilities.ensure_directory_exists(folder) # TODO check if this also create nested folders if required
|
|
2063
|
+
else:
|
|
2064
|
+
raise ValueError(f"Folder '{folder}' does not exist.")
|
|
2065
|
+
|
|
2066
|
+
GeneralUtilities.ensure_directory_exists(path)
|