config: use repo.tree (#4190)

Fixes #4188
This commit is contained in:
Ruslan Kuprieiev
2020-07-12 06:45:04 +03:00
committed by GitHub
parent 375998c664
commit b8a42939ad
7 changed files with 72 additions and 23 deletions
+32 -17
View File
@@ -232,8 +232,10 @@ class Config(dict):
CONFIG_LOCAL = "config.local"
def __init__(
self, dvc_dir=None, validate=True
self, dvc_dir=None, validate=True, tree=None,
): # pylint: disable=super-init-not-called
from dvc.scm.tree import WorkingTree
self.dvc_dir = dvc_dir
if not dvc_dir:
@@ -246,6 +248,9 @@ class Config(dict):
else:
self.dvc_dir = os.path.abspath(os.path.realpath(dvc_dir))
self.wtree = WorkingTree(self.dvc_dir)
self.tree = tree.tree if tree else self.wtree
self.load(validate=validate)
@classmethod
@@ -304,8 +309,32 @@ class Config(dict):
if not self["cache"].get("dir") and self.dvc_dir:
self["cache"]["dir"] = os.path.join(self.dvc_dir, "cache")
def _load_config(self, level):
filename = self.files[level]
tree = self.tree if level == "repo" else self.wtree
if tree.exists(filename):
with tree.open(filename) as fobj:
conf_obj = configobj.ConfigObj(fobj)
else:
conf_obj = configobj.ConfigObj()
return _parse_remotes(_lower_keys(conf_obj.dict()))
def _save_config(self, level, conf_dict):
filename = self.files[level]
tree = self.tree if level == "repo" else self.wtree
logger.debug(f"Writing '{filename}'.")
tree.makedirs(os.path.dirname(filename), exist_ok=True)
config = configobj.ConfigObj(_pack_remotes(conf_dict))
with tree.open(filename, "wb") as fobj:
config.write(fobj)
config.filename = filename
def load_one(self, level):
conf = _load_config(self.files[level])
conf = self._load_config(level)
conf = self._load_paths(conf, self.files[level])
# Auto-verify sections
@@ -375,7 +404,7 @@ class Config(dict):
_merge(merged_conf, conf)
self.validate(merged_conf)
_save_config(self.files[level], conf)
self._save_config(level, conf)
self.load()
@staticmethod
@@ -386,20 +415,6 @@ class Config(dict):
raise ConfigError(str(exc)) from None
def _load_config(filename):
conf_obj = configobj.ConfigObj(filename)
return _parse_remotes(_lower_keys(conf_obj.dict()))
def _save_config(filename, conf_dict):
logger.debug(f"Writing '{filename}'.")
os.makedirs(os.path.dirname(filename), exist_ok=True)
config = configobj.ConfigObj(_pack_remotes(conf_dict))
config.filename = filename
config.write()
def _parse_remotes(conf):
result = {"remote": {}}
+3
View File
@@ -254,3 +254,6 @@ class CleanTree(BaseTree):
@property
def hash_jobs(self):
return self.tree.hash_jobs
def makedirs(self, path, mode=0o777, exist_ok=True):
self.tree.makedirs(path, mode=mode, exist_ok=exist_ok)
+2 -2
View File
@@ -91,14 +91,14 @@ class Repo:
else:
root_dir = self.find_root(root_dir)
self.root_dir = os.path.abspath(os.path.realpath(root_dir))
self.tree = WorkingTree(self.root_dir)
self.dvc_dir = os.path.join(self.root_dir, self.DVC_DIR)
self.config = Config(self.dvc_dir)
self.config = Config(self.dvc_dir, tree=self.tree)
if not scm:
no_scm = self.config["core"].get("no_scm", False)
self.scm = SCM(self.root_dir, no_scm=no_scm)
self.tree = WorkingTree(self.root_dir)
self.tmp_dir = os.path.join(self.dvc_dir, "tmp")
self.index_dir = os.path.join(self.tmp_dir, "index")
+2 -2
View File
@@ -12,7 +12,7 @@ from dvc.utils.fs import copy_fobj_to_file, makedirs
logger = logging.getLogger(__name__)
class DvcTree(BaseTree):
class DvcTree(BaseTree): # pylint:disable=abstract-method
"""DVC repo tree.
Args:
@@ -236,7 +236,7 @@ class DvcTree(BaseTree):
return out.checksum
class RepoTree(BaseTree):
class RepoTree(BaseTree): # pylint:disable=abstract-method
"""DVC + git-tracked files tree.
Args:
+1 -1
View File
@@ -19,7 +19,7 @@ def _item_basename(item):
return os.path.basename(item.path)
class GitTree(BaseTree):
class GitTree(BaseTree): # pylint:disable=abstract-method
"""Proxies the repo file access methods to Git objects"""
def __init__(self, git, rev):
+6
View File
@@ -37,6 +37,9 @@ class BaseTree:
# NOTE: os.path.join is ~5.5 times slower
yield f"{root}{os.sep}{file}"
def makedirs(self, path, mode=0o777, exist_ok=True):
raise NotImplementedError
class WorkingTree(BaseTree):
"""Proxies the repo file access methods to working tree files"""
@@ -90,6 +93,9 @@ class WorkingTree(BaseTree):
def hash_jobs(self):
return max(1, min(4, cpu_count() // 2))
def makedirs(self, path, mode=0o777, exist_ok=True):
os.makedirs(path, mode=mode, exist_ok=exist_ok)
def is_working_tree(tree):
return isinstance(tree, WorkingTree) or isinstance(
+26 -1
View File
@@ -3,7 +3,8 @@ import os
import pytest
from funcy import raiser
from dvc.repo import locked
from dvc.repo import NotDvcRepoError, Repo, locked
from dvc.utils.fs import remove
def test_is_dvc_internal(dvc):
@@ -127,3 +128,27 @@ def test_skip_graph_checks(tmp_dir, dvc, mocker, run_copy):
dvc.add("quux")
run_copy("quux", "quuz", single_stage=True)
assert mock_collect_graph.called
def test_branch_config(tmp_dir, scm):
tmp_dir.scm_gen("foo", "foo", commit="init")
scm.checkout("branch", create_new=True)
dvc = Repo.init()
with dvc.config.edit() as conf:
conf["remote"]["branch"] = {"url": "/some/path"}
scm.add([".dvc"])
scm.commit("init dvc")
scm.checkout("master")
remove(".dvc")
# sanity check
with pytest.raises(NotDvcRepoError):
Repo()
with pytest.raises(NotDvcRepoError):
Repo(scm=scm, rev="master")
dvc = Repo(scm=scm, rev="branch")
assert dvc.config["remote"]["branch"]["url"] == "/some/path"