Skip to content

Commit

Permalink
feat: Make protoc dependency optional (#72)
Browse files Browse the repository at this point in the history
This PR makes the dependency on `prost-build` (and therefore `protoc`)
optional.

To do this, the rust source generated by `protoc` is copied in-tree, and
the build script will only recompile `.proto` files if the
`build_protos` feature is enabled.

This does introduce a potential point of confusion if the proto
definitions are modified, but presumably these are rarely changed.
  • Loading branch information
nathanwhit authored Apr 27, 2024
1 parent ec1132f commit 7e6aa78
Show file tree
Hide file tree
Showing 6 changed files with 558 additions and 22 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ jobs:
- name: Check linting
run: cargo clippy --release --all-targets --all-features -- -D clippy::all

- name: Check generated protobuf sources are up to date
if: runner.os == 'Linux' || runner.os == 'macOS'
run: |-
cargo check -p denokv_proto --features='build_protos'
cargo fmt -p denokv_proto
git diff --exit-code
- name: Build
run: cargo build --release --all-targets --all-features --tests -v

Expand Down
5 changes: 4 additions & 1 deletion proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ authors.workspace = true
[lib]
path = "lib.rs"

[features]
build_protos = ["prost-build"]

[dependencies]
anyhow.workspace = true
async-trait.workspace = true
Expand All @@ -21,4 +24,4 @@ serde.workspace = true
uuid.workspace = true

[build-dependencies]
prost-build.workspace = true
prost-build = { workspace = true, optional = true }
80 changes: 65 additions & 15 deletions proto/build.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,73 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

use std::env;
use std::io;
use std::path::PathBuf;

fn main() -> io::Result<()> {
println!("cargo:rerun-if-changed=./schema/datapath.proto");
println!("cargo:rerun-if-changed=./schema/backup.proto");
#[cfg(feature = "build_protos")]
mod build_protos {
use std::env;
use std::io;
use std::path::Path;
use std::path::PathBuf;
fn compiled_proto_path(proto: impl AsRef<Path>) -> PathBuf {
let proto = proto.as_ref();
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
path.push(format!(
"com.deno.kv.{}.rs",
proto.file_stem().unwrap().to_str().unwrap()
));
path
}

fn protobuf_module_path() -> PathBuf {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("protobuf")
}

fn protobuf_dest_path(compiled_proto_path: impl AsRef<Path>) -> PathBuf {
let mut path = protobuf_module_path();
path.push(compiled_proto_path.as_ref().file_name().unwrap());
path
}

fn copy_compiled_proto(proto: impl AsRef<Path>) -> io::Result<()> {
let generated = compiled_proto_path(proto);
let contents = std::fs::read_to_string(&generated)?;
let header = r"// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Generated by prost-build, enable the `build_protos` feature to regenerate.";

let contents = format!("{header}\n\n{}", contents);
std::fs::write(protobuf_dest_path(&generated), contents.as_bytes())?;
Ok(())
}

let descriptor_path =
PathBuf::from(env::var("OUT_DIR").unwrap()).join("proto_descriptor.bin");
pub fn build() -> io::Result<()> {
let descriptor_path =
PathBuf::from(env::var("OUT_DIR").unwrap()).join("proto_descriptor.bin");

prost_build::Config::new()
.file_descriptor_set_path(&descriptor_path)
.compile_well_known_types()
.compile_protos(
&["schema/datapath.proto", "schema/backup.proto"],
&["protobuf/"],
)?;
let protos = &["schema/datapath.proto", "schema/backup.proto"];

Ok(())
prost_build::Config::new()
.file_descriptor_set_path(&descriptor_path)
.compile_well_known_types()
.compile_protos(protos, &["schema/"])?;

for proto in protos {
copy_compiled_proto(proto)?;
}

Ok(())
}
}

fn main() -> io::Result<()> {
println!("cargo:rerun-if-changed=./schema/datapath.proto");
println!("cargo:rerun-if-changed=./schema/backup.proto");
#[cfg(feature = "build_protos")]
{
build_protos::build()
}
#[cfg(not(feature = "build_protos"))]
{
Ok(())
}
}
10 changes: 4 additions & 6 deletions proto/protobuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

// Generated code, disable lints
#[allow(clippy::all, non_snake_case)]
pub mod datapath {
include!(concat!(env!("OUT_DIR"), "/com.deno.kv.datapath.rs"));
}
#[path = "protobuf/com.deno.kv.datapath.rs"]
pub mod datapath;

#[allow(clippy::all, non_snake_case)]
pub mod backup {
include!(concat!(env!("OUT_DIR"), "/com.deno.kv.backup.rs"));
}
#[path = "protobuf/com.deno.kv.backup.rs"]
pub mod backup;
84 changes: 84 additions & 0 deletions proto/protobuf/com.deno.kv.backup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.

// Generated by prost-build, enable the `build_protos` feature to regenerate.

#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BackupSnapshotRange {
#[prost(message, repeated, tag = "1")]
pub data_list: ::prost::alloc::vec::Vec<BackupKvPair>,
#[prost(message, repeated, tag = "2")]
pub metadata_list: ::prost::alloc::vec::Vec<BackupKvPair>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BackupKvPair {
#[prost(bytes = "vec", tag = "1")]
pub key: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "2")]
pub value: ::prost::alloc::vec::Vec<u8>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BackupMutationRange {
#[prost(message, repeated, tag = "1")]
pub entries: ::prost::alloc::vec::Vec<BackupReplicationLogEntry>,
#[prost(uint64, tag = "2")]
pub timestamp_ms: u64,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BackupReplicationLogEntry {
#[prost(bytes = "vec", tag = "1")]
pub versionstamp: ::prost::alloc::vec::Vec<u8>,
#[prost(enumeration = "BackupKvMutationKind", tag = "2")]
pub kind: i32,
#[prost(bytes = "vec", tag = "3")]
pub key: ::prost::alloc::vec::Vec<u8>,
#[prost(bytes = "vec", tag = "4")]
pub value: ::prost::alloc::vec::Vec<u8>,
#[prost(int32, tag = "5")]
pub value_encoding: i32,
#[prost(uint64, tag = "6")]
pub expire_at_ms: u64,
}
#[derive(
Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration,
)]
#[repr(i32)]
pub enum BackupKvMutationKind {
MkUnspecified = 0,
MkSet = 1,
MkClear = 2,
MkSum = 3,
MkMax = 4,
MkMin = 5,
}
impl BackupKvMutationKind {
/// 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 {
BackupKvMutationKind::MkUnspecified => "MK_UNSPECIFIED",
BackupKvMutationKind::MkSet => "MK_SET",
BackupKvMutationKind::MkClear => "MK_CLEAR",
BackupKvMutationKind::MkSum => "MK_SUM",
BackupKvMutationKind::MkMax => "MK_MAX",
BackupKvMutationKind::MkMin => "MK_MIN",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"MK_UNSPECIFIED" => Some(Self::MkUnspecified),
"MK_SET" => Some(Self::MkSet),
"MK_CLEAR" => Some(Self::MkClear),
"MK_SUM" => Some(Self::MkSum),
"MK_MAX" => Some(Self::MkMax),
"MK_MIN" => Some(Self::MkMin),
_ => None,
}
}
}
Loading

0 comments on commit 7e6aa78

Please sign in to comment.