-
Notifications
You must be signed in to change notification settings - Fork 343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prototype for jj api
#3601
base: main
Are you sure you want to change the base?
Prototype for jj api
#3601
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# This crate contains the proto files that correspond to the API for jj. | ||
[package] | ||
name = "jj-api" | ||
version.workspace = true | ||
license.workspace = true | ||
rust-version.workspace = true | ||
edition.workspace = true | ||
readme.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
documentation.workspace = true | ||
categories.workspace = true | ||
keywords.workspace = true | ||
|
||
[dependencies] | ||
hex.workspace = true | ||
prost.workspace = true | ||
prost-types.workspace = true | ||
tonic.workspace = true | ||
|
||
[build-dependencies] | ||
prost-build.workspace = true | ||
protoc-bin-vendored.workspace = true | ||
tonic-build.workspace = true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
use std::io::Result; | ||
use std::path::{Path, PathBuf}; | ||
|
||
fn list_files(dir: &Path) -> impl Iterator<Item = PathBuf> { | ||
std::fs::read_dir(&dir) | ||
.unwrap() | ||
.into_iter() | ||
.filter_map(|res| { | ||
let res = res.unwrap(); | ||
res.file_type().unwrap().is_file().then_some(res.path()) | ||
}) | ||
} | ||
|
||
fn main() -> Result<()> { | ||
// Doesn't support all architectures (namely, M1 macs), so for now we can't just unwrap it. | ||
if let Ok(protoc) = protoc_bin_vendored::protoc_bin_path() { | ||
std::env::set_var("PROTOC", protoc); | ||
} | ||
|
||
let crate_root = Path::new(env!("CARGO_MANIFEST_DIR")); | ||
let generated = crate_root.join("src/generated"); | ||
let input_dir = crate_root.join("proto"); | ||
let proto_files: Vec<PathBuf> = list_files(&input_dir.join("rpc")) | ||
.chain(list_files(&input_dir.join("objects"))) | ||
.collect(); | ||
let service_files: Vec<PathBuf> = list_files(&input_dir.join("services")).collect(); | ||
|
||
prost_build::Config::new() | ||
.out_dir(&generated) | ||
.include_file(generated.join("mod.rs")) | ||
.compile_protos(&proto_files, &[&input_dir]) | ||
.unwrap(); | ||
|
||
tonic_build::configure() | ||
.out_dir(&generated) | ||
.build_client(true) | ||
.build_server(true) | ||
.compile(&service_files, &[&input_dir]) | ||
.unwrap(); | ||
|
||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
syntax = "proto3"; | ||
|
||
package jj_api.objects; | ||
|
||
message Change { | ||
string change_id = 1; | ||
string commit_id = 2; | ||
// TODO: add more fields. | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
syntax = "proto3"; | ||
|
||
package jj_api.objects; | ||
|
||
message RepoOptions { | ||
string repo_path = 1; | ||
string at_operation = 2; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
syntax = "proto3"; | ||
|
||
import "objects/change.proto"; | ||
|
||
package jj_api.objects; | ||
|
||
|
||
message Workspace { | ||
string workspace_id = 1; | ||
|
||
jj_api.objects.Change change = 2; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
syntax = "proto3"; | ||
|
||
import "objects/repo_options.proto"; | ||
import "google/protobuf/field_mask.proto"; | ||
|
||
package jj_api.rpc; | ||
|
||
message ListWorkspacesRequest { | ||
jj_api.objects.RepoOptions repo = 1; | ||
google.protobuf.FieldMask field_mask = 2; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
syntax = "proto3"; | ||
|
||
import "objects/workspace.proto"; | ||
|
||
package jj_api.rpc; | ||
|
||
message ListWorkspacesResponse { | ||
repeated jj_api.objects.Workspace workspace = 1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
syntax = "proto3"; | ||
|
||
import "google/protobuf/empty.proto"; | ||
import "rpc/ListWorkspacesRequest.proto"; | ||
import "rpc/ListWorkspacesResponse.proto"; | ||
|
||
package jj_api.services; | ||
|
||
// Handles things that operate on a given workspace. | ||
// Most commands will be contained within here, but commands such as `jj init` | ||
// will not. | ||
service JjService { | ||
rpc ListWorkspaces(jj_api.rpc.ListWorkspacesRequest) returns (jj_api.rpc.ListWorkspacesResponse) {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use std::path::{Path, PathBuf}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Serialization and deserialization are a pain here. I wrote a bunch of wrappers because it gets to be a massive pain in the ass since protos are represented as a string, but in reality the type we usually want is I'd like to see if we can think of a better way to do it, but I'm not hopeful. Maybe we need to have every proto message have its own rust type, and implement
|
||
use tonic::Status; | ||
|
||
pub fn option_str(value: &str) -> Option<&str> { | ||
if value == "" { | ||
None | ||
} else { | ||
Some(&value) | ||
} | ||
} | ||
|
||
pub fn path(value: &str) -> Option<&Path> { | ||
option_str(value).map(Path::new) | ||
} | ||
|
||
pub fn pathbuf(value: &str) -> Option<PathBuf> { | ||
path(value).map(PathBuf::from) | ||
} | ||
|
||
pub fn hex(value: &str) -> Result<Option<Vec<u8>>, Status> { | ||
option_str(value) | ||
.map(hex::decode) | ||
.transpose() | ||
.map_err(|err| Status::invalid_argument(err.to_string())) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// This file is @generated by prost-build. | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct RepoOptions { | ||
#[prost(string, tag = "1")] | ||
pub repo_path: ::prost::alloc::string::String, | ||
#[prost(string, tag = "2")] | ||
pub at_operation: ::prost::alloc::string::String, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct Change { | ||
#[prost(string, tag = "1")] | ||
pub change_id: ::prost::alloc::string::String, | ||
/// TODO: add more fields. | ||
#[prost(string, tag = "2")] | ||
pub commit_id: ::prost::alloc::string::String, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct Workspace { | ||
#[prost(string, tag = "1")] | ||
pub workspace_id: ::prost::alloc::string::String, | ||
#[prost(message, optional, tag = "2")] | ||
pub change: ::core::option::Option<Change>, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// This file is @generated by prost-build. | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct ListWorkspacesRequest { | ||
#[prost(message, optional, tag = "1")] | ||
pub repo: ::core::option::Option<super::objects::RepoOptions>, | ||
#[prost(message, optional, tag = "2")] | ||
pub field_mask: ::core::option::Option<::prost_types::FieldMask>, | ||
} | ||
#[allow(clippy::derive_partial_eq_without_eq)] | ||
#[derive(Clone, PartialEq, ::prost::Message)] | ||
pub struct ListWorkspacesResponse { | ||
#[prost(message, repeated, tag = "1")] | ||
pub workspace: ::prost::alloc::vec::Vec<super::objects::Workspace>, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that field masks would be really handy because sometimes you only want change IDs, while sometimes you want full changes. Unfortunately, although the type exists, there's currently no way to actually do anything based on these field masks in rust.