···11+# Gitmirror
22+33+gitmirror is alternative name of Knotmirror v2. It is designed to be run under the AppView as git syncing service.
44+Because it's internal sync service like tap or hydrant, it uses grpc over xrpc.
···11+syntax = "proto3";
22+33+package gitmirror.v1;
44+55+import "google/protobuf/timestamp.proto";
66+77+option go_package = "tangled.org/core/gitmirror/proto/gen;gitmirrorv1";
88+99+service GitMirrorService {
1010+ rpc CommitLog(CommitLogRequest) returns (stream CommitLogResponse);
1111+ rpc GetBlob(GetBlobRequest) returns (stream BlobChunk);
1212+ rpc Diff(DiffRequest) returns (stream FileDiff);
1313+ rpc Interdiff(InterdiffRequest) returns (stream FileDiff);
1414+}
1515+1616+message CommitLogRequest {
1717+ // repo DID
1818+ string repo = 1;
1919+ // Ranges to include in the git log (revspec, "A..B", "A...B", etc.).
2020+ // At least one range, or all_refs must be specified.
2121+ repeated bytes ranges = 2;
2222+ // If true, all refs are searched for commits.
2323+ // Must not be true when ranges are given.
2424+ bool all_refs = 3;
2525+ // After is an optional parameter to specify the earliest commit to consider.
2626+ google.protobuf.Timestamp after = 4;
2727+ // Before is an optional parameter to specify the latest commit to consider.
2828+ google.protobuf.Timestamp before = 5;
2929+ // MaxCommits is an optional parameter to specify the maximum number of commits
3030+ // to return. If max_commits is 0, all commits that match the criteria will be
3131+ // returned.
3232+ uint32 max_commits = 6;
3333+ // Skip is an optional parameter to specify the number of commits to skip.
3434+ // This can be used to implement a poor mans pagination.
3535+ uint32 skip = 7;
3636+}
3737+message CommitLogResponse {
3838+ repeated GitCommit commits = 1;
3939+}
4040+4141+message GetBlobRequest {
4242+ // repo carries the DID as a string.
4343+ string repo = 1;
4444+ // oid is the blob object id (hex).
4545+ string oid = 2;
4646+}
4747+message BlobChunk {
4848+ bytes data = 1;
4949+}
5050+5151+message DiffRequest {
5252+ // repo carries the DID as a string; parsing/validation is an impl detail.
5353+ string repo = 1;
5454+ // base_rev_spec/head_rev_spec are commit-ish ref strings.
5555+ // base_rev_spec is optional; when unset, diff head against head's first parent.
5656+ optional bytes base_rev_spec = 2;
5757+ bytes head_rev_spec = 3;
5858+ ComparisonType comparison_type = 4;
5959+6060+ enum ComparisonType {
6161+ COMPARISON_TYPE_UNSPECIFIED = 0;
6262+ // Corresponds to the BASE..HEAD syntax that only returns any commits that
6363+ // are in HEAD but not in BASE.
6464+ COMPARISON_TYPE_ONLY_IN_HEAD = 1;
6565+ // Corresponds to the BASE...HEAD syntax that returns any commits that are
6666+ // not in both BASE and HEAD.
6767+ COMPARISON_TYPE_INTERSECTION = 2;
6868+ }
6969+}
7070+7171+message InterdiffRequest {
7272+ // repo carries the DID as a string.
7373+ string repo = 1;
7474+ // Old patch range (from_base..from_head) and new patch range (to_base..to_head).
7575+ bytes from_base = 2;
7676+ bytes from_head = 3;
7777+ bytes to_base = 4;
7878+ bytes to_head = 5;
7979+}
8080+8181+// Diff and Interdiff stream one FileDiff per changed file.
8282+8383+message FileContent {
8484+ string path = 1;
8585+ string oid = 2;
8686+ uint64 size = 3;
8787+ bool is_binary = 4;
8888+ bool is_submodule = 5;
8989+ // Raw file bytes, inlined when the oid is not fetchable by the client
9090+ // (e.g. interdiff)
9191+ optional bytes content = 6;
9292+}
9393+9494+// One aligned line pair; a side is absent (None) when unset.
9595+message LinePair {
9696+ optional uint32 lhs = 1;
9797+ optional uint32 rhs = 2;
9898+}
9999+100100+message Hunk {
101101+ // LineNumber (u32) sets containing novel content per side.
102102+ repeated uint32 novel_lhs = 1;
103103+ repeated uint32 novel_rhs = 2;
104104+ repeated LinePair lines = 3;
105105+}
106106+107107+// Number of bytes per side when the files differ (Rust Option<(usize, usize)>).
108108+message ByteChanges {
109109+ uint64 lhs = 1;
110110+ uint64 rhs = 2;
111111+}
112112+113113+message FileDiff {
114114+ FileContent lhs_src = 1;
115115+ FileContent rhs_src = 2;
116116+ repeated Hunk hunks = 3;
117117+ optional ByteChanges has_byte_changes = 4;
118118+ bool has_syntactic_changes = 5;
119119+ // TODO: lhs_positions & rhs_positions
120120+}
121121+122122+message GitCommit {
123123+ string oid = 1;
124124+ GitSignature author = 2;
125125+ GitSignature committer = 3;
126126+ bytes message = 4;
127127+ repeated string parents = 5;
128128+ map<string, string> extra_headers = 6;
129129+}
130130+131131+message GitSignature {
132132+ bytes name = 1;
133133+ bytes email = 2;
134134+ google.protobuf.Timestamp date = 3;
135135+}
···11+# Development only. Not for production use.
22+33+FROM rust:1.96-bookworm AS build
44+55+RUN apt-get update && apt-get install -y --no-install-recommends protobuf-compiler libprotobuf-dev \
66+ && rm -rf /var/lib/apt/lists/*
77+88+WORKDIR /src
99+COPY . .
1010+1111+# Cache mounts on the cargo registry + target dir. The binary is copied out within the same
1212+# RUN because the target cache mount is unmounted afterwards (a later COPY --from could not
1313+# see it).
1414+RUN --mount=type=cache,target=/usr/local/cargo/registry \
1515+ --mount=type=cache,target=/src/target \
1616+ cargo build --release -p gitmirror \
1717+ && cp /src/target/release/gitmirror /usr/local/bin/gitmirror
1818+1919+FROM debian:bookworm-slim
2020+2121+RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates tini \
2222+ && rm -rf /var/lib/apt/lists/*
2323+2424+COPY --from=build /usr/local/bin/gitmirror /usr/local/bin/gitmirror
2525+2626+EXPOSE 9000
2727+2828+ENTRYPOINT ["/usr/bin/tini", "--"]
2929+CMD ["sh", "-c", "if [ -f /usr/local/share/ca-certificates/caddy.crt ]; then update-ca-certificates; fi && exec /usr/local/bin/gitmirror serve"]