diff --git a/bin/isimage b/bin/isimage index f15e1e733ddfcb7b9b3356af100c39fefb89e920..9c80c625ea4b4f16ce8175bd5dbc9c358c5835fe 100755 --- a/bin/isimage +++ b/bin/isimage @@ -49,27 +49,28 @@ def build(args): # Top level argument parsing p_main = argparse.ArgumentParser() -p_main.add_argument("-V", "--version", action="version", version=installsystems.version, +p_main.add_argument("-V", "--version", action = "version", + version = installsystems.version, help="show installsystems version") -p_main.add_argument('-d', "--debug", action=ISAction, nargs=0, +p_main.add_argument('-d', "--debug", action = ISAction, nargs = 0, help="active debug mode") -p_main.add_argument('-q', "--quiet", action=ISAction, nargs=0, +p_main.add_argument('-q', "--quiet", action = ISAction, nargs = 0, help="active quiet mode") subparsers = p_main.add_subparsers() # Init command parser -p_init = subparsers.add_parser("init", help=init.__doc__.lower()) -p_init.add_argument("path", help="Path of new image directory") -p_init.set_defaults(func=init) +p_init = subparsers.add_parser("init", help = init.__doc__.lower()) +p_init.add_argument("path", help = "Path of new image directory") +p_init.set_defaults(func = init) # Build command parser -p_build = subparsers.add_parser("build", help=build.__doc__.lower()) -p_build.add_argument('-f', "--force", action="store_true", dest="force", default=False, - help="overwrite existing image") -p_build.add_argument('-c', "--no-check", action="store_false", dest="check", default=True, - help="do not check compilation before adding scripts") +p_build = subparsers.add_parser("build", help = build.__doc__.lower()) +p_build.add_argument('-f', "--force", action = "store_true", dest = "force", default = False, + help = "overwrite existing image") +p_build.add_argument('-c', "--no-check", action = "store_false", dest = "check", default = True, + help = "do not check compilation before adding scripts") -p_build.add_argument("path", nargs="?", type=str, default=".") -p_build.set_defaults(func=build) +p_build.add_argument("path", nargs = "?", default = ".") +p_build.set_defaults(func = build) # Parse and run args = p_main.parse_args() args.func(args) diff --git a/bin/isinstall b/bin/isinstall index 8dd7db8b2786d745054c2e45a24dcdf564ae69fe..59debbea0af5149f8d6eda763ee6b3360131b107 100755 --- a/bin/isinstall +++ b/bin/isinstall @@ -15,10 +15,12 @@ import installsystems.argparse as argparse # To remove when default to python 2. from installsystems.printer import * from installsystems.repository import RepositoryManager, RepositoryConfig from installsystems.image import PackageImage -from installsystems.config import ConfigFile +from installsystems.config import MainConfigFile, RepoConfigFile class ISAction(argparse.Action): - '''Set installsystems quiet/debug mode. Argparse callback''' + ''' + Set installsystems quiet/debug mode. Argparse callback + ''' def __call__(self, parser, namespace, values, option_string=None): if option_string in ("-q", "--quiet"): installsystems.debug = False @@ -28,29 +30,32 @@ class ISAction(argparse.Action): # Argument parsing loading p_main = argparse.ArgumentParser() -p_main.add_argument("-V", "--version", action="version", version=installsystems.version, - help="show installsystems version") -p_main.add_argument('-d', "--debug", action=ISAction, nargs=0, - help="active debug mode") -p_main.add_argument('-q', "--quiet", action=ISAction, nargs=0, - help="active quiet mode") -p_main.add_argument("--no-cache", action="store_false", default=False, - help="Not use persistent db caching") -p_main.add_argument("-c", "--config", dest="config", type=str, default=None, - help="config file path") -p_main.add_argument("-v", "--image-version", dest="image_version", type=int, default=None, - help="image version") -p_main.add_argument("-t", "--timeout", dest="timeout", type=int, default=None, - help="download timeout") -p_main.add_argument("-r", "--repo", dest="repos", action="append", default=[], - help="repository (can be specified more than one time)") -p_main.add_argument("image_name", type=str, - help="image to install (path or name)") +p_main.add_argument("-V", "--version", action = "version", + version = installsystems.version, + help = "show installsystems version") +p_main.add_argument('-d', "--debug", action = ISAction, nargs = 0, + help = "active debug mode") +p_main.add_argument('-q', "--quiet", action = ISAction, nargs = 0, + help = "active quiet mode") +p_main.add_argument("--no-cache", action = "store_false", default = False, + help = "Not use persistent db caching") +p_main.add_argument("-c", "--config", dest = "config", default = "isinstall", + help = "config file path") +p_main.add_argument("-v", "--image-version", type = int, default = None, + help = "image version") +p_main.add_argument("-t", "--timeout", dest = "timeout", type = int, default = None, + help = "download timeout") +p_main.add_argument("-r", "--repo-path", action = "append", default = [], + help = "repository path") +p_main.add_argument("-R", "--repo-config", action = "append", default = ["repository"], + help = "repository config path (can be specified more than one time)") +p_main.add_argument("image_name", help = "image to install (path or name)") + try: # Partial parse args = p_main.parse_known_args()[0] - # load config - config = ConfigFile("isinstall", args.config) + # load main config + config = MainConfigFile(args.config) # looks if arguments is a file or image name if istools.pathtype(args.image_name) == "file" and os.path.isfile(args.image_name): pkg = PackageImage(istools.abspath(args.image_name)) @@ -60,12 +65,13 @@ try: config.cache = None # init repo cache object repoman = RepositoryManager(config.cache, timeout=args.timeout) - # register config repositories - for crepo in config.repos: - repoman.register(crepo) - # register command line repositories - for rpath in args.repos: + # register command line repositories (order matter) + for rpath in args.repo_path: repoman.register(RepositoryConfig(None, path=rpath)) + # register config repositories + for r_config in args.repo_config: + for r_repo in RepoConfigFile(r_config).repos: + repoman.register(r_repo) # get image package pkg = repoman.get(args.image_name, args.image_version) else: diff --git a/bin/isrepo b/bin/isrepo index 0c137cff4f905589f2a730e129ba8f53f0b369d5..ccc0c41f7a0e35f0fc7858aa1238708d97670dfa 100755 --- a/bin/isrepo +++ b/bin/isrepo @@ -8,14 +8,16 @@ InstallSystems Repository Manipulation Tool import os import installsystems -import installsystems.argparse as argparse # To remove when default to python 2.7 +import installsystems.argparse as argparse # To Remove when python 2.7 from installsystems.printer import * from installsystems.repository import Repository, RepositoryConfig from installsystems.image import PackageImage -from installsystems.config import ConfigFile +from installsystems.config import MainConfigFile, RepoConfigFile class ISAction(argparse.Action): - '''Set installsystems quiet/debug mode. Argparse callback''' + ''' + Set installsystems quiet/debug mode. Argparse callback + ''' def __call__(self, parser, namespace, values, option_string=None): if option_string in ("-q", "--quiet"): installsystems.quiet = True @@ -24,7 +26,9 @@ class ISAction(argparse.Action): def init(args): - '''Create an empty fresh repo tree''' + ''' + Create an empty fresh repo tree + ''' # call init from library try: Repository.create(args.repository) @@ -32,7 +36,9 @@ def init(args): raise Exception("init failed: %s" % e) def add(args): - '''Add a package to repository''' + ''' + Add a package to repository + ''' try: repo = Repository(args.repository) pkg = PackageImage(args.path) @@ -41,7 +47,9 @@ def add(args): raise Exception("add failed: %s" % e) def delete(args): - '''Remove a package from repository''' + ''' + Remove a package from repository + ''' try: repo = Repository(args.repository) repo.delete(args.image_name, args.image_version) @@ -50,24 +58,28 @@ def delete(args): # Top level argument parsing p_main = argparse.ArgumentParser() -p_main.add_argument("-V", "--version", action="version", version=installsystems.version, - help="show installsystems version") -p_main.add_argument('-d', "--debug", action=ISAction, nargs=0, - help="active debug mode") -p_main.add_argument('-q', "--quiet", action=ISAction, nargs=0, - help="active quiet mode") -p_main.add_argument("-c", "--config", dest="config", type=str, default=None, - help="config file path") -p_main.add_argument("-r", "--repo-name", dest="repo_name", type=str, default=None, - help="repository name in config file") +p_main.add_argument("-V", "--version", action = "version", + version = installsystems.version, + help = "show installsystems version") +p_main.add_argument('-d', "--debug", action = ISAction, nargs = 0, + help = "active debug mode") +p_main.add_argument('-q', "--quiet", action = ISAction, nargs = 0, + help = "active quiet mode") +p_main.add_argument("-c", "--config", default = "isrepo", + help = "config file path") +p_main.add_argument("-r", "--repo-name", default = None, + help = "select repository by name in config files") +p_main.add_argument("-R", "--repo-config", action = "append", + default = ["repository"], + help = "repository config (can be specified more than one time)") subparsers = p_main.add_subparsers() # Init command parser -p_init = subparsers.add_parser("init", help=init.__doc__.lower()) -p_init.set_defaults(func=init) +p_init = subparsers.add_parser("init", help = init.__doc__.lower()) +p_init.set_defaults(func = init) # Add command parser -p_add = subparsers.add_parser("add", help=add.__doc__.lower()) -p_add.add_argument("path", type=str) -p_add.set_defaults(func=add) +p_add = subparsers.add_parser("add", help = add.__doc__.lower()) +p_add.add_argument("path") +p_add.set_defaults(func = add) # Del command parser #p_del = subparsers.add_parser("del", help=delete.__doc__.lower()) #p_del.add_argument("image_name", type=str) @@ -76,13 +88,16 @@ p_add.set_defaults(func=add) try: # Parse and run args = p_main.parse_args() - # load config - config = ConfigFile("isrepo", args.config) + # load isinstall config + config = MainConfigFile(args.config) + config.merge(args) + # load repo configs + repos = [] + for r_config in args.repo_config: + repos += RepoConfigFile(r_config).repos # filtering on repository name if present if args.repo_name is not None: - repos = filter(lambda x: x.name == args.repo_name, config.repos) - else: - repos = config.repos + repos = filter(lambda x: x.name == args.repo_name, repos) if len(repos) == 1: args.repository = repos[0] elif len(repos) > 1: diff --git a/installsystems/config.py b/installsystems/config.py index b9799112eaa1124de0aa94e79fc5a2ab0707824c..0d32aa652c4952c078d492a11875e05c3839dec6 100644 --- a/installsystems/config.py +++ b/installsystems/config.py @@ -11,59 +11,57 @@ from ConfigParser import RawConfigParser from installsystems.printer import * from installsystems.repository import RepositoryConfig + class ConfigFile(object): - '''Configuration class''' + ''' + Configuration File base class + ''' - def __init__(self, prefix=None, filename=None): - # prefix is config file indentifier (isinstall / isrepo) - self.prefix = prefix - self.path = self._config_path() if filename is None else os.path.abspath(filename) + def __init__(self, filename): + ''' + filename can be name in config path + ''' + #try to get filename in default config dir + if "/" not in filename: + path = self._config_path(filename) + if path is not None: + self.path = path + elif os.path.exists(filename): + self.path = filename + else: + self.path = None + debug("No config file found: %s" % filename) self.reload() - def _config_path(self): - '''Return path of the best config file''' - for cf in [ os.path.join(os.path.expanduser("~/.config/installsystems/%s.conf" % self.prefix)), - "/etc/installsystems/%s.conf" % self.prefix ]: + def reload(): + ''' + Reload configuration from file + ''' + raise NotImplementedError + + def _config_path(self, name): + ''' + Return path of the best config file + ''' + for cf in [ os.path.join(os.path.expanduser("~/.config/installsystems/%s.conf" % name)), + "/etc/installsystems/%s.conf" % name ]: if (os.path.exists(cf) and os.path.isfile(cf) and os.access(cf, os.R_OK)): return cf return None - def reload(self): - '''Load/Reload config file''' - # seting default config - self._config = {} - self._repos = [] - # loading config file if exists - if self.path is not None: - debug("Loading config file: %s" % self.path) - try: - cp = RawConfigParser() - cp.read(self.path) - # main configuration - if cp.has_section(self.prefix): - self._config = dict(cp.items(self.prefix)) - cp.remove_section(self.prefix) - # each section is a repository - for rep in cp.sections(): - # check if its a repo section - if "path" not in cp.options(rep): - continue - # get all options in repo - self._repos.append(RepositoryConfig(rep, **dict(cp.items(rep)))) - except Exception as e: - raise Exception("Unable load file %s: %s" % (self.path, e)) - else: - debug("No config file found") - - def _cache_paths(self): - '''List all candidates to cache directories. Alive or not''' + def _cache_paths(self, name): + ''' + List all candidates to cache directories. Alive or not + ''' dirs = [] # ["/var/tmp", "/tmp"] # we have a different behaviour if we are root dirs.insert(0, "/var/cache" if os.getuid() == 0 else os.path.expanduser("~/.cache")) - return map(lambda x: os.path.join(x, self.prefix), dirs) + return map(lambda x: os.path.join(x, name), dirs) def _cache_path(self): - '''Return path of the best cache directory''' + ''' + Return path of the best cache directory + ''' # find a good directory for di in self._cache_paths(): if (os.path.exists(di) @@ -72,9 +70,46 @@ class ConfigFile(object): return di return None + +class MainConfigFile(ConfigFile): + ''' + Program configuration file + ''' + + def reload(self): + ''' + Load/Reload config file + ''' + self._config = {} + # loading config file if exists + if self.path is None: + return + debug("Loading config file: %s" % self.path) + try: + cp = RawConfigParser() + cp.read(self.path) + # main configuration + name = os.path.splitext(os.path.basename(self.path))[0] + if cp.has_section(name): + self._config = dict(cp.items(name)) + except Exception as e: + raise Exception("Unable load file %s: %s" % (self.path, e)) + + def merge(self, namespace): + ''' + Merge current loaded option with a namespace from argparse + ''' + for option, value in self._config.items(): + if not hasattr(namespace, option): + setattr(namespace, option, value) + elif getattr(namespace, option) == None: + setattr(namespace, option, value) + @property def cache(self): - '''Find a cache directory''' + ''' + Find a cache directory + ''' if "cache" in self._config: return self._config["cache"] if self._cache_path() is None: @@ -86,8 +121,41 @@ class ConfigFile(object): debug("Unable to create %s: %s" % (di, e)) return self._cache_path() + +class RepoConfigFile(ConfigFile): + ''' + Repository Configuration class + ''' + + def reload(self): + ''' + Load/Reload config file + ''' + # seting default config + self._config = {} + self._repos = [] + # loading config file if exists + if self.path is not None: + debug("Loading config file: %s" % self.path) + try: + cp = RawConfigParser() + cp.read(self.path) + # each section is a repository + for rep in cp.sections(): + # check if its a repo section + if "path" not in cp.options(rep): + continue + # get all options in repo + self._repos.append(RepositoryConfig(rep, **dict(cp.items(rep)))) + except Exception as e: + raise Exception("Unable load file %s: %s" % (self.path, e)) + else: + debug("No config file found") + @property def repos(self): - '''Get a list of repository available''' + ''' + Get a list of repository available + ''' # deep copy return list(self._repos) diff --git a/samples/isinstall.conf b/samples/isinstall.conf index c398b6b61720401d6e50ce2a48b092c1fac1dc2f..188337ce0d9133b46ecfcd9c4e1c6312b98022c3 100644 --- a/samples/isinstall.conf +++ b/samples/isinstall.conf @@ -1,13 +1,14 @@ # isinstall program configuration + [isinstall] -debug = False +# define a custom cache directory +#cache = /tmp/sex + +# disable cache of remote repository +#no_cache = 1 -# smartjog official installsystems repository -[smartjog] -image = http://installsystems.boot.wan/images -data = http://installsystems.boot.wan/data +# define connection timeout +#timeout = 30 -# localhost testing repository -[localhost] -image = http://localhost/images -data = http://localhost/data +# custom repository config file +#repo_config = diff --git a/samples/isrepo.conf b/samples/isrepo.conf index 0b4cd41fca6399c0714297132a18b247e90d7550..9b213b21dc5c0a8ba67f4368294bb8f9ff16bf1f 100644 --- a/samples/isrepo.conf +++ b/samples/isrepo.conf @@ -1,10 +1,6 @@ [isrepo] -cache = /tmp/cache +#default repository name +repo_name = local -[smartjog] -image = /home/installsystemsng/image -data = /home/installsystemsng/data -chown = seblu -chgroup = sebgp -fchmod = 644 -dchmod = 755 +# custom repository config file +#repo_config = diff --git a/samples/repository.conf b/samples/repository.conf new file mode 100644 index 0000000000000000000000000000000000000000..65da67a94cf93f84dab17b6b3f4d4817b061a8ac --- /dev/null +++ b/samples/repository.conf @@ -0,0 +1,17 @@ +# repository configuration + +# local repository +[local] +path = /home/seblu/pub/is +fmod = 644 +dmod = 755 +uid = seblu +gid = sebgp + +# localhost testing repository +[http] +path = http://127.0.0.1/is + +# smartjog official installsystems repository +[smartjog] +path = http://installsystems.boot.wan/is