def install(version=None, packages=None): """Install COMPAS for Rhino. Parameters ---------- version : {'5.0', '6.0', '7.0'}, optional The version number of Rhino. Default is ``'6.0'``. packages : list of str, optional List of packages to install or None to use default package list. Default is ``['compas', 'compas_rhino', 'compas_ghpython']``. Examples -------- .. code-block:: python import compas_rhino compas_rhino.install('6.0') .. code-block:: bash python -m compas_rhino.install -v 6.0 """ if version not in ('5.0', '6.0', '7.0'): version = '6.0' packages = _filter_installable_packages(version, packages) ipylib_path = compas_rhino._get_ironpython_lib_path(version) scripts_path = compas_rhino._get_scripts_path(version) print('Installing COMPAS packages to Rhino {0} scripts folder:'.format( version)) print('Location scripts folder: {}'.format(scripts_path)) print() results = [] symlinks_to_install = [] symlinks_to_uninstall = [] exit_code = 0 for package in packages: package_path = compas_rhino._get_package_path( importlib.import_module(package)) symlink_path = os.path.join(scripts_path, package) symlinks_to_install.append( dict(name=package, source_path=package_path, link=symlink_path)) symlinks_to_uninstall.append(dict(name=package, link=symlink_path)) # Handle legacy install location legacy_path = os.path.join(ipylib_path, package) if os.path.exists(legacy_path): symlinks_to_uninstall.append(dict(name=package, link=legacy_path)) # First uninstall existing copies of packages requested for installation symlinks = [link['link'] for link in symlinks_to_uninstall] uninstall_results = compas._os.remove_symlinks(symlinks) for uninstall_data, success in zip(symlinks_to_uninstall, uninstall_results): if not success: results.append( (uninstall_data['name'], 'ERROR: Cannot remove symlink, try to run as administrator.')) # Handle legacy bootstrapper if not compas_rhino._try_remove_bootstrapper(ipylib_path): results.append(( 'compas_bootstrapper', 'ERROR: Cannot remove legacy compas_bootstrapper, try to run as administrator.' )) # Ready to start installing symlinks = [(link['source_path'], link['link']) for link in symlinks_to_install] install_results = compas._os.create_symlinks(symlinks) 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.' results.append((install_data['name'], result)) if not all(install_results): exit_code = -1 if exit_code == -1: results.append(( 'compas_bootstrapper', 'WARNING: One or more packages failed, will not install bootstrapper, try uninstalling first' )) else: try: _update_bootstrapper(scripts_path, packages) results.append(('compas_bootstrapper', 'OK')) except: # noqa: E722 results.append(( 'compas_bootstrapper', 'ERROR: Could not create compas_bootstrapper to auto-determine Python environment' )) for package, status in results: print(' {} {}'.format(package.ljust(20), status)) if status != 'OK': exit_code = -1 print('\nCompleted.') if exit_code != 0: sys.exit(exit_code)
def install(version=None, packages=None, clean=False): """Install COMPAS for Rhino. Parameters ---------- version : {'5.0', '6.0', '7.0', '8.0'}, optional The version number of Rhino. Default is ``'7.0'``. packages : list of str, optional List of packages to install or None to use default package list. Default is the result of ``installable_rhino_packages``, which collects all installable packages in the current environment. clean : bool, optional If ``True``, this will clean up the entire scripts folder and remove also existing symlinks that are not importable in the current environment. Examples -------- .. code-block:: python import compas_rhino.install compas_rhino.install.install() .. code-block:: bash python -m compas_rhino.install """ version = compas_rhino._check_rhino_version(version) # We install COMPAS packages in the scripts folder # instead of directly as IPy module. scripts_path = compas_rhino._get_rhino_scripts_path(version) # This is for old installs ipylib_path = compas_rhino._get_rhino_ironpython_lib_path(version) # Filter the provided list of packages # If no packages are provided # this first collects all installable packages from the environment. packages = _filter_installable_packages(version, packages) results = [] symlinks_to_install = [] symlinks_to_uninstall = [] exit_code = 0 # check all installable packages # add the packages that can't be imported from the current env to the list of symlinks to uninstall # and remove the package name from the list of installable packages # make a copy of the list to avoid problems with removing items # note: perhaps this should already happen in the filter function... for name in packages[:]: try: importlib.import_module(name) except ImportError: path = os.path.join(scripts_path, name) symlinks_to_uninstall.append(dict(name=name, link=path)) packages.remove(name) # Also remove all broken symlinks from the scripts folder # because ... they're broken! # If it is an actual folder or a file, leave it alone # because probably someone put it there on purpose. for name in os.listdir(scripts_path): path = os.path.join(scripts_path, name) if os.path.islink(path): if not os.path.exists(path): symlinks_to_uninstall.append(dict(name=name, link=path)) try: importlib.import_module(name) except ImportError: pass else: if name not in packages: packages.append(name) # If the scripts folder is supposed to be cleaned # also remove all existing symlinks that cannot be imported # and reinstall symlinks that can be imported if clean: for name in os.listdir(scripts_path): path = os.path.join(scripts_path, name) if os.path.islink(path): if os.path.exists(path): try: importlib.import_module(name) except ImportError: path = os.path.join(scripts_path, name) symlinks_to_uninstall.append(dict(name=name, link=path)) else: if name not in packages: packages.append(name) # add all of the packages in the list of installable packages # to the list of symlinks to uninstall # and to the list of symlinks to install for package in packages: symlink_path = os.path.join(scripts_path, package) symlinks_to_uninstall.append(dict(name=package, link=symlink_path)) package_path = compas_rhino._get_package_path( importlib.import_module(package)) symlinks_to_install.append( dict(name=package, source_path=package_path, link=symlink_path)) # Handle legacy install location # This does not always work, # and especially not in cases where it is not necessary :) if ipylib_path: legacy_path = os.path.join(ipylib_path, package) if os.path.exists(legacy_path): symlinks_to_uninstall.append( dict(name=package, link=legacy_path)) # ------------------------- # Uninstall first # ------------------------- symlinks = [link['link'] for link in symlinks_to_uninstall] uninstall_results = compas._os.remove_symlinks(symlinks) # Let the user know if some symlinks could not be removed. for uninstall_data, success in zip(symlinks_to_uninstall, uninstall_results): if not success: results.append( (uninstall_data['name'], 'ERROR: Cannot remove symlink, try to run as administrator.')) # Handle legacy bootstrapper # Again, only if possible... if ipylib_path: if not compas_rhino._try_remove_bootstrapper(ipylib_path): results.append(( 'compas_bootstrapper', 'ERROR: Cannot remove legacy compas_bootstrapper, try to run as administrator.' )) # ------------------------- # Ready to start installing # ------------------------- # create new symlinks and register the results symlinks = [(link['source_path'], link['link']) for link in symlinks_to_install] install_results = compas._os.create_symlinks(symlinks) # set the exit code based on the installation results if not all(install_results): exit_code = -1 # make a list of installed packages # based on the installation results # and update the general results list installed_packages = [] for install_data, success in zip(symlinks_to_install, install_results): 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)) # finalize the general results list with info about the bootstrapper if exit_code == -1: results.append(( 'compas_bootstrapper', 'WARNING: One or more packages failed, will not install bootstrapper, try uninstalling first' )) else: try: _update_bootstrapper(scripts_path, packages) results.append(('compas_bootstrapper', 'OK')) except: # noqa: E722 results.append(( 'compas_bootstrapper', 'ERROR: Could not create compas_bootstrapper to auto-determine Python environment' )) # output the outcome of the installation process # perhaps we should more info here print('Installing COMPAS packages to Rhino {0} scripts folder:'.format( version)) print('{}\n'.format(scripts_path)) for package, status in results: print(' {} {}'.format(package.ljust(20), status)) if status != 'OK': exit_code = -1 if exit_code == 0 and len(installed_packages): print('\nRunning post-installation steps...\n') if not _run_post_execution_steps( after_rhino_install(installed_packages)): exit_code = -1 print('\nInstall completed.') if exit_code != 0: sys.exit(exit_code) global INSTALLED_VERSION INSTALLED_VERSION = version