Commit b23a7310 authored by Alan Marchiori's avatar Alan Marchiori
Browse files

initial

parent 9a45279a
from .init import init
from .check import check
from .userconfig import userconfig
__all__ = ['userconfig', 'init', 'check']
import click
import config
@click.command()
@click.argument('lab_number')
def check(lab_number):
"""check LAB_NUMBER without submitting, format as the string
"lab" plus a number (no spaces!), like "lab1" or "lab10".
"""
click.echo("cmd: Check {}".format(lab_number))
import click
import os
import os.path
import config
import config.validation as validation
from config.echo import echo, error, warn
from utils.gitlab import GitLab
@click.command()
@click.argument('course', callback=validation.course)
@click.argument('section', callback=validation.section)
@click.argument('semester', callback=validation.semester)
def init(course, semester, section):
"""Initializes the lab tool structure on your local system
and on gitlab for a given COURSE, SECTION, and SEMESTER. Example: init CSCI206 S20 61.
"""
coursename = config.course_name_fmt.format(
course=course,
semester=semester,
section=section)
lp = os.path.expanduser(config.local_home.format(
course=course,
semester=semester,
section=section))
if click.confirm ("Initialize {} into {}?".format(coursename, lp)):
labdir = os.path.join(lp, config.labs_subdir)
if not os.path.exists(lp):
# make the root folder, plus the labs subfolder
# ensure permissions are not globally readable
for d in [lp, labdir]:
os.makedirs(d)
os.chmod(d,mode=0o0770)
else:
warn("The path already exists, skipping directory creation.")
with config.UserConfig() as uc:
uc.add_course(
name=coursename,
path=labdir)
gl = GitLab()
while not 'api_token' in uc.cfg or not gl.check_token():
api_token = click.prompt("Got to {} and create a personal access token with the \"api scope\" checked. Copy-paste the value here".format(
config.gitlab_api_token_url
))
uc.add_string(
name='api_token',
value=api_token
)
# needed to refresh the new token cached in the GitLab module
gl = GitLab()
import click
import config.user
import pprint
import json
@click.group()
def userconfig():
"debug interface for userconfig"
pass
@userconfig.command()
def show():
"shows the user config data"
click.echo(pprint.pformat(config.UserConfig().cfg))
@userconfig.command()
def reset():
"removes all user config information (WARNING!)"
if click.confirm("Are you sure you want to wipe the labtool user config? (this does not delete any course work!)"):
with config.UserConfig() as uc:
uc.cfg = {}
@userconfig.command()
@click.argument('name')
@click.option('--value', help="the value to set")
@click.option('--jsonvalue', help="the value as a json object")
def set(name, value, jsonvalue):
"set a userconfig NAME to VALUE"
print(jsonvalue)
with config.UserConfig() as uc:
if jsonvalue:
uc.cfg[name] = json.loads(jsonvalue)
else:
uc.cfg[name] = value
@userconfig.command()
@click.argument('name')
def rm(name):
"remove a userconfig value"
with config.UserConfig() as uc:
del uc.cfg[name]
from config.user import UserConfig
local_conf = "~/.labtool/config.json"
course_name_fmt = "{course}-{semester}-{section}"
local_home = "~/" + course_name_fmt
labs_subdir = "labs"
# define valid course strings
courses = ['CSCI206']
# shown to the user when asking for a Gitlab API token
gitlab_api_token_url = "https://gitlab.bucknell.edu/profile/personal_access_tokens"
gitlab_url = "https://gitlab.bucknell.edu/"
gitlab_api = "api/v4/"
import click
def echo(*args, **kwargs):
click.echo(*args, **kwargs)
def error(*args, **kwargs):
click.echo(
click.style("ERROR", fg='red', bold=True) + \
": " + args[0], *args[1:], **kwargs)
def warn(*args, **kwargs):
click.echo(
click.style("WARNING", fg='yellow', bold=True) + \
": " + args[0], *args[1:], **kwargs)
"""Per user configuration manager
Implemented as a singleton dictionary use with a context manager (with)
The fist use loads and the last use saves to disk. It is safe
to open in multiple contexts.
"""
import config
import json
import os
import os.path
class UserConfig:
__instance = None
__depth = 0
@staticmethod
def getConfig():
return UserConfig.__instance.cfg
#
# def add_to_list(self, x, val):
# "add an item onto the list x or create if needed"
# if x in self.cfg:
# self.cfg[x].append(val)
# else:
# self.cfg[x] = list(val)
def add_course(self, name, path):
"add a course to the dict of courses: local_path"
if not 'courses' in self.cfg:
self.cfg['courses'] = {}
self.cfg['courses'][name] = path
def add_string(self, name, value):
"add a named value to the config"
self.cfg[name] = value
def __enter__(self):
"Load User config on enter"
if UserConfig.__instance == None:
UserConfig.__instance = self
p = os.path.expanduser(config.local_conf)
if os.path.exists(p):
with open(p, 'r') as cf:
UserConfig.cfg = json.load(cf)
if 'debug' in UserConfig.cfg:
print("USERCONFIG: READ")
else:
UserConfig.cfg = {}
UserConfig.__depth += 1
return UserConfig.__instance
def __exit__(self, type, value, traceback):
"Save User config on exit"
UserConfig.__depth -= 1
if UserConfig.__depth == 0:
p = os.path.expanduser(config.local_conf)
if UserConfig.__instance:
if 'debug' in UserConfig.cfg:
print("USERCONFIG: WRITE")
os.makedirs(os.path.dirname(p), exist_ok=True)
with open(p, 'w') as cf:
json.dump(
UserConfig.__instance.cfg,
cf,
indent=4,
sort_keys=True
)
UserConfig.__instance = None
import click
import config
def course(c, param, value):
"ensure a valid course defined in config.__init__.py"
if value not in config.courses:
raise click.BadParameter("Course must be one of {}.".format(
config.courses
))
return value
def section(c, param, value):
"ensure section is in the range 60..99"
errstr = "Section must be a two-digit integer, like 61."
try:
section = int(value)
if section < 60 or section > 99:
raise click.BadParameter(errstr)
except ValueError:
raise click.BadParameter(errstr)
return value
def semester(c, param, value):
"ensure F## or S## where ## >= 20"
errstr = "Semester must be the letter F or S ([F]all or [S]pring) followed by the 2 digit year (20, 21...)"
try:
if not value[0] in ['F', 'S']:
raise click.BadParameter(errstr)
year = int(value[1:])
if year < 20 or year > 50:
raise click.BadParameter(errstr)
except ValueError:
raise click.BadParameter(errstr)
return value
def load_rubrics(path):
"return a dict of rubric docs"
all = {
'CSCI206':
{'S20':
{
'instructors': ['amm042','xmeng','jvs008']
'rubrics': load_rubrics('labs/CSCI206/')
} # S20
} #CSCI206
}
__all__ = [all]
{
"course": "csci206",
"version": 1,
"name": "Lab01",
"path": "Labs/Lab01",
"parts":
{"setup":
{
"index": 1,
"name": "Setup",
"prompt": "[20 points] will be given for correctly creating ~/csci206/Labs/Lab01 and placing your lab01.txt file in the right location.",
"points": 20,
"execute": "ls -lah"
},
"short_answers":
{
"index": 2,
"name": "Short answers",
"points": 80,
"prompt": "<ol><li>[15 points] One line mkdir ~/csci206/Labs/Lab01 command.</li><li>[5 point each] One sentence description of each of the following commands do: cat, more, less, head, and tail.</li><li>[10 points] The complete command line to start up emacs without a GUI.</li><li>[10 points] What is the command to show line numbers in vim?</li><li>[10 points] What is the command to show line numbers in emacs?</li><li>[10 points] Complete this sentence in your file: After careful consideration, I will use <vim or emacs> in csci206 as my text editor.</li></ol>",
"show": "lab01.txt"
}
}
}
{
"course": "csci206",
"version": 1,
"name": "Lab02",
"path": "Labs/Lab02",
"parts":
{"prelab":
{
"index": 1,
"name": "prelab",
"prompt": "[25 points] Prelab reading / activities (zybook).",
"points": 25
},
"ex1":
{
"index": 2,
"name": "isalary",
"points": 10,
"prompt": "ex1 salary and isalary correct and have all header information.",
"show": "isalary.c",
"execute": [ "gcc -Wall isalary.c -o isalary", "/bin/bash -c 'echo \"result should be: Annual salary is: 198000\"; echo 99.5|./isalary'"]
},
"ex2":
{
"index": 3,
"name": "nogood and fsalary",
"points": 20,
"prompt": "nogood and fsalary correct and compile without warning with -Wall. -5 for each warning, -15 for an error",
"show": [ "nogood.c", "fsalary.c"],
"execute": [ "gcc -Wall nogood.c -o nogood",
"gcc -Wall fsalary.c -o fsalary",
"./nogood",
"/bin/bash -c 'echo \"result should be: Annual salary is: \\$19180.80\"; echo 9.99 48 | ./fsalary'" ]
},
"ex3":
{ "index": 4,
"name": "as and ld",
"points": 10,
"prompt": "nogood.s and nogood.o exist.",
"show": [ "nogood.s" ],
"execute": "ls -lah nogood.o"
},
"ex4":
{ "index": 5,
"name": "cvp",
"points": 25,
"prompt": "primefact.py and primefact.c exist, compile without warning, and speedup is reasonable (noted in primefact.c).",
"show": [ "primefact.py", "primefact.c" ],
"execute": [ "gcc -Wall primefact.c -o primefact", "./primefact" ]
},
"ex5":
{
"index": 6,
"name" : "change case",
"points": 10,
"prompt": "switchcase.c compiles without warning and operates correctly.",
"show": ["switchcase.c"],
"execute": [ "gcc -Wall switchcase.c -o switchcase", "/bin/bash -c 'echo \"hello 123...\"|./switchcase" ]
}
}
}
{
"course": "csci206",
"version": 1,
"name": "Lab03",
"path": "Labs/Lab03",
"parts":
{"prelab":
{
"index": 1,
"name": "prelab",
"prompt": "<ul>\t<li>[1 point each, 4 total] Exercise 1: Debugging questions answered correctly.</li>\t<li>[2 points each, 12 total] Exercise 2: Answers for the register groups $at, $a0-$a3, $t0-$t9, $s0-$s7, $gp, and $sp.</li>\t<li>[1 points each, 4 total] Exercise 3: Each instruction and its effect are described accurately.</li>\t<li>[1 point each, 5 total] Exercise 4: Base conversions show intermediate steps and arrive at the correct result.</li></ul>",
"points": 25,
"show": "prelab.txt"
},
"ex1_2":
{
"index": 2,
"name": "mystery.asm",
"points": 35,
"prompt": "All register numbers in mystery.asm converted to the appropriately named register. -1 for each register not converted. Comments added to mystery.asm clearly indicate an understanding of what the program is doing (not just what each line does in isolation).",
"show": "mystery.asm"
},
"ex3a":
{
"index": 3,
"name": "c_mystery.c",
"points": 20,
"prompt": "c_mystery.c was created and it implements the proper algorithm.",
"show": [ "c_mystery.c"],
"execute": [ "gcc -Wall c_mystery.c -o c_mystery", "./c_mystery" ]
},
"ex3b":
{ "index": 4,
"name": "c_mystery.asm",
"points": 10,
"prompt": "generated c_mystery.asm using mipsel-linux-gcc",
"show": [ "c_mystery.asm" ]
},
"coding":
{ "index": 5,
"name": "conventions",
"points": 10,
"prompt": "Followed good coding conventions.",
"show": [ "c_mystery.c" ]
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment