-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathmoss.py
More file actions
140 lines (116 loc) · 5.53 KB
/
Copy pathmoss.py
File metadata and controls
140 lines (116 loc) · 5.53 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
import os
import subprocess
import shlex
import glob
import tempfile
import re
import difflib
from server.models import Assignment, Backup, db
from server.utils import encode_id
from server import jobs
@jobs.background_job
def submit_to_moss(moss_id=None, file_regex=".*", assignment_id=None, language=None,
subtract_template=False):
logger = jobs.get_job_logger()
logger.info('Starting MOSS Export...')
assign = Assignment.query.filter_by(id=assignment_id).one_or_none()
if not assign:
logger.info("Could not find assignment")
return
subms = assign.course_submissions(include_empty=False)
subm_keys = set()
for subm in subms:
if subm['backup']['id'] in subm_keys:
continue
else:
subm_keys.add(subm['backup']['id'])
if subm['group']:
group_members = subm['group']['group_member_emails'] or []
group_members.append(subm['user']['email'])
logger.info("{} -> {}".format(encode_id(subm['backup']['id']),
', '.join(group_members)))
else:
logger.info("{} -> {}".format(encode_id(subm['backup']['id']),
subm['user']['email']))
backup_query = (Backup.query.options(db.joinedload('messages'))
.filter(Backup.id.in_(subm_keys))
.order_by(Backup.created.desc())
.all())
logger.info("Retrieved {} final submissions".format(len(subm_keys)))
# TODO: Customize the location of the tmp writing (especially useful during dev)
with tempfile.TemporaryDirectory() as tmp_dir:
# Copy in the moss script
with open('server/jobs/moss-submission.pl', 'r') as f:
moss_script = f.read()
moss_script = moss_script.replace('YOUR_USER_ID_HERE', str(moss_id))
with open(tmp_dir + "/moss.pl", 'w') as script:
script.write(moss_script)
match_pattern = re.compile(file_regex)
ignored_files = set()
template_files = []
for template in assign.files:
dest = os.path.join(tmp_dir, template)
with open(dest, 'w') as f:
f.write(assign.files[template])
template_files.append(template)
logger.info("Using template files: {}".format(' '.join(template_files)))
if subtract_template:
logger.info("Subtract Template Enabled: Not sending templates through MOSS")
templates = ''
else:
templates = ' '.join(["-b {file}".format(file=f) for f in template_files])
for backup in backup_query:
# Write file into file
file_contents = [m for m in backup.messages if m.kind == 'file_contents']
if not file_contents:
logger.info("{} didn't have any file contents".format(backup.hashid))
continue
contents = file_contents[0].contents
dest_dir = os.path.join(tmp_dir, backup.hashid)
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir)
for file in contents:
if file == 'submit': # ignore fake file from ok-client
continue
if subtract_template and file in assign.files:
# Compare to template and only include lines that new
template, source = assign.files[file], contents[file]
d = difflib.Differ(linejunk=difflib.IS_LINE_JUNK,
charjunk=difflib.IS_CHARACTER_JUNK)
diff = d.compare(template.splitlines(keepends=True),
source.splitlines(keepends=True))
added = [line[1:] for line in diff if line[0] == '+']
contents[file] = ''.join(added)
if match_pattern.match(file):
with open(os.path.join(dest_dir, file), 'w') as f:
f.write(contents[file])
else:
ignored_files.add(file)
# tmp_dir contains folders of the form: backup_hashid/file1.py
os.chdir(tmp_dir)
all_student_files = glob.glob("*/*")
logger.info("Wrote all files to {}".format(tmp_dir))
if ignored_files:
logger.info("Regex {} ignored files with names: {}".format(file_regex,
ignored_files))
else:
logger.info("Regex {} has captured all possible files".format(file_regex))
if not all_student_files:
raise Exception("Did not match any files")
# Ensure that all of the files are in the tmp_dir (and not elsewhere)
command = ("perl moss.pl -l {lang} {templates} -d {folder}"
.format(lang=language, templates=templates,
folder=' '.join(all_student_files)))
logger.critical("Running {}".format(command[:100] + ' ...'))
try:
process = subprocess.check_output(shlex.split(command),
stderr=subprocess.STDOUT)
moss_output = process.decode("utf-8")
logger.info(moss_output)
last_line = moss_output
if 'moss.stanford' in last_line:
return last_line
except subprocess.CalledProcessError as e:
logger.warning("There was an error running the Moss Upload.")
logger.info("{}".format(e.output.decode('utf-8')))
raise e