Skip to content

Commit ceca803

Browse files
muffatovsoch
andauthored
View install commands (#596)
* Removed the `--view` option of `shpc install` as per #590 (comment) * bugfix: always install in the default view, alongside additionally requested views Renamed the variables to make it clear what is a view and what is a view name. * Print what bash is running * Test views on tcsh too * Moved the code to install a module into a view to a separate function * addition of intermediate module class This will help to carry around some common data attributes and functions, and reduce redundancy within the ModuleBase class. It also allows for providing fewer variables to the rendered templates since they can come from the module. * ensure we maintain parsed name * Moved the view uninstallation to a separate function to mirror view_install * No need to make this local variable * Use parsed_name for consistency * Document the "force" flags Signed-off-by: vsoch <[email protected]> Co-authored-by: vsoch <[email protected]>
1 parent 6e6ec0a commit ceca803

File tree

14 files changed

+338
-278
lines changed

14 files changed

+338
-278
lines changed

.github/workflows/test.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ jobs:
9898
printf "\n\nmodule help ============================================\n"
9999
module help python/3.9.5-alpine
100100
101+
set -x
101102
python-exec echo donuts >test_output
102103
cat test_output
103104
grep --quiet donuts test_output
@@ -109,13 +110,14 @@ jobs:
109110
cat test_output
110111
grep --quiet 'Python 3.9.5' test_output
111112
rm test_output
112-
shpc uninstall --force python:3.9.5-alpine
113113
114-
# Try creating views install
115114
mkdir -p tmp-modules
116115
shpc config set views_base:tmp-modules
117116
shpc view create noodles
118-
shpc install --view noodles python:3.9.5-alpine
117+
shpc view install noodles python:3.9.5-alpine
118+
119+
shpc uninstall --force python:3.9.5-alpine
120+
shpc view --force delete noodles
119121
120122
- name: Run python module tests (tcsh)
121123
shell: tcsh -e {0}
@@ -164,4 +166,11 @@ jobs:
164166
cat test_output
165167
grep --quiet 'Python 3.9.5' test_output
166168
rm test_output
169+
170+
mkdir -p tmp-modules
171+
shpc config set views_base:tmp-modules
172+
shpc view create noodles
173+
shpc view install noodles python:3.9.5-alpine
174+
167175
shpc uninstall --force python:3.9.5-alpine
176+
shpc view --force delete noodles

shpc/client/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,6 @@ def get_parser():
101101
"install_recipe",
102102
help="recipe to install\nshpc install python\nshpc install python:3.9.5-alpine",
103103
)
104-
install.add_argument(
105-
"--view",
106-
dest="view",
107-
help="install module to a named view (must be installed to shpc first).",
108-
default=None,
109-
)
110104
install.add_argument(
111105
"--no-view",
112106
dest="no_view",

shpc/client/install.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
__license__ = "MPL 2.0"
44

55
import shpc.utils
6-
from shpc.logger import logger
76

87

98
def main(args, parser, extra, subparser):
@@ -25,11 +24,9 @@ def main(args, parser, extra, subparser):
2524
# Update config settings on the fly
2625
cli.settings.update_params(args.config_params)
2726

28-
# It doesn't make sense to define view and no view
29-
if args.view and args.no_view:
30-
logger.exit("Conflicting arguments --view and --no-view, choose one.")
31-
3227
# And do the install
33-
cli.install(
34-
args.install_recipe, view=args.view, disable_view=args.no_view, force=args.force
35-
)
28+
cli.install(args.install_recipe, force=args.force)
29+
if cli.settings.default_view and not args.no_view:
30+
cli.view_install(
31+
cli.settings.default_view, args.install_recipe, force=args.force
32+
)

shpc/client/view.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ def create_from_file(
5252

5353
# Extra modules to install
5454
for install_module in install_modules:
55-
cli.install(install_module, view=view_name, disable_view=False, force=force)
55+
56+
# TODO: can we cut out early if already installed?
57+
cli.install(install_module, force=force)
58+
cli.view_install(view_name, install_module, force=force)
5659

5760

5861
def main(args, parser, extra, subparser):
@@ -168,7 +171,8 @@ def main(args, parser, extra, subparser):
168171
# We don't make it hard to require them to install to the root first
169172
module_name = args.params.pop(0)
170173
if command == "install":
171-
cli.install(module_name, view=view_name, disable_view=False, force=args.force)
174+
cli.install(module_name, force=args.force)
175+
cli.view_install(view_name, module_name, force=args.force)
172176

173177
if command == "uninstall":
174-
cli.uninstall(module_name, view=view_name, force=args.force)
178+
cli.view_uninstall(view_name, module_name, force=args.force)

shpc/main/__init__.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@ def get_client(quiet=False, **kwargs):
4141

4242
# Add the container operator
4343
if container == "singularity":
44-
from .container import SingularityContainer
44+
from shpc.main.container import SingularityContainer
4545

4646
Client.container = SingularityContainer()
4747

4848
elif container == "podman":
49-
from .container import PodmanContainer
49+
from shpc.main.container import PodmanContainer
5050

5151
Client.container = PodmanContainer()
5252

5353
elif container == "docker":
54-
from .container import DockerContainer
54+
from shpc.main.container import DockerContainer
5555

5656
Client.container = DockerContainer()
5757

@@ -64,6 +64,8 @@ def get_client(quiet=False, **kwargs):
6464
logger.warning(
6565
"%s is not installed, functionality might be limited." % container.upper()
6666
)
67+
68+
# Pass on settings and container to module too
6769
Client.quiet = quiet
6870
Client.settings = settings
6971
return Client()

shpc/main/container/docker.py

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,7 @@ def test_script(self, image, test_script):
185185
# Return code
186186
return result["return_code"]
187187

188-
def install(
189-
self,
190-
module_path,
191-
container_path,
192-
name,
193-
template,
194-
parsed_name,
195-
aliases=None,
196-
url=None,
197-
description=None,
198-
version=None,
199-
config_features=None,
200-
features=None,
201-
config=None,
202-
):
188+
def install(self, module_path, template, module, features=None):
203189
"""Install a general container path to a module
204190
205191
The module_dir should be created by the calling function, and
@@ -210,50 +196,45 @@ def install(
210196
# Container features are defined in container.yaml and the settings
211197
# and specific values are determined by the container technology
212198
features = self.get_features(
213-
config_features, self.settings.container_features, features
199+
module.config.features, self.settings.container_features, features
214200
)
215201

216202
# Ensure that the container exists
217203
# Do we want to clean up other versions here too?
218-
manifest = self.inspect(container_path)
204+
manifest = self.inspect(module.container_path)
219205
if not manifest:
220-
sys.exit("Container %s was not found. Was it pulled?" % container_path)
206+
sys.exit(
207+
"Container %s was not found. Was it pulled?" % module.container_path
208+
)
221209

222210
labels = manifest[0].get("Labels", {})
223211

224-
# If there's a tag in the name, don't use it
225-
name = name.split(":", 1)[0]
226-
227212
# Option to create wrapper scripts for commands
228-
module_dir = os.path.dirname(module_path)
213+
aliases = module.config.get_aliases()
229214
wrapper_scripts = []
230215

231216
# Wrapper scripts can be global (for aliases) or container specific
232217
if self.settings.wrapper_scripts["enabled"] is True:
233218
wrapper_scripts = shpc.main.wrappers.generate(
234219
aliases=aliases,
235-
module_dir=module_dir,
220+
module_dir=module.module_dir,
236221
features=features,
237222
container=self,
238-
image=container_path,
239-
config=config,
223+
image=module.container_path,
224+
config=module.config,
240225
)
241226

242227
# Make sure to render all values!
243228
out = template.render(
244229
settings=self.settings,
245230
shell=self.shell_path,
246-
image=container_path,
247-
description=description,
248231
aliases=aliases,
249-
url=url,
250232
features=features,
251-
version=version,
252233
labels=labels,
253234
creation_date=datetime.now(),
254-
name=name,
255-
parsed_name=parsed_name,
256235
command=self.command,
236+
module=module,
237+
parsed_name=module.config.name,
257238
wrapper_scripts=wrapper_scripts,
258239
)
259240
shpc.utils.write_file(module_path, out)

shpc/main/container/singularity.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,7 @@ def _add_docker_image(self, name, tag, image, config, container_yaml, **kwargs):
165165
config.add_tag(tag, tags[tag])
166166
return config
167167

168-
def install(
169-
self,
170-
module_path,
171-
container_path,
172-
name,
173-
template,
174-
parsed_name,
175-
aliases=None,
176-
template_name=None,
177-
url=None,
178-
description=None,
179-
config_features=None,
180-
features=None,
181-
version=None,
182-
config=None,
183-
):
168+
def install(self, module_path, template, module, features=None):
184169
"""Install a general container path to a module
185170
186171
The module_dir should be created by the calling function, and
@@ -191,19 +176,19 @@ def install(
191176
# Container features are defined in container.yaml and the settings
192177
# and specific values are determined by the container technology
193178
features = self.get_features(
194-
config_features, self.settings.container_features, features
179+
module.config.features, self.settings.container_features, features
195180
)
196181

197182
# Remove any previous containers
198-
container_dir = os.path.dirname(container_path)
183+
container_dir = os.path.dirname(module.container_path)
199184
for older in glob("%s%s*.sif" % (container_dir, os.sep)):
200-
if older == container_path:
185+
if older == module.container_path:
201186
continue
202187
os.remove(older)
203188

204189
# Get inspect metadata from the container (only if singularity installed
205190
try:
206-
metadata = self.inspect(container_path)
191+
metadata = self.inspect(module.container_path)
207192

208193
# Add labels, and deffile
209194
labels = metadata.get("attributes", {}).get("labels")
@@ -216,34 +201,30 @@ def install(
216201
labels = {}
217202

218203
# Option to create wrapper scripts for commands
219-
module_dir = os.path.dirname(module_path)
204+
aliases = module.config.get_aliases()
220205

221206
# Wrapper scripts can be global (for aliases) or container specific
222207
wrapper_scripts = []
223208
if self.settings.wrapper_scripts["enabled"] is True:
224209
wrapper_scripts = shpc.main.wrappers.generate(
225210
aliases=aliases,
226-
module_dir=module_dir,
211+
module_dir=module.module_dir,
227212
features=features,
228213
container=self,
229-
image=container_path,
230-
config=config,
214+
image=module.container_path,
215+
config=module.config,
231216
)
232217

233218
# Make sure to render all values!
234219
out = template.render(
235220
settings=self.settings,
236-
container_sif=container_path,
237-
description=description,
238221
aliases=aliases,
239-
url=url,
240222
features=features,
241-
version=version,
242223
labels=labels,
243224
deffile=deffile,
244225
creation_date=datetime.now(),
245-
name=name,
246-
parsed_name=parsed_name,
226+
module=module,
227+
parsed_name=module.config.name,
247228
wrapper_scripts=wrapper_scripts,
248229
)
249230
utils.write_file(module_path, out)

0 commit comments

Comments
 (0)