]>
Commit | Line | Data |
---|---|---|
781aab86 FG |
1 | use crate::{config::cache::util::ApplyLeniencyDefault, repository::IndexPersistedOrInMemory, worktree}; |
2 | ||
3 | /// Index access | |
4 | impl crate::Repository { | |
5 | /// Open a new copy of the index file and decode it entirely. | |
6 | /// | |
7 | /// It will use the `index.threads` configuration key to learn how many threads to use. | |
8 | /// Note that it may fail if there is no index. | |
9 | pub fn open_index(&self) -> Result<gix_index::File, worktree::open_index::Error> { | |
10 | let thread_limit = self | |
11 | .config | |
12 | .resolved | |
13 | .string("index", None, "threads") | |
14 | .map(|value| crate::config::tree::Index::THREADS.try_into_index_threads(value)) | |
15 | .transpose() | |
16 | .with_lenient_default(self.config.lenient_config)?; | |
17 | let skip_hash = self | |
18 | .config | |
19 | .resolved | |
20 | .boolean("index", None, "skipHash") | |
21 | .map(|res| crate::config::tree::Index::SKIP_HASH.enrich_error(res)) | |
22 | .transpose() | |
23 | .with_lenient_default(self.config.lenient_config)? | |
24 | .unwrap_or_default(); | |
25 | ||
26 | let index = gix_index::File::at( | |
27 | self.index_path(), | |
28 | self.object_hash(), | |
29 | skip_hash, | |
30 | gix_index::decode::Options { | |
31 | thread_limit, | |
32 | min_extension_block_in_bytes_for_threading: 0, | |
33 | expected_checksum: None, | |
34 | }, | |
35 | )?; | |
36 | ||
37 | Ok(index) | |
38 | } | |
39 | ||
40 | /// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file | |
41 | /// on disk has changed. | |
42 | /// | |
43 | /// The index file is shared across all clones of this repository. | |
44 | pub fn index(&self) -> Result<worktree::Index, worktree::open_index::Error> { | |
45 | self.try_index().and_then(|opt| match opt { | |
46 | Some(index) => Ok(index), | |
47 | None => Err(worktree::open_index::Error::IndexFile( | |
48 | gix_index::file::init::Error::Io(std::io::Error::new( | |
49 | std::io::ErrorKind::NotFound, | |
50 | format!("Could not find index file at {:?} for opening.", self.index_path()), | |
51 | )), | |
52 | )), | |
53 | }) | |
54 | } | |
55 | ||
ed00b5ec FG |
56 | /// Return the shared worktree index if present, or return a new empty one which has an association to the place where the index would be. |
57 | pub fn index_or_empty(&self) -> Result<worktree::Index, worktree::open_index::Error> { | |
58 | Ok(self.try_index()?.unwrap_or_else(|| { | |
59 | worktree::Index::new(gix_fs::FileSnapshot::new(gix_index::File::from_state( | |
60 | gix_index::State::new(self.object_hash()), | |
61 | self.index_path(), | |
62 | ))) | |
63 | })) | |
64 | } | |
65 | ||
781aab86 FG |
66 | /// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file |
67 | /// on disk has changed, or `None` if no such file exists. | |
68 | /// | |
69 | /// The index file is shared across all clones of this repository. | |
70 | pub fn try_index(&self) -> Result<Option<worktree::Index>, worktree::open_index::Error> { | |
71 | self.index.recent_snapshot( | |
72 | || self.index_path().metadata().and_then(|m| m.modified()).ok(), | |
73 | || { | |
74 | self.open_index().map(Some).or_else(|err| match err { | |
75 | worktree::open_index::Error::IndexFile(gix_index::file::init::Error::Io(err)) | |
76 | if err.kind() == std::io::ErrorKind::NotFound => | |
77 | { | |
78 | Ok(None) | |
79 | } | |
80 | err => Err(err), | |
81 | }) | |
82 | }, | |
83 | ) | |
84 | } | |
85 | ||
86 | /// Open the persisted worktree index or generate it from the current `HEAD^{tree}` to live in-memory only. | |
87 | /// | |
88 | /// Use this method to get an index in any repository, even bare ones that don't have one naturally. | |
89 | /// | |
90 | /// ### Note | |
91 | /// | |
92 | /// The locally stored index is not guaranteed to represent `HEAD^{tree}` if this repository is bare - bare repos | |
93 | /// don't naturally have an index and if an index is present it must have been generated by hand. | |
94 | pub fn index_or_load_from_head( | |
95 | &self, | |
96 | ) -> Result<IndexPersistedOrInMemory, crate::repository::index_or_load_from_head::Error> { | |
97 | Ok(match self.try_index()? { | |
98 | Some(index) => IndexPersistedOrInMemory::Persisted(index), | |
99 | None => { | |
100 | let tree = self.head_commit()?.tree_id()?; | |
101 | IndexPersistedOrInMemory::InMemory(self.index_from_tree(&tree)?) | |
102 | } | |
103 | }) | |
104 | } | |
105 | ||
106 | /// Create new index-file, which would live at the correct location, in memory from the given `tree`. | |
107 | /// | |
108 | /// Note that this is an expensive operation as it requires recursively traversing the entire tree to unpack it into the index. | |
109 | pub fn index_from_tree( | |
110 | &self, | |
111 | tree: &gix_hash::oid, | |
112 | ) -> Result<gix_index::File, gix_traverse::tree::breadthfirst::Error> { | |
113 | Ok(gix_index::File::from_state( | |
4b012472 | 114 | gix_index::State::from_tree(tree, &self.objects)?, |
781aab86 FG |
115 | self.git_dir().join("index"), |
116 | )) | |
117 | } | |
118 | } | |
119 | ||
120 | impl std::ops::Deref for IndexPersistedOrInMemory { | |
121 | type Target = gix_index::File; | |
122 | ||
123 | fn deref(&self) -> &Self::Target { | |
124 | match self { | |
125 | IndexPersistedOrInMemory::Persisted(i) => i, | |
126 | IndexPersistedOrInMemory::InMemory(i) => i, | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | impl IndexPersistedOrInMemory { | |
132 | /// Consume this instance and turn it into an owned index file. | |
133 | /// | |
134 | /// Note that this will cause the persisted index to be cloned, which would happen whenever the repository has a worktree. | |
135 | pub fn into_owned(self) -> gix_index::File { | |
136 | match self { | |
137 | IndexPersistedOrInMemory::Persisted(i) => gix_index::File::clone(&i), | |
138 | IndexPersistedOrInMemory::InMemory(i) => i, | |
139 | } | |
140 | } | |
141 | } |