Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tyler/easy installer #7

Merged
merged 1 commit into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,39 @@ As long as your package supports Plugins, Python, and Qt (or PySide), you can us
* In the future, I *do* have ideas for building an interface to an advanced deformer for dynamically previewing arbitrary splits, but the final output will always have the ability to bake down to a basic blendshape.

### Basic Usage
Follow this youtube link to a basic walkthrough of Simplex usage. This video highlights an older version of Simplex, but the interaction remains basically the same. [https://www.youtube.com/watch?v=LQwzsxU8z_Q](https://www.youtube.com/watch?v=LQwzsxU8z_Q)
Follow this youtube link to a basic walkthrough of Simplex usage. This video highlights a slightly older version of Simplex, but the interaction remains basically the same. [https://www.youtube.com/watch?v=LQwzsxU8z_Q](https://www.youtube.com/watch?v=LQwzsxU8z_Q)

## INSTALLATION

1. Download the latest release
2. Copy the `modules` folder from the zip file into your maya directory. On windows, that would mean copying into `%USERPROFILE%\Documents\maya` so that the module file sits at `%USERPROFILE%\Documents\maya\modules\simplex.mod`
3. Install numpy for mayapy [using pip](https://knowledge.autodesk.com/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2022/ENU/Maya-Scripting/files/GUID-72A245EC-CDB4-46AB-BEE0-4BBBF9791627-htm.html). If you're using a Maya with Python 3, you should just be able to install numpy. For Python 2 on Windows, you'll have to find a .whl file compiled for your version. I'm not sure about Mac or Linux for Py2.
4. Run these two Python commands in Maya to start the tool. (This is probably what you should put into a shelf button)
## Easy Installation
1. Download [this file](https://raw.githubusercontent.com/blurstudio/Simplex/master/simplex_maya_installer.py) to your computer. Make sure it's saved as a python file.
2. Drag/drop the python file into a freshly opened instance of Maya (make sure all other mayas are closed). A command prompt window may open for a couple seconds. This is normal.
3. If you have multiple Maya versions installed, repeat step 2 for those versions as well. This just ensures that numpy is installed for those versions.
4. Create a python shelf button with this script.
```python
from simplexui import runSimplexUI
runSimplexUI()
```

## Updating
1. Download [this file](https://raw.githubusercontent.com/blurstudio/Simplex/master/simplex_maya_installer.py) to your computer. Make sure it's saved as a python file.
2. Drag/drop the python file into a freshly opened instance of Maya (make sure all other mayas are closed). A command prompt window may open for a couple seconds. This is normal.
3. If you have multiple Maya versions installed, you do NOT have to repeat step 2 for all of them.


## Manual Installation
1. Download the `simplex-v*.*.*.zip` file from the [latest release](https://github.com/blurstudio/Simplex/releases/latest)
2. Create a `modules` folder in your maya user directory. For example, on Windows, that would mean creating `C:\Users\<your-username>\Documents\maya\modules`
3. Copy the `simplex.mod` file and the `simplex` folder into that directory.
4. Install numpy for mayapy [using pip](https://knowledge.autodesk.com/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2022/ENU/Maya-Scripting/files/GUID-72A245EC-CDB4-46AB-BEE0-4BBBF9791627-htm.html). For example, on Windows, once you're in the right place the command will be `mayapy -m pip install numpy`. You will need admin privelages for this.
5. Run these two Python commands in Maya to start the tool. (This is probably what you should put into a shelf button)
```python
from simplexui import runSimplexUI
runSimplexUI()
```

## Uninstalling
1. Delete the `simplex.mod` file and the `simplex` folder from the `modules` folder in your maya user directory. For example, on Windows, that would mean deleting `C:\Users\<your-username>\Documents\maya\modules\simplex.mod` and `C:\Users\<your-username>\Documents\maya\modules\simplex`


## Compiling
Hopefully you don't need to do this, but if you have to, just take a look at `.github/workflows/main.yml` and you should be able to piece together how to get a compile working using CMake. You aren't required to download the devkit or set its path for CMake if you've got maya installed on your machine. Also note, I use features from CMake 3.16+ so I can target python 2 and 3 separately.
201 changes: 201 additions & 0 deletions simplex_maya_installer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import logging
import os
import sys
import zipfile
from pathlib import Path

from maya import cmds, mel

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)


sys.dont_write_bytecode = True


def install_numpy(pyexe, target):
"""Install numpy to a particular folder

Arguments:
pyexe (str|Path): A path to the current python executable
target (str|Path): The folder to install to

Raises:
CalledProcessError: If the pip command fails
"""
import subprocess

cmd = [str(pyexe), "-m", "pip", "install", "--target", str(target), "numpy"]
proc = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
)

if proc.returncode != 0:
logging.critical("\n\n")
logging.critical(proc.stdout)
logging.critical("\n\n")
cmds.confirmDialog(
title="Simplex Install Error",
message="Numpy install failed",
button=["OK"],
)
raise subprocess.CalledProcessError(proc.returncode, cmd, output=proc.stdout)


def get_latest_git_release(user, repo, asset_regex, out_path):
"""Get the latest github release from a particular user/repo and download
it to a specified path

Arguments:
user (str): The github user name to download from
repo (str): The github repo name to download
asset_regex (str): A regex to match against the name of the asset
out_path (str|Path): A filepath where the release should be downloaded to

Returns:
Path: The path that the file was downloaded to. This *technically* may be
different from the provided out_path

Raises:
ValueError: If the latest repo asset can't be found for download
"""
import json
import re
import urllib.request

latest_link = f"https://api.github.com/repos/{user}/{repo}/releases/latest"
f = urllib.request.urlopen(latest_link)
latest_release_data = json.loads(f.read())
assets = latest_release_data.get("assets", [])
download_url = None
for a in assets:
if re.match(asset_regex, a["name"]):
download_url = a["browser_download_url"]
break

if download_url is None:
asset_names = "\n".join([a["name"] for a in assets])
msg = f"regex: {asset_regex}\nnames:\n{asset_names}"
cmds.confirmDialog(
title="Simplex Install Error",
message="Release Download Failed",
button=["OK"],
)

raise ValueError(
f"Cannot find latest {user}/{repo} version to download.\nCheck your asset_regex\n{msg}"
)

out_path = Path(out_path)
outFolder = out_path.parent
outFolder.mkdir(exist_ok=True)
logger.info(f"Downloading latest simplex")
logger.info(f"from: {download_url}")
logger.info(f"to: {out_path}")
path, headers = urllib.request.urlretrieve(download_url, filename=out_path)
return Path(path)


def get_mayapy_path():
"""Get the path to the mayapy executable"""
binFolder = Path(sys.executable).parent
if sys.platform == "win32":
return binFolder / "mayapy.exe"
elif sys.platform == "darwin":
return binFolder / "mayapy"
elif sys.platform == "linux":
return binFolder / "mayapy"
cmds.confirmDialog(
title="Simplex Install Error",
message=f"Unsupported Platform: {sys.platform}",
button=["OK"],
)

raise RuntimeError(f"Current platform is unsupported: {sys.platform}")


def get_numpy_simplex_target(mod_folder):
"""Get the target path for the numpy simplex install"""

if sys.platform == "win32":
platform = "win64"
elif sys.platform == "darwin":
platform = "mac"
elif sys.platform == "linux":
platform = "linux"
else:
cmds.confirmDialog(
title="Simplex Install Error",
message=f"Unsupported Platform: {sys.platform}",
button=["OK"],
)
raise RuntimeError(f"Current platform is unsupported: {sys.platform}")

year = cmds.about(majorVersion=True)
nppath = mod_folder / "simplex" / f"{platform}-{year}" / "pyModules"
return nppath


def onMayaDroppedPythonFile(obj):
"""This function will get run when you drag/drop this python script onto maya"""
try:
# Ensure that people will report a full error
cmds.optionVar(intValue=("stackTraceIsOn", 1))
mel.eval('synchronizeScriptEditorOption(1, "StackTraceMenuItem")')

mod_folder = Path(cmds.internalVar(uad=True)) / "modules"
modfile = mod_folder / "simplex.mod"
simplex_zip = mod_folder / "simplex.zip"
moddir = mod_folder / "simplex"
if modfile.is_file() != moddir.is_dir():
msg = f"Simplex module is partially installed.\nPlease delete {modfile} and {moddir} and try again"
cmds.confirmDialog(
title="Simplex Install Error",
message=msg,
button=["OK"],
)
raise ValueError(msg)

if simplex_zip.is_file():
os.remove(simplex_zip)

# This will overwrite the existing install, but will leave any numpy installs alone
simplex_zip = get_latest_git_release(
"blurstudio",
"simplex",
r"simplex-v\d+\.\d+\.\d+\.zip",
simplex_zip,
)

if not simplex_zip.is_file():
cmds.confirmDialog(
title="Simplex Install Error",
message="Zip file download failed",
button=["OK"],
)
raise RuntimeError("Download of simplex zip failed")

with zipfile.ZipFile(simplex_zip, "r") as zip_ref:
zip_ref.extractall(mod_folder)
os.remove(simplex_zip)

try:
import numpy
except ModuleNotFoundError:
mayapy = get_mayapy_path()
target = get_numpy_simplex_target(mod_folder)
install_numpy(mayapy, target)
else:
logger.info("Numpy is already installed for this version of maya")
finally:
sys.dont_write_bytecode = False

cmds.confirmDialog(
title="Simplex Installed",
message="Simplex installation complete",
button=["OK"],
)