2022-11-26 23:57:50 +00:00
|
|
|
// Copyright 2020 The Jujutsu Authors
|
2020-12-12 08:00:42 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2023-07-10 15:17:00 +00:00
|
|
|
#![allow(missing_docs)]
|
|
|
|
|
2023-05-31 10:30:48 +00:00
|
|
|
use std::collections::BTreeMap;
|
2021-03-14 17:37:28 +00:00
|
|
|
use std::sync::Arc;
|
2020-12-12 08:00:42 +00:00
|
|
|
|
2021-09-12 06:52:38 +00:00
|
|
|
use crate::backend;
|
|
|
|
use crate::backend::{TreeId, TreeValue};
|
2023-06-01 01:47:26 +00:00
|
|
|
use crate::repo_path::RepoPath;
|
2021-09-12 06:52:38 +00:00
|
|
|
use crate::store::Store;
|
2020-12-12 08:00:42 +00:00
|
|
|
use crate::tree::Tree;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum Override {
|
|
|
|
Tombstone,
|
|
|
|
Replace(TreeValue),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TreeBuilder {
|
2021-09-12 06:52:38 +00:00
|
|
|
store: Arc<Store>,
|
2020-12-12 08:00:42 +00:00
|
|
|
base_tree_id: TreeId,
|
|
|
|
overrides: BTreeMap<RepoPath, Override>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TreeBuilder {
|
2021-09-12 06:52:38 +00:00
|
|
|
pub fn new(store: Arc<Store>, base_tree_id: TreeId) -> TreeBuilder {
|
2020-12-12 08:00:42 +00:00
|
|
|
let overrides = BTreeMap::new();
|
|
|
|
TreeBuilder {
|
|
|
|
store,
|
|
|
|
base_tree_id,
|
|
|
|
overrides,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-30 05:13:35 +00:00
|
|
|
pub fn store(&self) -> &Store {
|
2020-12-12 08:00:42 +00:00
|
|
|
self.store.as_ref()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set(&mut self, path: RepoPath, value: TreeValue) {
|
2023-06-01 01:33:41 +00:00
|
|
|
assert!(!path.is_root());
|
2020-12-12 08:00:42 +00:00
|
|
|
self.overrides.insert(path, Override::Replace(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove(&mut self, path: RepoPath) {
|
2023-06-01 01:33:41 +00:00
|
|
|
assert!(!path.is_root());
|
2020-12-12 08:00:42 +00:00
|
|
|
self.overrides.insert(path, Override::Tombstone);
|
|
|
|
}
|
|
|
|
|
2023-08-24 01:14:05 +00:00
|
|
|
pub fn set_or_remove(&mut self, path: RepoPath, value: Option<TreeValue>) {
|
|
|
|
assert!(!path.is_root());
|
|
|
|
if let Some(value) = value {
|
|
|
|
self.overrides.insert(path, Override::Replace(value));
|
|
|
|
} else {
|
|
|
|
self.overrides.insert(path, Override::Tombstone);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-31 11:07:01 +00:00
|
|
|
pub fn write_tree(self) -> TreeId {
|
2023-06-01 01:33:41 +00:00
|
|
|
if self.overrides.is_empty() {
|
2020-12-12 08:00:42 +00:00
|
|
|
return self.base_tree_id;
|
|
|
|
}
|
|
|
|
|
2023-06-01 01:33:41 +00:00
|
|
|
let mut trees_to_write = self.get_base_trees();
|
|
|
|
|
2020-12-12 08:00:42 +00:00
|
|
|
// Update entries in parent trees for file overrides
|
|
|
|
for (path, file_override) in self.overrides {
|
2023-06-01 01:33:41 +00:00
|
|
|
let (dir, basename) = path.split().unwrap();
|
|
|
|
let tree = trees_to_write.get_mut(&dir).unwrap();
|
|
|
|
match file_override {
|
|
|
|
Override::Replace(value) => {
|
2023-11-25 09:22:09 +00:00
|
|
|
tree.set(basename.to_owned(), value);
|
2023-06-01 01:33:41 +00:00
|
|
|
}
|
|
|
|
Override::Tombstone => {
|
|
|
|
tree.remove(basename);
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-31 10:30:48 +00:00
|
|
|
// Write trees in reverse lexicographical order, starting with trees without
|
|
|
|
// children.
|
2023-06-30 05:58:47 +00:00
|
|
|
let store = &self.store;
|
2023-07-20 11:53:16 +00:00
|
|
|
while let Some((dir, tree)) = trees_to_write.pop_last() {
|
2023-05-31 10:30:48 +00:00
|
|
|
if let Some((parent, basename)) = dir.split() {
|
|
|
|
let parent_tree = trees_to_write.get_mut(&parent).unwrap();
|
|
|
|
if tree.is_empty() {
|
2023-05-31 13:30:20 +00:00
|
|
|
if let Some(TreeValue::Tree(_)) = parent_tree.value(basename) {
|
|
|
|
parent_tree.remove(basename);
|
|
|
|
} else {
|
|
|
|
// Entry would have been replaced with file (see above)
|
|
|
|
}
|
2020-12-12 08:00:42 +00:00
|
|
|
} else {
|
2023-06-30 05:58:47 +00:00
|
|
|
let tree = store.write_tree(&dir, tree).unwrap();
|
2023-11-25 09:22:09 +00:00
|
|
|
parent_tree.set(basename.to_owned(), TreeValue::Tree(tree.id().clone()));
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
2023-05-31 10:30:48 +00:00
|
|
|
} else {
|
|
|
|
// We're writing the root tree. Write it even if empty. Return its id.
|
2023-07-20 11:53:16 +00:00
|
|
|
assert!(trees_to_write.is_empty());
|
2023-06-30 05:58:47 +00:00
|
|
|
return store.write_tree(&dir, tree).unwrap().id().clone();
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-31 10:30:48 +00:00
|
|
|
|
|
|
|
unreachable!("trees_to_write must contain the root tree");
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
|
2023-05-31 11:07:01 +00:00
|
|
|
fn get_base_trees(&self) -> BTreeMap<RepoPath, backend::Tree> {
|
2023-06-01 01:47:26 +00:00
|
|
|
let store = &self.store;
|
2023-06-01 01:39:56 +00:00
|
|
|
let mut tree_cache = {
|
|
|
|
let dir = RepoPath::root();
|
|
|
|
let tree = store.get_tree(&dir, &self.base_tree_id).unwrap();
|
|
|
|
BTreeMap::from([(dir, tree)])
|
|
|
|
};
|
2020-12-12 08:00:42 +00:00
|
|
|
|
2023-06-01 01:47:26 +00:00
|
|
|
fn populate_trees<'a>(
|
|
|
|
tree_cache: &'a mut BTreeMap<RepoPath, Tree>,
|
|
|
|
store: &Arc<Store>,
|
|
|
|
dir: RepoPath,
|
|
|
|
) -> &'a Tree {
|
|
|
|
// `if let Some(tree) = ...` doesn't pass lifetime check as of Rust 1.69.0
|
|
|
|
if tree_cache.contains_key(&dir) {
|
|
|
|
return tree_cache.get(&dir).unwrap();
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
2023-06-01 01:47:26 +00:00
|
|
|
let (parent, basename) = dir.split().expect("root must be populated");
|
|
|
|
let tree = populate_trees(tree_cache, store, parent)
|
|
|
|
.sub_tree(basename)
|
|
|
|
.unwrap_or_else(|| Tree::null(store.clone(), dir.clone()));
|
|
|
|
tree_cache.entry(dir).or_insert(tree)
|
|
|
|
}
|
|
|
|
|
2020-12-12 08:00:42 +00:00
|
|
|
for path in self.overrides.keys() {
|
2023-06-01 01:33:41 +00:00
|
|
|
let parent = path.parent().unwrap();
|
2023-06-01 01:47:26 +00:00
|
|
|
populate_trees(&mut tree_cache, store, parent);
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 01:17:14 +00:00
|
|
|
tree_cache
|
|
|
|
.into_iter()
|
|
|
|
.map(|(dir, tree)| (dir, tree.data().clone()))
|
|
|
|
.collect()
|
2020-12-12 08:00:42 +00:00
|
|
|
}
|
|
|
|
}
|