#!/usr/bin/python # -*- python -*- # -*- coding: utf-8 -*- # Started 30/06/2011 by Seblu ''' InstallSystems Command line Tool ''' import os import time import datetime import re import fnmatch import warnings import installsystems import installsystems.tools as istools import installsystems.argparse as argparse # to be removed when python2.7 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, filter=args.repo_filter) # register repositories (order matter) # load repo configs from command line if args.repo_path is not None: repoman.register(RepositoryConfig(istools.smd5sum(args.repo_path)[:8], path=args.repo_path)) # load repo configs from config for repoconf in RepoConfigFile(args.repo_config).repos: repoman.register(repoconf) return repoman def select_image(name, repoman, best=False): ''' 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: x = re.match("^(([-_\w]+)/)?([-_\w]+)(:v?(\d+))?$", name) if x is None: raise Exception("%s is not a valid image" % name) (repo, image, version) = x.group(2,3,5) debug("Selected image is %s v%s in %s" % (image, version, repo)) if repo is None: return repoman.get(image, version, best) else: return repoman[repo].get(image, version), repoman[repo] def c_add(parser, args): ''' Add an image package into a repository ''' 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): ''' Build an image source ''' # 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): ''' Display image's file ''' # looks if arguments is a file or image name repoman = load_repositories(args) img, repo = select_image(args.image, repoman, args.best) for filename in args.file: img.cat(filename) def c_check(parser, args): ''' Check for unreferenced and missing files inside a repository ''' repoman = load_repositories(args) for reponame in args.repository: repoman[reponame].check() def c_clean(parser, args): ''' Remove unreferenced files from repoistory ''' repoman = load_repositories(args) for reponame in args.repository: repoman[reponame].clean() def c_copy(parser, args): ''' Copy an image from a repository to another one ''' repoman = load_repositories(args) dstrepo = repoman[args.repository] for image in args.image: srcimg, srcrepo = select_image(image, repoman, args.best) arrow("Copying %s v%s from repository %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): ''' Remove an image package from a repository ''' repoman = load_repositories(args) for image in args.image: img, repo = select_image(image, repoman, args.best) if repo is None: raise Exception("You cannot delete an image outside a repository") if not args.force: 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 not confirm(): raise Exception("Aborted!") repo.delete(img.name, img.version) def c_diff(parser, args): ''' Show diff between two repositories or images ''' repoman = load_repositories(args) if args.object[0] in repoman.onlines and args.object[1] in repoman.onlines: Repository.diff(repoman[args.object[0]], repoman[args.object[1]]) else: img1, repo1 = select_image(args.object[0], repoman, args.best) img2, repo2 = select_image(args.object[1], repoman, args.best) PackageImage.diff(img1, img2) def c_extract(parser, args): ''' Extract an image package inside a directory ''' repoman = load_repositories(args) img, repo = select_image(args.image, repoman, args.best) img.extract(args.path, payload=args.payload, force=args.force) def c_get(parser, args): ''' Download a remote image in current directory ''' repoman = load_repositories(args) for image in args.image: img, repo = select_image(image, repoman, args.best) img.download(".", payload=args.payload, force=args.force) 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): ''' Install an image ''' # select image to install repoman = load_repositories(args) img = select_image(args.image, repoman, args.best)[0] # add default show help options args.subparser.add_argument("-h", "--help", action="help", default=argparse.SUPPRESS, help="show program's version number and exit") # Print setup information arrow("Installing %s v%s" % (img.name, img.version)) # install start time t0 = time.time() # run parser scripts with parser parser argument img.run_parser(parser=args.subparser) # call parser again, with extended attributes arrow("Parsing arguments") args = parser.parse_args(namespace=args) # run setup scripts img.run_setup(namespace=args) # compute building time t1 = time.time() dt = int(t1 - t0) arrow("Install time: %s" % datetime.timedelta(seconds=dt)) def c_list(parser, args): ''' List images in repository or image content ''' # List available repositories repoman = load_repositories(args) if len(args.object) == 0: arrow("Repositories") repoman.show(verbose=args.verbose) else: for o in args.object: repos = fnmatch.filter(repoman.onlines, o) if len(repos) > 0: for reponame in repos: arrow(reponame) repoman[reponame].show(verbose=args.verbose, changelog=args.changelog) else: img, repo = select_image(o, repoman, args.best) img.show(verbose=args.verbose, changelog=args.changelog) def c_move(parser, args): ''' Move an image from a repository to another one ''' repoman = load_repositories(args) dstrepo = repoman[args.repository] for image in args.image: srcimg, srcrepo = select_image(image, repoman, args.best) if not args.force: out("You will move %s v%s from %s to %s" % (srcimg.name, srcimg.version, srcrepo.config.name, dstrepo.config.name)) if not confirm(): raise Exception("Aborted!") arrow("Moving %s v%s from repository %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): ''' Create a new source image ''' SourceImage.create(args.path, args.force) def c_search(parser, args): ''' Search in repository ''' repoman = load_repositories(args) repoman.search(args.pattern) def c_version(parser, args): ''' Print installsystems version ''' out(installsystems.version) # 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", help="active debug mode") ex_group.add_argument("-q", "--quiet", action="store_true", help="active quiet mode") # common options p_main.add_argument("-c", "--config", default="installsystems", help="config file path") p_main.add_argument("-R", "--repo-config", default="repository", help="repository config file path") 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, 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)") # 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 images will be added") p_add.add_argument("path", nargs="+", help="image path") p_add.set_defaults(func=c_add) # 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, help="overwrite existing image") p_build.add_argument("-c", "--no-check", action="store_true", default=False, 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()) p_cat.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_cat.add_argument("image", help="") p_cat.add_argument("file", nargs="+", help="file inside image to cat (globbing allowed)") p_cat.set_defaults(func=c_cat) # check command parser p_check = subparsers.add_parser("check", help=c_check.__doc__.lower()) p_check.add_argument("repository", nargs="+", help="repositories to check") p_check.set_defaults(func=c_check) # clean command parser p_clean = subparsers.add_parser("clean", help=c_clean.__doc__.lower()) p_clean.add_argument("repository", nargs="+", help="repositories to clean") 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("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_copy.add_argument("image", nargs="+", help="image syntax is ") p_copy.add_argument("repository", help="destination repository") p_copy.set_defaults(func=c_copy) # del command parser p_del = subparsers.add_parser("del", help=c_del.__doc__.lower()) p_del.add_argument("image", nargs="+", help="image syntax is ") p_del.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_del.add_argument("-f", "--force", action="store_true", default=False, help="delete image without confirmation") p_del.set_defaults(func=c_del) # diff command parser p_diff = subparsers.add_parser("diff", help=c_diff.__doc__.lower()) p_diff.add_argument("object", nargs=2, help="object syntax is ") p_diff.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_diff.set_defaults(func=c_diff) # extract command parser p_extract = subparsers.add_parser("extract", help=c_extract.__doc__.lower()) p_extract.add_argument("-p", action="store_true", dest="payload", default=False, help="extract payloads") p_extract.add_argument("-f", "--force", action="store_true", default=False, help="overwrite existing destinations") p_extract.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_extract.add_argument("image", help="image syntax is ") p_extract.add_argument("path", help="image will be extracted in path") p_extract.set_defaults(func=c_extract) # get command parser p_get = subparsers.add_parser("get", help=c_get.__doc__.lower()) p_get.add_argument("-p", action="store_true", dest="payload", default=False, help="get payloads") p_get.add_argument("-f", "--force", action="store_true", default=False, help="overwrite existing destinations") p_get.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_get.add_argument("image", nargs="+", help="image syntax is ") 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 to initialize") p_init.set_defaults(func=c_init) # install command parser p_install = subparsers.add_parser("install", add_help=False, help=c_install.__doc__.lower()) p_install.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_install.add_argument("image", help="image syntax is ") 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("-v", action="store_true", dest="verbose", default=False, help="verbose output") p_list.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_list.add_argument("-c", "--changelog", action="store_true", default=False, help="display image changelog") p_list.add_argument("object", nargs="*", help="object syntax is ") p_list.set_defaults(func=c_list, subparser=p_list) # move command parser p_move = subparsers.add_parser("move", help=c_move.__doc__.lower()) p_move.add_argument("-f", "--force", action="store_true", default=False, help="move image without confirmation") p_move.add_argument("-b", "--best", action="store_true", default=False, help="in best mode, image is the most recent in all repositories") p_move.add_argument("image", nargs="+", help="image syntax is ") p_move.add_argument("repository", help="destination repository") 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("-f", "--force", action="store_true", default=False, help="overwrite existing source image") p_new.add_argument("path", help="new image directory path") 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="pattern to search in repositories") p_search.set_defaults(func=c_search) # version command parser p_version = subparsers.add_parser("version", help=c_version.__doc__.lower()) p_version.set_defaults(func=c_version) 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") config.merge(args) # set debug and quiet mode after merge installsystems.debug = args.debug installsystems.quiet = args.quiet # no warning if we are not in debug mode if not installsystems.debug: warnings.filterwarnings("ignore") # except for install command we parse all args! if args.func is not c_install: args = p_main.parse_args(namespace=args) # let's go args.func(p_main, args) except Exception as e: error(e) except KeyboardInterrupt: warn("Keyboard Interrupted")