-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild_new.py
executable file
·175 lines (131 loc) · 4.86 KB
/
build_new.py
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/usr/bin/env python
import sys
import os
import shutil
import subprocess
import argparse
import logging
from pprint import pprint
import fileinput
from typing import Tuple, List
import dryable
from distutils.dir_util import copy_tree
from build_utils import *
# the make pdf command to fire.
CMD_MAKE_PDF = 'make pdf'
def get_target_dirs(path: str = '.') -> List[str]:
"""
Returns the result of the `ls` command in path `path` listing
only non-hidden directories.
"""
def isdir(f): return os.path.isdir(f)
def ishidden(f): return f.startswith('.')
return [f for f in os.listdir(path) if isdir(f) and not ishidden(f)]
def ensure_path(path) -> str:
if not os.path.exists(path):
os.makedirs(path)
return path
@ dryable.Dryable([True, "dry-run"])
def trigger_build(path) -> Tuple[bool, str]:
logging.info(f'Building "{path}".')
cmd = f'cd {path}; {CMD_MAKE_PDF}'
proc = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
o, e = proc.communicate(timeout=20 * 60)
e = e.decode('utf-8')
o = o.decode('utf-8')
retcode = proc.returncode
if retcode == 0:
logging.info(f'Build of "{path}" has done with return code {retcode}.')
logging.debug(f'Output: {o}')
return (True, o)
else:
logging.error(
f'Build of "{path}" has failed with return code {retcode}.')
logging.debug(f'Output: {o}')
logging.debug(f'Error: {e}')
return (False, e)
@dryable.Dryable([True, "dry-run"])
def copy_dist(path) -> Tuple[bool, str]:
dist_folder = '.dist'
ensure_path(dist_folder)
logging.info(f'Copying dist from "{path}" to "{dist_folder}".')
conventional_dirs = ["exercise", "solution"]
# Note: when *Weak Conventions* are not followed (see README.md) the scripts copies only
# pdf and cpp files. Instead, when `exercise` and/or `solution` folders are present
# the script copies only the two directories and their content.
# TODO: move weak conventions to strict conventions will simplify the code.
copy_list = []
for root, dirs, files in os.walk(path):
for name in dirs:
if name in conventional_dirs:
copy_list.append(os.path.join(root, name))
for name in files:
if name.endswith(".pdf"):
copy_list.append(os.path.join(root, name))
logging.debug(copy_list)
# Copy pdfs, solution and exercises folder to their folder in `.dist`
for name in copy_list:
if os.path.isdir(name):
copy_tree(name, os.path.join(dist_folder, name))
else:
newdir = os.path.join(dist_folder, os.path.dirname(name))
newfile = os.path.join(dist_folder, name)
ensure_path(newdir)
shutil.copy(name, newfile)
# Copy all pdfs in one directory
assigmnets_fodler = ".dist-pdf"
ensure_path(assigmnets_fodler)
for name in copy_list:
if not os.path.isdir(name) and name.endswith(".pdf"):
assigment_name = os.path.dirname(name)
newfile = os.path.join(assigmnets_fodler, assigment_name + ".pdf")
shutil.copy(name, newfile)
logging.info(f'Copied {len(copy_list)} files.')
return (True, "")
def main(args, loglevel):
logging.basicConfig(format="%(levelname)s: %(message)s", level=loglevel)
target_dirs = get_target_dirs()
print(f'Building directories.')
failed_no = 0
build_no = 0
for d in target_dirs:
build_no += 1
(build_ok, out) = trigger_build(d)
(copy_ok, _) = copy_dist(d)
if not build_ok:
failed_no += 1
# print(out)
# TODO handle build failures
print(
f'Build completed with {build_no-failed_no} success and {failed_no} failed, total {build_no}.')
return 0 if (failed_no == 0) else 1
# entry point
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description="""
Welcome to the building script for the high school assignments.
You can build assignments source with a single command.
(C) Luca Parolari <[email protected]>
""",
epilog="""
As an alternative to the commandline, params can be placed
in a file, one per line, and specified on the commandline
like '%(prog)s @params.conf'.
""",
fromfile_prefix_chars='@')
parser.add_argument(
"--dry-run",
help="Do a trial run with actions performed.",
action="store_true")
parser.add_argument(
"-v",
"--verbose",
help="Increase output verbosity.",
action="store_true")
args = parser.parse_args()
dryable.set(args.dry_run)
log_level = get_log_level(args.verbose)
main(args, log_level or logging.INFO)