Newer
Older
# -*- coding: utf-8 -*-
# Started 30/06/2011 by Seblu <seblu@seblu.net>
'''
InstallSystems Command line Tool
'''
import os
import time
import datetime
import warnings
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
################################################################################
# Common functions
################################################################################
Load repositories on a repository manager
'''
# remove cache is asked
if hasattr(args, "no_cache") and args.no_cache:
# split filter in list
if args.repo_filter is not None:
args.repo_filter = [f for f in re.split("[ ,\n\t\v]+", args.repo_filter)
if f != ""]
repoman = RepositoryManager(args.cache, timeout=args.timeout, filter=args.repo_filter)
# register repositories (order matter)
if args.repo_path is not None:
repoman.register(RepositoryConfig(istools.smd5sum(args.repo_path)[:8],
path=args.repo_path), temp=True,
nosync=hasattr(args, "no_sync") and args.no_sync,
offline=hasattr(args, "force_offline") and args.force_offline)
Seblu
committed
for repoconf in RepoConfigFile(args.repo_config).repos:
repoman.register(repoconf,
nosync=hasattr(args, "no_sync") and args.no_sync,
offline=hasattr(args, "force_offline") and args.force_offline)
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
# we need to find image in a repository
if len(repoman.onlines) == 0:
raise Exception('No online repository')
(repo, image, version) = istools.split_image_path(name)
debug("Requested image: %s v%s in %s" % (image, version, repo))
# repo is not specified, we need to crawl in path
# split search path as a list
if args.repo_search is not None:
args.repo_search = [s for s in re.split("[ ,\n\t\v]+", args.repo_search)
if s in repoman.onlines]
else:
args.repo_search = []
# if we have only one repo, search in it
if len(args.repo_search) == 0 and len(repoman.onlines) == 1:
args.repo_search = repoman.onlines
elif len(args.repo_search) == 0 and len(repoman.onlines) > 1:
raise Exception('You must use a full image path or set a valid search path')
return repoman.get(image, version, search=args.repo_search, best=best)
# we can ask directly repository about image
else:
return repoman[repo].get(image, version), repoman[repo]
################################################################################
# Commands functions
################################################################################
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)
Build an image source in current directory
# build start time
t0 = time.time()
# load source image
simg = SourceImage(args.path)
# do the job
simg.build(force=args.force, force_payload=args.payload, check=not args.no_check)
# compute building time
t1 = time.time()
dt = int(t1 - t0)
arrow("Build time: %s" % datetime.timedelta(seconds=dt))
# looks if arguments is a file or image name
img, repo = select_image(args.image, repoman, args.best)
def c_changelog(parser, args):
'''
Display image's changelog
'''
# looks if arguments is a file or image name
repoman = load_repositories(args)
img, repo = select_image(args.image, repoman, args.best)
img.changelog.show(int(img.version), args.all_version)
'''
repoman = load_repositories(args)
for reponame in args.repository:
repoman[reponame].check()
def c_chroot(parser, args):
'''
Helper to go cleanly inside a chroot
'''
istools.chroot(args.path, shell=args.shell, mount=not args.no_mount)
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
'''
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)
'''
Remove an image package from a repository
'''
img, repo = select_image(image, repoman, args.best)
if repo is None:
raise Exception("You cannot delete an image outside a repository")
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, payloads=not args.preserve)
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,
img, repo = select_image(image, repoman, args.best)
img.download(".", image=not args.no_image, 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_info(parser, args):
'''
Get info about an image
'''
repoman = load_repositories(args)
for image in args.image:
img, repo = select_image(image, repoman, args.best)
img.show(verbose=args.verbose, changelog=args.changelog)
def c_init(parser, args):
'''
Create an empty repository
'''
repoman = load_repositories(args)
for reponame in args.repository:
repoman[reponame].init()
# remove old image args
args.parser._remove_action([d for d in args.parser._actions if d.dest == "image"][0])
# create a subparser for current image to have a sexy display of args
#args.image = "roger"
subparser = args.parser.add_subparsers().add_parser(args.image)
# select image to install
repoman = load_repositories(args)
img = select_image(args.image, repoman, args.best)[0]
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=subparser)
# call parser again, with extended attributes
arrow("Parsing arguments")
#parser.print_help()
args = parser.parse_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
'''
repoman.show_images(pattern, all_version=args.all_version, o_long=args.long, o_json=args.json,
o_md5=args.md5, o_date=args.date, o_author=args.author,
o_size=args.size, o_url=args.url, o_description=args.description)
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)
SourceImage.create(args.path, args.force)
def c_prepare_chroot(parser, args):
'''
Prepare a chroot
'''
istools.prepare_chroot(args.path, mount=not args.no_mount)
def c_repo(parser, args):
'''
Get information about repositories
'''
repoman = load_repositories(args)
repoman.show_repos(pattern, online=args.online, local=args.local,
url=args.url, state=args.state)
def c_search(parser, args):
'''
Search in repository
'''
repoman = load_repositories(args)
repoman.search(args.pattern)
def c_unprepare_chroot(parser, args):
'''
Remove preparation of a chroot
'''
istools.unprepare_chroot(args.path, mount=not args.no_umount)
def c_version(parser, args):
'''
Print installsystems version
'''
out(installsystems.version)
################################################################################
# Parser definition
################################################################################
# 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", default=None,
ex_group.add_argument("-q", "--quiet", action="store_true", default=None,
help="active quiet mode")
# common options
p_main.add_argument("-c", "--config", default="installsystems", metavar="PATH",
p_main.add_argument("-R", "--repo-config", default="repository", metavar="REPO",
help="repository config file path")
p_main.add_argument("-s", "--repo-search", metavar="REPO,REPO,...",
help="search for images inside those repositories")
p_main.add_argument("-f", "--repo-filter", metavar="REPO,REPO,...",
help="filter repositories by name")
p_main.add_argument("-r", "--repo-path", metavar="PATH",
help="define a temporary repository")
p_main.add_argument("-C", "--cache", metavar="PATH",
help="path of the repository cache")
p_main.add_argument("--no-cache", action="store_true", default=None,
p_main.add_argument("--no-color", action="store_true", default=None,
help="dot not display colored output")
p_main.add_argument("-t", "--timeout", dest="timeout", type=int, default=None,
metavar="SECONDS", 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")
# build command parser
p_build = subparsers.add_parser("build", help=c_build.__doc__.lower())
p_build.add_argument("-c", "--no-check", action="store_true", default=False,
help="do not check compilation before adding scripts")
p_build.add_argument("-f", "--force", action="store_true", default=False,
help="rebuild image if already exists")
p_build.add_argument("-p", "--payload", action="store_true", default=False,
help="rebuild payloads if already exists")
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="take the most recent image in all searchable repositories")
p_cat.add_argument("image", help="<path|[repository/]image[:version]>")
p_cat.add_argument("file", nargs="+",
help="file inside image to cat (globbing allowed)")
# changelog command parser
p_changelog = subparsers.add_parser("changelog", help=c_changelog.__doc__.lower())
p_changelog.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_changelog.add_argument("-v", "--all-version", action="store_true", default=False,
help="display changelog for all versions")
p_changelog.add_argument("image", help="<path|[repository/]image[:version]>")
p_changelog.set_defaults(func=c_changelog)
# 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)
# chroot command parser
p_chroot = subparsers.add_parser("chroot", help=c_chroot.__doc__.lower())
p_chroot.add_argument("-m", "--no-mount", action="store_true", default=False,
help="disable mouting of /{proc,dev,sys} inside chroot")
p_chroot.add_argument("-s", "--shell", default="/bin/bash",
help="shell to call inside chroot")
p_chroot.add_argument("path")
p_chroot.set_defaults(func=c_chroot)
# 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="take the most recent image in all searchable repositories")
p_copy.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p_copy.add_argument("repository", help="destination repository")
# del command parser
p_del = subparsers.add_parser("del", help=c_del.__doc__.lower())
help="image syntax is <path|[repository/]image[:version]>")
p_del.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_del.add_argument("-f", "--force", action="store_true", default=False,
help="delete image without confirmation")
p_del.add_argument("-p", "--preserve", action="store_true", default=False,
help="preserve payloads. doesn't remove it from repository")
# 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 <path|repository|[repository/]image[:version]>")
p_diff.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
# extract command parser
p_extract = subparsers.add_parser("extract", help=c_extract.__doc__.lower())
p_extract.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_extract.add_argument("-f", "--force", action="store_true", default=False,
help="overwrite existing destinations")
p_extract.add_argument("-g", "--gen-description", action="store_true", default=False,
help="generate a description file from metadata")
p_extract.add_argument("-p", "--payload", action="store_true", default=False,
help="extract payloads")
p_extract.add_argument("image",
help="image syntax is <path|[repository/]image[:version]>")
p_extract.add_argument("path", help="image will be extracted in path")
# get command parser
p_get = subparsers.add_parser("get", help=c_get.__doc__.lower())
p_get.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_get.add_argument("-f", "--force", action="store_true", default=False,
help="overwrite existing destinations")
p_get.add_argument("-I", "--no-image", action="store_true", default=False,
help="do not get image")
p_get.add_argument("-p", "--payload", action="store_true", default=False,
help="get payloads")
p_get.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
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)
# info command parser
p_info = subparsers.add_parser("info", help=c_info.__doc__.lower())
p_info.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_info.add_argument("-c", "--changelog", action="store_true", default=False,
help="display image changelog")
p_info.add_argument("-v", "--verbose", action="store_true", default=False,
help="verbose output")
p_info.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p_info.set_defaults(func=c_info)
# init command parser
p_init = subparsers.add_parser("init", help=c_init.__doc__.lower())
p_init.add_argument("repository", nargs="+",
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="take the most recent image in all searchable repositories")
p_install.add_argument("image",
help="image syntax is <path|[repository/]image[:version]>")
p_install.set_defaults(func=c_install, parser=p_install)
# list command parser
p_list = subparsers.add_parser("list", help=c_list.__doc__.lower())
p_list.add_argument("-a", "--all-version", action="store_true", default=False,
help="list all versions of the same image")
p_list.add_argument("-A", "--author", action="store_true", default=False,
help="display image author")
p_list.add_argument("-d", "--date", action="store_true", default=False,
help="display image date")
p_list.add_argument("-D", "--description", action="store_true", default=False,
help="display image description")
p_list.add_argument("-j", "--json", action="store_true", default=False,
help="long display")
p_list.add_argument("-l", "--long", action="store_true", default=False,
help="long display")
p_list.add_argument("-m", "--md5", action="store_true", default=False,
help="display image md5")
p_list.add_argument("--no-sync", action="store_true", default=False,
help="doesn't sync repository before listing")
p_list.add_argument("-s", "--size", action="store_true", default=False,
help="display image size")
p_list.add_argument("-u", "--url", action="store_true", default=False,
help="display image url")
p_list.add_argument("image", nargs="*", default=['*'],
help="image syntax is [repository/]image[:version]")
p_list.set_defaults(func=c_list)
# move command parser
p_move = subparsers.add_parser("move", help=c_move.__doc__.lower())
p_move.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p_move.add_argument("-f", "--force", action="store_true", default=False,
help="move image without confirmation")
p_move.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p_move.add_argument("repository", help="destination repository")
# 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")
# prepare_chroot command parser
p_prepare_chroot = subparsers.add_parser("prepare_chroot", help=c_prepare_chroot.__doc__.lower())
p_prepare_chroot.add_argument("-m", "--no-mount", action="store_true", default=False,
help="disable mouting of /{proc,dev,sys}")
p_prepare_chroot.add_argument("path")
p_prepare_chroot.set_defaults(func=c_prepare_chroot)
# repo command parser
p_repo = subparsers.add_parser("repo", help=c_repo.__doc__.lower())
p_repo.add_argument("--force-offline", action="store_true", default=False,
help="force repository to be offline")
p_repo_mgroup = p_repo.add_mutually_exclusive_group()
p_repo_mgroup.add_argument("-l", "--local", action="store_true", default=None,
help="list local repository (filter)")
p_repo_mgroup.add_argument("-r", "--remote", action="store_false", dest="local",
help="list remote repository (filter)")
p_repo_mgroup = p_repo.add_mutually_exclusive_group()
p_repo_mgroup.add_argument("-o", "--online", action="store_true", default=None,
help="list online repository (filter)")
p_repo_mgroup.add_argument("-O", "--offline", action="store_false", dest="online",
help="list offline repository (filter)")
p_repo.add_argument("-s", "--state", action="store_true", default=False,
help="display repository state (online/offline/local/remote)")
p_repo.add_argument("-u", "--url", action="store_true", default=False,
help="display repository url")
p_repo.add_argument("repository", nargs='*', default=["*"], help="repository pattern")
p_repo.set_defaults(func=c_repo)
# 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")
# unprepare_chroot command parser
p_unprepare_chroot = subparsers.add_parser("unprepare_chroot", help=c_unprepare_chroot.__doc__.lower())
p_unprepare_chroot.add_argument("-m", "--no-umount", action="store_true", default=False,
help="disable unmouting of /{proc,dev,sys}")
p_unprepare_chroot.add_argument("path")
p_unprepare_chroot.set_defaults(func=c_unprepare_chroot)
# version command parser
p_version = subparsers.add_parser("version", help=c_version.__doc__.lower())
p_version.set_defaults(func=c_version)
################################################################################
# Main
################################################################################
# first (partial) parsing
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")
# disable coloring if asked
if args.no_color:
installsystems.printer.NOCOLOR = True
# except for install command we parse all args!
# install command is responsible of parsing
if args.func is not c_install:
args = p_main.parse_args(namespace=args)
# let's go
except Exception as e:
error(e)
except KeyboardInterrupt:
warn("Keyboard Interrupted")