Skip to content

Commit

Permalink
Merge pull request #770 from compas-dev/add-grasshopper_library_path
Browse files Browse the repository at this point in the history
Grasshopper GHPY libraries install
  • Loading branch information
tomvanmele authored Feb 12, 2021
2 parents bdf7b4d + 4836330 commit f4cb6fe
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `RobotModel.remove_link`, `RobotModel.remove_joint`, `RobotModel.to_urdf_string`, and `RobotModel.ensure_geometry`.
* Added Blender Python-example to the documentation section: Tutorials -> Robots
* Added `compas_blender.unload_modules`.
* Added `after_rhino_install` and `after_rhino_uninstall` pluggable interfaces to extend the install/uninstall with arbitrary steps.

### Changed

Expand Down
6 changes: 5 additions & 1 deletion docs/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ Category: ``booleans``
Category: ``install``
^^^^^^^^^^^^^^^^^^^^^

.. currentmodule:: compas_rhino.install
.. currentmodule::

* :func:`installable_rhino_packages`
* :func:`after_rhino_install`

.. currentmodule:: compas_rhino.uninstall
* :func:`after_rhino_uninstall`


Category: ``intersections``
Expand Down
6 changes: 5 additions & 1 deletion src/compas/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,11 @@ def wrapper(*args, **kwargs):
results = []

for plugin_impl in _collect_plugins(extension_point_url):
results.append(plugin_impl.method(*args, **kwargs))
try:
result = plugin_impl.method(*args, **kwargs)
results.append(result)
except Exception as e:
results.append(e)

return results
else:
Expand Down
12 changes: 12 additions & 0 deletions src/compas_ghpython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
compas_ghpython.utilities
"""
import os
import compas

if compas.RHINO:
Expand All @@ -21,5 +22,16 @@
__version__ = '1.0.0'


def get_grasshopper_library_path(version):
if compas.WINDOWS:
grasshopper_library_path = os.path.join(os.getenv('APPDATA'), 'Grasshopper', 'Libraries')
elif compas.OSX:
grasshopper_library_path = os.path.join(os.getenv('HOME'), 'Library', 'Application Support', 'McNeel', 'Rhinoceros', '{}'.format(version),
'Plug-ins', 'Grasshopper (b45a29b1-4343-4035-989e-044e8580d9cf)', 'Libraries')
else:
raise Exception('Unsupported platform')
return grasshopper_library_path


__all_plugins__ = ['compas_ghpython.install']
__all__ = [name for name in dir() if not name.startswith('_')]
1 change: 1 addition & 0 deletions src/compas_rhino/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,5 @@ def _try_remove_bootstrapper(path):
__all_plugins__ = [
'compas_rhino.geometry.booleans',
'compas_rhino.install',
'compas_rhino.uninstall',
]
81 changes: 79 additions & 2 deletions src/compas_rhino/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
import compas._os
import compas.plugins

__all__ = ['install']
__all__ = [
'install',
'installable_rhino_packages',
'after_rhino_install',
]


def install(version=None, packages=None):
Expand Down Expand Up @@ -84,8 +88,13 @@ def install(version=None, packages=None):
symlinks = [(link['source_path'], link['link']) for link in symlinks_to_install]
install_results = compas._os.create_symlinks(symlinks)

installed_packages = []
for install_data, success in zip(symlinks_to_install, install_results):
result = 'OK' if success else 'ERROR: Cannot create symlink, try to run as administrator.'
if success:
installed_packages.append(install_data['name'])
result = 'OK'
else:
result = 'ERROR: Cannot create symlink, try to run as administrator.'
results.append((install_data['name'], result))

if not all(install_results):
Expand All @@ -106,11 +115,49 @@ def install(version=None, packages=None):
if status != 'OK':
exit_code = -1

if exit_code == 0 and len(installed_packages):
print()
print('Running post-installation steps...')
print()
if not _run_post_execution_steps(after_rhino_install(installed_packages)):
exit_code = -1

print('\nCompleted.')
if exit_code != 0:
sys.exit(exit_code)


def _run_post_execution_steps(steps_generator):
all_steps_succeeded = True
post_execution_errors = []

for result in steps_generator:
if isinstance(result, Exception):
post_execution_errors.append(result)
continue

for item in result:
try:
package, message, success = item
status = 'OK' if success else 'ERROR'
if not success:
all_steps_succeeded = False
print(' {} {}: {}'.format(package.ljust(20), status, message))
except ValueError:
post_execution_errors.append(ValueError('Step ran without errors but result is wrongly formatted: {}'.format(str(item))))

if post_execution_errors:
print()
print('One or more errors occurred:')
print()
for error in post_execution_errors:
print(' - {}'.format(repr(error)))

all_steps_succeeded = False

return all_steps_succeeded


@compas.plugins.plugin(category='install', pluggable_name='installable_rhino_packages', tryfirst=True)
def default_installable_rhino_packages():
# While this list could obviously be hard-coded, I think
Expand Down Expand Up @@ -143,6 +190,36 @@ def installable_rhino_packages():
pass


@compas.plugins.pluggable(category='install', selector='collect_all')
def after_rhino_install(installed_packages):
"""Allows extensions to execute actions after install to Rhino is done.
Extensions providing Rhino or Grasshopper features
can implement this pluggable interface to perform
additional steps after an installation to Rhino has
been completed.
Parameters
----------
installed_packages : :obj:`list` of :obj:`str`
List of packages that have been installed successfully.
Examples
--------
>>> import compas.plugins
>>> @compas.plugins.plugin(category='install')
... def after_rhino_install(installed_packages):
... # Do something after package is installed to Rhino, eg, copy components, etc
... return [('compas_ghpython', 'GH Components installed', True)]
Returns
-------
:obj:`list` of 3-tuple (str, str, bool)
List containing a 3-tuple with component name, message and ``True``/``False`` success flag.
"""
pass


def _update_bootstrapper(install_path, packages):
# Take either the CONDA environment directory or the current Python executable's directory
python_directory = os.environ.get('CONDA_PREFIX', None) or os.path.dirname(sys.executable)
Expand Down
54 changes: 50 additions & 4 deletions src/compas_rhino/uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import os
import sys

import compas._os
import compas.plugins
import compas_rhino
from compas_rhino.install import _run_post_execution_steps
from compas_rhino.install import installable_rhino_packages

import compas._os

__all__ = ['uninstall']
__all__ = [
'uninstall',
'after_rhino_uninstall',
]


def uninstall(version=None, packages=None):
Expand Down Expand Up @@ -68,8 +72,13 @@ def uninstall(version=None, packages=None):
symlinks = [link['link'] for link in symlinks_to_uninstall]
uninstall_results = compas._os.remove_symlinks(symlinks)

uninstalled_packages = []
for uninstall_data, success in zip(symlinks_to_uninstall, uninstall_results):
result = 'OK' if success else 'ERROR: Cannot remove symlink, try to run as administrator.'
if success:
uninstalled_packages.append(uninstall_data['name'])
result = 'OK'
else:
result = 'ERROR: Cannot remove symlink, try to run as administrator.'
results.append((uninstall_data['name'], result))

if not all(uninstall_results):
Expand All @@ -92,6 +101,13 @@ def uninstall(version=None, packages=None):
if status != 'OK':
exit_code = -1

if exit_code == 0 and len(uninstalled_packages):
print()
print('Running post-uninstallation steps...')
print()
if not _run_post_execution_steps(after_rhino_uninstall(uninstalled_packages)):
exit_code = -1

print('\nUninstall completed.')
if exit_code != 0:
sys.exit(exit_code)
Expand Down Expand Up @@ -126,6 +142,36 @@ def _filter_installed_packages(version, packages):
return packages


@compas.plugins.pluggable(category='install', selector='collect_all')
def after_rhino_uninstall(uninstalled_packages):
"""Allows extensions to execute actions after uninstall from Rhino is done.
Extensions providing Rhino or Grasshopper features
can implement this pluggable interface to perform
additional steps after the uninstall from Rhino has
been completed.
Parameters
----------
uninstalled_packages : :obj:`list` of :obj:`str`
List of packages that have been uninstalled.
Examples
--------
>>> import compas.plugins
>>> @compas.plugins.plugin(category='install')
... def after_rhino_uninstall(uninstalled_packages):
... # Do something cleanup, eg remove copied files.
... return [('compas_ghpython', 'GH Components uninstalled', True)]
Returns
-------
:obj:`list` of 3-tuple (str, str, bool)
List containing a 3-tuple with component name, message and ``True``/``False`` success flag.
"""
pass


# ==============================================================================
# Main
# ==============================================================================
Expand Down

0 comments on commit f4cb6fe

Please sign in to comment.