mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-28 23:55:54 +00:00
local_backend: switch from Protobuf to Thrift
This migrates the native backend from Protobuf to Thrift since Google's Protobuf team does let us import jj into Google's monorepo if it uses a third-party Protobuf library. Since the native backend is not supported, I didn't write any migration code for it. We can't remove `lib/src/protos/store.proto` yet, because it's also used by the Git backend (only the `predecessors` and `change_id` fields).
This commit is contained in:
parent
2ae2010007
commit
5b10c9aa0a
5 changed files with 971 additions and 118 deletions
|
@ -26,6 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
automatically upgraded the first time you run a command in an existing repo.
|
||||
The operation IDs will change in that process.
|
||||
|
||||
* The storage format for the native backend has changed. Unlike the operation
|
||||
log, it will *not* be automatically upgraded. We consider the native backend
|
||||
a proof-of-concept that users should not use.
|
||||
|
||||
### New features
|
||||
|
||||
* The new `jj git remote rename` command allows git remotes to be renamed
|
||||
|
|
|
@ -31,6 +31,7 @@ pub mod gitignore;
|
|||
pub mod index;
|
||||
pub mod index_store;
|
||||
pub mod local_backend;
|
||||
mod local_backend_model;
|
||||
pub mod lock;
|
||||
pub mod matchers;
|
||||
pub mod nightly_shims;
|
||||
|
|
|
@ -19,8 +19,8 @@ use std::io::{ErrorKind, Read, Write};
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use blake2::{Blake2b512, Digest};
|
||||
use protobuf::{Message, MessageField};
|
||||
use tempfile::{NamedTempFile, PersistError};
|
||||
use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol, TSerializable};
|
||||
|
||||
use crate::backend::{
|
||||
make_root_commit, Backend, BackendError, BackendResult, ChangeId, Commit, CommitId, Conflict,
|
||||
|
@ -29,6 +29,7 @@ use crate::backend::{
|
|||
};
|
||||
use crate::content_hash::ContentHash;
|
||||
use crate::file_util::persist_content_addressed_temp_file;
|
||||
use crate::local_backend_model;
|
||||
use crate::repo_path::{RepoPath, RepoPathComponent};
|
||||
|
||||
impl From<std::io::Error> for BackendError {
|
||||
|
@ -43,8 +44,8 @@ impl From<PersistError> for BackendError {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<protobuf::Error> for BackendError {
|
||||
fn from(err: protobuf::Error) -> Self {
|
||||
impl From<thrift::Error> for BackendError {
|
||||
fn from(err: thrift::Error) -> Self {
|
||||
BackendError::Other(err.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -184,19 +185,17 @@ impl Backend for LocalBackend {
|
|||
fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
|
||||
let path = self.tree_path(id);
|
||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
||||
|
||||
let proto: crate::protos::store::Tree = Message::parse_from_reader(&mut file)?;
|
||||
Ok(tree_from_proto(&proto))
|
||||
let thrift_tree = read_thrift(&mut file).unwrap();
|
||||
Ok(tree_from_thrift(&thrift_tree))
|
||||
}
|
||||
|
||||
fn write_tree(&self, _path: &RepoPath, tree: &Tree) -> BackendResult<TreeId> {
|
||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||
|
||||
let proto = tree_to_proto(tree);
|
||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
||||
let thrift_tree = tree_to_thrift(tree);
|
||||
write_thrift(&thrift_tree, &mut temp_file.as_file())?;
|
||||
|
||||
let id = TreeId::new(hash(tree).to_vec());
|
||||
|
||||
persist_content_addressed_temp_file(temp_file, self.tree_path(&id))?;
|
||||
Ok(id)
|
||||
}
|
||||
|
@ -204,19 +203,17 @@ impl Backend for LocalBackend {
|
|||
fn read_conflict(&self, _path: &RepoPath, id: &ConflictId) -> BackendResult<Conflict> {
|
||||
let path = self.conflict_path(id);
|
||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
||||
|
||||
let proto: crate::protos::store::Conflict = Message::parse_from_reader(&mut file)?;
|
||||
Ok(conflict_from_proto(&proto))
|
||||
let thrift_conflict = read_thrift(&mut file)?;
|
||||
Ok(conflict_from_thrift(&thrift_conflict))
|
||||
}
|
||||
|
||||
fn write_conflict(&self, _path: &RepoPath, conflict: &Conflict) -> BackendResult<ConflictId> {
|
||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||
|
||||
let proto = conflict_to_proto(conflict);
|
||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
||||
let thrift_conflict = conflict_to_thrift(conflict);
|
||||
write_thrift(&thrift_conflict, &mut temp_file.as_file())?;
|
||||
|
||||
let id = ConflictId::new(hash(conflict).to_vec());
|
||||
|
||||
persist_content_addressed_temp_file(temp_file, self.conflict_path(&id))?;
|
||||
Ok(id)
|
||||
}
|
||||
|
@ -228,142 +225,150 @@ impl Backend for LocalBackend {
|
|||
|
||||
let path = self.commit_path(id);
|
||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
||||
|
||||
let proto: crate::protos::store::Commit = Message::parse_from_reader(&mut file)?;
|
||||
Ok(commit_from_proto(&proto))
|
||||
let thrift_commit = read_thrift(&mut file).unwrap();
|
||||
Ok(commit_from_thrift(&thrift_commit))
|
||||
}
|
||||
|
||||
fn write_commit(&self, commit: &Commit) -> BackendResult<CommitId> {
|
||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||
|
||||
let proto = commit_to_proto(commit);
|
||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
||||
let thrift_commit = commit_to_thrift(commit);
|
||||
write_thrift(&thrift_commit, &mut temp_file.as_file())?;
|
||||
|
||||
let id = CommitId::new(hash(commit).to_vec());
|
||||
|
||||
persist_content_addressed_temp_file(temp_file, self.commit_path(&id))?;
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_to_proto(commit: &Commit) -> crate::protos::store::Commit {
|
||||
let mut proto = crate::protos::store::Commit::new();
|
||||
for parent in &commit.parents {
|
||||
proto.parents.push(parent.to_bytes());
|
||||
}
|
||||
for predecessor in &commit.predecessors {
|
||||
proto.predecessors.push(predecessor.to_bytes());
|
||||
}
|
||||
proto.root_tree = commit.root_tree.to_bytes();
|
||||
proto.change_id = commit.change_id.to_bytes();
|
||||
proto.description = commit.description.clone();
|
||||
proto.author = MessageField::some(signature_to_proto(&commit.author));
|
||||
proto.committer = MessageField::some(signature_to_proto(&commit.committer));
|
||||
proto
|
||||
fn read_thrift<T: TSerializable>(input: &mut impl Read) -> BackendResult<T> {
|
||||
let mut protocol = TCompactInputProtocol::new(input);
|
||||
Ok(TSerializable::read_from_in_protocol(&mut protocol).unwrap())
|
||||
}
|
||||
|
||||
fn commit_from_proto(proto: &crate::protos::store::Commit) -> Commit {
|
||||
let commit_id_from_proto = |parent: &Vec<u8>| CommitId::new(parent.clone());
|
||||
let parents = proto.parents.iter().map(commit_id_from_proto).collect();
|
||||
let predecessors = proto
|
||||
fn write_thrift<T: TSerializable>(thrift_object: &T, output: &mut impl Write) -> BackendResult<()> {
|
||||
let mut protocol = TCompactOutputProtocol::new(output);
|
||||
thrift_object.write_to_out_protocol(&mut protocol)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn commit_to_thrift(commit: &Commit) -> local_backend_model::Commit {
|
||||
let mut parents = vec![];
|
||||
for parent in &commit.parents {
|
||||
parents.push(parent.to_bytes());
|
||||
}
|
||||
let mut predecessors = vec![];
|
||||
for predecessor in &commit.predecessors {
|
||||
predecessors.push(predecessor.to_bytes());
|
||||
}
|
||||
let root_tree = commit.root_tree.to_bytes();
|
||||
let change_id = commit.change_id.to_bytes();
|
||||
let description = commit.description.clone();
|
||||
let author = signature_to_thrift(&commit.author);
|
||||
let committer = signature_to_thrift(&commit.committer);
|
||||
local_backend_model::Commit::new(
|
||||
parents,
|
||||
predecessors,
|
||||
root_tree,
|
||||
change_id,
|
||||
description,
|
||||
author,
|
||||
committer,
|
||||
)
|
||||
}
|
||||
|
||||
fn commit_from_thrift(thrift_commit: &local_backend_model::Commit) -> Commit {
|
||||
let commit_id_from_thrift = |parent: &Vec<u8>| CommitId::new(parent.clone());
|
||||
let parents = thrift_commit
|
||||
.parents
|
||||
.iter()
|
||||
.map(commit_id_from_thrift)
|
||||
.collect();
|
||||
let predecessors = thrift_commit
|
||||
.predecessors
|
||||
.iter()
|
||||
.map(commit_id_from_proto)
|
||||
.map(commit_id_from_thrift)
|
||||
.collect();
|
||||
let root_tree = TreeId::new(proto.root_tree.to_vec());
|
||||
let change_id = ChangeId::new(proto.change_id.to_vec());
|
||||
let root_tree = TreeId::new(thrift_commit.root_tree.to_vec());
|
||||
let change_id = ChangeId::new(thrift_commit.change_id.to_vec());
|
||||
Commit {
|
||||
parents,
|
||||
predecessors,
|
||||
root_tree,
|
||||
change_id,
|
||||
description: proto.description.clone(),
|
||||
author: signature_from_proto(&proto.author),
|
||||
committer: signature_from_proto(&proto.committer),
|
||||
description: thrift_commit.description.clone(),
|
||||
author: signature_from_thrift(&thrift_commit.author),
|
||||
committer: signature_from_thrift(&thrift_commit.committer),
|
||||
}
|
||||
}
|
||||
|
||||
fn tree_to_proto(tree: &Tree) -> crate::protos::store::Tree {
|
||||
let mut proto = crate::protos::store::Tree::new();
|
||||
fn tree_to_thrift(tree: &Tree) -> local_backend_model::Tree {
|
||||
let mut entries = vec![];
|
||||
for entry in tree.entries() {
|
||||
let mut proto_entry = crate::protos::store::tree::Entry::new();
|
||||
proto_entry.name = entry.name().string();
|
||||
proto_entry.value = MessageField::some(tree_value_to_proto(entry.value()));
|
||||
proto.entries.push(proto_entry);
|
||||
let name = entry.name().string();
|
||||
let value = tree_value_to_thrift(entry.value());
|
||||
let thrift_entry = local_backend_model::TreeEntry::new(name, value);
|
||||
entries.push(thrift_entry);
|
||||
}
|
||||
proto
|
||||
local_backend_model::Tree::new(entries)
|
||||
}
|
||||
|
||||
fn tree_from_proto(proto: &crate::protos::store::Tree) -> Tree {
|
||||
fn tree_from_thrift(thrift_tree: &local_backend_model::Tree) -> Tree {
|
||||
let mut tree = Tree::default();
|
||||
for proto_entry in &proto.entries {
|
||||
let value = tree_value_from_proto(proto_entry.value.as_ref().unwrap());
|
||||
tree.set(RepoPathComponent::from(proto_entry.name.as_str()), value);
|
||||
for thrift_tree_entry in &thrift_tree.entries {
|
||||
let value = tree_value_from_thrift(&thrift_tree_entry.value);
|
||||
tree.set(
|
||||
RepoPathComponent::from(thrift_tree_entry.name.as_str()),
|
||||
value,
|
||||
);
|
||||
}
|
||||
tree
|
||||
}
|
||||
|
||||
fn tree_value_to_proto(value: &TreeValue) -> crate::protos::store::TreeValue {
|
||||
let mut proto = crate::protos::store::TreeValue::new();
|
||||
fn tree_value_to_thrift(value: &TreeValue) -> local_backend_model::TreeValue {
|
||||
match value {
|
||||
TreeValue::Normal { id, executable } => {
|
||||
let mut file = crate::protos::store::tree_value::NormalFile::new();
|
||||
file.id = id.to_bytes();
|
||||
file.executable = *executable;
|
||||
proto.set_normal_file(file);
|
||||
}
|
||||
TreeValue::Symlink(id) => {
|
||||
proto.set_symlink_id(id.to_bytes());
|
||||
let file = local_backend_model::NormalFile::new(id.to_bytes(), *executable);
|
||||
local_backend_model::TreeValue::NormalFile(file)
|
||||
}
|
||||
TreeValue::Symlink(id) => local_backend_model::TreeValue::SymlinkId(id.to_bytes()),
|
||||
TreeValue::GitSubmodule(_id) => {
|
||||
panic!("cannot store git submodules");
|
||||
}
|
||||
TreeValue::Tree(id) => {
|
||||
proto.set_tree_id(id.to_bytes());
|
||||
}
|
||||
TreeValue::Conflict(id) => {
|
||||
proto.set_conflict_id(id.to_bytes());
|
||||
}
|
||||
};
|
||||
proto
|
||||
TreeValue::Tree(id) => local_backend_model::TreeValue::TreeId(id.to_bytes()),
|
||||
TreeValue::Conflict(id) => local_backend_model::TreeValue::ConflictId(id.to_bytes()),
|
||||
}
|
||||
}
|
||||
|
||||
fn tree_value_from_proto(proto: &crate::protos::store::TreeValue) -> TreeValue {
|
||||
match proto.value.as_ref().unwrap() {
|
||||
crate::protos::store::tree_value::Value::TreeId(id) => {
|
||||
TreeValue::Tree(TreeId::new(id.clone()))
|
||||
}
|
||||
crate::protos::store::tree_value::Value::NormalFile(
|
||||
crate::protos::store::tree_value::NormalFile { id, executable, .. },
|
||||
) => TreeValue::Normal {
|
||||
id: FileId::new(id.clone()),
|
||||
executable: *executable,
|
||||
fn tree_value_from_thrift(thrift_tree_value: &local_backend_model::TreeValue) -> TreeValue {
|
||||
match thrift_tree_value {
|
||||
local_backend_model::TreeValue::NormalFile(file) => TreeValue::Normal {
|
||||
id: FileId::from_bytes(&file.id),
|
||||
executable: file.executable,
|
||||
},
|
||||
crate::protos::store::tree_value::Value::SymlinkId(id) => {
|
||||
TreeValue::Symlink(SymlinkId::new(id.clone()))
|
||||
local_backend_model::TreeValue::SymlinkId(id) => {
|
||||
TreeValue::Symlink(SymlinkId::from_bytes(id))
|
||||
}
|
||||
crate::protos::store::tree_value::Value::ConflictId(id) => {
|
||||
TreeValue::Conflict(ConflictId::new(id.clone()))
|
||||
local_backend_model::TreeValue::TreeId(id) => TreeValue::Tree(TreeId::from_bytes(id)),
|
||||
local_backend_model::TreeValue::ConflictId(id) => {
|
||||
TreeValue::Conflict(ConflictId::from_bytes(id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn signature_to_proto(signature: &Signature) -> crate::protos::store::commit::Signature {
|
||||
let mut proto = crate::protos::store::commit::Signature::new();
|
||||
proto.name = signature.name.clone();
|
||||
proto.email = signature.email.clone();
|
||||
let mut timestamp_proto = crate::protos::store::commit::Timestamp::new();
|
||||
timestamp_proto.millis_since_epoch = signature.timestamp.timestamp.0;
|
||||
timestamp_proto.tz_offset = signature.timestamp.tz_offset;
|
||||
proto.timestamp = MessageField::some(timestamp_proto);
|
||||
proto
|
||||
fn signature_to_thrift(signature: &Signature) -> local_backend_model::Signature {
|
||||
let timestamp = local_backend_model::Timestamp::new(
|
||||
signature.timestamp.timestamp.0,
|
||||
signature.timestamp.tz_offset,
|
||||
);
|
||||
local_backend_model::Signature::new(signature.name.clone(), signature.email.clone(), timestamp)
|
||||
}
|
||||
|
||||
fn signature_from_proto(proto: &crate::protos::store::commit::Signature) -> Signature {
|
||||
let timestamp = &proto.timestamp;
|
||||
fn signature_from_thrift(thrift: &local_backend_model::Signature) -> Signature {
|
||||
let timestamp = &thrift.timestamp;
|
||||
Signature {
|
||||
name: proto.name.clone(),
|
||||
email: proto.email.clone(),
|
||||
name: thrift.name.clone(),
|
||||
email: thrift.email.clone(),
|
||||
timestamp: Timestamp {
|
||||
timestamp: MillisSinceEpoch(timestamp.millis_since_epoch),
|
||||
tz_offset: timestamp.tz_offset,
|
||||
|
@ -371,38 +376,37 @@ fn signature_from_proto(proto: &crate::protos::store::commit::Signature) -> Sign
|
|||
}
|
||||
}
|
||||
|
||||
fn conflict_to_proto(conflict: &Conflict) -> crate::protos::store::Conflict {
|
||||
let mut proto = crate::protos::store::Conflict::new();
|
||||
for part in &conflict.adds {
|
||||
proto.adds.push(conflict_part_to_proto(part));
|
||||
}
|
||||
fn conflict_to_thrift(conflict: &Conflict) -> local_backend_model::Conflict {
|
||||
let mut removes = vec![];
|
||||
for part in &conflict.removes {
|
||||
proto.removes.push(conflict_part_to_proto(part));
|
||||
removes.push(conflict_part_to_thrift(part));
|
||||
}
|
||||
proto
|
||||
let mut adds = vec![];
|
||||
for part in &conflict.adds {
|
||||
adds.push(conflict_part_to_thrift(part));
|
||||
}
|
||||
local_backend_model::Conflict::new(removes, adds)
|
||||
}
|
||||
|
||||
fn conflict_from_proto(proto: &crate::protos::store::Conflict) -> Conflict {
|
||||
fn conflict_from_thrift(thrift: &local_backend_model::Conflict) -> Conflict {
|
||||
let mut conflict = Conflict::default();
|
||||
for part in &proto.removes {
|
||||
conflict.removes.push(conflict_part_from_proto(part))
|
||||
for part in &thrift.removes {
|
||||
conflict.removes.push(conflict_part_from_thrift(part))
|
||||
}
|
||||
for part in &proto.adds {
|
||||
conflict.adds.push(conflict_part_from_proto(part))
|
||||
for part in &thrift.adds {
|
||||
conflict.adds.push(conflict_part_from_thrift(part))
|
||||
}
|
||||
conflict
|
||||
}
|
||||
|
||||
fn conflict_part_from_proto(proto: &crate::protos::store::conflict::Part) -> ConflictPart {
|
||||
fn conflict_part_from_thrift(thrift: &local_backend_model::ConflictPart) -> ConflictPart {
|
||||
ConflictPart {
|
||||
value: tree_value_from_proto(proto.content.as_ref().unwrap()),
|
||||
value: tree_value_from_thrift(&thrift.content),
|
||||
}
|
||||
}
|
||||
|
||||
fn conflict_part_to_proto(part: &ConflictPart) -> crate::protos::store::conflict::Part {
|
||||
let mut proto = crate::protos::store::conflict::Part::new();
|
||||
proto.content = MessageField::some(tree_value_to_proto(&part.value));
|
||||
proto
|
||||
fn conflict_part_to_thrift(part: &ConflictPart) -> local_backend_model::ConflictPart {
|
||||
local_backend_model::ConflictPart::new(tree_value_to_thrift(&part.value))
|
||||
}
|
||||
|
||||
fn hash(x: &impl ContentHash) -> digest::Output<Blake2b512> {
|
||||
|
|
780
lib/src/local_backend_model.rs
Normal file
780
lib/src/local_backend_model.rs
Normal file
|
@ -0,0 +1,780 @@
|
|||
// Autogenerated by Thrift Compiler (0.17.0)
|
||||
// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_extern_crates)]
|
||||
#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::convert::{From, TryFrom};
|
||||
use std::default::Default;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::rc::Rc;
|
||||
|
||||
use thrift::OrderedFloat;
|
||||
use thrift::{ApplicationError, ApplicationErrorKind, ProtocolError, ProtocolErrorKind, TThriftClient};
|
||||
use thrift::protocol::{TFieldIdentifier, TListIdentifier, TMapIdentifier, TMessageIdentifier, TMessageType, TInputProtocol, TOutputProtocol, TSerializable, TSetIdentifier, TStructIdentifier, TType};
|
||||
use thrift::protocol::field_id;
|
||||
use thrift::protocol::verify_expected_message_type;
|
||||
use thrift::protocol::verify_expected_sequence_number;
|
||||
use thrift::protocol::verify_expected_service_call;
|
||||
use thrift::protocol::verify_required_field_exists;
|
||||
|
||||
//
|
||||
// NormalFile
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct NormalFile {
|
||||
pub id: Vec<u8>,
|
||||
pub executable: bool,
|
||||
}
|
||||
|
||||
impl NormalFile {
|
||||
pub fn new(id: Vec<u8>, executable: bool) -> NormalFile {
|
||||
NormalFile {
|
||||
id,
|
||||
executable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for NormalFile {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<NormalFile> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<Vec<u8>> = None;
|
||||
let mut f_2: Option<bool> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let val = i_prot.read_bool()?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("NormalFile.id", &f_1)?;
|
||||
verify_required_field_exists("NormalFile.executable", &f_2)?;
|
||||
let ret = NormalFile {
|
||||
id: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
executable: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("NormalFile");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("id", TType::String, 1))?;
|
||||
o_prot.write_bytes(&self.id)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("executable", TType::Bool, 2))?;
|
||||
o_prot.write_bool(self.executable)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TreeValue
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum TreeValue {
|
||||
NormalFile(NormalFile),
|
||||
SymlinkId(Vec<u8>),
|
||||
TreeId(Vec<u8>),
|
||||
ConflictId(Vec<u8>),
|
||||
}
|
||||
|
||||
impl TSerializable for TreeValue {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<TreeValue> {
|
||||
let mut ret: Option<TreeValue> = None;
|
||||
let mut received_field_count = 0;
|
||||
i_prot.read_struct_begin()?;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = NormalFile::read_from_in_protocol(i_prot)?;
|
||||
if ret.is_none() {
|
||||
ret = Some(TreeValue::NormalFile(val));
|
||||
}
|
||||
received_field_count += 1;
|
||||
},
|
||||
2 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
if ret.is_none() {
|
||||
ret = Some(TreeValue::SymlinkId(val));
|
||||
}
|
||||
received_field_count += 1;
|
||||
},
|
||||
3 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
if ret.is_none() {
|
||||
ret = Some(TreeValue::TreeId(val));
|
||||
}
|
||||
received_field_count += 1;
|
||||
},
|
||||
4 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
if ret.is_none() {
|
||||
ret = Some(TreeValue::ConflictId(val));
|
||||
}
|
||||
received_field_count += 1;
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
received_field_count += 1;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
if received_field_count == 0 {
|
||||
Err(
|
||||
thrift::Error::Protocol(
|
||||
ProtocolError::new(
|
||||
ProtocolErrorKind::InvalidData,
|
||||
"received empty union from remote TreeValue"
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if received_field_count > 1 {
|
||||
Err(
|
||||
thrift::Error::Protocol(
|
||||
ProtocolError::new(
|
||||
ProtocolErrorKind::InvalidData,
|
||||
"received multiple fields for union from remote TreeValue"
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Ok(ret.expect("return value should have been constructed"))
|
||||
}
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("TreeValue");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
match *self {
|
||||
TreeValue::NormalFile(ref f) => {
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("normal_file", TType::Struct, 1))?;
|
||||
f.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
},
|
||||
TreeValue::SymlinkId(ref f) => {
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("symlink_id", TType::String, 2))?;
|
||||
o_prot.write_bytes(f)?;
|
||||
o_prot.write_field_end()?;
|
||||
},
|
||||
TreeValue::TreeId(ref f) => {
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("tree_id", TType::String, 3))?;
|
||||
o_prot.write_bytes(f)?;
|
||||
o_prot.write_field_end()?;
|
||||
},
|
||||
TreeValue::ConflictId(ref f) => {
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("conflict_id", TType::String, 4))?;
|
||||
o_prot.write_bytes(f)?;
|
||||
o_prot.write_field_end()?;
|
||||
},
|
||||
}
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TreeEntry
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct TreeEntry {
|
||||
pub name: String,
|
||||
pub value: TreeValue,
|
||||
}
|
||||
|
||||
impl TreeEntry {
|
||||
pub fn new(name: String, value: TreeValue) -> TreeEntry {
|
||||
TreeEntry {
|
||||
name,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for TreeEntry {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<TreeEntry> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<String> = None;
|
||||
let mut f_2: Option<TreeValue> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = i_prot.read_string()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let val = TreeValue::read_from_in_protocol(i_prot)?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("TreeEntry.name", &f_1)?;
|
||||
verify_required_field_exists("TreeEntry.value", &f_2)?;
|
||||
let ret = TreeEntry {
|
||||
name: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
value: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("TreeEntry");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("name", TType::String, 1))?;
|
||||
o_prot.write_string(&self.name)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("value", TType::Struct, 2))?;
|
||||
self.value.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Tree
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Tree {
|
||||
pub entries: Vec<TreeEntry>,
|
||||
}
|
||||
|
||||
impl Tree {
|
||||
pub fn new(entries: Vec<TreeEntry>) -> Tree {
|
||||
Tree {
|
||||
entries,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for Tree {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<Tree> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<Vec<TreeEntry>> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let list_ident = i_prot.read_list_begin()?;
|
||||
let mut val: Vec<TreeEntry> = Vec::with_capacity(list_ident.size as usize);
|
||||
for _ in 0..list_ident.size {
|
||||
let list_elem_0 = TreeEntry::read_from_in_protocol(i_prot)?;
|
||||
val.push(list_elem_0);
|
||||
}
|
||||
i_prot.read_list_end()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("Tree.entries", &f_1)?;
|
||||
let ret = Tree {
|
||||
entries: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("Tree");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("entries", TType::List, 1))?;
|
||||
o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.entries.len() as i32))?;
|
||||
for e in &self.entries {
|
||||
e.write_to_out_protocol(o_prot)?;
|
||||
}
|
||||
o_prot.write_list_end()?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Timestamp
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Timestamp {
|
||||
pub millis_since_epoch: i64,
|
||||
pub tz_offset: i32,
|
||||
}
|
||||
|
||||
impl Timestamp {
|
||||
pub fn new(millis_since_epoch: i64, tz_offset: i32) -> Timestamp {
|
||||
Timestamp {
|
||||
millis_since_epoch,
|
||||
tz_offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for Timestamp {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<Timestamp> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<i64> = None;
|
||||
let mut f_2: Option<i32> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = i_prot.read_i64()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let val = i_prot.read_i32()?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("Timestamp.millis_since_epoch", &f_1)?;
|
||||
verify_required_field_exists("Timestamp.tz_offset", &f_2)?;
|
||||
let ret = Timestamp {
|
||||
millis_since_epoch: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
tz_offset: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("Timestamp");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("millis_since_epoch", TType::I64, 1))?;
|
||||
o_prot.write_i64(self.millis_since_epoch)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("tz_offset", TType::I32, 2))?;
|
||||
o_prot.write_i32(self.tz_offset)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Signature
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Signature {
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
pub timestamp: Timestamp,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub fn new(name: String, email: String, timestamp: Timestamp) -> Signature {
|
||||
Signature {
|
||||
name,
|
||||
email,
|
||||
timestamp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for Signature {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<Signature> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<String> = None;
|
||||
let mut f_2: Option<String> = None;
|
||||
let mut f_3: Option<Timestamp> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = i_prot.read_string()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let val = i_prot.read_string()?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
3 => {
|
||||
let val = Timestamp::read_from_in_protocol(i_prot)?;
|
||||
f_3 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("Signature.name", &f_1)?;
|
||||
verify_required_field_exists("Signature.email", &f_2)?;
|
||||
verify_required_field_exists("Signature.timestamp", &f_3)?;
|
||||
let ret = Signature {
|
||||
name: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
email: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
timestamp: f_3.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("Signature");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("name", TType::String, 1))?;
|
||||
o_prot.write_string(&self.name)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("email", TType::String, 2))?;
|
||||
o_prot.write_string(&self.email)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("timestamp", TType::Struct, 3))?;
|
||||
self.timestamp.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Commit
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Commit {
|
||||
pub parents: Vec<Vec<u8>>,
|
||||
pub predecessors: Vec<Vec<u8>>,
|
||||
pub root_tree: Vec<u8>,
|
||||
pub change_id: Vec<u8>,
|
||||
pub description: String,
|
||||
pub author: Signature,
|
||||
pub committer: Signature,
|
||||
}
|
||||
|
||||
impl Commit {
|
||||
pub fn new(parents: Vec<Vec<u8>>, predecessors: Vec<Vec<u8>>, root_tree: Vec<u8>, change_id: Vec<u8>, description: String, author: Signature, committer: Signature) -> Commit {
|
||||
Commit {
|
||||
parents,
|
||||
predecessors,
|
||||
root_tree,
|
||||
change_id,
|
||||
description,
|
||||
author,
|
||||
committer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for Commit {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<Commit> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<Vec<Vec<u8>>> = None;
|
||||
let mut f_2: Option<Vec<Vec<u8>>> = None;
|
||||
let mut f_3: Option<Vec<u8>> = None;
|
||||
let mut f_4: Option<Vec<u8>> = None;
|
||||
let mut f_5: Option<String> = None;
|
||||
let mut f_6: Option<Signature> = None;
|
||||
let mut f_7: Option<Signature> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let list_ident = i_prot.read_list_begin()?;
|
||||
let mut val: Vec<Vec<u8>> = Vec::with_capacity(list_ident.size as usize);
|
||||
for _ in 0..list_ident.size {
|
||||
let list_elem_1 = i_prot.read_bytes()?;
|
||||
val.push(list_elem_1);
|
||||
}
|
||||
i_prot.read_list_end()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let list_ident = i_prot.read_list_begin()?;
|
||||
let mut val: Vec<Vec<u8>> = Vec::with_capacity(list_ident.size as usize);
|
||||
for _ in 0..list_ident.size {
|
||||
let list_elem_2 = i_prot.read_bytes()?;
|
||||
val.push(list_elem_2);
|
||||
}
|
||||
i_prot.read_list_end()?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
3 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
f_3 = Some(val);
|
||||
},
|
||||
4 => {
|
||||
let val = i_prot.read_bytes()?;
|
||||
f_4 = Some(val);
|
||||
},
|
||||
5 => {
|
||||
let val = i_prot.read_string()?;
|
||||
f_5 = Some(val);
|
||||
},
|
||||
6 => {
|
||||
let val = Signature::read_from_in_protocol(i_prot)?;
|
||||
f_6 = Some(val);
|
||||
},
|
||||
7 => {
|
||||
let val = Signature::read_from_in_protocol(i_prot)?;
|
||||
f_7 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("Commit.parents", &f_1)?;
|
||||
verify_required_field_exists("Commit.predecessors", &f_2)?;
|
||||
verify_required_field_exists("Commit.root_tree", &f_3)?;
|
||||
verify_required_field_exists("Commit.change_id", &f_4)?;
|
||||
verify_required_field_exists("Commit.description", &f_5)?;
|
||||
verify_required_field_exists("Commit.author", &f_6)?;
|
||||
verify_required_field_exists("Commit.committer", &f_7)?;
|
||||
let ret = Commit {
|
||||
parents: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
predecessors: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
root_tree: f_3.expect("auto-generated code should have checked for presence of required fields"),
|
||||
change_id: f_4.expect("auto-generated code should have checked for presence of required fields"),
|
||||
description: f_5.expect("auto-generated code should have checked for presence of required fields"),
|
||||
author: f_6.expect("auto-generated code should have checked for presence of required fields"),
|
||||
committer: f_7.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("Commit");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("parents", TType::List, 1))?;
|
||||
o_prot.write_list_begin(&TListIdentifier::new(TType::String, self.parents.len() as i32))?;
|
||||
for e in &self.parents {
|
||||
o_prot.write_bytes(e)?;
|
||||
}
|
||||
o_prot.write_list_end()?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("predecessors", TType::List, 2))?;
|
||||
o_prot.write_list_begin(&TListIdentifier::new(TType::String, self.predecessors.len() as i32))?;
|
||||
for e in &self.predecessors {
|
||||
o_prot.write_bytes(e)?;
|
||||
}
|
||||
o_prot.write_list_end()?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("root_tree", TType::String, 3))?;
|
||||
o_prot.write_bytes(&self.root_tree)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("change_id", TType::String, 4))?;
|
||||
o_prot.write_bytes(&self.change_id)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("description", TType::String, 5))?;
|
||||
o_prot.write_string(&self.description)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("author", TType::Struct, 6))?;
|
||||
self.author.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("committer", TType::Struct, 7))?;
|
||||
self.committer.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ConflictPart
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct ConflictPart {
|
||||
pub content: TreeValue,
|
||||
}
|
||||
|
||||
impl ConflictPart {
|
||||
pub fn new(content: TreeValue) -> ConflictPart {
|
||||
ConflictPart {
|
||||
content,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for ConflictPart {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<ConflictPart> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<TreeValue> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let val = TreeValue::read_from_in_protocol(i_prot)?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("ConflictPart.content", &f_1)?;
|
||||
let ret = ConflictPart {
|
||||
content: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("ConflictPart");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("content", TType::Struct, 1))?;
|
||||
self.content.write_to_out_protocol(o_prot)?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Conflict
|
||||
//
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Conflict {
|
||||
pub removes: Vec<ConflictPart>,
|
||||
pub adds: Vec<ConflictPart>,
|
||||
}
|
||||
|
||||
impl Conflict {
|
||||
pub fn new(removes: Vec<ConflictPart>, adds: Vec<ConflictPart>) -> Conflict {
|
||||
Conflict {
|
||||
removes,
|
||||
adds,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TSerializable for Conflict {
|
||||
fn read_from_in_protocol(i_prot: &mut dyn TInputProtocol) -> thrift::Result<Conflict> {
|
||||
i_prot.read_struct_begin()?;
|
||||
let mut f_1: Option<Vec<ConflictPart>> = None;
|
||||
let mut f_2: Option<Vec<ConflictPart>> = None;
|
||||
loop {
|
||||
let field_ident = i_prot.read_field_begin()?;
|
||||
if field_ident.field_type == TType::Stop {
|
||||
break;
|
||||
}
|
||||
let field_id = field_id(&field_ident)?;
|
||||
match field_id {
|
||||
1 => {
|
||||
let list_ident = i_prot.read_list_begin()?;
|
||||
let mut val: Vec<ConflictPart> = Vec::with_capacity(list_ident.size as usize);
|
||||
for _ in 0..list_ident.size {
|
||||
let list_elem_3 = ConflictPart::read_from_in_protocol(i_prot)?;
|
||||
val.push(list_elem_3);
|
||||
}
|
||||
i_prot.read_list_end()?;
|
||||
f_1 = Some(val);
|
||||
},
|
||||
2 => {
|
||||
let list_ident = i_prot.read_list_begin()?;
|
||||
let mut val: Vec<ConflictPart> = Vec::with_capacity(list_ident.size as usize);
|
||||
for _ in 0..list_ident.size {
|
||||
let list_elem_4 = ConflictPart::read_from_in_protocol(i_prot)?;
|
||||
val.push(list_elem_4);
|
||||
}
|
||||
i_prot.read_list_end()?;
|
||||
f_2 = Some(val);
|
||||
},
|
||||
_ => {
|
||||
i_prot.skip(field_ident.field_type)?;
|
||||
},
|
||||
};
|
||||
i_prot.read_field_end()?;
|
||||
}
|
||||
i_prot.read_struct_end()?;
|
||||
verify_required_field_exists("Conflict.removes", &f_1)?;
|
||||
verify_required_field_exists("Conflict.adds", &f_2)?;
|
||||
let ret = Conflict {
|
||||
removes: f_1.expect("auto-generated code should have checked for presence of required fields"),
|
||||
adds: f_2.expect("auto-generated code should have checked for presence of required fields"),
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
fn write_to_out_protocol(&self, o_prot: &mut dyn TOutputProtocol) -> thrift::Result<()> {
|
||||
let struct_ident = TStructIdentifier::new("Conflict");
|
||||
o_prot.write_struct_begin(&struct_ident)?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("removes", TType::List, 1))?;
|
||||
o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.removes.len() as i32))?;
|
||||
for e in &self.removes {
|
||||
e.write_to_out_protocol(o_prot)?;
|
||||
}
|
||||
o_prot.write_list_end()?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_begin(&TFieldIdentifier::new("adds", TType::List, 2))?;
|
||||
o_prot.write_list_begin(&TListIdentifier::new(TType::Struct, self.adds.len() as i32))?;
|
||||
for e in &self.adds {
|
||||
e.write_to_out_protocol(o_prot)?;
|
||||
}
|
||||
o_prot.write_list_end()?;
|
||||
o_prot.write_field_end()?;
|
||||
o_prot.write_field_stop()?;
|
||||
o_prot.write_struct_end()
|
||||
}
|
||||
}
|
||||
|
64
lib/src/local_backend_model.thrift
Normal file
64
lib/src/local_backend_model.thrift
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
struct NormalFile {
|
||||
1: required binary id,
|
||||
2: required bool executable,
|
||||
}
|
||||
|
||||
union TreeValue {
|
||||
1: NormalFile normal_file,
|
||||
2: binary symlink_id,
|
||||
3: binary tree_id,
|
||||
4: binary conflict_id,
|
||||
}
|
||||
|
||||
struct TreeEntry {
|
||||
1: required string name,
|
||||
2: required TreeValue value,
|
||||
}
|
||||
|
||||
struct Tree {
|
||||
1: required list<TreeEntry> entries,
|
||||
}
|
||||
|
||||
struct Timestamp {
|
||||
1: required i64 millis_since_epoch,
|
||||
2: required i32 tz_offset,
|
||||
}
|
||||
|
||||
struct Signature {
|
||||
1: required string name,
|
||||
2: required string email,
|
||||
3: required Timestamp timestamp,
|
||||
}
|
||||
|
||||
struct Commit {
|
||||
1: required list<binary> parents,
|
||||
2: required list<binary> predecessors,
|
||||
3: required binary root_tree,
|
||||
4: required binary change_id,
|
||||
5: required string description,
|
||||
6: required Signature author,
|
||||
7: required Signature committer,
|
||||
}
|
||||
|
||||
struct ConflictPart {
|
||||
1: required TreeValue content,
|
||||
}
|
||||
|
||||
struct Conflict {
|
||||
1: required list<ConflictPart> removes,
|
||||
2: required list<ConflictPart> adds,
|
||||
}
|
Loading…
Reference in a new issue