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 = split_repositories(args.repo_filter)
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 split_repositories(repos, filter=None):
'''
Return a list of repository from an comma/space separated list of repo
'''
if filter is None:
filter = lambda x: x != ""
return [r for r in re.split("[ ,\n\t\v]+", repos) if filter(r)]
def show_repositories(repoman, pattern, local=None, online=None,
url=False, state=True):
'''
Show repository inside manager
if :param online: is true, list only online repositories
if :param online: is false, list only offline repostiories
if :param online: is None, list both online and offline repostiories.
if :param local: is true, list only local repositories
if :param local: is false, list only remote repostiories
if :param local: is None, list both local and remote repostiories.
'''
for reponame in fnmatch.filter(repoman.names, pattern):
repo = repoman[reponame]
if repo.config.offline and online is True:
continue
if not repo.config.offline and online is False:
continue
if repo.local and local is False:
continue
if not repo.local and local is True:
continue
so = "#l##r#Off#R# " if repo.config.offline else "#l##g#On#R# "
sl = "#l##y#Local#R# " if repo.local else "#l##c#Remote#R# "
rc = "#l##r#" if repo.config.offline else "#l##g#"
s = ""
if state:
s += "%s%s " % (so, sl)
rc = "#l##b#"
s += "%s%s#R#"% (rc, repo.config.name)
if url:
s += " (%s)" % repo.config.path
out(s)
def select_image(name, repoman, search=None, 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 search is not None:
search = split_repositories(search,
lambda x: x in repoman.onlines)
# if we have only one repo, search in it
if len(search) == 0 and len(repoman.onlines) == 1:
search = repoman.onlines
elif len(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=search, best=best)
# we can ask directly repository about image
else:
return repoman[repo].get(image, version), repoman[repo]
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
def show_images(repoman, pattern, all_version=True, search=None,
o_json=False, o_long=False,
o_md5=False, o_date=False, o_author=False, o_size=False,
o_url=False, o_description=False):
'''
Show repository inside manager
json: display output in json
long: display output in long format
all images parameter can be given in arguments to displayed
'''
# get image list
images = repoman.images(pattern, all_version, search)
# display result
if o_json:
s = json.dumps(images)
else:
l = []
for imgp in sorted(images.keys()):
img = images[imgp]
l.append(u"%s#R#/#l##b#%s#R#:#p#%s#R#" % (
img["repo"], img["name"], img["version"]))
if o_md5 or o_long:
l[-1] = l[-1] + u" (#y#%s#R#)" % img["md5"]
if o_date or o_long:
l.append(u" #l#date:#R# %s" % istools.time_rfc2822(img["date"]))
if o_author or o_long:
l.append(u" #l#author:#R# %s" % img["author"])
if o_size or o_long:
l.append(u" #l#size:#R# %s" % istools.human_size(img["size"]))
if o_url or o_long:
l.append(u" #l#url:#R# %s" % img["url"])
if o_description or o_long:
l.append(u" #l#description:#R# %s" % img["description"])
s = os.linesep.join(l)
if len(s) > 0:
out(s)
################################################################################
# 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,
search=args.repo_search, best=args.best)
'''
Display image's changelog
'''
# looks if arguments is a file or image name
repoman = load_repositories(args)
img, repo = select_image(args.image, repoman,
search=args.repo_search, best=args.best)
img.changelog.show(int(img.version), args.all_version)
'''
repoman = load_repositories(args)
for reponame in args.repository:
repoman[reponame].check()
'''
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()
'''
Copy an image from a repository to another one
'''
dstrepo = repoman[args.repository]
for image in args.image:
srcimg, srcrepo = select_image(image, repoman,
search=args.repo_search, best=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,
search=args.repo_search, best=args.best)
if repo is None:
raise Exception("You cannot delete an image outside a repository")
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)
'''
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,
search=args.repo_search, best=args.best)
img2, repo2 = select_image(args.object[1], repoman,
search=args.repo_search, best=args.best)
'''
Extract an image package inside a directory
'''
repoman = load_repositories(args)
img, repo = select_image(args.image, repoman,
search=args.repo_search, best=args.best)
img.extract(args.path, payload=args.payload, force=args.force,
img, repo = select_image(image, repoman,
search=args.repo_search, best=args.best)
img.download(".", image=not args.no_image, payload=args.payload, force=args.force)
'''
Show help
'''
if args.command not in args.subparser.choices:
else:
args.subparser.choices[args.command].print_help()
'''
Get info about an image
'''
repoman = load_repositories(args)
for image in args.image:
img, repo = select_image(image, repoman,
search=args.repo_search, best=args.best)
img.show(verbose=args.verbose, changelog=args.changelog)
'''
Create an empty repository
'''
repoman = load_repositories(args)
for reponame in args.repository:
repoman[reponame].init()
# remove old image args
args.install_parser._remove_action(
[d for d in args.install_parser._actions if d.dest == "image"][0])
# create a subparser for current image to have a sexy display of args
subparser = args.install_parser.add_subparsers().add_parser(args.image)
# select image to install
repoman = load_repositories(args)
img = select_image(args.image, repoman,
search=args.repo_search, best=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")
args = args.parser.parse_args()
# compute building time
t1 = time.time()
dt = int(t1 - t0)
arrow("Install time: %s" % datetime.timedelta(seconds=dt))
'''
List images in repository or image content
'''
if args.search is not None:
args.search = split_repositories(args.repo_search, lambda x: x in repoman.onlines)
show_images(repoman, pattern,
all_version=args.all_version, search=args.search,
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)
'''
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,
search=args.repo_search, best=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)
'''
Prepare a chroot
'''
istools.prepare_chroot(args.path, mount=not args.no_mount)
'''
Get information about repositories
'''
# in cleaning mode we doesn't needs to get repositories
if args.purge:
args.force_offline = True
repoman = load_repositories(args)
if args.purge:
repoman.purge_cache(pattern)
else:
show_repositories(repoman, pattern,
online=args.online, local=args.local,
url=args.url, state=args.state)
'''
Search in repository
'''
repoman = load_repositories(args)
repoman.search(args.pattern)
def c_unprepare_chroot(args):
'''
Remove preparation of a chroot
'''
istools.unprepare_chroot(args.path, mount=not args.no_umount)
'''
Print installsystems version
'''
out(installsystems.version)
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
def parser_init():
'''
Create command parser
'''
# Top level argument parsing
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", action="version",
version=installsystems.version,
help="show installsystems version")
# exclusive group on debug/quiet
g = parser.add_mutually_exclusive_group()
g.add_argument("-d", "--debug", action="store_true", default=None,
help="active debug mode")
g.add_argument("-q", "--quiet", action="store_true", default=None,
help="active quiet mode")
# common options
parser.add_argument("-c", "--config", default="installsystems", metavar="PATH",
help="config file path")
parser.add_argument("-R", "--repo-config", default="repository", metavar="REPO",
help="repository config file path")
parser.add_argument("-s", "--repo-search", metavar="REPO,REPO,...",
help="search for images inside those repositories")
parser.add_argument("-f", "--repo-filter", metavar="REPO,REPO,...",
help="filter repositories by name")
parser.add_argument("-r", "--repo-path", metavar="PATH",
help="define a temporary repository")
parser.add_argument("-C", "--cache", metavar="PATH",
help="path of repositories cache")
parser.add_argument("-t", "--timeout", dest="timeout", type=int, default=None,
metavar="SECONDS", help="download timeout (default 3)")
parser.add_argument("--no-cache", action="store_true", default=None,
help="not use persistent db caching")
parser.add_argument("--no-color", action="store_true", default=None,
help="dot not display colored output")
# create a subparser for commands
subparser = parser.add_subparsers()
# add command parser
p = subparser.add_parser("add", help=c_add.__doc__.lower())
p.add_argument("-p", "--preserve", action="store_true", default=False,
help="don't remove image after adding to database")
p.add_argument("repository", help="repository where images will be added")
p.add_argument("path", nargs="+", help="image path")
p.set_defaults(func=c_add)
# build command parser
p = subparser.add_parser("build", help=c_build.__doc__.lower())
p.add_argument("-c", "--no-check", action="store_true", default=False,
help="do not check compilation before adding scripts")
p.add_argument("-f", "--force", action="store_true", default=False,
help="rebuild image if already exists")
p.add_argument("-p", "--payload", action="store_true", default=False,
help="rebuild payloads if already exists")
p.add_argument("path", nargs="?", default=".")
p.set_defaults(func=c_build)
# cat command parser
p = subparser.add_parser("cat", help=c_cat.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("image", help="<path|[repository/]image[:version]>")
p.add_argument("file", nargs="+",
help="file inside image to cat (globbing allowed)")
p.set_defaults(func=c_cat)
# changelog command parser
p = subparser.add_parser("changelog", help=c_changelog.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
p.add_argument("-v", "--all-version", action="store_true", default=False,
help="display changelog for all versions")
p.add_argument("image", help="<path|[repository/]image[:version]>")
p.set_defaults(func=c_changelog)
# check command parser
p = subparser.add_parser("check", help=c_check.__doc__.lower())
p.add_argument("repository", nargs="+", help="repositories to check")
p.set_defaults(func=c_check)
# chroot command parser
p = subparser.add_parser("chroot", help=c_chroot.__doc__.lower())
p.add_argument("-m", "--no-mount", action="store_true", default=False,
help="disable mouting of /{proc,dev,sys} inside chroot")
p.add_argument("-s", "--shell", default="/bin/bash",
help="shell to call inside chroot")
p.add_argument("path")
p.set_defaults(func=c_chroot)
# clean command parser
p = subparser.add_parser("clean", help=c_clean.__doc__.lower())
p.add_argument("repository", nargs="+", help="repositories to clean")
p.set_defaults(func=c_clean)
# copy command parser
p = subparser.add_parser("copy", help=c_copy.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p.add_argument("repository", help="destination repository")
p.set_defaults(func=c_copy)
# del command parser
p = subparser.add_parser("del", help=c_del.__doc__.lower())
p.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("-f", "--force", action="store_true", default=False,
help="delete image without confirmation")
p.add_argument("-p", "--preserve", action="store_true", default=False,
help="preserve payloads. doesn't remove it from repository")
p.set_defaults(func=c_del)
# diff command parser
p = subparser.add_parser("diff", help=c_diff.__doc__.lower())
p.add_argument("object", nargs=2,
help="object syntax is <path|repository|[repository/]image[:version]>")
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.set_defaults(func=c_diff)
# extract command parser
p = subparser.add_parser("extract", help=c_extract.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("-f", "--force", action="store_true", default=False,
help="overwrite existing destinations")
p.add_argument("-g", "--gen-description", action="store_true", default=False,
help="generate a description file from metadata")
p.add_argument("-p", "--payload", action="store_true", default=False,
help="extract payloads")
p.add_argument("image",
help="image syntax is <path|[repository/]image[:version]>")
p.add_argument("path", help="image will be extracted in path")
p.set_defaults(func=c_extract)
# get command parser
p = subparser.add_parser("get", help=c_get.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("-f", "--force", action="store_true", default=False,
help="overwrite existing destinations")
p.add_argument("-I", "--no-image", action="store_true", default=False,
p.add_argument("-p", "--payload", action="store_true", default=False,
p.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
p.set_defaults(func=c_get)
# help command parser
p = subparser.add_parser("help", help=c_help.__doc__.lower())
p.add_argument("command", nargs="?", help="command name")
p.set_defaults(func=c_help, parser=parser, subparser=subparser)
# info command parser
p = subparser.add_parser("info", help=c_info.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("-c", "--changelog", action="store_true", default=False,
help="display image changelog")
p.add_argument("-v", "--verbose", action="store_true", default=False,
help="verbose output")
p.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p.set_defaults(func=c_info)
# init command parser
p = subparser.add_parser("init", help=c_init.__doc__.lower())
p.add_argument("repository", nargs="+",
help="repository to initialize")
p.set_defaults(func=c_init)
# install command parser
p = subparser.add_parser("install", add_help=False,
help=c_install.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("image",
help="image syntax is <path|[repository/]image[:version]>")
p.set_defaults(func=c_install, parser=parser, install_parser=p)
# list command parser
p = subparser.add_parser("list", help=c_list.__doc__.lower())
p.add_argument("-a", "--all-version", action="store_true", default=False,
help="list all versions of the same image")
p.add_argument("-A", "--author", action="store_true", default=False,
help="display image author")
p.add_argument("-d", "--date", action="store_true", default=False,
help="display image date")
p.add_argument("-D", "--description", action="store_true", default=False,
help="display image description")
p.add_argument("-j", "--json", action="store_true", default=False,
help="output is formated in json")
p.add_argument("-l", "--long", action="store_true", default=False,
help="long display")
p.add_argument("-m", "--md5", action="store_true", default=False,
help="display image md5")
p.add_argument("-s", "--size", action="store_true", default=False,
help="display image size")
p.add_argument("-u", "--url", action="store_true", default=False,
help="display image url")
p.add_argument("-S", "--search", action="store_true", default=None,
help="only list image in search path")
p.add_argument("--no-sync", action="store_true", default=False,
help="doesn't sync repository before listing")
p.add_argument("image", nargs="*", default=['*'],
help="image syntax is [repository/]image[:version]")
p.set_defaults(func=c_list)
# move command parser
p = subparser.add_parser("move", help=c_move.__doc__.lower())
p.add_argument("-b", "--best", action="store_true", default=False,
help="take the most recent image in all searchable repositories")
p.add_argument("-f", "--force", action="store_true", default=False,
help="move image without confirmation")
p.add_argument("image", nargs="+",
help="image syntax is <path|[repository/]image[:version]>")
p.add_argument("repository", help="destination repository")
p.set_defaults(func=c_move)
# new command parser
p = subparser.add_parser("new", help=c_new.__doc__.lower())
p.add_argument("-f", "--force", action="store_true", default=False,
help="overwrite existing source image")
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
p.add_argument("path", help="new image directory path")
p.set_defaults(func=c_new)
# prepare_chroot command parser
p = subparser.add_parser("prepare_chroot",
help=c_prepare_chroot.__doc__.lower())
p.add_argument("-m", "--no-mount", action="store_true", default=False,
help="disable mouting of /{proc,dev,sys}")
p.add_argument("path")
p.set_defaults(func=c_prepare_chroot)
# repo command parser
p = subparser.add_parser("repo", help=c_repo.__doc__.lower())
g = p.add_mutually_exclusive_group()
g.add_argument("-l", "--local", action="store_true", default=None,
help="list local repository (filter)")
g.add_argument("-r", "--remote", action="store_false", dest="local",
help="list remote repository (filter)")
g = p.add_mutually_exclusive_group()
g.add_argument("-o", "--online", action="store_true", default=None,
help="list online repository (filter)")
g.add_argument("-O", "--offline", action="store_false", dest="online",
help="list offline repository (filter)")
p.add_argument("-s", "--state", action="store_true", default=False,
help="display repository state (online/offline/local/remote)")
p.add_argument("-u", "--url", action="store_true", default=False,
help="display repository url")
p.add_argument("--purge", action="store_true", default=False,
help="remove cache databases")
p.add_argument("--force-offline", action="store_true", default=False,
help="force repository to be offline")
p.add_argument("repository", nargs='*', default=["*"], help="repository pattern")
p.set_defaults(func=c_repo)
# search command parser
p = subparser.add_parser("search", help=c_search.__doc__.lower())
p.add_argument("pattern", help="pattern to search in repositories")
p.set_defaults(func=c_search)
# unprepare_chroot command parser
p = subparser.add_parser("unprepare_chroot",
help=c_unprepare_chroot.__doc__.lower())
p.add_argument("-m", "--no-umount", action="store_true", default=False,
help="disable unmouting of /{proc,dev,sys}")
p.add_argument("path")
p.set_defaults(func=c_unprepare_chroot)
# version command parser
p = subparser.add_parser("version", help=c_version.__doc__.lower())
p.set_defaults(func=c_version)
# return main parser
return parser
def main():
'''
Program main
'''
try:
parser = parser_init()
# first (partial) parsing
args = parser.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 = parser.parse_args(namespace=args)
# let's go
args.func(args)
exit(0)
except Exception as e:
error(e)
except KeyboardInterrupt:
warn("Keyboard Interrupted")
exit(1)
# Entry point
if __name__ == '__main__':
main()