From 1e0c53e55242ca83890845fa7c454b0e0c55b453 Mon Sep 17 00:00:00 2001 From: Sebastien Luttringer <sebastien.luttringer@smartjog.com> Date: Tue, 13 Dec 2011 14:02:27 +0100 Subject: [PATCH] Image are not searched in search path Image are not crawled anymore in all repositories by default You needs to specify a list of repo to look in --- bin/is | 82 ++++++++++++++++++++++++++---------- installsystems/config.py | 17 ++++++-- installsystems/repository.py | 37 ++++++++-------- installsystems/tools.py | 10 +++++ samples/installsystems.conf | 7 ++- 5 files changed, 107 insertions(+), 46 deletions(-) diff --git a/bin/is b/bin/is index 05b4e90..b550598 100755 --- a/bin/is +++ b/bin/is @@ -24,6 +24,10 @@ from installsystems.repository import RepositoryConfig from installsystems.image import PackageImage, SourceImage from installsystems.config import MainConfigFile, RepoConfigFile +################################################################################ +# Common functions +################################################################################ + def load_repositories(args): ''' Load repositories on a repository manager @@ -31,6 +35,10 @@ def load_repositories(args): # remove cache is asked if hasattr(args, "no_cache") and args.no_cache: args.cache = None + # 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 != ""] # init repo cache object repoman = RepositoryManager(args.cache, timeout=args.timeout, filter=args.repo_filter) # register repositories (order matter) @@ -56,19 +64,37 @@ def select_image(name, repoman, best=False): Return the repository as second argument ''' + # image is a local file if istools.isfile(name) and os.path.isfile(name): return PackageImage(name), None + # we need to find image in a repository 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 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 if repo is None: - return repoman.get(image, version, best) + # 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 +################################################################################ + def c_add(parser, args): ''' Add an image package into a repository @@ -328,6 +354,10 @@ def c_version(parser, args): ''' out(installsystems.version) +################################################################################ +# Parser definition +################################################################################ + # Top level argument parsing p_main = argparse.ArgumentParser() p_main.add_argument("-V", "--version", action="version", @@ -340,22 +370,24 @@ 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", +p_main.add_argument("-c", "--config", default="installsystems", metavar="PATH", help="config file path") -p_main.add_argument("-R", "--repo-config", default="repository", +p_main.add_argument("-R", "--repo-config", default="repository", metavar="REPO", 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, +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, help="not use persistent db caching") 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, - help="download timeout (default 3)") + metavar="SECONDS", help="download timeout (default 3)") # create a subparsers for each command subparsers = p_main.add_subparsers() @@ -382,7 +414,7 @@ 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") + 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)") @@ -391,7 +423,7 @@ p_cat.set_defaults(func=c_cat) # 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="in best mode, image is the most recent in all repositories") + 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]>") @@ -419,7 +451,7 @@ 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") + 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") @@ -430,7 +462,7 @@ p_del = subparsers.add_parser("del", help=c_del.__doc__.lower()) p_del.add_argument("image", nargs="+", help="image syntax is <path|[repository/]image[:version]>") p_del.add_argument("-b", "--best", action="store_true", default=False, - help="in best mode, image is the most recent in all repositories") + 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, @@ -442,13 +474,13 @@ 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="in best mode, image is the most recent in all repositories") + help="take the most recent image in all searchable 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("-b", "--best", action="store_true", default=False, - help="in best mode, image is the most recent in all repositories") + 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, @@ -463,7 +495,7 @@ 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("-b", "--best", action="store_true", default=False, - help="in best mode, image is the most recent in all repositories") + 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, @@ -482,7 +514,7 @@ 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="in best mode, image is the most recent in all repositories") + 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, @@ -535,7 +567,7 @@ 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="in best mode, image is the most recent in all repositories") + 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="+", @@ -594,6 +626,10 @@ p_unprepare_chroot.set_defaults(func=c_unprepare_chroot) p_version = subparsers.add_parser("version", help=c_version.__doc__.lower()) p_version.set_defaults(func=c_version) +################################################################################ +# Main +################################################################################ + try: # first (partial) parsing args = p_main.parse_known_args()[0] diff --git a/installsystems/config.py b/installsystems/config.py index 78fd510..7fef69d 100644 --- a/installsystems/config.py +++ b/installsystems/config.py @@ -51,6 +51,8 @@ class MainConfigFile(ConfigFile): Program configuration file ''' + valid_options = ("debug", "quiet", "no_cache", "no_color", "timeout", "cache", "repo_search", "repo_filter", "repo_config") + def __init__(self, filename, prefix=os.path.basename(sys.argv[0])): self.prefix = prefix ConfigFile.__init__(self, filename) @@ -81,8 +83,14 @@ class MainConfigFile(ConfigFile): Merge current loaded option with a namespace from argparse ''' for option, value in self._config.items(): + # check option is valid + if option not in self.valid_options: + warn("Invalid option %s in %s, skipped" % (option, self.path)) + continue + # no option is specified in command line, set it if not hasattr(namespace, option): setattr(namespace, option, value) + # handle by default none options elif getattr(namespace, option) == None: # we need to handle boolean differently if option in ("debug", "quiet", "no_cache", "no_color"): @@ -94,11 +102,12 @@ class MainConfigFile(ConfigFile): except ValueError: raise Exception("Invalid %s: Not a number" % option) setattr(namespace, option, n) - # we can handle string more carefuly - elif option in ("cache", "repo_filter", "repo_config"): + # handle strings + elif option in ("cache", "repo_search", "repo_filter"): setattr(namespace, option, value) - else: - warn("Invalid option %s in %s, skipped" % (option, self.path)) + # repo_config is a special parameter, default value is repository + elif option == "repo_config" and option.repo_config == "repository": + setattr(namespace, option, value) def _cache_paths(self): ''' diff --git a/installsystems/repository.py b/installsystems/repository.py index ede1ac9..8128c0f 100644 --- a/installsystems/repository.py +++ b/installsystems/repository.py @@ -391,7 +391,8 @@ class Repository(object): r = self.db.ask("select md5 from image where name = ? and version = ? limit 1", (name, version)).fetchone() if r is None: - raise Exception("Unable to find image %s v%s" % (name, version)) + raise Exception("Unable to find image %s v%s in %s" % (name, version, + self.config.name)) path = os.path.join(self.config.path, r[0]) # getting the file arrow("Loading image %s v%s from repository %s" % (name, @@ -436,7 +437,7 @@ class RepositoryManager(object): self.timeout = 3 if timeout is None else timeout self.repos = [] self.tempfiles = [] - self.filter = filter + self.filter = [] if filter is None else filter if cache_path is None: self.cache_path = None debug("No repository cache") @@ -500,8 +501,9 @@ class RepositoryManager(object): offline: repository is marked offline ''' # check filter on name - if self.filter is not None: - if not fnmatch.fnmatch(config.name, self.filter): + if len(self.filter) > 0: + if config.name not in self.filter: + debug("Filtering repository %s" % config.name) return # repository is offline if config.offline or offline: @@ -622,19 +624,20 @@ class RepositoryManager(object): del images["%s/%s:%s" % (repo, img, rmv)] return images - def get(self, name, version=None, best=False): + def get(self, name, version=None, search=None, best=False): ''' - Crawl repositories to get an image + Crawl searchable repositories to get an image best mode search the most recent version accross all repo else it search the first match ''' + if search is None: + search = [] # search last version if needed if version is None: version = -1 - for repo in self.repos: - if repo.config.offline: continue - current = repo.last(name) + for repo in search: + current = self[repo].last(name) # if not best mode, we found our version if not best and current > 0: version = current @@ -642,13 +645,14 @@ class RepositoryManager(object): version = max(version, current) # if version < 0, il n'y a pas d'image if version < 0: - raise Exception("Unable to find image %s" % name) + raise Exception("Unable to find image %s in %s" % ( + name, search)) # search image in repos - for repo in self.repos: - if repo.config.offline: continue - if repo.has(name, version): - return repo.get(name, version), repo - raise Exception("Unable to find image %s v%s" % (name, version)) + for repo in search: + if self[repo].has(name, version): + return self[repo].get(name, version), repo + raise Exception("No image %s v%s in %s" % ( + name, version, search)) def show_repos(self, pattern, local=None, online=None, url=False, state=True): ''' @@ -722,8 +726,7 @@ class RepositoryManager(object): ''' Search pattern accross all registered repositories ''' - for repo in self.repos: - if repo.config.offline: continue + for repo in self.onlines: arrow(repo.config.name) repo.search(pattern) diff --git a/installsystems/tools.py b/installsystems/tools.py index 713dd35..757ffd2 100644 --- a/installsystems/tools.py +++ b/installsystems/tools.py @@ -493,3 +493,13 @@ def compare_versions(v1, v2): fv1 = get_ver(v1) fv2 = get_ver(v2) return fv1 - fv2 + +def split_image_path(path): + ''' + Split an image path (repo/image:version) + in a tuple (repo, image, version) + ''' + x = re.match(u"^(?:([-_\w]+)/)?([-_\w]+)(?::v?(\d+))?$", path) + if x is None: + raise Exception("invalid image path: %s" % path) + return x.group(1,2,3) diff --git a/samples/installsystems.conf b/samples/installsystems.conf index 4808d26..c8b5f24 100644 --- a/samples/installsystems.conf +++ b/samples/installsystems.conf @@ -23,8 +23,11 @@ # define connection timeout #timeout = 30 -# default repository name -#repo_filter = local +# search images inside repositories +#repo_search = stable testing + +# filter repository list +#repo_filter = stable testing # custom repository config file #repo_config = -- GitLab