Skip to content

Commit f4cb6fe

Browse files
authored
Merge pull request #770 from compas-dev/add-grasshopper_library_path
Grasshopper GHPY libraries install
2 parents bdf7b4d + 4836330 commit f4cb6fe

File tree

7 files changed

+153
-8
lines changed

7 files changed

+153
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
* Added `RobotModel.remove_link`, `RobotModel.remove_joint`, `RobotModel.to_urdf_string`, and `RobotModel.ensure_geometry`.
1414
* Added Blender Python-example to the documentation section: Tutorials -> Robots
1515
* Added `compas_blender.unload_modules`.
16+
* Added `after_rhino_install` and `after_rhino_uninstall` pluggable interfaces to extend the install/uninstall with arbitrary steps.
1617

1718
### Changed
1819

docs/plugins.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ Category: ``booleans``
2424
Category: ``install``
2525
^^^^^^^^^^^^^^^^^^^^^
2626

27-
.. currentmodule:: compas_rhino.install
27+
.. currentmodule::
2828

2929
* :func:`installable_rhino_packages`
30+
* :func:`after_rhino_install`
31+
32+
.. currentmodule:: compas_rhino.uninstall
33+
* :func:`after_rhino_uninstall`
3034

3135

3236
Category: ``intersections``

src/compas/plugins.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,11 @@ def wrapper(*args, **kwargs):
288288
results = []
289289

290290
for plugin_impl in _collect_plugins(extension_point_url):
291-
results.append(plugin_impl.method(*args, **kwargs))
291+
try:
292+
result = plugin_impl.method(*args, **kwargs)
293+
results.append(result)
294+
except Exception as e:
295+
results.append(e)
292296

293297
return results
294298
else:

src/compas_ghpython/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
compas_ghpython.utilities
1313
1414
"""
15+
import os
1516
import compas
1617

1718
if compas.RHINO:
@@ -21,5 +22,16 @@
2122
__version__ = '1.0.0'
2223

2324

25+
def get_grasshopper_library_path(version):
26+
if compas.WINDOWS:
27+
grasshopper_library_path = os.path.join(os.getenv('APPDATA'), 'Grasshopper', 'Libraries')
28+
elif compas.OSX:
29+
grasshopper_library_path = os.path.join(os.getenv('HOME'), 'Library', 'Application Support', 'McNeel', 'Rhinoceros', '{}'.format(version),
30+
'Plug-ins', 'Grasshopper (b45a29b1-4343-4035-989e-044e8580d9cf)', 'Libraries')
31+
else:
32+
raise Exception('Unsupported platform')
33+
return grasshopper_library_path
34+
35+
2436
__all_plugins__ = ['compas_ghpython.install']
2537
__all__ = [name for name in dir() if not name.startswith('_')]

src/compas_rhino/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,5 @@ def _try_remove_bootstrapper(path):
211211
__all_plugins__ = [
212212
'compas_rhino.geometry.booleans',
213213
'compas_rhino.install',
214+
'compas_rhino.uninstall',
214215
]

src/compas_rhino/install.py

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
import compas._os
1313
import compas.plugins
1414

15-
__all__ = ['install']
15+
__all__ = [
16+
'install',
17+
'installable_rhino_packages',
18+
'after_rhino_install',
19+
]
1620

1721

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

91+
installed_packages = []
8792
for install_data, success in zip(symlinks_to_install, install_results):
88-
result = 'OK' if success else 'ERROR: Cannot create symlink, try to run as administrator.'
93+
if success:
94+
installed_packages.append(install_data['name'])
95+
result = 'OK'
96+
else:
97+
result = 'ERROR: Cannot create symlink, try to run as administrator.'
8998
results.append((install_data['name'], result))
9099

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

118+
if exit_code == 0 and len(installed_packages):
119+
print()
120+
print('Running post-installation steps...')
121+
print()
122+
if not _run_post_execution_steps(after_rhino_install(installed_packages)):
123+
exit_code = -1
124+
109125
print('\nCompleted.')
110126
if exit_code != 0:
111127
sys.exit(exit_code)
112128

113129

130+
def _run_post_execution_steps(steps_generator):
131+
all_steps_succeeded = True
132+
post_execution_errors = []
133+
134+
for result in steps_generator:
135+
if isinstance(result, Exception):
136+
post_execution_errors.append(result)
137+
continue
138+
139+
for item in result:
140+
try:
141+
package, message, success = item
142+
status = 'OK' if success else 'ERROR'
143+
if not success:
144+
all_steps_succeeded = False
145+
print(' {} {}: {}'.format(package.ljust(20), status, message))
146+
except ValueError:
147+
post_execution_errors.append(ValueError('Step ran without errors but result is wrongly formatted: {}'.format(str(item))))
148+
149+
if post_execution_errors:
150+
print()
151+
print('One or more errors occurred:')
152+
print()
153+
for error in post_execution_errors:
154+
print(' - {}'.format(repr(error)))
155+
156+
all_steps_succeeded = False
157+
158+
return all_steps_succeeded
159+
160+
114161
@compas.plugins.plugin(category='install', pluggable_name='installable_rhino_packages', tryfirst=True)
115162
def default_installable_rhino_packages():
116163
# While this list could obviously be hard-coded, I think
@@ -143,6 +190,36 @@ def installable_rhino_packages():
143190
pass
144191

145192

193+
@compas.plugins.pluggable(category='install', selector='collect_all')
194+
def after_rhino_install(installed_packages):
195+
"""Allows extensions to execute actions after install to Rhino is done.
196+
197+
Extensions providing Rhino or Grasshopper features
198+
can implement this pluggable interface to perform
199+
additional steps after an installation to Rhino has
200+
been completed.
201+
202+
Parameters
203+
----------
204+
installed_packages : :obj:`list` of :obj:`str`
205+
List of packages that have been installed successfully.
206+
207+
Examples
208+
--------
209+
>>> import compas.plugins
210+
>>> @compas.plugins.plugin(category='install')
211+
... def after_rhino_install(installed_packages):
212+
... # Do something after package is installed to Rhino, eg, copy components, etc
213+
... return [('compas_ghpython', 'GH Components installed', True)]
214+
215+
Returns
216+
-------
217+
:obj:`list` of 3-tuple (str, str, bool)
218+
List containing a 3-tuple with component name, message and ``True``/``False`` success flag.
219+
"""
220+
pass
221+
222+
146223
def _update_bootstrapper(install_path, packages):
147224
# Take either the CONDA environment directory or the current Python executable's directory
148225
python_directory = os.environ.get('CONDA_PREFIX', None) or os.path.dirname(sys.executable)

src/compas_rhino/uninstall.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
import os
77
import sys
88

9+
import compas._os
10+
import compas.plugins
911
import compas_rhino
12+
from compas_rhino.install import _run_post_execution_steps
1013
from compas_rhino.install import installable_rhino_packages
1114

12-
import compas._os
13-
14-
__all__ = ['uninstall']
15+
__all__ = [
16+
'uninstall',
17+
'after_rhino_uninstall',
18+
]
1519

1620

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

75+
uninstalled_packages = []
7176
for uninstall_data, success in zip(symlinks_to_uninstall, uninstall_results):
72-
result = 'OK' if success else 'ERROR: Cannot remove symlink, try to run as administrator.'
77+
if success:
78+
uninstalled_packages.append(uninstall_data['name'])
79+
result = 'OK'
80+
else:
81+
result = 'ERROR: Cannot remove symlink, try to run as administrator.'
7382
results.append((uninstall_data['name'], result))
7483

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

104+
if exit_code == 0 and len(uninstalled_packages):
105+
print()
106+
print('Running post-uninstallation steps...')
107+
print()
108+
if not _run_post_execution_steps(after_rhino_uninstall(uninstalled_packages)):
109+
exit_code = -1
110+
95111
print('\nUninstall completed.')
96112
if exit_code != 0:
97113
sys.exit(exit_code)
@@ -126,6 +142,36 @@ def _filter_installed_packages(version, packages):
126142
return packages
127143

128144

145+
@compas.plugins.pluggable(category='install', selector='collect_all')
146+
def after_rhino_uninstall(uninstalled_packages):
147+
"""Allows extensions to execute actions after uninstall from Rhino is done.
148+
149+
Extensions providing Rhino or Grasshopper features
150+
can implement this pluggable interface to perform
151+
additional steps after the uninstall from Rhino has
152+
been completed.
153+
154+
Parameters
155+
----------
156+
uninstalled_packages : :obj:`list` of :obj:`str`
157+
List of packages that have been uninstalled.
158+
159+
Examples
160+
--------
161+
>>> import compas.plugins
162+
>>> @compas.plugins.plugin(category='install')
163+
... def after_rhino_uninstall(uninstalled_packages):
164+
... # Do something cleanup, eg remove copied files.
165+
... return [('compas_ghpython', 'GH Components uninstalled', True)]
166+
167+
Returns
168+
-------
169+
:obj:`list` of 3-tuple (str, str, bool)
170+
List containing a 3-tuple with component name, message and ``True``/``False`` success flag.
171+
"""
172+
pass
173+
174+
129175
# ==============================================================================
130176
# Main
131177
# ==============================================================================

0 commit comments

Comments
 (0)