Commit 73fb66f5 authored by Alan Marchiori's avatar Alan Marchiori
Browse files

new commands and shell run

parent c8eb0227
......@@ -4,13 +4,13 @@ import config
from config.echo import *
import courses
from config import UserConfig
from utils.shell import run
from utils.git import Git
from pprint import pprint
import os
from pathlib import Path
from utils.git import Git
import difflib
def dbg(x):
debug(__name__ + x)
......@@ -20,10 +20,50 @@ class Checker:
self.info = checkinfo
self.cwd = labroot
def execute(self, args):
"execute a command and optionally examine results"
dbg('.execute({})'.format(args))
results = []
for test in args:
# plain string is just a command (ignore output)
if isinstance(test, str):
c,t = run(test)
else:
# dicts can be used to specify tests to perform
for cmd, check in test.items():
if 'stdin' in check:
c,t = run(cmd, input=check['stdin'])
else:
c,t = run(cmd)
if 'returncode' in check:
results += [c == check['returncode']]
if results[-1]:
success("$ {}: Reported success.".format(cmd))
else:
error("$ {}: Reported failure!".format(cmd))
error(t)
if 'stdout' in check:
results += [t == check['stdout']]
if results[-1]:
success("$ {}: Output passed.".format(cmd))
else:
error("$ {}: Output not as expected (check formatting!)".format(cmd))
for line in difflib.context_diff(
check['stdout'].split("\n"), t.split("\n"),
fromfile='Requested output',
tofile='Your output'):
echo(line.strip())
return all(results)
def exists(self, args):
"file existence check, args should be a list"
dbg('.exists({})'.format(args))
return all(map(os.path.exists, args))
for fname, result in zip(args, map(os.path.exists, args)):
if not result:
error("The file {} does not exist!".format(fname))
return False
return True
def is_empty(self, args):
"true if all files in args (list) exist and have size 0 bytes"
......@@ -38,8 +78,9 @@ class Checker:
result = []
for test in args:
for fname, check in test.items():
t = run('wc {}'.format(fname)).split()
c, t = run('wc {}'.format(fname))
#t = newlines, words, bytes, filename
t = t.split()
for chk, value in check.items():
if chk == 'min_lines':
a = int(t[0]) >= int(value)
......@@ -89,12 +130,16 @@ class Checker:
r = []
for k, args in self.info.items():
if k in ['index', 'name', 'check', 'prompt', 'points',
'on_error', 'on_pass']:
if k in ['index', 'name', 'check',
'prompt', 'points',
'on_error', 'on_pass', # these are rubric attributes
'show']: # show is used for grading
continue
debug(k, args)
if hasattr(self, k):
r += [getattr(self, k)(args)]
if not r[-1]:
break
else:
warn("I don't know what {} means.".format(
k
......@@ -141,10 +186,11 @@ def check(lab, part):
return
for partstr, info in rubric['parts'].items():
if info['check']:
if 'check' in info and info['check']:
if part and part != info['index']:
continue
c = Checker(info, os.path.join(coursepath, rubric['path']))
c = Checker(info,
os.path.join(coursepath, rubric['path']))
echo("---[{:25}({})]{}[{} points]{}".format(
info['name'],
......
......@@ -11,11 +11,13 @@ from utils.git import Git
import courses
@click.command(short_help='Initalize a course.')
@click.command(short_help='Initialize a course.')
@click.argument('course', callback=validation.course)
@click.argument('section', callback=validation.section)
@click.argument('semester', callback=validation.semester)
def init(course, semester, section):
@click.option('--prefix', default=None,
help="Override the default path prefix (~/)")
def init(course, semester, section, prefix):
"""Initializes the lab tool structure on your local system
and on gitlab for a given COURSE, SECTION, and SEMESTER. Example: init CSCI206 S20 61.
"""
......@@ -31,10 +33,19 @@ def init(course, semester, section):
coursedef = courses.all[coursename]
lp = os.path.expanduser(config.local_home.format(
course=course,
semester=semester,
section=section))
if prefix == None:
lp = os.path.expanduser(config.local_home.format(
course=course,
semester=semester,
section=section))
else:
lp = os.path.expanduser(
os.path.join(
prefix,
config.course_name_fmt.format(
course=course,
semester=semester,
section=section)))
if confirm("Initialize {} into {}?".format(coursename, lp)):
......
......@@ -38,4 +38,9 @@ def set(name, value, jsonvalue):
def rm(name):
"remove a userconfig value"
with config.UserConfig() as uc:
del uc.cfg[name]
if name in uc.cfg:
del uc.cfg[name]
else:
click.echo("ERROR: value {} doesn't exist in userconfig!".format(
name
))
from config.user import UserConfig
# where UserConfig is stored. (cannot be overridden)
local_conf = "~/.labtool/config.json"
# course name for user's path and git repo
course_name_fmt = "{course}-{semester}-{section}"
# course name in course object (ignores section assuming shared sections)
#course_objf_fmt = "{course}-{semester}"
# the default local_home is $HOME, it can be overridden with --prefix
local_home = "~/" + course_name_fmt
#labs_subdir = "labs"
# shown to the user when asking for a Gitlab API token
gitlab_api_token_url = "https://gitlab.bucknell.edu/profile/personal_access_tokens"
......
......@@ -4,17 +4,14 @@ import os
import os.path
import shutil
import utils.shell as shell
from config.echo import *
class Git:
def clean(self, cwd):
"returns True if the there are no diffs to remote (aka clean)"
result = subprocess.run(
shlex.split("git diff-index --quiet HEAD"),
env=os.environ.copy(),
cwd=cwd
)
return result.returncode == 0
c, r = shell.run("git diff-index --quiet HEAD", cwd=cwd)
return c == 0
def do_clone(self, giturl, localpath = None, cwd = '.', branch = None):
if localpath:
# localpath is where you want it like /home/amm042/CSCI206-S20-61
......@@ -24,99 +21,63 @@ class Git:
cmd = "git clone {} {}".format(giturl, localpath)
echo("Cloning {} into {}/{}... ".format(giturl, cwd, localpath))
else:
cmd = "git clone {}".format(giturl)
echo("Cloning {}... ".format(giturl))
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c, r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
return result.returncode == 0
return c == 0
def do_push(self, login, cwd, addfiles=[],
message='A commit message', branch='master',
addall=False):
cmd = 'git branch {}'.format(branch)
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
cmd = 'git checkout {}'.format(branch)
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
if addall:
cmd = "git add -A"
echo("Adding: ", cmd)
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
else:
for addf in addfiles:
cmd = "git add {}".format(addf)
echo("Adding: ", cmd)
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
cmd = 'git commit -m "{}"'.format(message)
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
else:
success('[{}]$ {}'.format(cwd, cmd))
cmd = 'git push origin ' + branch
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
capture_output=True
)
if result.returncode != 0:
error(result)
c,r = shell.run(cmd, cwd=cwd)
if c != 0:
error(r)
return False
else:
success('[{}]$ {}'.format(cwd, cmd))
......
......@@ -2,12 +2,16 @@ import subprocess
import os
import shlex
def run(cmd, cwd=None):
def run(cmd, cwd=None, input=None, timeout=5):
result = subprocess.run(
shlex.split(cmd),
env=os.environ.copy(),
cwd=cwd,
input=input,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
stderr=subprocess.STDOUT,
timeout=timeout,
universal_newlines=True
)
return result.stdout.decode("utf-8", "replace").strip()
#return result.returncode, result.stdout.decode("utf-8", "replace").strip()
return result.returncode, result.stdout
Supports Markdown
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