Skip to content
is 15.4 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:
        (repo, image, version) = re.match("((\w+)/)?(\w+)(:(\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_new(parser, args):
Seblu's avatar
Seblu committed
    '''
    Create a new source image
    '''
Seblu's avatar
Seblu committed
    SourceImage.create(args.path)
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_init(parser, args):
    '''
Seblu's avatar
Seblu committed
    Create an empty repository
Seblu's avatar
Seblu committed
    repoman = load_repositories(args)
    for reponame in args.repository:
        repoman[reponame].init()
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_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_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

Aurélien Dunand's avatar
Aurélien Dunand committed
def c_cat(parser, args):
    '''
    Display image's file(s)
Aurélien Dunand's avatar
Aurélien Dunand committed
    '''
    # looks if arguments is a file or image name
    if istools.isfile(args.image) and os.path.isfile(args.image):
Aurélien Dunand's avatar
Aurélien Dunand committed
        pkg = PackageImage(istools.abspath(args.image))
    elif PackageImage.check_image_name(args.image):
        # get image package
        repoman = load_repositories(args)
        pkg = repoman.get(args.image, args.image_version)
    for filename in args.files:
        pkg.cat(filename)
Aurélien Dunand's avatar
Aurélien Dunand committed

def c_search(parser, args):
Seblu's avatar
Seblu committed
    '''
    Search in repository
    '''
Aurélien Dunand's avatar
Aurélien Dunand committed
    repoman = load_repositories(args)
    repoman.search(args.pattern)
def c_get(parser, args):
Seblu's avatar
Seblu committed
    '''
    Get a remove image in current directory
    '''
    raise NotImplementedError("Not yet implemented")

def c_clean(parser, args):
Seblu's avatar
Seblu committed
    '''
    Clean a repository
    '''
    raise NotImplementedError("Not yet implemented")

Aurélien Dunand's avatar
Aurélien Dunand committed
def c_copy(parser, args):
    '''
    Copy an image from a repository to another one
    '''
Seblu's avatar
Seblu committed
    # load repositories
Aurélien Dunand's avatar
Aurélien Dunand committed
    repoman = load_repositories(args)
Seblu's avatar
Seblu committed
    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))
Aurélien Dunand's avatar
Aurélien Dunand committed
    arrowlevel(1)
Seblu's avatar
Seblu committed
    dstrepo.add(srcimg)
Aurélien Dunand's avatar
Aurélien Dunand committed
    arrowlevel(-1)

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)

Seblu's avatar
Seblu committed
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()
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()

# new command parser
p_new = subparsers.add_parser("new", help=c_new.__doc__.lower())
Seblu's avatar
Seblu committed
p_new.add_argument("path", help="path of new image directory")
p_new.set_defaults(func=c_new)
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)

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

Seblu's avatar
Seblu committed
# 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")
Seblu's avatar
Seblu committed
p_add.set_defaults(func=c_add)

# 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)

# 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)

Aurélien Dunand's avatar
Aurélien Dunand committed
# cat command parser
p_cat = subparsers.add_parser("cat", help=c_cat.__doc__.lower())
p_cat.add_argument("-v", "--image-version", type=int, default=None,
Aurélien Dunand's avatar
Aurélien Dunand committed
p_cat.add_argument("image", help="image (path or name)")
p_cat.add_argument("files", nargs="+", help="files to cat")
p_cat.set_defaults(func=c_cat)
Aurélien Dunand's avatar
Aurélien Dunand committed

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

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

Seblu's avatar
Seblu committed
# clean command parser
p_clean = subparsers.add_parser("clean", help=c_clean.__doc__.lower())
p_clean.set_defaults(func=c_clean)

Aurélien Dunand's avatar
Aurélien Dunand committed
# 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
# 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)

Seblu's avatar
Seblu committed
# help command parser
Seblu's avatar
Seblu committed
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)
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")