Mercurial > hg > beaglert
view scripts/hvresources/uploader.py @ 198:62f6269f4b3e
Added support for MidiIn to heavy (with example patch and subpatches).
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Fri, 05 Feb 2016 06:17:35 +0000 |
parents | 5bcf04234f80 |
children | c768ed1055b0 |
line wrap: on
line source
#!/usr/bin/python # Copyright 2015 Section6. All Rights Reserved. import argparse import getpass import json import os import requests import shutil import stat import tempfile import time import urlparse import zipfile import sys class Colours: purple = "\033[95m" cyan = "\033[96m" dark_cyan = "\033[36m" blue = "\033[94m" green = "\033[92m" yellow = "\033[93m" red = "\033[91m" bold = "\033[1m" underline = "\033[4m" end = "\033[0m" def __zip_dir(in_dir, zip_path, file_filter=None): zf = zipfile.ZipFile(zip_path, mode="w", compression=zipfile.ZIP_DEFLATED) for subdir, dirs, files in os.walk(in_dir): for file in files: if (file_filter is None) or (len(file_filter) > 0 and file.lower().split(".")[-1] in file_filter): zf.write( filename=os.path.join(subdir,file), arcname=os.path.relpath(os.path.join(subdir,file), start=in_dir)) return zip_path def __unzip(zip_path, target_dir): """Unzip a file to a given directory. All destination files are overwritten. """ zipfile.ZipFile(zip_path).extractall(target_dir) def main(): parser = argparse.ArgumentParser( description="Compiles a Pure Data file.") parser.add_argument( "input_dir", help="A directory containing _main.pd. The entire directory will be uploaded.") parser.add_argument( "-n", "--name", default="heavy", help="Patch name. If it doesn't exist, the uploader will fail. Make sure that it exists on the Heavy website.") parser.add_argument( "-g", "--gen", nargs="+", default=["c"], help="List of generator outputs. Currently supported generators are 'c' and 'js'.") parser.add_argument( "-b", help="All files will be placed in the output directory, placed in their own subdirectory corresonding to the generator name.", action="count") parser.add_argument( "-o", "--out", nargs="+", default=["./"], # by default help="List of destination directories for retrieved files. Order should be the same as for --gen.") parser.add_argument( "-d", "--domain", default="https://enzienaudio.com", help="Domain. Default is https://enzienaudio.com.") parser.add_argument( "-x", help="Don't save the returned token.", action="count") parser.add_argument( "-z", help="Force the use of a password, regardless of saved token.", action="count") parser.add_argument( "--noverify", help="Don't verify the SSL connection. Generally a bad idea.", action="count") parser.add_argument( "-v", "--verbose", help="Show debugging information.", action="count") args = parser.parse_args() domain = args.domain or "https://enzienaudio.com" post_data = {} # token should be stored in ~/.heavy/token token_path = os.path.expanduser(os.path.join("~/", ".heavy", "token")) if os.path.exists(token_path) and not args.z: with open(token_path, "r") as f: post_data["credentials"] = { "token": f.read() } else: # otherwise, get the username and password post_data["credentials"] = { "username": raw_input("Enter username: "), "password": getpass.getpass("Enter password: ") } tick = time.time() # make a temporary directory temp_dir = tempfile.mkdtemp(prefix="lroyal-") # zip up the pd directory into the temporary directory try: if not os.path.exists(os.path.join(args.input_dir, "_main.pd")): raise Exception("Root Pd directory does not contain a file named _main.pd.") zip_path = __zip_dir( args.input_dir, os.path.join(temp_dir, "archive.zip"), file_filter={"pd"}) except Exception as e: print e shutil.rmtree(temp_dir) # clean up the temporary directory return post_data["name"] = args.name # the outputs to generate (always include c) __SUPPORTED_GENERATOR_SET = {"c", "js"} post_data["gen"] = list(({"c"} | set(args.gen)) & __SUPPORTED_GENERATOR_SET) # upload the job, get the response back # NOTE(mhroth): multipart-encoded file can only be sent as a flat dictionary, # but we want to send a json encoded deep dictionary. So we do a bit of a hack. r = requests.post( urlparse.urljoin(domain, "/a/heavy"), data={"json":json.dumps(post_data)}, files={"file": (os.path.basename(zip_path), open(zip_path, "rb"), "application/zip")}, verify=False if args.noverify else True) if r.status_code != requests.codes.ok: shutil.rmtree(temp_dir) # clean up the temporary directory r.raise_for_status() # raise an exception # decode the JSON API response r_json = r.json() """ { "data": { "compileTime": 0.05078411102294922, "id": "mhroth/asdf/Edp2G", "slug": "Edp2G", "index": 3, "links": { "files": { "linkage": [ { "id": "mhroth/asdf/Edp2G/c", "type": "file" } ], "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G/files" }, "project": { "linkage": { "id": "mhroth/asdf", "type": "project" }, "self": "https://enzienaudio.com/h/mhroth/asdf" }, "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G", "user": { "linkage": { "id": "mhroth", "type": "user" }, "self": "https://enzienaudio.com/h/mhroth" } }, "type": "job" }, "included": [ { "filename": "file.c.zip", "generator": "c", "id": "mhroth/asdf/Edp2G/c", "links": { "self": "https://enzienaudio.com/h/mhroth/asdf/Edp2G/c/file.c.zip" }, "mime": "application/zip", "type": "file" } ], "warnings": [], "meta": { "token": "11AS0qPRmjTUHEMSovPEvzjodnzB1xaz" } } """ reply_json = r.json() if args.verbose: print json.dumps( reply_json, sort_keys=True, indent=2, separators=(",", ": ")) # update the api token, if present if "token" in reply_json.get("meta",{}) and not args.x: if not os.path.exists(os.path.dirname(token_path)): os.makedirs(os.path.dirname(token_path)) # ensure that the .heavy directory exists with open(token_path, "w") as f: f.write(reply_json["meta"]["token"]) os.chmod(token_path, stat.S_IRUSR | stat.S_IWUSR) # force rw------- permissions on the file # print any warnings for x in r_json["warnings"]: print "{0}Warning:{1} {2}".format(Colours.yellow, Colours.end, x["detail"]) # check for errors if len(r_json.get("errors",[])) > 0: shutil.rmtree(temp_dir) # clean up the temporary directory for x in r_json["errors"]: print "{0}Error:{1} {2}".format(Colours.red, Colours.end, x["detail"]) sys.exit(1) return # retrieve all requested files for i,g in enumerate(args.gen): file_url = __get_file_url_for_generator(reply_json, g) if file_url is not None and (len(args.out) > i or args.b): r = requests.get( file_url, cookies={"token": reply_json["meta"]["token"]}, verify=False if args.noverify else True) r.raise_for_status() # write the reply to a temporary file c_zip_path = os.path.join(temp_dir, "archive.{0}.zip".format(g)) with open(c_zip_path, "wb") as f: f.write(r.content) # unzip the files to where they belong if args.b: target_dir = os.path.join(os.path.abspath(os.path.expanduser(args.out[0])), g) else: target_dir = os.path.abspath(os.path.expanduser(args.out[i])) if not os.path.exists(target_dir): os.makedirs(target_dir) # ensure that the output directory exists __unzip(c_zip_path, target_dir) print "{0} files placed in {1}".format(g, target_dir) else: print "{0}Warning:{1} {2} files could not be retrieved.".format( Colours.yellow, Colours.end, g) # delete the temporary directory shutil.rmtree(temp_dir) print "Job URL", reply_json["data"]["links"]["self"] print "Total request time: {0}ms".format(int(1000.0*(time.time()-tick))) sys.exit(0) def __get_file_url_for_generator(json_api, g): """Returns the file link for a specific generator. Returns None if no link could be found. """ for i in json_api["included"]: if g == i["generator"]: return i["links"]["self"] return None # by default, return None if __name__ == "__main__": main()