Maya Github Python project bootstrapping script
''' | |
Maya Python Github project bootstrapping script | |
Makes particular Maya Python Github project releases available in Maya via the | |
user script dir. Pass user, project, and release strings to getGithubRelease, | |
which will download the zip file to the user script dir, and unzip it in there | |
(if it doesn't yet exist). Returns the full path to the unzipped project | |
folder, which can be used to modify sys.path[1], circumventing installation. | |
Note: you still need to ensure all tools deal with one version of the project, | |
but this makes it easy to throw a call to the latest version in a startup file | |
to ensure the latest version is fetched and on the path each session[2]. | |
[1] this allows for standard "import <projectname>" semantics | |
[2] downside: tool versions will have no history of this dependency | |
''' | |
import os, sys | |
import urllib | |
import urllib2 | |
import zipfile | |
import maya.cmds as cmds | |
def ensurePath (path): | |
''' | |
Prepends given path to sys.path, if not already in sys.path (idempotent) | |
''' | |
if path not in sys.path: | |
sys.path.insert(0, path) | |
def getGithubRelease (user, project, release): | |
''' | |
Given user, project, and release, all taken from the Github release[1]: | |
1. downloads release zip to Maya user scripts dir (if missing) | |
2. unzips project to its own folder in user scripts dir (if missing) | |
Returns unzipped project folder path (which you can put on sys.path if needed) | |
[1] from the Github "Clone or download" ZIP link for a given branch or tag | |
e.g. for the following tagged release: | |
https://github.com/LumaPictures/pymel/archive/1.0.3.zip | |
pass these arguments: | |
user = "LumaPictures" | |
project = "pymel" | |
release = "1.0.3.zip" | |
''' | |
# set up remote and local paths | |
remotePath = "https://github.com/%s/%s/archive/%s.zip" % (user, project, release) | |
scriptsDir = cmds.internalVar(userScriptDir=True) | |
localZipPath = scriptsDir + project + "-" + release + ".zip" | |
# Note: This process is screwy; the only way to build up the impending, | |
# unzipped project path string, which is not tied to the zip name at all, | |
# is to query the zip for its root entry, and append it to the target path. | |
# if release zip doesn't exist in the scripts dir, retrieve it from Github | |
if not os.path.exists(localZipPath): | |
print ("retrieving " + remotePath) | |
# open zip URL just to see if we can; will error out if we can't | |
u = urllib2.urlopen(remotePath) | |
u.close() | |
# actually retrieve zip | |
urllib.urlretrieve(remotePath, localZipPath) | |
# the release zip should exist locally at this point | |
if not os.path.exists(localZipPath): | |
raise RuntimeError("Could not retrieve " + project + " zip from Github.") | |
# grab a handle to the zip file | |
z = zipfile.ZipFile(localZipPath) | |
# get the list of root entries in the zip; there must be only 1 | |
# (zip's spec guarantees '/' separators internally for Amiga/Unix compatibility) | |
roots = list(set(map(lambda x: x.split('/')[0], z.namelist()))) | |
if len(roots) != 1: | |
raise RuntimeError("must have exactly 1 root: " + localZipPath) | |
projDirName = roots[0] | |
# actual unzipping | |
try: | |
# unzip the file to the user scripts dir and close the handle | |
z.extractall(scriptsDir) | |
z.close() | |
except zipfile.BadZipfile: | |
z.close() | |
# decided against deleting here, so the bad zip could be analyzed | |
raise RuntimeError("Bad zip file: " + localZipPath) | |
# assemble the presumed path to our unzipped project folder | |
localProjDir = scriptsDir + projDirName | |
# check that the unzipped folder exists | |
if not os.path.isdir(localProjDir): | |
raise RuntimeError("Could not find project path: " + localProjDir) | |
# return path to project (for use in sys.path) | |
return localProjDir |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment