1212import compas ._os
1313import compas .plugins
1414
15- __all__ = ['install' ]
15+ __all__ = [
16+ 'install' ,
17+ 'installable_rhino_packages' ,
18+ 'after_rhino_install' ,
19+ 'after_rhino_uninstall' ,
20+ ]
1621
1722
1823def install (version = None , packages = None ):
@@ -84,8 +89,13 @@ def install(version=None, packages=None):
8489 symlinks = [(link ['source_path' ], link ['link' ]) for link in symlinks_to_install ]
8590 install_results = compas ._os .create_symlinks (symlinks )
8691
92+ installed_packages = []
8793 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.'
94+ if success :
95+ installed_packages .append (install_data ['name' ])
96+ result = 'OK'
97+ else :
98+ result = 'ERROR: Cannot create symlink, try to run as administrator.'
8999 results .append ((install_data ['name' ], result ))
90100
91101 if not all (install_results ):
@@ -106,10 +116,38 @@ def install(version=None, packages=None):
106116 if status != 'OK' :
107117 exit_code = - 1
108118
119+ if len (installed_packages ):
120+ print ()
121+ print ('Running post-installation steps...' )
122+ print ()
123+ _run_post_execution_steps (after_rhino_install (installed_packages ))
124+
109125 print ('\n Completed.' )
110126 if exit_code != 0 :
111127 sys .exit (exit_code )
112128
129+ def _run_post_execution_steps (steps_generator ):
130+ post_execution_errors = []
131+ for result in steps_generator :
132+ if isinstance (result , Exception ):
133+ post_execution_errors .append (result )
134+ continue
135+
136+ for item in result :
137+ try :
138+ package , message , success = item
139+ status = 'OK' if success else 'ERROR'
140+ print (' {} {}: {}' .format (package .ljust (20 ), status , message ))
141+ except ValueError :
142+ post_execution_errors .append (ValueError ('Step successful, but result is wrongly formatted: {}' .format (str (result ))))
143+
144+ if post_execution_errors :
145+ print ()
146+ print ('One or more errors occurred:' )
147+ print ()
148+ for error in post_execution_errors :
149+ print (' - {}' .format (repr (error )))
150+
113151
114152@compas .plugins .plugin (category = 'install' , pluggable_name = 'installable_rhino_packages' , tryfirst = True )
115153def default_installable_rhino_packages ():
@@ -143,6 +181,35 @@ def installable_rhino_packages():
143181 pass
144182
145183
184+ @compas .plugins .pluggable (category = 'install' , selector = 'collect_all' )
185+ def after_rhino_install (installed_packages ):
186+ """Allows extensions to execute actions after install to Rhino is done.
187+
188+ Extensions providing Rhino or Grasshopper features
189+ can implement this pluggable interface to perform
190+ additional steps after an installation to Rhino has
191+ been completed.
192+
193+ Parameters
194+ ----------
195+ installed_packages : :obj:`list` of :obj:`str`
196+ List of packages that have been installed successfully.
197+
198+ Examples
199+ --------
200+ >>> import compas.plugins
201+ >>> @compas.plugins.plugin(category='install')
202+ ... def after_rhino_install(installed_packages):
203+ ... # Do something after package is installed to Rhino, eg, copy components, etc
204+ ... return [('compas_ghpython', 'GH Components installed', True)]
205+
206+ Returns
207+ -------
208+ :obj:`list` of 3-tuple (str, str, bool)
209+ List containing a 3-tuple with component name, message and ``True``/``False`` success flag.
210+ """
211+ pass
212+
146213def _update_bootstrapper (install_path , packages ):
147214 # Take either the CONDA environment directory or the current Python executable's directory
148215 python_directory = os .environ .get ('CONDA_PREFIX' , None ) or os .path .dirname (sys .executable )
0 commit comments