Add a cleaned up repo command.

This commit is contained in:
Todd Gamblin 2015-11-28 19:00:24 -08:00
parent 73ef06018e
commit dfcf567de0

View File

@ -22,103 +22,114 @@
# along with this program; if not, write to the Free Software Foundation, # along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
import os
import re
import shutil
from external import argparse from external import argparse
import llnl.util.tty as tty import llnl.util.tty as tty
from llnl.util.tty.color import colorize
from llnl.util.tty.colify import colify
from llnl.util.lang import index_by
from llnl.util.filesystem import join_path, mkdirp from llnl.util.filesystem import join_path, mkdirp
import spack.spec import spack.spec
import spack.config import spack.config
from spack.util.environment import get_path from spack.util.environment import get_path
from spack.repository import repo_config_name from spack.repository import packages_dir_name, repo_config_name, Repo
import os description = "Manage package source repositories."
import exceptions
from contextlib import closing
description = "Manage package sources"
def setup_parser(subparser): def setup_parser(subparser):
sp = subparser.add_subparsers( sp = subparser.add_subparsers(metavar='SUBCOMMAND', dest='repo_command')
metavar='SUBCOMMAND', dest='repo_command')
add_parser = sp.add_parser('add', help=repo_add.__doc__)
add_parser.add_argument('directory', help="Directory containing the packages.")
# Create
create_parser = sp.add_parser('create', help=repo_create.__doc__) create_parser = sp.add_parser('create', help=repo_create.__doc__)
create_parser.add_argument('directory', help="Directory containing the packages.") create_parser.add_argument(
create_parser.add_argument('name', help="Name of new package repository.") 'namespace', help="Namespace to identify packages in the repository.")
create_parser.add_argument(
remove_parser = sp.add_parser('remove', help=repo_remove.__doc__) 'directory', help="Directory to create the repo in. Defaults to same as namespace.", nargs='?')
remove_parser.add_argument('name')
# List
list_parser = sp.add_parser('list', help=repo_list.__doc__) list_parser = sp.add_parser('list', help=repo_list.__doc__)
def add_to_config(dir): def repo_create(args):
config = spack.config.get_config() """Create a new package repo for a particular namespace."""
user_config = spack.config.get_config('user') namespace = args.namespace
orig = None if not re.match(r'\w[\.\w-]*', namespace):
if config.has_value('repo', '', 'directories'): tty.die("Invalid namespace: '%s'" % namespace)
orig = config.get_value('repo', '', 'directories')
if orig and dir in orig.split(':'):
return False
newsetting = orig + ':' + dir if orig else dir root = args.directory
user_config.set_value('repo', '', 'directories', newsetting) if not root:
user_config.write() root = namespace
return True
existed = False
if os.path.exists(root):
if os.path.isfile(root):
tty.die('File %s already exists and is not a directory' % root)
elif os.path.isdir(root):
if not os.access(root, os.R_OK | os.W_OK):
tty.die('Cannot create new repo in %s: cannot access directory.' % root)
if os.listdir(root):
tty.die('Cannot create new repo in %s: directory is not empty.' % root)
existed = True
full_path = os.path.realpath(root)
parent = os.path.dirname(full_path)
if not os.access(parent, os.R_OK | os.W_OK):
tty.die("Cannot create repository in %s: can't access parent!" % root)
try:
config_path = os.path.join(root, repo_config_name)
packages_path = os.path.join(root, packages_dir_name)
mkdirp(packages_path)
with open(config_path, 'w') as config:
config.write("repo:\n")
config.write(" namespace: '%s'\n" % namespace)
except (IOError, OSError) as e:
tty.die('Failed to create new repository in %s.' % root,
"Caused by %s: %s" % (type(e), e))
# try to clean up.
if existed:
shutil.rmtree(config_path, ignore_errors=True)
shutil.rmtree(packages_path, ignore_errors=True)
else:
shutil.rmtree(root, ignore_errors=True)
tty.msg("Created repo with namespace '%s'." % namespace)
tty.msg("To register it with Spack, add a line like this to ~/.spack/repos.yaml:",
'repos:',
' - ' + full_path)
def repo_add(args): def repo_add(args):
"""Add package sources to the Spack configuration.""" """Remove a package source from the Spack configuration"""
if not add_to_config(args.directory): # FIXME: how to deal with this with the current config architecture?
tty.die('Repo directory %s already exists in the repo list' % dir) # FIXME: Repos do not have mnemonics, which I assumed would be simpler... should they have them after all?
def repo_create(args):
"""Create a new package repo at a directory and name"""
dir = args.directory
name = args.name
if os.path.exists(dir) and not os.path.isdir(dir):
tty.die('File %s already exists and is not a directory' % dir)
if not os.path.exists(dir):
try:
mkdirp(dir)
except exceptions.OSError, e:
tty.die('Failed to create new directory %s' % dir)
path = os.path.join(dir, repo_config_filename)
try:
with closing(open(path, 'w')) as repofile:
repofile.write(name + '\n')
except exceptions.IOError, e:
tty.die('Could not create new file %s' % path)
if not add_to_config(args.directory):
tty.warn('Repo directory %s already exists in the repo list' % dir)
def repo_remove(args): def repo_remove(args):
"""Remove a package source from the Spack configuration""" """Remove a package source from the Spack configuration"""
pass # FIXME: see above.
def repo_list(args): def repo_list(args):
"""List package sources and their mnemoics""" """List package sources and their mnemoics"""
root_names = spack.repo.repos roots = spack.config.get_repos_config()
max_len = max(len(s[0]) for s in root_names) repos = [Repo(r) for r in roots]
fmt = "%%-%ds%%s" % (max_len + 4)
for root in root_names:
print fmt % (root[0], root[1])
msg = "%d package repositor" % len(repos)
msg += "y." if len(repos) == 1 else "ies."
tty.msg(msg)
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)
def repo(parser, args): def repo(parser, args):
action = { 'add' : repo_add, action = { 'create' : repo_create,
'create' : repo_create,
'remove' : repo_remove,
'list' : repo_list } 'list' : repo_list }
action[args.repo_command](args) action[args.repo_command](args)