ScriptCollection 3.5.12__py3-none-any.whl → 3.5.14__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.
@@ -67,7 +67,7 @@ class GeneralUtilities:
67
67
  @functools.wraps(func)
68
68
  def new_func(*args, **kwargs):
69
69
  warnings.simplefilter('always', DeprecationWarning)
70
- warnings.warn(f"Call to deprecated function {func.__name__}", category=DeprecationWarning, stacklevel=2)
70
+ warnings.warn(f"Call to deprecated function {func.__name__}", category=DeprecationWarning, stacklevel=2)
71
71
  warnings.simplefilter('default', DeprecationWarning)
72
72
  return func(*args, **kwargs)
73
73
  return new_func
@@ -574,12 +574,14 @@ class GeneralUtilities:
574
574
  @check_arguments
575
575
  def get_direct_files_of_folder(folder: str) -> list[str]:
576
576
  result = [os.path.join(folder, f) for f in listdir(folder) if isfile(join(folder, f))]
577
+ result = sorted(result, key=str.casefold)
577
578
  return result
578
579
 
579
580
  @staticmethod
580
581
  @check_arguments
581
582
  def get_direct_folders_of_folder(folder: str) -> list[str]:
582
583
  result = [os.path.join(folder, f) for f in listdir(folder) if isdir(join(folder, f))]
584
+ result = sorted(result, key=str.casefold)
583
585
  return result
584
586
 
585
587
  @staticmethod
@@ -589,6 +591,7 @@ class GeneralUtilities:
589
591
  result.extend(GeneralUtilities.get_direct_files_of_folder(folder))
590
592
  for subfolder in GeneralUtilities.get_direct_folders_of_folder(folder):
591
593
  result.extend(GeneralUtilities.get_all_files_of_folder(subfolder))
594
+ result = sorted(result, key=str.casefold)
592
595
  return result
593
596
 
594
597
  @staticmethod
@@ -599,12 +602,13 @@ class GeneralUtilities:
599
602
  result.extend(subfolders)
600
603
  for subfolder in subfolders:
601
604
  result.extend(GeneralUtilities.get_all_folders_of_folder(subfolder))
605
+ result = sorted(result, key=str.casefold)
602
606
  return result
603
607
 
604
608
  @staticmethod
605
609
  @check_arguments
606
610
  def get_all_objects_of_folder(folder: str) -> list[str]:
607
- return GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder)
611
+ return sorted(GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder), key=str.casefold)
608
612
 
609
613
  @staticmethod
610
614
  @check_arguments
@@ -7,7 +7,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
7
7
  class ProgramRunnerPopen(ProgramRunnerBase):
8
8
 
9
9
  @GeneralUtilities.check_arguments
10
- 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:
10
+ 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
11
  arguments_for_process = [program]
12
12
  arguments_for_process.extend(arguments_as_array)
13
13
  # "shell=True" is not allowed because it is not recommended and also something like
@@ -15,9 +15,9 @@ class ProgramRunnerPopen(ProgramRunnerBase):
15
15
  # would not be possible anymore because the ampersand will be treated as shell-command.
16
16
  try:
17
17
  if interactive:
18
- result = Popen(arguments_for_process, cwd=working_directory , stdout=PIPE, stderr=PIPE, shell=False, stdin = sys.stdin) # pylint: disable=consider-using-with
18
+ result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False, text=True, stdin=sys.stdin) # pylint: disable=consider-using-with
19
19
  else:
20
- result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False) # pylint: disable=consider-using-with
20
+ result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False, text=True) # pylint: disable=consider-using-with
21
21
  except FileNotFoundError as fileNotFoundError:
22
22
  raise FileNotFoundError(f"Starting '{program}' in '{working_directory}' resulted in a FileNotFoundError: '{fileNotFoundError.filename}'")
23
23
  return result
@@ -34,18 +34,18 @@ class ProgramRunnerPopen(ProgramRunnerBase):
34
34
  return result
35
35
 
36
36
  @GeneralUtilities.check_arguments
37
- 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]:
38
- process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive)
37
+ 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]:
38
+ process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive)
39
39
  return self.wait(process, custom_argument)
40
40
 
41
41
  @GeneralUtilities.check_arguments
42
- def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
42
+ def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
43
43
  return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
44
44
 
45
45
  @GeneralUtilities.check_arguments
46
- 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:
47
- return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive).pid
46
+ 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:
47
+ return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive).pid
48
48
 
49
49
  @GeneralUtilities.check_arguments
50
- def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
51
- return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
50
+ def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive: bool = False) -> int:
51
+ return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument, interactive)
@@ -1,19 +1,19 @@
1
- import time
2
1
  from datetime import timedelta, datetime
3
2
  import json
4
3
  import binascii
5
4
  import filecmp
5
+ import time
6
6
  import hashlib
7
- from io import BufferedReader, BytesIO
7
+ from io import BytesIO
8
8
  import itertools
9
9
  import math
10
10
  import os
11
+ from queue import Queue, Empty
12
+ from concurrent.futures import ThreadPoolExecutor
11
13
  from pathlib import Path
12
- from random import randrange
13
14
  from subprocess import Popen
14
15
  import re
15
16
  import shutil
16
- import traceback
17
17
  import uuid
18
18
  import tempfile
19
19
  import io
@@ -29,7 +29,7 @@ from .ProgramRunnerBase import ProgramRunnerBase
29
29
  from .ProgramRunnerPopen import ProgramRunnerPopen
30
30
  from .ProgramRunnerEpew import ProgramRunnerEpew, CustomEpewArgument
31
31
 
32
- version = "3.5.12"
32
+ version = "3.5.14"
33
33
  __version__ = version
34
34
 
35
35
 
@@ -59,8 +59,7 @@ class ScriptCollectionCore:
59
59
  errorsonly_argument = ""
60
60
  else:
61
61
  errorsonly_argument = " --errors-only"
62
- (exit_code, stdout, stderr, _) = self.run_program("pylint", filename +
63
- errorsonly_argument, working_directory, throw_exception_if_exitcode_is_not_zero=False)
62
+ (exit_code, stdout, stderr, _) = self.run_program("pylint", filename + errorsonly_argument, working_directory, throw_exception_if_exitcode_is_not_zero=False)
64
63
  if (exit_code != 0):
65
64
  errors.append(f"Linting-issues of {file}:")
66
65
  errors.append(f"Pylint-exitcode: {exit_code}")
@@ -74,18 +73,15 @@ class ScriptCollectionCore:
74
73
 
75
74
  @GeneralUtilities.check_arguments
76
75
  def replace_version_in_dockerfile_file(self, dockerfile: str, new_version_value: str) -> None:
77
- GeneralUtilities.write_text_to_file(dockerfile, re.sub(
78
- "ARG Version=\"\\d+\\.\\d+\\.\\d+\"", f"ARG Version=\"{new_version_value}\"", GeneralUtilities.read_text_from_file(dockerfile)))
76
+ GeneralUtilities.write_text_to_file(dockerfile, re.sub("ARG Version=\"\\d+\\.\\d+\\.\\d+\"", f"ARG Version=\"{new_version_value}\"", GeneralUtilities.read_text_from_file(dockerfile)))
79
77
 
80
78
  @GeneralUtilities.check_arguments
81
79
  def replace_version_in_python_file(self, file: str, new_version_value: str):
82
- GeneralUtilities.write_text_to_file(file, re.sub(
83
- "version = \"\\d+\\.\\d+\\.\\d+\"", f"version = \"{new_version_value}\"", GeneralUtilities.read_text_from_file(file)))
80
+ GeneralUtilities.write_text_to_file(file, re.sub("version = \"\\d+\\.\\d+\\.\\d+\"", f"version = \"{new_version_value}\"", GeneralUtilities.read_text_from_file(file)))
84
81
 
85
82
  @GeneralUtilities.check_arguments
86
83
  def replace_version_in_ini_file(self, file: str, new_version_value: str):
87
- GeneralUtilities.write_text_to_file(file, re.sub(
88
- "version = \\d+\\.\\d+\\.\\d+", f"version = {new_version_value}", GeneralUtilities.read_text_from_file(file)))
84
+ GeneralUtilities.write_text_to_file(file, re.sub("version = \\d+\\.\\d+\\.\\d+", f"version = {new_version_value}", GeneralUtilities.read_text_from_file(file)))
89
85
 
90
86
  @GeneralUtilities.check_arguments
91
87
  def replace_version_in_nuspec_file(self, nuspec_file: str, new_version: str) -> None:
@@ -96,8 +92,7 @@ class ScriptCollectionCore:
96
92
  if pattern.match(new_version):
97
93
  GeneralUtilities.write_text_to_file(nuspec_file, re.sub(f"<version>{versionregex}<\\/version>", f"<version>{new_version}</version>", GeneralUtilities.read_text_from_file(nuspec_file)))
98
94
  else:
99
- raise ValueError(
100
- f"Version '{new_version}' does not match version-regex '{versiononlyregex}'")
95
+ raise ValueError(f"Version '{new_version}' does not match version-regex '{versiononlyregex}'")
101
96
 
102
97
  @GeneralUtilities.check_arguments
103
98
  def replace_version_in_csproj_file(self, csproj_file: str, current_version: str):
@@ -106,25 +101,20 @@ class ScriptCollectionCore:
106
101
  pattern = re.compile(versiononlyregex)
107
102
  if pattern.match(current_version):
108
103
  for tag in ["Version", "AssemblyVersion", "FileVersion"]:
109
- GeneralUtilities.write_text_to_file(csproj_file, re.sub(
110
- f"<{tag}>{versionregex}(.\\d+)?<\\/{tag}>", f"<{tag}>{current_version}</{tag}>", GeneralUtilities.read_text_from_file(csproj_file)))
104
+ GeneralUtilities.write_text_to_file(csproj_file, re.sub(f"<{tag}>{versionregex}(.\\d+)?<\\/{tag}>", f"<{tag}>{current_version}</{tag}>", GeneralUtilities.read_text_from_file(csproj_file)))
111
105
  else:
112
- raise ValueError(
113
- f"Version '{current_version}' does not match version-regex '{versiononlyregex}'")
106
+ raise ValueError(f"Version '{current_version}' does not match version-regex '{versiononlyregex}'")
114
107
 
115
108
  @GeneralUtilities.check_arguments
116
109
  def push_nuget_build_artifact(self, nupkg_file: str, registry_address: str, api_key: str, verbosity: int = 1):
117
110
  nupkg_file_name = os.path.basename(nupkg_file)
118
111
  nupkg_file_folder = os.path.dirname(nupkg_file)
119
- self.run_program(
120
- "dotnet", f"nuget push {nupkg_file_name} --force-english-output --source {registry_address} --api-key {api_key}", nupkg_file_folder, verbosity)
112
+ self.run_program("dotnet", f"nuget push {nupkg_file_name} --force-english-output --source {registry_address} --api-key {api_key}", nupkg_file_folder, verbosity)
121
113
 
122
114
  @GeneralUtilities.check_arguments
123
115
  def dotnet_build(self, repository_folder: str, projectname: str, configuration: str):
124
- self.run_program(
125
- "dotnet", f"clean -c {configuration}", repository_folder)
126
- self.run_program(
127
- "dotnet", f"build {projectname}/{projectname}.csproj -c {configuration}", repository_folder)
116
+ self.run_program("dotnet", f"clean -c {configuration}", repository_folder)
117
+ self.run_program("dotnet", f"build {projectname}/{projectname}.csproj -c {configuration}", repository_folder)
128
118
 
129
119
  @GeneralUtilities.check_arguments
130
120
  def find_file_by_extension(self, folder: str, extension: str):
@@ -162,8 +152,7 @@ class ScriptCollectionCore:
162
152
  subfolder_argument = ""
163
153
  else:
164
154
  subfolder_argument = f" -- {subfolder}"
165
- log_result = self.run_program(
166
- "git", f'log --pretty=%aN{space_character}%aE%n%cN{space_character}%cE HEAD{subfolder_argument}', repository_folder, verbosity=0)
155
+ log_result = self.run_program("git", f'log --pretty=%aN{space_character}%aE%n%cN{space_character}%cE HEAD{subfolder_argument}', repository_folder, verbosity=0)
167
156
  plain_content: list[str] = list(
168
157
  set([line for line in log_result[1].split("\n") if len(line) > 0]))
169
158
  result: list[tuple[str, str]] = []
@@ -179,8 +168,7 @@ class ScriptCollectionCore:
179
168
  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:
180
169
  since_as_string = self.__datetime_to_string_for_git(since)
181
170
  until_as_string = self.__datetime_to_string_for_git(until)
182
- result = filter(lambda line: not GeneralUtilities.string_is_none_or_whitespace(line), self.run_program(
183
- "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", ""))
171
+ 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", ""))
184
172
  if ignore_commits_which_are_not_in_history_of_head:
185
173
  result = [commit_id for commit_id in result if self.git_commit_is_ancestor(
186
174
  repository_folder, commit_id)]
@@ -192,8 +180,7 @@ class ScriptCollectionCore:
192
180
 
193
181
  @GeneralUtilities.check_arguments
194
182
  def git_commit_is_ancestor(self, repository_folder: str, ancestor: str, descendant: str = "HEAD") -> bool:
195
- exit_code = self.run_program_argsasarray(
196
- "git", ["merge-base", "--is-ancestor", ancestor, descendant], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0]
183
+ exit_code = self.run_program_argsasarray("git", ["merge-base", "--is-ancestor", ancestor, descendant], repository_folder, throw_exception_if_exitcode_is_not_zero=False)[0]
197
184
  if exit_code == 0:
198
185
  return True
199
186
  elif exit_code == 1:
@@ -203,8 +190,7 @@ class ScriptCollectionCore:
203
190
 
204
191
  @GeneralUtilities.check_arguments
205
192
  def __git_changes_helper(self, repository_folder: str, arguments_as_array: list[str]) -> bool:
206
- lines = GeneralUtilities.string_to_lines(self.run_program_argsasarray(
207
- "git", arguments_as_array, repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)[1], False)
193
+ 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)
208
194
  for line in lines:
209
195
  if GeneralUtilities.string_has_content(line):
210
196
  return True
@@ -245,8 +231,7 @@ class ScriptCollectionCore:
245
231
 
246
232
  @GeneralUtilities.check_arguments
247
233
  def git_get_commit_date(self, repository_folder: str, commit: str = "HEAD") -> datetime:
248
- result: tuple[int, str, str, int] = self.run_program_argsasarray(
249
- "git", ["show", "-s", "--format=%ci", commit], repository_folder, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
234
+ 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)
250
235
  date_as_string = result[1].replace('\n', '')
251
236
  result = datetime.strptime(date_as_string, '%Y-%m-%d %H:%M:%S %z')
252
237
  return result
@@ -359,8 +344,7 @@ class ScriptCollectionCore:
359
344
  self.run_program_argsasarray("git", ['checkout', '.'], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
360
345
 
361
346
  @GeneralUtilities.check_arguments
362
- def git_commit(self, directory: str, message: str, author_name: str = None, author_email: str = None, stage_all_changes: bool = True,
363
- no_changes_behavior: int = 0) -> str:
347
+ def git_commit(self, directory: str, message: str, author_name: str = None, author_email: str = None, stage_all_changes: bool = True, no_changes_behavior: int = 0) -> str:
364
348
  # no_changes_behavior=0 => No commit
365
349
  # no_changes_behavior=1 => Commit anyway
366
350
  # no_changes_behavior=2 => Exception
@@ -410,7 +394,7 @@ class ScriptCollectionCore:
410
394
  @GeneralUtilities.check_arguments
411
395
  def git_checkout(self, directory: str, branch: str) -> None:
412
396
  self.run_program_argsasarray("git", ["checkout", branch], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
413
- self.run_program_argsasarray("git", ["submodule", "update", "--recursive"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
397
+ self.run_program_argsasarray("git", ["submodule", "update", "--recursive"], directory, throw_exception_if_exitcode_is_not_zero=True, verbosity=0)
414
398
 
415
399
  @GeneralUtilities.check_arguments
416
400
  def git_merge_abort(self, directory: str) -> None:
@@ -450,7 +434,7 @@ class ScriptCollectionCore:
450
434
  self.git_fetch(target_directory)
451
435
  else:
452
436
  # clone
453
- self.git_clone(target_repository, source_repository, include_submodules=True, mirror=True)
437
+ self.git_clone(target_repository, source_repository, include_submodules=True, mirror=True)
454
438
 
455
439
  def get_git_submodules(self, folder: str) -> list[str]:
456
440
  e = self.run_program("git", "submodule status", folder)
@@ -472,8 +456,7 @@ class ScriptCollectionCore:
472
456
  return True
473
457
  if (exit_code == 1):
474
458
  return False
475
- raise ValueError(
476
- f"Unable to calculate whether '{file_in_repository}' in repository '{repositorybasefolder}' is ignored due to git-exitcode {exit_code}.")
459
+ raise ValueError(f"Unable to calculate whether '{file_in_repository}' in repository '{repositorybasefolder}' is ignored due to git-exitcode {exit_code}.")
477
460
 
478
461
  @GeneralUtilities.check_arguments
479
462
  def git_discard_all_changes(self, repository: str) -> None:
@@ -562,9 +545,11 @@ class ScriptCollectionCore:
562
545
  with open(target_file, "w", encoding=encoding) as file_object:
563
546
  file_object.write("\n".join(lines))
564
547
 
548
+ @GeneralUtilities.check_arguments
565
549
  def escape_git_repositories_in_folder(self, folder: str) -> dict[str, str]:
566
550
  return self.__escape_git_repositories_in_folder_internal(folder, dict[str, str]())
567
551
 
552
+ @GeneralUtilities.check_arguments
568
553
  def __escape_git_repositories_in_folder_internal(self, folder: str, renamed_items: dict[str, str]) -> dict[str, str]:
569
554
  for file in GeneralUtilities.get_direct_files_of_folder(folder):
570
555
  filename = os.path.basename(file)
@@ -586,10 +571,12 @@ class ScriptCollectionCore:
586
571
  self.__escape_git_repositories_in_folder_internal(subfolder2, renamed_items)
587
572
  return renamed_items
588
573
 
574
+ @GeneralUtilities.check_arguments
589
575
  def deescape_git_repositories_in_folder(self, renamed_items: dict[str, str]):
590
576
  for renamed_item, original_name in renamed_items.items():
591
577
  os.rename(renamed_item, original_name)
592
578
 
579
+ @GeneralUtilities.check_arguments
593
580
  def __sort_fmd(self, line: str):
594
581
  splitted: list = line.split(";")
595
582
  filetype: str = splitted[1]
@@ -626,29 +613,36 @@ class ScriptCollectionCore:
626
613
 
627
614
  @GeneralUtilities.check_arguments
628
615
  def __calculate_lengh_in_seconds(self, filename: str, folder: str) -> float:
629
- argument = ['-v', 'error', '-show_entries', 'format=duration',
630
- '-of', 'default=noprint_wrappers=1:nokey=1', filename]
616
+ argument = ['-v', 'error', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', filename]
631
617
  result = self.run_program_argsasarray("ffprobe", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
632
618
  return float(result[1].replace('\n', ''))
633
619
 
634
620
  @GeneralUtilities.check_arguments
635
- def __create_thumbnails(self, filename: str, fps: str, folder: str, tempname_for_thumbnails: str) -> None:
636
- argument = ['-i', filename, '-r', str(fps), '-vf', 'scale=-1:120',
637
- '-vcodec', 'png', f'{tempname_for_thumbnails}-%002d.png']
621
+ def __create_thumbnails(self, filename: str, fps: str, folder: str, tempname_for_thumbnails: str) -> list[str]:
622
+ argument = ['-i', filename, '-r', str(fps), '-vf', 'scale=-1:120', '-vcodec', 'png', f'{tempname_for_thumbnails}-%002d.png']
638
623
  self.run_program_argsasarray("ffmpeg", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
624
+ files = GeneralUtilities.get_direct_files_of_folder(folder)
625
+ result: list[str] = []
626
+ regex = "^"+re.escape(tempname_for_thumbnails)+"\\-\\d+\\.png$"
627
+ regex_for_files = re.compile(regex)
628
+ for file in files:
629
+ filename = os.path.basename(file)
630
+ if regex_for_files.match(filename):
631
+ result.append(file)
632
+ GeneralUtilities.assert_condition(0 < len(result), "No thumbnail-files found.")
633
+ return result
639
634
 
640
635
  @GeneralUtilities.check_arguments
641
636
  def __create_thumbnail(self, outputfilename: str, folder: str, length_in_seconds: float, tempname_for_thumbnails: str, amount_of_images: int) -> None:
642
637
  duration = timedelta(seconds=length_in_seconds)
643
638
  info = GeneralUtilities.timedelta_to_simple_string(duration)
644
- next_square_number = str(int(math.sqrt(GeneralUtilities.get_next_square_number(amount_of_images))))
645
- argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{next_square_number}x{next_square_number}',
646
- f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
647
- self.run_program_argsasarray(
648
- "montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
639
+ rows: int = 5
640
+ columns: int = math.ceil(amount_of_images/rows)
641
+ argument = ['-title', f'"{outputfilename} ({info})"', '-tile', f'{rows}x{columns}', f'{tempname_for_thumbnails}*.png', f'{outputfilename}.png']
642
+ self.run_program_argsasarray("montage", argument, folder, throw_exception_if_exitcode_is_not_zero=True)
649
643
 
650
644
  @GeneralUtilities.check_arguments
651
- def roundup(self, x: float, places: int) -> int:
645
+ def __roundup(self, x: float, places: int) -> int:
652
646
  d = 10 ** places
653
647
  if x < 0:
654
648
  return math.floor(x * d) / d
@@ -656,33 +650,35 @@ class ScriptCollectionCore:
656
650
  return math.ceil(x * d) / d
657
651
 
658
652
  @GeneralUtilities.check_arguments
659
- def generate_thumbnail(self, file: str, frames_per_second: str, tempname_for_thumbnails: str = None) -> None:
653
+ def generate_thumbnail(self, file: str, frames_per_second: str, tempname_for_thumbnails: str = None, hook=None) -> None:
660
654
  if tempname_for_thumbnails is None:
661
- tempname_for_thumbnails = "t"+str(uuid.uuid4())
655
+ tempname_for_thumbnails = "t_"+str(uuid.uuid4())
662
656
 
663
657
  file = GeneralUtilities.resolve_relative_path_from_current_working_directory(file)
664
658
  filename = os.path.basename(file)
665
659
  folder = os.path.dirname(file)
666
660
  filename_without_extension = Path(file).stem
667
-
661
+ preview_files: list[str] = []
668
662
  try:
669
663
  length_in_seconds = self.__calculate_lengh_in_seconds(filename, folder)
670
664
  if (frames_per_second.endswith("fps")):
671
665
  # frames per second, example: frames_per_second="20fps" => 20 frames per second
672
- x = self.roundup(float(frames_per_second[:-3]), 2)
673
- frames_per_secondx = str(x)
674
- amounf_of_previewframes = int(math.floor(length_in_seconds*x))
666
+ frames_per_second = self.__roundup(float(frames_per_second[:-3]), 2)
667
+ frames_per_second_as_string = str(frames_per_second)
668
+ amounf_of_previewframes = int(math.floor(length_in_seconds*frames_per_second))
675
669
  else:
676
670
  # concrete amount of frame, examples: frames_per_second="16" => 16 frames for entire video
677
671
  amounf_of_previewframes = int(float(frames_per_second))
678
672
  # self.roundup((amounf_of_previewframes-2)/length_in_seconds, 2)
679
- frames_per_secondx = f"{amounf_of_previewframes-2}/{length_in_seconds}"
680
- self.__create_thumbnails(filename, frames_per_secondx, folder, tempname_for_thumbnails)
681
- self.__create_thumbnail(filename_without_extension, folder, length_in_seconds, tempname_for_thumbnails, amounf_of_previewframes)
673
+ frames_per_second_as_string = f"{amounf_of_previewframes-2}/{length_in_seconds}"
674
+ preview_files = self.__create_thumbnails(filename, frames_per_second_as_string, folder, tempname_for_thumbnails)
675
+ if hook is not None:
676
+ hook(file, preview_files)
677
+ actual_amounf_of_previewframes = len(preview_files)
678
+ self.__create_thumbnail(filename_without_extension, folder, length_in_seconds, tempname_for_thumbnails, actual_amounf_of_previewframes)
682
679
  finally:
683
- for thumbnail_to_delete in Path(folder).rglob(tempname_for_thumbnails+"-*"):
684
- file = str(thumbnail_to_delete)
685
- os.remove(file)
680
+ for thumbnail_to_delete in preview_files:
681
+ os.remove(thumbnail_to_delete)
686
682
 
687
683
  @GeneralUtilities.check_arguments
688
684
  def extract_pdf_pages(self, file: str, from_page: int, to_page: int, outputfile: str) -> None:
@@ -908,29 +904,6 @@ class ScriptCollectionCore:
908
904
  line[0], line[1], line[2], line[3], line[4])
909
905
  GeneralUtilities.write_message_to_stdout(separator_line)
910
906
 
911
- @GeneralUtilities.check_arguments
912
- def SCUploadFileToFileHost(self, file: str, host: str) -> int:
913
- try:
914
- GeneralUtilities.write_message_to_stdout(
915
- self.upload_file_to_file_host(file, host))
916
- return 0
917
- except Exception as exception:
918
- GeneralUtilities.write_exception_to_stderr_with_traceback(exception, traceback)
919
- return 1
920
-
921
- @GeneralUtilities.check_arguments
922
- def SCFileIsAvailableOnFileHost(self, file: str) -> int:
923
- try:
924
- if self.file_is_available_on_file_host(file):
925
- GeneralUtilities.write_message_to_stdout(f"'{file}' is available")
926
- return 0
927
- else:
928
- GeneralUtilities.write_message_to_stdout(f"'{file}' is not available")
929
- return 1
930
- except Exception as exception:
931
- GeneralUtilities.write_exception_to_stderr_with_traceback(exception, traceback)
932
- return 2
933
-
934
907
  @GeneralUtilities.check_arguments
935
908
  def SCCalculateBitcoinBlockHash(self, block_version_number: str, previousblockhash: str, transactionsmerkleroot: str, timestamp: str, target: str, nonce: str) -> str:
936
909
  # Example-values:
@@ -1119,44 +1092,6 @@ class ScriptCollectionCore:
1119
1092
  tor_version = version_with_overhead.split("~")[0]
1120
1093
  return tor_version
1121
1094
 
1122
- @GeneralUtilities.check_arguments
1123
- def upload_file_to_file_host(self, file: str, host: str) -> int:
1124
- if (host is None):
1125
- return self.upload_file_to_random_filesharing_service(file)
1126
- elif host == "anonfiles.com":
1127
- return self.upload_file_to_anonfiles(file)
1128
- elif host == "bayfiles.com":
1129
- return self.upload_file_to_bayfiles(file)
1130
- GeneralUtilities.write_message_to_stderr("Unknown host: "+host)
1131
- return 1
1132
-
1133
- @GeneralUtilities.check_arguments
1134
- def upload_file_to_random_filesharing_service(self, file: str) -> int:
1135
- host = randrange(2)
1136
- if host == 0:
1137
- return self.upload_file_to_anonfiles(file)
1138
- if host == 1:
1139
- return self.upload_file_to_bayfiles(file)
1140
- return 1
1141
-
1142
- @GeneralUtilities.check_arguments
1143
- def upload_file_to_anonfiles(self, file) -> int:
1144
- return self.upload_file_by_using_simple_curl_request("https://api.anonfiles.com/upload", file)
1145
-
1146
- @GeneralUtilities.check_arguments
1147
- def upload_file_to_bayfiles(self, file) -> int:
1148
- return self.upload_file_by_using_simple_curl_request("https://api.bayfiles.com/upload", file)
1149
-
1150
- @GeneralUtilities.check_arguments
1151
- def upload_file_by_using_simple_curl_request(self, api_url: str, file: str) -> int:
1152
- # TODO implement
1153
- return 1
1154
-
1155
- @GeneralUtilities.check_arguments
1156
- def file_is_available_on_file_host(self, file) -> int:
1157
- # TODO implement
1158
- return 1
1159
-
1160
1095
  def run_testcases_for_python_project(self, repository_folder: str):
1161
1096
  self.run_program("coverage", "run -m pytest", repository_folder)
1162
1097
  self.run_program("coverage", "xml", repository_folder)
@@ -1167,7 +1102,7 @@ class ScriptCollectionCore:
1167
1102
 
1168
1103
  @GeneralUtilities.check_arguments
1169
1104
  def get_file_permission(self, file: str) -> str:
1170
- """This function returns an usual octet-triple, for example "0700"."""
1105
+ """This function returns an usual octet-triple, for example "700"."""
1171
1106
  ls_output = self.__ls(file)
1172
1107
  return self.__get_file_permission_helper(ls_output)
1173
1108
 
@@ -1210,12 +1145,10 @@ class ScriptCollectionCore:
1210
1145
  @GeneralUtilities.check_arguments
1211
1146
  def __ls(self, file: str) -> str:
1212
1147
  file = file.replace("\\", "/")
1213
- GeneralUtilities.assert_condition(os.path.isfile(file) or os.path.isdir(
1214
- file), f"Can not execute 'ls' because '{file}' does not exist")
1148
+ GeneralUtilities.assert_condition(os.path.isfile(file) or os.path.isdir(file), f"Can not execute 'ls' because '{file}' does not exist.")
1215
1149
  result = self.run_program_argsasarray("ls", ["-ld", file])
1216
1150
  GeneralUtilities.assert_condition(result[0] == 0, f"'ls -ld {file}' resulted in exitcode {str(result[0])}. StdErr: {result[2]}")
1217
- GeneralUtilities.assert_condition(not GeneralUtilities.string_is_none_or_whitespace(
1218
- result[1]), f"'ls' of '{file}' had an empty output. StdErr: '{result[2]}'")
1151
+ GeneralUtilities.assert_condition(not GeneralUtilities.string_is_none_or_whitespace(result[1]), f"'ls' of '{file}' had an empty output. StdErr: '{result[2]}'")
1219
1152
  return result[1]
1220
1153
 
1221
1154
  @GeneralUtilities.check_arguments
@@ -1255,8 +1188,39 @@ class ScriptCollectionCore:
1255
1188
  popen: Popen = self.program_runner.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument, interactive)
1256
1189
  return popen
1257
1190
 
1258
- # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
1191
+ @staticmethod
1192
+ @GeneralUtilities.check_arguments
1193
+ def __enqueue_output(file, queue):
1194
+ for line in iter(file.readline, ''):
1195
+ queue.put(line)
1196
+ file.close()
1259
1197
 
1198
+ @staticmethod
1199
+ @GeneralUtilities.check_arguments
1200
+ def __read_popen_pipes(p: Popen):
1201
+
1202
+ with ThreadPoolExecutor(2) as pool:
1203
+ q_stdout, q_stderr = Queue(), Queue()
1204
+
1205
+ pool.submit(ScriptCollectionCore.__enqueue_output, p.stdout, q_stdout)
1206
+ pool.submit(ScriptCollectionCore.__enqueue_output, p.stderr, q_stderr)
1207
+ while True:
1208
+ time.sleep(0.2)
1209
+ if p.poll() is not None and q_stdout.empty() and q_stderr.empty():
1210
+ break
1211
+
1212
+ out_line = ''
1213
+ err_line = ''
1214
+
1215
+ try:
1216
+ out_line = q_stdout.get_nowait()
1217
+ err_line = q_stderr.get_nowait()
1218
+ except Empty:
1219
+ pass
1220
+
1221
+ yield (out_line, err_line)
1222
+
1223
+ # Return-values program_runner: Exitcode, StdOut, StdErr, Pid
1260
1224
  @GeneralUtilities.check_arguments
1261
1225
  def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, verbosity: int = 1, print_errors_as_information: bool = False, log_file: str = None, timeoutInSeconds: int = 600, addLogOverhead: bool = False, title: str = None, log_namespace: str = "", arguments_for_log: list[str] = None, throw_exception_if_exitcode_is_not_zero: bool = True, custom_argument: object = None, interactive: bool = False) -> tuple[int, str, str, int]:
1262
1226
  # verbosity 1: No output will be logged.
@@ -1284,82 +1248,37 @@ class ScriptCollectionCore:
1284
1248
 
1285
1249
  if verbosity >= 3:
1286
1250
  GeneralUtilities.write_message_to_stdout(f"Run '{info_for_log}'.")
1251
+
1252
+ print_live_output = 1 < verbosity
1253
+
1254
+ exit_code: int = None
1255
+ stdout: str = ""
1256
+ stderr: str = ""
1257
+ pid: int = None
1258
+
1287
1259
  with self.__run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, verbosity, print_errors_as_information, log_file, timeoutInSeconds, addLogOverhead, title, log_namespace, arguments_for_log, custom_argument, interactive) as process:
1260
+
1288
1261
  pid = process.pid
1262
+ for out_line, err_line in ScriptCollectionCore.__read_popen_pipes(process):
1263
+ if print_live_output:
1264
+ #print(out_line, end='')
1265
+ GeneralUtilities.write_message_to_stdout(out_line)
1266
+ #print(err_line, end='')
1267
+ GeneralUtilities.write_message_to_stderr(err_line)
1289
1268
 
1290
- stdout_lines = list[str]()
1291
- stderr_lines = list[str]()
1292
-
1293
- live_console_output_printing = 2 < verbosity and interactive
1294
-
1295
- log_to_file = log_file is not None
1296
- if log_to_file:
1297
- GeneralUtilities.ensure_file_exists(log_file)
1298
-
1299
- if interactive:
1300
- # there are 2 issues in this part:
1301
- # 1.: ctrl+c
1302
- # 2.: sometimes this function does not terminate even if the started process exited
1303
- def stream_process(process) -> bool:
1304
- try:
1305
- go: bool = process.poll() is None
1306
-
1307
- stdoutreader: BufferedReader = process.stdout
1308
- if stdoutreader.readable():
1309
- stdoutresultb: bytes = stdoutreader.read()
1310
- stdoutresult = GeneralUtilities.bytes_to_string(
1311
- stdoutresultb)
1312
- stdoutlines = GeneralUtilities.string_to_lines(stdoutresult)
1313
- for line in stdoutlines:
1314
- line_stripped = line.replace("\r", "").strip()
1315
- if len(line_stripped) > 0:
1316
- line_str = line_stripped
1317
- stdout_lines.append(line_str)
1318
- if live_console_output_printing:
1319
- GeneralUtilities.write_message_to_stdout(line_str)
1320
- if log_to_file:
1321
- GeneralUtilities.append_line_to_file(
1322
- log_file, line_str)
1323
-
1324
- stderrreader: BufferedReader = process.stderr
1325
- if stderrreader.readable():
1326
- stderrresultb: bytes = stderrreader.read()
1327
- stderrresult = GeneralUtilities.bytes_to_string(stderrresultb)
1328
- stderrlines = GeneralUtilities.string_to_lines(stderrresult)
1329
- for line in stderrlines:
1330
- line_stripped = line.replace("\r", "").strip()
1331
- if len(line_stripped) > 0:
1332
- line_str = line_stripped
1333
- stderr_lines.append(line_str)
1334
- if live_console_output_printing:
1335
- if print_errors_as_information:
1336
- GeneralUtilities.write_message_to_stdout(line_str)
1337
- else:
1338
- GeneralUtilities.write_message_to_stderr(line_str)
1339
- if log_to_file:
1340
- GeneralUtilities.append_line_to_file(log_file, line_str)
1341
-
1342
- return go
1343
- except Exception:
1344
- return False
1345
-
1346
- while stream_process(process):
1347
- time.sleep(0.1)
1348
-
1349
- exit_code = process.poll()
1350
- stdout = '\n'.join(stdout_lines)
1351
- stderr = '\n'.join(stderr_lines)
1352
- else:
1353
- stdout, stderr = process.communicate()
1354
- exit_code = process.wait()
1355
- stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
1356
- stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
1269
+ if out_line is not None and GeneralUtilities.string_has_content(out_line):
1270
+ stdout = stdout+"\n"+out_line
1271
+ if err_line is not None and GeneralUtilities.string_has_content(err_line):
1272
+ stderr = stderr+"\n"+err_line
1357
1273
 
1358
- if throw_exception_if_exitcode_is_not_zero and exit_code != 0:
1359
- raise ValueError(f"Program '{working_directory}>{program} {arguments_for_log_as_string}' resulted in exitcode {exit_code}. (StdOut: '{stdout}', StdErr: '{stderr}')")
1274
+ process.poll()
1275
+ exit_code = process.returncode
1360
1276
 
1361
- result = (exit_code, stdout, stderr, pid)
1362
- return result
1277
+ if throw_exception_if_exitcode_is_not_zero and exit_code != 0:
1278
+ raise ValueError(f"Program '{working_directory}>{program} {arguments_for_log_as_string}' resulted in exitcode {exit_code}. (StdOut: '{stdout}', StdErr: '{stderr}')")
1279
+
1280
+ result = (exit_code, stdout, stderr, pid)
1281
+ return result
1363
1282
  except Exception as e:
1364
1283
  raise e
1365
1284
 
@@ -1516,8 +1435,7 @@ class ScriptCollectionCore:
1516
1435
  result = self.get_version_from_gitversion(repository_folder, "MajorMinorPatch")
1517
1436
  if self.git_repository_has_uncommitted_changes(repository_folder):
1518
1437
  if self.get_current_git_branch_has_tag(repository_folder):
1519
- id_of_latest_tag = self.git_get_commitid_of_tag(
1520
- repository_folder, self.get_latest_git_tag(repository_folder))
1438
+ id_of_latest_tag = self.git_get_commitid_of_tag(repository_folder, self.get_latest_git_tag(repository_folder))
1521
1439
  current_commit = self.git_get_commit_id(repository_folder)
1522
1440
  current_commit_is_on_latest_tag = id_of_latest_tag == current_commit
1523
1441
  if current_commit_is_on_latest_tag:
@@ -1560,8 +1478,7 @@ class ScriptCollectionCore:
1560
1478
  self.run_program("openssl", f'genrsa -out {filename}.key {rsa_key_length}', folder)
1561
1479
  self.run_program("openssl", f'req -new -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou} -x509 -key {filename}.key -out {filename}.unsigned.crt -days {days_until_expire}', folder)
1562
1480
  self.run_program("openssl", f'pkcs12 -export -out {filename}.selfsigned.pfx -password pass:{password} -inkey {filename}.key -in {filename}.unsigned.crt', folder)
1563
- GeneralUtilities.write_text_to_file(
1564
- os.path.join(folder, f"{filename}.password"), password)
1481
+ GeneralUtilities.write_text_to_file(os.path.join(folder, f"{filename}.password"), password)
1565
1482
  GeneralUtilities.write_text_to_file(os.path.join(folder, f"{filename}.san.conf"), f"""[ req ]
1566
1483
  default_bits = {rsa_key_length}
1567
1484
  distinguished_name = req_distinguished_name
@@ -1587,8 +1504,7 @@ DNS = {domain}
1587
1504
 
1588
1505
  @GeneralUtilities.check_arguments
1589
1506
  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:
1590
- self.run_program(
1591
- "openssl", f'req -new -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou} -key {filename}.key -out {filename}.csr -config {filename}.san.conf', folder)
1507
+ self.run_program("openssl", f'req -new -subj /C={subj_c}/ST={subj_st}/L={subj_l}/O={subj_o}/CN={domain}/OU={subj_ou} -key {filename}.key -out {filename}.csr -config {filename}.san.conf', folder)
1592
1508
 
1593
1509
  @GeneralUtilities.check_arguments
1594
1510
  def sign_certificate(self, folder: str, ca_folder: str, ca_name: str, domain: str, filename: str, days_until_expire: int = None) -> None:
@@ -1616,11 +1532,13 @@ DNS = {domain}
1616
1532
  elif ">" in line:
1617
1533
  try:
1618
1534
  # line is something like "cyclonedx-bom>=2.0.2" and the function must return with the updated version
1619
- # (something like "cyclonedx-bom>=3.11.0" for example)
1535
+ # (something like "cyclonedx-bom>=2.11.0" for example)
1620
1536
  package = line.split(">")[0]
1621
1537
  operator = ">=" if ">=" in line else ">"
1622
1538
  response = requests.get(f'https://pypi.org/pypi/{package}/json', timeout=5)
1623
1539
  latest_version = response.json()['info']['version']
1540
+ # TODO update only minor- and patch-version
1541
+ # TODO print info if there is a new major-version
1624
1542
  return package+operator+latest_version
1625
1543
  except:
1626
1544
  return line
@@ -1683,8 +1601,7 @@ DNS = {domain}
1683
1601
  GeneralUtilities.ensure_directory_exists(packagecontent_entireresult_folder)
1684
1602
 
1685
1603
  # create "debian-binary"-file
1686
- debianbinary_file = os.path.join(
1687
- packagecontent_entireresult_folder, "debian-binary")
1604
+ debianbinary_file = os.path.join(packagecontent_entireresult_folder, "debian-binary")
1688
1605
  GeneralUtilities.ensure_file_exists(debianbinary_file)
1689
1606
  GeneralUtilities.write_text_to_file(debianbinary_file, "2.0\n")
1690
1607
 
@@ -1701,10 +1618,10 @@ DNS = {domain}
1701
1618
  link_file = f"/usr/bin/{toolname.lower()}"
1702
1619
  permission = str(permission_of_executable_file_as_octet_triple)
1703
1620
  GeneralUtilities.write_text_to_file(postinst_file, f"""#!/bin/sh
1704
- ln -s {exe_file} {link_file}
1705
- chmod {permission} {exe_file}
1706
- chmod {permission} {link_file}
1707
- """)
1621
+ ln -s {exe_file} {link_file}
1622
+ chmod {permission} {exe_file}
1623
+ chmod {permission} {link_file}
1624
+ """)
1708
1625
 
1709
1626
  # control
1710
1627
  control_file = os.path.join(packagecontent_control_folder, "control")
@@ -1775,24 +1692,22 @@ DNS = {domain}
1775
1692
  proxies = None
1776
1693
  if GeneralUtilities.string_has_content(proxy):
1777
1694
  proxies = {"http": proxy}
1778
- response = requests.get('https://ipinfo.io',
1779
- proxies=proxies, timeout=5)
1695
+ response = requests.get('https://ipinfo.io', proxies=proxies, timeout=5)
1780
1696
  network_information_as_json_string = GeneralUtilities.bytes_to_string(
1781
1697
  response.content)
1782
1698
  return network_information_as_json_string
1783
1699
 
1784
1700
  @GeneralUtilities.check_arguments
1785
1701
  def change_file_extensions(self, folder: str, from_extension: str, to_extension: str, recursive: bool, ignore_case: bool) -> None:
1786
- extension_to_compare:str=None
1702
+ extension_to_compare: str = None
1787
1703
  if ignore_case:
1788
- extension_to_compare=from_extension.lower()
1704
+ extension_to_compare = from_extension.lower()
1789
1705
  else:
1790
- extension_to_compare=from_extension
1706
+ extension_to_compare = from_extension
1791
1707
  for file in GeneralUtilities.get_direct_files_of_folder(folder):
1792
- if (ignore_case and file.lower().endswith(f".{extension_to_compare}")
1793
- or not ignore_case and file.endswith(f".{extension_to_compare}")):
1708
+ if (ignore_case and file.lower().endswith(f".{extension_to_compare}") or not ignore_case and file.endswith(f".{extension_to_compare}")):
1794
1709
  p = Path(file)
1795
1710
  p.rename(p.with_suffix('.'+to_extension))
1796
1711
  if recursive:
1797
1712
  for subfolder in GeneralUtilities.get_direct_folders_of_folder(folder):
1798
- self.change_file_extensions(subfolder, from_extension, to_extension, recursive,ignore_case)
1713
+ self.change_file_extensions(subfolder, from_extension, to_extension, recursive, ignore_case)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ScriptCollection
3
- Version: 3.5.12
3
+ Version: 3.5.14
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
@@ -1,16 +1,16 @@
1
1
  ScriptCollection/Executables.py,sha256=msAlVLjgrxCxW-5Uu7Gk8NI1CNQLK2i6TjNR1fppaCY,19535
2
- ScriptCollection/GeneralUtilities.py,sha256=kfvlZaqbbC9ZPgEiNIHFdleUpu-686rRjcNKDreiqaE,34941
2
+ ScriptCollection/GeneralUtilities.py,sha256=AElXv2NO30cTw-Qs3qVmO-YCOQ5FvBQM3RZMywuKQ_Y,35121
3
3
  ScriptCollection/ProcessesRunner.py,sha256=3mu4ZxzZleQo0Op6o9EYTCFiJfb6kx5ov2YfZfT89mU,1395
4
4
  ScriptCollection/ProgramRunnerBase.py,sha256=7QAjoqOz6XPmJH19F2k-Z1fFQB_uZnPFvn-T54IJcHQ,2324
5
5
  ScriptCollection/ProgramRunnerEpew.py,sha256=C2Rs3YWOWWWJct7XmKphp5CF1tf0j4Fp-ljV2drLTfs,6349
6
- ScriptCollection/ProgramRunnerPopen.py,sha256=ECx35Yz-MKPeoRa_42Bsq8qmbHd13I40vXUJSpZPrI4,3475
6
+ ScriptCollection/ProgramRunnerPopen.py,sha256=G3LgQUVCfaq7XjBsGzalElH31Hbr0etttGR2_H87YzA,3512
7
7
  ScriptCollection/RPStream.py,sha256=NRRHL3YSP3D9MuAV2jB_--0KUKCsvJGxeKnxgrRZ9kY,1545
8
- ScriptCollection/ScriptCollectionCore.py,sha256=Xi9Htfv8F8AXQ04cbPpm2cf2KgqRpNyAWv2eFP2mMlM,96680
8
+ ScriptCollection/ScriptCollectionCore.py,sha256=na1wwDDpUOZAyIqPREH5MeCn1IJfYvN0NEm-YeViCdE,92720
9
9
  ScriptCollection/TasksForCommonProjectStructure.py,sha256=-QxOB01yFHrcPpTNnDA0GY0rv9McvQ95DZ3PNHRCrFE,184090
10
10
  ScriptCollection/UpdateCertificates.py,sha256=Eynbgu7k9jLxApP2D_8Il77B6BFjJap6K7oTeEAZYbk,7790
11
11
  ScriptCollection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- ScriptCollection-3.5.12.dist-info/METADATA,sha256=KluMvH8NET-JxQTy_phEnaAkKFOrWzEzP5dFBSZR36o,7680
13
- ScriptCollection-3.5.12.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
14
- ScriptCollection-3.5.12.dist-info/entry_points.txt,sha256=Jz1pyS3Q6lqpuOWVHogt00jGwrpcHYtPrHGY0_Ltjbo,2227
15
- ScriptCollection-3.5.12.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
- ScriptCollection-3.5.12.dist-info/RECORD,,
12
+ ScriptCollection-3.5.14.dist-info/METADATA,sha256=e_vy24P8qOOWX0xn2ds4jO7IrEojsfAR4c5pCa1FcgM,7680
13
+ ScriptCollection-3.5.14.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
14
+ ScriptCollection-3.5.14.dist-info/entry_points.txt,sha256=Jz1pyS3Q6lqpuOWVHogt00jGwrpcHYtPrHGY0_Ltjbo,2227
15
+ ScriptCollection-3.5.14.dist-info/top_level.txt,sha256=hY2hOVH0V0Ce51WB76zKkIWTUNwMUdHo4XDkR2vYVwg,17
16
+ ScriptCollection-3.5.14.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5