Skip to content
is 15 KiB
Newer Older
#!/usr/bin/python2.7
Seblu's avatar
Seblu committed
# -*- python -*-
Seblu's avatar
Seblu committed
# -*- coding: utf-8 -*-
# Started 30/06/2011 by Seblu <seblu@seblu.net>

'''
InstallSystems Command line Tool
'''

import os
import time
Seblu's avatar
Seblu committed
import datetime
import argparse
import re
Seblu's avatar
Seblu committed
import installsystems
import installsystems.tools as istools
from installsystems.printer import *
from installsystems.repository import Repository
from installsystems.repository import RepositoryManager
from installsystems.repository import RepositoryConfig
from installsystems.image import PackageImage, SourceImage
from installsystems.config import MainConfigFile, RepoConfigFile

def load_repositories(args):
    '''
    Load repositories on a repository manager
    '''
    # remove cache is asked
    if args.no_cache:
        args.cache = None
    # init repo cache object
    repoman = RepositoryManager(args.cache, timeout=args.timeout)
    # register repositories (order matter)
    # load repo configs
    if args.repo_path is not None:
        # from command line
        repoman.register(RepositoryConfig(None, path=args.repo_path))
    else:
        # from config
        for repoconf in RepoConfigFile(args.repo_config).repos:
            if args.repo_filter is None:
                repoman.register(repoconf)
            else:
                if len(fnmatch.filter([repoconf.name], args.repo_filter)) > 0:
                    repoman.register(repoconf)
def select_one_repository(repoman):
    if len(repoman) == 0:
        raise Exception("No repository selected")
    elif len(repoman) > 1:
        raise Exception("Please select only one repository")
    return repoman[0]

def select_image(name, repoman):
    '''
    Select and load a package image from a standard naming type

    Allowed type are a direct filename on filesystem
    or [repo/]image[:version]

    Return the repository as second argument
    '''
    if istools.isfile(name) and os.path.isfile(name):
        return PackageImage(name), None
    else:
Seblu's avatar
Seblu committed
        (repo, image, version) = re.match("((\w+)/)?(\w+)(:v?(\d+))?", name).group(2,3,5)
        if repo is None:
            return repoman.get(image, version)
        else:
            return repoman[repo].get(image, version), repoman[repo]

def c_add(parser, args):
Seblu's avatar
Seblu committed
    '''
    Add an image package into a repository
Seblu's avatar
Seblu committed
    '''
    repoman = load_repositories(args)
    repo = repoman[args.repository]
    for image in args.path:
        pkg = PackageImage(image)
        repo.add(pkg, delete=not args.preserve)
def c_build(parser, args):
Seblu's avatar
Seblu committed
    '''
    Build an image source
    '''
Seblu's avatar
Seblu committed
    # build start time
    t0 = time.time()
    # load source image
    simg = SourceImage(args.path)
    # do the job
    simg.build(force=args.force, check=not args.no_check)
    # compute building time
    t1 = time.time()
    dt = int(t1 - t0)
    arrow("Build time: %s" % datetime.timedelta(seconds=dt))
def c_cat(parser, args):
Seblu's avatar
Seblu committed
    Display image's file
    # looks if arguments is a file or image name
Seblu's avatar
Seblu committed
    repoman = load_repositories(args)
    img, repo = select_image(args.image, repoman)
    for filename in args.file:
        img.cat(filename)
def c_clean(parser, args):
Seblu's avatar
Seblu committed
    '''
    Clean a repository
Seblu's avatar
Seblu committed
    '''
    raise NotImplementedError("Not yet implemented")

def c_copy(parser, args):
    '''
    Copy an image from a repository to another one
    '''
    # load repositories
Seblu's avatar
Seblu committed
    repoman = load_repositories(args)
    srcrepo = repoman[args.repo_src]
    dstrepo = repoman[args.repo_dst]
    # load source image
    srcimg = srcrepo.get(args.image, args.image_version)
    # Advertise
    arrow("Copying %s v%s from %s to %s" % (srcimg.name,
                                             srcimg.version,
                                             srcrepo.config.name,
                                             dstrepo.config.name))
    arrowlevel(1)
    dstrepo.add(srcimg)
    arrowlevel(-1)
def c_del(parser, args):
Seblu's avatar
Seblu committed
    '''
    Remove an image package from a repository
    '''
Seblu's avatar
Seblu committed
    repoman = load_repositories(args)
    for image in args.image:
        img, repo = select_image(image, repoman)
        if repo is None:
            raise Exception("You cannot delete an image outside a repository")
        if args.force:
            repo.delete(img.name, img.version)
        else:
            warn("The following opereation cannot be reversed!")
            out("You will delete %s v%s in repository %s" % (img.name,
                                                             img.version,
                                                             repo.config.name))
            if raw_input("Are you sure (yes)" ) == "yes":
                repo.delete(img.name, img.version)
def c_get(parser, args):
    '''
    Get a remove image in current directory
    '''
    raise NotImplementedError("Not yet implemented")

def c_help(parser, args):
    '''
    Show help
    '''
    if args.command not in args.subparser.choices:
        parser.print_help()
    else:
        args.subparser.choices[args.command].print_help()

def c_init(parser, args):
    '''
    Create an empty repository
    '''
    repoman = load_repositories(args)
    for reponame in args.repository:
        repoman[reponame].init()

def c_install(parser, args):
Seblu's avatar
Seblu committed
    '''
    Install an image
    '''
    # looks if arguments is a file or image name
    if istools.isfile(args.image) and os.path.isfile(args.image):
Seblu's avatar
Seblu committed
        pkg = PackageImage(istools.abspath(args.image))
    elif PackageImage.check_image_name(args.image):
        # get image package
        repoman = load_repositories(args)
Seblu's avatar
Seblu committed
        pkg = repoman.get(args.image, args.image_version)
    # add default show help options
    args.subparser.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS,
                                help="show program's version number and exit")
Seblu's avatar
Seblu committed
    # Print setup information
    arrow("Installing %s v%s" % (pkg.name, pkg.version))
    # install start time
    t0 = time.time()
    # run parser scripts with parser parser argument
    pkg.run_parser(parser=args.subparser)
    # call parser again, with extended attributes
    arrow("Parsing arguments")
    args = parser.parse_args(namespace=args)
Seblu's avatar
Seblu committed
    # run setup scripts
    pkg.run_setup(namespace=args)
    # compute building time
    t1 = time.time()
    dt = int(t1 - t0)
    arrow("Install time: %s" % datetime.timedelta(seconds=dt))

Aurélien Dunand's avatar
Aurélien Dunand committed
def c_list(parser, args):
    '''
    List images in repository or image content
    '''
Seblu's avatar
Seblu committed
    # List available repositories
    if len(args.values) == 0:
Aurélien Dunand's avatar
Aurélien Dunand committed
        repoman = load_repositories(args)
        arrow("Repositories")
Seblu's avatar
Seblu committed
        repoman.show(verbose=args.detail)
        return
    # list direct image or reposity content
    elif len(args.values) == 1:
Seblu's avatar
Seblu committed
        # list image file content
        if (istools.isfile(args.values[0]) and os.path.isfile(args.values[0])):
            pkg = PackageImage(args.values[0])
            arrow("Image %s v%s" % (pkg.name, pkg.version))
Seblu's avatar
Seblu committed
            pkg.show(verbose=args.detail)
        # list repository content
Aurélien Dunand's avatar
Aurélien Dunand committed
        else:
            args.repo_filter = args.values[0]
Aurélien Dunand's avatar
Aurélien Dunand committed
            repoman = load_repositories(args)
Seblu's avatar
Seblu committed
            for repo in repoman:
                arrow("Image in %s" % repo.config.name)
Seblu's avatar
Seblu committed
                repo.show(args.detail)
        return
    # list last image version
    elif len(args.values) == 2:
        args.repo_filter = args.values[0]
        args.image = args.values[1]
Seblu's avatar
Seblu committed
        args.image_version = None
    # list specific image version
    elif len(args.values) == 3:
        args.repo_filter = args.values[0]
        args.image = args.values[1]
        args.image_version = args.values[2]
    else:
        args.subparser.print_usage()
        exit(1)
Seblu's avatar
Seblu committed
    # display content of image accross a repositories
    repoman = load_repositories(args)
    pkg = repoman.get(args.image, args.image_version)
    arrow("Image %s v%s" % (pkg.name, pkg.version))
Seblu's avatar
Seblu committed
    pkg.show(verbose=args.detail)
Aurélien Dunand's avatar
Aurélien Dunand committed

Seblu's avatar
Seblu committed
def c_move(parser, args):
    '''
    Move an image from a repository to another one
    '''
    # load repositories
    repoman = load_repositories(args)
    srcrepo = repoman[args.repo_src]
    dstrepo = repoman[args.repo_dst]
    # load source image
    srcimg = srcrepo.get(args.image, args.image_version)
    # Advertise
    arrow("Copying %s v%s from %s to %s" % (srcimg.name,
                                             srcimg.version,
                                             srcrepo.config.name,
                                             dstrepo.config.name))
    arrowlevel(1)
    dstrepo.add(srcimg)
    srcrepo.delete(srcimg.name, srcimg.version)
    arrowlevel(-1)

def c_new(parser, args):
Seblu's avatar
Seblu committed
    '''
    Create a new source image
Seblu's avatar
Seblu committed
    '''
    SourceImage.create(args.path)

def c_search(parser, args):
    '''
    Search in repository
    '''
    repoman = load_repositories(args)
    repoman.search(args.pattern)
Seblu's avatar
Seblu committed
def c_version(parser, args):
    '''
    Print installsystems version
    '''
    out(installsystems.version)

Seblu's avatar
Seblu committed
# Top level argument parsing
p_main = argparse.ArgumentParser()
p_main.add_argument("-V", "--version", action="version",
                    version=installsystems.version,
                    help="show installsystems version")
# exclusive group on debug/quiet
ex_group = p_main.add_mutually_exclusive_group()
ex_group.add_argument("-d", "--debug", action="store_true",
Seblu's avatar
Seblu committed
                      help="active debug mode")
ex_group.add_argument("-q", "--quiet", action="store_true",
Seblu's avatar
Seblu committed
                      help="active quiet mode")
# common options
p_main.add_argument("-c", "--config", default="installsystems",
Seblu's avatar
Seblu committed
                    help="config file path")
p_main.add_argument("-R", "--repo-config", default="repository",
                    help="repository config file path")
Seblu's avatar
Seblu committed
p_main.add_argument("-f", "--repo-filter", default=None,
                    help="select repository by name in config files")
p_main.add_argument("-r", "--repo-path", default=None,
Seblu's avatar
Seblu committed
                    help="repository path")
p_main.add_argument("-C", "--cache", default=None,
                    help="path of the repository cache")
p_main.add_argument("--no-cache", action="store_true", default=False,
                    help="Not use persistent db caching")
p_main.add_argument("-t", "--timeout", dest="timeout", type=int, default=3,
                    help="download timeout (default 3)")

Seblu's avatar
Seblu committed
# create a subparsers for each command
subparsers = p_main.add_subparsers()

# add command parser
p_add =  subparsers.add_parser("add", help=c_add.__doc__.lower())
p_add.add_argument("-p", "--preserve", action="store_true", default=False,
                   help="don't remove image after adding to database")
p_add.add_argument("repository", help="repository where image will be added")
p_add.add_argument("path", nargs="+",
                   help="image path")
p_add.set_defaults(func=c_add)
Seblu's avatar
Seblu committed

# build command parser
p_build = subparsers.add_parser("build", help=c_build.__doc__.lower())
p_build.add_argument("-f", "--force", action="store_true", default=False,
Seblu's avatar
Seblu committed
                     help="overwrite existing image")
p_build.add_argument("-c", "--no-check", action="store_true", default=False,
Seblu's avatar
Seblu committed
                     help="do not check compilation before adding scripts")
p_build.add_argument("path", nargs="?", default=".")
p_build.set_defaults(func=c_build)

# cat command parser
p_cat = subparsers.add_parser("cat", help=c_cat.__doc__.lower())
Seblu's avatar
Seblu committed
p_cat.add_argument("image")
p_cat.add_argument("file", nargs="+", help="file to cat (glob allowed)")
p_cat.set_defaults(func=c_cat)
# clean command parser
p_clean = subparsers.add_parser("clean", help=c_clean.__doc__.lower())
p_clean.set_defaults(func=c_clean)

# copy command parser
p_copy = subparsers.add_parser("copy", help=c_copy.__doc__.lower())
p_copy.add_argument("repo_src", help="name of source repository")
p_copy.add_argument("repo_dst", help="name of destination repository")
p_copy.add_argument("image", help="image name")
p_copy.add_argument("image_version", nargs="?", help="image version")
p_copy.set_defaults(func=c_copy)
Seblu's avatar
Seblu committed

# del command parser
p_del =  subparsers.add_parser("del", help=c_del.__doc__.lower())
p_del.add_argument("image", nargs="+",
                   help="image to delete")
p_del.add_argument("-f", "--force", action="store_true", default=False,
                   help="delete image without confirmation")
Seblu's avatar
Seblu committed
p_del.set_defaults(func=c_del)

# get command parser
p_get = subparsers.add_parser("get", help=c_get.__doc__.lower())
p_get.set_defaults(func=c_get)

# help command parser
p_help = subparsers.add_parser("help", help=c_help.__doc__.lower())
p_help.add_argument("command", nargs="?", help="command name")
p_help.set_defaults(func=c_help, subparser=subparsers)

# init command parser
p_init = subparsers.add_parser("init", help=c_init.__doc__.lower())
p_init.add_argument("repository", nargs="+",
                    help="repository's name to initialize")
p_init.set_defaults(func=c_init)

Seblu's avatar
Seblu committed
# install command parser
p_install = subparsers.add_parser("install", add_help=False,
                                  help=c_install.__doc__.lower())
p_install.add_argument("-f", "--force", action="store_true", default=False,
Seblu's avatar
Seblu committed
                       help="overwrite existing image")
p_install.add_argument("-v", "--image-version", type=int, default=None,
                       help="image version")
p_install.add_argument("image", help="image to install (path or name)")
p_install.set_defaults(func=c_install, subparser=p_install)
# list command parser
p_list = subparsers.add_parser("list", help=c_list.__doc__.lower())
p_list.add_argument("-l", action="store_true", dest="detail",
                    default=False, help="detailled list output")
p_list.add_argument("values", nargs="*",
                    help="image or repositories to list")
p_list.set_defaults(func=c_list, subparser=p_list)

Seblu's avatar
Seblu committed
# move command parser
p_move = subparsers.add_parser("move", help=c_move.__doc__.lower())
p_move.add_argument("repo_src", help="name of source repository")
p_move.add_argument("repo_dst", help="name of destination repository")
p_move.add_argument("image", help="image name")
p_move.add_argument("image_version", nargs="?", help="image version")
p_move.set_defaults(func=c_move)

# new command parser
p_new = subparsers.add_parser("new", help=c_new.__doc__.lower())
p_new.add_argument("path", help="path of new image directory")
p_new.set_defaults(func=c_new)

# search command parser
p_search = subparsers.add_parser("search", help=c_search.__doc__.lower())
p_search.add_argument("pattern", help="search pattern in repository")
p_search.set_defaults(func=c_search)
Seblu's avatar
Seblu committed

Seblu's avatar
Seblu committed
# version command parser
p_version = subparsers.add_parser("version", help=c_version.__doc__.lower())
p_version.set_defaults(func=c_version)

Seblu's avatar
Seblu committed
try:
    # Parse and run
    args = p_main.parse_known_args()[0]
    # set debug and quiet mode before merge
    installsystems.debug = args.debug
    installsystems.quiet = args.quiet
    # load isinstall config
    config = MainConfigFile(args.config, "installsystems")
Seblu's avatar
Seblu committed
    config.merge(args)
    # set debug and quiet mode after merge
    installsystems.debug = args.debug
    installsystems.quiet = args.quiet
    if args.func is not c_install:
Seblu's avatar
Seblu committed
        args = p_main.parse_args(namespace=args)
    # let's go
    args.func(p_main, args)
Seblu's avatar
Seblu committed
except Exception as e:
    error(e)
except KeyboardInterrupt:
    warn("Keyboard Interrupted")