remote: use RemoteConfig class

Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
Ruslan Kuprieiev
2019-06-06 16:00:44 +03:00
parent f69836c2b3
commit 8ef9133194
6 changed files with 167 additions and 153 deletions
+14
View File
@@ -7,6 +7,20 @@ import os
from dvc.config import Config
class CacheConfig(object):
def __init__(self, config):
self.config = config
def set_dir(self, dname, level=None):
from dvc.remote.config import RemoteConfig
configobj = self.config.get_configobj(level)
path = RemoteConfig.resolve_path(dname, configobj.filename)
self.config.set(
Config.SECTION_CACHE, Config.SECTION_CACHE_DIR, path, level=level
)
class Cache(object):
"""Class that manages cache locations of a dvc repo.
+6 -2
View File
@@ -4,12 +4,16 @@ import argparse
from dvc.command.base import fix_subparsers, append_doc_link
from dvc.command.config import CmdConfig
from dvc.remote.config import set_cache_dir
from dvc.cache import CacheConfig
class CmdCacheDir(CmdConfig):
def __init__(self, args):
super(CmdCacheDir, self).__init__(args)
self.config = CacheConfig(self.config)
def run(self):
set_cache_dir(self.config, self.args.value, level=self.args.level)
self.config.set_dir(self.args.value, level=self.args.level)
return 0
+18 -19
View File
@@ -5,16 +5,20 @@ import logging
from dvc.command.base import append_doc_link, fix_subparsers
from dvc.command.config import CmdConfig
from dvc.remote.config import remote_add, remote_remove, remote_modify
from dvc.remote.config import remote_list, remote_default
from dvc.remote.config import RemoteConfig
logger = logging.getLogger(__name__)
class CmdRemoteAdd(CmdConfig):
class CmdRemoteConfig(CmdConfig):
def __init__(self, args):
super(CmdRemoteConfig, self).__init__(args)
self.config = RemoteConfig(self.config)
class CmdRemoteAdd(CmdRemoteConfig):
def run(self):
remote_add(
self.config,
self.config.add(
self.args.name,
self.args.url,
force=self.args.force,
@@ -24,16 +28,15 @@ class CmdRemoteAdd(CmdConfig):
return 0
class CmdRemoteRemove(CmdConfig):
class CmdRemoteRemove(CmdRemoteConfig):
def run(self):
remote_remove(self.config, self.args.name, level=self.args.level)
self.config.remove(self.args.name, level=self.args.level)
return 0
class CmdRemoteModify(CmdConfig):
class CmdRemoteModify(CmdRemoteConfig):
def run(self):
remote_modify(
self.config,
self.config.modify(
self.args.name,
self.args.option,
self.args.value,
@@ -42,21 +45,17 @@ class CmdRemoteModify(CmdConfig):
return 0
class CmdRemoteDefault(CmdConfig):
class CmdRemoteDefault(CmdRemoteConfig):
def run(self):
remote_default(
self.config,
self.args.name,
unset=self.args.unset,
level=self.args.level,
self.config.set_default(
self.args.name, unset=self.args.unset, level=self.args.level
)
return 0
class CmdRemoteList(CmdConfig):
class CmdRemoteList(CmdRemoteConfig):
def run(self):
remotes = remote_list(self.config, level=self.args.level)
for name, url in remotes.items():
for name, url in self.config.list(level=self.args.level).items():
logger.info("{}\t{}".format(name, url))
return 0
+1 -1
View File
@@ -534,7 +534,7 @@ class Config(object): # pylint: disable=too-many-instance-attributes
config[section][opt] = value
self.save(config)
def get(self, section, opt, level=None):
def get(self, section, opt=None, level=None):
"""Return option value from the config.
Args:
+3 -2
View File
@@ -10,7 +10,7 @@ from dvc.remote.http import RemoteHTTP
from dvc.remote.https import RemoteHTTPS
from dvc.remote.oss import RemoteOSS
from .config import get_remote_settings
from .config import RemoteConfig
REMOTES = [
@@ -36,7 +36,8 @@ def _get(config):
def Remote(repo, **kwargs):
name = kwargs.get("name")
if name:
settings = get_remote_settings(repo.config, name)
remote_config = RemoteConfig(repo.config)
settings = remote_config.get_settings(name)
else:
settings = kwargs
return _get(settings)(repo, settings)
+125 -129
View File
@@ -9,147 +9,143 @@ from dvc.config import Config, ConfigError
logger = logging.getLogger(__name__)
def get_remote_settings(config, name):
"""
Args:
name (str): The name of the remote that we want to retrieve
class RemoteConfig(object):
def __init__(self, config):
self.config = config
Returns:
dict: The content beneath the given remote name.
def get_settings(self, name):
"""
Args:
name (str): The name of the remote that we want to retrieve
Example:
>>> config = {'remote "server"': {'url': 'ssh://localhost/'}}
>>> get_remote_settings("server")
{'url': 'ssh://localhost/'}
"""
settings = config.config.get(
config.SECTION_REMOTE_FMT.format(name.lower())
)
Returns:
dict: The content beneath the given remote name.
if settings is None:
raise ConfigError("unable to find remote section '{}'".format(name))
parsed = urlparse(settings["url"])
# Support for cross referenced remotes.
# This will merge the settings, giving priority to the outer reference.
# For example, having:
#
# dvc remote add server ssh://localhost
# dvc remote modify server user root
# dvc remote modify server ask_password true
#
# dvc remote add images remote://server/tmp/pictures
# dvc remote modify images user alice
# dvc remote modify images ask_password false
# dvc remote modify images password asdf1234
#
# Results on a config dictionary like:
#
# {
# "url": "ssh://localhost/tmp/pictures",
# "user": "alice",
# "password": "asdf1234",
# "ask_password": False,
# }
#
if parsed.scheme == "remote":
reference = get_remote_settings(config, parsed.netloc)
url = posixpath.join(reference["url"], parsed.path.lstrip("/"))
merged = reference.copy()
merged.update(settings)
merged["url"] = url
return merged
return settings
def _resolve_remote_path(path, config_file):
"""Resolve path relative to config file location.
Args:
path: Path to be resolved.
config_file: Path to config file, which `path` is specified
relative to.
Returns:
Path relative to the `config_file` location. If `path` is an
absolute path then it will be returned without change.
"""
if os.path.isabs(path):
return path
return os.path.relpath(path, os.path.dirname(config_file))
def remote_add(config, name, url, default=False, force=False, level=None):
from dvc.remote import _get, RemoteLOCAL
configobj = config.get_configobj(level)
remote = _get({Config.SECTION_REMOTE_URL: url})
if remote == RemoteLOCAL and not url.startswith("remote://"):
url = _resolve_remote_path(url, configobj.filename)
config.set(
config.SECTION_REMOTE_FMT.format(name),
config.SECTION_REMOTE_URL,
url,
force=force,
level=level,
)
if default:
logger.info("Setting '{}' as a default remote.".format(name))
config.set(
config.SECTION_CORE, config.SECTION_CORE_REMOTE, name, level=level
Example:
>>> config = {'remote "server"': {'url': 'ssh://localhost/'}}
>>> get_settings("server")
{'url': 'ssh://localhost/'}
"""
settings = self.config.config.get(
Config.SECTION_REMOTE_FMT.format(name.lower())
)
if settings is None:
raise ConfigError(
"unable to find remote section '{}'".format(name)
)
def remote_remove(config, name, level=None):
config.unset(config.SECTION_REMOTE_FMT.format(name), level=level)
parsed = urlparse(settings["url"])
if level is None:
level = config.LEVEL_REPO
# Support for cross referenced remotes.
# This will merge the settings, giving priority to the outer reference.
# For example, having:
#
# dvc remote add server ssh://localhost
# dvc remote modify server user root
# dvc remote modify server ask_password true
#
# dvc remote add images remote://server/tmp/pictures
# dvc remote modify images user alice
# dvc remote modify images ask_password false
# dvc remote modify images password asdf1234
#
# Results on a config dictionary like:
#
# {
# "url": "ssh://localhost/tmp/pictures",
# "user": "alice",
# "password": "asdf1234",
# "ask_password": False,
# }
#
if parsed.scheme == "remote":
reference = self.get_settings(parsed.netloc)
url = posixpath.join(reference["url"], parsed.path.lstrip("/"))
merged = reference.copy()
merged.update(settings)
merged["url"] = url
return merged
for lev in [
config.LEVEL_LOCAL,
config.LEVEL_REPO,
config.LEVEL_GLOBAL,
config.LEVEL_SYSTEM,
]:
config.unset(
config.SECTION_CORE,
config.SECTION_CORE_REMOTE,
level=lev,
force=True,
return settings
@staticmethod
def resolve_path(path, config_file):
"""Resolve path relative to config file location.
Args:
path: Path to be resolved.
config_file: Path to config file, which `path` is specified
relative to.
Returns:
Path relative to the `config_file` location. If `path` is an
absolute path then it will be returned without change.
"""
if os.path.isabs(path):
return path
return os.path.relpath(path, os.path.dirname(config_file))
def add(self, name, url, default=False, force=False, level=None):
from dvc.remote import _get, RemoteLOCAL
configobj = self.config.get_configobj(level)
remote = _get({Config.SECTION_REMOTE_URL: url})
if remote == RemoteLOCAL and not url.startswith("remote://"):
url = self.resolve_path(url, configobj.filename)
self.config.set(
Config.SECTION_REMOTE_FMT.format(name),
Config.SECTION_REMOTE_URL,
url,
force=force,
level=level,
)
if lev == level:
break
if default:
logger.info("Setting '{}' as a default remote.".format(name))
self.config.set(
Config.SECTION_CORE,
Config.SECTION_CORE_REMOTE,
name,
level=level,
)
def remove(self, name, level=None):
self.config.unset(Config.SECTION_REMOTE_FMT.format(name), level=level)
def remote_modify(config, name, option, value, level=None):
config.set(
config.SECTION_REMOTE_FMT.format(name), option, value, level=level
)
if level is None:
level = Config.LEVEL_REPO
for lev in [
Config.LEVEL_LOCAL,
Config.LEVEL_REPO,
Config.LEVEL_GLOBAL,
Config.LEVEL_SYSTEM,
]:
self.config.unset(
Config.SECTION_CORE,
Config.SECTION_CORE_REMOTE,
level=lev,
force=True,
)
if lev == level:
break
def remote_list(config, level=None):
return config.list_options(
config.SECTION_REMOTE_REGEX, config.SECTION_REMOTE_URL, level=level
)
def modify(self, name, option, value, level=None):
self.config.set(
Config.SECTION_REMOTE_FMT.format(name), option, value, level=level
)
def list(self, level=None):
return self.config.list_options(
Config.SECTION_REMOTE_REGEX, Config.SECTION_REMOTE_URL, level=level
)
def remote_default(config, name, unset=False, level=None):
if unset:
config.unset(config.SECTION_CORE, config.SECTION_CORE_REMOTE)
return
config.set(
config.SECTION_CORE, config.SECTION_CORE_REMOTE, name, level=level
)
def set_cache_dir(config, dname, level=None):
configobj = config.get_configobj(level)
path = _resolve_remote_path(dname, configobj.filename)
config.set(
config.SECTION_CACHE, config.SECTION_CACHE_DIR, path, level=level
)
def set_default(self, name, unset=False, level=None):
if unset:
self.config.unset(Config.SECTION_CORE, Config.SECTION_CORE_REMOTE)
return
self.config.set(
Config.SECTION_CORE, Config.SECTION_CORE_REMOTE, name, level=level
)