Skip to content

Instantly share code, notes, and snippets.

@gfixler
Last active October 13, 2017 01:55
Show Gist options
  • Save gfixler/b5c405e182ceb9ced70e91a47ed3e8c5 to your computer and use it in GitHub Desktop.
Save gfixler/b5c405e182ceb9ced70e91a47ed3e8c5 to your computer and use it in GitHub Desktop.
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