class CmdConfig(CmdBaseNoRepo): def __init__(self, args): from dvc.config import Config super().__init__(args) self.config = Config(validate=False) def run(self): if self.args.show_origin: if any((self.args.value, self.args.unset)): logger.error( "--show-origin can't be used together with any of these " "options: -u/--unset, value" ) return 1 if self.args.list: return self._list() if self.args.name is None: logger.error("name argument is required") return 1 remote, section, opt = self.args.name if self.args.value is None and not self.args.unset: return self._get(remote, section, opt) return self._set(remote, section, opt) def _list(self): if any((self.args.name, self.args.value, self.args.unset)): logger.error( "-l/--list can't be used together with any of these " "options: -u/--unset, name, value" ) return 1 levels = self._get_appropriate_levels(self.args.level) for level in levels: conf = self.config.read(level) prefix = self._config_file_prefix( self.args.show_origin, self.config, level ) configs = list(self._format_config(conf, prefix)) if configs: ui.write("\n".join(configs)) return 0 def _get(self, remote, section, opt): from dvc.config import ConfigError levels = self._get_appropriate_levels(self.args.level)[::-1] for level in levels: conf = self.config.read(level) if remote: conf = conf["remote"] try: self._check(conf, remote, section, opt) except ConfigError: if self.args.level: raise else: prefix = self._config_file_prefix( self.args.show_origin, self.config, level ) ui.write(prefix, conf[section][opt], sep="") break return 0 def _set(self, remote, section, opt): with self.config.edit(self.args.level) as conf: if remote: conf = conf["remote"] if self.args.unset: self._check(conf, remote, section, opt) del conf[section][opt] else: self._check(conf, remote, section) conf[section][opt] = self.args.value if self.args.name == "cache.type": logger.warning( "You have changed the 'cache.type' option. This doesn't update" " any existing workspace file links, but it can be done with:" "\n dvc checkout --relink" ) return 0 def _check(self, conf, remote, section, opt=None): from dvc.config import ConfigError name = "remote" if remote else "section" if section not in conf: raise ConfigError(f"{name} '{section}' doesn't exist") if opt and opt not in conf[section]: raise ConfigError( f"option '{opt}' doesn't exist in {name} '{section}'" ) def _get_appropriate_levels(self, levels): if levels: self._validate_level_for_non_repo_operation(levels) return [levels] if self.config.dvc_dir is None: return self.config.SYSTEM_LEVELS return self.config.LEVELS def _validate_level_for_non_repo_operation(self, level): from dvc.config import ConfigError if self.config.dvc_dir is None and level in self.config.REPO_LEVELS: raise ConfigError("Not inside a DVC repo") @staticmethod def _format_config(config, prefix=""): from dvc.utils.flatten import flatten for key, value in flatten(config).items(): yield f"{prefix}{key}={value}" @staticmethod def _config_file_prefix(show_origin, config, level): from dvc.repo import Repo if not show_origin: return "" level = level or "repo" fname = config.files[level] if level in ["local", "repo"]: fname = os.path.relpath(fname, start=Repo.find_root()) return fname + "\t"
class CmdConfig(CmdBaseNoRepo): def __init__(self, args): super().__init__(args) self.config = Config(validate=False) def run(self): if self.args.show_origin: if any((self.args.value, self.args.unset)): logger.error( "--show-origin can't be used together with any of these " "options: -u/--unset, value" ) return 1 if not self.args.level: logger.error( "--show-origin requires one of these options: " "--system, --global, --repo, --local" ) return 1 if self.args.list: if any((self.args.name, self.args.value, self.args.unset)): logger.error( "-l/--list can't be used together with any of these " "options: -u/--unset, name, value" ) return 1 conf = self.config.read(self.args.level) prefix = self._config_file_prefix( self.args.show_origin, self.config, self.args.level ) logger.info("\n".join(self._format_config(conf, prefix))) return 0 if self.args.name is None: logger.error("name argument is required") return 1 remote, section, opt = self.args.name if self.args.value is None and not self.args.unset: conf = self.config.read(self.args.level) prefix = self._config_file_prefix( self.args.show_origin, self.config, self.args.level ) if remote: conf = conf["remote"] self._check(conf, remote, section, opt) logger.info("{}{}".format(prefix, conf[section][opt])) return 0 with self.config.edit(self.args.level) as conf: if remote: conf = conf["remote"] if self.args.unset: self._check(conf, remote, section, opt) del conf[section][opt] else: self._check(conf, remote, section) conf[section][opt] = self.args.value if self.args.name == "cache.type": logger.warning( "You have changed the 'cache.type' option. This doesn't update" " any existing workspace file links, but it can be done with:" "\n dvc checkout --relink" ) return 0 def _check(self, conf, remote, section, opt=None): name = "remote" if remote else "section" if section not in conf: raise ConfigError(f"{name} '{section}' doesn't exist") if opt and opt not in conf[section]: raise ConfigError( f"option '{opt}' doesn't exist in {name} '{section}'" ) @staticmethod def _format_config(config, prefix=""): for key, value in flatten(config).items(): yield f"{prefix}{key}={value}" @staticmethod def _config_file_prefix(show_origin, config, level): if not show_origin: return "" level = level or "repo" fname = config.files[level] if level in ["local", "repo"]: fname = os.path.relpath(fname, start=Repo.find_root()) return fname + "\t"