|
1 | 1 | import os
|
2 | 2 | import re
|
3 | 3 | import json
|
4 |
| -import boto3 |
5 | 4 | import base64
|
6 | 5 | import shutil
|
7 | 6 | import hashlib
|
8 | 7 | import zipfile
|
9 |
| -import paramiko |
10 | 8 | import tempfile
|
11 | 9 | import pycparser
|
12 | 10 | from os import environ
|
13 | 11 | from glob import glob
|
14 |
| -from Crypto import Random |
15 | 12 | from subprocess import run
|
16 | 13 | from subprocess import PIPE
|
17 | 14 | from tabulate import tabulate
|
18 |
| -from Crypto.Cipher import AES |
19 | 15 | from distutils.dir_util import copy_tree
|
20 | 16 |
|
21 | 17 |
|
22 |
| -# encrypt a string |
23 |
| -def encrypt(raw): |
24 |
| - def pad(s): |
25 |
| - return s + (16 - len(s) % 16) * chr(16 - len(s) % 16) |
26 |
| - rawkey = environ['AUTOGRADERS_KEY'] |
27 |
| - key = hashlib.sha256(rawkey.encode()).digest() |
28 |
| - raw = pad(raw) |
29 |
| - iv = Random.new().read(AES.block_size) |
30 |
| - cipher = AES.new(key, AES.MODE_CBC, iv) |
31 |
| - return base64.b64encode(iv + cipher.encrypt(raw)).decode() |
32 |
| - |
33 |
| - |
34 |
| -# decrypt an encrypted string |
35 |
| -def decrypt(enc): |
36 |
| - def unpad(s): |
37 |
| - if (type(s[-1]) == int): |
38 |
| - return s[0: -s[-1]] |
39 |
| - return s[0: -ord(s[-1])] |
40 |
| - enc = base64.b64decode(enc) |
41 |
| - iv = enc[:16] |
42 |
| - rawkey = environ['AUTOGRADERS_KEY'] |
43 |
| - key = hashlib.sha256(rawkey.encode()).digest() |
44 |
| - cipher = AES.new(key, AES.MODE_CBC, iv) |
45 |
| - return unpad(cipher.decrypt(enc[16:])).decode() |
| 18 | +# builds program file string |
| 19 | +def get_ex(ch, ex): |
| 20 | + return f"./ch{ch}/ex-{ch}.{ex}.c" |
46 | 21 |
|
47 | 22 |
|
| 23 | +# builds program test file string |
| 24 | +def get_in(ch, ex): |
| 25 | + if (ch == 1): |
| 26 | + if (ex == 9): |
| 27 | + return "./ch1/spaces.test" |
| 28 | + elif (ex == 13 or ex == 14): |
| 29 | + return "./ch1/words.test" |
| 30 | + elif (ex == 17): |
| 31 | + return "./ch1/long.test" |
| 32 | + elif (ex == 20): |
| 33 | + return "./ch1/tabs.test" |
| 34 | + else: |
| 35 | + return "./ch1/input.test" |
| 36 | + else: |
| 37 | + return "placeholder.test" |
| 38 | + |
| 39 | +# builds expected output file string |
| 40 | +def get_out(ch, ex): |
| 41 | + return f"./ch{ch}/expected-{ch}.{ex}" |
| 42 | + |
48 | 43 | # reads a file
|
49 | 44 | def read(filename):
|
50 | 45 | f = open(filename, 'r')
|
@@ -154,12 +149,66 @@ def expected_files(files, dir='.'):
|
154 | 149 | def execute(cmd=[], shell=False, dir='.', input=None, encoding='ascii', timeout=5):
|
155 | 150 | return run(cmd, shell=shell, stdout=PIPE, stderr=PIPE, input=input, cwd=dir, timeout=timeout)
|
156 | 151 |
|
157 |
| - |
158 | 152 | # makes a target
|
159 | 153 | def make(target=''):
|
160 | 154 | return execute(cmd=['make', target])
|
161 | 155 |
|
162 | 156 |
|
| 157 | +# compile a target |
| 158 | +def compile(target=''): |
| 159 | + return execute(cmd=['gcc', '-std=c99', target]) |
| 160 | + |
| 161 | +# run a file |
| 162 | +def run_program(command): |
| 163 | + return run(command, shell=True, stdout=PIPE, stderr=PIPE, cwd='.', timeout=10) |
| 164 | + |
| 165 | + |
| 166 | +# passed message |
| 167 | +def passed(*args): |
| 168 | + if len(args) > 0: |
| 169 | + return 'passed: ' + args[0] |
| 170 | + return 'passed' |
| 171 | + |
| 172 | + |
| 173 | +# failed message |
| 174 | +def failed(*args): |
| 175 | + if len(args) > 0: |
| 176 | + return 'failed: ' + args[0] |
| 177 | + return 'failed' |
| 178 | + |
| 179 | + |
| 180 | +# incomplete message |
| 181 | +def incomplete(*args): |
| 182 | + if len(args) > 0: |
| 183 | + return 'incomplete: ' + args[0] |
| 184 | + return 'incomplete' |
| 185 | + |
| 186 | + |
| 187 | +# creates a compilation error msg |
| 188 | +def create_error(filename, msg): |
| 189 | + if msg != '': |
| 190 | + return '[%s]\n\n%s\n' % (filename, msg) |
| 191 | + return '' |
| 192 | + |
| 193 | + |
| 194 | +# creates a pretty result report |
| 195 | +def report(table): |
| 196 | + return tabulate(table, headers=['Exercise', 'Grade', 'Message']) |
| 197 | + |
| 198 | + |
| 199 | +# writes autograder result (lab) |
| 200 | +def write_result(grade, msg): |
| 201 | + write_json({'grade': grade, 'output': msg}, 'output.json') |
| 202 | + |
| 203 | + |
| 204 | +# finds a specific function in the ast |
| 205 | +def find_func(ast, name): |
| 206 | + for f in ast.ext: |
| 207 | + if type(f) == pycparser.c_ast.FuncDef and f.decl.name == name: |
| 208 | + return f |
| 209 | + return None |
| 210 | + |
| 211 | + |
163 | 212 | # parses a form
|
164 | 213 | def parse_form(f):
|
165 | 214 | f = open(f, 'r', encoding='latin1')
|
@@ -212,93 +261,3 @@ def parse_c_raw(filename):
|
212 | 261 | text = task.stdout.decode().strip()
|
213 | 262 | parser = pycparser.c_parser.CParser()
|
214 | 263 | return parser.parse(text)
|
215 |
| - |
216 |
| - |
217 |
| -# passed message |
218 |
| -def passed(*args): |
219 |
| - if len(args) > 0: |
220 |
| - return 'passed: ' + args[0] |
221 |
| - return 'passed' |
222 |
| - |
223 |
| - |
224 |
| -# failed message |
225 |
| -def failed(*args): |
226 |
| - if len(args) > 0: |
227 |
| - return 'failed: ' + args[0] |
228 |
| - return 'failed' |
229 |
| - |
230 |
| - |
231 |
| -# incomplete message |
232 |
| -def incomplete(*args): |
233 |
| - if len(args) > 0: |
234 |
| - return 'incomplete: ' + args[0] |
235 |
| - return 'incomplete' |
236 |
| - |
237 |
| - |
238 |
| -# creates a compilation error msg |
239 |
| -def create_error(filename, msg): |
240 |
| - if msg != '': |
241 |
| - return '[%s]\n\n%s\n' % (filename, msg) |
242 |
| - return '' |
243 |
| - |
244 |
| - |
245 |
| -# creates a pretty result report |
246 |
| -def report(table): |
247 |
| - return tabulate(table, headers=['Exercise', 'Grade', 'Message']) |
248 |
| - |
249 |
| - |
250 |
| -# writes autograder result |
251 |
| -def write_result(grade, msg): |
252 |
| - write_json({'grade': grade, 'output': msg}, 'output.json') |
253 |
| - |
254 |
| - |
255 |
| -# finds a specific function in the ast |
256 |
| -def find_func(ast, name): |
257 |
| - for f in ast.ext: |
258 |
| - if type(f) == pycparser.c_ast.FuncDef and f.decl.name == name: |
259 |
| - return f |
260 |
| - return None |
261 |
| - |
262 |
| - |
263 |
| -class AWSTask: |
264 |
| - |
265 |
| - def __init__(self, name, instance='c5.2xlarge', AMI='ami-0e262d4de9c0b73fd', key='cc3'): |
266 |
| - ec2 = boto3.resource('ec2') |
267 |
| - self.instance = ec2.create_instances( |
268 |
| - ImageId=AMI, |
269 |
| - MaxCount=1, |
270 |
| - MinCount=1, |
271 |
| - InstanceType=instance, |
272 |
| - SecurityGroupIds=['sg-00b6ec171be0d43f7'], |
273 |
| - KeyName=key, |
274 |
| - TagSpecifications=[ |
275 |
| - { |
276 |
| - 'ResourceType': 'instance', |
277 |
| - 'Tags': [ |
278 |
| - { |
279 |
| - 'Key': 'Name', |
280 |
| - 'Value': name |
281 |
| - }, |
282 |
| - ] |
283 |
| - }, |
284 |
| - ], |
285 |
| - )[0] |
286 |
| - self.instance.wait_until_running() |
287 |
| - self.instance.reload() |
288 |
| - self.instance.wait_until_running() |
289 |
| - self.key = key |
290 |
| - self.ipv4 = self.instance.public_ip_address |
291 |
| - |
292 |
| - def connect(self): |
293 |
| - key = paramiko.RSAKey.from_private_key_file(self.key + '.pem') |
294 |
| - client = paramiko.SSHClient() |
295 |
| - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) |
296 |
| - client.connect(hostname=self.ipv4, username='ubuntu', pkey=key) |
297 |
| - self.client = client |
298 |
| - |
299 |
| - def run(self, cmd, timeout=30): |
300 |
| - stdin, stdout, stderr = self.client.exec_command(cmd, timeout=timeout) |
301 |
| - return (stdout.read().decode(), stderr.read().decode()) |
302 |
| - |
303 |
| - def terminate(self): |
304 |
| - self.instance.terminate() |
0 commit comments