# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from __future__ import print_function
import os
import sys
import llnl.util.tty as tty
import spack.config
import spack.repo
import spack.util.path
description = "manage package source repositories"
section = "config"
level = "long"
[docs]def setup_parser(subparser):
sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='repo_command')
scopes = spack.config.scopes()
scopes_metavar = spack.config.scopes_metavar
# Create
create_parser = sp.add_parser('create', help=repo_create.__doc__)
create_parser.add_argument(
'directory', help="directory to create the repo in")
create_parser.add_argument(
'namespace', help="namespace to identify packages in the repository. "
"defaults to the directory name", nargs='?')
# List
list_parser = sp.add_parser('list', help=repo_list.__doc__)
list_parser.add_argument(
'--scope', choices=scopes, metavar=scopes_metavar,
default=spack.config.default_list_scope(),
help="configuration scope to read from")
# Add
add_parser = sp.add_parser('add', help=repo_add.__doc__)
add_parser.add_argument(
'path', help="path to a Spack package repository directory")
add_parser.add_argument(
'--scope', choices=scopes, metavar=scopes_metavar,
default=spack.config.default_modify_scope(),
help="configuration scope to modify")
# Remove
remove_parser = sp.add_parser(
'remove', help=repo_remove.__doc__, aliases=['rm'])
remove_parser.add_argument(
'namespace_or_path',
help="namespace or path of a Spack package repository")
remove_parser.add_argument(
'--scope', choices=scopes, metavar=scopes_metavar,
default=spack.config.default_modify_scope(),
help="configuration scope to modify")
[docs]def repo_create(args):
"""Create a new package repository."""
full_path, namespace = spack.repo.create_repo(
args.directory, args.namespace
)
tty.msg("Created repo with namespace '%s'." % namespace)
tty.msg("To register it with spack, run this command:",
'spack repo add %s' % full_path)
[docs]def repo_add(args):
"""Add a package source to Spack's configuration."""
path = args.path
# real_path is absolute and handles substitution.
canon_path = spack.util.path.canonicalize_path(path)
# check if the path exists
if not os.path.exists(canon_path):
tty.die("No such file or directory: %s" % path)
# Make sure the path is a directory.
if not os.path.isdir(canon_path):
tty.die("Not a Spack repository: %s" % path)
# Make sure it's actually a spack repository by constructing it.
repo = spack.repo.Repo(canon_path)
# If that succeeds, finally add it to the configuration.
repos = spack.config.get('repos', scope=args.scope)
if not repos:
repos = []
if repo.root in repos or path in repos:
tty.die("Repository is already registered with Spack: %s" % path)
repos.insert(0, canon_path)
spack.config.set('repos', repos, args.scope)
tty.msg("Added repo with namespace '%s'." % repo.namespace)
[docs]def repo_remove(args):
"""Remove a repository from Spack's configuration."""
repos = spack.config.get('repos', scope=args.scope)
namespace_or_path = args.namespace_or_path
# If the argument is a path, remove that repository from config.
canon_path = spack.util.path.canonicalize_path(namespace_or_path)
for repo_path in repos:
repo_canon_path = spack.util.path.canonicalize_path(repo_path)
if canon_path == repo_canon_path:
repos.remove(repo_path)
spack.config.set('repos', repos, args.scope)
tty.msg("Removed repository %s" % repo_path)
return
# If it is a namespace, remove corresponding repo
for path in repos:
try:
repo = spack.repo.Repo(path)
if repo.namespace == namespace_or_path:
repos.remove(path)
spack.config.set('repos', repos, args.scope)
tty.msg("Removed repository %s with namespace '%s'."
% (repo.root, repo.namespace))
return
except spack.repo.RepoError:
continue
tty.die("No repository with path or namespace: %s"
% namespace_or_path)
[docs]def repo_list(args):
"""Show registered repositories and their namespaces."""
roots = spack.config.get('repos', scope=args.scope)
repos = []
for r in roots:
try:
repos.append(spack.repo.Repo(r))
except spack.repo.RepoError:
continue
if sys.stdout.isatty():
msg = "%d package repositor" % len(repos)
msg += "y." if len(repos) == 1 else "ies."
tty.msg(msg)
if not repos:
return
max_ns_len = max(len(r.namespace) for r in repos)
for repo in repos:
fmt = "%%-%ds%%s" % (max_ns_len + 4)
print(fmt % (repo.namespace, repo.root))
[docs]def repo(parser, args):
action = {'create': repo_create,
'list': repo_list,
'add': repo_add,
'remove': repo_remove,
'rm': repo_remove}
action[args.repo_command](args)