Skip to content

Instantly share code, notes, and snippets.

@robobenklein
Last active January 29, 2018 03:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robobenklein/9c67cfebed431003aa11cabbbf4438a3 to your computer and use it in GitHub Desktop.
Save robobenklein/9c67cfebed431003aa11cabbbf4438a3 to your computer and use it in GitHub Desktop.
CS140 Makefile
# CS140 makefile
# original by robobenklein / bklein3@utk
# GPLv3 license
# contact me if this breaks for some reason,
# but it's not my fault if you delete your programs using this
CC:=g++
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
current_dir := $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
venv_dir := ~/.cs140-cfapi-venv
canvas_dir := cs140/makefile_uploaded
dirname = $(patsubst %/,%,$(dir $1))
lab:=$(notdir $(current_dir))
tardir:=$(abspath $(dir $(mkfile_path)))
tarfile:=$(tardir)/$(lab)_$(shell date --rfc-3339=date 2>/dev/null || python -c 'import datetime;print(str(datetime.date.today()))').tar.gz
SOURCEDIR := .
CPP_FILES := $(shell find $(SOURCEDIR) -name '*.cpp')
HPP_FILES := $(shell find $(SOURCEDIR) -name '*.hpp' -o -name '*.h')
CPP_MAINS := $(shell grep -nwl -e '^int main' $(CPP_FILES) /dev/null | tr '\n' ' ' )
PROGS = $(patsubst %.cpp,%,$(CPP_MAINS))
CC_FLAGS := -std=c++11 -g
# Check that given variables are set and all have non-empty values,
# die with an error otherwise.
# https://stackoverflow.com/questions/10858261/abort-makefile-if-variable-not-set
# Params:
# 1. Variable name(s) to test.
# 2. (optional) Error message to print.
check_defined = \
$(strip $(foreach 1,$1, \
$(call __check_defined,$1,$(strip $(value 2)))))
__check_defined = \
$(if $(value $1),, \
$(error Undefined $1$(if $2, ($2))))
all: $(PROGS)
# sources: $(CPP_MAINS)
# outputs: $(PROGS)
%: %.cpp
# building: $@
$(CC) $(CC_FLAGS) -o $@ $<
clean:
# removing built programs: $(PROGS)
gvfs-trash --force $(PROGS)
tar:
# lab: $(lab)
tar -cvzf $(TAR_FLAGS) $(tarfile) $(CPP_FILES) $(HPP_FILES)
upload: update-cfapi
@:$(call check_defined, FILE, usage: `make upload FILE=path/to/file`)
$(venv_dir)/bin/python $(venv_dir)/cfapi/post-file.py "$(FILE)" -D $(canvas_dir)
@echo -e 'File uploaded to \033[36mhttps://utk.instructure.com/files/folder/self/$(canvas_dir)'
uptar: tar update-cfapi
$(venv_dir)/bin/python $(venv_dir)/cfapi/post-file.py $(tarfile) -D tars
@echo -e 'File uploaded to \033[36mhttps://utk.instructure.com/files/folder/self/tars\033[0m'
update:
which curl
$(eval updatefile = /tmp/${USER}.update.makefile )
curl -fsSL https://gist.githubusercontent.com/robobenklein/9c67cfebed431003aa11cabbbf4438a3/raw/Makefile > $(updatefile)
test -s $(updatefile)
gvfs-trash $(mkfile_path)
mv $(updatefile) $(mkfile_path)
test -s $(mkfile_path)
# if the updated version doesn't work, the old Makefile is in your trash, probably ~/.local/share/Trash/
# if there's a problem with the latest version, report bugs to bklein3@vols.utk.edu
# thanks for using my Makefile!
update-cfapi:
test -d $(venv_dir) || virtualenv $(venv_dir)
$(venv_dir)/bin/pip install -U requests
$(eval updatefile = /tmp/${USER}.update.makefile.post-file.py )
curl -fsSL https://gist.githubusercontent.com/robobenklein/9c67cfebed431003aa11cabbbf4438a3/raw/post-file.py > $(updatefile)
test -s $(updatefile)
mkdir -p $(venv_dir)/cfapi
mv $(updatefile) $(venv_dir)/cfapi/post-file.py
help:
@echo -e '\033[36mCS140 makefile\033[0m by \033[31mrobobenklein\033[0m aka \033[36mbklein3\033[0m'
@echo -e 'Running \033[36mmake\033[0m will compile these files: '
@echo -e ' \033[44m$(CPP_MAINS)\033[0m'
@echo -e 'into these output programs: '
@echo -e ' \033[44m$(PROGS)\033[0m'
@echo -e 'only if the source files have changed, so no need to recompile irrelevant parts'
@echo -e ''
@echo -e 'When done with a lab, you can use `make tar` to tar.gz your .cpp files'
@echo -e 'which will put all of these files: '
@echo -e ' \033[44m$(CPP_FILES) $(HPP_FILES)\033[0m'
@echo -e 'into a tar.gz file here: \033[36m$(tarfile)\033[0m'
@echo -e ''
@echo -e 'If you want to upload this file to canvas, you can use \033[36mmake uptar\033[0m to tar and upload to canvas.'
@echo -e 'You will be prompted for the information needed as you run it for the first time.'
@echo -e 'If you just want to upload a single file or want to do so manually, use \033[36mmake upload FILE=folder/something.cpp\033[0m'
@echo -e ''
@echo -e 'If you want to know what a make command will do before you run it,'
@echo -e ' use \033[36mmake -n\033[0m in place of \033[36mmake\033[0m and make will show you the commands without running them'
@echo -e 'Note that things beginning with a \033[36m#\033[0m are comments!'
@echo -e ''
@echo -e 'If you have feedback, bugs, or suggestions, email me! <\033[36mbklein3@vols.utk.edu\033[0m>'
#!/usr/bin/env python
import requests
import argparse
import getpass
import json
import os
import sys
from os.path import expanduser
parser = argparse.ArgumentParser(description='Upload file to canvas')
parser.add_argument('filepath', type=str, help='a file to upload')
parser.add_argument(
'-D', '--destination', type=str, default="script-uploads",
help='the folder on canvas to upload to')
args = parser.parse_args()
upload_filename = os.path.basename(args.filepath)
class dotdict(dict):
"""dot.notation access to dictionary attributes"""
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
canvas = dotdict()
canvas.host = "utk.instructure.com"
try:
with open(expanduser("~/.canvas-auth-token")) as authfile:
canvas.token = authfile.readline().strip()
print("Auth token is " + str(len(canvas.token)) + " characters long.")
except IOError:
print("CANVAS API TOKEN CREATION")
print("======")
print("You can get one at https://utk.instructure.com/profile/settings#access_tokens_holder")
print("Click 'New Access Token', purpose: 'cs140', then click 'Generate Token'")
print("Copy and paste that token here, it should look something like this: ")
print("####~ag5hap9e85hgajergaAGshs46hrsagaeg38h9ATHFHDyhg")
print("======")
print("Please enter the canvas API token, input not shown:")
canvas.token = getpass.getpass(prompt='Enter Token: ')
with open(expanduser("~/.canvas-auth-token"), 'w') as authfile:
authfile.write(canvas.token)
os.chmod(expanduser("~/.canvas-auth-token"), 0o700)
print("Token stored to ~/.canvas-auth-token")
canvas.scheme = "https"
canvas.baseurl = canvas.scheme + "://" + canvas.host
canvas.fileapi = "/api/v1/users/self/files"
canvas.fileapiurl = canvas.baseurl + canvas.fileapi
canvas.uploaddest = args.destination
header_auth = {
'Authorization': ("Bearer " + canvas.token),
}
responses = dotdict
preupload_data = {
'name': upload_filename,
'parent_folder_path': canvas.uploaddest,
'on_duplicate': 'overwrite',
}
responses.preupload = requests.post(
canvas.fileapiurl,
data=preupload_data,
headers=header_auth,
)
print("code PREUP: " + str(responses.preupload))
# print("DEBUG preup headers: " + str(responses.preupload.json()))
if responses.preupload.status_code == 401:
print("Bad auth token. Please correct the token.")
print("Token should be placed in ~/.canvas-auth-token")
sys.exit(1)
elif responses.preupload.status_code != 200:
print("Something went wrong...")
print(str(responses.preupload.text))
# print("DEBUG: PREUP json: " + str(json.dumps(responses.preupload.json(), indent=2)))
try:
uploadfile = open(expanduser(args.filepath), 'rb')
except IOError as err:
print("Error opening file to be uploaded:")
print(err)
upload_params = responses.preupload.json()[u'upload_params']
# print("DEBUG upload_params json: " + str(json.dumps(upload_params, indent=2)))
# open file instances
upload_files = {
'file': uploadfile,
}
responses.upload = requests.post(
url=responses.preupload.json()[u'upload_url'],
data=upload_params,
allow_redirects=False,
files=upload_files,
)
print("code UPLOAD: " + str(responses.upload))
# print("DEBUG head UPLOAD: " + str(responses.upload.headers))
confirm_url = responses.upload.headers['Location']
print("UPLOAD confirm url: " + confirm_url)
if responses.upload.status_code not in [200, 301, 303]:
print("Error during file upload:")
print(str(responses.upload.text))
sys.exit(2)
responses.postupload = requests.post(
url=confirm_url,
headers=header_auth,
)
print(responses.postupload)
if responses.postupload.status_code not in [200]:
print("Error confirming file upload: ")
# print("DEBUG: " + str(responses.postupload.text))
sys.exit(3)
print("Upload complete, file info: ")
print(json.dumps(responses.postupload.json(), indent=2))
@robobenklein
Copy link
Author

robobenklein commented Aug 31, 2017

CS140 Students:

First, log into hydra. Remember, log in with your netid and password, ssh username@hydraXX.eecs.utk.edu if on a Unix system. (OSX or Linux) For windows, use Putty, or the Ubuntu/Linux subsystem on Windows 10.

cd into your lab directory, ex. cd cs140/labs/lab1 or something similar.

Then run curl -fsSL https://gist.githubusercontent.com/robobenklein/9c67cfebed431003aa11cabbbf4438a3/raw/Makefile > Makefile to get this Makefile. (You can use ctrl-shift-v to paste into a linux terminal.)

Now you can make help to get started!

@robobenklein
Copy link
Author

robobenklein commented Aug 31, 2017

Future updates might be made, in which case you can use make update in order to get the latest version!

When starting another lab, you can just copy this same Makefile over into the new lab's directory and it should autodetect the change! (ex. cp ../lab1/Makefile ./Makefile)

TODO:

  • Canvas API Submit tarfile: Done!
  • Canvas API individual file uploads: make upload FILE=something.cpp Done!
  • Mac OSX support: mostly done...
  • Large userbase testing: in progress

@atltt
Copy link

atltt commented Sep 1, 2017

Nice Ben keep it up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment