From cf223b9fc639222b51546a946fee15e3307f8686 Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Wed, 17 Jun 2026 20:19:59 -0700 Subject: [PATCH 1/2] lore-revision: Expose size and file mode in TreePath This allows a thin client to use ThinClientService.RevisionTree to efficiently retrieve additional information such as file size and mode. Fixes #18 Signed-off-by: Javier Blazquez --- lore-proto/proto/lore/thin_client/v1/model.proto | 4 ++++ lore-proto/src/grpc/lore.thin_client.v1.rs | 6 ++++++ lore-proto/tests/v1_thin_client.rs | 2 ++ lore-revision/src/state.rs | 4 ++++ lore-server/src/grpc/thinclient/v1/revision_tree.rs | 2 ++ 5 files changed, 18 insertions(+) diff --git a/lore-proto/proto/lore/thin_client/v1/model.proto b/lore-proto/proto/lore/thin_client/v1/model.proto index 44812ae..761c35e 100644 --- a/lore-proto/proto/lore/thin_client/v1/model.proto +++ b/lore-proto/proto/lore/thin_client/v1/model.proto @@ -90,6 +90,10 @@ message TreeNode { NodeType node_type = 2; // Content address for FILE / LINK entries; unused for DIRECTORY. lore.model.v1.Address address = 3; + // Original size in bytes. For DIRECTORY entries, this is the cumulative size of its descendant files. + uint64 size = 4; + // True when the FILE entry has the executable bit set. + bool executable = 5; } // Self-describing revision record. Carries the resolved RevisionIdentifier diff --git a/lore-proto/src/grpc/lore.thin_client.v1.rs b/lore-proto/src/grpc/lore.thin_client.v1.rs index 157147b..b832d81 100644 --- a/lore-proto/src/grpc/lore.thin_client.v1.rs +++ b/lore-proto/src/grpc/lore.thin_client.v1.rs @@ -75,6 +75,12 @@ pub struct TreeNode { /// Content address for FILE / LINK entries; unused for DIRECTORY. #[prost(message, optional, tag = "3")] pub address: ::core::option::Option, + /// Original size in bytes. For DIRECTORY entries, this is the cumulative size of its descendant files. + #[prost(uint64, tag = "4")] + pub size: u64, + /// True when the FILE entry has the executable bit set. + #[prost(bool, tag = "5")] + pub executable: bool, } impl ::prost::Name for TreeNode { const NAME: &'static str = "TreeNode"; diff --git a/lore-proto/tests/v1_thin_client.rs b/lore-proto/tests/v1_thin_client.rs index 84ccbac..d85ed11 100644 --- a/lore-proto/tests/v1_thin_client.rs +++ b/lore-proto/tests/v1_thin_client.rs @@ -108,6 +108,8 @@ fn v1_thin_client_field_shapes() { path: _, node_type: _, address: _, + size: _, + executable: _, } = TreeNode::default(); // Revision + nested Parent + Metadata diff --git a/lore-revision/src/state.rs b/lore-revision/src/state.rs index 61f792d..33445ce 100644 --- a/lore-revision/src/state.rs +++ b/lore-revision/src/state.rs @@ -3305,6 +3305,8 @@ pub struct TreePath { pub path: RelativePath, pub address: Option
, pub flags: NodeFlags, + pub size: u64, + pub executable: bool, } pub type CanReadRepository = Arc bool + Send + Sync>; @@ -3466,6 +3468,8 @@ async fn gather_tree_paths_node( path: node_path.clone(), address, flags, + size: node.size, + executable: node.mode & NodeFileMode::Executable == NodeFileMode::Executable, }); let depth_remaining = max_depth == 0 || depth + 1 < max_depth; diff --git a/lore-server/src/grpc/thinclient/v1/revision_tree.rs b/lore-server/src/grpc/thinclient/v1/revision_tree.rs index d05f072..96f606b 100644 --- a/lore-server/src/grpc/thinclient/v1/revision_tree.rs +++ b/lore-server/src/grpc/thinclient/v1/revision_tree.rs @@ -155,6 +155,8 @@ async fn stream_tree( hash: address.hash.into(), context: address.context.into(), }), + size: tree_path.size, + executable: tree_path.executable, }; if tx .send(Ok(RevisionTreeResponse { From f37a1e8f5fc0523640d92a360b32f194217f4886 Mon Sep 17 00:00:00 2001 From: Javier Blazquez Date: Mon, 22 Jun 2026 12:29:18 -0700 Subject: [PATCH 2/2] Add lore.thin_client.v1.FileMode This replaces the use of a boolean to indicate the executable flags on files. Signed-off-by: Javier Blazquez --- lore-proto/proto/lore/thin_client/v1/model.proto | 12 ++++++++++-- lore-proto/src/grpc/lore.thin_client.v1.rs | 6 +++--- lore-proto/tests/v1_thin_client.rs | 2 +- lore-revision/src/state.rs | 4 ++-- lore-server/src/grpc/thinclient/v1/revision_tree.rs | 2 +- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lore-proto/proto/lore/thin_client/v1/model.proto b/lore-proto/proto/lore/thin_client/v1/model.proto index 761c35e..ae28020 100644 --- a/lore-proto/proto/lore/thin_client/v1/model.proto +++ b/lore-proto/proto/lore/thin_client/v1/model.proto @@ -14,6 +14,14 @@ enum NodeType { LINK = 2; } +// File mode for a file-system entry. +enum FileMode { + // No special file mode. + NONE = 0; + // File is executable. + EXECUTABLE = 1; +} + // Per-path action describing what happened between two states (or relative // to the common ancestor in 3-way merges). enum Action { @@ -92,8 +100,8 @@ message TreeNode { lore.model.v1.Address address = 3; // Original size in bytes. For DIRECTORY entries, this is the cumulative size of its descendant files. uint64 size = 4; - // True when the FILE entry has the executable bit set. - bool executable = 5; + // File mode for this entry. For possible flags and values, see enum FileMode. + uint64 mode = 5; } // Self-describing revision record. Carries the resolved RevisionIdentifier diff --git a/lore-proto/src/grpc/lore.thin_client.v1.rs b/lore-proto/src/grpc/lore.thin_client.v1.rs index b832d81..98ee32e 100644 --- a/lore-proto/src/grpc/lore.thin_client.v1.rs +++ b/lore-proto/src/grpc/lore.thin_client.v1.rs @@ -78,9 +78,9 @@ pub struct TreeNode { /// Original size in bytes. For DIRECTORY entries, this is the cumulative size of its descendant files. #[prost(uint64, tag = "4")] pub size: u64, - /// True when the FILE entry has the executable bit set. - #[prost(bool, tag = "5")] - pub executable: bool, + /// File mode for this entry. For possible flags and values, see enum FileMode. + #[prost(uint64, tag = "5")] + pub mode: u64, } impl ::prost::Name for TreeNode { const NAME: &'static str = "TreeNode"; diff --git a/lore-proto/tests/v1_thin_client.rs b/lore-proto/tests/v1_thin_client.rs index d85ed11..ad5cf5f 100644 --- a/lore-proto/tests/v1_thin_client.rs +++ b/lore-proto/tests/v1_thin_client.rs @@ -109,7 +109,7 @@ fn v1_thin_client_field_shapes() { node_type: _, address: _, size: _, - executable: _, + mode: _, } = TreeNode::default(); // Revision + nested Parent + Metadata diff --git a/lore-revision/src/state.rs b/lore-revision/src/state.rs index 33445ce..b3401bd 100644 --- a/lore-revision/src/state.rs +++ b/lore-revision/src/state.rs @@ -3306,7 +3306,7 @@ pub struct TreePath { pub address: Option
, pub flags: NodeFlags, pub size: u64, - pub executable: bool, + pub mode: u64, } pub type CanReadRepository = Arc bool + Send + Sync>; @@ -3469,7 +3469,7 @@ async fn gather_tree_paths_node( address, flags, size: node.size, - executable: node.mode & NodeFileMode::Executable == NodeFileMode::Executable, + mode: node.mode as u64, }); let depth_remaining = max_depth == 0 || depth + 1 < max_depth; diff --git a/lore-server/src/grpc/thinclient/v1/revision_tree.rs b/lore-server/src/grpc/thinclient/v1/revision_tree.rs index 96f606b..dadf610 100644 --- a/lore-server/src/grpc/thinclient/v1/revision_tree.rs +++ b/lore-server/src/grpc/thinclient/v1/revision_tree.rs @@ -156,7 +156,7 @@ async fn stream_tree( context: address.context.into(), }), size: tree_path.size, - executable: tree_path.executable, + mode: tree_path.mode, }; if tx .send(Ok(RevisionTreeResponse {