mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
WIP: Create an example API.
This PR is meant to trigger a discussion on what the specific structure of the API should look like. This crate contains only the minimal set of code for an external library to start using it.
This commit is contained in:
parent
03a0921e12
commit
79bc5bcbe3
6 changed files with 283 additions and 0 deletions
39
api/proto/objects/options.proto
Normal file
39
api/proto/objects/options.proto
Normal file
|
@ -0,0 +1,39 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package jj_api.objects;
|
||||
|
||||
// Leaving this as a proto in case we come up with some sort of revset-style
|
||||
// syntax for operations.
|
||||
message OperationRef {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
enum Snapshot {
|
||||
SNAPSHOT_UNSPECIFIED = 0;
|
||||
NO_SNAPSHOT = 1;
|
||||
SNAPSHOT = 2;
|
||||
}
|
||||
|
||||
message GlobalOptions {
|
||||
// Generally prefer providing working_dir over repo_path, since working_dir
|
||||
// allows jj to infer the path if you're not at the repo root.
|
||||
string working_dir = 1;
|
||||
string repo_path = 2;
|
||||
|
||||
// Technically this could be a boolean, but this forces users to choose either
|
||||
// SNAPSHOT or NO_SNAPSHOT.
|
||||
Snapshot snapshot = 3;
|
||||
|
||||
OperationRef operation = 4;
|
||||
|
||||
// If true, user configuration will be loaded. In particular:
|
||||
// * User revset aliases will be used
|
||||
// * User template aliases will be used
|
||||
bool use_user_config = 5;
|
||||
|
||||
// Path to additional config files.
|
||||
// Will be applied after the user configuration, if use_user_config is set.
|
||||
repeated string extra_configs = 6;
|
||||
|
||||
bool ignore_immutable = 7;
|
||||
}
|
70
api/proto/objects/revision.proto
Normal file
70
api/proto/objects/revision.proto
Normal file
|
@ -0,0 +1,70 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package jj_api.objects;
|
||||
|
||||
// A RevisionMask controls how much of a revision is returned.
|
||||
// For example, `jj log` will likely not care about files, while `jj status`
|
||||
// will want to know what files changed in a revision, and `jj diff` will want
|
||||
// to know both the content of the file and the content of the file in the
|
||||
// parent revision.
|
||||
message RevisionMask {
|
||||
// Which files will be returned.
|
||||
enum FilePathMask {
|
||||
NONE = 0;
|
||||
MODIFIED_FILES = 1;
|
||||
ALL_FILES = 3;
|
||||
// Include all files that were matched by the RevisionMask containing this
|
||||
// RevisionMask. For example, if we had:
|
||||
// RevisionMask(
|
||||
// files_to_include = MODIFIED_FILES,
|
||||
// files = FileMask(content = True),
|
||||
// parents = RevisionMask(
|
||||
// files_to_include = PARENT_FILES
|
||||
// files = FileMask(content = True),
|
||||
// ),
|
||||
// )
|
||||
// And we returned the revision @, which modfied the file foo, then both
|
||||
// r.files["foo"].content and r.parent.files["foo"].content would be filled.
|
||||
PARENT_FILES = 4;
|
||||
};
|
||||
FilePathMask files_to_include = 1;
|
||||
repeated string additional_files = 2;
|
||||
|
||||
bool rendered = 3;
|
||||
|
||||
bool file_content = 4;
|
||||
bool file_hash = 5;
|
||||
bool file_metadata = 6;
|
||||
|
||||
// How much of the parent revision to fill in.
|
||||
RevisionMask parents = 7;
|
||||
}
|
||||
|
||||
message File {
|
||||
// If you query for MODIFIED_FILES, you may get a file that's been deleted.
|
||||
bool exists = 1;
|
||||
string hash = 2;
|
||||
bytes content = 3;
|
||||
// TODO: file metadata (eg. permissions)?
|
||||
}
|
||||
|
||||
|
||||
// By default,
|
||||
message Revision {
|
||||
string change_id = 1;
|
||||
string commit_id = 2;
|
||||
string description = 3;
|
||||
bool empty = 4;
|
||||
bool conflicts = 5;
|
||||
bool mutable = 6;
|
||||
|
||||
// The rendered template.
|
||||
// Open question: Is a template a first-class citizen of jj, or is it specific
|
||||
// to jj-cli?
|
||||
string rendered = 7;
|
||||
|
||||
map<string, File> files = 8;
|
||||
|
||||
// revision.parents[*].parents is always empty, to avoid recursion.
|
||||
repeated Revision parents = 9;
|
||||
}
|
72
api/proto/objects/revset.proto
Normal file
72
api/proto/objects/revset.proto
Normal file
|
@ -0,0 +1,72 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package jj_api.objects;
|
||||
|
||||
message Revset {
|
||||
oneof kind {
|
||||
// Should ideally only be used when the user types in their own revset.
|
||||
// Otherwise, construct it using this proto.
|
||||
string revset = 1;
|
||||
|
||||
// Primitives that we can look up directly.
|
||||
string change_id = 2;
|
||||
string commit_id = 3;
|
||||
|
||||
// Operators
|
||||
Union union = 4;
|
||||
Intersection intersection = 5;
|
||||
Revset not = 6;
|
||||
Between between = 7;
|
||||
|
||||
// Functions
|
||||
Revset parents = 8;
|
||||
Revset children = 9;
|
||||
Ancestors ancestors = 10;
|
||||
// Descendants is skipped (use Between(from=x, to=None, inclusive=True)
|
||||
Reachable reachable = 12;
|
||||
// Connected is skipped (use Between(from=x, to=x, inclusive=True)
|
||||
bool all = 13; // Use bool for a function with no parameters
|
||||
bool none = 14; // Use bool for a function with no parameters
|
||||
Branches branches = 15;
|
||||
RemoteBranches remote_branches = 16;
|
||||
|
||||
// You get the point. Each builtin function is implemented as a oneof in
|
||||
// this message.
|
||||
}
|
||||
}
|
||||
|
||||
message Union {
|
||||
repeated Revset srcs = 1;
|
||||
}
|
||||
|
||||
message Intersection {
|
||||
repeated Revset srcs = 1;
|
||||
}
|
||||
|
||||
// Equivalent to from::to when inclusive is set, or from..to when not set.
|
||||
message Between {
|
||||
optional Revset from = 1;
|
||||
optional Revset to = 2;
|
||||
// If false, equivalent to ..
|
||||
// If true, equivalent to ::
|
||||
bool inclusive = 3;
|
||||
}
|
||||
|
||||
message Ancestors {
|
||||
Revset srcs = 1;
|
||||
int32 depth = 2;
|
||||
}
|
||||
|
||||
message Reachable {
|
||||
Revset srcs = 1;
|
||||
Revset domain = 2;
|
||||
}
|
||||
|
||||
message Branches {
|
||||
string pattern = 1;
|
||||
}
|
||||
|
||||
message RemoteBranches {
|
||||
string branch_pattern = 1;
|
||||
string remote_pattern = 2;
|
||||
}
|
52
api/proto/rpc/read_revisions.proto
Normal file
52
api/proto/rpc/read_revisions.proto
Normal file
|
@ -0,0 +1,52 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package jj_api.rpc;
|
||||
|
||||
import "objects/options.proto";
|
||||
import "objects/revset.proto";
|
||||
import "objects/revision.proto";
|
||||
|
||||
message RevisionsRequest {
|
||||
// Since this is a read-only request, we don't want to require the user to
|
||||
// start a transaction.
|
||||
oneof state {
|
||||
string transaction_id = 1;
|
||||
jj_api.objects.GlobalOptions repo_state = 2;
|
||||
}
|
||||
|
||||
jj_api.objects.RevisionMask revision_mask = 3;
|
||||
|
||||
jj_api.objects.Revset revisions = 4;
|
||||
|
||||
int32 limit = 5;
|
||||
// TODO: We have three options here:
|
||||
// 1) Make this a string, and return the string
|
||||
// 2) Make this similar to Revset, where we can construct it
|
||||
// 3) Remove this from the API and put it in jj-cli entirely. Templates would,
|
||||
// instead of formatting a Commit object, format a Revision proto.
|
||||
// I don't really like option 2, since it seems that the caller of this could
|
||||
// always just do that themselves in whatever the language is calling this
|
||||
// API.
|
||||
// Option 1 and Option 3 both seem reasonable, and mainly depend on whether we
|
||||
// think that jj-cli will be the only user of templates.
|
||||
// I personally am leaning towards option 3, because I think that an extension
|
||||
// may quite reasonably want to, for example, take advantage of a user's
|
||||
// jj config file containing custom templates or template aliases.
|
||||
string template = 6;
|
||||
}
|
||||
|
||||
message ListRevisionsResponse {
|
||||
repeated jj_api.objects.Revision revisions = 1;
|
||||
|
||||
// This is useful if you want to perform, for example, `jj diff` between two
|
||||
// revisions.
|
||||
string operation_id = 2;
|
||||
}
|
||||
|
||||
message GetRevisionResponse {
|
||||
jj_api.objects.Revision revision = 1;
|
||||
|
||||
// This is useful if you want to perform, for example, `jj diff` between two
|
||||
// revisions.
|
||||
string operation_id = 2;
|
||||
}
|
25
api/proto/rpc/transaction.proto
Normal file
25
api/proto/rpc/transaction.proto
Normal file
|
@ -0,0 +1,25 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package jj_api.rpc;
|
||||
|
||||
import "objects/options.proto";
|
||||
|
||||
message BeginTransactionRequest {
|
||||
jj_api.objects.GlobalOptions state = 1;
|
||||
|
||||
// If EndTransaction is not called within timeout_seconds, then the daemon
|
||||
// will abandon the transaction.
|
||||
uint32 timeout_seconds = 2;
|
||||
}
|
||||
|
||||
message BeginTransactionResponse {
|
||||
string transaction_id = 1;
|
||||
}
|
||||
|
||||
message EndTransactionRequest {
|
||||
string transaction_id = 1;
|
||||
}
|
||||
|
||||
message EndTransactionResponse {
|
||||
string operation_id = 1;
|
||||
}
|
25
api/proto/services/service.proto
Normal file
25
api/proto/services/service.proto
Normal file
|
@ -0,0 +1,25 @@
|
|||
syntax = "proto3";
|
||||
|
||||
import "rpc/read_revisions.proto";
|
||||
import "rpc/transaction.proto";
|
||||
|
||||
package jj_api.services;
|
||||
|
||||
// All jj things will go into this service.
|
||||
service JjService {
|
||||
rpc BeginTransaction(jj_api.rpc.BeginTransactionRequest) returns (jj_api.rpc.BeginTransactionResponse) {}
|
||||
rpc EndTransaction(jj_api.rpc.EndTransactionRequest) returns (jj_api.rpc.EndTransactionResponse) {}
|
||||
|
||||
// This RPC will be used by `jj log`
|
||||
rpc ListRevisions(jj_api.rpc.RevisionsRequest) returns (jj_api.rpc.ListRevisionsResponse) {}
|
||||
|
||||
// This RPC will be used by:
|
||||
// * cat
|
||||
// * diff
|
||||
// * files
|
||||
// * show
|
||||
// * status
|
||||
// It only differs from `ListRevisions` in that it throws an error if there
|
||||
// isn't exactly one match.
|
||||
rpc GetRevision(jj_api.rpc.RevisionsRequest) returns (jj_api.rpc.GetRevisionResponse) {}
|
||||
}
|
Loading…
Reference in a new issue