-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStandardFunctor.py
More file actions
144 lines (123 loc) · 4.44 KB
/
Copy pathStandardFunctor.py
File metadata and controls
144 lines (123 loc) · 4.44 KB
1
2
3
4
5
6
7
8
9
10
11
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import logging
from pathlib import Path
from subprocess import Popen, PIPE, STDOUT
from .Functor import Functor
from .Method import method
# The standard Functor extends Functor to add a set of standard members and methods.
# This is similar to the standard library in C and C++
# You must inherit from *this if you would like to use the functionality *this provides. The methods defined will not be propagated.
class StandardFunctor(Functor):
def __init__(this, name="Standard Functor"):
super().__init__(name)
# Override this and do whatever!
# This is purposefully vague.
def Function(this):
pass
# Undo any changes made by UserFunction.
# Please override this too!
def Rollback(this):
pass
# Override this to check results of operation and report on status.
# Override this to perform whatever success checks are necessary.
def DidFunctionSucceed(this):
return this.functionSucceeded
# RETURN whether or not the Rollback was successful.
# Override this to perform whatever success checks are necessary.
def DidRollbackSucceed(this):
return this.rollbackSucceeded
######## START: UTILITIES ########
# RETURNS: an opened file object for writing.
# Creates the path if it does not exist.
@method()
def CreateFile(this, file, mode="w+"):
Path(os.path.dirname(os.path.abspath(file))).mkdir(parents=True, exist_ok=True)
return open(file, mode)
# Copy a file or folder from source to destination.
# This really shouldn't be so hard...
# root allows us to interpret '/' as something other than the top of the filesystem.
@method()
def Copy(this, source, destination, root='/'):
if (source.startswith('/')):
source = str(Path(root).joinpath(source[1:]).resolve())
else:
source = str(Path(source).resolve())
destination = str(Path(destination).resolve())
Path(destination).parent.mkdir(parents=True, exist_ok=True)
if (os.path.isfile(source)):
logging.debug(f"Copying file {source} to {destination}")
try:
shutil.copy(source, destination)
except shutil.Error as exc:
errors = exc.args[0]
for error in errors:
src, dst, msg = error
logging.debug(f"{msg}")
elif (os.path.isdir(source)):
logging.debug(f"Copying directory {source} to {destination}")
try:
shutil.copytree(source, destination)
except shutil.Error as exc:
errors = exc.args[0]
for error in errors:
src, dst, msg = error
logging.debug(f"{msg}")
for sub in Path(source).iterdir():
if (sub.is_dir()):
try:
shutil.copytree(sub, Path(destination).joinpath(sub.name))
except shutil.Error as exc2:
errors = exc2.args[0]
for error in errors:
src, dst, msg = error
logging.debug(f"{msg}")
else:
try:
shutil.copy(sub, Path(destination).joinpath(sub.name))
except shutil.Error as exc2:
errors = exc2.args[0]
for error in errors:
src, dst, msg = error
logging.debug(f"{msg}")
else:
logging.error(f"Could not find source to copy: {source}")
# Delete a file or folder
@method()
def Delete(this, target):
if (not os.path.exists(target)):
logging.debug(f"Unable to delete nonexistent target: {target}")
return
if (os.path.isfile(target)):
logging.debug(f"Deleting file {target}")
os.remove(target)
elif (os.path.isdir(target)):
logging.debug(f"Deleting directory {target}")
try:
shutil.rmtree(target)
except shutil.Error as exc:
errors = exc.args[0]
for error in errors:
src, dst, msg = error
logging.debug(f"{msg}")
# Run whatever.
# DANGEROUS!!!!!
# RETURN: Return value and, optionally, the output as a list of lines.
@method()
def RunCommand(this, command, saveout=False, raiseExceptions=True):
logging.debug(f"================ Running command: {command} ================")
process = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True)
output = []
while process.poll() is None:
line = process.stdout.readline().decode('utf8')[:-1]
if (saveout):
output.append(line)
if (line):
logging.debug(f"| {line}") # [:-1] to strip excessive new lines.
message = f"Command returned {process.returncode}: {command}"
logging.debug(message)
if (raiseExceptions and process.returncode is not None and process.returncode):
raise CommandUnsuccessful(message)
logging.debug(f"================ Completed command: {command} ================")
if (saveout):
return process.returncode, output
return process.returncode
######## END: UTILITIES ########