jujutsu_lib/
legacy_thrift_op_store.rs1use std::collections::BTreeMap;
16use std::fmt::Debug;
17use std::fs::File;
18use std::io::{ErrorKind, Read};
19use std::path::PathBuf;
20
21use itertools::Itertools;
22use thrift::protocol::{TCompactInputProtocol, TSerializable};
23
24use crate::backend::{CommitId, MillisSinceEpoch, ObjectId, Timestamp};
25use crate::op_store::{
26 BranchTarget, OpStoreError, OpStoreResult, Operation, OperationId, OperationMetadata,
27 RefTarget, View, ViewId, WorkspaceId,
28};
29use crate::simple_op_store_model;
30
31impl From<thrift::Error> for OpStoreError {
32 fn from(err: thrift::Error) -> Self {
33 OpStoreError::Other(err.to_string())
34 }
35}
36
37fn not_found_to_store_error(err: std::io::Error) -> OpStoreError {
38 if err.kind() == ErrorKind::NotFound {
39 OpStoreError::NotFound
40 } else {
41 OpStoreError::from(err)
42 }
43}
44
45#[derive(Debug)]
46pub struct ThriftOpStore {
47 path: PathBuf,
48}
49
50impl ThriftOpStore {
51 pub fn load(store_path: PathBuf) -> Self {
52 ThriftOpStore { path: store_path }
53 }
54
55 fn view_path(&self, id: &ViewId) -> PathBuf {
56 self.path.join("views").join(id.hex())
57 }
58
59 fn operation_path(&self, id: &OperationId) -> PathBuf {
60 self.path.join("operations").join(id.hex())
61 }
62
63 pub fn read_view(&self, id: &ViewId) -> OpStoreResult<View> {
64 let path = self.view_path(id);
65 let mut file = File::open(path).map_err(not_found_to_store_error)?;
66 let thrift_view = read_thrift(&mut file)?;
67 Ok(View::from(&thrift_view))
68 }
69
70 pub fn read_operation(&self, id: &OperationId) -> OpStoreResult<Operation> {
71 let path = self.operation_path(id);
72 let mut file = File::open(path).map_err(not_found_to_store_error)?;
73 let thrift_operation = read_thrift(&mut file)?;
74 Ok(Operation::from(&thrift_operation))
75 }
76}
77
78pub fn read_thrift<T: TSerializable>(input: &mut impl Read) -> OpStoreResult<T> {
79 let mut protocol = TCompactInputProtocol::new(input);
80 Ok(TSerializable::read_from_in_protocol(&mut protocol).unwrap())
81}
82
83impl From<&simple_op_store_model::Timestamp> for Timestamp {
84 fn from(timestamp: &simple_op_store_model::Timestamp) -> Self {
85 Timestamp {
86 timestamp: MillisSinceEpoch(timestamp.millis_since_epoch),
87 tz_offset: timestamp.tz_offset,
88 }
89 }
90}
91
92impl From<&simple_op_store_model::OperationMetadata> for OperationMetadata {
93 fn from(metadata: &simple_op_store_model::OperationMetadata) -> Self {
94 let start_time = Timestamp::from(&metadata.start_time);
95 let end_time = Timestamp::from(&metadata.end_time);
96 let description = metadata.description.to_owned();
97 let hostname = metadata.hostname.to_owned();
98 let username = metadata.username.to_owned();
99 let tags = metadata
100 .tags
101 .iter()
102 .map(|(key, value)| (key.clone(), value.clone()))
103 .collect();
104 OperationMetadata {
105 start_time,
106 end_time,
107 description,
108 hostname,
109 username,
110 tags,
111 }
112 }
113}
114
115impl From<&simple_op_store_model::Operation> for Operation {
116 fn from(operation: &simple_op_store_model::Operation) -> Self {
117 let operation_id_from_thrift = |parent: &Vec<u8>| OperationId::new(parent.clone());
118 let parents = operation
119 .parents
120 .iter()
121 .map(operation_id_from_thrift)
122 .collect();
123 let view_id = ViewId::new(operation.view_id.clone());
124 let metadata = OperationMetadata::from(operation.metadata.as_ref());
125 Operation {
126 view_id,
127 parents,
128 metadata,
129 }
130 }
131}
132
133impl From<&simple_op_store_model::View> for View {
134 fn from(thrift_view: &simple_op_store_model::View) -> Self {
135 let mut view = View::default();
136 for (workspace_id, commit_id) in &thrift_view.wc_commit_ids {
137 view.wc_commit_ids.insert(
138 WorkspaceId::new(workspace_id.clone()),
139 CommitId::new(commit_id.clone()),
140 );
141 }
142 for head_id_bytes in &thrift_view.head_ids {
143 view.head_ids.insert(CommitId::from_bytes(head_id_bytes));
144 }
145 for head_id_bytes in &thrift_view.public_head_ids {
146 view.public_head_ids
147 .insert(CommitId::from_bytes(head_id_bytes));
148 }
149
150 for thrift_branch in &thrift_view.branches {
151 let local_target = thrift_branch.local_target.as_ref().map(RefTarget::from);
152
153 let mut remote_targets = BTreeMap::new();
154 for remote_branch in &thrift_branch.remote_branches {
155 remote_targets.insert(
156 remote_branch.remote_name.clone(),
157 RefTarget::from(&remote_branch.target),
158 );
159 }
160
161 view.branches.insert(
162 thrift_branch.name.clone(),
163 BranchTarget {
164 local_target,
165 remote_targets,
166 },
167 );
168 }
169
170 for thrift_tag in &thrift_view.tags {
171 view.tags
172 .insert(thrift_tag.name.clone(), RefTarget::from(&thrift_tag.target));
173 }
174
175 for git_ref in &thrift_view.git_refs {
176 view.git_refs
177 .insert(git_ref.name.clone(), RefTarget::from(&git_ref.target));
178 }
179
180 view.git_head = thrift_view
181 .git_head
182 .as_ref()
183 .map(|head| RefTarget::Normal(CommitId::new(head.clone())));
184
185 view
186 }
187}
188
189impl From<&simple_op_store_model::RefTarget> for RefTarget {
190 fn from(thrift_ref_target: &simple_op_store_model::RefTarget) -> Self {
191 match thrift_ref_target {
192 simple_op_store_model::RefTarget::CommitId(commit_id) => {
193 RefTarget::Normal(CommitId::from_bytes(commit_id))
194 }
195 simple_op_store_model::RefTarget::Conflict(conflict) => {
196 let removes = conflict
197 .removes
198 .iter()
199 .map(|id_bytes| CommitId::from_bytes(id_bytes))
200 .collect_vec();
201 let adds = conflict
202 .adds
203 .iter()
204 .map(|id_bytes| CommitId::from_bytes(id_bytes))
205 .collect_vec();
206 RefTarget::Conflict { removes, adds }
207 }
208 }
209 }
210}