Skip to content

Commit 08f76e9

Browse files
authored
Merge pull request #929 from compas-dev/remove-broken-links
Also try to remove broken symlinks during uninstall
2 parents c0fb259 + 4edd43d commit 08f76e9

File tree

4 files changed

+112
-34
lines changed

4 files changed

+112
-34
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4242

4343
### Changed
4444

45+
* Changed `compas_rhino.uninstall` to also remove broken symlinks if no specific packages are provided for un-installation.
46+
* Changed `compas_rhino.install` to also remove broken symlinks.
47+
4548
### Removed
4649

4750

src/compas_rhino/install.py

Lines changed: 69 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@
1919
]
2020

2121

22-
def install(version=None, packages=None):
22+
def install(version=None, packages=None, clean=False):
2323
"""Install COMPAS for Rhino.
2424
2525
Parameters
2626
----------
27-
version : {'5.0', '6.0', '7.0'}, optional
27+
version : {'5.0', '6.0', '7.0', '8.0'}, optional
2828
The version number of Rhino.
2929
Default is ``'6.0'``.
3030
packages : list of str, optional
3131
List of packages to install or None to use default package list.
32-
Default is ``['compas', 'compas_rhino', 'compas_ghpython']``.
32+
Default is the result of ``installable_rhino_packages``,
33+
which collects all installable packages in the current environment.
34+
clean : bool, optional
35+
If ``True``, this will clean up the entire scripts folder and remove
36+
also existing symlinks that are not importable in the current environment.
3337
3438
Examples
3539
--------
@@ -44,28 +48,62 @@ def install(version=None, packages=None):
4448
4549
"""
4650

47-
if version not in ('5.0', '6.0', '7.0'):
51+
if version not in ('5.0', '6.0', '7.0', '8.0'):
4852
version = '6.0'
4953

50-
packages = _filter_installable_packages(version, packages)
51-
52-
ipylib_path = compas_rhino._get_ironpython_lib_path(version)
5354
# We install COMPAS packages in the scripts folder
5455
# instead of directly as IPy module.
5556
scripts_path = compas_rhino._get_scripts_path(version)
5657

57-
print('Installing COMPAS packages to Rhino {0} scripts folder:'.format(version))
58-
print('{}\n'.format(scripts_path))
58+
# This is for old installs
59+
ipylib_path = compas_rhino._get_ironpython_lib_path(version)
60+
61+
packages = _filter_installable_packages(version, packages)
5962

6063
results = []
6164
symlinks_to_install = []
6265
symlinks_to_uninstall = []
6366
exit_code = 0
6467

68+
# check all installable packages
69+
# add the packages that can't be imported from the current env to the list of symlinks to uninstall
70+
# and remove the package name from the list of installable packages
71+
# make a copy of the list to avoid problems with removing items
72+
# note: perhaps this should already happen in the filter function...
73+
for name in packages[:]:
74+
try:
75+
importlib.import_module(name)
76+
except ImportError:
77+
path = os.path.join(scripts_path, name)
78+
symlinks_to_uninstall.append(dict(name=name, link=path))
79+
packages.remove(name)
80+
81+
# Also remove all broken symlinks from the scripts folder
82+
# because ... they're broken!
83+
# If it is an actual folder or a file, leave it alone
84+
# because probably someone put it there on purpose.
85+
for name in os.listdir(scripts_path):
86+
path = os.path.join(scripts_path, name)
87+
if os.path.islink(path):
88+
if not os.path.exists(path):
89+
symlinks_to_uninstall.append(dict(name=name, link=path))
90+
else:
91+
if clean:
92+
try:
93+
importlib.import_module(name)
94+
except ImportError:
95+
path = os.path.join(scripts_path, name)
96+
symlinks_to_uninstall.append(dict(name=name, link=path))
97+
else:
98+
if name not in packages:
99+
packages.append(name)
100+
101+
# add all of the packages in the list of installable packages
102+
# to the list of symlinks to uninstall
103+
# and to the list of symlinks to install
65104
for package in packages:
66105
symlink_path = os.path.join(scripts_path, package)
67-
if os.path.exists(symlink_path):
68-
symlinks_to_uninstall.append(dict(name=package, link=symlink_path))
106+
symlinks_to_uninstall.append(dict(name=package, link=symlink_path))
69107

70108
package_path = compas_rhino._get_package_path(importlib.import_module(package))
71109
symlinks_to_install.append(dict(name=package, source_path=package_path, link=symlink_path))
@@ -92,10 +130,21 @@ def install(version=None, packages=None):
92130
if not compas_rhino._try_remove_bootstrapper(ipylib_path):
93131
results.append(('compas_bootstrapper', 'ERROR: Cannot remove legacy compas_bootstrapper, try to run as administrator.'))
94132

133+
# -------------------------
95134
# Ready to start installing
135+
# -------------------------
136+
137+
# create new symlinks and register the results
96138
symlinks = [(link['source_path'], link['link']) for link in symlinks_to_install]
97139
install_results = compas._os.create_symlinks(symlinks)
98140

141+
# set the exit code based on the installation results
142+
if not all(install_results):
143+
exit_code = -1
144+
145+
# make a list of installed packages
146+
# based on the installation results
147+
# and update the general results list
99148
installed_packages = []
100149
for install_data, success in zip(symlinks_to_install, install_results):
101150
if success:
@@ -105,9 +154,7 @@ def install(version=None, packages=None):
105154
result = 'ERROR: Cannot create symlink, try to run as administrator.'
106155
results.append((install_data['name'], result))
107156

108-
if not all(install_results):
109-
exit_code = -1
110-
157+
# finalize the general results list with info about the bootstrapper
111158
if exit_code == -1:
112159
results.append(('compas_bootstrapper', 'WARNING: One or more packages failed, will not install bootstrapper, try uninstalling first'))
113160
else:
@@ -117,9 +164,13 @@ def install(version=None, packages=None):
117164
except: # noqa: E722
118165
results.append(('compas_bootstrapper', 'ERROR: Could not create compas_bootstrapper to auto-determine Python environment'))
119166

167+
# output the outcome of the installation process
168+
# perhaps we should more info here
169+
print('Installing COMPAS packages to Rhino {0} scripts folder:'.format(version))
170+
print('{}\n'.format(scripts_path))
171+
120172
for package, status in results:
121173
print(' {} {}'.format(package.ljust(20), status))
122-
123174
if status != 'OK':
124175
exit_code = -1
125176

@@ -271,9 +322,10 @@ def _filter_installable_packages(version, packages):
271322

272323
parser = argparse.ArgumentParser()
273324

274-
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0'], default='6.0', help="The version of Rhino to install the packages in.")
325+
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0', '8.0'], default='6.0', help="The version of Rhino to install the packages in.")
275326
parser.add_argument('-p', '--packages', nargs='+', help="The packages to install.")
327+
parser.add_argument('--clean', dest='clean', default=False, action='store_true')
276328

277329
args = parser.parse_args()
278330

279-
install(version=args.version, packages=args.packages)
331+
install(version=args.version, packages=args.packages, clean=args.clean)

src/compas_rhino/install_plugin.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def install_plugin(plugin, version=None):
1717
----------
1818
plugin : str
1919
The path to the plugin folder.
20-
version : {'5.0', '6.0', '7.0'}, optional
20+
version : {'5.0', '6.0', '7.0', '8.0'}, optional
2121
The version of Rhino for which the plugin should be installed.
2222
Default is ``'6.0'``.
2323
@@ -58,14 +58,29 @@ def install_plugin(plugin, version=None):
5858
python -m compas_rhino.install_plugin -v 7.0 ui/Rhino/XXX
5959
6060
"""
61-
if version not in ('5.0', '6.0', '7.0'):
61+
if version not in ('5.0', '6.0', '7.0', '8.0'):
6262
version = '6.0'
6363

6464
if not os.path.isdir(plugin):
6565
raise Exception('Cannot find the plugin: {}'.format(plugin))
6666

6767
plugin_dir = os.path.abspath(plugin)
6868

69+
# clean up the plugin directory
70+
71+
# # Also remove all broken symlinks
72+
# # because ... they're broken!
73+
# broken = []
74+
# for name in os.listdir(plugin_dir):
75+
# path = os.path.join(plugin_dir, name)
76+
# if os.path.islink(path):
77+
# if not os.path.exists(path):
78+
# broken.append(path)
79+
# if broken:
80+
# pass
81+
82+
# proceed with the installation
83+
6984
plugin_path, plugin_name = os.path.split(plugin_dir)
7085
if not plugin_path:
7186
plugin_path = os.getcwd()
@@ -98,15 +113,13 @@ def install_plugin(plugin, version=None):
98113
source = plugin_dir
99114
destination = os.path.join(python_plugins_path, plugin_fullname)
100115

101-
print('Installing PlugIn {} to Rhino PythonPlugIns.'.format(plugin_name))
116+
print('\nInstalling PlugIn {} to Rhino PythonPlugIns.'.format(plugin_name))
102117

103118
remove_symlinks([destination])
104119
create_symlinks([(source, destination)])
105120

106-
print()
107-
print('PlugIn {} Installed.'.format(plugin_name))
108-
print()
109-
print('Restart Rhino and open the Python editor at least once to make it available.')
121+
print('\nPlugIn {} Installed.'.format(plugin_name))
122+
print('\nRestart Rhino and open the Python editor at least once to make it available.')
110123

111124

112125
# ==============================================================================
@@ -118,10 +131,10 @@ def install_plugin(plugin, version=None):
118131
import argparse
119132

120133
parser = argparse.ArgumentParser(
121-
description='COMPAS Rhino PLugin Installation command-line utility.')
134+
description='COMPAS Rhino Plugin Installation command-line utility.')
122135

123136
parser.add_argument('plugin', help="The path to the plugin directory.")
124-
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0'], default='6.0', help="The version of Rhino.")
137+
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0', '8.0'], default='6.0', help="The version of Rhino.")
125138

126139
args = parser.parse_args()
127140

src/compas_rhino/uninstall.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def uninstall(version=None, packages=None):
2323
2424
Parameters
2525
----------
26-
version : {'5.0', '6.0', '7.0'}, optional
26+
version : {'5.0', '6.0', '7.0', '8.0'}, optional
2727
The version number of Rhino.
2828
Default is ``'6.0'``.
2929
packages : list of str, optional
@@ -42,16 +42,27 @@ def uninstall(version=None, packages=None):
4242
python -m compas_rhino.uninstall -v 6.0
4343
4444
"""
45-
if version not in ('5.0', '6.0', '7.0'):
45+
if version not in ('5.0', '6.0', '7.0', '8.0'):
4646
version = '6.0'
4747

48-
packages = _filter_installed_packages(version, packages)
49-
50-
ipylib_path = compas_rhino._get_ironpython_lib_path(version)
5148
# We install COMPAS packages in the scripts folder
5249
# instead of directly as IPy module.
5350
scripts_path = compas_rhino._get_scripts_path(version)
5451

52+
# This is for old installs
53+
ipylib_path = compas_rhino._get_ironpython_lib_path(version)
54+
55+
packages = _filter_installed_packages(version, packages)
56+
57+
# Also remove all broken symlinks
58+
# because ... they're broken!
59+
for name in os.listdir(scripts_path):
60+
path = os.path.join(scripts_path, name)
61+
if os.path.islink(path):
62+
if not os.path.exists(path):
63+
if name not in packages:
64+
packages.append(name)
65+
5566
print('Uninstalling COMPAS packages from Rhino {0} scripts folder: \n{1}'.format(version, scripts_path))
5667

5768
results = []
@@ -60,8 +71,7 @@ def uninstall(version=None, packages=None):
6071

6172
for package in packages:
6273
symlink_path = os.path.join(scripts_path, package)
63-
if os.path.exists(symlink_path):
64-
symlinks_to_uninstall.append(dict(name=package, link=symlink_path))
74+
symlinks_to_uninstall.append(dict(name=package, link=symlink_path))
6575

6676
# Handle legacy install location
6777
# This does not always work,
@@ -197,7 +207,7 @@ def after_rhino_uninstall(uninstalled_packages):
197207

198208
parser = argparse.ArgumentParser()
199209

200-
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0'], default='6.0', help="The version of Rhino to install the packages in.")
210+
parser.add_argument('-v', '--version', choices=['5.0', '6.0', '7.0', '8.0'], default='6.0', help="The version of Rhino to install the packages in.")
201211
parser.add_argument('-p', '--packages', nargs='+', help="The packages to uninstall.")
202212

203213
args = parser.parse_args()

0 commit comments

Comments
 (0)