We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
import: Handle non-DVC Git repositories 
After https://github.com/iterative/dvc/pull/2889, `dvc import` can also import files that are tracked by Git but not DVC. DVC still requires that they come from a DVC repository rather than any Git repository, although there is no longer need for that.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `dvc/external_repo.py`
Content:
```
1 import os
2 import tempfile
3 from contextlib import contextmanager
4 from distutils.dir_util import copy_tree
5 
6 from funcy import retry
7 
8 from dvc.config import NoRemoteError, ConfigError
9 from dvc.exceptions import NoRemoteInExternalRepoError
10 from dvc.remote import RemoteConfig
11 from dvc.exceptions import NoOutputInExternalRepoError
12 from dvc.exceptions import OutputNotFoundError
13 from dvc.utils.fs import remove
14 
15 
16 REPO_CACHE = {}
17 
18 
19 @contextmanager
20 def external_repo(url=None, rev=None, rev_lock=None, cache_dir=None):
21     from dvc.repo import Repo
22 
23     path = _external_repo(url=url, rev=rev_lock or rev, cache_dir=cache_dir)
24     repo = Repo(path)
25     try:
26         yield repo
27     except NoRemoteError:
28         raise NoRemoteInExternalRepoError(url)
29     except OutputNotFoundError as exc:
30         if exc.repo is repo:
31             raise NoOutputInExternalRepoError(exc.output, repo.root_dir, url)
32         raise
33     repo.close()
34 
35 
36 def _external_repo(url=None, rev=None, cache_dir=None):
37     from dvc.config import Config
38     from dvc.cache import CacheConfig
39     from dvc.repo import Repo
40 
41     key = (url, rev, cache_dir)
42     if key in REPO_CACHE:
43         return REPO_CACHE[key]
44 
45     new_path = tempfile.mkdtemp("dvc-erepo")
46 
47     # Copy and adjust existing clone
48     if (url, None, None) in REPO_CACHE:
49         old_path = REPO_CACHE[url, None, None]
50 
51         # This one unlike shutil.copytree() works with an existing dir
52         copy_tree(old_path, new_path)
53     else:
54         # Create a new clone
55         _clone_repo(url, new_path)
56 
57         # Save clean clone dir so that we will have access to a default branch
58         clean_clone_path = tempfile.mkdtemp("dvc-erepo")
59         copy_tree(new_path, clean_clone_path)
60         REPO_CACHE[url, None, None] = clean_clone_path
61 
62     # Adjust new clone/copy to fit rev and cache_dir
63 
64     # Checkout needs to be done first because current branch might not be
65     # DVC repository
66     if rev is not None:
67         _git_checkout(new_path, rev)
68 
69     repo = Repo(new_path)
70     try:
71         # check if the URL is local and no default remote is present
72         # add default remote pointing to the original repo's cache location
73         if os.path.isdir(url):
74             rconfig = RemoteConfig(repo.config)
75             if not _default_remote_set(rconfig):
76                 original_repo = Repo(url)
77                 try:
78                     rconfig.add(
79                         "auto-generated-upstream",
80                         original_repo.cache.local.cache_dir,
81                         default=True,
82                         level=Config.LEVEL_LOCAL,
83                     )
84                 finally:
85                     original_repo.close()
86 
87         if cache_dir is not None:
88             cache_config = CacheConfig(repo.config)
89             cache_config.set_dir(cache_dir, level=Config.LEVEL_LOCAL)
90     finally:
91         # Need to close/reopen repo to force config reread
92         repo.close()
93 
94     REPO_CACHE[key] = new_path
95     return new_path
96 
97 
98 def _git_checkout(repo_path, revision):
99     from dvc.scm import Git
100 
101     git = Git(repo_path)
102     try:
103         git.checkout(revision)
104     finally:
105         git.close()
106 
107 
108 def clean_repos():
109     # Outside code should not see cache while we are removing
110     repo_paths = list(REPO_CACHE.values())
111     REPO_CACHE.clear()
112 
113     for path in repo_paths:
114         _remove(path)
115 
116 
117 def _remove(path):
118     if os.name == "nt":
119         # git.exe may hang for a while not permitting to remove temp dir
120         os_retry = retry(5, errors=OSError, timeout=0.1)
121         os_retry(remove)(path)
122     else:
123         remove(path)
124 
125 
126 def _clone_repo(url, path):
127     from dvc.scm.git import Git
128 
129     git = Git.clone(url, path)
130     git.close()
131 
132 
133 def _default_remote_set(rconfig):
134     """
135     Checks if default remote config is present.
136     Args:
137         rconfig: a remote config
138 
139     Returns:
140         True if the default remote config is set, else False
141     """
142     try:
143         rconfig.get_default()
144         return True
145     except ConfigError:
146         return False
147
```

Path: `dvc/dependency/repo.py`
Content:
```
1 import copy
2 import os
3 from contextlib import contextmanager
4 from dvc.utils.compat import FileNotFoundError
5 
6 from funcy import merge
7 
8 from .local import DependencyLOCAL
9 from dvc.external_repo import external_repo
10 from dvc.exceptions import OutputNotFoundError
11 from dvc.exceptions import PathMissingError
12 from dvc.utils.fs import fs_copy
13 
14 
15 class DependencyREPO(DependencyLOCAL):
16     PARAM_REPO = "repo"
17     PARAM_URL = "url"
18     PARAM_REV = "rev"
19     PARAM_REV_LOCK = "rev_lock"
20 
21     REPO_SCHEMA = {PARAM_URL: str, PARAM_REV: str, PARAM_REV_LOCK: str}
22 
23     def __init__(self, def_repo, stage, *args, **kwargs):
24         self.def_repo = def_repo
25         super(DependencyREPO, self).__init__(stage, *args, **kwargs)
26 
27     def _parse_path(self, remote, path):
28         return None
29 
30     @property
31     def is_in_repo(self):
32         return False
33 
34     @property
35     def repo_pair(self):
36         d = self.def_repo
37         return d[self.PARAM_URL], d[self.PARAM_REV_LOCK] or d[self.PARAM_REV]
38 
39     def __str__(self):
40         return "{} ({})".format(self.def_path, self.def_repo[self.PARAM_URL])
41 
42     @contextmanager
43     def _make_repo(self, **overrides):
44         with external_repo(**merge(self.def_repo, overrides)) as repo:
45             yield repo
46 
47     def status(self):
48         with self._make_repo() as repo:
49             current = repo.find_out_by_relpath(self.def_path).info
50 
51         with self._make_repo(rev_lock=None) as repo:
52             updated = repo.find_out_by_relpath(self.def_path).info
53 
54         if current != updated:
55             return {str(self): "update available"}
56 
57         return {}
58 
59     def save(self):
60         pass
61 
62     def dumpd(self):
63         return {self.PARAM_PATH: self.def_path, self.PARAM_REPO: self.def_repo}
64 
65     def fetch(self):
66         with self._make_repo(
67             cache_dir=self.repo.cache.local.cache_dir
68         ) as repo:
69             self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()
70 
71             out = repo.find_out_by_relpath(self.def_path)
72             with repo.state:
73                 repo.cloud.pull(out.get_used_cache())
74 
75         return out
76 
77     @staticmethod
78     def _is_git_file(repo, path):
79         if not os.path.isabs(path):
80             try:
81                 output = repo.find_out_by_relpath(path)
82                 if not output.use_cache:
83                     return True
84             except OutputNotFoundError:
85                 return True
86         return False
87 
88     def _copy_if_git_file(self, to_path):
89         src_path = self.def_path
90         with self._make_repo(
91             cache_dir=self.repo.cache.local.cache_dir
92         ) as repo:
93             if not self._is_git_file(repo, src_path):
94                 return False
95 
96             src_full_path = os.path.join(repo.root_dir, src_path)
97             dst_full_path = os.path.abspath(to_path)
98             fs_copy(src_full_path, dst_full_path)
99         return True
100 
101     def download(self, to):
102         try:
103             if self._copy_if_git_file(to.fspath):
104                 return
105 
106             out = self.fetch()
107             to.info = copy.copy(out.info)
108             to.checkout()
109         except (FileNotFoundError):
110             raise PathMissingError(
111                 self.def_path, self.def_repo[self.PARAM_URL]
112             )
113 
114     def update(self):
115         with self._make_repo(rev_lock=None) as repo:
116             self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()
117
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/dvc/dependency/repo.py b/dvc/dependency/repo.py
--- a/dvc/dependency/repo.py
+++ b/dvc/dependency/repo.py
@@ -6,7 +6,9 @@
 from funcy import merge
 
 from .local import DependencyLOCAL
+from dvc.external_repo import cached_clone
 from dvc.external_repo import external_repo
+from dvc.exceptions import NotDvcRepoError
 from dvc.exceptions import OutputNotFoundError
 from dvc.exceptions import PathMissingError
 from dvc.utils.fs import fs_copy
@@ -75,27 +77,35 @@
         return out
 
     @staticmethod
-    def _is_git_file(repo, path):
-        if not os.path.isabs(path):
-            try:
-                output = repo.find_out_by_relpath(path)
-                if not output.use_cache:
-                    return True
-            except OutputNotFoundError:
-                return True
-        return False
+    def _is_git_file(repo_dir, path):
+        from dvc.repo import Repo
+
+        if os.path.isabs(path):
+            return False
+
+        try:
+            repo = Repo(repo_dir)
+        except NotDvcRepoError:
+            return True
+
+        try:
+            output = repo.find_out_by_relpath(path)
+            return not output.use_cache
+        except OutputNotFoundError:
+            return True
+        finally:
+            repo.close()
 
     def _copy_if_git_file(self, to_path):
         src_path = self.def_path
-        with self._make_repo(
-            cache_dir=self.repo.cache.local.cache_dir
-        ) as repo:
-            if not self._is_git_file(repo, src_path):
-                return False
+        repo_dir = cached_clone(**self.def_repo)
+
+        if not self._is_git_file(repo_dir, src_path):
+            return False
 
-            src_full_path = os.path.join(repo.root_dir, src_path)
-            dst_full_path = os.path.abspath(to_path)
-            fs_copy(src_full_path, dst_full_path)
+        src_full_path = os.path.join(repo_dir, src_path)
+        dst_full_path = os.path.abspath(to_path)
+        fs_copy(src_full_path, dst_full_path)
         return True
 
     def download(self, to):
diff --git a/dvc/external_repo.py b/dvc/external_repo.py
--- a/dvc/external_repo.py
+++ b/dvc/external_repo.py
@@ -33,18 +33,20 @@
     repo.close()
 
 
-def _external_repo(url=None, rev=None, cache_dir=None):
-    from dvc.config import Config
-    from dvc.cache import CacheConfig
-    from dvc.repo import Repo
+def cached_clone(url, rev=None, **_ignored_kwargs):
+    """Clone an external git repo to a temporary directory.
 
-    key = (url, rev, cache_dir)
-    if key in REPO_CACHE:
-        return REPO_CACHE[key]
+    Returns the path to a local temporary directory with the specified
+    revision checked out.
+
+    Uses the REPO_CACHE to avoid accessing the remote server again if
+    cloning from the same URL twice in the same session.
+
+    """
 
     new_path = tempfile.mkdtemp("dvc-erepo")
 
-    # Copy and adjust existing clone
+    # Copy and adjust existing clean clone
     if (url, None, None) in REPO_CACHE:
         old_path = REPO_CACHE[url, None, None]
 
@@ -59,13 +61,24 @@
         copy_tree(new_path, clean_clone_path)
         REPO_CACHE[url, None, None] = clean_clone_path
 
-    # Adjust new clone/copy to fit rev and cache_dir
-
-    # Checkout needs to be done first because current branch might not be
-    # DVC repository
+    # Check out the specified revision
     if rev is not None:
         _git_checkout(new_path, rev)
 
+    return new_path
+
+
+def _external_repo(url=None, rev=None, cache_dir=None):
+    from dvc.config import Config
+    from dvc.cache import CacheConfig
+    from dvc.repo import Repo
+
+    key = (url, rev, cache_dir)
+    if key in REPO_CACHE:
+        return REPO_CACHE[key]
+
+    new_path = cached_clone(url, rev=rev)
+
     repo = Repo(new_path)
     try:
         # check if the URL is local and no default remote is present

{"golden_diff": "diff --git a/dvc/dependency/repo.py b/dvc/dependency/repo.py\n--- a/dvc/dependency/repo.py\n+++ b/dvc/dependency/repo.py\n@@ -6,7 +6,9 @@\n from funcy import merge\n \n from .local import DependencyLOCAL\n+from dvc.external_repo import cached_clone\n from dvc.external_repo import external_repo\n+from dvc.exceptions import NotDvcRepoError\n from dvc.exceptions import OutputNotFoundError\n from dvc.exceptions import PathMissingError\n from dvc.utils.fs import fs_copy\n@@ -75,27 +77,35 @@\n         return out\n \n     @staticmethod\n-    def _is_git_file(repo, path):\n-        if not os.path.isabs(path):\n-            try:\n-                output = repo.find_out_by_relpath(path)\n-                if not output.use_cache:\n-                    return True\n-            except OutputNotFoundError:\n-                return True\n-        return False\n+    def _is_git_file(repo_dir, path):\n+        from dvc.repo import Repo\n+\n+        if os.path.isabs(path):\n+            return False\n+\n+        try:\n+            repo = Repo(repo_dir)\n+        except NotDvcRepoError:\n+            return True\n+\n+        try:\n+            output = repo.find_out_by_relpath(path)\n+            return not output.use_cache\n+        except OutputNotFoundError:\n+            return True\n+        finally:\n+            repo.close()\n \n     def _copy_if_git_file(self, to_path):\n         src_path = self.def_path\n-        with self._make_repo(\n-            cache_dir=self.repo.cache.local.cache_dir\n-        ) as repo:\n-            if not self._is_git_file(repo, src_path):\n-                return False\n+        repo_dir = cached_clone(**self.def_repo)\n+\n+        if not self._is_git_file(repo_dir, src_path):\n+            return False\n \n-            src_full_path = os.path.join(repo.root_dir, src_path)\n-            dst_full_path = os.path.abspath(to_path)\n-            fs_copy(src_full_path, dst_full_path)\n+        src_full_path = os.path.join(repo_dir, src_path)\n+        dst_full_path = os.path.abspath(to_path)\n+        fs_copy(src_full_path, dst_full_path)\n         return True\n \n     def download(self, to):\ndiff --git a/dvc/external_repo.py b/dvc/external_repo.py\n--- a/dvc/external_repo.py\n+++ b/dvc/external_repo.py\n@@ -33,18 +33,20 @@\n     repo.close()\n \n \n-def _external_repo(url=None, rev=None, cache_dir=None):\n-    from dvc.config import Config\n-    from dvc.cache import CacheConfig\n-    from dvc.repo import Repo\n+def cached_clone(url, rev=None, **_ignored_kwargs):\n+    \"\"\"Clone an external git repo to a temporary directory.\n \n-    key = (url, rev, cache_dir)\n-    if key in REPO_CACHE:\n-        return REPO_CACHE[key]\n+    Returns the path to a local temporary directory with the specified\n+    revision checked out.\n+\n+    Uses the REPO_CACHE to avoid accessing the remote server again if\n+    cloning from the same URL twice in the same session.\n+\n+    \"\"\"\n \n     new_path = tempfile.mkdtemp(\"dvc-erepo\")\n \n-    # Copy and adjust existing clone\n+    # Copy and adjust existing clean clone\n     if (url, None, None) in REPO_CACHE:\n         old_path = REPO_CACHE[url, None, None]\n \n@@ -59,13 +61,24 @@\n         copy_tree(new_path, clean_clone_path)\n         REPO_CACHE[url, None, None] = clean_clone_path\n \n-    # Adjust new clone/copy to fit rev and cache_dir\n-\n-    # Checkout needs to be done first because current branch might not be\n-    # DVC repository\n+    # Check out the specified revision\n     if rev is not None:\n         _git_checkout(new_path, rev)\n \n+    return new_path\n+\n+\n+def _external_repo(url=None, rev=None, cache_dir=None):\n+    from dvc.config import Config\n+    from dvc.cache import CacheConfig\n+    from dvc.repo import Repo\n+\n+    key = (url, rev, cache_dir)\n+    if key in REPO_CACHE:\n+        return REPO_CACHE[key]\n+\n+    new_path = cached_clone(url, rev=rev)\n+\n     repo = Repo(new_path)\n     try:\n         # check if the URL is local and no default remote is present\n", "issue": "import: Handle non-DVC Git repositories \nAfter https://github.com/iterative/dvc/pull/2889, `dvc import` can also import files that are tracked by Git but not DVC. DVC still requires that they come from a DVC repository rather than any Git repository, although there is no longer need for that.\n", "before_files": [{"content": "import os\nimport tempfile\nfrom contextlib import contextmanager\nfrom distutils.dir_util import copy_tree\n\nfrom funcy import retry\n\nfrom dvc.config import NoRemoteError, ConfigError\nfrom dvc.exceptions import NoRemoteInExternalRepoError\nfrom dvc.remote import RemoteConfig\nfrom dvc.exceptions import NoOutputInExternalRepoError\nfrom dvc.exceptions import OutputNotFoundError\nfrom dvc.utils.fs import remove\n\n\nREPO_CACHE = {}\n\n\n@contextmanager\ndef external_repo(url=None, rev=None, rev_lock=None, cache_dir=None):\n    from dvc.repo import Repo\n\n    path = _external_repo(url=url, rev=rev_lock or rev, cache_dir=cache_dir)\n    repo = Repo(path)\n    try:\n        yield repo\n    except NoRemoteError:\n        raise NoRemoteInExternalRepoError(url)\n    except OutputNotFoundError as exc:\n        if exc.repo is repo:\n            raise NoOutputInExternalRepoError(exc.output, repo.root_dir, url)\n        raise\n    repo.close()\n\n\ndef _external_repo(url=None, rev=None, cache_dir=None):\n    from dvc.config import Config\n    from dvc.cache import CacheConfig\n    from dvc.repo import Repo\n\n    key = (url, rev, cache_dir)\n    if key in REPO_CACHE:\n        return REPO_CACHE[key]\n\n    new_path = tempfile.mkdtemp(\"dvc-erepo\")\n\n    # Copy and adjust existing clone\n    if (url, None, None) in REPO_CACHE:\n        old_path = REPO_CACHE[url, None, None]\n\n        # This one unlike shutil.copytree() works with an existing dir\n        copy_tree(old_path, new_path)\n    else:\n        # Create a new clone\n        _clone_repo(url, new_path)\n\n        # Save clean clone dir so that we will have access to a default branch\n        clean_clone_path = tempfile.mkdtemp(\"dvc-erepo\")\n        copy_tree(new_path, clean_clone_path)\n        REPO_CACHE[url, None, None] = clean_clone_path\n\n    # Adjust new clone/copy to fit rev and cache_dir\n\n    # Checkout needs to be done first because current branch might not be\n    # DVC repository\n    if rev is not None:\n        _git_checkout(new_path, rev)\n\n    repo = Repo(new_path)\n    try:\n        # check if the URL is local and no default remote is present\n        # add default remote pointing to the original repo's cache location\n        if os.path.isdir(url):\n            rconfig = RemoteConfig(repo.config)\n            if not _default_remote_set(rconfig):\n                original_repo = Repo(url)\n                try:\n                    rconfig.add(\n                        \"auto-generated-upstream\",\n                        original_repo.cache.local.cache_dir,\n                        default=True,\n                        level=Config.LEVEL_LOCAL,\n                    )\n                finally:\n                    original_repo.close()\n\n        if cache_dir is not None:\n            cache_config = CacheConfig(repo.config)\n            cache_config.set_dir(cache_dir, level=Config.LEVEL_LOCAL)\n    finally:\n        # Need to close/reopen repo to force config reread\n        repo.close()\n\n    REPO_CACHE[key] = new_path\n    return new_path\n\n\ndef _git_checkout(repo_path, revision):\n    from dvc.scm import Git\n\n    git = Git(repo_path)\n    try:\n        git.checkout(revision)\n    finally:\n        git.close()\n\n\ndef clean_repos():\n    # Outside code should not see cache while we are removing\n    repo_paths = list(REPO_CACHE.values())\n    REPO_CACHE.clear()\n\n    for path in repo_paths:\n        _remove(path)\n\n\ndef _remove(path):\n    if os.name == \"nt\":\n        # git.exe may hang for a while not permitting to remove temp dir\n        os_retry = retry(5, errors=OSError, timeout=0.1)\n        os_retry(remove)(path)\n    else:\n        remove(path)\n\n\ndef _clone_repo(url, path):\n    from dvc.scm.git import Git\n\n    git = Git.clone(url, path)\n    git.close()\n\n\ndef _default_remote_set(rconfig):\n    \"\"\"\n    Checks if default remote config is present.\n    Args:\n        rconfig: a remote config\n\n    Returns:\n        True if the default remote config is set, else False\n    \"\"\"\n    try:\n        rconfig.get_default()\n        return True\n    except ConfigError:\n        return False\n", "path": "dvc/external_repo.py"}, {"content": "import copy\nimport os\nfrom contextlib import contextmanager\nfrom dvc.utils.compat import FileNotFoundError\n\nfrom funcy import merge\n\nfrom .local import DependencyLOCAL\nfrom dvc.external_repo import external_repo\nfrom dvc.exceptions import OutputNotFoundError\nfrom dvc.exceptions import PathMissingError\nfrom dvc.utils.fs import fs_copy\n\n\nclass DependencyREPO(DependencyLOCAL):\n    PARAM_REPO = \"repo\"\n    PARAM_URL = \"url\"\n    PARAM_REV = \"rev\"\n    PARAM_REV_LOCK = \"rev_lock\"\n\n    REPO_SCHEMA = {PARAM_URL: str, PARAM_REV: str, PARAM_REV_LOCK: str}\n\n    def __init__(self, def_repo, stage, *args, **kwargs):\n        self.def_repo = def_repo\n        super(DependencyREPO, self).__init__(stage, *args, **kwargs)\n\n    def _parse_path(self, remote, path):\n        return None\n\n    @property\n    def is_in_repo(self):\n        return False\n\n    @property\n    def repo_pair(self):\n        d = self.def_repo\n        return d[self.PARAM_URL], d[self.PARAM_REV_LOCK] or d[self.PARAM_REV]\n\n    def __str__(self):\n        return \"{} ({})\".format(self.def_path, self.def_repo[self.PARAM_URL])\n\n    @contextmanager\n    def _make_repo(self, **overrides):\n        with external_repo(**merge(self.def_repo, overrides)) as repo:\n            yield repo\n\n    def status(self):\n        with self._make_repo() as repo:\n            current = repo.find_out_by_relpath(self.def_path).info\n\n        with self._make_repo(rev_lock=None) as repo:\n            updated = repo.find_out_by_relpath(self.def_path).info\n\n        if current != updated:\n            return {str(self): \"update available\"}\n\n        return {}\n\n    def save(self):\n        pass\n\n    def dumpd(self):\n        return {self.PARAM_PATH: self.def_path, self.PARAM_REPO: self.def_repo}\n\n    def fetch(self):\n        with self._make_repo(\n            cache_dir=self.repo.cache.local.cache_dir\n        ) as repo:\n            self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()\n\n            out = repo.find_out_by_relpath(self.def_path)\n            with repo.state:\n                repo.cloud.pull(out.get_used_cache())\n\n        return out\n\n    @staticmethod\n    def _is_git_file(repo, path):\n        if not os.path.isabs(path):\n            try:\n                output = repo.find_out_by_relpath(path)\n                if not output.use_cache:\n                    return True\n            except OutputNotFoundError:\n                return True\n        return False\n\n    def _copy_if_git_file(self, to_path):\n        src_path = self.def_path\n        with self._make_repo(\n            cache_dir=self.repo.cache.local.cache_dir\n        ) as repo:\n            if not self._is_git_file(repo, src_path):\n                return False\n\n            src_full_path = os.path.join(repo.root_dir, src_path)\n            dst_full_path = os.path.abspath(to_path)\n            fs_copy(src_full_path, dst_full_path)\n        return True\n\n    def download(self, to):\n        try:\n            if self._copy_if_git_file(to.fspath):\n                return\n\n            out = self.fetch()\n            to.info = copy.copy(out.info)\n            to.checkout()\n        except (FileNotFoundError):\n            raise PathMissingError(\n                self.def_path, self.def_repo[self.PARAM_URL]\n            )\n\n    def update(self):\n        with self._make_repo(rev_lock=None) as repo:\n            self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()\n", "path": "dvc/dependency/repo.py"}], "after_files": [{"content": "import os\nimport tempfile\nfrom contextlib import contextmanager\nfrom distutils.dir_util import copy_tree\n\nfrom funcy import retry\n\nfrom dvc.config import NoRemoteError, ConfigError\nfrom dvc.exceptions import NoRemoteInExternalRepoError\nfrom dvc.remote import RemoteConfig\nfrom dvc.exceptions import NoOutputInExternalRepoError\nfrom dvc.exceptions import OutputNotFoundError\nfrom dvc.utils.fs import remove\n\n\nREPO_CACHE = {}\n\n\n@contextmanager\ndef external_repo(url=None, rev=None, rev_lock=None, cache_dir=None):\n    from dvc.repo import Repo\n\n    path = _external_repo(url=url, rev=rev_lock or rev, cache_dir=cache_dir)\n    repo = Repo(path)\n    try:\n        yield repo\n    except NoRemoteError:\n        raise NoRemoteInExternalRepoError(url)\n    except OutputNotFoundError as exc:\n        if exc.repo is repo:\n            raise NoOutputInExternalRepoError(exc.output, repo.root_dir, url)\n        raise\n    repo.close()\n\n\ndef cached_clone(url, rev=None, **_ignored_kwargs):\n    \"\"\"Clone an external git repo to a temporary directory.\n\n    Returns the path to a local temporary directory with the specified\n    revision checked out.\n\n    Uses the REPO_CACHE to avoid accessing the remote server again if\n    cloning from the same URL twice in the same session.\n\n    \"\"\"\n\n    new_path = tempfile.mkdtemp(\"dvc-erepo\")\n\n    # Copy and adjust existing clean clone\n    if (url, None, None) in REPO_CACHE:\n        old_path = REPO_CACHE[url, None, None]\n\n        # This one unlike shutil.copytree() works with an existing dir\n        copy_tree(old_path, new_path)\n    else:\n        # Create a new clone\n        _clone_repo(url, new_path)\n\n        # Save clean clone dir so that we will have access to a default branch\n        clean_clone_path = tempfile.mkdtemp(\"dvc-erepo\")\n        copy_tree(new_path, clean_clone_path)\n        REPO_CACHE[url, None, None] = clean_clone_path\n\n    # Check out the specified revision\n    if rev is not None:\n        _git_checkout(new_path, rev)\n\n    return new_path\n\n\ndef _external_repo(url=None, rev=None, cache_dir=None):\n    from dvc.config import Config\n    from dvc.cache import CacheConfig\n    from dvc.repo import Repo\n\n    key = (url, rev, cache_dir)\n    if key in REPO_CACHE:\n        return REPO_CACHE[key]\n\n    new_path = cached_clone(url, rev=rev)\n\n    repo = Repo(new_path)\n    try:\n        # check if the URL is local and no default remote is present\n        # add default remote pointing to the original repo's cache location\n        if os.path.isdir(url):\n            rconfig = RemoteConfig(repo.config)\n            if not _default_remote_set(rconfig):\n                original_repo = Repo(url)\n                try:\n                    rconfig.add(\n                        \"auto-generated-upstream\",\n                        original_repo.cache.local.cache_dir,\n                        default=True,\n                        level=Config.LEVEL_LOCAL,\n                    )\n                finally:\n                    original_repo.close()\n\n        if cache_dir is not None:\n            cache_config = CacheConfig(repo.config)\n            cache_config.set_dir(cache_dir, level=Config.LEVEL_LOCAL)\n    finally:\n        # Need to close/reopen repo to force config reread\n        repo.close()\n\n    REPO_CACHE[key] = new_path\n    return new_path\n\n\ndef _git_checkout(repo_path, revision):\n    from dvc.scm import Git\n\n    git = Git(repo_path)\n    try:\n        git.checkout(revision)\n    finally:\n        git.close()\n\n\ndef clean_repos():\n    # Outside code should not see cache while we are removing\n    repo_paths = list(REPO_CACHE.values())\n    REPO_CACHE.clear()\n\n    for path in repo_paths:\n        _remove(path)\n\n\ndef _remove(path):\n    if os.name == \"nt\":\n        # git.exe may hang for a while not permitting to remove temp dir\n        os_retry = retry(5, errors=OSError, timeout=0.1)\n        os_retry(remove)(path)\n    else:\n        remove(path)\n\n\ndef _clone_repo(url, path):\n    from dvc.scm.git import Git\n\n    git = Git.clone(url, path)\n    git.close()\n\n\ndef _default_remote_set(rconfig):\n    \"\"\"\n    Checks if default remote config is present.\n    Args:\n        rconfig: a remote config\n\n    Returns:\n        True if the default remote config is set, else False\n    \"\"\"\n    try:\n        rconfig.get_default()\n        return True\n    except ConfigError:\n        return False\n", "path": "dvc/external_repo.py"}, {"content": "import copy\nimport os\nfrom contextlib import contextmanager\nfrom dvc.utils.compat import FileNotFoundError\n\nfrom funcy import merge\n\nfrom .local import DependencyLOCAL\nfrom dvc.external_repo import cached_clone\nfrom dvc.external_repo import external_repo\nfrom dvc.exceptions import NotDvcRepoError\nfrom dvc.exceptions import OutputNotFoundError\nfrom dvc.exceptions import PathMissingError\nfrom dvc.utils.fs import fs_copy\n\n\nclass DependencyREPO(DependencyLOCAL):\n    PARAM_REPO = \"repo\"\n    PARAM_URL = \"url\"\n    PARAM_REV = \"rev\"\n    PARAM_REV_LOCK = \"rev_lock\"\n\n    REPO_SCHEMA = {PARAM_URL: str, PARAM_REV: str, PARAM_REV_LOCK: str}\n\n    def __init__(self, def_repo, stage, *args, **kwargs):\n        self.def_repo = def_repo\n        super(DependencyREPO, self).__init__(stage, *args, **kwargs)\n\n    def _parse_path(self, remote, path):\n        return None\n\n    @property\n    def is_in_repo(self):\n        return False\n\n    @property\n    def repo_pair(self):\n        d = self.def_repo\n        return d[self.PARAM_URL], d[self.PARAM_REV_LOCK] or d[self.PARAM_REV]\n\n    def __str__(self):\n        return \"{} ({})\".format(self.def_path, self.def_repo[self.PARAM_URL])\n\n    @contextmanager\n    def _make_repo(self, **overrides):\n        with external_repo(**merge(self.def_repo, overrides)) as repo:\n            yield repo\n\n    def status(self):\n        with self._make_repo() as repo:\n            current = repo.find_out_by_relpath(self.def_path).info\n\n        with self._make_repo(rev_lock=None) as repo:\n            updated = repo.find_out_by_relpath(self.def_path).info\n\n        if current != updated:\n            return {str(self): \"update available\"}\n\n        return {}\n\n    def save(self):\n        pass\n\n    def dumpd(self):\n        return {self.PARAM_PATH: self.def_path, self.PARAM_REPO: self.def_repo}\n\n    def fetch(self):\n        with self._make_repo(\n            cache_dir=self.repo.cache.local.cache_dir\n        ) as repo:\n            self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()\n\n            out = repo.find_out_by_relpath(self.def_path)\n            with repo.state:\n                repo.cloud.pull(out.get_used_cache())\n\n        return out\n\n    @staticmethod\n    def _is_git_file(repo_dir, path):\n        from dvc.repo import Repo\n\n        if os.path.isabs(path):\n            return False\n\n        try:\n            repo = Repo(repo_dir)\n        except NotDvcRepoError:\n            return True\n\n        try:\n            output = repo.find_out_by_relpath(path)\n            return not output.use_cache\n        except OutputNotFoundError:\n            return True\n        finally:\n            repo.close()\n\n    def _copy_if_git_file(self, to_path):\n        src_path = self.def_path\n        repo_dir = cached_clone(**self.def_repo)\n\n        if not self._is_git_file(repo_dir, src_path):\n            return False\n\n        src_full_path = os.path.join(repo_dir, src_path)\n        dst_full_path = os.path.abspath(to_path)\n        fs_copy(src_full_path, dst_full_path)\n        return True\n\n    def download(self, to):\n        try:\n            if self._copy_if_git_file(to.fspath):\n                return\n\n            out = self.fetch()\n            to.info = copy.copy(out.info)\n            to.checkout()\n        except (FileNotFoundError):\n            raise PathMissingError(\n                self.def_path, self.def_repo[self.PARAM_URL]\n            )\n\n    def update(self):\n        with self._make_repo(rev_lock=None) as repo:\n            self.def_repo[self.PARAM_REV_LOCK] = repo.scm.get_rev()\n", "path": "dvc/dependency/repo.py"}]}