ScriptCollection 3.5.92__py3-none-any.whl → 3.5.94__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 +9 -0
- ScriptCollection/GeneralUtilities.py +47 -11
- ScriptCollection/SCLog.py +2 -0
- ScriptCollection/ScriptCollectionCore.py +11 -5
- ScriptCollection/TasksForCommonProjectStructure.py +145 -20
- {scriptcollection-3.5.92.dist-info → scriptcollection-3.5.94.dist-info}/METADATA +2 -2
- scriptcollection-3.5.94.dist-info/RECORD +17 -0
- {scriptcollection-3.5.92.dist-info → scriptcollection-3.5.94.dist-info}/WHEEL +1 -1
- {scriptcollection-3.5.92.dist-info → scriptcollection-3.5.94.dist-info}/entry_points.txt +1 -0
- scriptcollection-3.5.92.dist-info/RECORD +0 -16
- {scriptcollection-3.5.92.dist-info → scriptcollection-3.5.94.dist-info}/top_level.txt +0 -0
ScriptCollection/Executables.py
CHANGED
@@ -619,3 +619,12 @@ def NpmI() -> int:
|
|
619
619
|
t = TasksForCommonProjectStructure()
|
620
620
|
t.do_npm_install(folder, args.force, 3 if args.verbose else 0)
|
621
621
|
return 0
|
622
|
+
|
623
|
+
|
624
|
+
def CurrentUserHasElevatedPrivileges() -> int:
|
625
|
+
parser = argparse.ArgumentParser(description="Returns 1 if the current user has elevated privileges. Otherwise this function returns 0.")
|
626
|
+
parser.parse_args()
|
627
|
+
if GeneralUtilities.current_user_has_elevated_privileges():
|
628
|
+
return 1
|
629
|
+
else:
|
630
|
+
return 0
|
@@ -348,29 +348,60 @@ class GeneralUtilities:
|
|
348
348
|
@staticmethod
|
349
349
|
@check_arguments
|
350
350
|
def ends_with_newline_character(content: bytes) -> bool:
|
351
|
-
|
351
|
+
result = content.endswith(GeneralUtilities.string_to_bytes("\n"))
|
352
|
+
return result
|
352
353
|
|
353
354
|
@staticmethod
|
354
355
|
@check_arguments
|
355
|
-
def
|
356
|
+
def file_ends_with_content(file: str) -> bool:
|
356
357
|
content = GeneralUtilities.read_binary_from_file(file)
|
357
358
|
if len(content) == 0:
|
358
|
-
return
|
359
|
+
return False
|
359
360
|
else:
|
360
361
|
if GeneralUtilities.ends_with_newline_character(content):
|
361
|
-
return
|
362
|
+
return False
|
362
363
|
else:
|
363
|
-
return
|
364
|
+
return True
|
365
|
+
|
366
|
+
@staticmethod
|
367
|
+
@check_arguments
|
368
|
+
def get_new_line_character_for_textfile_if_required(file: str) -> bool:
|
369
|
+
if GeneralUtilities.file_ends_with_content(file):
|
370
|
+
return "\n"
|
371
|
+
else:
|
372
|
+
return ""
|
364
373
|
|
365
374
|
@staticmethod
|
366
375
|
@check_arguments
|
367
376
|
def append_line_to_file(file: str, line: str, encoding: str = "utf-8") -> None:
|
368
|
-
|
369
|
-
|
377
|
+
GeneralUtilities.append_lines_to_file(file, [line], encoding)
|
378
|
+
|
379
|
+
@staticmethod
|
380
|
+
@check_arguments
|
381
|
+
def append_lines_to_file(file: str, lines: list[str], encoding: str = "utf-8") -> None:
|
382
|
+
if len(lines) == 0:
|
383
|
+
return
|
384
|
+
is_first_line = True
|
385
|
+
for line in lines:
|
386
|
+
insert_linebreak: bool
|
387
|
+
if is_first_line:
|
388
|
+
insert_linebreak = GeneralUtilities.file_ends_with_content(file)
|
389
|
+
else:
|
390
|
+
insert_linebreak = True
|
391
|
+
line_to_write: str = None
|
392
|
+
if insert_linebreak:
|
393
|
+
line_to_write = "\n"+line
|
394
|
+
else:
|
395
|
+
line_to_write = line
|
396
|
+
with open(file, "r+b") as fileObject:
|
397
|
+
fileObject.seek(0, os.SEEK_END)
|
398
|
+
fileObject.write(GeneralUtilities.string_to_bytes(line_to_write, encoding))
|
399
|
+
is_first_line = False
|
370
400
|
|
371
401
|
@staticmethod
|
372
402
|
@check_arguments
|
373
403
|
def append_to_file(file: str, content: str, encoding: str = "utf-8") -> None:
|
404
|
+
GeneralUtilities.assert_condition(not "\n" in content, "Appending multiple lines is not allowed. Use append_lines_to_file instead.")
|
374
405
|
with open(file, "a", encoding=encoding) as fileObject:
|
375
406
|
fileObject.write(content)
|
376
407
|
|
@@ -508,6 +539,11 @@ class GeneralUtilities:
|
|
508
539
|
def read_lines_from_file(file: str, encoding="utf-8") -> list[str]:
|
509
540
|
return [GeneralUtilities.strip_new_line_character(line) for line in GeneralUtilities.read_text_from_file(file, encoding).split('\n')]
|
510
541
|
|
542
|
+
@staticmethod
|
543
|
+
@check_arguments
|
544
|
+
def read_nonempty_lines_from_file(file: str, encoding="utf-8") -> list[str]:
|
545
|
+
return [line for line in GeneralUtilities.read_lines_from_file(file, encoding) if GeneralUtilities.string_has_content(line)]
|
546
|
+
|
511
547
|
@staticmethod
|
512
548
|
@check_arguments
|
513
549
|
def read_text_from_file(file: str, encoding="utf-8") -> str:
|
@@ -960,20 +996,20 @@ class GeneralUtilities:
|
|
960
996
|
|
961
997
|
@staticmethod
|
962
998
|
@check_arguments
|
963
|
-
def retry_action(action, amount_of_attempts: int,action_name:str=None) -> None:
|
999
|
+
def retry_action(action, amount_of_attempts: int, action_name: str = None) -> None:
|
964
1000
|
amount_of_fails = 0
|
965
1001
|
enabled = True
|
966
1002
|
while enabled:
|
967
1003
|
try:
|
968
|
-
result=action()
|
1004
|
+
result = action()
|
969
1005
|
return result
|
970
1006
|
except Exception:
|
971
1007
|
amount_of_fails = amount_of_fails+1
|
972
1008
|
GeneralUtilities.assert_condition(not (amount_of_attempts < amount_of_fails))
|
973
1009
|
if amount_of_fails == amount_of_attempts:
|
974
|
-
message=f"Action failed {amount_of_attempts} times."
|
1010
|
+
message = f"Action failed {amount_of_attempts} times."
|
975
1011
|
if action_name is not None:
|
976
|
-
message=f"{message} Name of action: {action_name}"
|
1012
|
+
message = f"{message} Name of action: {action_name}"
|
977
1013
|
GeneralUtilities.write_message_to_stderr(message)
|
978
1014
|
raise
|
979
1015
|
return None
|
@@ -12,6 +12,7 @@ import math
|
|
12
12
|
import os
|
13
13
|
from queue import Queue, Empty
|
14
14
|
from concurrent.futures import ThreadPoolExecutor
|
15
|
+
import xml.etree.ElementTree as ET
|
15
16
|
from pathlib import Path
|
16
17
|
from subprocess import Popen
|
17
18
|
import re
|
@@ -32,7 +33,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
|
|
32
33
|
from .ProgramRunnerPopen import ProgramRunnerPopen
|
33
34
|
from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
|
34
35
|
|
35
|
-
version = "3.5.
|
36
|
+
version = "3.5.94"
|
36
37
|
__version__ = version
|
37
38
|
|
38
39
|
|
@@ -2052,7 +2053,7 @@ chmod {permission} {link_file}
|
|
2052
2053
|
if productname is None:
|
2053
2054
|
productname = os.path.basename(repository)
|
2054
2055
|
if subfolder is None:
|
2055
|
-
subfolder = "Other/
|
2056
|
+
subfolder = "Other/Reference"
|
2056
2057
|
reference_root_folder = f"{repository}/{subfolder}"
|
2057
2058
|
reference_content_folder = reference_root_folder + "/Technical"
|
2058
2059
|
if os.path.isdir(reference_root_folder):
|
@@ -2109,8 +2110,7 @@ TXDX
|
|
2109
2110
|
|
2110
2111
|
## Deployment-proecsses
|
2111
2112
|
|
2112
|
-
TXDX
|
2113
|
-
""")
|
2113
|
+
TXDX""")
|
2114
2114
|
self.__add_chapter(main_reference_file, reference_content_folder, 8, 'Crosscutting Concepts', """TXDX""")
|
2115
2115
|
self.__add_chapter(main_reference_file, reference_content_folder, 9, 'Architectural Decisions', """## Decision-board
|
2116
2116
|
|
@@ -2153,7 +2153,6 @@ TXDX
|
|
2153
2153
|
- [Repository](TXDX)
|
2154
2154
|
- [Productive-System](TXDX)
|
2155
2155
|
- [QualityCheck-system](TXDX)
|
2156
|
-
|
2157
2156
|
""".replace("XDX", "ODO"))
|
2158
2157
|
|
2159
2158
|
@GeneralUtilities.check_arguments
|
@@ -2243,3 +2242,10 @@ TXDX
|
|
2243
2242
|
raise ValueError(f"Folder '{folder}' does not exist.")
|
2244
2243
|
|
2245
2244
|
GeneralUtilities.ensure_directory_exists(path)
|
2245
|
+
|
2246
|
+
@GeneralUtilities.check_arguments
|
2247
|
+
def format_xml_file(self, file: str) -> None:
|
2248
|
+
encoding = "utf-8"
|
2249
|
+
element = ET.XML(GeneralUtilities.read_text_from_file(file, encoding))
|
2250
|
+
ET.indent(element)
|
2251
|
+
GeneralUtilities.write_text_to_file(file, ET.tostring(element, encoding="unicode"), encoding)
|
@@ -307,6 +307,7 @@ class TasksForCommonProjectStructure:
|
|
307
307
|
@GeneralUtilities.check_arguments
|
308
308
|
def generate_bom_for_python_project(self, verbosity: int, codeunit_folder: str, codeunitname: str, commandline_arguments: list[str]) -> None:
|
309
309
|
self.assert_is_codeunit_folder(codeunit_folder)
|
310
|
+
repository_folder = os.path.dirname(codeunit_folder)
|
310
311
|
verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
|
311
312
|
codeunitversion = self.get_version_of_codeunit_folder(codeunit_folder)
|
312
313
|
bom_folder = "Other/Artifacts/BOM"
|
@@ -316,9 +317,20 @@ class TasksForCommonProjectStructure:
|
|
316
317
|
raise ValueError(f"Codeunit {codeunitname} does not have a 'requirements.txt'-file.")
|
317
318
|
# TODO check that all values from setup.cfg are contained in requirements.txt
|
318
319
|
result = self.__sc.run_program("cyclonedx-py", "requirements", codeunit_folder, verbosity=verbosity)
|
319
|
-
|
320
|
-
|
321
|
-
|
320
|
+
bom_file_relative_json = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.json"
|
321
|
+
bom_file_relative_xml = f"{bom_folder}/{codeunitname}.{codeunitversion}.bom.xml"
|
322
|
+
bom_file_json = os.path.join(codeunit_folder, bom_file_relative_json)
|
323
|
+
bom_file_xml = os.path.join(codeunit_folder, bom_file_relative_xml)
|
324
|
+
|
325
|
+
GeneralUtilities.ensure_file_exists(bom_file_json)
|
326
|
+
GeneralUtilities.write_text_to_file(bom_file_json, result[1])
|
327
|
+
self.ensure_cyclonedxcli_is_available(repository_folder)
|
328
|
+
cyclonedx_exe = os.path.join(repository_folder, "Other/Resources/CycloneDXCLI/cyclonedx-cli")
|
329
|
+
if GeneralUtilities.current_system_is_windows():
|
330
|
+
cyclonedx_exe = cyclonedx_exe+".exe"
|
331
|
+
self.__sc.run_program(cyclonedx_exe, f"convert --input-file ./{codeunitname}/{bom_file_relative_json} --input-format json --output-file ./{codeunitname}/{bom_file_relative_xml} --output-format xml", repository_folder)
|
332
|
+
self.__sc.format_xml_file(bom_file_xml)
|
333
|
+
GeneralUtilities.ensure_file_does_not_exist(bom_file_json)
|
322
334
|
|
323
335
|
@GeneralUtilities.check_arguments
|
324
336
|
def standardized_tasks_push_wheel_file_to_registry(self, wheel_file: str, api_key: str, repository: str, gpg_identity: str, verbosity: int) -> None:
|
@@ -759,6 +771,7 @@ class TasksForCommonProjectStructure:
|
|
759
771
|
target = f"{codeunit_folder}\\{bomfile_folder}\\{codeunit_name}.{codeunitversion}.sbom.xml"
|
760
772
|
GeneralUtilities.ensure_file_does_not_exist(target)
|
761
773
|
os.rename(f"{codeunit_folder}\\{bomfile_folder}\\bom.xml", target)
|
774
|
+
self.__sc.format_xml_file(target)
|
762
775
|
|
763
776
|
@GeneralUtilities.check_arguments
|
764
777
|
def standardized_tasks_run_linting_for_flutter_project_in_common_project_structure(self, script_file: str, default_verbosity: int, args: list[str]):
|
@@ -1338,12 +1351,38 @@ class TasksForCommonProjectStructure:
|
|
1338
1351
|
@GeneralUtilities.check_arguments
|
1339
1352
|
def standardized_tasks_build_for_docker_project(self, build_script_file: str, target_environment_type: str, verbosity: int, commandline_arguments: list[str]) -> None:
|
1340
1353
|
self.standardized_tasks_build_for_docker_project_with_additional_build_arguments(build_script_file, target_environment_type, verbosity, commandline_arguments, dict[str, str]())
|
1354
|
+
self.generate_sbom_for_docker_image(build_script_file, verbosity, commandline_arguments)
|
1355
|
+
|
1356
|
+
@GeneralUtilities.check_arguments
|
1357
|
+
def merge_sbom_file_from_dependent_codeunit_into_this(self, build_script_file: str, dependent_codeunit_name: str) -> None:
|
1358
|
+
codeunitname: str = Path(os.path.dirname(build_script_file)).parent.parent.name
|
1359
|
+
codeunit_folder = GeneralUtilities.resolve_relative_path("../..", str(os.path.dirname(build_script_file)))
|
1360
|
+
repository_folder = GeneralUtilities.resolve_relative_path("..", codeunit_folder)
|
1361
|
+
dependent_codeunit_folder = os.path.join(repository_folder, dependent_codeunit_name).replace("\\", "/")
|
1362
|
+
t = TasksForCommonProjectStructure()
|
1363
|
+
sbom_file = f"{codeunitname}/Other/Artifacts/BOM/{codeunitname}.{t.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml"
|
1364
|
+
dependent_sbom_file = f"{dependent_codeunit_name}/Other/Artifacts/BOM/{dependent_codeunit_name}.{t.get_version_of_codeunit_folder(dependent_codeunit_folder)}.sbom.xml"
|
1365
|
+
self.merge_sbom_file(repository_folder, dependent_sbom_file, sbom_file)
|
1366
|
+
|
1367
|
+
@GeneralUtilities.check_arguments
|
1368
|
+
def merge_sbom_file(self, repository_folder: str, source_sbom_file: str, target_sbom_file: str) -> None:
|
1369
|
+
GeneralUtilities.assert_file_exists(os.path.join(repository_folder, source_sbom_file))
|
1370
|
+
GeneralUtilities.assert_file_exists(os.path.join(repository_folder, target_sbom_file))
|
1371
|
+
target_original_sbom_file = os.path.dirname(target_sbom_file)+"/"+os.path.basename(target_sbom_file)+".original.xml"
|
1372
|
+
os.rename(os.path.join(repository_folder, target_sbom_file), os.path.join(repository_folder, target_original_sbom_file))
|
1373
|
+
|
1374
|
+
self.ensure_cyclonedxcli_is_available(repository_folder)
|
1375
|
+
cyclonedx_exe = os.path.join(repository_folder, "Other/Resources/CycloneDXCLI/cyclonedx-cli")
|
1376
|
+
if GeneralUtilities.current_system_is_windows():
|
1377
|
+
cyclonedx_exe = cyclonedx_exe+".exe"
|
1378
|
+
self.__sc.run_program("cyclonedx_exe", f"merge --input-files {source_sbom_file} {target_original_sbom_file} --output-file {target_sbom_file}")
|
1379
|
+
GeneralUtilities.ensure_file_does_not_exist(os.path.join(repository_folder, target_original_sbom_file))
|
1380
|
+
self.__sc.format_xml_file(target_original_sbom_file)
|
1341
1381
|
|
1342
1382
|
@GeneralUtilities.check_arguments
|
1343
1383
|
def standardized_tasks_build_for_docker_project_with_additional_build_arguments(self, build_script_file: str, target_environment_type: str, verbosity: int, commandline_arguments: list[str], custom_arguments: dict[str, str]) -> None:
|
1344
1384
|
use_cache: bool = False
|
1345
1385
|
verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
|
1346
|
-
sc: ScriptCollectionCore = ScriptCollectionCore()
|
1347
1386
|
codeunitname: str = Path(os.path.dirname(build_script_file)).parent.parent.name
|
1348
1387
|
codeunit_folder = GeneralUtilities.resolve_relative_path("../..", str(os.path.dirname(build_script_file)))
|
1349
1388
|
codeunitname_lower = codeunitname.lower()
|
@@ -1358,7 +1397,7 @@ class TasksForCommonProjectStructure:
|
|
1358
1397
|
args.append("--no-cache")
|
1359
1398
|
args.append(".")
|
1360
1399
|
codeunit_content_folder = os.path.join(codeunit_folder)
|
1361
|
-
|
1400
|
+
self.__sc.run_program_argsasarray("docker", args, codeunit_content_folder, verbosity=verbosity, print_errors_as_information=True)
|
1362
1401
|
artifacts_folder = GeneralUtilities.resolve_relative_path("Other/Artifacts", codeunit_folder)
|
1363
1402
|
app_artifacts_folder = os.path.join(artifacts_folder, "BuildResult_OCIImage")
|
1364
1403
|
GeneralUtilities.ensure_directory_does_not_exist(app_artifacts_folder)
|
@@ -1377,6 +1416,7 @@ class TasksForCommonProjectStructure:
|
|
1377
1416
|
codeunitversion = self.get_version_of_codeunit(os.path.join(codeunit_folder, f"{codeunitname}.codeunit.xml"))
|
1378
1417
|
GeneralUtilities.ensure_directory_exists(sbom_folder)
|
1379
1418
|
self.__sc.run_program_argsasarray("docker", ["sbom", "--format", "cyclonedx", f"{codeunitname_lower}:{codeunitversion}", "--output", f"{codeunitname}.{codeunitversion}.sbom.xml"], sbom_folder, verbosity=verbosity, print_errors_as_information=True)
|
1419
|
+
self.__sc.format_xml_file(sbom_folder+f"/{codeunitname}.{codeunitversion}.sbom.xml")
|
1380
1420
|
|
1381
1421
|
@GeneralUtilities.check_arguments
|
1382
1422
|
def push_docker_build_artifact(self, push_artifacts_file: str, registry: str, verbosity: int, push_readme: bool, commandline_arguments: list[str], repository_folder_name: str) -> None:
|
@@ -1527,6 +1567,8 @@ class TasksForCommonProjectStructure:
|
|
1527
1567
|
author_emailaddress = expected_author.xpath('./cps:developeremailaddress/text()', namespaces=namespaces)[0]
|
1528
1568
|
expected_authors.append((author_name, author_emailaddress))
|
1529
1569
|
actual_authors: list[tuple[str, str]] = self.__sc.get_all_authors_and_committers_of_repository(repository_folder, codeunit_name, verbosity)
|
1570
|
+
# TODO refactor this check to only check commits which are behind this but which are not already on main
|
1571
|
+
# TODO verify also if the commit is signed by a valid key of the author
|
1530
1572
|
for actual_author in actual_authors:
|
1531
1573
|
if not (actual_author) in expected_authors:
|
1532
1574
|
actual_author_formatted = f"{actual_author[0]} <{actual_author[1]}>"
|
@@ -1704,7 +1746,9 @@ class TasksForCommonProjectStructure:
|
|
1704
1746
|
def standardized_tasks_build_bom_for_node_project(self, codeunit_folder: str, verbosity: int, commandline_arguments: list[str]) -> None:
|
1705
1747
|
self.assert_is_codeunit_folder(codeunit_folder)
|
1706
1748
|
verbosity = TasksForCommonProjectStructure.get_verbosity_from_commandline_arguments(commandline_arguments, verbosity)
|
1707
|
-
|
1749
|
+
relative_path_to_bom_file = f"Other/Artifacts/BOM/{os.path.basename(codeunit_folder)}.{self.get_version_of_codeunit_folder(codeunit_folder)}.sbom.xml"
|
1750
|
+
self.run_with_epew("cyclonedx-npm", f"--output-format xml --output-file {relative_path_to_bom_file}", codeunit_folder, verbosity=verbosity)
|
1751
|
+
self.__sc.format_xml_file(codeunit_folder+"/"+relative_path_to_bom_file)
|
1708
1752
|
|
1709
1753
|
@GeneralUtilities.check_arguments
|
1710
1754
|
def standardized_tasks_linting_for_angular_codeunit(self, linting_script_file: str, verbosity: int, build_environment_target_type: str, commandline_arguments: list[str]) -> None:
|
@@ -2509,11 +2553,10 @@ class TasksForCommonProjectStructure:
|
|
2509
2553
|
i = i+1
|
2510
2554
|
GeneralUtilities.write_message_to_stdout(f"{i}.: {codeunit}")
|
2511
2555
|
self.__do_repository_checks(repository_folder, project_version)
|
2512
|
-
line = "----------"
|
2513
2556
|
for codeunit in sorted_codeunits:
|
2514
|
-
GeneralUtilities.write_message_to_stdout(
|
2557
|
+
GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_line())
|
2515
2558
|
self.__build_codeunit(os.path.join(repository_folder, codeunit), verbosity, target_environmenttype, additional_arguments_file, is_pre_merge, assume_dependent_codeunits_are_already_built, commandline_arguments)
|
2516
|
-
GeneralUtilities.write_message_to_stdout(
|
2559
|
+
GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_line())
|
2517
2560
|
contains_uncommitted_changes_at_end = self.__sc.git_repository_has_uncommitted_changes(repository_folder)
|
2518
2561
|
if contains_uncommitted_changes_at_end and not is_pre_merge:
|
2519
2562
|
if contains_uncommitted_changes_at_begin:
|
@@ -2524,6 +2567,7 @@ class TasksForCommonProjectStructure:
|
|
2524
2567
|
GeneralUtilities.write_message_to_stderr(f"Warning: {message}")
|
2525
2568
|
else:
|
2526
2569
|
raise ValueError(message)
|
2570
|
+
|
2527
2571
|
if export_target_directory is not None:
|
2528
2572
|
project_name = self.get_project_name(repository_folder)
|
2529
2573
|
for codeunit in sorted_codeunits:
|
@@ -2547,9 +2591,14 @@ class TasksForCommonProjectStructure:
|
|
2547
2591
|
self.__sc.assert_is_git_repository(repository_folder)
|
2548
2592
|
self.__check_if_changelog_exists(repository_folder, project_version)
|
2549
2593
|
self.__check_whether_security_txt_exists(repository_folder)
|
2594
|
+
self.__check_whether_general_reference_exists(repository_folder)
|
2550
2595
|
self.__check_whether_workspace_file_exists(repository_folder)
|
2551
2596
|
self.__check_for_staged_or_committed_ignored_files(repository_folder)
|
2552
2597
|
|
2598
|
+
@GeneralUtilities.check_arguments
|
2599
|
+
def __check_whether_general_reference_exists(self, repository_folder: str) -> None:
|
2600
|
+
GeneralUtilities.assert_file_exists(os.path.join(repository_folder, "Other", "Reference", "Reference.md"))
|
2601
|
+
|
2553
2602
|
@GeneralUtilities.check_arguments
|
2554
2603
|
def __check_if_changelog_exists(self, repository_folder: str, project_version: str) -> None:
|
2555
2604
|
self.__sc.assert_is_git_repository(repository_folder)
|
@@ -2564,6 +2613,8 @@ class TasksForCommonProjectStructure:
|
|
2564
2613
|
security_txt_file = GeneralUtilities.resolve_relative_path(security_txt_file_relative, repository_folder)
|
2565
2614
|
if not os.path.isfile(security_txt_file):
|
2566
2615
|
raise ValueError(f"The repository does not contain a '{security_txt_file_relative}'-file. See https://securitytxt.org/ for more information.")
|
2616
|
+
# TODO throw error if the date set in the file is expired
|
2617
|
+
# TODO write wartning if the date set in the file expires soon
|
2567
2618
|
|
2568
2619
|
@GeneralUtilities.check_arguments
|
2569
2620
|
def __check_for_staged_or_committed_ignored_files(self, repository_folder: str) -> None:
|
@@ -2664,6 +2715,17 @@ class TasksForCommonProjectStructure:
|
|
2664
2715
|
def ensure_androidappbundletool_is_available(self, target_folder: str) -> None:
|
2665
2716
|
self.ensure_file_from_github_assets_is_available(target_folder, "google", "bundletool", "AndroidAppBundleTool", "bundletool.jar", lambda latest_version: f"bundletool-all-{latest_version}.jar")
|
2666
2717
|
|
2718
|
+
@GeneralUtilities.check_arguments
|
2719
|
+
def ensure_cyclonedxcli_is_available(self, target_folder: str) -> None:
|
2720
|
+
local_filename = "cyclonedx-cli"
|
2721
|
+
filename_on_github: str
|
2722
|
+
if GeneralUtilities.current_system_is_windows():
|
2723
|
+
filename_on_github = "cyclonedx-win-x64.exe"
|
2724
|
+
local_filename = local_filename+".exe"
|
2725
|
+
else:
|
2726
|
+
filename_on_github = "cyclonedx-linux-x64"
|
2727
|
+
self.ensure_file_from_github_assets_is_available(target_folder, "CycloneDX", "cyclonedx-cli", "CycloneDXCLI", local_filename, lambda latest_version: filename_on_github)
|
2728
|
+
|
2667
2729
|
@GeneralUtilities.check_arguments
|
2668
2730
|
def ensure_file_from_github_assets_is_available(self, target_folder: str, githubuser: str, githubprojectname: str, resource_name: str, local_filename: str, get_filename_on_github) -> None:
|
2669
2731
|
resource_folder = os.path.join(target_folder, "Other", "Resources", resource_name)
|
@@ -2674,11 +2736,11 @@ class TasksForCommonProjectStructure:
|
|
2674
2736
|
GeneralUtilities.ensure_directory_does_not_exist(resource_folder)
|
2675
2737
|
GeneralUtilities.ensure_directory_exists(resource_folder)
|
2676
2738
|
headers = {'Cache-Control': 'no-cache'}
|
2677
|
-
response = requests.get(f"https://api.github.com/repos/{githubuser}/{githubprojectname}/releases/latest", timeout=
|
2678
|
-
latest_version = response.json()["
|
2739
|
+
response = requests.get(f"https://api.github.com/repos/{githubuser}/{githubprojectname}/releases/latest", timeout=10, headers=headers)
|
2740
|
+
latest_version = response.json()["tag_name"]
|
2679
2741
|
filename_on_github = get_filename_on_github(latest_version)
|
2680
|
-
|
2681
|
-
urllib.request.urlretrieve(
|
2742
|
+
link = f"https://github.com/{githubuser}/{githubprojectname}/releases/download/{latest_version}/{filename_on_github}"
|
2743
|
+
urllib.request.urlretrieve(link, file)
|
2682
2744
|
else:
|
2683
2745
|
if file_exists:
|
2684
2746
|
GeneralUtilities.write_message_to_stdout(f"Warning: Can not check for updates of {resource_name} due to missing internet-connection.")
|
@@ -2686,15 +2748,78 @@ class TasksForCommonProjectStructure:
|
|
2686
2748
|
raise ValueError(f"Can not download {resource_name}.")
|
2687
2749
|
|
2688
2750
|
@GeneralUtilities.check_arguments
|
2689
|
-
def
|
2690
|
-
self.
|
2691
|
-
|
2692
|
-
|
2751
|
+
def generate_svg_files_from_plantuml_files_for_repository(self, repository_folder: str) -> None:
|
2752
|
+
self.__sc.assert_is_git_repository(repository_folder)
|
2753
|
+
self.ensure_plantuml_is_available(repository_folder)
|
2754
|
+
plant_uml_folder = os.path.join(repository_folder, "Other", "Resources", "PlantUML")
|
2755
|
+
target_folder = os.path.join(repository_folder, "Other", "Reference")
|
2756
|
+
self.__generate_svg_files_from_plantuml(target_folder, plant_uml_folder)
|
2757
|
+
|
2758
|
+
@GeneralUtilities.check_arguments
|
2759
|
+
def generate_svg_files_from_plantuml_files_for_codeunit(self, codeunit_folder: str) -> None:
|
2760
|
+
self.assert_is_codeunit_folder(codeunit_folder)
|
2761
|
+
repository_folder = os.path.dirname(codeunit_folder)
|
2762
|
+
self.ensure_plantuml_is_available(repository_folder)
|
2763
|
+
plant_uml_folder = os.path.join(repository_folder, "Other", "Resources", "PlantUML")
|
2764
|
+
target_folder = os.path.join(codeunit_folder, "Other", "Reference")
|
2765
|
+
self.__generate_svg_files_from_plantuml(target_folder, plant_uml_folder)
|
2766
|
+
|
2767
|
+
@GeneralUtilities.check_arguments
|
2768
|
+
def __generate_svg_files_from_plantuml(self, diagrams_files_folder: str, plant_uml_folder: str) -> None:
|
2693
2769
|
sc = ScriptCollectionCore()
|
2694
|
-
for file in GeneralUtilities.get_all_files_of_folder(
|
2770
|
+
for file in GeneralUtilities.get_all_files_of_folder(diagrams_files_folder):
|
2695
2771
|
if file.endswith(".plantuml"):
|
2696
|
-
|
2697
|
-
|
2772
|
+
output_filename = self.get_output_filename_for_plantuml_filename(file)
|
2773
|
+
argument = ['-jar', f'{plant_uml_folder}/plantuml.jar', '-tsvg', os.path.basename(file)]
|
2774
|
+
folder = os.path.dirname(file)
|
2775
|
+
sc.run_program_argsasarray("java", argument, folder, verbosity=0)
|
2776
|
+
result_file = folder+"/" + output_filename
|
2777
|
+
GeneralUtilities.assert_file_exists(result_file)
|
2778
|
+
self.__sc.format_xml_file(result_file)
|
2779
|
+
|
2780
|
+
@GeneralUtilities.check_arguments
|
2781
|
+
def get_output_filename_for_plantuml_filename(self, plantuml_file: str) -> str:
|
2782
|
+
for line in GeneralUtilities.read_lines_from_file(plantuml_file):
|
2783
|
+
prefix = "@startuml "
|
2784
|
+
if line.startswith(prefix):
|
2785
|
+
title = line[len(prefix):]
|
2786
|
+
return title+".svg"
|
2787
|
+
return Path(plantuml_file).stem+".svg"
|
2788
|
+
|
2789
|
+
@GeneralUtilities.check_arguments
|
2790
|
+
def generate_codeunits_overview_diagram(self, repository_folder: str) -> None:
|
2791
|
+
self.__sc.assert_is_git_repository(repository_folder)
|
2792
|
+
project_name: str = os.path.basename(repository_folder)
|
2793
|
+
target_folder = os.path.join(repository_folder, "Other", "Reference", "Technical", "Diagrams")
|
2794
|
+
GeneralUtilities.ensure_directory_exists(target_folder)
|
2795
|
+
target_file = os.path.join(target_folder, "CodeUnits-Overview.plantuml")
|
2796
|
+
lines = ["@startuml CodeUnits-Overview"]
|
2797
|
+
lines.append(f"title CodeUnits of {project_name}")
|
2798
|
+
|
2799
|
+
codeunits = self.get_codeunits(repository_folder)
|
2800
|
+
for codeunitname in codeunits:
|
2801
|
+
codeunit_file: str = os.path.join(repository_folder, codeunitname, f"{codeunitname}.codeunit.xml")
|
2802
|
+
|
2803
|
+
description = self.get_codeunit_description(codeunit_file)
|
2804
|
+
|
2805
|
+
lines.append(f"")
|
2806
|
+
lines.append(f"[{codeunitname}]")
|
2807
|
+
lines.append(f"note as {codeunitname}Note")
|
2808
|
+
lines.append(f" {description}")
|
2809
|
+
lines.append(f"end note")
|
2810
|
+
lines.append(f"{codeunitname} .. {codeunitname}Note")
|
2811
|
+
|
2812
|
+
lines.append(f"")
|
2813
|
+
for codeunitname in codeunits:
|
2814
|
+
codeunit_file: str = os.path.join(repository_folder, codeunitname, f"{codeunitname}.codeunit.xml")
|
2815
|
+
dependent_codeunits = self.get_dependent_code_units(codeunit_file)
|
2816
|
+
for dependent_codeunit in dependent_codeunits:
|
2817
|
+
lines.append(f"{codeunitname} --> {dependent_codeunit}")
|
2818
|
+
|
2819
|
+
lines.append(f"")
|
2820
|
+
lines.append("@enduml")
|
2821
|
+
|
2822
|
+
GeneralUtilities.write_lines_to_file(target_file, lines)
|
2698
2823
|
|
2699
2824
|
@GeneralUtilities.check_arguments
|
2700
2825
|
def load_deb_control_file_content(self, file: str, codeunitname: str, codeunitversion: str, installedsize: int, maintainername: str, maintaineremail: str, description: str,) -> str:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ScriptCollection
|
3
|
-
Version: 3.5.
|
3
|
+
Version: 3.5.94
|
4
4
|
Summary: The ScriptCollection is the place for reusable scripts.
|
5
5
|
Home-page: https://github.com/anionDev/ScriptCollection
|
6
6
|
Author: Marius Göcke
|
@@ -33,7 +33,7 @@ Requires-Dist: ntplib>=0.4.0
|
|
33
33
|
Requires-Dist: Pillow>=11.1.0
|
34
34
|
Requires-Dist: pycdlib>=1.14.0
|
35
35
|
Requires-Dist: Pygments>=2.19.1
|
36
|
-
Requires-Dist: pylint>=3.3.
|
36
|
+
Requires-Dist: pylint>=3.3.5
|
37
37
|
Requires-Dist: pyOpenSSL>=25.0.0
|
38
38
|
Requires-Dist: PyPDF>=5.3.1
|
39
39
|
Requires-Dist: pytest>=8.3.5
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ScriptCollection/Executables.py,sha256=HI9Pxs5Z9QxPGyqeJU2lWslEggFyGYANCqYVQZp6eJ0,30490
|
2
|
+
ScriptCollection/GeneralUtilities.py,sha256=q0ikIwmhklCFsaaj9YGPGdrNonibuRmWofvbwOtlxdM,42246
|
3
|
+
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
4
|
+
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
5
|
+
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
6
|
+
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
7
|
+
ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
|
8
|
+
ScriptCollection/SCLog.py,sha256=l4aekBiGoNkKGtvO_Er3NY_K7ts4ZWtIGlhq07I-4LY,30
|
9
|
+
ScriptCollection/ScriptCollectionCore.py,sha256=kuiMlekPcD_BTbCjqKgsEQjeMWL7consYcplP1lTByU,123973
|
10
|
+
ScriptCollection/TasksForCommonProjectStructure.py,sha256=QqpfA-9sLtUogsOqg4uHHS2kucwZkTuzhDs24OdFIrE,225316
|
11
|
+
ScriptCollection/UpdateCertificates.py,sha256=Eynbgu7k9jLxApP2D_8Il77B6BFjJap6K7oTeEAZYbk,7790
|
12
|
+
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
+
scriptcollection-3.5.94.dist-info/METADATA,sha256=UrFm_ztejp_WXvuM7uom8cka14YxGvMC_wPzpf6rdjw,7664
|
14
|
+
scriptcollection-3.5.94.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
15
|
+
scriptcollection-3.5.94.dist-info/entry_points.txt,sha256=fYCGWGNGijBQHhFe6UAO-BEpfEOxLyNJemukt5ElSzs,3644
|
16
|
+
scriptcollection-3.5.94.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
17
|
+
scriptcollection-3.5.94.dist-info/RECORD,,
|
@@ -14,6 +14,7 @@ sccreatefolder = ScriptCollection.Executables:CreateFolder
|
|
14
14
|
sccreatehashofallfiles = ScriptCollection.Executables:CreateHashOfAllFiles
|
15
15
|
sccreateisofilewithobfuscatedfiles = ScriptCollection.Executables:CreateISOFileWithObfuscatedFiles
|
16
16
|
sccreatesimplemergewithoutrelease = ScriptCollection.Executables:CreateSimpleMergeWithoutRelease
|
17
|
+
sccurrentuserhaselevatedprivileges = ScriptCollection.Executables:CurrentUserHasElevatedPrivileges
|
17
18
|
scextractpdfpages = ScriptCollection.Executables:ExtractPDFPages
|
18
19
|
scfilecontainscontent = ScriptCollection.Executables:FileContainsContent
|
19
20
|
scfileexists = ScriptCollection.Executables:FileExists
|
@@ -1,16 +0,0 @@
|
|
1
|
-
ScriptCollection/Executables.py,sha256=ApfwgRftLeG1NBpv7Jad98Yb-wI8sKjhtoIsxMmfGVY,30167
|
2
|
-
ScriptCollection/GeneralUtilities.py,sha256=VVbbGFD4qLwWV211-E-n3faP2fZGc8mOBlKLd0oKHl4,40765
|
3
|
-
ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
|
4
|
-
ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
|
5
|
-
ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
|
6
|
-
ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
|
7
|
-
ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
|
8
|
-
ScriptCollection/ScriptCollectionCore.py,sha256=Qyo5uuSsVQIbwWxqGgyfetyVrZ2KO1yg_PlICIavTto,123626
|
9
|
-
ScriptCollection/TasksForCommonProjectStructure.py,sha256=YWHvLc91WuCrmay9qqf43onRhYy94nbd1sKLiBfNrZ4,217137
|
10
|
-
ScriptCollection/UpdateCertificates.py,sha256=Eynbgu7k9jLxApP2D_8Il77B6BFjJap6K7oTeEAZYbk,7790
|
11
|
-
ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
scriptcollection-3.5.92.dist-info/METADATA,sha256=lsBwVdHT7ePQ2yjnuj-kq7uX7NVvVniSWodbiPdMJzs,7664
|
13
|
-
scriptcollection-3.5.92.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
14
|
-
scriptcollection-3.5.92.dist-info/entry_points.txt,sha256=1jAL5AuB8mvdw2v-6E7wCZFThurQxchiQynL8DCi-Yg,3545
|
15
|
-
scriptcollection-3.5.92.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
|
16
|
-
scriptcollection-3.5.92.dist-info/RECORD,,
|
File without changes
|