ScriptCollection 3.5.105__py3-none-any.whl → 3.5.107__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.
@@ -1,46 +1,53 @@
1
1
  import os
2
2
  from pathlib import Path
3
+ from datetime import datetime, timedelta
3
4
  import traceback
4
5
  from shutil import copyfile
5
- from .ScriptCollectionCore import ScriptCollectionCore
6
+ import argparse
6
7
  from .GeneralUtilities import GeneralUtilities
8
+ from .ScriptCollectionCore import ScriptCollectionCore
7
9
 
8
10
 
9
11
  class CertificateUpdater:
12
+ maximal_age_of_certificates_in_days: int = None
13
+ __domains: list[str] = None
14
+ __email: str = None
15
+ __current_folder: str = None
16
+ __last_update_timestamp_file: str = None
17
+ __repository_folder: str = None
18
+ __letsencrypt_folder: str = None
19
+ __letsencrypt_live_folder: str = None
20
+ __letsencrypt_archive_folder: str = None
21
+ __log_folder: str = None
22
+ __sc: ScriptCollectionCore = None
23
+ __arguments: ScriptCollectionCore = None
10
24
 
11
- __domains: list[str]
12
- __email: str
13
-
14
- __current_folder = os.path.dirname(os.path.abspath(__file__))
15
- __repository_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}..{os.path.sep}..{os.path.sep}", __current_folder)
16
- __letsencrypt_folder = GeneralUtilities.resolve_relative_path(f"..{os.path.sep}..{os.path.sep}Volumes{os.path.sep}letsencrypt", __current_folder)
17
- __letsencrypt_live_folder = os.path.join(__letsencrypt_folder, "live")
18
- __letsencrypt_archive_folder = os.path.join(__letsencrypt_folder, "archive")
19
- __log_folder = GeneralUtilities.resolve_relative_path(f"Logs{os.path.sep}Overhead", __repository_folder)
20
- __sc = ScriptCollectionCore()
21
- __line = "___________________________________________________________________"
22
-
23
- def __init__(self, domains: list[str], email: str):
25
+ def __init__(self, domains: list[str], email: str, current_file: str, arguments: list[str]):
26
+ self.__sc = ScriptCollectionCore()
27
+ self.maximal_age_of_certificates_in_days = 60
24
28
  self.__domains = domains
25
29
  self.__email = email
30
+ self.__current_folder = current_file
31
+ self.__arguments = arguments
32
+ self.__last_update_timestamp_file = GeneralUtilities.resolve_relative_path("./LastCertificateUpdate.csv", self.__current_folder)
33
+ self.__repository_folder = GeneralUtilities.resolve_relative_path("../..", self.__current_folder)
34
+ self.__sc.assert_is_git_repository(self.__repository_folder)
35
+ self.__letsencrypt_folder = f"{ self.__repository_folder}/Configuration/Volumes/letsencrypt"
36
+ self.__letsencrypt_live_folder = os.path.join(self.__letsencrypt_folder, "live")
37
+ self.__letsencrypt_archive_folder = os.path.join(self.__letsencrypt_folder, "archive")
38
+ self.__log_folder = GeneralUtilities.resolve_relative_path("Logs/Overhead", self.__repository_folder)
26
39
 
27
40
  @GeneralUtilities.check_arguments
28
41
  def __get_latest_index_by_domain(self, domain: str) -> int:
29
42
  result = self.__get_latest_index_by_filelist(GeneralUtilities.get_all_files_of_folder(os.path.join(self.__letsencrypt_archive_folder, domain)))
30
- #GeneralUtilities.write_message_to_stdout(f"Debug: Latest found existing number for domain {domain}: {result}")
43
+ GeneralUtilities.write_message_to_stdout(f"Debug: Latest found existing number for domain {domain}: {result}")
31
44
  return result
32
45
 
33
46
  @GeneralUtilities.check_arguments
34
- def __get_latest_index_by_filelist(self, filenames: list) -> int:
35
- print("files:")
36
- print(filenames)
47
+ def __get_latest_index_by_filelist(self, filenames: list[str]) -> int:
37
48
  filenames = [Path(os.path.basename(file)).stem for file in filenames]
38
- print(filenames)
39
49
  filenames = [file for file in filenames if file.startswith("privkey")]
40
- print(filenames)
41
50
  numbers = [int(file[len("privkey"):]) for file in filenames]
42
- # numbers=[]
43
- # print([os.path.basename(file) for file in filenames])
44
51
  result = max(numbers)
45
52
  return result
46
53
 
@@ -51,7 +58,7 @@ class CertificateUpdater:
51
58
  live_folder = os.path.join(self.__letsencrypt_live_folder, domain)
52
59
  live_filename = filename+".pem"
53
60
  live_file = os.path.join(live_folder, live_filename)
54
- self.__sc.run_program("rm", live_filename, live_folder)
61
+ self.__sc.run_program("rm", live_filename, live_folder, throw_exception_if_exitcode_is_not_zero=True)
55
62
  copyfile(archive_file, live_file)
56
63
 
57
64
  @GeneralUtilities.check_arguments
@@ -59,8 +66,8 @@ class CertificateUpdater:
59
66
  # new ".../live/example.com/cert.pem" is a file but should replaced by a symlink which points to ".../archive/example.com/cert42.pem"
60
67
  live_folder = os.path.join(self.__letsencrypt_live_folder, domain)
61
68
  live_filename = filename+".pem"
62
- self.__sc.run_program("rm", live_filename, live_folder)
63
- self.__sc.run_program("ln", f"-s ../../archive/{domain}/{filename+str(index)}.pem {live_filename}", live_folder)
69
+ self.__sc.run_program("rm", live_filename, live_folder, throw_exception_if_exitcode_is_not_zero=True)
70
+ self.__sc.run_program("ln", f"-s ../../archive/{domain}/{filename+str(index)}.pem {live_filename}", live_folder, throw_exception_if_exitcode_is_not_zero=True)
64
71
 
65
72
  @GeneralUtilities.check_arguments
66
73
  def __replace_symlinks_by_files(self, domain):
@@ -79,48 +86,61 @@ class CertificateUpdater:
79
86
  self.__replace_file_by_symlink(domain, "privkey", index)
80
87
 
81
88
  @GeneralUtilities.check_arguments
82
- def update_certificate_managed_by_docker_and_letsencrypt(self) -> None:
83
- GeneralUtilities.write_message_to_stdout("current_folder:")
84
- GeneralUtilities.write_message_to_stdout(self.__current_folder)
85
- GeneralUtilities.write_message_to_stdout("letsencrypt_folder:")
86
- GeneralUtilities.write_message_to_stdout(self.__letsencrypt_folder)
87
- GeneralUtilities.write_message_to_stdout("letsencrypt_live_folder:")
88
- GeneralUtilities.write_message_to_stdout(self.__letsencrypt_live_folder)
89
- GeneralUtilities.write_message_to_stdout("letsencrypt_archive_folder:")
90
- GeneralUtilities.write_message_to_stdout(self.__letsencrypt_archive_folder)
91
- GeneralUtilities.write_message_to_stdout("log_folder:")
92
- GeneralUtilities.write_message_to_stdout(self.__log_folder)
93
-
94
- GeneralUtilities.write_message_to_stdout(self.__line+self.__line)
95
- GeneralUtilities.write_message_to_stdout("Updating certificates")
96
- self.__sc.git_commit(self.__current_folder, "Saved current changes")
89
+ def __update_certificates(self) -> None:
90
+ self.__sc.git_commit(self.__repository_folder, "Saved current changes")
91
+ error_occurred = False
97
92
  for domain in self.__domains:
93
+ certbot_container_name = "certificate_updater"
98
94
  try:
99
- GeneralUtilities.write_message_to_stdout(self.__line)
95
+ GeneralUtilities.write_message_to_stdout(GeneralUtilities.get_line())
100
96
  GeneralUtilities.write_message_to_stdout(f"Process domain {domain}")
97
+ self.__sc.run_program("docker", f"container rm {certbot_container_name}", self.__current_folder, throw_exception_if_exitcode_is_not_zero=False, verbosity=0)
101
98
  certificate_for_domain_already_exists = os.path.isfile(f"{self.__letsencrypt_folder}/renewal/{domain}.conf")
102
99
  if certificate_for_domain_already_exists:
103
100
  GeneralUtilities.write_message_to_stdout(f"Update certificate for domain {domain}")
104
101
  self.__replace_files_by_symlinks(domain)
105
102
  else:
106
103
  GeneralUtilities.write_message_to_stdout(f"Create certificate for domain {domain}")
107
- certbot_container_name = "r2_updatecertificates_certbot"
108
104
  dockerargument = f"run --name {certbot_container_name} --volume {self.__letsencrypt_folder}:/etc/letsencrypt"
109
- dockerargument = dockerargument+f" --volume {self.__log_folder}:/var/log/letsencrypt -p 80:80 certbot/certbot:latest"
105
+ dockerargument = dockerargument + f" --volume {self.__log_folder}:/var/log/letsencrypt -p 80:80 certbot/certbot:latest"
110
106
  certbotargument = f"--standalone --email {self.__email} --agree-tos --force-renewal --rsa-key-size 4096 --non-interactive --no-eff-email --domain {domain}"
111
107
  if (certificate_for_domain_already_exists):
112
- self.__sc.run_program("docker", f"{dockerargument} certonly --no-random-sleep-on-renew {certbotargument}", self.__current_folder, throw_exception_if_exitcode_is_not_zero=True)
108
+ self.__sc.run_program("docker", f"{dockerargument} certonly --no-random-sleep-on-renew {certbotargument}", self.__current_folder)
113
109
  self.__replace_symlinks_by_files(domain)
114
110
  else:
115
- self.__sc.run_program("docker", f"{dockerargument} certonly --cert-name {domain} {certbotargument}", self.__current_folder, throw_exception_if_exitcode_is_not_zero=True)
111
+ self.__sc.run_program("docker", f"{dockerargument} certonly --cert-name {domain} {certbotargument}", self.__current_folder)
116
112
  except Exception as exception:
113
+ error_occurred = True
117
114
  GeneralUtilities.write_exception_to_stderr_with_traceback(exception, traceback, "Error while updating certificate")
118
115
  finally:
119
116
  try:
120
117
  self.__sc.run_program("docker", f"container rm {certbot_container_name}", self.__current_folder, throw_exception_if_exitcode_is_not_zero=True)
121
118
  except Exception as exception:
122
119
  GeneralUtilities.write_exception_to_stderr_with_traceback(exception, traceback, "Error while removing container")
123
-
124
- GeneralUtilities.write_message_to_stdout("Commit changes...")
125
120
  self.__sc.git_commit(self.__repository_folder, "Executed certificate-update-process")
126
121
  GeneralUtilities.write_message_to_stdout("Finished certificate-update-process")
122
+ if error_occurred:
123
+ raise ValueError("Certificates for at least one domain could not be added/updated.")
124
+
125
+ @GeneralUtilities.check_arguments
126
+ def __get_last_certificate_update_date(self) -> datetime:
127
+ if os.path.exists(self.__last_update_timestamp_file):
128
+ filecontent = GeneralUtilities.read_text_from_file(self.__last_update_timestamp_file)
129
+ return GeneralUtilities.string_to_datetime(filecontent.replace("\r", "").replace("\n", ""))
130
+ else:
131
+ return datetime(year=1970, month=1, day=1)
132
+
133
+ @GeneralUtilities.check_arguments
134
+ def __set_last_certificate_update_date(self, moment: datetime) -> datetime:
135
+ GeneralUtilities.ensure_file_exists(self.__last_update_timestamp_file)
136
+ GeneralUtilities.write_text_to_file(self.__last_update_timestamp_file, GeneralUtilities.datetime_to_string(moment))
137
+
138
+ @GeneralUtilities.check_arguments
139
+ def update_certificates_if_required(self) -> None:
140
+ parser = argparse.ArgumentParser(description="Updated lets-encrypt-certificates")
141
+ parser.add_argument('-f', '--force', action='store_true', required=False, default=False)
142
+ args = parser.parse_args(self.__arguments)
143
+ now = datetime.now()
144
+ if (self.__get_last_certificate_update_date()+timedelta(days=self.maximal_age_of_certificates_in_days)) < now or args.force:
145
+ self.__update_certificates()
146
+ self.__set_last_certificate_update_date(now)
@@ -12,6 +12,7 @@ import stat
12
12
  import secrets
13
13
  import string as strin
14
14
  import sys
15
+ from enum import Enum
15
16
  import traceback
16
17
  import warnings
17
18
  import functools
@@ -26,6 +27,12 @@ from defusedxml.minidom import parse
26
27
  from OpenSSL import crypto
27
28
 
28
29
 
30
+ class VersionEcholon(Enum):
31
+ Patch = 0
32
+ MinorOrPatch = 1
33
+ MajorOrMinorOrPatch = 2
34
+
35
+
29
36
  class GeneralUtilities:
30
37
 
31
38
  __datetime_format: str = "%Y-%m-%dT%H:%M:%S"
@@ -133,33 +140,34 @@ class GeneralUtilities:
133
140
 
134
141
  @staticmethod
135
142
  @check_arguments
136
- def copy_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files=False) -> None:
137
- GeneralUtilities.__copy_or_move_content_of_folder(source_directory, target_directory, overwrite_existing_files, False)
143
+ def copy_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files=False, filtertext: str = None) -> None:
144
+ GeneralUtilities.__copy_or_move_content_of_folder(source_directory, target_directory, overwrite_existing_files, False, filtertext)
138
145
 
139
146
  @staticmethod
140
147
  @check_arguments
141
- def move_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files=False) -> None:
142
- GeneralUtilities.__copy_or_move_content_of_folder(source_directory, target_directory, overwrite_existing_files, True)
148
+ def move_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files=False, filtertext: str = None) -> None:
149
+ GeneralUtilities.__copy_or_move_content_of_folder(source_directory, target_directory, overwrite_existing_files, True, filtertext)
143
150
 
144
151
  @staticmethod
145
152
  @check_arguments
146
- def __copy_or_move_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files, remove_source: bool) -> None:
153
+ def __copy_or_move_content_of_folder(source_directory: str, target_directory: str, overwrite_existing_files, remove_source: bool, filtertext: str = None) -> None:
147
154
  srcDirFull = GeneralUtilities.resolve_relative_path_from_current_working_directory(source_directory)
148
155
  dstDirFull = GeneralUtilities.resolve_relative_path_from_current_working_directory(target_directory)
149
156
  if (os.path.isdir(source_directory)):
150
157
  GeneralUtilities.ensure_directory_exists(target_directory)
151
158
  for file in GeneralUtilities.get_direct_files_of_folder(srcDirFull):
152
159
  filename = os.path.basename(file)
153
- targetfile = os.path.join(dstDirFull, filename)
154
- if (os.path.isfile(targetfile)):
155
- if overwrite_existing_files:
156
- GeneralUtilities.ensure_file_does_not_exist(targetfile)
160
+ if filtertext is None or re.match(filtertext, file):
161
+ targetfile = os.path.join(dstDirFull, filename)
162
+ if (os.path.isfile(targetfile)):
163
+ if overwrite_existing_files:
164
+ GeneralUtilities.ensure_file_does_not_exist(targetfile)
165
+ else:
166
+ raise ValueError(f"Targetfile '{targetfile}' does already exist.")
167
+ if remove_source:
168
+ shutil.move(file, dstDirFull)
157
169
  else:
158
- raise ValueError(f"Targetfile {targetfile} does already exist")
159
- if remove_source:
160
- shutil.move(file, dstDirFull)
161
- else:
162
- shutil.copy(file, dstDirFull)
170
+ shutil.copy(file, dstDirFull)
163
171
  for sub_folder in GeneralUtilities.get_direct_folders_of_folder(srcDirFull):
164
172
  foldername = os.path.basename(sub_folder)
165
173
  sub_target = os.path.join(dstDirFull, foldername)
@@ -1031,27 +1039,25 @@ class GeneralUtilities:
1031
1039
 
1032
1040
  @staticmethod
1033
1041
  @check_arguments
1034
- def process_is_running_by_name(process_name: str) -> bool:
1042
+ def process_is_running_by_name(process_name: str) -> bool:
1035
1043
  processes: list[psutil.Process] = list(psutil.process_iter())
1036
1044
  for p in processes:
1037
1045
  if p.name() == process_name:
1038
1046
  return True
1039
1047
  return False
1040
1048
 
1041
-
1042
1049
  @staticmethod
1043
1050
  @check_arguments
1044
- def process_is_running_by_id(process_id: int) -> bool:
1051
+ def process_is_running_by_id(process_id: int) -> bool:
1045
1052
  processes: list[psutil.Process] = list(psutil.process_iter())
1046
1053
  for p in processes:
1047
1054
  if p.pid == process_id:
1048
1055
  return True
1049
1056
  return False
1050
1057
 
1051
-
1052
1058
  @staticmethod
1053
1059
  @check_arguments
1054
- def kill_process(process_id:int,include_child_processes:bool) -> bool:
1060
+ def kill_process(process_id: int, include_child_processes: bool) -> bool:
1055
1061
  if GeneralUtilities. process_is_running_by_id(process_id):
1056
1062
  GeneralUtilities.write_message_to_stdout(f"Process with id {process_id} is running. Terminating it...")
1057
1063
  process = psutil.Process(process_id)
@@ -28,12 +28,12 @@ import qrcode
28
28
  import pycdlib
29
29
  import send2trash
30
30
  from pypdf import PdfReader, PdfWriter
31
- from .GeneralUtilities import GeneralUtilities
31
+ from .GeneralUtilities import GeneralUtilities, VersionEcholon
32
32
  from .ProgramRunnerBase import ProgramRunnerBase
33
33
  from .ProgramRunnerPopen import ProgramRunnerPopen
34
34
  from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
35
35
 
36
- version = "3.5.105"
36
+ version = "3.5.107"
37
37
  __version__ = version
38
38
 
39
39
 
@@ -1868,8 +1868,8 @@ DNS = {domain}
1868
1868
  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)
1869
1869
 
1870
1870
  @GeneralUtilities.check_arguments
1871
- def update_dependencies_of_python_in_requirementstxt_file(self, file: str,ignored_dependencies:list[str], verbosity: int):
1872
- #TODO consider ignored_dependencies
1871
+ def update_dependencies_of_python_in_requirementstxt_file(self, file: str, ignored_dependencies: list[str], verbosity: int):
1872
+ # TODO consider ignored_dependencies
1873
1873
  lines = GeneralUtilities.read_lines_from_file(file)
1874
1874
  new_lines = []
1875
1875
  for line in lines:
@@ -1899,8 +1899,8 @@ DNS = {domain}
1899
1899
  raise ValueError(f'Unexpected line in requirements-file: "{line}"')
1900
1900
 
1901
1901
  @GeneralUtilities.check_arguments
1902
- def update_dependencies_of_python_in_setupcfg_file(self, setup_cfg_file: str,ignored_dependencies:list[str], verbosity: int):
1903
- #TODO consider ignored_dependencies
1902
+ def update_dependencies_of_python_in_setupcfg_file(self, setup_cfg_file: str, ignored_dependencies: list[str], verbosity: int):
1903
+ # TODO consider ignored_dependencies
1904
1904
  lines = GeneralUtilities.read_lines_from_file(setup_cfg_file)
1905
1905
  new_lines = []
1906
1906
  requirement_parsing_mode = False
@@ -2280,5 +2280,50 @@ TXDX
2280
2280
  ET.indent(element)
2281
2281
  GeneralUtilities.write_text_to_file(file, ET.tostring(element, encoding="unicode"), encoding)
2282
2282
 
2283
- def install_requirementstxt_file(self,requirements_txt_file: str, folder: str, verbosity: int):
2283
+ @GeneralUtilities.check_arguments
2284
+ def install_requirementstxt_file(self, requirements_txt_file: str, folder: str, verbosity: int):
2284
2285
  self.run_program_argsasarray("pip", ["install", "-r", requirements_txt_file], folder, verbosity=verbosity)
2286
+
2287
+ @GeneralUtilities.check_arguments
2288
+ def update_all_services_in_docker_compose_file(self, dockercompose_file: str, version_echolon: VersionEcholon):
2289
+ raise ValueError("not implemented yet")
2290
+
2291
+ @GeneralUtilities.check_arguments
2292
+ def update_service_in_docker_compose_file(self, dockercompose_file: str, service_name: str, version_echolon: VersionEcholon):
2293
+ raise ValueError("not implemented yet")
2294
+
2295
+ @GeneralUtilities.check_arguments
2296
+ def get_current_version_of_service_from_docker_compose_file(self, dockercompose_file: str, service_name: str):
2297
+ raise ValueError("not implemented yet")
2298
+
2299
+ @GeneralUtilities.check_arguments
2300
+ def get_services_from_docker_compose_file(self, dockercompose_file: str):
2301
+ raise ValueError("not implemented yet")
2302
+
2303
+ @GeneralUtilities.check_arguments
2304
+ def get_next_version_for_nginx(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
2305
+ raise ValueError("not implemented yet")
2306
+
2307
+ @GeneralUtilities.check_arguments
2308
+ def get_next_version_for_prometheus(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
2309
+ raise ValueError("not implemented yet")
2310
+
2311
+ @GeneralUtilities.check_arguments
2312
+ def get_next_version_for_blackbox_exporter(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
2313
+ raise ValueError("not implemented yet")
2314
+
2315
+ @GeneralUtilities.check_arguments
2316
+ def get_next_version_for_gitlab(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
2317
+ raise ValueError("not implemented yet")
2318
+
2319
+ @GeneralUtilities.check_arguments
2320
+ def get_next_version_for_nextcloud(self, registry_address: str, current_version: str, version_echolon: VersionEcholon):
2321
+ raise ValueError("not implemented yet")
2322
+
2323
+ @GeneralUtilities.check_arguments
2324
+ def get_next_version_for_genericservice(self, registry_address: str, current_version: str, version_echolon: VersionEcholon, tag_prefix: str):
2325
+ raise ValueError("not implemented yet")
2326
+
2327
+ @GeneralUtilities.check_arguments
2328
+ def get_all_available_tags(self, registry_address: str, service: str):
2329
+ raise ValueError("not implemented yet")
@@ -3298,3 +3298,20 @@ class TasksForCommonProjectStructure:
3298
3298
  @GeneralUtilities.check_arguments
3299
3299
  def install_requirementstxt_for_repository(self, repository_folde: str,verbosity:int):
3300
3300
  self.__sc.install_requirementstxt_file(repository_folde+"/Other/requirements.txt", verbosity)
3301
+
3302
+ @GeneralUtilities.check_arguments
3303
+ def update_submodule(self, repository_folder: str, submodule_name:str):
3304
+ submodule_folder = GeneralUtilities.resolve_relative_path("Other/Resources/Submodules/"+submodule_name, repository_folder)
3305
+ self.__sc.git_fetch(submodule_folder, "origin")
3306
+ self.__sc.git_checkout(submodule_folder, "main")
3307
+ self.__sc.git_pull(submodule_folder, "origin", "main", "main", True)
3308
+ current_version = self.__sc.get_semver_version_from_gitversion(repository_folder)
3309
+ changelog_file = os.path.join(repository_folder, "Other", "Resources", "Changelog", f"v{current_version}.md")
3310
+ if (not os.path.isfile(changelog_file)):
3311
+ GeneralUtilities.ensure_file_exists(changelog_file)
3312
+ GeneralUtilities.write_text_to_file(changelog_file, """# Release notes
3313
+
3314
+ ## Changes
3315
+
3316
+ - Updated geo-ip-database.
3317
+ """)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ScriptCollection
3
- Version: 3.5.105
3
+ Version: 3.5.107
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
@@ -30,7 +30,7 @@ Requires-Dist: keyboard>=0.13.5
30
30
  Requires-Dist: lcov-cobertura>=2.1.1
31
31
  Requires-Dist: lxml>=5.3.2
32
32
  Requires-Dist: ntplib>=0.4.0
33
- Requires-Dist: Pillow>=11.1.0
33
+ Requires-Dist: Pillow>=11.2.1
34
34
  Requires-Dist: pycdlib>=1.14.0
35
35
  Requires-Dist: Pygments>=2.19.1
36
36
  Requires-Dist: pylint>=3.3.6
@@ -41,7 +41,7 @@ Requires-Dist: PyYAML>=6.0.2
41
41
  Requires-Dist: qrcode>=8.1
42
42
  Requires-Dist: send2trash>=1.8.3
43
43
  Requires-Dist: twine>=6.1.0
44
- Requires-Dist: xmlschema>=3.4.5
44
+ Requires-Dist: xmlschema>=4.0.1
45
45
 
46
46
  # ScriptCollection
47
47
 
@@ -1,16 +1,16 @@
1
+ ScriptCollection/CertificateUpdater.py,sha256=pJopWFcwaLAEVljtC4O3SVrlpIpoJNUhT1V4mgiqLvE,8970
1
2
  ScriptCollection/Executables.py,sha256=HI9Pxs5Z9QxPGyqeJU2lWslEggFyGYANCqYVQZp6eJ0,30490
2
- ScriptCollection/GeneralUtilities.py,sha256=jkJu6y8Wv-j_braS_0zsjF6JzDo46NshMeeAphsXGX4,43848
3
+ ScriptCollection/GeneralUtilities.py,sha256=VO4a7xctkjN5dcBXc32gz0x9U07DEagasjvYVKqLmdM,44173
3
4
  ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
4
5
  ScriptCollection/ProgramRunnerBase.py,sha256=2kMIAqdc65UjBAddOZkzy_aFx9h5roZ5a4bQNM6RV6Y,2480
5
6
  ScriptCollection/ProgramRunnerEpew.py,sha256=4pjEd0r9Fcz3TTDv0MdTSd5KkigYXcWUVI1X43regfU,6477
6
7
  ScriptCollection/ProgramRunnerPopen.py,sha256=BPY7-ZMIlqT7JOKz8qlB5c0laF2Js-ijzqk09GxZC48,3821
7
8
  ScriptCollection/SCLog.py,sha256=Gw27Oclcb0ten7_89PD5CdNMoO-at2hGUOYbF-x1HPQ,2296
8
- ScriptCollection/ScriptCollectionCore.py,sha256=U4kI7ztIm6_KL4FFRmway_y8QRrQiJgFEZTBzZ618Ys,126071
9
- ScriptCollection/TasksForCommonProjectStructure.py,sha256=iemQ1J0UAengGAvCTJdc8-ipjhfLqf0Su8evQTDdLGU,231626
10
- ScriptCollection/UpdateCertificates.py,sha256=xRebqD2etBD7ILHL-7fg-Y-kPF0Tbmnwexv4FhwDntQ,7791
9
+ ScriptCollection/ScriptCollectionCore.py,sha256=pMWerT9kxD823d4CHKLV7eyAMjRAsDdYaXEoCGDEYis,128371
10
+ ScriptCollection/TasksForCommonProjectStructure.py,sha256=9rO_W6kZiy3Lgov0HeyyDhOwriorMeJXlVDvwZ3S1UE,232511
11
11
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- scriptcollection-3.5.105.dist-info/METADATA,sha256=BK_ZzXAIr0w33y_eYM1aDhSh24Po6Mb26eXLacXe1ns,7664
13
- scriptcollection-3.5.105.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
- scriptcollection-3.5.105.dist-info/entry_points.txt,sha256=fYCGWGNGijBQHhFe6UAO-BEpfEOxLyNJemukt5ElSzs,3644
15
- scriptcollection-3.5.105.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
- scriptcollection-3.5.105.dist-info/RECORD,,
12
+ scriptcollection-3.5.107.dist-info/METADATA,sha256=nKrrtDhb2dkTemESq47FReNNmlOsk99wSZD6GJlCvkc,7664
13
+ scriptcollection-3.5.107.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
14
+ scriptcollection-3.5.107.dist-info/entry_points.txt,sha256=fYCGWGNGijBQHhFe6UAO-BEpfEOxLyNJemukt5ElSzs,3644
15
+ scriptcollection-3.5.107.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
+ scriptcollection-3.5.107.dist-info/RECORD,,