Newer
Older
import os, shutil
from coursebox.core.info_paths import get_paths
from coursebox.core.info import class_information
from snipper.snip_dir import snip_dir
from coursebox.material.homepage_lectures_exercises import fix_shared
from snipper.snipper_main import censor_file
from pathlib import Path
import fnmatch
import glob
from coursebox.material.documentation import fix_all_shared_files
def setup_student_files(run_files=True,
cut_files=True,
censor_files=True,
week=None, extra_dirs=None,
include_solutions=None,
projects=None,
fix_shared_files=True,
include_exam_examples=False, # Include the directory with exam-related examples.
verbose=True,
students_irlc_tools=None, # Destination dir for the irlc folder (the one we really want to deploy).
midterms=None, # Can be a list: [0, 1]
include_docs=False, # Include the documentation directory, i.e. 02465public/src/docs.
convert_svg=True, # Whether to convert SVG file when deploying. Leave to true, unless we are doing CI/CD in which case inkscape may not be installed.
):
if midterms is None:
midterms = []
from coursebox.core import info_paths
# info = class_information()
from coursebox.core.info import core_conf
if len(core_conf['projects_all']) > 0:
PACKAGE = list(core_conf['projects_all'].values()).pop()['module_public'].split(".")[0]
else:
PACKAGE = [w for w in core_conf['weeks_all'].values() if 'module_public' in w][0]['module_public'].split(".")[0]
if censor_files:
assert not run_files, "You cannot run files while you are censoring them -- your scripts will crash. Call with run_files=False."
week = [week] if isinstance(week, int) else week
if verbose:
print("toolbox running. Fixing student files by copying to student dir")
paths = get_paths()
if include_solutions is None:
include_solutions = []
if projects is None:
projects = []
public_irlc_tools = f"{paths['02450public']}/src/{PACKAGE}"
students_irlc_tools = f"{paths['02450students']}/{PACKAGE}"
students_irlc_tools = f"{paths['02450students']}_complete/{PACKAGE}"
if not os.path.isdir(students_irlc_tools):
os.makedirs(students_irlc_tools)
init_dest = students_irlc_tools+"/__init__.py"
shutil.copy(public_irlc_tools + "/__init__.py", init_dest)
for fpy in glob.glob(public_irlc_tools + "/*.py"):
shutil.copy(fpy, students_irlc_tools + "/" + os.path.basename(fpy))
if os.path.isfile(public_irlc_tools + "/../.coveragerc"):
shutil.copy(public_irlc_tools + "/../.coveragerc", students_irlc_tools+ "/../.coveragerc")
# assert False
censor_file(init_dest)
# Check for exclusion mask.
exclude = list( info_paths.core_conf.get('student_files', {}).get('exclude', []) )
extra_dirs = list(info_paths.core_conf.get('student_files', {}).get('extra_dirs', []))
exclude += [f'tests_week{w if w >= 10 else f"0{w}"}.py' for w in range(0,14) if w not in week]
exclude = exclude + ["**/" + ex for ex in exclude]
if not include_exam_examples:
inclusion = [] # 'ex09old/cache']
hws = []
for m in midterms:
# Copy the midterm from the exam directory into the public repository. This will ensure the midterm is later propagated to the student directory.
# The midterm should always be distributed as a .zip file: This is the only legal distribution mechanism.
# The midterm in the student directory does not need to be super-duper up to date. This is not the file which is distributed 'officially'.
if verbose:
print(m)
if extra_dirs is None:
extra_dirs = ['utils', 'tests', 'exam/exam2023spring', 'pacman', 'gridworld', 'car'] # 'assignments',
for m in midterms:
if m == 0:
extra_dirs += ['exam/midterm2023a']
if m == 1:
extra_dirs += ['exam/midterm2023b']
# if include_exam_examples:
# extra_dirs += ['exam_tabular_examples']
if setup_lectures:
extra_dirs += [
# 'lectures/chapter0pythonC',
# 'lectures/chapter0pythonA',
# 'lectures/chapter0pythonB',
# 'lectures/chapter1',
'lectures',
# 'workshop'
]
for id in projects:
# if setup_projects:
if 'projects_all' in info_paths.core_conf:
p = info_paths.core_conf['projects_all'][id]['class']
extra_dirs += [os.path.basename(os.path.dirname(p.mfile()))]
else:
if id <= 3:
extra_dirs += [f'project{id}'] # , 'project1', 'project2', 'project3']
else:
extra_dirs.append(f'project3i')
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
if week is not None:
for w in week:
ex = str(w)
ex = "ex" + ("0" + ex if len(ex) < 2 else ex)
base = public_irlc_tools +"/"+ex
if not os.path.isdir(base):
continue
d = {'base': base,
'out': students_irlc_tools +"/"+ex,
'exclusion': exclude,
'inclusion': inclusion,
'include_solutions': w in include_solutions,
'week': w}
hws.append(d)
weekn = 101
for weekn, d in enumerate(extra_dirs):
dutil = {'base': public_irlc_tools + "/" + d,
'out': students_irlc_tools + "/" + d,
'exclusion': exclude,
'inclusion': inclusion,
'include_solutions': False,
'week': f'{weekn+100}'}
hws.append(dutil)
weekn += 1
else:
raise Exception("Specify a week")
if len(hws) > 0:
info = class_information(verbose=verbose)
else:
info = None
for hw in hws:
# if "ex08" in hw['out']:
# print("ex08")
print("Fixing hw", hw['out'])
n = fix_hw(paths=paths, info=info, hw=hw, out= hw['out'], output_dir=paths['shared'] +"/output", run_files=run_files, cut_files=cut_files,
package_base_dir=os.path.dirname(students_irlc_tools), censor_files=censor_files, strict=strict,
include_solutions=hw.get('include_solutions', False),
verbose=verbose)
if censor_files:
with open(paths['shared'] + f"/output/lines_{hw['week']}.txt", 'w') as f:
f.write(str(n))
if fix_shared_files:
if verbose:
print("> Homework fixed, copying shared files...")
fix_all_shared_files(paths=paths, compile_templates=False, verbose=verbose, dosvg=convert_svg)
if verbose:
print("> Removing excluded files from students gitlab directory...")
# for f in exclude + ["lectures"]:
for l in list(Path(students_irlc_tools).glob('**/*')):
if not os.path.exists(l): # May have been removed as part of a subtree
continue
m = [ ex for ex in exclude if fnmatch.fnmatch(l, ex)]
if len(m) > 0:
if os.path.isdir(l):
shutil.rmtree(l)
else:
os.remove(l)
for f in glob.glob(public_irlc_tools +"/../requirements*.txt"):
if "full" in os.path.basename(f):
continue
os.path.basename(f) # Copy requirements and all simiarly named files.
shutil.copy(f, students_irlc_tools +"/../"+os.path.basename(f))
# shutil.copy(public_irlc_tools +"/../requirements_conda.txt", students_irlc_tools +"/../requirements_conda.txt")
# Don't think we need this anymore. Why copy docs if they cannot be compiled anyway? Perhaps for the complete docs?
if include_docs:
if os.path.isdir(students_irlc_tools + "/../docs"):
shutil.rmtree(students_irlc_tools + "/../docs")
# if not censor_files:
shutil.copytree(public_irlc_tools + "/../docs", students_irlc_tools + "/../docs")
# Fix reference to output.
snip_dir(public_irlc_tools + "/../docs/source", students_irlc_tools + "/../docs/source", run_files=False, cut_files=False, censor_files=False, references=info['references'], verbose=verbose)
if verbose:
print("> All student file stuff completed.")
def fix_hw(paths, info, hw, out, output_dir, run_files=False, cut_files=False, censor_files=True,
include_solutions=False,
package_base_dir=None, # When runing files using #!o, this specify the base directory of the package the files resides in. Can be None.
verbose=True,
**kwargs):
n, cutouts = snip_dir(source_dir=hw['base'], dest_dir=out, output_dir=output_dir, exclude=hw['exclusion'], references=info['references'],
run_files=run_files, cut_files=cut_files, license_head=info.get('code_copyright', None),
censor_files=censor_files,verbose=verbose,package_base_dir=package_base_dir)
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
if include_solutions:
wk = hw['base'].split("/")[-1]
sp = paths['02450students'] + "/solutions/"
if not os.path.exists(sp):
os.mkdir(sp)
sp = sp + wk
if os.path.isdir(sp):
shutil.rmtree(sp)
# if not os.path.exists(sp):
os.mkdir(sp)
for f, cut in cutouts.items():
if len(cut) > 0:
fname = os.path.basename(f)
sols = []
stext = ["\n".join(lines) for lines in cut]
for i, sol in enumerate(stext):
sols.append((sol,))
sout = sp + f"/{os.path.basename(fname)[:-3]}_TODO_{i + 1}.py"
wsol = True
print(sout, "(published)" if wsol else "")
if wsol:
with open(sout, "w") as f:
f.write(sol)
return n