ScriptCollection 3.4.55__py3-none-any.whl → 3.5.44__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 +389 -353
- ScriptCollection/GeneralUtilities.py +51 -14
- ScriptCollection/ProcessesRunner.py +41 -0
- ScriptCollection/ProgramRunnerBase.py +47 -42
- ScriptCollection/ProgramRunnerEpew.py +122 -122
- ScriptCollection/ProgramRunnerPopen.py +51 -52
- ScriptCollection/RPStream.py +42 -0
- ScriptCollection/ScriptCollectionCore.py +1930 -1703
- ScriptCollection/TasksForCommonProjectStructure.py +2980 -2413
- ScriptCollection/UpdateCertificates.py +126 -128
- {ScriptCollection-3.4.55.dist-info → ScriptCollection-3.5.44.dist-info}/METADATA +22 -21
- ScriptCollection-3.5.44.dist-info/RECORD +16 -0
- {ScriptCollection-3.4.55.dist-info → ScriptCollection-3.5.44.dist-info}/WHEEL +1 -1
- {ScriptCollection-3.4.55.dist-info → ScriptCollection-3.5.44.dist-info}/entry_points.txt +3 -0
- ScriptCollection-3.4.55.dist-info/RECORD +0 -14
- {ScriptCollection-3.4.55.dist-info → ScriptCollection-3.5.44.dist-info}/top_level.txt +0 -0
|
@@ -12,6 +12,8 @@ import secrets
|
|
|
12
12
|
import string as strin
|
|
13
13
|
import sys
|
|
14
14
|
import traceback
|
|
15
|
+
import warnings
|
|
16
|
+
import functools
|
|
15
17
|
from datetime import datetime, timedelta, date
|
|
16
18
|
from os import listdir
|
|
17
19
|
from os.path import isfile, join, isdir
|
|
@@ -49,19 +51,27 @@ class GeneralUtilities:
|
|
|
49
51
|
# Check type of arguments if the type is a generic type seems to be impossible.
|
|
50
52
|
if not GeneralUtilities.is_generic(function.__annotations__[parameters[index]]):
|
|
51
53
|
if not isinstance(argument, function.__annotations__[parameters[index]]):
|
|
52
|
-
raise TypeError(f"Argument with index {index} for function {function.__name__} ('{str(argument)}') is not of type "
|
|
53
|
-
f"{ function.__annotations__[parameters[index]]} but has type "+str(type(argument)))
|
|
54
|
+
raise TypeError(f"Argument with index {index} for function {function.__name__} ('{str(argument)}') is not of type {function.__annotations__[parameters[index]]} but has type "+str(type(argument)))
|
|
54
55
|
for index, named_argument in enumerate(named_args):
|
|
55
56
|
if named_args[named_argument] is not None:
|
|
56
57
|
if parameters[index] in function.__annotations__:
|
|
57
58
|
if not GeneralUtilities.is_generic(function.__annotations__.get(named_argument)):
|
|
58
59
|
if not isinstance(named_args[named_argument], function.__annotations__.get(named_argument)):
|
|
59
|
-
raise TypeError(f"Argument with name {named_argument} for function {function.__name__} ('{str(named_args[named_argument])}') "
|
|
60
|
-
f"is not of type { function.__annotations__.get(named_argument)}")
|
|
60
|
+
raise TypeError(f"Argument with name {named_argument} for function {function.__name__} ('{str(named_args[named_argument])}') is not of type {function.__annotations__.get(named_argument)}")
|
|
61
61
|
return function(*args, **named_args)
|
|
62
62
|
__check_function.__doc__ = function.__doc__
|
|
63
63
|
return __check_function
|
|
64
64
|
|
|
65
|
+
@staticmethod
|
|
66
|
+
def deprecated(func):
|
|
67
|
+
@functools.wraps(func)
|
|
68
|
+
def new_func(*args, **kwargs):
|
|
69
|
+
warnings.simplefilter('always', DeprecationWarning)
|
|
70
|
+
warnings.warn(f"Call to deprecated function {func.__name__}", category=DeprecationWarning, stacklevel=2)
|
|
71
|
+
warnings.simplefilter('default', DeprecationWarning)
|
|
72
|
+
return func(*args, **kwargs)
|
|
73
|
+
return new_func
|
|
74
|
+
|
|
65
75
|
@staticmethod
|
|
66
76
|
@check_arguments
|
|
67
77
|
def args_array_surround_with_quotes_if_required(arguments: list[str]) -> list[str]:
|
|
@@ -381,8 +391,8 @@ class GeneralUtilities:
|
|
|
381
391
|
|
|
382
392
|
@staticmethod
|
|
383
393
|
@check_arguments
|
|
384
|
-
def
|
|
385
|
-
shutil.rmtree(directory, onerror=GeneralUtilities.__remove_readonly)
|
|
394
|
+
def __rmtree(directory: str) -> None:
|
|
395
|
+
shutil.rmtree(directory, onerror=GeneralUtilities.__remove_readonly) # pylint: disable=deprecated-argument
|
|
386
396
|
|
|
387
397
|
@staticmethod
|
|
388
398
|
@check_arguments
|
|
@@ -394,8 +404,8 @@ class GeneralUtilities:
|
|
|
394
404
|
os.chmod(filename, stat.S_IWUSR)
|
|
395
405
|
os.remove(filename)
|
|
396
406
|
for name in dirs:
|
|
397
|
-
GeneralUtilities.
|
|
398
|
-
GeneralUtilities.
|
|
407
|
+
GeneralUtilities.__rmtree(os.path.join(root, name))
|
|
408
|
+
GeneralUtilities.__rmtree(path)
|
|
399
409
|
|
|
400
410
|
@staticmethod
|
|
401
411
|
@check_arguments
|
|
@@ -461,6 +471,16 @@ class GeneralUtilities:
|
|
|
461
471
|
result.append(fileB)
|
|
462
472
|
return result
|
|
463
473
|
|
|
474
|
+
@staticmethod
|
|
475
|
+
@check_arguments
|
|
476
|
+
def to_pascal_case(s: str) -> str:
|
|
477
|
+
return ''.join(current.lower() if prev.isalnum() else current.upper() for prev, current in zip(' ' + s, s) if current.isalnum())
|
|
478
|
+
|
|
479
|
+
@staticmethod
|
|
480
|
+
@check_arguments
|
|
481
|
+
def find_between(s: str, start: str, end: str) -> str:
|
|
482
|
+
return s.split(start)[1].split(end)[0]
|
|
483
|
+
|
|
464
484
|
@staticmethod
|
|
465
485
|
@check_arguments
|
|
466
486
|
def write_lines_to_file(file: str, lines: list, encoding="utf-8") -> None:
|
|
@@ -545,6 +565,12 @@ class GeneralUtilities:
|
|
|
545
565
|
except AttributeError:
|
|
546
566
|
return ctypes.windll.shell32.IsUserAnAdmin() == 1
|
|
547
567
|
|
|
568
|
+
@staticmethod
|
|
569
|
+
@check_arguments
|
|
570
|
+
def ensure_elevated_privileges() -> None:
|
|
571
|
+
if (not GeneralUtilities.current_user_has_elevated_privileges()):
|
|
572
|
+
raise ValueError("Not enough privileges.")
|
|
573
|
+
|
|
548
574
|
@staticmethod
|
|
549
575
|
@check_arguments
|
|
550
576
|
def rename_names_of_all_files_and_folders(folder: str, replace_from: str, replace_to: str, replace_only_full_match=False):
|
|
@@ -558,12 +584,14 @@ class GeneralUtilities:
|
|
|
558
584
|
@check_arguments
|
|
559
585
|
def get_direct_files_of_folder(folder: str) -> list[str]:
|
|
560
586
|
result = [os.path.join(folder, f) for f in listdir(folder) if isfile(join(folder, f))]
|
|
587
|
+
result = sorted(result, key=str.casefold)
|
|
561
588
|
return result
|
|
562
589
|
|
|
563
590
|
@staticmethod
|
|
564
591
|
@check_arguments
|
|
565
592
|
def get_direct_folders_of_folder(folder: str) -> list[str]:
|
|
566
593
|
result = [os.path.join(folder, f) for f in listdir(folder) if isdir(join(folder, f))]
|
|
594
|
+
result = sorted(result, key=str.casefold)
|
|
567
595
|
return result
|
|
568
596
|
|
|
569
597
|
@staticmethod
|
|
@@ -573,6 +601,7 @@ class GeneralUtilities:
|
|
|
573
601
|
result.extend(GeneralUtilities.get_direct_files_of_folder(folder))
|
|
574
602
|
for subfolder in GeneralUtilities.get_direct_folders_of_folder(folder):
|
|
575
603
|
result.extend(GeneralUtilities.get_all_files_of_folder(subfolder))
|
|
604
|
+
result = sorted(result, key=str.casefold)
|
|
576
605
|
return result
|
|
577
606
|
|
|
578
607
|
@staticmethod
|
|
@@ -583,12 +612,13 @@ class GeneralUtilities:
|
|
|
583
612
|
result.extend(subfolders)
|
|
584
613
|
for subfolder in subfolders:
|
|
585
614
|
result.extend(GeneralUtilities.get_all_folders_of_folder(subfolder))
|
|
615
|
+
result = sorted(result, key=str.casefold)
|
|
586
616
|
return result
|
|
587
617
|
|
|
588
618
|
@staticmethod
|
|
589
619
|
@check_arguments
|
|
590
620
|
def get_all_objects_of_folder(folder: str) -> list[str]:
|
|
591
|
-
return GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder)
|
|
621
|
+
return sorted(GeneralUtilities.get_all_files_of_folder(folder) + GeneralUtilities.get_all_folders_of_folder(folder), key=str.casefold)
|
|
592
622
|
|
|
593
623
|
@staticmethod
|
|
594
624
|
@check_arguments
|
|
@@ -718,8 +748,7 @@ class GeneralUtilities:
|
|
|
718
748
|
|
|
719
749
|
@staticmethod
|
|
720
750
|
@check_arguments
|
|
721
|
-
def read_csv_file(file: str, ignore_first_line: bool = False, treat_number_sign_at_begin_of_line_as_comment: bool = True, trim_values: bool = True,
|
|
722
|
-
encoding="utf-8", ignore_empty_lines: bool = True, separator_character: str = ";", values_are_surrounded_by_quotes: bool = False) -> list[list[str]]:
|
|
751
|
+
def read_csv_file(file: str, ignore_first_line: bool = False, treat_number_sign_at_begin_of_line_as_comment: bool = True, trim_values: bool = True, encoding="utf-8", ignore_empty_lines: bool = True, separator_character: str = ";", values_are_surrounded_by_quotes: bool = False) -> list[list[str]]:
|
|
723
752
|
lines = GeneralUtilities.read_lines_from_file(file, encoding)
|
|
724
753
|
|
|
725
754
|
if ignore_first_line:
|
|
@@ -768,10 +797,9 @@ class GeneralUtilities:
|
|
|
768
797
|
|
|
769
798
|
@staticmethod
|
|
770
799
|
@check_arguments
|
|
800
|
+
@deprecated
|
|
771
801
|
def absolute_file_paths(directory: str) -> list[str]:
|
|
772
|
-
|
|
773
|
-
for filename in filenames:
|
|
774
|
-
yield os.path.abspath(os.path.join(dirpath, filename))
|
|
802
|
+
return GeneralUtilities.get_all_files_of_folder(directory)
|
|
775
803
|
|
|
776
804
|
@staticmethod
|
|
777
805
|
@check_arguments
|
|
@@ -852,3 +880,12 @@ class GeneralUtilities:
|
|
|
852
880
|
@check_arguments
|
|
853
881
|
def replace_variable_in_string(input_string: str, variable_name: str, variable_value: str) -> None:
|
|
854
882
|
return input_string.replace(f"__[{variable_name}]__", variable_value)
|
|
883
|
+
|
|
884
|
+
@staticmethod
|
|
885
|
+
@check_arguments
|
|
886
|
+
def input(prompt: str, print_result: bool) -> str: # This function is a workaround for usescases like python scripts which calls input(...) using epew because then the prompt is not printed by the built-in-input-function.
|
|
887
|
+
GeneralUtilities.write_message_to_stdout(prompt)
|
|
888
|
+
result: str = input()
|
|
889
|
+
if print_result:
|
|
890
|
+
GeneralUtilities.write_message_to_stdout(f"Result: {result}")
|
|
891
|
+
return result
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import psutil
|
|
2
|
+
from .ScriptCollectionCore import ScriptCollectionCore
|
|
3
|
+
|
|
4
|
+
# runs multiple processes in parallel and terminate all if at least one is terminated
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProcessStartInformation:
|
|
8
|
+
workingdirectory: str = None
|
|
9
|
+
program: str = None
|
|
10
|
+
arguments: str = None
|
|
11
|
+
|
|
12
|
+
def __init__(self, workingdirectory: str, program: str, arguments: str):
|
|
13
|
+
self.workingdirectory = workingdirectory
|
|
14
|
+
self.program = program
|
|
15
|
+
self.arguments = arguments
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProcessesRunner:
|
|
19
|
+
sc: ScriptCollectionCore
|
|
20
|
+
processes: list[ProcessStartInformation]
|
|
21
|
+
|
|
22
|
+
def __init__(self, processes: list[ProcessStartInformation]):
|
|
23
|
+
self.sc = ScriptCollectionCore()
|
|
24
|
+
self.processes = processes
|
|
25
|
+
|
|
26
|
+
def run(self):
|
|
27
|
+
pids: list[int] = list[int]()
|
|
28
|
+
for processstartinfo in self.processes:
|
|
29
|
+
pids.append(self.sc.run_program_async(processstartinfo.program, processstartinfo.argumentss, processstartinfo.workingdirectory))
|
|
30
|
+
enabled = True
|
|
31
|
+
while enabled:
|
|
32
|
+
for pid in pids:
|
|
33
|
+
if not psutil.pid_exists(pid):
|
|
34
|
+
enabled = False
|
|
35
|
+
# one program terminate so exit and terminate all now
|
|
36
|
+
processes = psutil.process_iter()
|
|
37
|
+
for pid in pids:
|
|
38
|
+
if psutil.pid_exists(pid):
|
|
39
|
+
for proc in processes:
|
|
40
|
+
if proc.pid == pid:
|
|
41
|
+
proc.kill()
|
|
@@ -1,42 +1,47 @@
|
|
|
1
|
-
from abc import abstractmethod
|
|
2
|
-
from subprocess import Popen
|
|
3
|
-
from .GeneralUtilities import GeneralUtilities
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class ProgramRunnerBase:
|
|
7
|
-
|
|
8
|
-
# Return-values program_runner: Pid
|
|
9
|
-
@abstractmethod
|
|
10
|
-
@GeneralUtilities.check_arguments
|
|
11
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> Popen:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from subprocess import Popen
|
|
3
|
+
from .GeneralUtilities import GeneralUtilities
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ProgramRunnerBase:
|
|
7
|
+
|
|
8
|
+
# Return-values program_runner: Pid
|
|
9
|
+
@abstractmethod
|
|
10
|
+
@GeneralUtilities.check_arguments
|
|
11
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
12
|
+
# Verbosity:
|
|
13
|
+
# 0=Quiet (No output will be printed.)
|
|
14
|
+
# 1=Normal (If the exitcode of the executed program is not 0 then the StdErr will be printed.)
|
|
15
|
+
# 2=Full (Prints StdOut and StdErr of the executed program.)
|
|
16
|
+
# 3=Verbose (Same as "Full" but with some more information.)
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
|
|
19
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
20
|
+
@abstractmethod
|
|
21
|
+
@GeneralUtilities.check_arguments
|
|
22
|
+
def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
26
|
+
@abstractmethod
|
|
27
|
+
@GeneralUtilities.check_arguments
|
|
28
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
|
|
31
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
32
|
+
@abstractmethod
|
|
33
|
+
@GeneralUtilities.check_arguments
|
|
34
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
|
|
37
|
+
# Return-values program_runner: Pid
|
|
38
|
+
@abstractmethod
|
|
39
|
+
@GeneralUtilities.check_arguments
|
|
40
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
|
|
43
|
+
# Return-values program_runner: Pid
|
|
44
|
+
@abstractmethod
|
|
45
|
+
@GeneralUtilities.check_arguments
|
|
46
|
+
def run_program_async(self, program: str, arguments: str, working_directory: str, custom_argument: object, interactive:bool=False) -> int:
|
|
47
|
+
raise NotImplementedError
|
|
@@ -1,122 +1,122 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import base64
|
|
3
|
-
import tempfile
|
|
4
|
-
from subprocess import Popen
|
|
5
|
-
from uuid import uuid4
|
|
6
|
-
|
|
7
|
-
from .GeneralUtilities import GeneralUtilities
|
|
8
|
-
from .ProgramRunnerBase import ProgramRunnerBase
|
|
9
|
-
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class CustomEpewArgument:
|
|
13
|
-
|
|
14
|
-
print_errors_as_information: bool
|
|
15
|
-
log_file: str
|
|
16
|
-
timeoutInSeconds: int
|
|
17
|
-
addLogOverhead: bool
|
|
18
|
-
title: str
|
|
19
|
-
log_namespace: str
|
|
20
|
-
verbosity: int
|
|
21
|
-
arguments_for_log: list[str]
|
|
22
|
-
tempdir = os.path.join(tempfile.gettempdir(), str(uuid4()))
|
|
23
|
-
stdoutfile = tempdir + ".epew.stdout.txt"
|
|
24
|
-
stderrfile = tempdir + ".epew.stderr.txt"
|
|
25
|
-
exitcodefile = tempdir + ".epew.exitcode.txt"
|
|
26
|
-
pidfile = tempdir + ".epew.pid.txt"
|
|
27
|
-
|
|
28
|
-
def __init__(self, print_errors_as_information: bool, log_file: str, timeoutInSeconds: int, addLogOverhead: bool, title: str, log_namespace: str, verbosity: int, arguments_for_log: list[str]):
|
|
29
|
-
self.print_errors_as_information = print_errors_as_information
|
|
30
|
-
self.log_file = log_file
|
|
31
|
-
self.timeoutInSeconds = timeoutInSeconds
|
|
32
|
-
self.addLogOverhead = addLogOverhead
|
|
33
|
-
self.title = title
|
|
34
|
-
self.log_namespace = log_namespace
|
|
35
|
-
self.verbosity = verbosity
|
|
36
|
-
self.arguments_for_log = arguments_for_log
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class ProgramRunnerEpew(ProgramRunnerBase):
|
|
40
|
-
|
|
41
|
-
@GeneralUtilities.check_arguments
|
|
42
|
-
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> Popen:
|
|
43
|
-
if GeneralUtilities.epew_is_available():
|
|
44
|
-
custom_argument: CustomEpewArgument = custom_argument
|
|
45
|
-
args = []
|
|
46
|
-
|
|
47
|
-
base64argument = base64.b64encode(' '.join(arguments_as_array).encode('utf-8')).decode('utf-8')
|
|
48
|
-
args.append(f'-p "{program}"')
|
|
49
|
-
args.append(f'-a {base64argument}')
|
|
50
|
-
args.append('-b')
|
|
51
|
-
args.append(f'-w "{working_directory}"')
|
|
52
|
-
if custom_argument.stdoutfile is not None:
|
|
53
|
-
args.append(f'-o {custom_argument.stdoutfile}')
|
|
54
|
-
if custom_argument.stderrfile is not None:
|
|
55
|
-
args.append(f'-e {custom_argument.stderrfile}')
|
|
56
|
-
if custom_argument.exitcodefile is not None:
|
|
57
|
-
args.append(f'-x {custom_argument.exitcodefile}')
|
|
58
|
-
if custom_argument.pidfile is not None:
|
|
59
|
-
args.append(f'-r {custom_argument.pidfile}')
|
|
60
|
-
args.append(f'-d {str(custom_argument.timeoutInSeconds*1000)}')
|
|
61
|
-
args.append(f'-t "{custom_argument.title}"')
|
|
62
|
-
args.append(f'-l "{custom_argument.log_namespace}"')
|
|
63
|
-
if not GeneralUtilities.string_is_none_or_whitespace(custom_argument.log_file):
|
|
64
|
-
args.append(f'-f "{custom_argument.log_file}"')
|
|
65
|
-
if custom_argument.print_errors_as_information:
|
|
66
|
-
args.append("-i")
|
|
67
|
-
if custom_argument.addLogOverhead:
|
|
68
|
-
args.append("-g")
|
|
69
|
-
args.append("-v "+str(custom_argument.verbosity))
|
|
70
|
-
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory)
|
|
71
|
-
else:
|
|
72
|
-
raise ValueError("Epew is not available.")
|
|
73
|
-
|
|
74
|
-
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
75
|
-
@GeneralUtilities.check_arguments
|
|
76
|
-
def wait(self, process: Popen, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
77
|
-
process.wait()
|
|
78
|
-
custom_argument: CustomEpewArgument = custom_argument
|
|
79
|
-
stdout = self.__load_text(custom_argument.output_file_for_stdout)
|
|
80
|
-
stderr = self.__load_text(custom_argument.output_file_for_stderr)
|
|
81
|
-
exit_code = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_exit_code))
|
|
82
|
-
pid = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_pid))
|
|
83
|
-
GeneralUtilities.ensure_directory_does_not_exist(custom_argument.tempdir)
|
|
84
|
-
result = (exit_code, stdout, stderr, pid)
|
|
85
|
-
return result
|
|
86
|
-
|
|
87
|
-
@GeneralUtilities.check_arguments
|
|
88
|
-
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
89
|
-
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument)
|
|
90
|
-
return self.wait(process, custom_argument)
|
|
91
|
-
|
|
92
|
-
@GeneralUtilities.check_arguments
|
|
93
|
-
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
94
|
-
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
95
|
-
|
|
96
|
-
@GeneralUtilities.check_arguments
|
|
97
|
-
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None) -> int:
|
|
98
|
-
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument).pid
|
|
99
|
-
|
|
100
|
-
@GeneralUtilities.check_arguments
|
|
101
|
-
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None) -> int:
|
|
102
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
103
|
-
|
|
104
|
-
@GeneralUtilities.check_arguments
|
|
105
|
-
def __get_number_from_filecontent(self, filecontent: str) -> int:
|
|
106
|
-
for line in filecontent.splitlines():
|
|
107
|
-
try:
|
|
108
|
-
striped_line = GeneralUtilities.strip_new_line_character(line)
|
|
109
|
-
result = int(striped_line)
|
|
110
|
-
return result
|
|
111
|
-
except:
|
|
112
|
-
pass
|
|
113
|
-
raise ValueError(f"'{filecontent}' does not containe an int-line")
|
|
114
|
-
|
|
115
|
-
@GeneralUtilities.check_arguments
|
|
116
|
-
def __load_text(self, file: str) -> str:
|
|
117
|
-
if os.path.isfile(file):
|
|
118
|
-
content = GeneralUtilities.read_text_from_file(file).replace('\r', '')
|
|
119
|
-
os.remove(file)
|
|
120
|
-
return content
|
|
121
|
-
else:
|
|
122
|
-
raise ValueError(f"File '{file}' does not exist")
|
|
1
|
+
import os
|
|
2
|
+
import base64
|
|
3
|
+
import tempfile
|
|
4
|
+
from subprocess import Popen
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from .GeneralUtilities import GeneralUtilities
|
|
8
|
+
from .ProgramRunnerBase import ProgramRunnerBase
|
|
9
|
+
from .ProgramRunnerPopen import ProgramRunnerPopen
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CustomEpewArgument:
|
|
13
|
+
|
|
14
|
+
print_errors_as_information: bool
|
|
15
|
+
log_file: str
|
|
16
|
+
timeoutInSeconds: int
|
|
17
|
+
addLogOverhead: bool
|
|
18
|
+
title: str
|
|
19
|
+
log_namespace: str
|
|
20
|
+
verbosity: int
|
|
21
|
+
arguments_for_log: list[str]
|
|
22
|
+
tempdir = os.path.join(tempfile.gettempdir(), str(uuid4()))
|
|
23
|
+
stdoutfile = tempdir + ".epew.stdout.txt"
|
|
24
|
+
stderrfile = tempdir + ".epew.stderr.txt"
|
|
25
|
+
exitcodefile = tempdir + ".epew.exitcode.txt"
|
|
26
|
+
pidfile = tempdir + ".epew.pid.txt"
|
|
27
|
+
|
|
28
|
+
def __init__(self, print_errors_as_information: bool, log_file: str, timeoutInSeconds: int, addLogOverhead: bool, title: str, log_namespace: str, verbosity: int, arguments_for_log: list[str]):
|
|
29
|
+
self.print_errors_as_information = print_errors_as_information
|
|
30
|
+
self.log_file = log_file
|
|
31
|
+
self.timeoutInSeconds = timeoutInSeconds
|
|
32
|
+
self.addLogOverhead = addLogOverhead
|
|
33
|
+
self.title = title
|
|
34
|
+
self.log_namespace = log_namespace
|
|
35
|
+
self.verbosity = verbosity
|
|
36
|
+
self.arguments_for_log = arguments_for_log
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProgramRunnerEpew(ProgramRunnerBase):
|
|
40
|
+
|
|
41
|
+
@GeneralUtilities.check_arguments
|
|
42
|
+
def run_program_argsasarray_async_helper(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> Popen:
|
|
43
|
+
if GeneralUtilities.epew_is_available():
|
|
44
|
+
custom_argument: CustomEpewArgument = custom_argument
|
|
45
|
+
args = []
|
|
46
|
+
|
|
47
|
+
base64argument = base64.b64encode(' '.join(arguments_as_array).encode('utf-8')).decode('utf-8')
|
|
48
|
+
args.append(f'-p "{program}"')
|
|
49
|
+
args.append(f'-a {base64argument}')
|
|
50
|
+
args.append('-b')
|
|
51
|
+
args.append(f'-w "{working_directory}"')
|
|
52
|
+
if custom_argument.stdoutfile is not None:
|
|
53
|
+
args.append(f'-o {custom_argument.stdoutfile}')
|
|
54
|
+
if custom_argument.stderrfile is not None:
|
|
55
|
+
args.append(f'-e {custom_argument.stderrfile}')
|
|
56
|
+
if custom_argument.exitcodefile is not None:
|
|
57
|
+
args.append(f'-x {custom_argument.exitcodefile}')
|
|
58
|
+
if custom_argument.pidfile is not None:
|
|
59
|
+
args.append(f'-r {custom_argument.pidfile}')
|
|
60
|
+
args.append(f'-d {str(custom_argument.timeoutInSeconds*1000)}')
|
|
61
|
+
args.append(f'-t "{custom_argument.title}"')
|
|
62
|
+
args.append(f'-l "{custom_argument.log_namespace}"')
|
|
63
|
+
if not GeneralUtilities.string_is_none_or_whitespace(custom_argument.log_file):
|
|
64
|
+
args.append(f'-f "{custom_argument.log_file}"')
|
|
65
|
+
if custom_argument.print_errors_as_information:
|
|
66
|
+
args.append("-i")
|
|
67
|
+
if custom_argument.addLogOverhead:
|
|
68
|
+
args.append("-g")
|
|
69
|
+
args.append("-v "+str(custom_argument.verbosity))
|
|
70
|
+
return ProgramRunnerPopen().run_program_argsasarray_async_helper("epew", args, working_directory,custom_argument,interactive)
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError("Epew is not available.")
|
|
73
|
+
|
|
74
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
75
|
+
@GeneralUtilities.check_arguments
|
|
76
|
+
def wait(self, process: Popen, custom_argument: object = None) -> tuple[int, str, str, int]:
|
|
77
|
+
process.wait()
|
|
78
|
+
custom_argument: CustomEpewArgument = custom_argument
|
|
79
|
+
stdout = self.__load_text(custom_argument.output_file_for_stdout)
|
|
80
|
+
stderr = self.__load_text(custom_argument.output_file_for_stderr)
|
|
81
|
+
exit_code = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_exit_code))
|
|
82
|
+
pid = self.__get_number_from_filecontent(self.__load_text(custom_argument.output_file_for_pid))
|
|
83
|
+
GeneralUtilities.ensure_directory_does_not_exist(custom_argument.tempdir)
|
|
84
|
+
result = (exit_code, stdout, stderr, pid)
|
|
85
|
+
return result
|
|
86
|
+
|
|
87
|
+
@GeneralUtilities.check_arguments
|
|
88
|
+
def run_program_argsasarray(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
89
|
+
process: Popen = self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive)
|
|
90
|
+
return self.wait(process, custom_argument)
|
|
91
|
+
|
|
92
|
+
@GeneralUtilities.check_arguments
|
|
93
|
+
def run_program(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> tuple[int, str, str, int]:
|
|
94
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
95
|
+
|
|
96
|
+
@GeneralUtilities.check_arguments
|
|
97
|
+
def run_program_argsasarray_async(self, program: str, arguments_as_array: list[str] = [], working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
98
|
+
return self.run_program_argsasarray_async_helper(program, arguments_as_array, working_directory, custom_argument,interactive).pid
|
|
99
|
+
|
|
100
|
+
@GeneralUtilities.check_arguments
|
|
101
|
+
def run_program_async(self, program: str, arguments: str = "", working_directory: str = None, custom_argument: object = None, interactive:bool=False) -> int:
|
|
102
|
+
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument,interactive)
|
|
103
|
+
|
|
104
|
+
@GeneralUtilities.check_arguments
|
|
105
|
+
def __get_number_from_filecontent(self, filecontent: str) -> int:
|
|
106
|
+
for line in filecontent.splitlines():
|
|
107
|
+
try:
|
|
108
|
+
striped_line = GeneralUtilities.strip_new_line_character(line)
|
|
109
|
+
result = int(striped_line)
|
|
110
|
+
return result
|
|
111
|
+
except:
|
|
112
|
+
pass
|
|
113
|
+
raise ValueError(f"'{filecontent}' does not containe an int-line")
|
|
114
|
+
|
|
115
|
+
@GeneralUtilities.check_arguments
|
|
116
|
+
def __load_text(self, file: str) -> str:
|
|
117
|
+
if os.path.isfile(file):
|
|
118
|
+
content = GeneralUtilities.read_text_from_file(file).replace('\r', '')
|
|
119
|
+
os.remove(file)
|
|
120
|
+
return content
|
|
121
|
+
else:
|
|
122
|
+
raise ValueError(f"File '{file}' does not exist")
|
|
@@ -1,52 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
from subprocess import PIPE, Popen
|
|
3
|
-
from .GeneralUtilities import GeneralUtilities
|
|
4
|
-
from .ProgramRunnerBase import ProgramRunnerBase
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ProgramRunnerPopen(ProgramRunnerBase):
|
|
8
|
-
|
|
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) -> Popen:
|
|
11
|
-
arguments_for_process = [program]
|
|
12
|
-
arguments_for_process.extend(arguments_as_array)
|
|
13
|
-
# "shell=True" is not allowed because it is not recommended and also something like
|
|
14
|
-
# "ScriptCollectionCore().run_program('curl', 'https://example.com/dataset?id=1&format=json')"
|
|
15
|
-
# would not be possible anymore because the ampersand will be treated as shell-command.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
result
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return self.run_program_argsasarray_async(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
1
|
+
import sys
|
|
2
|
+
from subprocess import PIPE, Popen
|
|
3
|
+
from .GeneralUtilities import GeneralUtilities
|
|
4
|
+
from .ProgramRunnerBase import ProgramRunnerBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProgramRunnerPopen(ProgramRunnerBase):
|
|
8
|
+
|
|
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:
|
|
11
|
+
arguments_for_process = [program]
|
|
12
|
+
arguments_for_process.extend(arguments_as_array)
|
|
13
|
+
# "shell=True" is not allowed because it is not recommended and also something like
|
|
14
|
+
# "ScriptCollectionCore().run_program('curl', 'https://example.com/dataset?id=1&format=json')"
|
|
15
|
+
# would not be possible anymore because the ampersand will be treated as shell-command.
|
|
16
|
+
try:
|
|
17
|
+
if interactive:
|
|
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
|
+
else:
|
|
20
|
+
result = Popen(arguments_for_process, cwd=working_directory, stdout=PIPE, stderr=PIPE, shell=False, text=True) # pylint: disable=consider-using-with
|
|
21
|
+
except FileNotFoundError as fileNotFoundError:
|
|
22
|
+
raise FileNotFoundError(f"Starting '{program}' in '{working_directory}' resulted in a FileNotFoundError: '{fileNotFoundError.filename}'")
|
|
23
|
+
return result
|
|
24
|
+
|
|
25
|
+
# Return-values program_runner: Exitcode, StdOut, StdErr, Pid
|
|
26
|
+
@GeneralUtilities.check_arguments
|
|
27
|
+
def wait(self, process: Popen, custom_argument: object) -> tuple[int, str, str, int]:
|
|
28
|
+
pid = process.pid
|
|
29
|
+
stdout, stderr = process.communicate()
|
|
30
|
+
exit_code = process.wait()
|
|
31
|
+
stdout = GeneralUtilities.bytes_to_string(stdout).replace('\r', '')
|
|
32
|
+
stderr = GeneralUtilities.bytes_to_string(stderr).replace('\r', '')
|
|
33
|
+
result = (exit_code, stdout, stderr, pid)
|
|
34
|
+
return result
|
|
35
|
+
|
|
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)
|
|
39
|
+
return self.wait(process, custom_argument)
|
|
40
|
+
|
|
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]:
|
|
43
|
+
return self.run_program_argsasarray(program, GeneralUtilities.arguments_to_array(arguments), working_directory, custom_argument)
|
|
44
|
+
|
|
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
|
|
48
|
+
|
|
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)
|