mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-18 02:04:19 +00:00
lib: replace protobuf crate with prost
This commit is contained in:
parent
300f744e41
commit
aaa175eca7
16 changed files with 702 additions and 287 deletions
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
|
@ -42,6 +42,20 @@ jobs:
|
||||||
env:
|
env:
|
||||||
RUST_BACKTRACE: 1
|
RUST_BACKTRACE: 1
|
||||||
|
|
||||||
|
check-protos:
|
||||||
|
name: Check protos
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b
|
||||||
|
- uses: dtolnay/rust-toolchain@e645b0cf01249a964ec099494d38d2da0f0b349f
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
- run: sudo apt update && sudo apt-get -y install protobuf-compiler
|
||||||
|
- name: Generate Rust code from .proto files
|
||||||
|
run: cargo run -p gen-protos
|
||||||
|
- name: Check for uncommitted changes
|
||||||
|
run: git diff --exit-code
|
||||||
|
|
||||||
rustfmt:
|
rustfmt:
|
||||||
name: Check formatting
|
name: Check formatting
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
111
Cargo.lock
generated
111
Cargo.lock
generated
|
@ -545,6 +545,12 @@ dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixedbitset"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "float-cmp"
|
name = "float-cmp"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -564,6 +570,13 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gen-protos"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"prost-build",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.6"
|
version = "0.14.6"
|
||||||
|
@ -830,8 +843,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"protobuf",
|
"prost",
|
||||||
"protobuf-codegen",
|
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -984,6 +996,12 @@ dependencies = [
|
||||||
"windows-sys 0.36.1",
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "multimap"
|
||||||
|
version = "0.8.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.1"
|
version = "7.1.1"
|
||||||
|
@ -1180,6 +1198,16 @@ dependencies = [
|
||||||
"sha1",
|
"sha1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "petgraph"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143"
|
||||||
|
dependencies = [
|
||||||
|
"fixedbitset",
|
||||||
|
"indexmap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -1256,6 +1284,16 @@ dependencies = [
|
||||||
"termtree",
|
"termtree",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prettyplease"
|
||||||
|
version = "0.1.22"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -1290,55 +1328,58 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "protobuf"
|
name = "prost"
|
||||||
version = "3.2.0"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e"
|
checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"once_cell",
|
"prost-derive",
|
||||||
"protobuf-support",
|
|
||||||
"thiserror",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "protobuf-codegen"
|
name = "prost-build"
|
||||||
version = "3.2.0"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd418ac3c91caa4032d37cb80ff0d44e2ebe637b2fb243b6234bf89cdac4901"
|
checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"bytes",
|
||||||
"once_cell",
|
"heck",
|
||||||
"protobuf",
|
"itertools",
|
||||||
"protobuf-parse",
|
"lazy_static",
|
||||||
"regex",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "protobuf-parse"
|
|
||||||
version = "3.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d39b14605eaa1f6a340aec7f320b34064feb26c93aec35d6a9a2272a8ddfa49"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"indexmap",
|
|
||||||
"log",
|
"log",
|
||||||
"protobuf",
|
"multimap",
|
||||||
"protobuf-support",
|
"petgraph",
|
||||||
|
"prettyplease",
|
||||||
|
"prost",
|
||||||
|
"prost-types",
|
||||||
|
"regex",
|
||||||
|
"syn",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "protobuf-support"
|
name = "prost-derive"
|
||||||
version = "3.2.0"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372"
|
checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror",
|
"anyhow",
|
||||||
|
"itertools",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prost-types"
|
||||||
|
version = "0.11.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"prost",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -31,7 +31,7 @@ name = "diff_bench"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["lib", "lib/testutils"]
|
members = ["lib", "lib/testutils", "lib/gen-protos"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] }
|
chrono = { version = "0.4.23", default-features = false, features = ["std", "clock"] }
|
||||||
|
|
|
@ -14,7 +14,6 @@ readme = "../README.md"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
protobuf-codegen = "3.2.0"
|
|
||||||
version_check = "0.9.4"
|
version_check = "0.9.4"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -32,7 +31,6 @@ maplit = "1.0.2"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
pest = "2.5.1"
|
pest = "2.5.1"
|
||||||
pest_derive = "2.5.1"
|
pest_derive = "2.5.1"
|
||||||
protobuf = { version = "3.0.1", features = ["with-bytes"] }
|
|
||||||
regex = "1.7.0"
|
regex = "1.7.0"
|
||||||
serde_json = "1.0.91"
|
serde_json = "1.0.91"
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
|
@ -42,6 +40,7 @@ uuid = { version = "1.2.2", features = ["v4"] }
|
||||||
whoami = "1.2.3"
|
whoami = "1.2.3"
|
||||||
zstd = "0.12.1"
|
zstd = "0.12.1"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
|
prost = "0.11.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_matches = "1.5.0"
|
assert_matches = "1.5.0"
|
||||||
|
|
18
lib/build.rs
18
lib/build.rs
|
@ -12,24 +12,12 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
fn main() {
|
fn main() -> std::io::Result<()> {
|
||||||
let input = &[
|
|
||||||
"src/protos/op_store.proto",
|
|
||||||
"src/protos/store.proto",
|
|
||||||
"src/protos/working_copy.proto",
|
|
||||||
];
|
|
||||||
protobuf_codegen::Codegen::new()
|
|
||||||
.pure()
|
|
||||||
.inputs(input)
|
|
||||||
.include("src/protos")
|
|
||||||
.cargo_out_dir("protos")
|
|
||||||
.run_from_script();
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
for file in input {
|
|
||||||
println!("cargo:rerun-if-changed={file}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(true) = version_check::supports_feature("map_first_last") {
|
if let Some(true) = version_check::supports_feature("map_first_last") {
|
||||||
println!("cargo:rustc-cfg=feature=\"map_first_last\"");
|
println!("cargo:rustc-cfg=feature=\"map_first_last\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
8
lib/gen-protos/Cargo.toml
Normal file
8
lib/gen-protos/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "gen-protos"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
prost-build = "0.11.5"
|
34
lib/gen-protos/src/main.rs
Normal file
34
lib/gen-protos/src/main.rs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2022 The Jujutsu Authors
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use std::io::Result;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let input = ["op_store.proto", "store.proto", "working_copy.proto"];
|
||||||
|
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
|
||||||
|
let protos_dir = root.join("src").join("protos");
|
||||||
|
|
||||||
|
prost_build::Config::new()
|
||||||
|
.out_dir(&protos_dir)
|
||||||
|
.include_file("mod.rs")
|
||||||
|
.compile_protos(
|
||||||
|
&input
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| protos_dir.join(x))
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
&[protos_dir],
|
||||||
|
)
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use git2::Oid;
|
use git2::Oid;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use protobuf::Message;
|
use prost::Message;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
|
@ -126,17 +126,18 @@ fn signature_to_git(signature: &Signature) -> git2::Signature {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_extras(commit: &Commit) -> Vec<u8> {
|
fn serialize_extras(commit: &Commit) -> Vec<u8> {
|
||||||
let mut proto = crate::protos::store::Commit::new();
|
let mut proto = crate::protos::store::Commit {
|
||||||
proto.change_id = commit.change_id.to_bytes();
|
change_id: commit.change_id.to_bytes(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
for predecessor in &commit.predecessors {
|
for predecessor in &commit.predecessors {
|
||||||
proto.predecessors.push(predecessor.to_bytes());
|
proto.predecessors.push(predecessor.to_bytes());
|
||||||
}
|
}
|
||||||
proto.write_to_bytes().unwrap()
|
proto.encode_to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_extras(commit: &mut Commit, bytes: &[u8]) {
|
fn deserialize_extras(commit: &mut Commit, bytes: &[u8]) {
|
||||||
let mut cursor = Cursor::new(bytes);
|
let proto = crate::protos::store::Commit::decode(bytes).unwrap();
|
||||||
let proto: crate::protos::store::Commit = Message::parse_from_reader(&mut cursor).unwrap();
|
|
||||||
commit.change_id = ChangeId::new(proto.change_id);
|
commit.change_id = ChangeId::new(proto.change_id);
|
||||||
for predecessor in &proto.predecessors {
|
for predecessor in &proto.predecessors {
|
||||||
commit.predecessors.push(CommitId::from_bytes(predecessor));
|
commit.predecessors.push(CommitId::from_bytes(predecessor));
|
||||||
|
|
|
@ -19,7 +19,7 @@ use std::io::{ErrorKind, Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use blake2::{Blake2b512, Digest};
|
use blake2::{Blake2b512, Digest};
|
||||||
use protobuf::{Message, MessageField};
|
use prost::Message;
|
||||||
use tempfile::{NamedTempFile, PersistError};
|
use tempfile::{NamedTempFile, PersistError};
|
||||||
|
|
||||||
use crate::backend::{
|
use crate::backend::{
|
||||||
|
@ -43,8 +43,8 @@ impl From<PersistError> for BackendError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<protobuf::Error> for BackendError {
|
impl From<prost::DecodeError> for BackendError {
|
||||||
fn from(err: protobuf::Error) -> Self {
|
fn from(err: prost::DecodeError) -> Self {
|
||||||
BackendError::Other(err.to_string())
|
BackendError::Other(err.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,17 +183,17 @@ impl Backend for LocalBackend {
|
||||||
|
|
||||||
fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
|
fn read_tree(&self, _path: &RepoPath, id: &TreeId) -> BackendResult<Tree> {
|
||||||
let path = self.tree_path(id);
|
let path = self.tree_path(id);
|
||||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
let buf = fs::read(path).map_err(not_found_to_backend_error)?;
|
||||||
|
|
||||||
let proto: crate::protos::store::Tree = Message::parse_from_reader(&mut file)?;
|
let proto = crate::protos::store::Tree::decode(&*buf)?;
|
||||||
Ok(tree_from_proto(&proto))
|
Ok(tree_from_proto(proto))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_tree(&self, _path: &RepoPath, tree: &Tree) -> BackendResult<TreeId> {
|
fn write_tree(&self, _path: &RepoPath, tree: &Tree) -> BackendResult<TreeId> {
|
||||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||||
|
|
||||||
let proto = tree_to_proto(tree);
|
let proto = tree_to_proto(tree);
|
||||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
temp_file.as_file().write_all(&proto.encode_to_vec())?;
|
||||||
|
|
||||||
let id = TreeId::new(blake2b_hash(tree).to_vec());
|
let id = TreeId::new(blake2b_hash(tree).to_vec());
|
||||||
|
|
||||||
|
@ -203,17 +203,17 @@ impl Backend for LocalBackend {
|
||||||
|
|
||||||
fn read_conflict(&self, _path: &RepoPath, id: &ConflictId) -> BackendResult<Conflict> {
|
fn read_conflict(&self, _path: &RepoPath, id: &ConflictId) -> BackendResult<Conflict> {
|
||||||
let path = self.conflict_path(id);
|
let path = self.conflict_path(id);
|
||||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
let buf = fs::read(path).map_err(not_found_to_backend_error)?;
|
||||||
|
|
||||||
let proto: crate::protos::store::Conflict = Message::parse_from_reader(&mut file)?;
|
let proto = crate::protos::store::Conflict::decode(&*buf)?;
|
||||||
Ok(conflict_from_proto(&proto))
|
Ok(conflict_from_proto(proto))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_conflict(&self, _path: &RepoPath, conflict: &Conflict) -> BackendResult<ConflictId> {
|
fn write_conflict(&self, _path: &RepoPath, conflict: &Conflict) -> BackendResult<ConflictId> {
|
||||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||||
|
|
||||||
let proto = conflict_to_proto(conflict);
|
let proto = conflict_to_proto(conflict);
|
||||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
temp_file.as_file().write_all(&proto.encode_to_vec())?;
|
||||||
|
|
||||||
let id = ConflictId::new(blake2b_hash(conflict).to_vec());
|
let id = ConflictId::new(blake2b_hash(conflict).to_vec());
|
||||||
|
|
||||||
|
@ -227,17 +227,17 @@ impl Backend for LocalBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = self.commit_path(id);
|
let path = self.commit_path(id);
|
||||||
let mut file = File::open(path).map_err(not_found_to_backend_error)?;
|
let buf = fs::read(path).map_err(not_found_to_backend_error)?;
|
||||||
|
|
||||||
let proto: crate::protos::store::Commit = Message::parse_from_reader(&mut file)?;
|
let proto = crate::protos::store::Commit::decode(&*buf)?;
|
||||||
Ok(commit_from_proto(&proto))
|
Ok(commit_from_proto(proto))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_commit(&self, commit: &Commit) -> BackendResult<CommitId> {
|
fn write_commit(&self, commit: &Commit) -> BackendResult<CommitId> {
|
||||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||||
|
|
||||||
let proto = commit_to_proto(commit);
|
let proto = commit_to_proto(commit);
|
||||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
temp_file.as_file().write_all(&proto.encode_to_vec())?;
|
||||||
|
|
||||||
let id = CommitId::new(blake2b_hash(commit).to_vec());
|
let id = CommitId::new(blake2b_hash(commit).to_vec());
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ impl Backend for LocalBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_to_proto(commit: &Commit) -> crate::protos::store::Commit {
|
pub fn commit_to_proto(commit: &Commit) -> crate::protos::store::Commit {
|
||||||
let mut proto = crate::protos::store::Commit::new();
|
let mut proto = crate::protos::store::Commit::default();
|
||||||
for parent in &commit.parents {
|
for parent in &commit.parents {
|
||||||
proto.parents.push(parent.to_bytes());
|
proto.parents.push(parent.to_bytes());
|
||||||
}
|
}
|
||||||
|
@ -257,115 +257,116 @@ pub fn commit_to_proto(commit: &Commit) -> crate::protos::store::Commit {
|
||||||
proto.root_tree = commit.root_tree.to_bytes();
|
proto.root_tree = commit.root_tree.to_bytes();
|
||||||
proto.change_id = commit.change_id.to_bytes();
|
proto.change_id = commit.change_id.to_bytes();
|
||||||
proto.description = commit.description.clone();
|
proto.description = commit.description.clone();
|
||||||
proto.author = MessageField::some(signature_to_proto(&commit.author));
|
proto.author = Some(signature_to_proto(&commit.author));
|
||||||
proto.committer = MessageField::some(signature_to_proto(&commit.committer));
|
proto.committer = Some(signature_to_proto(&commit.committer));
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_from_proto(proto: &crate::protos::store::Commit) -> Commit {
|
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.into_iter().map(CommitId::new).collect();
|
||||||
let parents = proto.parents.iter().map(commit_id_from_proto).collect();
|
let predecessors = proto.predecessors.into_iter().map(CommitId::new).collect();
|
||||||
let predecessors = proto
|
let root_tree = TreeId::new(proto.root_tree);
|
||||||
.predecessors
|
let change_id = ChangeId::new(proto.change_id);
|
||||||
.iter()
|
|
||||||
.map(commit_id_from_proto)
|
|
||||||
.collect();
|
|
||||||
let root_tree = TreeId::new(proto.root_tree.to_vec());
|
|
||||||
let change_id = ChangeId::new(proto.change_id.to_vec());
|
|
||||||
Commit {
|
Commit {
|
||||||
parents,
|
parents,
|
||||||
predecessors,
|
predecessors,
|
||||||
root_tree,
|
root_tree,
|
||||||
change_id,
|
change_id,
|
||||||
description: proto.description.clone(),
|
description: proto.description,
|
||||||
author: signature_from_proto(&proto.author),
|
author: signature_from_proto(proto.author.unwrap_or_default()),
|
||||||
committer: signature_from_proto(&proto.committer),
|
committer: signature_from_proto(proto.committer.unwrap_or_default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_to_proto(tree: &Tree) -> crate::protos::store::Tree {
|
fn tree_to_proto(tree: &Tree) -> crate::protos::store::Tree {
|
||||||
let mut proto = crate::protos::store::Tree::new();
|
let mut proto = crate::protos::store::Tree::default();
|
||||||
for entry in tree.entries() {
|
for entry in tree.entries() {
|
||||||
let mut proto_entry = crate::protos::store::tree::Entry::new();
|
proto.entries.push(crate::protos::store::tree::Entry {
|
||||||
proto_entry.name = entry.name().string();
|
name: entry.name().string(),
|
||||||
proto_entry.value = MessageField::some(tree_value_to_proto(entry.value()));
|
value: Some(tree_value_to_proto(entry.value())),
|
||||||
proto.entries.push(proto_entry);
|
});
|
||||||
}
|
}
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_from_proto(proto: &crate::protos::store::Tree) -> Tree {
|
fn tree_from_proto(proto: crate::protos::store::Tree) -> Tree {
|
||||||
let mut tree = Tree::default();
|
let mut tree = Tree::default();
|
||||||
for proto_entry in &proto.entries {
|
for proto_entry in proto.entries {
|
||||||
let value = tree_value_from_proto(proto_entry.value.as_ref().unwrap());
|
let value = tree_value_from_proto(proto_entry.value.unwrap());
|
||||||
tree.set(RepoPathComponent::from(proto_entry.name.as_str()), value);
|
tree.set(RepoPathComponent::from(proto_entry.name), value);
|
||||||
}
|
}
|
||||||
tree
|
tree
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_value_to_proto(value: &TreeValue) -> crate::protos::store::TreeValue {
|
fn tree_value_to_proto(value: &TreeValue) -> crate::protos::store::TreeValue {
|
||||||
let mut proto = crate::protos::store::TreeValue::new();
|
let mut proto = crate::protos::store::TreeValue::default();
|
||||||
match value {
|
match value {
|
||||||
TreeValue::File { id, executable } => {
|
TreeValue::File { id, executable } => {
|
||||||
let mut file = crate::protos::store::tree_value::File::new();
|
proto.value = Some(crate::protos::store::tree_value::Value::File(
|
||||||
file.id = id.to_bytes();
|
crate::protos::store::tree_value::File {
|
||||||
file.executable = *executable;
|
id: id.to_bytes(),
|
||||||
proto.set_file(file);
|
executable: *executable,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
TreeValue::Symlink(id) => {
|
TreeValue::Symlink(id) => {
|
||||||
proto.set_symlink_id(id.to_bytes());
|
proto.value = Some(crate::protos::store::tree_value::Value::SymlinkId(
|
||||||
|
id.to_bytes(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
TreeValue::GitSubmodule(_id) => {
|
TreeValue::GitSubmodule(_id) => {
|
||||||
panic!("cannot store git submodules");
|
panic!("cannot store git submodules");
|
||||||
}
|
}
|
||||||
TreeValue::Tree(id) => {
|
TreeValue::Tree(id) => {
|
||||||
proto.set_tree_id(id.to_bytes());
|
proto.value = Some(crate::protos::store::tree_value::Value::TreeId(
|
||||||
|
id.to_bytes(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
TreeValue::Conflict(id) => {
|
TreeValue::Conflict(id) => {
|
||||||
proto.set_conflict_id(id.to_bytes());
|
proto.value = Some(crate::protos::store::tree_value::Value::ConflictId(
|
||||||
|
id.to_bytes(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tree_value_from_proto(proto: &crate::protos::store::TreeValue) -> TreeValue {
|
fn tree_value_from_proto(proto: crate::protos::store::TreeValue) -> TreeValue {
|
||||||
match proto.value.as_ref().unwrap() {
|
match proto.value.unwrap() {
|
||||||
crate::protos::store::tree_value::Value::TreeId(id) => {
|
crate::protos::store::tree_value::Value::TreeId(id) => TreeValue::Tree(TreeId::new(id)),
|
||||||
TreeValue::Tree(TreeId::new(id.clone()))
|
|
||||||
}
|
|
||||||
crate::protos::store::tree_value::Value::File(crate::protos::store::tree_value::File {
|
crate::protos::store::tree_value::Value::File(crate::protos::store::tree_value::File {
|
||||||
id,
|
id,
|
||||||
executable,
|
executable,
|
||||||
..
|
..
|
||||||
}) => TreeValue::File {
|
}) => TreeValue::File {
|
||||||
id: FileId::new(id.clone()),
|
id: FileId::new(id),
|
||||||
executable: *executable,
|
executable,
|
||||||
},
|
},
|
||||||
crate::protos::store::tree_value::Value::SymlinkId(id) => {
|
crate::protos::store::tree_value::Value::SymlinkId(id) => {
|
||||||
TreeValue::Symlink(SymlinkId::new(id.clone()))
|
TreeValue::Symlink(SymlinkId::new(id))
|
||||||
}
|
}
|
||||||
crate::protos::store::tree_value::Value::ConflictId(id) => {
|
crate::protos::store::tree_value::Value::ConflictId(id) => {
|
||||||
TreeValue::Conflict(ConflictId::new(id.clone()))
|
TreeValue::Conflict(ConflictId::new(id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_to_proto(signature: &Signature) -> crate::protos::store::commit::Signature {
|
fn signature_to_proto(signature: &Signature) -> crate::protos::store::commit::Signature {
|
||||||
let mut proto = crate::protos::store::commit::Signature::new();
|
crate::protos::store::commit::Signature {
|
||||||
proto.name = signature.name.clone();
|
name: signature.name.clone(),
|
||||||
proto.email = signature.email.clone();
|
email: signature.email.clone(),
|
||||||
let mut timestamp_proto = crate::protos::store::commit::Timestamp::new();
|
timestamp: Some(crate::protos::store::commit::Timestamp {
|
||||||
timestamp_proto.millis_since_epoch = signature.timestamp.timestamp.0;
|
millis_since_epoch: signature.timestamp.timestamp.0,
|
||||||
timestamp_proto.tz_offset = signature.timestamp.tz_offset;
|
tz_offset: signature.timestamp.tz_offset,
|
||||||
proto.timestamp = MessageField::some(timestamp_proto);
|
}),
|
||||||
proto
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature_from_proto(proto: &crate::protos::store::commit::Signature) -> Signature {
|
fn signature_from_proto(proto: crate::protos::store::commit::Signature) -> Signature {
|
||||||
let timestamp = &proto.timestamp;
|
let timestamp = proto.timestamp.unwrap_or_default();
|
||||||
Signature {
|
Signature {
|
||||||
name: proto.name.clone(),
|
name: proto.name,
|
||||||
email: proto.email.clone(),
|
email: proto.email,
|
||||||
timestamp: Timestamp {
|
timestamp: Timestamp {
|
||||||
timestamp: MillisSinceEpoch(timestamp.millis_since_epoch),
|
timestamp: MillisSinceEpoch(timestamp.millis_since_epoch),
|
||||||
tz_offset: timestamp.tz_offset,
|
tz_offset: timestamp.tz_offset,
|
||||||
|
@ -374,7 +375,7 @@ fn signature_from_proto(proto: &crate::protos::store::commit::Signature) -> Sign
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conflict_to_proto(conflict: &Conflict) -> crate::protos::store::Conflict {
|
fn conflict_to_proto(conflict: &Conflict) -> crate::protos::store::Conflict {
|
||||||
let mut proto = crate::protos::store::Conflict::new();
|
let mut proto = crate::protos::store::Conflict::default();
|
||||||
for part in &conflict.adds {
|
for part in &conflict.adds {
|
||||||
proto.adds.push(conflict_part_to_proto(part));
|
proto.adds.push(conflict_part_to_proto(part));
|
||||||
}
|
}
|
||||||
|
@ -384,25 +385,25 @@ fn conflict_to_proto(conflict: &Conflict) -> crate::protos::store::Conflict {
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conflict_from_proto(proto: &crate::protos::store::Conflict) -> Conflict {
|
fn conflict_from_proto(proto: crate::protos::store::Conflict) -> Conflict {
|
||||||
let mut conflict = Conflict::default();
|
let mut conflict = Conflict::default();
|
||||||
for part in &proto.removes {
|
for part in proto.removes {
|
||||||
conflict.removes.push(conflict_part_from_proto(part))
|
conflict.removes.push(conflict_part_from_proto(part))
|
||||||
}
|
}
|
||||||
for part in &proto.adds {
|
for part in proto.adds {
|
||||||
conflict.adds.push(conflict_part_from_proto(part))
|
conflict.adds.push(conflict_part_from_proto(part))
|
||||||
}
|
}
|
||||||
conflict
|
conflict
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conflict_part_from_proto(proto: &crate::protos::store::conflict::Part) -> ConflictPart {
|
fn conflict_part_from_proto(proto: crate::protos::store::conflict::Part) -> ConflictPart {
|
||||||
ConflictPart {
|
ConflictPart {
|
||||||
value: tree_value_from_proto(proto.content.as_ref().unwrap()),
|
value: tree_value_from_proto(proto.content.unwrap()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn conflict_part_to_proto(part: &ConflictPart) -> crate::protos::store::conflict::Part {
|
fn conflict_part_to_proto(part: &ConflictPart) -> crate::protos::store::conflict::Part {
|
||||||
let mut proto = crate::protos::store::conflict::Part::new();
|
crate::protos::store::conflict::Part {
|
||||||
proto.content = MessageField::some(tree_value_to_proto(&part.value));
|
content: Some(tree_value_to_proto(&part.value)),
|
||||||
proto
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,11 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::io::{ErrorKind, Write};
|
||||||
use std::io::ErrorKind;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use protobuf::{Message, MessageField};
|
use prost::Message;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
|
|
||||||
use crate::backend::{CommitId, MillisSinceEpoch, Timestamp};
|
use crate::backend::{CommitId, MillisSinceEpoch, Timestamp};
|
||||||
|
@ -31,8 +30,8 @@ use crate::op_store::{
|
||||||
RefTarget, View, ViewId, WorkspaceId,
|
RefTarget, View, ViewId, WorkspaceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl From<protobuf::Error> for OpStoreError {
|
impl From<prost::DecodeError> for OpStoreError {
|
||||||
fn from(err: protobuf::Error) -> Self {
|
fn from(err: prost::DecodeError) -> Self {
|
||||||
OpStoreError::Other(err.to_string())
|
OpStoreError::Other(err.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,17 +62,17 @@ impl ProtoOpStore {
|
||||||
|
|
||||||
pub fn read_view(&self, id: &ViewId) -> OpStoreResult<View> {
|
pub fn read_view(&self, id: &ViewId) -> OpStoreResult<View> {
|
||||||
let path = self.view_path(id);
|
let path = self.view_path(id);
|
||||||
let mut file = File::open(path).map_err(not_found_to_store_error)?;
|
let buf = fs::read(path)?;
|
||||||
|
|
||||||
let proto: crate::protos::op_store::View = Message::parse_from_reader(&mut file)?;
|
let proto = crate::protos::op_store::View::decode(&*buf)?;
|
||||||
Ok(view_from_proto(&proto))
|
Ok(view_from_proto(proto))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_view(&self, view: &View) -> OpStoreResult<ViewId> {
|
pub fn write_view(&self, view: &View) -> OpStoreResult<ViewId> {
|
||||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||||
|
|
||||||
let proto = view_to_proto(view);
|
let proto = view_to_proto(view);
|
||||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
temp_file.as_file().write_all(&proto.encode_to_vec())?;
|
||||||
|
|
||||||
let id = ViewId::new(blake2b_hash(view).to_vec());
|
let id = ViewId::new(blake2b_hash(view).to_vec());
|
||||||
|
|
||||||
|
@ -83,17 +82,17 @@ impl ProtoOpStore {
|
||||||
|
|
||||||
pub fn read_operation(&self, id: &OperationId) -> OpStoreResult<Operation> {
|
pub fn read_operation(&self, id: &OperationId) -> OpStoreResult<Operation> {
|
||||||
let path = self.operation_path(id);
|
let path = self.operation_path(id);
|
||||||
let mut file = File::open(path).map_err(not_found_to_store_error)?;
|
let buf = fs::read(path).map_err(not_found_to_store_error)?;
|
||||||
|
|
||||||
let proto: crate::protos::op_store::Operation = Message::parse_from_reader(&mut file)?;
|
let proto = crate::protos::op_store::Operation::decode(&*buf)?;
|
||||||
Ok(operation_from_proto(&proto))
|
Ok(operation_from_proto(proto))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_operation(&self, operation: &Operation) -> OpStoreResult<OperationId> {
|
pub fn write_operation(&self, operation: &Operation) -> OpStoreResult<OperationId> {
|
||||||
let temp_file = NamedTempFile::new_in(&self.path)?;
|
let temp_file = NamedTempFile::new_in(&self.path)?;
|
||||||
|
|
||||||
let proto = operation_to_proto(operation);
|
let proto = operation_to_proto(operation);
|
||||||
proto.write_to_writer(&mut temp_file.as_file())?;
|
temp_file.as_file().write_all(&proto.encode_to_vec())?;
|
||||||
|
|
||||||
let id = OperationId::new(blake2b_hash(operation).to_vec());
|
let id = OperationId::new(blake2b_hash(operation).to_vec());
|
||||||
|
|
||||||
|
@ -111,13 +110,13 @@ fn not_found_to_store_error(err: std::io::Error) -> OpStoreError {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timestamp_to_proto(timestamp: &Timestamp) -> crate::protos::op_store::Timestamp {
|
fn timestamp_to_proto(timestamp: &Timestamp) -> crate::protos::op_store::Timestamp {
|
||||||
let mut proto = crate::protos::op_store::Timestamp::new();
|
crate::protos::op_store::Timestamp {
|
||||||
proto.millis_since_epoch = timestamp.timestamp.0;
|
millis_since_epoch: timestamp.timestamp.0,
|
||||||
proto.tz_offset = timestamp.tz_offset;
|
tz_offset: timestamp.tz_offset,
|
||||||
proto
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timestamp_from_proto(proto: &crate::protos::op_store::Timestamp) -> Timestamp {
|
fn timestamp_from_proto(proto: crate::protos::op_store::Timestamp) -> Timestamp {
|
||||||
Timestamp {
|
Timestamp {
|
||||||
timestamp: MillisSinceEpoch(proto.millis_since_epoch),
|
timestamp: MillisSinceEpoch(proto.millis_since_epoch),
|
||||||
tz_offset: proto.tz_offset,
|
tz_offset: proto.tz_offset,
|
||||||
|
@ -127,50 +126,47 @@ fn timestamp_from_proto(proto: &crate::protos::op_store::Timestamp) -> Timestamp
|
||||||
fn operation_metadata_to_proto(
|
fn operation_metadata_to_proto(
|
||||||
metadata: &OperationMetadata,
|
metadata: &OperationMetadata,
|
||||||
) -> crate::protos::op_store::OperationMetadata {
|
) -> crate::protos::op_store::OperationMetadata {
|
||||||
let mut proto = crate::protos::op_store::OperationMetadata::new();
|
crate::protos::op_store::OperationMetadata {
|
||||||
proto.start_time = MessageField::some(timestamp_to_proto(&metadata.start_time));
|
start_time: Some(timestamp_to_proto(&metadata.start_time)),
|
||||||
proto.end_time = MessageField::some(timestamp_to_proto(&metadata.end_time));
|
end_time: Some(timestamp_to_proto(&metadata.end_time)),
|
||||||
proto.description = metadata.description.clone();
|
description: metadata.description.clone(),
|
||||||
proto.hostname = metadata.hostname.clone();
|
hostname: metadata.hostname.clone(),
|
||||||
proto.username = metadata.username.clone();
|
username: metadata.username.clone(),
|
||||||
proto.tags = metadata.tags.clone();
|
tags: metadata.tags.clone(),
|
||||||
proto
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operation_metadata_from_proto(
|
fn operation_metadata_from_proto(
|
||||||
proto: &crate::protos::op_store::OperationMetadata,
|
proto: crate::protos::op_store::OperationMetadata,
|
||||||
) -> OperationMetadata {
|
) -> OperationMetadata {
|
||||||
let start_time = timestamp_from_proto(&proto.start_time);
|
let start_time = timestamp_from_proto(proto.start_time.unwrap_or_default());
|
||||||
let end_time = timestamp_from_proto(&proto.end_time);
|
let end_time = timestamp_from_proto(proto.end_time.unwrap_or_default());
|
||||||
let description = proto.description.to_owned();
|
|
||||||
let hostname = proto.hostname.to_owned();
|
|
||||||
let username = proto.username.to_owned();
|
|
||||||
let tags = proto.tags.clone();
|
|
||||||
OperationMetadata {
|
OperationMetadata {
|
||||||
start_time,
|
start_time,
|
||||||
end_time,
|
end_time,
|
||||||
description,
|
description: proto.description,
|
||||||
hostname,
|
hostname: proto.hostname,
|
||||||
username,
|
username: proto.username,
|
||||||
tags,
|
tags: proto.tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operation_to_proto(operation: &Operation) -> crate::protos::op_store::Operation {
|
fn operation_to_proto(operation: &Operation) -> crate::protos::op_store::Operation {
|
||||||
let mut proto = crate::protos::op_store::Operation::new();
|
let mut proto = crate::protos::op_store::Operation {
|
||||||
proto.view_id = operation.view_id.as_bytes().to_vec();
|
view_id: operation.view_id.as_bytes().to_vec(),
|
||||||
|
metadata: Some(operation_metadata_to_proto(&operation.metadata)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
for parent in &operation.parents {
|
for parent in &operation.parents {
|
||||||
proto.parents.push(parent.to_bytes());
|
proto.parents.push(parent.to_bytes());
|
||||||
}
|
}
|
||||||
proto.metadata = MessageField::some(operation_metadata_to_proto(&operation.metadata));
|
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operation_from_proto(proto: &crate::protos::op_store::Operation) -> Operation {
|
fn operation_from_proto(proto: crate::protos::op_store::Operation) -> Operation {
|
||||||
let operation_id_from_proto = |parent: &Vec<u8>| OperationId::new(parent.clone());
|
let parents = proto.parents.into_iter().map(OperationId::new).collect();
|
||||||
let parents = proto.parents.iter().map(operation_id_from_proto).collect();
|
let view_id = ViewId::new(proto.view_id);
|
||||||
let view_id = ViewId::new(proto.view_id.clone());
|
let metadata = operation_metadata_from_proto(proto.metadata.unwrap_or_default());
|
||||||
let metadata = operation_metadata_from_proto(&proto.metadata);
|
|
||||||
Operation {
|
Operation {
|
||||||
view_id,
|
view_id,
|
||||||
parents,
|
parents,
|
||||||
|
@ -179,7 +175,7 @@ fn operation_from_proto(proto: &crate::protos::op_store::Operation) -> Operation
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_to_proto(view: &View) -> crate::protos::op_store::View {
|
fn view_to_proto(view: &View) -> crate::protos::op_store::View {
|
||||||
let mut proto = crate::protos::op_store::View::new();
|
let mut proto = crate::protos::op_store::View::default();
|
||||||
for (workspace_id, commit_id) in &view.wc_commit_ids {
|
for (workspace_id, commit_id) in &view.wc_commit_ids {
|
||||||
proto
|
proto
|
||||||
.wc_commit_ids
|
.wc_commit_ids
|
||||||
|
@ -193,32 +189,38 @@ fn view_to_proto(view: &View) -> crate::protos::op_store::View {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, target) in &view.branches {
|
for (name, target) in &view.branches {
|
||||||
let mut branch_proto = crate::protos::op_store::Branch::new();
|
let mut branch_proto = crate::protos::op_store::Branch {
|
||||||
|
name: name.clone(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
branch_proto.name = name.clone();
|
branch_proto.name = name.clone();
|
||||||
if let Some(local_target) = &target.local_target {
|
if let Some(local_target) = &target.local_target {
|
||||||
branch_proto.local_target = MessageField::some(ref_target_to_proto(local_target));
|
branch_proto.local_target = Some(ref_target_to_proto(local_target));
|
||||||
}
|
}
|
||||||
for (remote_name, target) in &target.remote_targets {
|
for (remote_name, target) in &target.remote_targets {
|
||||||
let mut remote_branch_proto = crate::protos::op_store::RemoteBranch::new();
|
branch_proto
|
||||||
remote_branch_proto.remote_name = remote_name.clone();
|
.remote_branches
|
||||||
remote_branch_proto.target = MessageField::some(ref_target_to_proto(target));
|
.push(crate::protos::op_store::RemoteBranch {
|
||||||
branch_proto.remote_branches.push(remote_branch_proto);
|
remote_name: remote_name.clone(),
|
||||||
|
target: Some(ref_target_to_proto(target)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
proto.branches.push(branch_proto);
|
proto.branches.push(branch_proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, target) in &view.tags {
|
for (name, target) in &view.tags {
|
||||||
let mut tag_proto = crate::protos::op_store::Tag::new();
|
proto.tags.push(crate::protos::op_store::Tag {
|
||||||
tag_proto.name = name.clone();
|
name: name.clone(),
|
||||||
tag_proto.target = MessageField::some(ref_target_to_proto(target));
|
target: Some(ref_target_to_proto(target)),
|
||||||
proto.tags.push(tag_proto);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (git_ref_name, target) in &view.git_refs {
|
for (git_ref_name, target) in &view.git_refs {
|
||||||
let mut git_ref_proto = crate::protos::op_store::GitRef::new();
|
proto.git_refs.push(crate::protos::op_store::GitRef {
|
||||||
git_ref_proto.name = git_ref_name.clone();
|
name: git_ref_name.clone(),
|
||||||
git_ref_proto.target = MessageField::some(ref_target_to_proto(target));
|
target: Some(ref_target_to_proto(target)),
|
||||||
proto.git_refs.push(git_ref_proto);
|
..Default::default()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(git_head) = &view.git_head {
|
if let Some(git_head) = &view.git_head {
|
||||||
|
@ -228,41 +230,34 @@ fn view_to_proto(view: &View) -> crate::protos::op_store::View {
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_from_proto(proto: &crate::protos::op_store::View) -> View {
|
fn view_from_proto(proto: crate::protos::op_store::View) -> View {
|
||||||
let mut view = View::default();
|
let mut view = View::default();
|
||||||
// For compatibility with old repos before we had support for multiple working
|
// For compatibility with old repos before we had support for multiple working
|
||||||
// copies
|
// copies
|
||||||
|
#[allow(deprecated)]
|
||||||
if !proto.wc_commit_id.is_empty() {
|
if !proto.wc_commit_id.is_empty() {
|
||||||
view.wc_commit_ids.insert(
|
view.wc_commit_ids
|
||||||
WorkspaceId::default(),
|
.insert(WorkspaceId::default(), CommitId::new(proto.wc_commit_id));
|
||||||
CommitId::new(proto.wc_commit_id.clone()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for (workspace_id, commit_id) in &proto.wc_commit_ids {
|
for (workspace_id, commit_id) in proto.wc_commit_ids {
|
||||||
view.wc_commit_ids.insert(
|
view.wc_commit_ids
|
||||||
WorkspaceId::new(workspace_id.clone()),
|
.insert(WorkspaceId::new(workspace_id), CommitId::new(commit_id));
|
||||||
CommitId::new(commit_id.clone()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
for head_id_bytes in &proto.head_ids {
|
for head_id_bytes in proto.head_ids {
|
||||||
view.head_ids.insert(CommitId::from_bytes(head_id_bytes));
|
view.head_ids.insert(CommitId::new(head_id_bytes));
|
||||||
}
|
}
|
||||||
for head_id_bytes in &proto.public_head_ids {
|
for head_id_bytes in proto.public_head_ids {
|
||||||
view.public_head_ids
|
view.public_head_ids.insert(CommitId::new(head_id_bytes));
|
||||||
.insert(CommitId::from_bytes(head_id_bytes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for branch_proto in &proto.branches {
|
for branch_proto in proto.branches {
|
||||||
let local_target = branch_proto
|
let local_target = branch_proto.local_target.map(ref_target_from_proto);
|
||||||
.local_target
|
|
||||||
.as_ref()
|
|
||||||
.map(ref_target_from_proto);
|
|
||||||
|
|
||||||
let mut remote_targets = BTreeMap::new();
|
let mut remote_targets = BTreeMap::new();
|
||||||
for remote_branch in &branch_proto.remote_branches {
|
for remote_branch in branch_proto.remote_branches {
|
||||||
remote_targets.insert(
|
remote_targets.insert(
|
||||||
remote_branch.remote_name.clone(),
|
remote_branch.remote_name,
|
||||||
ref_target_from_proto(&remote_branch.target),
|
ref_target_from_proto(remote_branch.target.unwrap_or_default()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,69 +270,69 @@ fn view_from_proto(proto: &crate::protos::op_store::View) -> View {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for tag_proto in &proto.tags {
|
for tag_proto in proto.tags {
|
||||||
view.tags.insert(
|
view.tags.insert(
|
||||||
tag_proto.name.clone(),
|
tag_proto.name,
|
||||||
ref_target_from_proto(&tag_proto.target),
|
ref_target_from_proto(tag_proto.target.unwrap_or_default()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for git_ref in &proto.git_refs {
|
for git_ref in proto.git_refs {
|
||||||
if let Some(target) = git_ref.target.as_ref() {
|
if let Some(target) = git_ref.target {
|
||||||
view.git_refs
|
view.git_refs
|
||||||
.insert(git_ref.name.clone(), ref_target_from_proto(target));
|
.insert(git_ref.name, ref_target_from_proto(target));
|
||||||
} else {
|
} else {
|
||||||
// Legacy format
|
// Legacy format
|
||||||
view.git_refs.insert(
|
view.git_refs.insert(
|
||||||
git_ref.name.clone(),
|
git_ref.name,
|
||||||
RefTarget::Normal(CommitId::new(git_ref.commit_id.clone())),
|
RefTarget::Normal(CommitId::new(git_ref.commit_id)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !proto.git_head.is_empty() {
|
if !proto.git_head.is_empty() {
|
||||||
view.git_head = Some(CommitId::new(proto.git_head.clone()));
|
view.git_head = Some(CommitId::new(proto.git_head));
|
||||||
}
|
}
|
||||||
|
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ref_target_to_proto(value: &RefTarget) -> crate::protos::op_store::RefTarget {
|
fn ref_target_to_proto(value: &RefTarget) -> crate::protos::op_store::RefTarget {
|
||||||
let mut proto = crate::protos::op_store::RefTarget::new();
|
let mut proto = crate::protos::op_store::RefTarget::default();
|
||||||
match value {
|
match value {
|
||||||
RefTarget::Normal(id) => {
|
RefTarget::Normal(id) => {
|
||||||
proto.set_commit_id(id.to_bytes());
|
proto.value = Some(crate::protos::op_store::ref_target::Value::CommitId(
|
||||||
|
id.to_bytes(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
RefTarget::Conflict { removes, adds } => {
|
RefTarget::Conflict { removes, adds } => {
|
||||||
let mut ref_conflict_proto = crate::protos::op_store::RefConflict::new();
|
let mut ref_conflict_proto = crate::protos::op_store::RefConflict::default();
|
||||||
for id in removes {
|
for id in removes {
|
||||||
ref_conflict_proto.removes.push(id.to_bytes());
|
ref_conflict_proto.removes.push(id.to_bytes());
|
||||||
}
|
}
|
||||||
for id in adds {
|
for id in adds {
|
||||||
ref_conflict_proto.adds.push(id.to_bytes());
|
ref_conflict_proto.adds.push(id.to_bytes());
|
||||||
}
|
}
|
||||||
proto.set_conflict(ref_conflict_proto);
|
proto.value = Some(crate::protos::op_store::ref_target::Value::Conflict(
|
||||||
|
ref_conflict_proto,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proto
|
proto
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ref_target_from_proto(proto: &crate::protos::op_store::RefTarget) -> RefTarget {
|
fn ref_target_from_proto(proto: crate::protos::op_store::RefTarget) -> RefTarget {
|
||||||
match proto.value.as_ref().unwrap() {
|
match proto.value.unwrap() {
|
||||||
crate::protos::op_store::ref_target::Value::CommitId(id) => {
|
crate::protos::op_store::ref_target::Value::CommitId(id) => {
|
||||||
RefTarget::Normal(CommitId::from_bytes(id))
|
RefTarget::Normal(CommitId::new(id))
|
||||||
}
|
}
|
||||||
crate::protos::op_store::ref_target::Value::Conflict(conflict) => {
|
crate::protos::op_store::ref_target::Value::Conflict(conflict) => {
|
||||||
let removes = conflict
|
let removes = conflict
|
||||||
.removes
|
.removes
|
||||||
.iter()
|
.into_iter()
|
||||||
.map(|id_bytes| CommitId::from_bytes(id_bytes))
|
.map(CommitId::new)
|
||||||
.collect_vec();
|
|
||||||
let adds = conflict
|
|
||||||
.adds
|
|
||||||
.iter()
|
|
||||||
.map(|id_bytes| CommitId::from_bytes(id_bytes))
|
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
let adds = conflict.adds.into_iter().map(CommitId::new).collect_vec();
|
||||||
RefTarget::Conflict { removes, adds }
|
RefTarget::Conflict { removes, adds }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
// Copyright 2020 The Jujutsu Authors
|
pub mod op_store {
|
||||||
//
|
include!("op_store.rs");
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
}
|
||||||
// you may not use this file except in compliance with the License.
|
pub mod store {
|
||||||
// You may obtain a copy of the License at
|
include!("store.rs");
|
||||||
//
|
}
|
||||||
// https://www.apache.org/licenses/LICENSE-2.0
|
pub mod working_copy {
|
||||||
//
|
include!("working_copy.rs");
|
||||||
// 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.
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));
|
|
||||||
|
|
132
lib/src/protos/op_store.rs
Normal file
132
lib/src/protos/op_store.rs
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct RefConflict {
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "1")]
|
||||||
|
pub removes: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "2")]
|
||||||
|
pub adds: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct RefTarget {
|
||||||
|
#[prost(oneof = "ref_target::Value", tags = "1, 2")]
|
||||||
|
pub value: ::core::option::Option<ref_target::Value>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `RefTarget`.
|
||||||
|
pub mod ref_target {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
|
pub enum Value {
|
||||||
|
#[prost(bytes, tag = "1")]
|
||||||
|
CommitId(::prost::alloc::vec::Vec<u8>),
|
||||||
|
#[prost(message, tag = "2")]
|
||||||
|
Conflict(super::RefConflict),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct RemoteBranch {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub remote_name: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub target: ::core::option::Option<RefTarget>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Branch {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: ::prost::alloc::string::String,
|
||||||
|
/// Unset if the branch has been deleted locally.
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub local_target: ::core::option::Option<RefTarget>,
|
||||||
|
/// TODO: How would we support renaming remotes while having undo work? If
|
||||||
|
/// the remote name is stored in config, it's going to become a mess if the
|
||||||
|
/// remote is renamed but the configs are left unchanged. Should each remote
|
||||||
|
/// be identified (here and in configs) by a UUID?
|
||||||
|
#[prost(message, repeated, tag = "3")]
|
||||||
|
pub remote_branches: ::prost::alloc::vec::Vec<RemoteBranch>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct GitRef {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: ::prost::alloc::string::String,
|
||||||
|
/// This field is just for historical reasons (before we had the RefTarget
|
||||||
|
/// type). New GitRefs have (only) the target field.
|
||||||
|
/// TODO: Delete support for the old format.
|
||||||
|
#[prost(bytes = "vec", tag = "2")]
|
||||||
|
pub commit_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(message, optional, tag = "3")]
|
||||||
|
pub target: ::core::option::Option<RefTarget>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Tag {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub target: ::core::option::Option<RefTarget>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct View {
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "1")]
|
||||||
|
pub head_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "4")]
|
||||||
|
pub public_head_ids: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[deprecated]
|
||||||
|
#[prost(bytes = "vec", tag = "2")]
|
||||||
|
pub wc_commit_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(map = "string, bytes", tag = "8")]
|
||||||
|
pub wc_commit_ids: ::std::collections::HashMap<
|
||||||
|
::prost::alloc::string::String,
|
||||||
|
::prost::alloc::vec::Vec<u8>,
|
||||||
|
>,
|
||||||
|
#[prost(message, repeated, tag = "5")]
|
||||||
|
pub branches: ::prost::alloc::vec::Vec<Branch>,
|
||||||
|
#[prost(message, repeated, tag = "6")]
|
||||||
|
pub tags: ::prost::alloc::vec::Vec<Tag>,
|
||||||
|
/// Only a subset of the refs. For example, does not include refs/notes/.
|
||||||
|
#[prost(message, repeated, tag = "3")]
|
||||||
|
pub git_refs: ::prost::alloc::vec::Vec<GitRef>,
|
||||||
|
#[prost(bytes = "vec", tag = "7")]
|
||||||
|
pub git_head: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Operation {
|
||||||
|
#[prost(bytes = "vec", tag = "1")]
|
||||||
|
pub view_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "2")]
|
||||||
|
pub parents: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[prost(message, optional, tag = "3")]
|
||||||
|
pub metadata: ::core::option::Option<OperationMetadata>,
|
||||||
|
}
|
||||||
|
/// TODO: Share with store.proto? Do we even need the timezone here?
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Timestamp {
|
||||||
|
#[prost(int64, tag = "1")]
|
||||||
|
pub millis_since_epoch: i64,
|
||||||
|
#[prost(int32, tag = "2")]
|
||||||
|
pub tz_offset: i32,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct OperationMetadata {
|
||||||
|
#[prost(message, optional, tag = "1")]
|
||||||
|
pub start_time: ::core::option::Option<Timestamp>,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub end_time: ::core::option::Option<Timestamp>,
|
||||||
|
#[prost(string, tag = "3")]
|
||||||
|
pub description: ::prost::alloc::string::String,
|
||||||
|
#[prost(string, tag = "4")]
|
||||||
|
pub hostname: ::prost::alloc::string::String,
|
||||||
|
#[prost(string, tag = "5")]
|
||||||
|
pub username: ::prost::alloc::string::String,
|
||||||
|
#[prost(map = "string, string", tag = "6")]
|
||||||
|
pub tags: ::std::collections::HashMap<
|
||||||
|
::prost::alloc::string::String,
|
||||||
|
::prost::alloc::string::String,
|
||||||
|
>,
|
||||||
|
}
|
108
lib/src/protos/store.rs
Normal file
108
lib/src/protos/store.rs
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct TreeValue {
|
||||||
|
#[prost(oneof = "tree_value::Value", tags = "2, 3, 4, 5")]
|
||||||
|
pub value: ::core::option::Option<tree_value::Value>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `TreeValue`.
|
||||||
|
pub mod tree_value {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct File {
|
||||||
|
#[prost(bytes = "vec", tag = "1")]
|
||||||
|
pub id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(bool, tag = "2")]
|
||||||
|
pub executable: bool,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
|
pub enum Value {
|
||||||
|
#[prost(message, tag = "2")]
|
||||||
|
File(File),
|
||||||
|
#[prost(bytes, tag = "3")]
|
||||||
|
SymlinkId(::prost::alloc::vec::Vec<u8>),
|
||||||
|
#[prost(bytes, tag = "4")]
|
||||||
|
TreeId(::prost::alloc::vec::Vec<u8>),
|
||||||
|
#[prost(bytes, tag = "5")]
|
||||||
|
ConflictId(::prost::alloc::vec::Vec<u8>),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Tree {
|
||||||
|
#[prost(message, repeated, tag = "1")]
|
||||||
|
pub entries: ::prost::alloc::vec::Vec<tree::Entry>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `Tree`.
|
||||||
|
pub mod tree {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Entry {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "2")]
|
||||||
|
pub value: ::core::option::Option<super::TreeValue>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Commit {
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "1")]
|
||||||
|
pub parents: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[prost(bytes = "vec", repeated, tag = "2")]
|
||||||
|
pub predecessors: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||||
|
#[prost(bytes = "vec", tag = "3")]
|
||||||
|
pub root_tree: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(bytes = "vec", tag = "4")]
|
||||||
|
pub change_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(string, tag = "5")]
|
||||||
|
pub description: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "6")]
|
||||||
|
pub author: ::core::option::Option<commit::Signature>,
|
||||||
|
#[prost(message, optional, tag = "7")]
|
||||||
|
pub committer: ::core::option::Option<commit::Signature>,
|
||||||
|
#[deprecated]
|
||||||
|
#[prost(bool, tag = "8")]
|
||||||
|
pub is_open: bool,
|
||||||
|
#[deprecated]
|
||||||
|
#[prost(bool, tag = "9")]
|
||||||
|
pub is_pruned: bool,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `Commit`.
|
||||||
|
pub mod commit {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Timestamp {
|
||||||
|
#[prost(int64, tag = "1")]
|
||||||
|
pub millis_since_epoch: i64,
|
||||||
|
#[prost(int32, tag = "2")]
|
||||||
|
pub tz_offset: i32,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Signature {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub name: ::prost::alloc::string::String,
|
||||||
|
#[prost(string, tag = "2")]
|
||||||
|
pub email: ::prost::alloc::string::String,
|
||||||
|
#[prost(message, optional, tag = "3")]
|
||||||
|
pub timestamp: ::core::option::Option<Timestamp>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Conflict {
|
||||||
|
#[prost(message, repeated, tag = "1")]
|
||||||
|
pub removes: ::prost::alloc::vec::Vec<conflict::Part>,
|
||||||
|
#[prost(message, repeated, tag = "2")]
|
||||||
|
pub adds: ::prost::alloc::vec::Vec<conflict::Part>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `Conflict`.
|
||||||
|
pub mod conflict {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Part {
|
||||||
|
#[prost(message, optional, tag = "1")]
|
||||||
|
pub content: ::core::option::Option<super::TreeValue>,
|
||||||
|
}
|
||||||
|
}
|
85
lib/src/protos/working_copy.rs
Normal file
85
lib/src/protos/working_copy.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct FileState {
|
||||||
|
#[prost(int64, tag = "1")]
|
||||||
|
pub mtime_millis_since_epoch: i64,
|
||||||
|
#[prost(uint64, tag = "2")]
|
||||||
|
pub size: u64,
|
||||||
|
#[prost(enumeration = "FileType", tag = "3")]
|
||||||
|
pub file_type: i32,
|
||||||
|
/// Set only if file_type is Conflict
|
||||||
|
#[prost(bytes = "vec", tag = "4")]
|
||||||
|
pub conflict_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct SparsePatterns {
|
||||||
|
#[prost(string, repeated, tag = "1")]
|
||||||
|
pub prefixes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct TreeState {
|
||||||
|
#[prost(bytes = "vec", tag = "1")]
|
||||||
|
pub tree_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
#[prost(map = "string, message", tag = "2")]
|
||||||
|
pub file_states: ::std::collections::HashMap<
|
||||||
|
::prost::alloc::string::String,
|
||||||
|
FileState,
|
||||||
|
>,
|
||||||
|
#[prost(message, optional, tag = "3")]
|
||||||
|
pub sparse_patterns: ::core::option::Option<SparsePatterns>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Checkout {
|
||||||
|
/// The operation at which the working copy was updated.
|
||||||
|
#[prost(bytes = "vec", tag = "2")]
|
||||||
|
pub operation_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
/// An identifier for this workspace. It is used for looking up the current
|
||||||
|
/// checkout in the repo view. Currently a human-readable name.
|
||||||
|
/// TODO: Is it better to make this a UUID and a have map that to a name in
|
||||||
|
/// config? That way users can rename a workspace.
|
||||||
|
#[prost(string, tag = "3")]
|
||||||
|
pub workspace_id: ::prost::alloc::string::String,
|
||||||
|
/// The checked-out commit, which can be viewed as a cache of the working-copy
|
||||||
|
/// commit ID recorded in `operation_id`'s operation. No longer used.
|
||||||
|
/// TODO: Delete this mid 2022 or so
|
||||||
|
#[prost(bytes = "vec", tag = "1")]
|
||||||
|
pub commit_id: ::prost::alloc::vec::Vec<u8>,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum FileType {
|
||||||
|
Normal = 0,
|
||||||
|
Symlink = 1,
|
||||||
|
Executable = 2,
|
||||||
|
Conflict = 3,
|
||||||
|
GitSubmodule = 4,
|
||||||
|
}
|
||||||
|
impl FileType {
|
||||||
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
|
///
|
||||||
|
/// The values are not transformed in any way and thus are considered stable
|
||||||
|
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||||
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
FileType::Normal => "Normal",
|
||||||
|
FileType::Symlink => "Symlink",
|
||||||
|
FileType::Executable => "Executable",
|
||||||
|
FileType::Conflict => "Conflict",
|
||||||
|
FileType::GitSubmodule => "GitSubmodule",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
|
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||||
|
match value {
|
||||||
|
"Normal" => Some(Self::Normal),
|
||||||
|
"Symlink" => Some(Self::Symlink),
|
||||||
|
"Executable" => Some(Self::Executable),
|
||||||
|
"Conflict" => Some(Self::Conflict),
|
||||||
|
"GitSubmodule" => Some(Self::GitSubmodule),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,10 +39,14 @@ impl RepoPathComponent {
|
||||||
|
|
||||||
impl From<&str> for RepoPathComponent {
|
impl From<&str> for RepoPathComponent {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
|
RepoPathComponent::from(value.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for RepoPathComponent {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
assert!(!value.contains('/'));
|
assert!(!value.contains('/'));
|
||||||
RepoPathComponent {
|
RepoPathComponent { value }
|
||||||
value: value.to_owned(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ use std::sync::Arc;
|
||||||
use std::time::UNIX_EPOCH;
|
use std::time::UNIX_EPOCH;
|
||||||
|
|
||||||
use once_cell::unsync::OnceCell;
|
use once_cell::unsync::OnceCell;
|
||||||
use protobuf::{EnumOrUnknown, Message, MessageField};
|
use prost::Message;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -125,13 +125,13 @@ pub struct TreeState {
|
||||||
own_mtime: MillisSinceEpoch,
|
own_mtime: MillisSinceEpoch,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_state_from_proto(proto: &crate::protos::working_copy::FileState) -> FileState {
|
fn file_state_from_proto(proto: crate::protos::working_copy::FileState) -> FileState {
|
||||||
let file_type = match proto.file_type.enum_value_or_default() {
|
let file_type = match proto.file_type() {
|
||||||
crate::protos::working_copy::FileType::Normal => FileType::Normal { executable: false },
|
crate::protos::working_copy::FileType::Normal => FileType::Normal { executable: false },
|
||||||
crate::protos::working_copy::FileType::Executable => FileType::Normal { executable: true },
|
crate::protos::working_copy::FileType::Executable => FileType::Normal { executable: true },
|
||||||
crate::protos::working_copy::FileType::Symlink => FileType::Symlink,
|
crate::protos::working_copy::FileType::Symlink => FileType::Symlink,
|
||||||
crate::protos::working_copy::FileType::Conflict => {
|
crate::protos::working_copy::FileType::Conflict => {
|
||||||
let id = ConflictId::new(proto.conflict_id.to_vec());
|
let id = ConflictId::new(proto.conflict_id);
|
||||||
FileType::Conflict { id }
|
FileType::Conflict { id }
|
||||||
}
|
}
|
||||||
crate::protos::working_copy::FileType::GitSubmodule => FileType::GitSubmodule,
|
crate::protos::working_copy::FileType::GitSubmodule => FileType::GitSubmodule,
|
||||||
|
@ -144,7 +144,7 @@ fn file_state_from_proto(proto: &crate::protos::working_copy::FileState) -> File
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_state_to_proto(file_state: &FileState) -> crate::protos::working_copy::FileState {
|
fn file_state_to_proto(file_state: &FileState) -> crate::protos::working_copy::FileState {
|
||||||
let mut proto = crate::protos::working_copy::FileState::new();
|
let mut proto = crate::protos::working_copy::FileState::default();
|
||||||
let file_type = match &file_state.file_type {
|
let file_type = match &file_state.file_type {
|
||||||
FileType::Normal { executable: false } => crate::protos::working_copy::FileType::Normal,
|
FileType::Normal { executable: false } => crate::protos::working_copy::FileType::Normal,
|
||||||
FileType::Normal { executable: true } => crate::protos::working_copy::FileType::Executable,
|
FileType::Normal { executable: true } => crate::protos::working_copy::FileType::Executable,
|
||||||
|
@ -155,7 +155,7 @@ fn file_state_to_proto(file_state: &FileState) -> crate::protos::working_copy::F
|
||||||
}
|
}
|
||||||
FileType::GitSubmodule => crate::protos::working_copy::FileType::GitSubmodule,
|
FileType::GitSubmodule => crate::protos::working_copy::FileType::GitSubmodule,
|
||||||
};
|
};
|
||||||
proto.file_type = EnumOrUnknown::new(file_type);
|
proto.file_type = file_type as i32;
|
||||||
proto.mtime_millis_since_epoch = file_state.mtime.0;
|
proto.mtime_millis_since_epoch = file_state.mtime.0;
|
||||||
proto.size = file_state.size;
|
proto.size = file_state.size;
|
||||||
proto
|
proto
|
||||||
|
@ -167,7 +167,7 @@ fn file_states_from_proto(
|
||||||
let mut file_states = BTreeMap::new();
|
let mut file_states = BTreeMap::new();
|
||||||
for (path_str, proto_file_state) in &proto.file_states {
|
for (path_str, proto_file_state) in &proto.file_states {
|
||||||
let path = RepoPath::from_internal_string(path_str.as_str());
|
let path = RepoPath::from_internal_string(path_str.as_str());
|
||||||
file_states.insert(path, file_state_from_proto(proto_file_state));
|
file_states.insert(path, file_state_from_proto(proto_file_state.clone()));
|
||||||
}
|
}
|
||||||
file_states
|
file_states
|
||||||
}
|
}
|
||||||
|
@ -401,32 +401,38 @@ impl TreeState {
|
||||||
|
|
||||||
fn read(&mut self, mut file: File) {
|
fn read(&mut self, mut file: File) {
|
||||||
self.update_own_mtime();
|
self.update_own_mtime();
|
||||||
let proto: crate::protos::working_copy::TreeState =
|
let mut buf = Vec::new();
|
||||||
Message::parse_from_reader(&mut file).unwrap();
|
file.read_to_end(&mut buf).unwrap();
|
||||||
|
let proto = crate::protos::working_copy::TreeState::decode(&*buf).unwrap();
|
||||||
self.tree_id = TreeId::new(proto.tree_id.clone());
|
self.tree_id = TreeId::new(proto.tree_id.clone());
|
||||||
self.file_states = file_states_from_proto(&proto);
|
self.file_states = file_states_from_proto(&proto);
|
||||||
self.sparse_patterns = sparse_patterns_from_proto(&proto);
|
self.sparse_patterns = sparse_patterns_from_proto(&proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self) {
|
fn save(&mut self) {
|
||||||
let mut proto = crate::protos::working_copy::TreeState::new();
|
let mut proto = crate::protos::working_copy::TreeState {
|
||||||
proto.tree_id = self.tree_id.to_bytes();
|
tree_id: self.tree_id.to_bytes(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
for (file, file_state) in &self.file_states {
|
for (file, file_state) in &self.file_states {
|
||||||
proto.file_states.insert(
|
proto.file_states.insert(
|
||||||
file.to_internal_file_string(),
|
file.to_internal_file_string(),
|
||||||
file_state_to_proto(file_state),
|
file_state_to_proto(file_state),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let mut sparse_patterns = crate::protos::working_copy::SparsePatterns::new();
|
let mut sparse_patterns = crate::protos::working_copy::SparsePatterns::default();
|
||||||
for path in &self.sparse_patterns {
|
for path in &self.sparse_patterns {
|
||||||
sparse_patterns
|
sparse_patterns
|
||||||
.prefixes
|
.prefixes
|
||||||
.push(path.to_internal_file_string());
|
.push(path.to_internal_file_string());
|
||||||
}
|
}
|
||||||
proto.sparse_patterns = MessageField::some(sparse_patterns);
|
proto.sparse_patterns = Some(sparse_patterns);
|
||||||
|
|
||||||
let mut temp_file = NamedTempFile::new_in(&self.state_path).unwrap();
|
let mut temp_file = NamedTempFile::new_in(&self.state_path).unwrap();
|
||||||
proto.write_to_writer(temp_file.as_file_mut()).unwrap();
|
temp_file
|
||||||
|
.as_file_mut()
|
||||||
|
.write_all(&proto.encode_to_vec())
|
||||||
|
.unwrap();
|
||||||
// update own write time while we before we rename it, so we know
|
// update own write time while we before we rename it, so we know
|
||||||
// there is no unknown data in it
|
// there is no unknown data in it
|
||||||
self.update_own_mtime();
|
self.update_own_mtime();
|
||||||
|
@ -1012,15 +1018,17 @@ impl WorkingCopy {
|
||||||
operation_id: OperationId,
|
operation_id: OperationId,
|
||||||
workspace_id: WorkspaceId,
|
workspace_id: WorkspaceId,
|
||||||
) -> WorkingCopy {
|
) -> WorkingCopy {
|
||||||
let mut proto = crate::protos::working_copy::Checkout::new();
|
let proto = crate::protos::working_copy::Checkout {
|
||||||
proto.operation_id = operation_id.to_bytes();
|
operation_id: operation_id.to_bytes(),
|
||||||
proto.workspace_id = workspace_id.as_str().to_string();
|
workspace_id: workspace_id.as_str().to_string(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.create_new(true)
|
.create_new(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(state_path.join("checkout"))
|
.open(state_path.join("checkout"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
proto.write_to_writer(&mut file).unwrap();
|
file.write_all(&proto.encode_to_vec()).unwrap();
|
||||||
WorkingCopy {
|
WorkingCopy {
|
||||||
store,
|
store,
|
||||||
working_copy_path,
|
working_copy_path,
|
||||||
|
@ -1050,7 +1058,10 @@ impl WorkingCopy {
|
||||||
|
|
||||||
fn write_proto(&self, proto: crate::protos::working_copy::Checkout) {
|
fn write_proto(&self, proto: crate::protos::working_copy::Checkout) {
|
||||||
let mut temp_file = NamedTempFile::new_in(&self.state_path).unwrap();
|
let mut temp_file = NamedTempFile::new_in(&self.state_path).unwrap();
|
||||||
proto.write_to_writer(temp_file.as_file_mut()).unwrap();
|
temp_file
|
||||||
|
.as_file_mut()
|
||||||
|
.write_all(&proto.encode_to_vec())
|
||||||
|
.unwrap();
|
||||||
// TODO: Retry if persisting fails (it will on Windows if the file happened to
|
// TODO: Retry if persisting fails (it will on Windows if the file happened to
|
||||||
// be open for read).
|
// be open for read).
|
||||||
temp_file.persist(self.state_path.join("checkout")).unwrap();
|
temp_file.persist(self.state_path.join("checkout")).unwrap();
|
||||||
|
@ -1058,9 +1069,8 @@ impl WorkingCopy {
|
||||||
|
|
||||||
fn checkout_state(&self) -> &CheckoutState {
|
fn checkout_state(&self) -> &CheckoutState {
|
||||||
self.checkout_state.get_or_init(|| {
|
self.checkout_state.get_or_init(|| {
|
||||||
let mut file = File::open(self.state_path.join("checkout")).unwrap();
|
let buf = fs::read(self.state_path.join("checkout")).unwrap();
|
||||||
let proto: crate::protos::working_copy::Checkout =
|
let proto = crate::protos::working_copy::Checkout::decode(&*buf).unwrap();
|
||||||
Message::parse_from_reader(&mut file).unwrap();
|
|
||||||
CheckoutState {
|
CheckoutState {
|
||||||
operation_id: OperationId::new(proto.operation_id),
|
operation_id: OperationId::new(proto.operation_id),
|
||||||
workspace_id: if proto.workspace_id.is_empty() {
|
workspace_id: if proto.workspace_id.is_empty() {
|
||||||
|
@ -1115,10 +1125,11 @@ impl WorkingCopy {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self) {
|
fn save(&mut self) {
|
||||||
let mut proto = crate::protos::working_copy::Checkout::new();
|
self.write_proto(crate::protos::working_copy::Checkout {
|
||||||
proto.operation_id = self.operation_id().to_bytes();
|
operation_id: self.operation_id().to_bytes(),
|
||||||
proto.workspace_id = self.workspace_id().as_str().to_string();
|
workspace_id: self.workspace_id().as_str().to_string(),
|
||||||
self.write_proto(proto);
|
..Default::default()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_mutation(&mut self) -> LockedWorkingCopy {
|
pub fn start_mutation(&mut self) -> LockedWorkingCopy {
|
||||||
|
|
Loading…
Reference in a new issue