about summary refs log tree commit diff
path: root/tvix
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2024-01-15T17·22+0200
committerclbot <clbot@tvl.fyi>2024-01-15T18·54+0000
commitf0a750bcb7e3145974f99383a5db905b9e0d72a3 (patch)
treeccb416ea9c9134bf2b118f68fc6ce0b74c6962fb /tvix
parent170e0cdfadd96176595c47b573d0a1f27a7c734b (diff)
feat(tvix/build): add CLI entrypoint r/7387
This starts a BuildService as a separate process, currently defaulting
to the DummyBuildService.

Change-Id: Ic206f00831641d3ffebaa44883b7dc053700b9ca
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10631
Autosubmit: flokli <flokli@flokli.de>
Reviewed-by: raitobezarius <tvl@lahfa.xyz>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix')
-rw-r--r--tvix/Cargo.lock3
-rw-r--r--tvix/Cargo.nix22
-rw-r--r--tvix/build/Cargo.toml3
-rw-r--r--tvix/build/src/bin/tvix-build.rs132
4 files changed, 160 insertions, 0 deletions
diff --git a/tvix/Cargo.lock b/tvix/Cargo.lock
index a37c04f974d6..429bdfd2571a 100644
--- a/tvix/Cargo.lock
+++ b/tvix/Cargo.lock
@@ -3283,16 +3283,19 @@ name = "tvix-build"
 version = "0.1.0"
 dependencies = [
  "bytes",
+ "clap",
  "itertools 0.12.0",
  "prost 0.12.1",
  "prost-build",
  "test-case",
  "thiserror",
  "tokio",
+ "tokio-listener",
  "tonic 0.10.2",
  "tonic-build",
  "tonic-reflection",
  "tracing",
+ "tracing-subscriber",
  "tvix-castore",
  "url",
 ]
diff --git a/tvix/Cargo.nix b/tvix/Cargo.nix
index d1ffbf326470..e3f4be07e3c7 100644
--- a/tvix/Cargo.nix
+++ b/tvix/Cargo.nix
@@ -10214,6 +10214,13 @@ rec {
         crateName = "tvix-build";
         version = "0.1.0";
         edition = "2021";
+        crateBin = [
+          {
+            name = "tvix-build";
+            path = "src/bin/tvix-build.rs";
+            requiredFeatures = [ ];
+          }
+        ];
         # We can't filter paths with references in Nix 2.4
         # See https://github.com/NixOS/nix/issues/5410
         src =
@@ -10226,6 +10233,11 @@ rec {
             packageId = "bytes";
           }
           {
+            name = "clap";
+            packageId = "clap";
+            features = [ "derive" "env" ];
+          }
+          {
             name = "itertools";
             packageId = "itertools 0.12.0";
           }
@@ -10242,6 +10254,11 @@ rec {
             packageId = "tokio";
           }
           {
+            name = "tokio-listener";
+            packageId = "tokio-listener";
+            features = [ "tonic010" ];
+          }
+          {
             name = "tonic";
             packageId = "tonic 0.10.2";
             features = [ "tls" "tls-roots" ];
@@ -10256,6 +10273,11 @@ rec {
             packageId = "tracing";
           }
           {
+            name = "tracing-subscriber";
+            packageId = "tracing-subscriber";
+            features = [ "json" ];
+          }
+          {
             name = "tvix-castore";
             packageId = "tvix-castore";
           }
diff --git a/tvix/build/Cargo.toml b/tvix/build/Cargo.toml
index 08102a66be50..289dda4d8c0d 100644
--- a/tvix/build/Cargo.toml
+++ b/tvix/build/Cargo.toml
@@ -5,13 +5,16 @@ edition = "2021"
 
 [dependencies]
 bytes = "1.4.0"
+clap = { version = "4.0", features = ["derive", "env"] }
 itertools = "0.12.0"
 prost = "0.12.1"
 thiserror = "1.0.56"
 tokio = { version = "1.32.0" }
+tokio-listener = { version = "0.2.2", features = [ "tonic010" ] }
 tonic = { version = "0.10.2", features = ["tls", "tls-roots"] }
 tvix-castore = { path = "../castore" }
 tracing = "0.1.37"
+tracing-subscriber = { version = "0.3.16", features = ["json"] }
 url = "2.4.0"
 
 [dependencies.tonic-reflection]
diff --git a/tvix/build/src/bin/tvix-build.rs b/tvix/build/src/bin/tvix-build.rs
new file mode 100644
index 000000000000..ed36c8933cae
--- /dev/null
+++ b/tvix/build/src/bin/tvix-build.rs
@@ -0,0 +1,132 @@
+use std::sync::Arc;
+
+use clap::Parser;
+use clap::Subcommand;
+use tokio_listener::Listener;
+use tokio_listener::SystemOptions;
+use tokio_listener::UserOptions;
+use tonic::{self, transport::Server};
+use tracing::{info, Level};
+use tracing_subscriber::prelude::*;
+use tvix_build::{
+    buildservice,
+    proto::{build_service_server::BuildServiceServer, GRPCBuildServiceWrapper},
+};
+use tvix_castore::blobservice;
+use tvix_castore::directoryservice;
+
+#[cfg(feature = "tonic-reflection")]
+use tvix_build::proto::FILE_DESCRIPTOR_SET;
+#[cfg(feature = "tonic-reflection")]
+use tvix_castore::proto::FILE_DESCRIPTOR_SET as CASTORE_FILE_DESCRIPTOR_SET;
+
+#[derive(Parser)]
+#[command(author, version, about, long_about = None)]
+struct Cli {
+    /// Whether to log in JSON
+    #[arg(long)]
+    json: bool,
+
+    #[arg(long)]
+    log_level: Option<Level>,
+
+    #[command(subcommand)]
+    command: Commands,
+}
+#[derive(Subcommand)]
+enum Commands {
+    /// Runs the tvix-build daemon.
+    Daemon {
+        #[arg(long, short = 'l')]
+        listen_address: Option<String>,
+
+        #[arg(long, env, default_value = "grpc+http://[::1]:8000")]
+        blob_service_addr: String,
+
+        #[arg(long, env, default_value = "grpc+http://[::1]:8000")]
+        directory_service_addr: String,
+
+        #[arg(long, env, default_value = "dummy://")]
+        build_service_addr: String,
+    },
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let cli = Cli::parse();
+
+    // configure log settings
+    let level = cli.log_level.unwrap_or(Level::INFO);
+
+    let subscriber = tracing_subscriber::registry()
+        .with(
+            cli.json.then_some(
+                tracing_subscriber::fmt::Layer::new()
+                    .with_writer(std::io::stderr.with_max_level(level))
+                    .json(),
+            ),
+        )
+        .with(
+            (!cli.json).then_some(
+                tracing_subscriber::fmt::Layer::new()
+                    .with_writer(std::io::stderr.with_max_level(level))
+                    .pretty(),
+            ),
+        );
+
+    tracing::subscriber::set_global_default(subscriber).expect("Unable to set global subscriber");
+
+    match cli.command {
+        Commands::Daemon {
+            listen_address,
+            blob_service_addr,
+            directory_service_addr,
+            build_service_addr,
+        } => {
+            // initialize stores
+            let blob_service = blobservice::from_addr(&blob_service_addr).await?;
+            let directory_service = directoryservice::from_addr(&directory_service_addr).await?;
+
+            let build_service = buildservice::from_addr(
+                &build_service_addr,
+                Arc::from(blob_service),
+                Arc::from(directory_service),
+            )
+            .await?;
+
+            let listen_address = listen_address
+                .unwrap_or_else(|| "[::]:8000".to_string())
+                .parse()
+                .unwrap();
+
+            let mut server = Server::builder();
+
+            #[allow(unused_mut)]
+            let mut router = server.add_service(BuildServiceServer::new(
+                GRPCBuildServiceWrapper::new(build_service),
+            ));
+
+            #[cfg(feature = "tonic-reflection")]
+            {
+                let reflection_svc = tonic_reflection::server::Builder::configure()
+                    .register_encoded_file_descriptor_set(CASTORE_FILE_DESCRIPTOR_SET)
+                    .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)
+                    .build()?;
+                router = router.add_service(reflection_svc);
+            }
+
+            info!(listen_address=%listen_address, "listening");
+
+            let listener = Listener::bind(
+                &listen_address,
+                &SystemOptions::default(),
+                &UserOptions::default(),
+            )
+            .await?;
+
+            router.serve_with_incoming(listener).await?;
+        }
+    }
+
+    Ok(())
+}