We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add a test for partial repro, when first few steps do not require reproduction


--- 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/repository_change.py`
Content:
```
1 import os
2 
3 from dvc.exceptions import DvcException
4 from dvc.git_wrapper import GitWrapper
5 from dvc.executor import Executor
6 from dvc.logger import Logger
7 from dvc.path.data_item import DataDirError, DataItemInStatusDirError
8 from dvc.path.stated_data_item import StatedDataItem
9 from dvc.utils import cached_property
10 from dvc.config import ConfigI
11 
12 class RepositoryChangeError(DvcException):
13     def __init__(self, msg):
14         DvcException.__init__(self, 'Repository change error: {}'.format(msg))
15 
16 
17 class RepositoryChange(object):
18     """Pre-condition: git repository has no changes"""
19 
20     def __init__(self, command, settings, stdout, stderr, shell=False):
21         self._settings = settings
22 
23         stemps_before = self.data_file_timesteps()
24 
25         Logger.debug(u'[Repository change] Exec command: {}. stdout={}, stderr={}, shell={}'.format(
26                      command,
27                      stdout,
28                      stderr,
29                      shell))
30         Executor.exec_cmd_only_success(command.split(' '), stdout, stderr, shell=shell)
31 
32         stemps_after = self.data_file_timesteps()
33 
34         sym_diff = stemps_after ^ stemps_before
35         self._modified_content_filenames = set([filename for filename, timestemp in sym_diff])
36 
37         Logger.debug(u'[Repository change] Identified modifications: {}'.format(
38                      u', '.join(self._modified_content_filenames)))
39 
40         self._stated_data_items = []
41         self._externally_created_files = []
42         self._created_status_files = []
43         self._init_file_states()
44 
45     @property
46     def modified_content_data_items(self):
47         return [self._settings.path_factory.data_item(file) for file in self._modified_content_filenames]
48 
49     @cached_property
50     def removed_data_items(self):
51         return [x for x in self._stated_data_items if x.is_removed]
52 
53     @cached_property
54     def modified_data_items(self):
55         return [x for x in self._stated_data_items if x.is_modified]
56 
57     @cached_property
58     def new_data_items(self):
59         return [x for x in self._stated_data_items if x.is_new]
60 
61     @cached_property
62     def unusual_data_items(self):
63         return [x for x in self._stated_data_items if x.is_unusual]
64 
65     @property
66     def changed_data_items(self):
67         res = set(self.new_data_items + self.modified_data_items + self.modified_content_data_items)
68         return list(res)
69 
70     def _add_stated_data_item(self, state, file):
71         try:
72             item = self._settings.path_factory.stated_data_item(state, file)
73             self._stated_data_items.append(item)
74             Logger.debug('[Repository change] Add status: {} {}'.format(
75                          item.status,
76                          item.data.dvc))
77         except DataItemInStatusDirError:
78             self._created_status_files.append(file)
79         except DataDirError:
80             self._externally_created_files.append(file)
81         pass
82 
83     def _init_file_states(self):
84         statuses = GitWrapper.git_file_statuses()
85 
86         for status, file in statuses:
87             file_path = os.path.join(self._settings.git.git_dir_abs, file)
88 
89             if not os.path.isdir(file_path):
90                 self._add_stated_data_item(status, file_path)
91             else:
92                 files = []
93                 self.get_all_files_from_dir(file_path, files)
94                 state = StatedDataItem.STATUS_UNTRACKED + StatedDataItem.STATUS_UNTRACKED
95                 for f in files:
96                     self._add_stated_data_item(state, f)
97         pass
98 
99     def get_all_files_from_dir(self, dir, result):
100         files = os.listdir(dir)
101         for f in files:
102             path = os.path.join(dir, f)
103             if os.path.isfile(path):
104                 result.append(path)
105             else:
106                 self.get_all_files_from_dir(path, result)
107         pass
108 
109     @property
110     def externally_created_files(self):
111         return self._externally_created_files
112 
113     @property
114     def created_status_files(self):
115         return self._created_status_files
116 
117     def data_file_timesteps(self):
118         res = set()
119         for root, dirs, files in os.walk(self._settings.git.git_dir_abs):
120             if root.startswith(os.path.join(self._settings.git.git_dir_abs, ConfigI.CONFIG_DIR)):
121                 continue
122 
123             for file in files:
124                 filename = os.path.join(root, file)
125                 if os.path.exists(filename):
126                     timestemp = os.path.getmtime(filename)
127                     res.add((filename, timestemp))
128 
129         return res
130
```

Path: `dvc/path/data_item.py`
Content:
```
1 import os
2 import stat
3 
4 from dvc.config import ConfigI
5 from dvc.path.path import Path
6 from dvc.exceptions import DvcException
7 from dvc.system import System
8 from dvc.utils import cached_property
9 from dvc.data_cloud import file_md5
10 from dvc.state_file import CacheStateFile, LocalStateFile
11 
12 
13 class DataItemError(DvcException):
14     def __init__(self, msg):
15         super(DataItemError, self).__init__('Data item error: {}'.format(msg))
16 
17 
18 class DataDirError(DvcException):
19     def __init__(self, msg):
20         super(DataDirError, self).__init__(msg)
21 
22 
23 class DataItemInStatusDirError(DataDirError):
24     def __init__(self, file):
25         msg = 'File "{}" is in state directory'.format(file)
26         super(DataItemInStatusDirError, self).__init__(msg)
27 
28 
29 class NotInGitDirError(DataDirError):
30     def __init__(self, file, git_dir):
31         msg = 'File "{}" is not in git directory "{}"'.format(file, git_dir)
32         super(NotInGitDirError, self).__init__(msg)
33 
34 
35 class DataItem(object):
36     STATE_FILE_SUFFIX = '.state'
37     LOCAL_STATE_FILE_SUFFIX = '.local_state'
38     CACHE_STATE_FILE_SUFFIX = '.cache_state'
39     CACHE_FILE_SEP = '_'
40 
41     def __init__(self, data_file, git, config, cache_file=None):
42         self._git = git
43         self._config = config
44         self._cache_file = cache_file
45 
46         self._data = Path(data_file, git)
47 
48         if not self._data.abs.startswith(self._git.git_dir_abs):
49             raise NotInGitDirError(data_file, self._git.git_dir_abs)
50 
51         if self._data.abs.startswith(self.state_dir_abs):
52             raise DataItemInStatusDirError(data_file)
53 
54         pass
55 
56     def copy(self, cache_file=None):
57         if not cache_file:
58             cache_file = self._cache_file
59 
60         return DataItem(self._data.abs, self._git, self._config, cache_file)
61 
62     def __hash__(self):
63         return self.data.dvc.__hash__()
64 
65     def __eq__(self, other):
66         if other == None:
67             return False
68 
69         return self.data.dvc == other.data.dvc
70 
71     @property
72     def data(self):
73         return self._data
74 
75     @cached_property
76     def state_dir(self):
77         return os.path.join(self._git.git_dir_abs, self._config.state_dir)
78 
79     def _state(self, suffix):
80         state_file = os.path.join(self.state_dir, self.data.dvc + suffix)
81         return Path(state_file, self._git)
82 
83     @cached_property
84     def state(self):
85         return self._state(self.STATE_FILE_SUFFIX)
86 
87     @cached_property
88     def cache_dir_abs(self):
89         return os.path.join(self._git.git_dir_abs, ConfigI.CACHE_DIR)
90 
91     @cached_property
92     def local_state(self):
93         return self._state(self.LOCAL_STATE_FILE_SUFFIX)
94 
95     @cached_property
96     def cache_state(self):
97         return self._state(self.CACHE_STATE_FILE_SUFFIX)
98 
99     @cached_property
100     def cache_dir(self):
101         return os.path.join(self._git.git_dir_abs, self._config.cache_dir)
102 
103     @property
104     def cache(self):
105         cache_dir = self.cache_dir_abs
106 
107         if self._cache_file:
108             file_name = os.path.relpath(os.path.realpath(self._cache_file), cache_dir)
109         else:
110             file_name = CacheStateFile.load(self).md5
111 
112         cache_file = os.path.join(cache_dir, file_name)
113         return Path(cache_file, self._git)
114 
115     @cached_property
116     def state_dir_abs(self):
117         return os.path.join(self._git.git_dir_abs, ConfigI.STATE_DIR)
118 
119     def move_data_to_cache(self):
120         md5 = file_md5(self.data.relative)[0]
121         self._cache_file = os.path.join(self.cache_dir_abs, md5)
122         self._git.modify_gitignore([self.data.relative])
123         if not os.path.isfile(self.cache.relative):
124             System.hardlink(self.data.relative, self.cache.relative)
125         os.chmod(self.data.relative, stat.S_IREAD)
126 
127         cache_state = CacheStateFile(self).save()
128 
129         local_state = LocalStateFile(self).save()
130         self._git.modify_gitignore([self.local_state.relative])
131
```
--- 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/path/data_item.py b/dvc/path/data_item.py
--- a/dvc/path/data_item.py
+++ b/dvc/path/data_item.py
@@ -20,9 +20,9 @@
         super(DataDirError, self).__init__(msg)
 
 
-class DataItemInStatusDirError(DataDirError):
+class DataItemInConfigDirError(DataDirError):
     def __init__(self, file):
-        msg = 'File "{}" is in state directory'.format(file)
+        msg = 'File "{}" is in config directory'.format(file)
         super(DataItemInStatusDirError, self).__init__(msg)
 
 
@@ -48,10 +48,8 @@
         if not self._data.abs.startswith(self._git.git_dir_abs):
             raise NotInGitDirError(data_file, self._git.git_dir_abs)
 
-        if self._data.abs.startswith(self.state_dir_abs):
-            raise DataItemInStatusDirError(data_file)
-
-        pass
+        if self._data.abs.startswith(os.path.join(self._git.git_dir_abs, self._config.CONFIG_DIR)):
+            raise DataItemInConfigDirError(data_file)
 
     def copy(self, cache_file=None):
         if not cache_file:
diff --git a/dvc/repository_change.py b/dvc/repository_change.py
--- a/dvc/repository_change.py
+++ b/dvc/repository_change.py
@@ -4,7 +4,7 @@
 from dvc.git_wrapper import GitWrapper
 from dvc.executor import Executor
 from dvc.logger import Logger
-from dvc.path.data_item import DataDirError, DataItemInStatusDirError
+from dvc.path.data_item import DataDirError, DataItemInConfigDirError
 from dvc.path.stated_data_item import StatedDataItem
 from dvc.utils import cached_property
 from dvc.config import ConfigI
@@ -74,7 +74,7 @@
             Logger.debug('[Repository change] Add status: {} {}'.format(
                          item.status,
                          item.data.dvc))
-        except DataItemInStatusDirError:
+        except DataItemInConfigDirError:
             self._created_status_files.append(file)
         except DataDirError:
             self._externally_created_files.append(file)

{"golden_diff": "diff --git a/dvc/path/data_item.py b/dvc/path/data_item.py\n--- a/dvc/path/data_item.py\n+++ b/dvc/path/data_item.py\n@@ -20,9 +20,9 @@\n         super(DataDirError, self).__init__(msg)\n \n \n-class DataItemInStatusDirError(DataDirError):\n+class DataItemInConfigDirError(DataDirError):\n     def __init__(self, file):\n-        msg = 'File \"{}\" is in state directory'.format(file)\n+        msg = 'File \"{}\" is in config directory'.format(file)\n         super(DataItemInStatusDirError, self).__init__(msg)\n \n \n@@ -48,10 +48,8 @@\n         if not self._data.abs.startswith(self._git.git_dir_abs):\n             raise NotInGitDirError(data_file, self._git.git_dir_abs)\n \n-        if self._data.abs.startswith(self.state_dir_abs):\n-            raise DataItemInStatusDirError(data_file)\n-\n-        pass\n+        if self._data.abs.startswith(os.path.join(self._git.git_dir_abs, self._config.CONFIG_DIR)):\n+            raise DataItemInConfigDirError(data_file)\n \n     def copy(self, cache_file=None):\n         if not cache_file:\ndiff --git a/dvc/repository_change.py b/dvc/repository_change.py\n--- a/dvc/repository_change.py\n+++ b/dvc/repository_change.py\n@@ -4,7 +4,7 @@\n from dvc.git_wrapper import GitWrapper\n from dvc.executor import Executor\n from dvc.logger import Logger\n-from dvc.path.data_item import DataDirError, DataItemInStatusDirError\n+from dvc.path.data_item import DataDirError, DataItemInConfigDirError\n from dvc.path.stated_data_item import StatedDataItem\n from dvc.utils import cached_property\n from dvc.config import ConfigI\n@@ -74,7 +74,7 @@\n             Logger.debug('[Repository change] Add status: {} {}'.format(\n                          item.status,\n                          item.data.dvc))\n-        except DataItemInStatusDirError:\n+        except DataItemInConfigDirError:\n             self._created_status_files.append(file)\n         except DataDirError:\n             self._externally_created_files.append(file)\n", "issue": "Add a test for partial repro, when first few steps do not require reproduction\n\n", "before_files": [{"content": "import os\n\nfrom dvc.exceptions import DvcException\nfrom dvc.git_wrapper import GitWrapper\nfrom dvc.executor import Executor\nfrom dvc.logger import Logger\nfrom dvc.path.data_item import DataDirError, DataItemInStatusDirError\nfrom dvc.path.stated_data_item import StatedDataItem\nfrom dvc.utils import cached_property\nfrom dvc.config import ConfigI\n\nclass RepositoryChangeError(DvcException):\n    def __init__(self, msg):\n        DvcException.__init__(self, 'Repository change error: {}'.format(msg))\n\n\nclass RepositoryChange(object):\n    \"\"\"Pre-condition: git repository has no changes\"\"\"\n\n    def __init__(self, command, settings, stdout, stderr, shell=False):\n        self._settings = settings\n\n        stemps_before = self.data_file_timesteps()\n\n        Logger.debug(u'[Repository change] Exec command: {}. stdout={}, stderr={}, shell={}'.format(\n                     command,\n                     stdout,\n                     stderr,\n                     shell))\n        Executor.exec_cmd_only_success(command.split(' '), stdout, stderr, shell=shell)\n\n        stemps_after = self.data_file_timesteps()\n\n        sym_diff = stemps_after ^ stemps_before\n        self._modified_content_filenames = set([filename for filename, timestemp in sym_diff])\n\n        Logger.debug(u'[Repository change] Identified modifications: {}'.format(\n                     u', '.join(self._modified_content_filenames)))\n\n        self._stated_data_items = []\n        self._externally_created_files = []\n        self._created_status_files = []\n        self._init_file_states()\n\n    @property\n    def modified_content_data_items(self):\n        return [self._settings.path_factory.data_item(file) for file in self._modified_content_filenames]\n\n    @cached_property\n    def removed_data_items(self):\n        return [x for x in self._stated_data_items if x.is_removed]\n\n    @cached_property\n    def modified_data_items(self):\n        return [x for x in self._stated_data_items if x.is_modified]\n\n    @cached_property\n    def new_data_items(self):\n        return [x for x in self._stated_data_items if x.is_new]\n\n    @cached_property\n    def unusual_data_items(self):\n        return [x for x in self._stated_data_items if x.is_unusual]\n\n    @property\n    def changed_data_items(self):\n        res = set(self.new_data_items + self.modified_data_items + self.modified_content_data_items)\n        return list(res)\n\n    def _add_stated_data_item(self, state, file):\n        try:\n            item = self._settings.path_factory.stated_data_item(state, file)\n            self._stated_data_items.append(item)\n            Logger.debug('[Repository change] Add status: {} {}'.format(\n                         item.status,\n                         item.data.dvc))\n        except DataItemInStatusDirError:\n            self._created_status_files.append(file)\n        except DataDirError:\n            self._externally_created_files.append(file)\n        pass\n\n    def _init_file_states(self):\n        statuses = GitWrapper.git_file_statuses()\n\n        for status, file in statuses:\n            file_path = os.path.join(self._settings.git.git_dir_abs, file)\n\n            if not os.path.isdir(file_path):\n                self._add_stated_data_item(status, file_path)\n            else:\n                files = []\n                self.get_all_files_from_dir(file_path, files)\n                state = StatedDataItem.STATUS_UNTRACKED + StatedDataItem.STATUS_UNTRACKED\n                for f in files:\n                    self._add_stated_data_item(state, f)\n        pass\n\n    def get_all_files_from_dir(self, dir, result):\n        files = os.listdir(dir)\n        for f in files:\n            path = os.path.join(dir, f)\n            if os.path.isfile(path):\n                result.append(path)\n            else:\n                self.get_all_files_from_dir(path, result)\n        pass\n\n    @property\n    def externally_created_files(self):\n        return self._externally_created_files\n\n    @property\n    def created_status_files(self):\n        return self._created_status_files\n\n    def data_file_timesteps(self):\n        res = set()\n        for root, dirs, files in os.walk(self._settings.git.git_dir_abs):\n            if root.startswith(os.path.join(self._settings.git.git_dir_abs, ConfigI.CONFIG_DIR)):\n                continue\n\n            for file in files:\n                filename = os.path.join(root, file)\n                if os.path.exists(filename):\n                    timestemp = os.path.getmtime(filename)\n                    res.add((filename, timestemp))\n\n        return res\n", "path": "dvc/repository_change.py"}, {"content": "import os\nimport stat\n\nfrom dvc.config import ConfigI\nfrom dvc.path.path import Path\nfrom dvc.exceptions import DvcException\nfrom dvc.system import System\nfrom dvc.utils import cached_property\nfrom dvc.data_cloud import file_md5\nfrom dvc.state_file import CacheStateFile, LocalStateFile\n\n\nclass DataItemError(DvcException):\n    def __init__(self, msg):\n        super(DataItemError, self).__init__('Data item error: {}'.format(msg))\n\n\nclass DataDirError(DvcException):\n    def __init__(self, msg):\n        super(DataDirError, self).__init__(msg)\n\n\nclass DataItemInStatusDirError(DataDirError):\n    def __init__(self, file):\n        msg = 'File \"{}\" is in state directory'.format(file)\n        super(DataItemInStatusDirError, self).__init__(msg)\n\n\nclass NotInGitDirError(DataDirError):\n    def __init__(self, file, git_dir):\n        msg = 'File \"{}\" is not in git directory \"{}\"'.format(file, git_dir)\n        super(NotInGitDirError, self).__init__(msg)\n\n\nclass DataItem(object):\n    STATE_FILE_SUFFIX = '.state'\n    LOCAL_STATE_FILE_SUFFIX = '.local_state'\n    CACHE_STATE_FILE_SUFFIX = '.cache_state'\n    CACHE_FILE_SEP = '_'\n\n    def __init__(self, data_file, git, config, cache_file=None):\n        self._git = git\n        self._config = config\n        self._cache_file = cache_file\n\n        self._data = Path(data_file, git)\n\n        if not self._data.abs.startswith(self._git.git_dir_abs):\n            raise NotInGitDirError(data_file, self._git.git_dir_abs)\n\n        if self._data.abs.startswith(self.state_dir_abs):\n            raise DataItemInStatusDirError(data_file)\n\n        pass\n\n    def copy(self, cache_file=None):\n        if not cache_file:\n            cache_file = self._cache_file\n\n        return DataItem(self._data.abs, self._git, self._config, cache_file)\n\n    def __hash__(self):\n        return self.data.dvc.__hash__()\n\n    def __eq__(self, other):\n        if other == None:\n            return False\n\n        return self.data.dvc == other.data.dvc\n\n    @property\n    def data(self):\n        return self._data\n\n    @cached_property\n    def state_dir(self):\n        return os.path.join(self._git.git_dir_abs, self._config.state_dir)\n\n    def _state(self, suffix):\n        state_file = os.path.join(self.state_dir, self.data.dvc + suffix)\n        return Path(state_file, self._git)\n\n    @cached_property\n    def state(self):\n        return self._state(self.STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_dir_abs(self):\n        return os.path.join(self._git.git_dir_abs, ConfigI.CACHE_DIR)\n\n    @cached_property\n    def local_state(self):\n        return self._state(self.LOCAL_STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_state(self):\n        return self._state(self.CACHE_STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_dir(self):\n        return os.path.join(self._git.git_dir_abs, self._config.cache_dir)\n\n    @property\n    def cache(self):\n        cache_dir = self.cache_dir_abs\n\n        if self._cache_file:\n            file_name = os.path.relpath(os.path.realpath(self._cache_file), cache_dir)\n        else:\n            file_name = CacheStateFile.load(self).md5\n\n        cache_file = os.path.join(cache_dir, file_name)\n        return Path(cache_file, self._git)\n\n    @cached_property\n    def state_dir_abs(self):\n        return os.path.join(self._git.git_dir_abs, ConfigI.STATE_DIR)\n\n    def move_data_to_cache(self):\n        md5 = file_md5(self.data.relative)[0]\n        self._cache_file = os.path.join(self.cache_dir_abs, md5)\n        self._git.modify_gitignore([self.data.relative])\n        if not os.path.isfile(self.cache.relative):\n            System.hardlink(self.data.relative, self.cache.relative)\n        os.chmod(self.data.relative, stat.S_IREAD)\n\n        cache_state = CacheStateFile(self).save()\n\n        local_state = LocalStateFile(self).save()\n        self._git.modify_gitignore([self.local_state.relative])\n", "path": "dvc/path/data_item.py"}], "after_files": [{"content": "import os\n\nfrom dvc.exceptions import DvcException\nfrom dvc.git_wrapper import GitWrapper\nfrom dvc.executor import Executor\nfrom dvc.logger import Logger\nfrom dvc.path.data_item import DataDirError, DataItemInConfigDirError\nfrom dvc.path.stated_data_item import StatedDataItem\nfrom dvc.utils import cached_property\nfrom dvc.config import ConfigI\n\nclass RepositoryChangeError(DvcException):\n    def __init__(self, msg):\n        DvcException.__init__(self, 'Repository change error: {}'.format(msg))\n\n\nclass RepositoryChange(object):\n    \"\"\"Pre-condition: git repository has no changes\"\"\"\n\n    def __init__(self, command, settings, stdout, stderr, shell=False):\n        self._settings = settings\n\n        stemps_before = self.data_file_timesteps()\n\n        Logger.debug(u'[Repository change] Exec command: {}. stdout={}, stderr={}, shell={}'.format(\n                     command,\n                     stdout,\n                     stderr,\n                     shell))\n        Executor.exec_cmd_only_success(command.split(' '), stdout, stderr, shell=shell)\n\n        stemps_after = self.data_file_timesteps()\n\n        sym_diff = stemps_after ^ stemps_before\n        self._modified_content_filenames = set([filename for filename, timestemp in sym_diff])\n\n        Logger.debug(u'[Repository change] Identified modifications: {}'.format(\n                     u', '.join(self._modified_content_filenames)))\n\n        self._stated_data_items = []\n        self._externally_created_files = []\n        self._created_status_files = []\n        self._init_file_states()\n\n    @property\n    def modified_content_data_items(self):\n        return [self._settings.path_factory.data_item(file) for file in self._modified_content_filenames]\n\n    @cached_property\n    def removed_data_items(self):\n        return [x for x in self._stated_data_items if x.is_removed]\n\n    @cached_property\n    def modified_data_items(self):\n        return [x for x in self._stated_data_items if x.is_modified]\n\n    @cached_property\n    def new_data_items(self):\n        return [x for x in self._stated_data_items if x.is_new]\n\n    @cached_property\n    def unusual_data_items(self):\n        return [x for x in self._stated_data_items if x.is_unusual]\n\n    @property\n    def changed_data_items(self):\n        res = set(self.new_data_items + self.modified_data_items + self.modified_content_data_items)\n        return list(res)\n\n    def _add_stated_data_item(self, state, file):\n        try:\n            item = self._settings.path_factory.stated_data_item(state, file)\n            self._stated_data_items.append(item)\n            Logger.debug('[Repository change] Add status: {} {}'.format(\n                         item.status,\n                         item.data.dvc))\n        except DataItemInConfigDirError:\n            self._created_status_files.append(file)\n        except DataDirError:\n            self._externally_created_files.append(file)\n        pass\n\n    def _init_file_states(self):\n        statuses = GitWrapper.git_file_statuses()\n\n        for status, file in statuses:\n            file_path = os.path.join(self._settings.git.git_dir_abs, file)\n\n            if not os.path.isdir(file_path):\n                self._add_stated_data_item(status, file_path)\n            else:\n                files = []\n                self.get_all_files_from_dir(file_path, files)\n                state = StatedDataItem.STATUS_UNTRACKED + StatedDataItem.STATUS_UNTRACKED\n                for f in files:\n                    self._add_stated_data_item(state, f)\n        pass\n\n    def get_all_files_from_dir(self, dir, result):\n        files = os.listdir(dir)\n        for f in files:\n            path = os.path.join(dir, f)\n            if os.path.isfile(path):\n                result.append(path)\n            else:\n                self.get_all_files_from_dir(path, result)\n        pass\n\n    @property\n    def externally_created_files(self):\n        return self._externally_created_files\n\n    @property\n    def created_status_files(self):\n        return self._created_status_files\n\n    def data_file_timesteps(self):\n        res = set()\n        for root, dirs, files in os.walk(self._settings.git.git_dir_abs):\n            if root.startswith(os.path.join(self._settings.git.git_dir_abs, ConfigI.CONFIG_DIR)):\n                continue\n\n            for file in files:\n                filename = os.path.join(root, file)\n                if os.path.exists(filename):\n                    timestemp = os.path.getmtime(filename)\n                    res.add((filename, timestemp))\n\n        return res\n", "path": "dvc/repository_change.py"}, {"content": "import os\nimport stat\n\nfrom dvc.config import ConfigI\nfrom dvc.path.path import Path\nfrom dvc.exceptions import DvcException\nfrom dvc.system import System\nfrom dvc.utils import cached_property\nfrom dvc.data_cloud import file_md5\nfrom dvc.state_file import CacheStateFile, LocalStateFile\n\n\nclass DataItemError(DvcException):\n    def __init__(self, msg):\n        super(DataItemError, self).__init__('Data item error: {}'.format(msg))\n\n\nclass DataDirError(DvcException):\n    def __init__(self, msg):\n        super(DataDirError, self).__init__(msg)\n\n\nclass DataItemInConfigDirError(DataDirError):\n    def __init__(self, file):\n        msg = 'File \"{}\" is in config directory'.format(file)\n        super(DataItemInStatusDirError, self).__init__(msg)\n\n\nclass NotInGitDirError(DataDirError):\n    def __init__(self, file, git_dir):\n        msg = 'File \"{}\" is not in git directory \"{}\"'.format(file, git_dir)\n        super(NotInGitDirError, self).__init__(msg)\n\n\nclass DataItem(object):\n    STATE_FILE_SUFFIX = '.state'\n    LOCAL_STATE_FILE_SUFFIX = '.local_state'\n    CACHE_STATE_FILE_SUFFIX = '.cache_state'\n    CACHE_FILE_SEP = '_'\n\n    def __init__(self, data_file, git, config, cache_file=None):\n        self._git = git\n        self._config = config\n        self._cache_file = cache_file\n\n        self._data = Path(data_file, git)\n\n        if not self._data.abs.startswith(self._git.git_dir_abs):\n            raise NotInGitDirError(data_file, self._git.git_dir_abs)\n\n        if self._data.abs.startswith(os.path.join(self._git.git_dir_abs, self._config.CONFIG_DIR)):\n            raise DataItemInConfigDirError(data_file)\n\n    def copy(self, cache_file=None):\n        if not cache_file:\n            cache_file = self._cache_file\n\n        return DataItem(self._data.abs, self._git, self._config, cache_file)\n\n    def __hash__(self):\n        return self.data.dvc.__hash__()\n\n    def __eq__(self, other):\n        if other == None:\n            return False\n\n        return self.data.dvc == other.data.dvc\n\n    @property\n    def data(self):\n        return self._data\n\n    @cached_property\n    def state_dir(self):\n        return os.path.join(self._git.git_dir_abs, self._config.state_dir)\n\n    def _state(self, suffix):\n        state_file = os.path.join(self.state_dir, self.data.dvc + suffix)\n        return Path(state_file, self._git)\n\n    @cached_property\n    def state(self):\n        return self._state(self.STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_dir_abs(self):\n        return os.path.join(self._git.git_dir_abs, ConfigI.CACHE_DIR)\n\n    @cached_property\n    def local_state(self):\n        return self._state(self.LOCAL_STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_state(self):\n        return self._state(self.CACHE_STATE_FILE_SUFFIX)\n\n    @cached_property\n    def cache_dir(self):\n        return os.path.join(self._git.git_dir_abs, self._config.cache_dir)\n\n    @property\n    def cache(self):\n        cache_dir = self.cache_dir_abs\n\n        if self._cache_file:\n            file_name = os.path.relpath(os.path.realpath(self._cache_file), cache_dir)\n        else:\n            file_name = CacheStateFile.load(self).md5\n\n        cache_file = os.path.join(cache_dir, file_name)\n        return Path(cache_file, self._git)\n\n    @cached_property\n    def state_dir_abs(self):\n        return os.path.join(self._git.git_dir_abs, ConfigI.STATE_DIR)\n\n    def move_data_to_cache(self):\n        md5 = file_md5(self.data.relative)[0]\n        self._cache_file = os.path.join(self.cache_dir_abs, md5)\n        self._git.modify_gitignore([self.data.relative])\n        if not os.path.isfile(self.cache.relative):\n            System.hardlink(self.data.relative, self.cache.relative)\n        os.chmod(self.data.relative, stat.S_IREAD)\n\n        cache_state = CacheStateFile(self).save()\n\n        local_state = LocalStateFile(self).save()\n        self._git.modify_gitignore([self.local_state.relative])\n", "path": "dvc/path/data_item.py"}]}