From 292208f280bd72b0af3b8590a4deaa79e4813b12 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 10:28:30 -0700 Subject: [PATCH 01/29] feat: Add experimentalObservability with an OTel backend --- Cargo.lock | 111 ++++++ Cargo.toml | 1 + crates/turborepo-lib/Cargo.toml | 1 + crates/turborepo-lib/src/cli/mod.rs | 125 ++++++ crates/turborepo-lib/src/commands/mod.rs | 1 + crates/turborepo-lib/src/config/env.rs | 37 +- .../src/config/experimental_otel.rs | 213 ++++++++++ crates/turborepo-lib/src/config/mod.rs | 13 + crates/turborepo-lib/src/config/turbo_json.rs | 148 ++++++- crates/turborepo-lib/src/lib.rs | 1 + crates/turborepo-lib/src/observability/mod.rs | 78 ++++ .../turborepo-lib/src/observability/otel.rs | 157 ++++++++ crates/turborepo-lib/src/opts.rs | 6 +- crates/turborepo-lib/src/run/builder.rs | 7 + crates/turborepo-lib/src/run/mod.rs | 2 + .../src/run/summary/execution.rs | 12 + crates/turborepo-lib/src/run/summary/mod.rs | 33 +- crates/turborepo-lib/src/run/summary/scm.rs | 8 + crates/turborepo-lib/src/run/summary/task.rs | 17 +- .../src/turbo_json/future_flags.rs | 6 + crates/turborepo-lib/src/turbo_json/mod.rs | 4 +- .../turborepo-lib/src/turbo_json/processed.rs | 6 + crates/turborepo-lib/src/turbo_json/raw.rs | 46 +++ crates/turborepo-otel/Cargo.toml | 20 + crates/turborepo-otel/src/lib.rs | 373 ++++++++++++++++++ .../content/docs/reference/configuration.mdx | 172 ++++++++ 26 files changed, 1591 insertions(+), 7 deletions(-) create mode 100644 crates/turborepo-lib/src/config/experimental_otel.rs create mode 100644 crates/turborepo-lib/src/observability/mod.rs create mode 100644 crates/turborepo-lib/src/observability/otel.rs create mode 100644 crates/turborepo-otel/Cargo.toml create mode 100644 crates/turborepo-otel/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 4cc226fe90033..5888da597c8c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3860,12 +3860,106 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b69a91d4893e713e06f724597ad630f1fa76057a5e1026c0ca67054a9032a76" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror 1.0.63", +] + +[[package]] +name = "opentelemetry-http" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0ba633e55c5ea6f431875ba55e71664f2fa5d3a90bd34ec9302eecc41c865dd" +dependencies = [ + "async-trait", + "bytes", + "http 0.2.11", + "opentelemetry", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a94c69209c05319cdf7460c6d4c055ed102be242a0a6245835d7bc42c6ec7f54" +dependencies = [ + "async-trait", + "futures-core", + "http 0.2.11", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost 0.12.3", + "thiserror 1.0.63", + "tokio", + "tonic", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984806e6cf27f2b49282e2a05e288f30594f3dbc74eb7a6e99422bc48ed78162" +dependencies = [ + "opentelemetry", + "opentelemetry_sdk", + "prost 0.12.3", + "tonic", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1869fb4bb9b35c5ba8a1e40c9b128a7b4c010d07091e864a29da19e4fe2ca4d7" + +[[package]] +name = "opentelemetry_sdk" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae312d58eaa90a82d2e627fd86e075cf5230b3f11794e2ed74199ebbe572d4fd" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "lazy_static", + "once_cell", + "opentelemetry", + "ordered-float", + "percent-encoding", + "rand 0.8.5", + "thiserror 1.0.63", + "tokio", + "tokio-stream", +] + [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-multimap" version = "0.7.3" @@ -6987,6 +7081,7 @@ dependencies = [ "turborepo-lockfiles", "turborepo-microfrontends", "turborepo-microfrontends-proxy", + "turborepo-otel", "turborepo-process", "turborepo-repository", "turborepo-scm", @@ -7103,6 +7198,22 @@ dependencies = [ "turborepo-scm", ] +[[package]] +name = "turborepo-otel" +version = "0.1.0" +dependencies = [ + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "serde", + "serde_json", + "thiserror 1.0.63", + "tokio", + "tonic", + "tracing", +] + [[package]] name = "turborepo-process" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index d11214162168b..26285b6d9c62a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,6 +71,7 @@ turborepo-ui = { path = "crates/turborepo-ui" } turborepo-unescape = { path = "crates/turborepo-unescape" } turborepo-scm = { path = "crates/turborepo-scm" } turborepo-signals = { path = "crates/turborepo-signals" } +turborepo-otel = { path = "crates/turborepo-otel" } wax = { path = "crates/turborepo-wax" } turborepo-vercel-api = { path = "crates/turborepo-vercel-api" } turborepo-vercel-api-mock = { path = "crates/turborepo-vercel-api-mock" } diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index 41dd0af80da88..8a52398e6373a 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -144,6 +144,7 @@ turborepo-scm = { workspace = true, features = ["git2"] } turborepo-signals = { workspace = true } turborepo-task-id = { workspace = true } turborepo-telemetry = { path = "../turborepo-telemetry" } +turborepo-otel = { workspace = true } turborepo-ui = { workspace = true } turborepo-unescape = { workspace = true } turborepo-vercel-api = { path = "../turborepo-vercel-api" } diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index ff2e963e7cb86..9716373255e97 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -1,5 +1,6 @@ use std::{ backtrace::Backtrace, + collections::BTreeMap, env, ffi::OsString, fmt::{self, Display}, @@ -31,6 +32,7 @@ use crate::{ bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, ls, prune, query, run, scan, telemetry, unlink, CommandBase, }, + config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, get_version, run::watch::WatchClient, shim::TurboState, @@ -228,6 +230,8 @@ pub struct Args { /// verbosity #[clap(flatten)] pub verbosity: Verbosity, + #[clap(flatten)] + pub experimental_otel_args: ExperimentalOtelCliArgs, /// Force a check for a new version of turbo #[clap(long, global = true, hide = true)] pub check_for_update: bool, @@ -287,6 +291,127 @@ impl From for u8 { } } +fn parse_key_val_pair(s: &str) -> Result<(String, String), String> { + let (key, value) = s + .split_once('=') + .ok_or_else(|| "must be in key=value format".to_string())?; + let key = key.trim(); + if key.is_empty() { + return Err("key cannot be empty".to_string()); + } + Ok((key.to_string(), value.trim().to_string())) +} + +#[derive(Parser, Clone, Debug, Default, PartialEq)] +pub struct ExperimentalOtelCliArgs { + #[clap( + long = "experimental-otel-enabled", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub enabled: Option, + #[clap( + long = "experimental-otel-protocol", + value_enum, + global = true, + value_name = "PROTOCOL" + )] + pub protocol: Option, + #[clap(long = "experimental-otel-endpoint", global = true, value_name = "URL")] + pub endpoint: Option, + #[clap( + long = "experimental-otel-timeout-ms", + global = true, + value_name = "MILLISECONDS" + )] + pub timeout_ms: Option, + #[clap( + long = "experimental-otel-header", + global = true, + value_parser = parse_key_val_pair, + value_name = "KEY=VALUE" + )] + pub headers: Vec<(String, String)>, + #[clap( + long = "experimental-otel-resource", + global = true, + value_parser = parse_key_val_pair, + value_name = "KEY=VALUE" + )] + pub resource_attributes: Vec<(String, String)>, + #[clap( + long = "experimental-otel-metrics-run-summary", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub metrics_run_summary: Option, + #[clap( + long = "experimental-otel-metrics-task-details", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub metrics_task_details: Option, +} + +impl ExperimentalOtelCliArgs { + pub fn to_config(&self) -> Option { + let mut options = ExperimentalOtelOptions::default(); + let mut touched = false; + + if let Some(enabled) = self.enabled { + options.enabled = Some(enabled); + touched = true; + } + if let Some(protocol) = self.protocol { + options.protocol = Some(protocol); + touched = true; + } + if let Some(endpoint) = &self.endpoint { + options.endpoint = Some(endpoint.clone()); + touched = true; + } + if let Some(timeout) = self.timeout_ms { + options.timeout_ms = Some(timeout); + touched = true; + } + if !self.headers.is_empty() { + let mut map = BTreeMap::new(); + for (key, value) in &self.headers { + map.insert(key.clone(), value.clone()); + } + options.headers = Some(map); + touched = true; + } + if !self.resource_attributes.is_empty() { + let mut map = BTreeMap::new(); + for (key, value) in &self.resource_attributes { + map.insert(key.clone(), value.clone()); + } + options.resource = Some(map); + touched = true; + } + if let Some(value) = self.metrics_run_summary { + options + .metrics + .get_or_insert_with(ExperimentalOtelMetricsOptions::default) + .run_summary = Some(value); + touched = true; + } + if let Some(value) = self.metrics_task_details { + options + .metrics + .get_or_insert_with(ExperimentalOtelMetricsOptions::default) + .task_details = Some(value); + touched = true; + } + + touched.then_some(options) + } +} + #[derive(Subcommand, Copy, Clone, Debug, PartialEq)] pub enum DaemonCommand { /// Restarts the turbo daemon diff --git a/crates/turborepo-lib/src/commands/mod.rs b/crates/turborepo-lib/src/commands/mod.rs index 534bda2cb7ee0..6db3271da3d08 100644 --- a/crates/turborepo-lib/src/commands/mod.rs +++ b/crates/turborepo-lib/src/commands/mod.rs @@ -129,6 +129,7 @@ impl CommandBase { args.execution_args() .and_then(|args| args.concurrency.clone()), ) + .with_experimental_otel(args.experimental_otel_args.to_config()) .build() } diff --git a/crates/turborepo-lib/src/config/env.rs b/crates/turborepo-lib/src/config/env.rs index 26fb21395e2c1..0b894a33bb768 100644 --- a/crates/turborepo-lib/src/config/env.rs +++ b/crates/turborepo-lib/src/config/env.rs @@ -9,7 +9,7 @@ use tracing::warn; use turbopath::AbsoluteSystemPathBuf; use turborepo_cache::CacheConfig; -use super::{ConfigurationOptions, Error, ResolvedConfigurationOptions}; +use super::{ConfigurationOptions, Error, ExperimentalOtelOptions, ResolvedConfigurationOptions}; use crate::{ cli::{EnvMode, LogOrder}, turbo_json::UIMode, @@ -46,6 +46,38 @@ const TURBO_MAPPING: &[(&str, &str)] = [ ("turbo_concurrency", "concurrency"), ("turbo_no_update_notifier", "no_update_notifier"), ("turbo_sso_login_callback_port", "sso_login_callback_port"), + ( + "turbo_experimental_otel_enabled", + "experimental_otel_enabled", + ), + ( + "turbo_experimental_otel_protocol", + "experimental_otel_protocol", + ), + ( + "turbo_experimental_otel_endpoint", + "experimental_otel_endpoint", + ), + ( + "turbo_experimental_otel_timeout_ms", + "experimental_otel_timeout_ms", + ), + ( + "turbo_experimental_otel_headers", + "experimental_otel_headers", + ), + ( + "turbo_experimental_otel_resource", + "experimental_otel_resource", + ), + ( + "turbo_experimental_otel_metrics_run_summary", + "experimental_otel_metrics_run_summary", + ), + ( + "turbo_experimental_otel_metrics_task_details", + "experimental_otel_metrics_task_details", + ), ] .as_slice(); @@ -221,6 +253,8 @@ impl ResolvedConfigurationOptions for EnvVars { .transpose() .map_err(Error::InvalidSsoLoginCallbackPort)?; + let experimental_otel = ExperimentalOtelOptions::from_env_map(&self.output_map)?; + let output = ConfigurationOptions { api_url: self.output_map.get("api_url").cloned(), login_url: self.output_map.get("login_url").cloned(), @@ -257,6 +291,7 @@ impl ResolvedConfigurationOptions for EnvVars { sso_login_callback_port, // Do not allow future flags to be set by env var future_flags: None, + experimental_otel, }; Ok(output) diff --git a/crates/turborepo-lib/src/config/experimental_otel.rs b/crates/turborepo-lib/src/config/experimental_otel.rs new file mode 100644 index 0000000000000..fb4cde6c5d82d --- /dev/null +++ b/crates/turborepo-lib/src/config/experimental_otel.rs @@ -0,0 +1,213 @@ +use std::{collections::BTreeMap, fmt, str::FromStr}; + +use clap::ValueEnum; +use merge::Merge; +use serde::{Deserialize, Serialize}; + +use super::Error; + +#[derive( + Copy, + Clone, + Debug, + PartialEq, + Eq, + Serialize, + Deserialize, + Default, + Hash, + PartialOrd, + Ord, + ValueEnum, +)] +#[serde(rename_all = "kebab-case")] +pub enum ExperimentalOtelProtocol { + #[default] + #[serde(alias = "grpc")] + Grpc, + #[serde(alias = "http")] + #[serde(alias = "http/protobuf")] + HttpProtobuf, +} + +impl fmt::Display for ExperimentalOtelProtocol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ExperimentalOtelProtocol::Grpc => write!(f, "grpc"), + ExperimentalOtelProtocol::HttpProtobuf => write!(f, "http/protobuf"), + } + } +} + +impl FromStr for ExperimentalOtelProtocol { + type Err = (); + + fn from_str(s: &str) -> Result { + match s.to_ascii_lowercase().as_str() { + "grpc" => Ok(Self::Grpc), + "http" | "http/protobuf" | "http_protobuf" => Ok(Self::HttpProtobuf), + _ => Err(()), + } + } +} + +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq, Eq, Merge)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalOtelMetricsOptions { + pub run_summary: Option, + pub task_details: Option, +} + +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq, Eq, Merge)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalOtelOptions { + pub enabled: Option, + pub protocol: Option, + pub endpoint: Option, + pub headers: Option>, + pub timeout_ms: Option, + pub resource: Option>, + pub metrics: Option, +} + +impl ExperimentalOtelOptions { + pub fn is_empty(&self) -> bool { + self.enabled.is_none() + && self.protocol.is_none() + && self.endpoint.is_none() + && self.headers.as_ref().map(|m| m.is_empty()).unwrap_or(true) + && self.timeout_ms.is_none() + && self.resource.as_ref().map(|m| m.is_empty()).unwrap_or(true) + && self + .metrics + .as_ref() + .map(|m| m.run_summary.is_none() && m.task_details.is_none()) + .unwrap_or(true) + } + + pub fn from_env_map( + map: &std::collections::HashMap<&'static str, String>, + ) -> Result, Error> { + let mut options = Self::default(); + let mut touched = false; + + if let Some(raw) = get_non_empty(map, "experimental_otel_enabled") { + options.enabled = Some(parse_bool_flag(raw, "TURBO_EXPERIMENTAL_OTEL_ENABLED")?); + touched = true; + } + + if let Some(raw) = get_non_empty(map, "experimental_otel_protocol") { + let protocol = ::from_str(raw).map_err(|_| { + Error::InvalidExperimentalOtelConfig { + message: format!( + "Unsupported experimentalObservability.otel protocol `{raw}`. Use `grpc` \ + or `http/protobuf`." + ), + } + })?; + options.protocol = Some(protocol); + touched = true; + } + + if let Some(raw) = get_non_empty(map, "experimental_otel_endpoint") { + options.endpoint = Some(raw.to_string()); + touched = true; + } + + if let Some(raw) = get_non_empty(map, "experimental_otel_timeout_ms") { + let timeout = raw + .parse() + .map_err(|_| Error::InvalidExperimentalOtelConfig { + message: "TURBO_EXPERIMENTAL_OTEL_TIMEOUT_MS must be a number.".to_string(), + })?; + options.timeout_ms = Some(timeout); + touched = true; + } + + if let Some(raw) = get_non_empty(map, "experimental_otel_headers") { + options.headers = Some(parse_key_value_pairs( + raw, + "TURBO_EXPERIMENTAL_OTEL_HEADERS", + )?); + touched = true; + } + + if let Some(raw) = get_non_empty(map, "experimental_otel_resource") { + options.resource = Some(parse_key_value_pairs( + raw, + "TURBO_EXPERIMENTAL_OTEL_RESOURCE", + )?); + touched = true; + } + + touched |= set_metric_flag( + map, + "experimental_otel_metrics_run_summary", + "TURBO_EXPERIMENTAL_OTEL_METRICS_RUN_SUMMARY", + |metrics, value| metrics.run_summary = Some(value), + &mut options, + )?; + + touched |= set_metric_flag( + map, + "experimental_otel_metrics_task_details", + "TURBO_EXPERIMENTAL_OTEL_METRICS_TASK_DETAILS", + |metrics, value| metrics.task_details = Some(value), + &mut options, + )?; + + Ok(touched.then_some(options)) + } +} + +fn get_non_empty<'a>( + map: &'a std::collections::HashMap<&'static str, String>, + key: &'static str, +) -> Option<&'a str> { + map.get(key).map(|s| s.as_str()).filter(|s| !s.is_empty()) +} + +fn parse_bool_flag(raw: &str, var: &str) -> Result { + crate::config::env::truth_env_var(raw).ok_or_else(|| Error::InvalidExperimentalOtelConfig { + message: format!("{var} should be either 1 or 0."), + }) +} + +fn parse_key_value_pairs(raw: &str, context: &str) -> Result, Error> { + let mut map = BTreeMap::new(); + for entry in raw.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { + let Some((key, value)) = entry.split_once('=') else { + return Err(Error::InvalidExperimentalOtelConfig { + message: format!("{context} entries must be in key=value format."), + }); + }; + if key.trim().is_empty() { + return Err(Error::InvalidExperimentalOtelConfig { + message: format!("{context} keys cannot be empty."), + }); + } + map.insert(key.trim().to_string(), value.trim().to_string()); + } + + Ok(map) +} + +fn set_metric_flag( + map: &std::collections::HashMap<&'static str, String>, + key: &'static str, + env_name: &'static str, + set: impl FnOnce(&mut ExperimentalOtelMetricsOptions, bool), + options: &mut ExperimentalOtelOptions, +) -> Result { + if let Some(raw) = get_non_empty(map, key) { + let value = parse_bool_flag(raw, env_name)?; + set( + options + .metrics + .get_or_insert_with(ExperimentalOtelMetricsOptions::default), + value, + ); + return Ok(true); + } + Ok(false) +} diff --git a/crates/turborepo-lib/src/config/mod.rs b/crates/turborepo-lib/src/config/mod.rs index fad0c7ed21dd8..16ed3e0718e38 100644 --- a/crates/turborepo-lib/src/config/mod.rs +++ b/crates/turborepo-lib/src/config/mod.rs @@ -1,4 +1,5 @@ mod env; +mod experimental_otel; mod file; mod override_env; mod turbo_json; @@ -32,6 +33,10 @@ use crate::{ pub const CONFIG_FILE: &str = "turbo.json"; pub const CONFIG_FILE_JSONC: &str = "turbo.jsonc"; +pub use experimental_otel::{ + ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol, +}; + #[derive(Debug, Error, Diagnostic)] #[error("Environment variables should not be prefixed with \"{env_pipeline_delimiter}\"")] #[diagnostic( @@ -252,6 +257,8 @@ pub enum Error { InvalidTuiScrollbackLength(#[source] std::num::ParseIntError), #[error("TURBO_SSO_LOGIN_CALLBACK_PORT: Invalid value. Use a number for the callback port.")] InvalidSsoLoginCallbackPort(#[source] std::num::ParseIntError), + #[error("Invalid experimentalOtel configuration: {message}")] + InvalidExperimentalOtelConfig { message: String }, } const DEFAULT_API_URL: &str = "https://vercel.com/api"; @@ -324,6 +331,8 @@ pub struct ConfigurationOptions { pub(crate) sso_login_callback_port: Option, #[serde(skip)] future_flags: Option, + #[serde(rename = "experimentalOtel")] + pub(crate) experimental_otel: Option, } #[derive(Default)] @@ -487,6 +496,10 @@ impl ConfigurationOptions { pub fn future_flags(&self) -> FutureFlags { self.future_flags.unwrap_or_default() } + + pub fn experimental_otel(&self) -> Option<&ExperimentalOtelOptions> { + self.experimental_otel.as_ref() + } } // Maps Some("") to None to emulate how Go handles empty strings diff --git a/crates/turborepo-lib/src/config/turbo_json.rs b/crates/turborepo-lib/src/config/turbo_json.rs index 1041c18b807ef..bfedc94badfde 100644 --- a/crates/turborepo-lib/src/config/turbo_json.rs +++ b/crates/turborepo-lib/src/config/turbo_json.rs @@ -1,8 +1,15 @@ +use std::{collections::BTreeMap, str::FromStr}; + use camino::Utf8PathBuf; use turbopath::{AbsoluteSystemPath, RelativeUnixPath}; -use super::{ConfigurationOptions, Error, ResolvedConfigurationOptions}; -use crate::turbo_json::{RawRemoteCacheOptions, RawRootTurboJson, RawTurboJson}; +use super::{ + ConfigurationOptions, Error, ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, + ExperimentalOtelProtocol, ResolvedConfigurationOptions, +}; +use crate::turbo_json::{ + RawKeyValue, RawObservabilityOtel, RawRemoteCacheOptions, RawRootTurboJson, RawTurboJson, +}; pub struct TurboJsonReader<'a> { repo_root: &'a AbsoluteSystemPath, @@ -78,7 +85,23 @@ impl<'a> TurboJsonReader<'a> { opts.env_mode = turbo_json.env_mode.map(|mode| *mode.as_inner()); opts.cache_dir = cache_dir; opts.concurrency = turbo_json.concurrency.map(|c| c.as_inner().clone()); + + // Only read observability config if futureFlags.experimentalObservability is + // enabled + let future_flags = turbo_json.future_flags.as_ref().map(|f| *f.as_inner()); opts.future_flags = turbo_json.future_flags.map(|f| *f.as_inner()); + + if future_flags + .map(|f| f.experimental_observability) + .unwrap_or(false) + { + let raw_otel = turbo_json + .experimental_observability + .and_then(|obs| obs.otel); + if let Some(raw_otel) = raw_otel { + opts.experimental_otel = Some(convert_raw_observability_otel(raw_otel)?); + } + } Ok(opts) } } @@ -103,6 +126,50 @@ impl<'a> ResolvedConfigurationOptions for TurboJsonReader<'a> { } } +fn convert_key_values(entries: Vec) -> BTreeMap { + let mut map = BTreeMap::new(); + for entry in entries { + map.insert( + entry.key.into_inner().into(), + entry.value.into_inner().into(), + ); + } + map +} + +fn convert_raw_observability_otel( + raw: RawObservabilityOtel, +) -> Result { + let protocol = if let Some(protocol) = raw.protocol { + let proto_str = protocol.as_inner().as_str(); + Some(ExperimentalOtelProtocol::from_str(proto_str).map_err(|_| { + Error::InvalidExperimentalOtelConfig { + message: format!( + "Unsupported experimentalObservability.otel protocol `{proto_str}`. Use \ + `grpc` or `http/protobuf`." + ), + } + })?) + } else { + None + }; + + let metrics = raw.metrics.map(|metrics| ExperimentalOtelMetricsOptions { + run_summary: metrics.run_summary.map(|flag| *flag.as_inner()), + task_details: metrics.task_details.map(|flag| *flag.as_inner()), + }); + + Ok(ExperimentalOtelOptions { + enabled: raw.enabled.map(|flag| *flag.as_inner()), + protocol, + endpoint: raw.endpoint.map(|endpoint| endpoint.into_inner().into()), + headers: raw.headers.map(convert_key_values), + timeout_ms: raw.timeout_ms.map(|timeout| *timeout.as_inner()), + resource: raw.resource.map(convert_key_values), + metrics, + }) +} + #[cfg(test)] mod test { use serde_json::json; @@ -227,4 +294,81 @@ mod test { let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); assert_eq!(config.allow_no_package_manager(), expected); } + + #[test] + fn test_experimental_observability_otel_with_future_flag_disabled() { + let turbo_json = RawRootTurboJson::parse( + &serde_json::to_string_pretty(&json!({ + "futureFlags": { + "experimentalObservability": false + }, + "experimentalObservability": { + "otel": { + "enabled": true, + "endpoint": "https://example.com/otel" + } + } + })) + .unwrap(), + "turbo.json", + ) + .unwrap() + .into(); + let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); + // Should be None because future flag is disabled + assert_eq!(config.experimental_otel(), None); + } + + #[test] + fn test_experimental_observability_otel_with_future_flag_enabled() { + let endpoint = "https://example.com/otel"; + let turbo_json = RawRootTurboJson::parse( + &serde_json::to_string_pretty(&json!({ + "futureFlags": { + "experimentalObservability": true + }, + "experimentalObservability": { + "otel": { + "enabled": true, + "endpoint": endpoint, + "protocol": "grpc", + "timeoutMs": 5000 + } + } + })) + .unwrap(), + "turbo.json", + ) + .unwrap() + .into(); + let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); + let otel_config = config.experimental_otel(); + assert!(otel_config.is_some()); + let otel_config = otel_config.unwrap(); + assert_eq!(otel_config.enabled, Some(true)); + assert_eq!(otel_config.endpoint.as_ref(), Some(&endpoint.to_string())); + assert_eq!(otel_config.protocol, Some(ExperimentalOtelProtocol::Grpc)); + assert_eq!(otel_config.timeout_ms, Some(5000)); + } + + #[test] + fn test_experimental_observability_without_future_flag() { + let turbo_json = RawRootTurboJson::parse( + &serde_json::to_string_pretty(&json!({ + "experimentalObservability": { + "otel": { + "enabled": true, + "endpoint": "https://example.com/otel" + } + } + })) + .unwrap(), + "turbo.json", + ) + .unwrap() + .into(); + let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); + // Should be None because future flag is not set (defaults to false) + assert_eq!(config.experimental_otel(), None); + } } diff --git a/crates/turborepo-lib/src/lib.rs b/crates/turborepo-lib/src/lib.rs index 65b8ed29b9819..fe337ac3b17e4 100644 --- a/crates/turborepo-lib/src/lib.rs +++ b/crates/turborepo-lib/src/lib.rs @@ -25,6 +25,7 @@ mod boundaries; mod gitignore; mod hash; mod microfrontends; +mod observability; mod opts; mod package_changes_watcher; mod panic_handler; diff --git a/crates/turborepo-lib/src/observability/mod.rs b/crates/turborepo-lib/src/observability/mod.rs new file mode 100644 index 0000000000000..39f5c17551bf2 --- /dev/null +++ b/crates/turborepo-lib/src/observability/mod.rs @@ -0,0 +1,78 @@ +//! Observability abstraction layer for Turborepo runs. +//! +//! This module provides a generic interface for recording metrics and telemetry +//! from completed Turborepo runs. The public API consists of: +//! +//! - [`Handle`]: An opaque handle to an observability backend +//! - [`try_init`]: Factory function to initialize an observability backend +//! +//! Currently, only OpenTelemetry is supported as a backend. Additional backends +//! can be added by: +//! +//! 1. Creating a new submodule (e.g., `observability::prometheus`) that +//! implements the internal `RunObserver` trait +//! 2. Adding a `try_init_*` function that returns `Option` +//! 3. Updating `try_init` to dispatch to the appropriate backend based on +//! config +//! +//! The abstraction ensures that callers only depend on the generic `Handle` +//! type and are not coupled to any specific observability implementation. + +use std::sync::Arc; + +use crate::{config::ExperimentalOtelOptions, run::summary::RunSummary}; + +mod otel; + +/// Trait for observing completed Turborepo runs, allowing different +/// observability backends like OpenTelemetry to be plugged in. +pub(crate) trait RunObserver: Send + Sync { + /// Record metrics for a completed run. + fn record(&self, summary: &RunSummary<'_>); + /// Shutdown the observer, flushing any pending metrics. + /// This is called when the handle is dropped or explicitly shut down. + fn shutdown(&self); +} + +/// A generic handle to an observability backend. +/// +/// This is the only type that the rest of turborepo-lib needs to know about. +/// The concrete backend implementation is hidden behind the `RunObserver` +/// trait. +#[derive(Clone)] +pub struct Handle { + pub(crate) inner: Arc, +} + +impl std::fmt::Debug for Handle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Handle").finish_non_exhaustive() + } +} + +impl Handle { + /// Record metrics for a completed run. + pub fn record(&self, summary: &RunSummary<'_>) { + self.inner.record(summary); + } + + /// Shutdown the observer, flushing any pending metrics. + pub fn shutdown(self) { + // We only have an Arc, so we delegate shutdown to the trait + // and let the concrete implementation handle any shared references. + self.inner.shutdown(); + } + + /// Initialize an observability handle from configuration options. + /// + /// Returns `None` if observability is disabled or misconfigured. + /// + /// Currently, this only supports OpenTelemetry backends configured via + /// `ExperimentalOtelOptions` (from `experimentalObservability.otel` in + /// turbo.json or via environment variables/CLI flags). In the future, this + /// may dispatch to different backends based on the configuration + /// provided. + pub(crate) fn try_init(options: &ExperimentalOtelOptions) -> Option { + otel::try_init_otel(options) + } +} diff --git a/crates/turborepo-lib/src/observability/otel.rs b/crates/turborepo-lib/src/observability/otel.rs new file mode 100644 index 0000000000000..3c7e6044a0ee2 --- /dev/null +++ b/crates/turborepo-lib/src/observability/otel.rs @@ -0,0 +1,157 @@ +use std::{sync::Arc, time::Duration}; + +use turborepo_otel::{RunMetricsPayload, TaskCacheStatus, TaskMetricsPayload}; + +use super::{Handle, RunObserver}; +use crate::{ + config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, + run::summary::{CacheStatus, RunSummary, TaskSummary}, +}; + +/// OpenTelemetry-based observer implementation. +struct OtelObserver { + handle: turborepo_otel::Handle, +} + +impl RunObserver for OtelObserver { + fn record(&self, summary: &RunSummary<'_>) { + if let Some(payload) = build_payload(summary) { + self.handle.record_run(&payload); + } + } + + fn shutdown(&self) { + // `shutdown` consumes the handle. Clone the cheap, Arc-backed handle first. + self.handle.clone().shutdown(); + } +} + +/// Initialize an OpenTelemetry observability handle from configuration options. +/// Returns `None` if observability is disabled or misconfigured. +pub(crate) fn try_init_otel(options: &ExperimentalOtelOptions) -> Option { + let config = config_from_options(options)?; + + match turborepo_otel::Handle::try_new(config) { + Ok(handle) => Some(Handle { + inner: Arc::new(OtelObserver { handle }), + }), + Err(e) => { + tracing::warn!("Failed to initialize OTel exporter: {}", e); + None + } + } +} + +fn config_from_options(options: &ExperimentalOtelOptions) -> Option { + if options.enabled.is_some_and(|enabled| !enabled) { + return None; + } + + let endpoint = options.endpoint.as_ref()?.trim(); + if endpoint.is_empty() { + return None; + } + let endpoint = endpoint.to_string(); + + let protocol = match options.protocol.unwrap_or(ExperimentalOtelProtocol::Grpc) { + ExperimentalOtelProtocol::Grpc => turborepo_otel::Protocol::Grpc, + ExperimentalOtelProtocol::HttpProtobuf => turborepo_otel::Protocol::HttpProtobuf, + }; + + let headers = options.headers.clone().unwrap_or_default(); + let resource_attributes = options.resource.clone().unwrap_or_default(); + let metrics = metrics_config(options.metrics.as_ref()); + let timeout = Duration::from_millis(options.timeout_ms.unwrap_or(10_000)); + + Some(turborepo_otel::Config { + endpoint, + protocol, + headers, + timeout, + resource_attributes, + metrics, + }) +} + +fn metrics_config( + options: Option<&ExperimentalOtelMetricsOptions>, +) -> turborepo_otel::MetricsConfig { + let run_summary = options.and_then(|opts| opts.run_summary).unwrap_or(true); + let task_details = options.and_then(|opts| opts.task_details).unwrap_or(false); + turborepo_otel::MetricsConfig { + run_summary, + task_details, + } +} + +fn build_payload(summary: &RunSummary<'_>) -> Option { + let execution = summary.execution_summary()?; + let duration_ms = (execution.end_time - execution.start_time) as f64; + let attempted_tasks = execution.attempted() as u64; + let failed_tasks = execution.failed() as u64; + let cached_tasks = execution.cached() as u64; + + let tasks = summary + .tasks() + .iter() + .map(build_task_payload) + .collect::>(); + + let scm = summary.scm_state(); + + Some(RunMetricsPayload { + run_id: summary.id().to_string(), + turbo_version: summary.turbo_version().to_string(), + duration_ms, + attempted_tasks, + failed_tasks, + cached_tasks, + exit_code: execution.exit_code, + scm_branch: scm.branch().map(|s| s.to_string()), + scm_revision: scm.sha().map(|s| s.to_string()), + tasks, + }) +} + +fn build_task_payload(task: &TaskSummary) -> TaskMetricsPayload { + let duration_ms = task + .shared + .execution + .as_ref() + .map(|exec| (exec.end_time - exec.start_time) as f64); + let exit_code = task + .shared + .execution + .as_ref() + .and_then(|exec| exec.exit_code); + let cache_status = match task.shared.cache.status() { + CacheStatus::Hit => TaskCacheStatus::Hit, + CacheStatus::Miss => TaskCacheStatus::Miss, + }; + let cache_source = task + .shared + .cache + .cache_source_label() + .map(|label| label.to_string()); + let cache_time_saved_ms = match cache_status { + TaskCacheStatus::Hit => { + let saved = task.shared.cache.time_saved(); + (saved > 0).then_some(saved) + } + TaskCacheStatus::Miss => None, + }; + + TaskMetricsPayload { + task_id: task.task_id.to_string(), + task: task.task.clone(), + package: task.package.clone(), + hash: task.shared.hash.clone(), + external_inputs_hash: task.shared.hash_of_external_dependencies.clone(), + command: task.shared.command.clone(), + duration_ms, + cache_status, + cache_source, + cache_time_saved_ms, + exit_code, + } +} diff --git a/crates/turborepo-lib/src/opts.rs b/crates/turborepo-lib/src/opts.rs index 173fc6960d272..c512358395084 100644 --- a/crates/turborepo-lib/src/opts.rs +++ b/crates/turborepo-lib/src/opts.rs @@ -13,7 +13,7 @@ use crate::{ Command, ContinueMode, DryRunMode, EnvMode, ExecutionArgs, LogOrder, LogPrefix, OutputLogsMode, RunArgs, }, - config::{ConfigurationOptions, CONFIG_FILE}, + config::{ConfigurationOptions, ExperimentalOtelOptions, CONFIG_FILE}, turbo_json::{FutureFlags, UIMode}, Args, }; @@ -78,6 +78,7 @@ pub struct Opts { pub scope_opts: ScopeOpts, pub tui_opts: TuiOpts, pub future_flags: FutureFlags, + pub experimental_otel: Option, } impl Opts { @@ -182,6 +183,7 @@ impl Opts { let repo_opts = RepoOpts::from(inputs); let tui_opts = TuiOpts::from(inputs); let future_flags = config.future_flags(); + let experimental_otel = config.experimental_otel().cloned(); Ok(Self { repo_opts, @@ -192,6 +194,7 @@ impl Opts { api_client_opts, tui_opts, future_flags, + experimental_otel, }) } } @@ -751,6 +754,7 @@ mod test { runcache_opts, tui_opts, future_flags: Default::default(), + experimental_otel: None, }; let synthesized = opts.synthesize_command(); assert_eq!(synthesized, expected); diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 00c87cf6dc2a8..4991f93771970 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -45,6 +45,7 @@ use crate::{ config::resolve_turbo_config_path, engine::{Engine, EngineBuilder}, microfrontends::MicrofrontendsConfigs, + observability::Handle as ObservabilityHandle, opts::Opts, run::{scope, task_access::TaskAccess, Error, Run, RunCache}, shim::TurboState, @@ -483,6 +484,11 @@ impl RunBuilder { .should_print_prelude_override .unwrap_or_else(|| self.will_execute_tasks()); + let observability_handle = match self.opts.experimental_otel.as_ref() { + Some(opts) => ObservabilityHandle::try_init(opts), + None => None, + }; + Ok(Run { version: self.version, color_config: self.color_config, @@ -506,6 +512,7 @@ impl RunBuilder { daemon, should_print_prelude, micro_frontend_configs, + observability_handle, }) } diff --git a/crates/turborepo-lib/src/run/mod.rs b/crates/turborepo-lib/src/run/mod.rs index e5e61ce9123c7..1930809c27ad5 100644 --- a/crates/turborepo-lib/src/run/mod.rs +++ b/crates/turborepo-lib/src/run/mod.rs @@ -78,6 +78,7 @@ pub struct Run { daemon: Option>, should_print_prelude: bool, micro_frontend_configs: Option, + observability_handle: Option, } type UIResult = Result>)>, Error>; @@ -646,6 +647,7 @@ impl Run { self.version, Vendor::get_user(), &self.scm, + self.observability_handle.clone(), ); let mut visitor = Visitor::new( diff --git a/crates/turborepo-lib/src/run/summary/execution.rs b/crates/turborepo-lib/src/run/summary/execution.rs index c8ba1d042c9bf..d09c6dd90bc80 100644 --- a/crates/turborepo-lib/src/run/summary/execution.rs +++ b/crates/turborepo-lib/src/run/summary/execution.rs @@ -165,6 +165,18 @@ impl<'a> ExecutionSummary<'a> { fn successful(&self) -> usize { self.success + self.cached } + + pub(crate) fn attempted(&self) -> usize { + self.attempted + } + + pub(crate) fn failed(&self) -> usize { + self.failed + } + + pub(crate) fn cached(&self) -> usize { + self.cached + } } /// The final states of all task executions diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index c6f82ab7547af..e89d11db83459 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -29,6 +29,7 @@ use turborepo_scm::SCM; use turborepo_task_id::TaskId; use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; +pub(crate) use self::task::{CacheStatus, TaskSummary}; use self::{ execution::TaskState, task::SinglePackageTaskSummary, task_factory::TaskSummaryFactory, }; @@ -40,7 +41,6 @@ use crate::{ run::summary::{ execution::{ExecutionSummary, ExecutionTracker}, scm::SCMState, - task::TaskSummary, }, task_hash::TaskHashTracker, }; @@ -98,6 +98,8 @@ pub struct RunSummary<'a> { should_save: bool, #[serde(skip)] run_type: RunType, + #[serde(skip)] + observability_handle: Option, } /// We use this to track the run, so it's constructed before the run. @@ -109,6 +111,7 @@ pub struct RunTracker { execution_tracker: ExecutionTracker, user: Option, synthesized_command: String, + observability_handle: Option, } impl RunTracker { @@ -121,6 +124,7 @@ impl RunTracker { version: &'static str, user: Option, scm: &SCM, + observability_handle: Option, ) -> Self { let scm = SCMState::get(env_at_execution_start, scm, repo_root); @@ -131,6 +135,7 @@ impl RunTracker { execution_tracker: ExecutionTracker::new(), user, synthesized_command, + observability_handle, } } @@ -197,6 +202,7 @@ impl RunTracker { repo_root, should_save, run_type, + observability_handle: self.observability_handle, }) } @@ -311,6 +317,26 @@ impl<'a> From<&'a RunSummary<'a>> for SinglePackageRunSummary<'a> { } impl<'a> RunSummary<'a> { + pub(crate) fn id(&self) -> &Ksuid { + &self.id + } + + pub(crate) fn turbo_version(&self) -> &'static str { + self.turbo_version + } + + pub(crate) fn execution_summary(&self) -> Option<&ExecutionSummary<'a>> { + self.execution.as_ref() + } + + pub(crate) fn tasks(&self) -> &[TaskSummary] { + &self.tasks + } + + pub(crate) fn scm_state(&self) -> &SCMState { + &self.scm + } + #[tracing::instrument(skip(self, pkg_dep_graph, ui))] async fn finish( mut self, @@ -324,6 +350,11 @@ impl<'a> RunSummary<'a> { return self.close_dry_run(pkg_dep_graph, ui); } + if let Some(handle) = self.observability_handle.take() { + handle.record(&self); + handle.shutdown(); + } + if self.should_save { if let Err(err) = self.save() { warn!("Error writing run summary: {}", err) diff --git a/crates/turborepo-lib/src/run/summary/scm.rs b/crates/turborepo-lib/src/run/summary/scm.rs index a546b8c8063c2..35d45854afd99 100644 --- a/crates/turborepo-lib/src/run/summary/scm.rs +++ b/crates/turborepo-lib/src/run/summary/scm.rs @@ -50,4 +50,12 @@ impl SCMState { state } + + pub(crate) fn branch(&self) -> Option<&str> { + self.branch.as_deref() + } + + pub(crate) fn sha(&self) -> Option<&str> { + self.sha.as_deref() + } } diff --git a/crates/turborepo-lib/src/run/summary/task.rs b/crates/turborepo-lib/src/run/summary/task.rs index 4ed0d4e688ae6..8f33107473a01 100644 --- a/crates/turborepo-lib/src/run/summary/task.rs +++ b/crates/turborepo-lib/src/run/summary/task.rs @@ -29,7 +29,7 @@ pub struct TaskCacheSummary { #[derive(Debug, Serialize, Copy, Clone)] #[serde(rename_all = "UPPERCASE")] -enum CacheStatus { +pub(crate) enum CacheStatus { Hit, Miss, } @@ -122,6 +122,21 @@ pub struct TaskEnvVarSummary { } impl TaskCacheSummary { + pub(crate) fn status(&self) -> CacheStatus { + self.status + } + + pub(crate) fn time_saved(&self) -> u64 { + self.time_saved + } + + pub(crate) fn cache_source_label(&self) -> Option<&'static str> { + self.source.map(|source| match source { + CacheSource::Local => "LOCAL", + CacheSource::Remote => "REMOTE", + }) + } + pub fn cache_miss() -> Self { Self { local: false, diff --git a/crates/turborepo-lib/src/turbo_json/future_flags.rs b/crates/turborepo-lib/src/turbo_json/future_flags.rs index 8d613c9f0455d..cab221e3e6dc4 100644 --- a/crates/turborepo-lib/src/turbo_json/future_flags.rs +++ b/crates/turborepo-lib/src/turbo_json/future_flags.rs @@ -42,6 +42,12 @@ pub struct FutureFlags { /// root. All `turbo.json` must still extend from the root `turbo.json` /// first. pub non_root_extends: bool, + /// Enable experimental OpenTelemetry exporter support. + /// + /// When enabled, Turborepo will honor the `experimentalObservability` + /// configuration block (if present) to send run summaries to an + /// observability backend. + pub experimental_observability: bool, } impl FutureFlags { diff --git a/crates/turborepo-lib/src/turbo_json/mod.rs b/crates/turborepo-lib/src/turbo_json/mod.rs index 9e4d781e0c99a..469a19a5592df 100644 --- a/crates/turborepo-lib/src/turbo_json/mod.rs +++ b/crates/turborepo-lib/src/turbo_json/mod.rs @@ -33,7 +33,8 @@ pub use future_flags::FutureFlags; pub use loader::{TurboJsonLoader, TurboJsonReader}; pub use processed::ProcessedTaskDefinition; pub use raw::{ - RawPackageTurboJson, RawRemoteCacheOptions, RawRootTurboJson, RawTaskDefinition, RawTurboJson, + RawKeyValue, RawObservabilityOtel, RawPackageTurboJson, RawRemoteCacheOptions, + RawRootTurboJson, RawTaskDefinition, RawTurboJson, }; use crate::boundaries::BoundariesConfig; @@ -1022,6 +1023,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: true, non_root_extends: false, + experimental_observability: false, } ); diff --git a/crates/turborepo-lib/src/turbo_json/processed.rs b/crates/turborepo-lib/src/turbo_json/processed.rs index cd9548d245b6b..eae5cea6c8c32 100644 --- a/crates/turborepo-lib/src/turbo_json/processed.rs +++ b/crates/turborepo-lib/src/turbo_json/processed.rs @@ -408,6 +408,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: true, non_root_extends: false, + experimental_observability: false, }, ); @@ -430,6 +431,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: false, non_root_extends: false, + experimental_observability: false, }, ); @@ -450,6 +452,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: true, non_root_extends: false, + experimental_observability: false, }, ); @@ -596,6 +599,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: true, non_root_extends: false, + experimental_observability: false, }, ) .unwrap(); @@ -620,6 +624,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: false, non_root_extends: false, + experimental_observability: false, }, ); assert!(result.is_err()); @@ -640,6 +645,7 @@ mod tests { &FutureFlags { turbo_extends_keyword: false, non_root_extends: false, + experimental_observability: false, }, ); assert!(result.is_err()); diff --git a/crates/turborepo-lib/src/turbo_json/raw.rs b/crates/turborepo-lib/src/turbo_json/raw.rs index 38a5eaa281b41..bc4dc5d02bed5 100644 --- a/crates/turborepo-lib/src/turbo_json/raw.rs +++ b/crates/turborepo-lib/src/turbo_json/raw.rs @@ -41,6 +41,46 @@ pub struct RawRemoteCacheOptions { pub upload_timeout: Option>, } +#[derive(Serialize, Default, Debug, Clone, Iterable, Deserializable)] +#[serde(rename_all = "camelCase")] +pub struct RawObservabilityOtel { + pub enabled: Option>, + pub protocol: Option>, + pub endpoint: Option>, + pub headers: Option>, + pub timeout_ms: Option>, + pub resource: Option>, + pub metrics: Option, +} + +#[derive(Serialize, Default, Debug, Clone, Iterable, Deserializable)] +#[serde(rename_all = "camelCase")] +pub struct RawExperimentalObservability { + pub otel: Option, +} + +#[derive(Serialize, Debug, Clone, Iterable, Deserializable)] +pub struct RawKeyValue { + pub key: Spanned, + pub value: Spanned, +} + +#[derive(Serialize, Default, Debug, Clone, Iterable, Deserializable)] +#[serde(rename_all = "camelCase")] +pub struct RawObservabilityOtelMetrics { + pub run_summary: Option>, + pub task_details: Option>, +} + +impl Default for RawKeyValue { + fn default() -> Self { + Self { + key: Spanned::new(UnescapedString::from(String::new())), + value: Spanned::new(UnescapedString::from(String::new())), + } + } +} + // Root turbo.json #[derive(Default, Debug, Clone, Iterable, Deserializable)] pub struct RawRootTurboJson { @@ -49,6 +89,8 @@ pub struct RawRootTurboJson { #[deserializable(rename = "$schema")] pub(crate) schema: Option, pub(crate) experimental_spaces: Option, + #[deserializable(rename = "experimentalObservability")] + pub(crate) experimental_observability: Option, // Global root filesystem dependencies pub(crate) global_dependencies: Option>>, @@ -142,6 +184,9 @@ pub struct RawTurboJson { pub concurrency: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub future_flags: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "experimentalObservability")] + pub experimental_observability: Option, #[deserializable(rename = "//")] #[serde(skip)] pub(crate) _comment: Option, @@ -186,6 +231,7 @@ impl From for RawTurboJson { span: root.span, schema: root.schema, experimental_spaces: root.experimental_spaces, + experimental_observability: root.experimental_observability, global_dependencies: root.global_dependencies, global_env: root.global_env, global_pass_through_env: root.global_pass_through_env, diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml new file mode 100644 index 0000000000000..102e392279aa2 --- /dev/null +++ b/crates/turborepo-otel/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "turborepo-otel" +version = "0.1.0" +edition = "2024" + +[dependencies] +opentelemetry = { version = "0.23", features = ["metrics"] } +opentelemetry-otlp = { version = "0.16", features = ["grpc-tonic", "http-proto", "metrics"] } +opentelemetry_sdk = { version = "0.23", features = ["rt-tokio", "metrics"] } +opentelemetry-semantic-conventions = "0.15" +thiserror = "1.0" +tracing = "0.1" +tokio = { version = "1", features = ["rt", "macros", "sync"] } +tonic = "0.11" +serde = { version = "1", features = ["derive"], optional = true } +serde_json = { version = "1", optional = true } + +[features] +default = [] +serde = ["dep:serde", "dep:serde_json"] diff --git a/crates/turborepo-otel/src/lib.rs b/crates/turborepo-otel/src/lib.rs new file mode 100644 index 0000000000000..c8195dd2af9e8 --- /dev/null +++ b/crates/turborepo-otel/src/lib.rs @@ -0,0 +1,373 @@ +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, + time::Duration, +}; + +use opentelemetry::{ + KeyValue, + metrics::{Counter, Histogram, Meter, MeterProvider as _}, +}; +use opentelemetry_otlp::WithExportConfig; +use opentelemetry_sdk::{ + Resource, + metrics::{ + PeriodicReader, SdkMeterProvider, + reader::{ + AggregationSelector, DefaultAggregationSelector, DefaultTemporalitySelector, + TemporalitySelector, + }, + }, + runtime::Tokio, +}; +use opentelemetry_semantic_conventions::resource::SERVICE_NAME; +use thiserror::Error; +use tonic::metadata::{MetadataKey, MetadataMap, MetadataValue}; +use tracing::warn; + +/// Protocol supported by the OTLP exporter. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Protocol { + Grpc, + HttpProtobuf, +} + +/// Metric toggle configuration. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct MetricsConfig { + pub run_summary: bool, + pub task_details: bool, +} + +/// Resolved configuration for the exporter. +#[derive(Debug, Clone)] +pub struct Config { + pub endpoint: String, + pub protocol: Protocol, + pub headers: BTreeMap, + pub timeout: Duration, + pub resource_attributes: BTreeMap, + pub metrics: MetricsConfig, +} + +/// Summary of a Turborepo run encoded for metrics export. +#[derive(Debug)] +pub struct RunMetricsPayload { + pub run_id: String, + pub turbo_version: String, + pub duration_ms: f64, + pub attempted_tasks: u64, + pub failed_tasks: u64, + pub cached_tasks: u64, + pub exit_code: i32, + pub scm_branch: Option, + pub scm_revision: Option, + pub tasks: Vec, +} + +/// Per-task metrics details. +#[derive(Debug)] +pub struct TaskMetricsPayload { + pub task_id: String, + pub task: String, + pub package: String, + pub hash: String, + pub external_inputs_hash: String, + pub command: String, + pub duration_ms: Option, + pub cache_status: TaskCacheStatus, + pub cache_source: Option, + pub cache_time_saved_ms: Option, + pub exit_code: Option, +} + +/// Cache status for a task. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TaskCacheStatus { + Hit, + Miss, +} + +impl TaskCacheStatus { + fn as_str(&self) -> &'static str { + match self { + TaskCacheStatus::Hit => "hit", + TaskCacheStatus::Miss => "miss", + } + } +} + +/// Errors that can occur while configuring or using the exporter. +#[derive(Error, Debug)] +pub enum Error { + #[error("experimentalOtel requires an endpoint")] + MissingEndpoint, + #[error("failed to build OTLP exporter: {0}")] + Exporter(opentelemetry_otlp::Error), + #[error("invalid OTLP header `{0}`")] + InvalidHeader(String), + #[error("metrics SDK error: {0}")] + Metrics(#[from] opentelemetry::metrics::MetricsError), +} + +struct Instruments { + run_duration: Histogram, + run_attempted: Counter, + run_failed: Counter, + run_cached: Counter, + task_duration: Histogram, + task_cache: Counter, +} + +struct HandleInner { + provider: SdkMeterProvider, + instruments: Arc, + metrics: MetricsConfig, +} + +/// Handle to the configured exporter. +#[derive(Clone)] +pub struct Handle { + inner: Arc, +} + +impl std::fmt::Debug for Handle { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Handle").finish_non_exhaustive() + } +} + +impl Handle { + pub fn try_new(config: Config) -> Result { + if config.endpoint.trim().is_empty() { + return Err(Error::MissingEndpoint); + } + + let provider = build_provider(&config)?; + let meter = provider.meter("turborepo"); + let instruments = Arc::new(create_instruments(&meter)); + + Ok(Self { + inner: Arc::new(HandleInner { + provider, + instruments, + metrics: config.metrics, + }), + }) + } + + pub fn record_run(&self, payload: &RunMetricsPayload) { + if self.inner.metrics.run_summary { + self.inner.instruments.record_run_summary(payload); + } + if self.inner.metrics.task_details { + self.inner.instruments.record_task_details(payload); + } + } + + pub fn shutdown(self) { + match Arc::try_unwrap(self.inner) { + Ok(inner) => { + if let Err(err) = inner.provider.shutdown() { + warn!("failed to shutdown otel exporter: {err}"); + } + } + Err(shared) => { + if let Err(err) = shared.provider.shutdown() { + warn!("failed to shutdown otel exporter: {err}"); + } + } + } + } +} + +impl Instruments { + fn record_run_summary(&self, payload: &RunMetricsPayload) { + let attrs = build_run_attributes(payload); + self.run_duration.record(payload.duration_ms, &attrs); + self.run_attempted.add(payload.attempted_tasks, &attrs); + self.run_failed.add(payload.failed_tasks, &attrs); + self.run_cached.add(payload.cached_tasks, &attrs); + } + + fn record_task_details(&self, payload: &RunMetricsPayload) { + let base_attrs = build_run_attributes(payload); + for task in payload.tasks.iter() { + let mut attrs = base_attrs.clone(); + attrs.push(KeyValue::new("turbo.task.id", task.task_id.clone())); + attrs.push(KeyValue::new("turbo.task.name", task.task.clone())); + attrs.push(KeyValue::new("turbo.task.package", task.package.clone())); + attrs.push(KeyValue::new("turbo.task.hash", task.hash.clone())); + attrs.push(KeyValue::new( + "turbo.task.external_inputs_hash", + task.external_inputs_hash.clone(), + )); + attrs.push(KeyValue::new("turbo.task.command", task.command.clone())); + attrs.push(KeyValue::new( + "turbo.task.cache_status", + task.cache_status.as_str(), + )); + if let Some(source) = &task.cache_source { + attrs.push(KeyValue::new("turbo.task.cache_source", source.clone())); + } + if let Some(time_saved) = task.cache_time_saved_ms { + attrs.push(KeyValue::new( + "turbo.task.cache_time_saved_ms", + time_saved as i64, + )); + } + if let Some(exit_code) = task.exit_code { + attrs.push(KeyValue::new("turbo.task.exit_code", exit_code as i64)); + } + if let Some(duration) = task.duration_ms { + self.task_duration.record(duration, &attrs); + } + self.task_cache.add(1, &attrs); + } + } +} + +fn build_provider(config: &Config) -> Result { + let resource = build_resource(config); + + let exporter = match config.protocol { + Protocol::Grpc => { + let export_config = opentelemetry_otlp::ExportConfig { + endpoint: config.endpoint.clone(), + timeout: config.timeout, + ..Default::default() + }; + let mut builder = opentelemetry_otlp::new_exporter() + .tonic() + .with_export_config(export_config); + if !config.headers.is_empty() { + builder = builder.with_metadata(build_metadata(&config.headers)?); + } + let (aggregation, temporality) = default_selectors(); + builder + .build_metrics_exporter(aggregation, temporality) + .map_err(Error::Metrics)? + } + Protocol::HttpProtobuf => { + let export_config = opentelemetry_otlp::ExportConfig { + endpoint: config.endpoint.clone(), + timeout: config.timeout, + ..Default::default() + }; + let mut builder = opentelemetry_otlp::new_exporter() + .http() + .with_export_config(export_config); + if !config.headers.is_empty() { + let headers: HashMap<_, _> = config.headers.clone().into_iter().collect(); + builder = builder.with_headers(headers); + } + let (aggregation, temporality) = default_selectors(); + builder + .build_metrics_exporter(aggregation, temporality) + .map_err(Error::Metrics)? + } + }; + + let reader = PeriodicReader::builder(exporter, Tokio).with_interval(Duration::from_secs(15)); + let reader = reader.build(); + + Ok(SdkMeterProvider::builder() + .with_resource(resource) + .with_reader(reader) + .build()) +} + +fn build_metadata(headers: &BTreeMap) -> Result { + let mut map = MetadataMap::new(); + for (key, value) in headers { + let metadata_key = MetadataKey::from_bytes(key.as_bytes()) + .map_err(|_| Error::InvalidHeader(key.clone()))?; + let metadata_value = MetadataValue::try_from(value.as_str()) + .map_err(|_| Error::InvalidHeader(key.clone()))?; + map.insert(metadata_key, metadata_value); + } + Ok(map) +} + +fn build_resource(config: &Config) -> Resource { + let mut attrs = Vec::with_capacity(config.resource_attributes.len() + 1); + let service_name = config + .resource_attributes + .get("service.name") + .cloned() + .unwrap_or_else(|| "turborepo".to_string()); + attrs.push(KeyValue::new(SERVICE_NAME, service_name)); + for (key, value) in config.resource_attributes.iter() { + if key == "service.name" { + continue; + } + attrs.push(KeyValue::new(key.clone(), value.clone())); + } + Resource::new(attrs) +} + +fn default_selectors() -> ( + Box, + Box, +) { + ( + Box::new(DefaultAggregationSelector::new()), + Box::new(DefaultTemporalitySelector::new()), + ) +} + +fn create_instruments(meter: &Meter) -> Instruments { + let run_duration = meter + .f64_histogram("turbo.run.duration_ms") + .with_description("Turborepo run duration in milliseconds") + .init(); + let run_attempted = meter + .u64_counter("turbo.run.tasks.attempted") + .with_description("Tasks attempted per run") + .init(); + let run_failed = meter + .u64_counter("turbo.run.tasks.failed") + .with_description("Tasks failed per run") + .init(); + let run_cached = meter + .u64_counter("turbo.run.tasks.cached") + .with_description("Tasks served from cache per run") + .init(); + let task_duration = meter + .f64_histogram("turbo.task.duration_ms") + .with_description("Task execution duration in milliseconds") + .init(); + let task_cache = meter + .u64_counter("turbo.task.cache.events") + .with_description("Cache hit/miss events") + .init(); + + Instruments { + run_duration, + run_attempted, + run_failed, + run_cached, + task_duration, + task_cache, + } +} + +fn build_run_attributes(payload: &RunMetricsPayload) -> Vec { + let mut attrs = Vec::with_capacity(6); + attrs.push(KeyValue::new("turbo.run.id", payload.run_id.clone())); + attrs.push(KeyValue::new( + "turbo.run.exit_code", + payload.exit_code.to_string(), + )); + attrs.push(KeyValue::new( + "turbo.version", + payload.turbo_version.clone(), + )); + if let Some(branch) = &payload.scm_branch { + attrs.push(KeyValue::new("turbo.scm.branch", branch.clone())); + } + if let Some(revision) = &payload.scm_revision { + attrs.push(KeyValue::new("turbo.scm.revision", revision.clone())); + } + attrs +} diff --git a/docs/site/content/docs/reference/configuration.mdx b/docs/site/content/docs/reference/configuration.mdx index 3fabffde8b6fa..ccce2e05ee23e 100644 --- a/docs/site/content/docs/reference/configuration.mdx +++ b/docs/site/content/docs/reference/configuration.mdx @@ -705,3 +705,175 @@ Must start with `team_` or it will not be used. The slug of the Remote Cache team. Value will be passed as `slug` in the querystring for all Remote Cache HTTP calls. + +## Future flags + +Future flags allow you to opt-in to experimental features before they become the default behavior. + +```jsonc title="./turbo.json" +{ + "futureFlags": { + "experimentalObservability": true + } +} +``` + +### `experimentalObservability` + +Default: `false` + +When enabled, Turborepo will honor the `experimentalObservability.otel` configuration block (if present) to send run summaries to an OpenTelemetry Protocol (OTLP) collector. + +## Experimental observability + +Experimental + +Configure Turborepo to export metrics to observability backends like Datadog, Prometheus, or other OTLP-compatible collectors. + +### `experimentalObservability` + +The `experimentalObservability` block is only read when `futureFlags.experimentalObservability` is set to `true` in your root `turbo.json`. Environment variables and CLI flags can still enable observability even if the future flag is disabled. + +```jsonc title="./turbo.json" +{ + "futureFlags": { + "experimentalObservability": true + }, + "experimentalObservability": { + "otel": { + "enabled": true, + "protocol": "grpc", + "endpoint": "https://api.datadoghq.com/api/v2/otlp", + "headers": { + "DD-API-KEY": "your-api-key" + }, + "timeoutMs": 10000, + "resource": { + "service.name": "turborepo" + }, + "metrics": { + "runSummary": true, + "taskDetails": false + } + } + } +} +``` + +#### `experimentalObservability.otel.enabled` + +Default: `true` (when endpoint is provided) + +Enable or disable the OpenTelemetry metrics exporter. + +#### `experimentalObservability.otel.protocol` + +Default: `"grpc"` + +The OTLP protocol to use. Supported values: +- `"grpc"` - OTLP over gRPC +- `"http/protobuf"` - OTLP over HTTP with protobuf encoding + +#### `experimentalObservability.otel.endpoint` + +**Required** when using file-based configuration. + +The OTLP collector endpoint URL. For example: +- Datadog: `"https://api.datadoghq.com/api/v2/otlp"` +- Custom collector: `"http://localhost:4317"` (gRPC) or `"http://localhost:4318"` (HTTP) + +#### `experimentalObservability.otel.headers` + +Optional HTTP headers to include with export requests. Useful for authentication (e.g., API keys) or custom metadata. + +```jsonc +{ + "experimentalObservability": { + "otel": { + "headers": { + "DD-API-KEY": "your-datadog-api-key", + "X-Custom-Header": "value" + } + } + } +} +``` + +#### `experimentalObservability.otel.timeoutMs` + +Default: `10000` (10 seconds) + +Timeout in milliseconds for export requests to the collector. + +#### `experimentalObservability.otel.resource` + +Optional resource attributes to attach to all exported metrics. These help identify the source of metrics in your observability platform. + +```jsonc +{ + "experimentalObservability": { + "otel": { + "resource": { + "service.name": "turborepo", + "service.namespace": "ci", + "deployment.environment": "production" + } + } + } +} +``` + +#### `experimentalObservability.otel.metrics` + +Control which metric groups are exported. + +##### `metrics.runSummary` + +Default: `true` + +Export run-level metrics: +- Run duration +- Tasks attempted, failed, and cached +- Exit code +- SCM branch and revision + +##### `metrics.taskDetails` + +Default: `false` + +Export per-task metrics: +- Task execution duration +- Cache hit/miss status and source +- Cache time saved +- Task identifiers (task ID, package, hash) + + + Exporter failures are logged but do not cause the run to fail. If the collector + is unavailable or misconfigured, Turborepo will continue executing tasks normally. + + +### Environment variables + +You can also configure observability via environment variables, which take precedence over `turbo.json` settings: + +- `TURBO_EXPERIMENTAL_OTEL_ENABLED` - Enable/disable exporter (`1` or `0`) +- `TURBO_EXPERIMENTAL_OTEL_PROTOCOL` - Protocol (`grpc` or `http/protobuf`) +- `TURBO_EXPERIMENTAL_OTEL_ENDPOINT` - Collector endpoint URL +- `TURBO_EXPERIMENTAL_OTEL_TIMEOUT_MS` - Timeout in milliseconds +- `TURBO_EXPERIMENTAL_OTEL_HEADERS` - Comma-separated key=value pairs (e.g., `"DD-API-KEY=key,Header=value"`) +- `TURBO_EXPERIMENTAL_OTEL_RESOURCE` - Comma-separated key=value pairs for resource attributes +- `TURBO_EXPERIMENTAL_OTEL_METRICS_RUN_SUMMARY` - Enable run summary metrics (`1` or `0`) +- `TURBO_EXPERIMENTAL_OTEL_METRICS_TASK_DETAILS` - Enable task details metrics (`1` or `0`) + +### CLI flags + +You can override observability settings via CLI flags: + +- `--experimental-otel-enabled` - Enable/disable exporter +- `--experimental-otel-protocol` - Protocol (`grpc` or `http/protobuf`) +- `--experimental-otel-endpoint` - Collector endpoint URL +- `--experimental-otel-timeout-ms` - Timeout in milliseconds +- `--experimental-otel-header KEY=VALUE` - Add HTTP header (can be repeated) +- `--experimental-otel-resource KEY=VALUE` - Add resource attribute (can be repeated) +- `--experimental-otel-metrics-run-summary` - Enable run summary metrics +- `--experimental-otel-metrics-task-details` - Enable task details metrics From cac92c13c15cabd69a0048bfc6b197d7fa625aa7 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 10:43:23 -0700 Subject: [PATCH 02/29] Align in experimental_observability to allow for more backends --- crates/turborepo-lib/src/commands/mod.rs | 8 ++++++-- crates/turborepo-lib/src/config/env.rs | 9 +++++++-- crates/turborepo-lib/src/config/mod.rs | 16 +++++++++++----- crates/turborepo-lib/src/config/turbo_json.rs | 18 ++++++++++-------- crates/turborepo-lib/src/observability/mod.rs | 18 +++++++++++------- crates/turborepo-lib/src/opts.rs | 10 +++++----- crates/turborepo-lib/src/run/builder.rs | 2 +- 7 files changed, 51 insertions(+), 30 deletions(-) diff --git a/crates/turborepo-lib/src/commands/mod.rs b/crates/turborepo-lib/src/commands/mod.rs index 6db3271da3d08..c6ce383198876 100644 --- a/crates/turborepo-lib/src/commands/mod.rs +++ b/crates/turborepo-lib/src/commands/mod.rs @@ -10,7 +10,7 @@ use crate::{ cli, config::{ resolve_turbo_config_path, ConfigurationOptions, Error as ConfigError, - TurborepoConfigBuilder, + ExperimentalObservabilityOptions, TurborepoConfigBuilder, }, opts::Opts, Args, @@ -129,7 +129,11 @@ impl CommandBase { args.execution_args() .and_then(|args| args.concurrency.clone()), ) - .with_experimental_otel(args.experimental_otel_args.to_config()) + .with_experimental_observability( + args.experimental_otel_args + .to_config() + .map(|otel| ExperimentalObservabilityOptions { otel: Some(otel) }), + ) .build() } diff --git a/crates/turborepo-lib/src/config/env.rs b/crates/turborepo-lib/src/config/env.rs index 0b894a33bb768..40879230195aa 100644 --- a/crates/turborepo-lib/src/config/env.rs +++ b/crates/turborepo-lib/src/config/env.rs @@ -9,7 +9,10 @@ use tracing::warn; use turbopath::AbsoluteSystemPathBuf; use turborepo_cache::CacheConfig; -use super::{ConfigurationOptions, Error, ExperimentalOtelOptions, ResolvedConfigurationOptions}; +use super::{ + ConfigurationOptions, Error, ExperimentalObservabilityOptions, ExperimentalOtelOptions, + ResolvedConfigurationOptions, +}; use crate::{ cli::{EnvMode, LogOrder}, turbo_json::UIMode, @@ -254,6 +257,8 @@ impl ResolvedConfigurationOptions for EnvVars { .map_err(Error::InvalidSsoLoginCallbackPort)?; let experimental_otel = ExperimentalOtelOptions::from_env_map(&self.output_map)?; + let experimental_observability = + experimental_otel.map(|otel| ExperimentalObservabilityOptions { otel: Some(otel) }); let output = ConfigurationOptions { api_url: self.output_map.get("api_url").cloned(), @@ -291,7 +296,7 @@ impl ResolvedConfigurationOptions for EnvVars { sso_login_callback_port, // Do not allow future flags to be set by env var future_flags: None, - experimental_otel, + experimental_observability, }; Ok(output) diff --git a/crates/turborepo-lib/src/config/mod.rs b/crates/turborepo-lib/src/config/mod.rs index 16ed3e0718e38..105e20a4b7940 100644 --- a/crates/turborepo-lib/src/config/mod.rs +++ b/crates/turborepo-lib/src/config/mod.rs @@ -14,7 +14,7 @@ use file::{AuthFile, ConfigFile}; use merge::Merge; use miette::{Diagnostic, NamedSource, SourceSpan}; use override_env::OverrideEnvVars; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use struct_iterable::Iterable; use thiserror::Error; use tracing::debug; @@ -37,6 +37,12 @@ pub use experimental_otel::{ ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol, }; +#[derive(Deserialize, Serialize, Default, Debug, Clone, PartialEq, Eq, Merge)] +#[serde(rename_all = "camelCase")] +pub struct ExperimentalObservabilityOptions { + pub otel: Option, +} + #[derive(Debug, Error, Diagnostic)] #[error("Environment variables should not be prefixed with \"{env_pipeline_delimiter}\"")] #[diagnostic( @@ -331,8 +337,8 @@ pub struct ConfigurationOptions { pub(crate) sso_login_callback_port: Option, #[serde(skip)] future_flags: Option, - #[serde(rename = "experimentalOtel")] - pub(crate) experimental_otel: Option, + #[serde(rename = "experimentalObservability")] + pub(crate) experimental_observability: Option, } #[derive(Default)] @@ -497,8 +503,8 @@ impl ConfigurationOptions { self.future_flags.unwrap_or_default() } - pub fn experimental_otel(&self) -> Option<&ExperimentalOtelOptions> { - self.experimental_otel.as_ref() + pub fn experimental_observability(&self) -> Option<&ExperimentalObservabilityOptions> { + self.experimental_observability.as_ref() } } diff --git a/crates/turborepo-lib/src/config/turbo_json.rs b/crates/turborepo-lib/src/config/turbo_json.rs index bfedc94badfde..642e81b63a39b 100644 --- a/crates/turborepo-lib/src/config/turbo_json.rs +++ b/crates/turborepo-lib/src/config/turbo_json.rs @@ -4,8 +4,8 @@ use camino::Utf8PathBuf; use turbopath::{AbsoluteSystemPath, RelativeUnixPath}; use super::{ - ConfigurationOptions, Error, ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, - ExperimentalOtelProtocol, ResolvedConfigurationOptions, + ConfigurationOptions, Error, ExperimentalObservabilityOptions, ExperimentalOtelMetricsOptions, + ExperimentalOtelOptions, ExperimentalOtelProtocol, ResolvedConfigurationOptions, }; use crate::turbo_json::{ RawKeyValue, RawObservabilityOtel, RawRemoteCacheOptions, RawRootTurboJson, RawTurboJson, @@ -99,7 +99,9 @@ impl<'a> TurboJsonReader<'a> { .experimental_observability .and_then(|obs| obs.otel); if let Some(raw_otel) = raw_otel { - opts.experimental_otel = Some(convert_raw_observability_otel(raw_otel)?); + opts.experimental_observability = Some(ExperimentalObservabilityOptions { + otel: Some(convert_raw_observability_otel(raw_otel)?), + }); } } Ok(opts) @@ -316,7 +318,7 @@ mod test { .into(); let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); // Should be None because future flag is disabled - assert_eq!(config.experimental_otel(), None); + assert_eq!(config.experimental_observability(), None); } #[test] @@ -342,9 +344,9 @@ mod test { .unwrap() .into(); let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); - let otel_config = config.experimental_otel(); - assert!(otel_config.is_some()); - let otel_config = otel_config.unwrap(); + let observability_config = config.experimental_observability(); + assert!(observability_config.is_some()); + let otel_config = observability_config.unwrap().otel.as_ref().unwrap(); assert_eq!(otel_config.enabled, Some(true)); assert_eq!(otel_config.endpoint.as_ref(), Some(&endpoint.to_string())); assert_eq!(otel_config.protocol, Some(ExperimentalOtelProtocol::Grpc)); @@ -369,6 +371,6 @@ mod test { .into(); let config = TurboJsonReader::turbo_json_to_config_options(turbo_json).unwrap(); // Should be None because future flag is not set (defaults to false) - assert_eq!(config.experimental_otel(), None); + assert_eq!(config.experimental_observability(), None); } } diff --git a/crates/turborepo-lib/src/observability/mod.rs b/crates/turborepo-lib/src/observability/mod.rs index 39f5c17551bf2..0e872d45508de 100644 --- a/crates/turborepo-lib/src/observability/mod.rs +++ b/crates/turborepo-lib/src/observability/mod.rs @@ -20,7 +20,7 @@ use std::sync::Arc; -use crate::{config::ExperimentalOtelOptions, run::summary::RunSummary}; +use crate::{config::ExperimentalObservabilityOptions, run::summary::RunSummary}; mod otel; @@ -68,11 +68,15 @@ impl Handle { /// Returns `None` if observability is disabled or misconfigured. /// /// Currently, this only supports OpenTelemetry backends configured via - /// `ExperimentalOtelOptions` (from `experimentalObservability.otel` in - /// turbo.json or via environment variables/CLI flags). In the future, this - /// may dispatch to different backends based on the configuration - /// provided. - pub(crate) fn try_init(options: &ExperimentalOtelOptions) -> Option { - otel::try_init_otel(options) + /// `ExperimentalObservabilityOptions` (from + /// `experimentalObservability.otel` in turbo.json or via environment + /// variables/CLI flags). In the future, this may dispatch to different + /// backends based on the configuration provided. + pub(crate) fn try_init(options: &ExperimentalObservabilityOptions) -> Option { + if let Some(otel_options) = options.otel.as_ref() { + otel::try_init_otel(otel_options) + } else { + None + } } } diff --git a/crates/turborepo-lib/src/opts.rs b/crates/turborepo-lib/src/opts.rs index c512358395084..711ba5e5fc4b8 100644 --- a/crates/turborepo-lib/src/opts.rs +++ b/crates/turborepo-lib/src/opts.rs @@ -13,7 +13,7 @@ use crate::{ Command, ContinueMode, DryRunMode, EnvMode, ExecutionArgs, LogOrder, LogPrefix, OutputLogsMode, RunArgs, }, - config::{ConfigurationOptions, ExperimentalOtelOptions, CONFIG_FILE}, + config::{ConfigurationOptions, CONFIG_FILE}, turbo_json::{FutureFlags, UIMode}, Args, }; @@ -78,7 +78,7 @@ pub struct Opts { pub scope_opts: ScopeOpts, pub tui_opts: TuiOpts, pub future_flags: FutureFlags, - pub experimental_otel: Option, + pub experimental_observability: Option, } impl Opts { @@ -183,7 +183,7 @@ impl Opts { let repo_opts = RepoOpts::from(inputs); let tui_opts = TuiOpts::from(inputs); let future_flags = config.future_flags(); - let experimental_otel = config.experimental_otel().cloned(); + let experimental_observability = config.experimental_observability().cloned(); Ok(Self { repo_opts, @@ -194,7 +194,7 @@ impl Opts { api_client_opts, tui_opts, future_flags, - experimental_otel, + experimental_observability, }) } } @@ -754,7 +754,7 @@ mod test { runcache_opts, tui_opts, future_flags: Default::default(), - experimental_otel: None, + experimental_observability: None, }; let synthesized = opts.synthesize_command(); assert_eq!(synthesized, expected); diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 4991f93771970..88d40440c875e 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -484,7 +484,7 @@ impl RunBuilder { .should_print_prelude_override .unwrap_or_else(|| self.will_execute_tasks()); - let observability_handle = match self.opts.experimental_otel.as_ref() { + let observability_handle = match self.opts.experimental_observability.as_ref() { Some(opts) => ObservabilityHandle::try_init(opts), None => None, }; From 356ed50471d5d1f362452f5077816a6274d006d0 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 11:15:01 -0700 Subject: [PATCH 03/29] Documentation and integration test fixes --- crates/turborepo-lib/Cargo.toml | 2 +- crates/turborepo-otel/Cargo.toml | 14 ++- .../content/docs/reference/configuration.mdx | 13 ++- .../integration/tests/other/no-args.t | 16 +++ .../integration/tests/other/turbo-help.t | 110 ++++++++++++++++++ 5 files changed, 145 insertions(+), 10 deletions(-) diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index 8a52398e6373a..fc8a3b651acb9 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -138,13 +138,13 @@ turborepo-graph-utils = { path = "../turborepo-graph-utils" } turborepo-lockfiles = { workspace = true } turborepo-microfrontends = { workspace = true } turborepo-microfrontends-proxy = { workspace = true } +turborepo-otel = { workspace = true } turborepo-process = { workspace = true } turborepo-repository = { path = "../turborepo-repository" } turborepo-scm = { workspace = true, features = ["git2"] } turborepo-signals = { workspace = true } turborepo-task-id = { workspace = true } turborepo-telemetry = { path = "../turborepo-telemetry" } -turborepo-otel = { workspace = true } turborepo-ui = { workspace = true } turborepo-unescape = { workspace = true } turborepo-vercel-api = { path = "../turborepo-vercel-api" } diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml index 102e392279aa2..c61ee8ac89d23 100644 --- a/crates/turborepo-otel/Cargo.toml +++ b/crates/turborepo-otel/Cargo.toml @@ -5,15 +5,19 @@ edition = "2024" [dependencies] opentelemetry = { version = "0.23", features = ["metrics"] } -opentelemetry-otlp = { version = "0.16", features = ["grpc-tonic", "http-proto", "metrics"] } -opentelemetry_sdk = { version = "0.23", features = ["rt-tokio", "metrics"] } +opentelemetry-otlp = { version = "0.16", features = [ + "grpc-tonic", + "http-proto", + "metrics", +] } opentelemetry-semantic-conventions = "0.15" +opentelemetry_sdk = { version = "0.23", features = ["rt-tokio", "metrics"] } +serde = { version = "1", features = ["derive"], optional = true } +serde_json = { version = "1", optional = true } thiserror = "1.0" -tracing = "0.1" tokio = { version = "1", features = ["rt", "macros", "sync"] } tonic = "0.11" -serde = { version = "1", features = ["derive"], optional = true } -serde_json = { version = "1", optional = true } +tracing = "0.1" [features] default = [] diff --git a/docs/site/content/docs/reference/configuration.mdx b/docs/site/content/docs/reference/configuration.mdx index ccce2e05ee23e..546034e4a483b 100644 --- a/docs/site/content/docs/reference/configuration.mdx +++ b/docs/site/content/docs/reference/configuration.mdx @@ -771,6 +771,7 @@ Enable or disable the OpenTelemetry metrics exporter. Default: `"grpc"` The OTLP protocol to use. Supported values: + - `"grpc"` - OTLP over gRPC - `"http/protobuf"` - OTLP over HTTP with protobuf encoding @@ -779,6 +780,7 @@ The OTLP protocol to use. Supported values: **Required** when using file-based configuration. The OTLP collector endpoint URL. For example: + - Datadog: `"https://api.datadoghq.com/api/v2/otlp"` - Custom collector: `"http://localhost:4317"` (gRPC) or `"http://localhost:4318"` (HTTP) @@ -786,7 +788,7 @@ The OTLP collector endpoint URL. For example: Optional HTTP headers to include with export requests. Useful for authentication (e.g., API keys) or custom metadata. -```jsonc +```jsonc title="./turbo.json" { "experimentalObservability": { "otel": { @@ -809,7 +811,7 @@ Timeout in milliseconds for export requests to the collector. Optional resource attributes to attach to all exported metrics. These help identify the source of metrics in your observability platform. -```jsonc +```jsonc title="./turbo.json" { "experimentalObservability": { "otel": { @@ -832,6 +834,7 @@ Control which metric groups are exported. Default: `true` Export run-level metrics: + - Run duration - Tasks attempted, failed, and cached - Exit code @@ -842,14 +845,16 @@ Export run-level metrics: Default: `false` Export per-task metrics: + - Task execution duration - Cache hit/miss status and source - Cache time saved - Task identifiers (task ID, package, hash) - Exporter failures are logged but do not cause the run to fail. If the collector - is unavailable or misconfigured, Turborepo will continue executing tasks normally. + Exporter failures are logged but do not cause the run to fail. If the + collector is unavailable or misconfigured, Turborepo will continue executing + tasks normally. ### Environment variables diff --git a/turborepo-tests/integration/tests/other/no-args.t b/turborepo-tests/integration/tests/other/no-args.t index cd6f13b67afac..c5480f3151b60 100644 --- a/turborepo-tests/integration/tests/other/no-args.t +++ b/turborepo-tests/integration/tests/other/no-args.t @@ -59,6 +59,22 @@ Make sure exit code is 2 when no args are passed Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json diff --git a/turborepo-tests/integration/tests/other/turbo-help.t b/turborepo-tests/integration/tests/other/turbo-help.t index 71df343af280d..ea1bfc5ca35f8 100644 --- a/turborepo-tests/integration/tests/other/turbo-help.t +++ b/turborepo-tests/integration/tests/other/turbo-help.t @@ -59,6 +59,22 @@ Test help flag Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json @@ -205,6 +221,30 @@ Test help flag --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + + --experimental-otel-endpoint + + + --experimental-otel-timeout-ms + + + --experimental-otel-header + + + --experimental-otel-resource + + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + + --experimental-otel-metrics-task-details [] + [possible values: true, false] + --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json`. @@ -324,6 +364,12 @@ Test help flag [possible values: auto, none, task] + + + + + + Test help flag for link command $ ${TURBO} link -h Link your local directory to a Vercel organization and enable remote caching @@ -371,6 +417,22 @@ Test help flag for link command Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json @@ -419,6 +481,22 @@ Test help flag for unlink command Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json @@ -471,6 +549,22 @@ Test help flag for login command Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json @@ -519,6 +613,22 @@ Test help flag for logout command Specify a file to save a pprof trace --verbosity Verbosity level. Useful when debugging Turborepo or creating logs for issue reports + --experimental-otel-enabled [] + [possible values: true, false] + --experimental-otel-protocol + [possible values: grpc, http-protobuf] + --experimental-otel-endpoint + + --experimental-otel-timeout-ms + + --experimental-otel-header + + --experimental-otel-resource + + --experimental-otel-metrics-run-summary [] + [possible values: true, false] + --experimental-otel-metrics-task-details [] + [possible values: true, false] --dangerously-disable-package-manager-check Allow for missing `packageManager` in `package.json` --root-turbo-json From 1134a4709f7e4857680a8d6c7861f2d8a49c10bb Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 11:18:51 -0700 Subject: [PATCH 04/29] Add some terms to the docs dictionary --- docs/site/dictionary.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/site/dictionary.txt b/docs/site/dictionary.txt index b3c4d20fbcab6..56047ba81b5ea 100644 --- a/docs/site/dictionary.txt +++ b/docs/site/dictionary.txt @@ -62,6 +62,7 @@ zero-config DevTools TSX backend +backends pre-configured Vue SvelteKit @@ -278,3 +279,17 @@ TailwindCSS TailwindCSS's frontend frontends +grpc +gRPC +observability +opentelemetry +OpenTelemetry +otlp +OTLP +otlp-compatible +OTLP-compatible +protobuf +scm +SCM +datadog +Datadog From 0c063da6d15cf313c1078d8060cd90926d80582f Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:00:39 -0700 Subject: [PATCH 05/29] Add more test coverage, and fix the capnproto error --- crates/turborepo-lib/build.rs | 41 +- crates/turborepo-lib/src/cli/mod.rs | 264 +- .../src/config/experimental_otel.rs | 276 ++ crates/turborepo-lib/src/hash/proto_capnp.rs | 3954 +++++++++++++++++ .../turborepo-lib/src/observability/otel.rs | 126 + crates/turborepo-otel/Cargo.toml | 1 + crates/turborepo-otel/src/lib.rs | 186 + .../tests/other/experimental-otel.t | 36 + 8 files changed, 4846 insertions(+), 38 deletions(-) create mode 100644 crates/turborepo-lib/src/hash/proto_capnp.rs create mode 100644 turborepo-tests/integration/tests/other/experimental-otel.t diff --git a/crates/turborepo-lib/build.rs b/crates/turborepo-lib/build.rs index eef97707179f7..4d8c65946516c 100644 --- a/crates/turborepo-lib/build.rs +++ b/crates/turborepo-lib/build.rs @@ -1,4 +1,11 @@ +use std::{fs, path::PathBuf}; + fn main() -> Result<(), Box> { + // Ensure Cargo reruns this script if either the schema or the pregenerated + // bindings change. + println!("cargo:rerun-if-changed=./src/hash/proto.capnp"); + println!("cargo:rerun-if-changed=./src/hash/proto_capnp.rs"); + let tonic_build_result = tonic_build::configure() .build_server(true) .file_descriptor_set_path("src/daemon/file_descriptor_set.bin") @@ -22,10 +29,38 @@ fn main() -> Result<(), Box> { } return Ok(()); - } else { - tonic_build_result.expect("tonic_build command"); - capnpc_result.expect("schema compiler command"); + } + + tonic_build_result.expect("tonic_build command"); + if let Err(err) = capnpc_result { + if !use_pregenerated_capnp()? { + // Preserve the previous behavior of failing the build when schema + // compilation fails, but surface the underlying error. + return Err(format!("schema compiler command failed: {err:?}").into()); + } + println!("cargo:warning=capnpc failed ({err:?}); using pre-generated Cap'n Proto bindings"); } Ok(()) } + +fn use_pregenerated_capnp() -> Result> { + let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); + let fallback = manifest_dir.join("src/hash/proto_capnp.rs"); + if !fallback.exists() { + return Ok(false); + } + + let out_dir = PathBuf::from(std::env::var("OUT_DIR")?); + let destination = out_dir.join("src/hash/proto_capnp.rs"); + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent)?; + } + fs::copy(&fallback, &destination)?; + println!( + "cargo:warning=Using pre-generated Cap'n Proto bindings from {}", + fallback.display() + ); + + Ok(true) +} diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 9716373255e97..150ee16935af4 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -10,10 +10,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, - ValueEnum, + ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, + builder::NonEmptyStringValueParser, }; -use clap_complete::{generate, Shell}; +use clap_complete::{Shell, generate}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -21,16 +21,17 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, - init_telemetry, track_usage, TelemetryHandle, + TelemetryHandle, + events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, + init_telemetry, track_usage, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, - ls, prune, query, run, scan, telemetry, unlink, CommandBase, + CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, + login, logout, ls, prune, query, run, scan, telemetry, unlink, }, config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, get_version, @@ -1619,11 +1620,7 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { - Ok(0) - } else { - Ok(1) - } + if scan::run(base).await { Ok(0) } else { Ok(1) } } Command::Config => { CommandEventBuilder::new("config") @@ -1861,7 +1858,11 @@ mod test { use itertools::Itertools; use pretty_assertions::assert_eq; - use crate::cli::{ContinueMode, ExecutionArgs, LinkTarget, RunArgs}; + use super::{ExperimentalOtelCliArgs, ExperimentalOtelProtocol}; + use crate::{ + cli::{ContinueMode, ExecutionArgs, LinkTarget, RunArgs}, + config::ExperimentalOtelOptions, + }; struct CommandTestCase { command: &'static str, @@ -3279,15 +3280,17 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!(Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err()); + assert!( + Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err() + ); } #[test] @@ -3428,19 +3431,23 @@ mod test { .collect(), ) .unwrap(); - assert!(inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package)); - assert!(explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false)); + assert!( + inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package) + ); + assert!( + explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false) + ); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] @@ -3494,4 +3501,191 @@ mod test { assert_snapshot!(args.join("-").as_str(), err); } } + + #[test] + fn test_experimental_otel_cli_args_empty() { + let args = ExperimentalOtelCliArgs::default(); + let result = args.to_config(); + assert_eq!(result, None); + } + + #[test] + fn test_experimental_otel_cli_args_enabled() { + let mut args = ExperimentalOtelCliArgs::default(); + args.enabled = Some(true); + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_protocol() { + let mut args = ExperimentalOtelCliArgs::default(); + args.protocol = Some(ExperimentalOtelProtocol::Grpc); + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::Grpc) + ); + } + + #[test] + fn test_experimental_otel_cli_args_protocol_http_protobuf() { + let mut args = ExperimentalOtelCliArgs::default(); + args.protocol = Some(ExperimentalOtelProtocol::HttpProtobuf); + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::HttpProtobuf) + ); + } + + #[test] + fn test_experimental_otel_cli_args_endpoint() { + let mut args = ExperimentalOtelCliArgs::default(); + args.endpoint = Some("https://example.com/otel".to_string()); + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().endpoint, + Some("https://example.com/otel".to_string()) + ); + } + + #[test] + fn test_experimental_otel_cli_args_timeout_ms() { + let mut args = ExperimentalOtelCliArgs::default(); + args.timeout_ms = Some(5000); + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!(result.unwrap().timeout_ms, Some(5000)); + } + + #[test] + fn test_experimental_otel_cli_args_headers_single() { + let mut args = ExperimentalOtelCliArgs::default(); + args.headers = vec![("key1".to_string(), "value1".to_string())]; + let result = args.to_config(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_headers_multiple() { + let mut args = ExperimentalOtelCliArgs::default(); + args.headers = vec![ + ("key1".to_string(), "value1".to_string()), + ("key2".to_string(), "value2".to_string()), + ]; + let result = args.to_config(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + assert_eq!(headers.get("key2"), Some(&"value2".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_headers_empty() { + let mut args = ExperimentalOtelCliArgs::default(); + args.headers = vec![]; + let result = args.to_config(); + assert_eq!(result, None); + } + + #[test] + fn test_experimental_otel_cli_args_resource_single() { + let mut args = ExperimentalOtelCliArgs::default(); + args.resource_attributes = vec![("service.name".to_string(), "my-service".to_string())]; + let result = args.to_config(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + } + + #[test] + fn test_experimental_otel_cli_args_resource_multiple() { + let mut args = ExperimentalOtelCliArgs::default(); + args.resource_attributes = vec![ + ("service.name".to_string(), "my-service".to_string()), + ("env".to_string(), "production".to_string()), + ]; + let result = args.to_config(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + assert_eq!(resource.get("env"), Some(&"production".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_run_summary() { + let mut args = ExperimentalOtelCliArgs::default(); + args.metrics_run_summary = Some(true); + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_task_details() { + let mut args = ExperimentalOtelCliArgs::default(); + args.metrics_task_details = Some(true); + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.task_details, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_both() { + let mut args = ExperimentalOtelCliArgs::default(); + args.metrics_run_summary = Some(true); + args.metrics_task_details = Some(false); + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + assert_eq!(metrics.task_details, Some(false)); + } + + #[test] + fn test_experimental_otel_cli_args_combined() { + let mut args = ExperimentalOtelCliArgs::default(); + args.enabled = Some(true); + args.protocol = Some(ExperimentalOtelProtocol::Grpc); + args.endpoint = Some("https://example.com/otel".to_string()); + args.timeout_ms = Some(15000); + args.headers = vec![("auth".to_string(), "token123".to_string())]; + args.resource_attributes = vec![("service.name".to_string(), "test".to_string())]; + args.metrics_run_summary = Some(true); + args.metrics_task_details = Some(false); + + let result = args.to_config(); + assert!(result.is_some()); + let opts = result.unwrap(); + assert_eq!(opts.enabled, Some(true)); + assert_eq!(opts.protocol, Some(ExperimentalOtelProtocol::Grpc)); + assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); + assert_eq!(opts.timeout_ms, Some(15000)); + assert_eq!( + opts.headers.unwrap().get("auth"), + Some(&"token123".to_string()) + ); + assert_eq!( + opts.resource.unwrap().get("service.name"), + Some(&"test".to_string()) + ); + let metrics = opts.metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + assert_eq!(metrics.task_details, Some(false)); + } } diff --git a/crates/turborepo-lib/src/config/experimental_otel.rs b/crates/turborepo-lib/src/config/experimental_otel.rs index fb4cde6c5d82d..9d16c638f58a6 100644 --- a/crates/turborepo-lib/src/config/experimental_otel.rs +++ b/crates/turborepo-lib/src/config/experimental_otel.rs @@ -211,3 +211,279 @@ fn set_metric_flag( } Ok(false) } + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use super::*; + + fn build_env_map(entries: &[(&'static str, &str)]) -> HashMap<&'static str, String> { + entries.iter().map(|(k, v)| (*k, v.to_string())).collect() + } + + #[test] + fn test_from_env_map_empty() { + let map = HashMap::new(); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert_eq!(result, None); + } + + #[test] + fn test_from_env_map_enabled_true() { + let map = build_env_map(&[("experimental_otel_enabled", "1")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(true)); + } + + #[test] + fn test_from_env_map_enabled_false() { + let map = build_env_map(&[("experimental_otel_enabled", "0")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(false)); + } + + #[test] + fn test_from_env_map_enabled_true_string() { + let map = build_env_map(&[("experimental_otel_enabled", "true")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(true)); + } + + #[test] + fn test_from_env_map_enabled_invalid() { + let map = build_env_map(&[("experimental_otel_enabled", "invalid")]); + let result = ExperimentalOtelOptions::from_env_map(&map); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidExperimentalOtelConfig { message } => { + assert!(message.contains("TURBO_EXPERIMENTAL_OTEL_ENABLED")); + } + _ => panic!("Expected InvalidExperimentalOtelConfig"), + } + } + + #[test] + fn test_from_env_map_protocol_grpc() { + let map = build_env_map(&[("experimental_otel_protocol", "grpc")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::Grpc) + ); + } + + #[test] + fn test_from_env_map_protocol_http_protobuf() { + for protocol_str in ["http/protobuf", "http", "http_protobuf"] { + let map = build_env_map(&[("experimental_otel_protocol", protocol_str)]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::HttpProtobuf) + ); + } + } + + #[test] + fn test_from_env_map_protocol_invalid() { + let map = build_env_map(&[("experimental_otel_protocol", "invalid")]); + let result = ExperimentalOtelOptions::from_env_map(&map); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidExperimentalOtelConfig { message } => { + assert!(message.contains("Unsupported experimentalObservability.otel protocol")); + assert!(message.contains("invalid")); + } + _ => panic!("Expected InvalidExperimentalOtelConfig"), + } + } + + #[test] + fn test_from_env_map_endpoint() { + let endpoint = "https://example.com/otel"; + let map = build_env_map(&[("experimental_otel_endpoint", endpoint)]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!(result.unwrap().endpoint, Some(endpoint.to_string())); + } + + #[test] + fn test_from_env_map_endpoint_empty_ignored() { + let map = build_env_map(&[("experimental_otel_endpoint", "")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert_eq!(result, None); + } + + #[test] + fn test_from_env_map_timeout_ms() { + let map = build_env_map(&[("experimental_otel_timeout_ms", "5000")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + assert_eq!(result.unwrap().timeout_ms, Some(5000)); + } + + #[test] + fn test_from_env_map_timeout_ms_invalid() { + let map = build_env_map(&[("experimental_otel_timeout_ms", "not-a-number")]); + let result = ExperimentalOtelOptions::from_env_map(&map); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidExperimentalOtelConfig { message } => { + assert!(message.contains("TURBO_EXPERIMENTAL_OTEL_TIMEOUT_MS must be a number")); + } + _ => panic!("Expected InvalidExperimentalOtelConfig"), + } + } + + #[test] + fn test_from_env_map_headers_single() { + let map = build_env_map(&[("experimental_otel_headers", "key1=value1")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + } + + #[test] + fn test_from_env_map_headers_multiple() { + let map = build_env_map(&[("experimental_otel_headers", "key1=value1,key2=value2")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + assert_eq!(headers.get("key2"), Some(&"value2".to_string())); + } + + #[test] + fn test_from_env_map_headers_with_spaces() { + let map = build_env_map(&[( + "experimental_otel_headers", + " key1 = value1 , key2 = value2 ", + )]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + assert_eq!(headers.get("key2"), Some(&"value2".to_string())); + } + + #[test] + fn test_from_env_map_headers_missing_equals() { + let map = build_env_map(&[("experimental_otel_headers", "key1value1")]); + let result = ExperimentalOtelOptions::from_env_map(&map); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidExperimentalOtelConfig { message } => { + assert!(message.contains("key=value format")); + } + _ => panic!("Expected InvalidExperimentalOtelConfig"), + } + } + + #[test] + fn test_from_env_map_headers_empty_key() { + let map = build_env_map(&[("experimental_otel_headers", "=value1")]); + let result = ExperimentalOtelOptions::from_env_map(&map); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidExperimentalOtelConfig { message } => { + assert!(message.contains("keys cannot be empty")); + } + _ => panic!("Expected InvalidExperimentalOtelConfig"), + } + } + + #[test] + fn test_from_env_map_resource_single() { + let map = build_env_map(&[("experimental_otel_resource", "service.name=my-service")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + } + + #[test] + fn test_from_env_map_resource_multiple() { + let map = build_env_map(&[( + "experimental_otel_resource", + "service.name=my-service,env=production", + )]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + assert_eq!(resource.get("env"), Some(&"production".to_string())); + } + + #[test] + fn test_from_env_map_metrics_run_summary() { + let map = build_env_map(&[("experimental_otel_metrics_run_summary", "1")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + } + + #[test] + fn test_from_env_map_metrics_task_details() { + let map = build_env_map(&[("experimental_otel_metrics_task_details", "1")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.task_details, Some(true)); + } + + #[test] + fn test_from_env_map_metrics_both() { + let map = build_env_map(&[ + ("experimental_otel_metrics_run_summary", "1"), + ("experimental_otel_metrics_task_details", "0"), + ]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + assert_eq!(metrics.task_details, Some(false)); + } + + #[test] + fn test_from_env_map_combined() { + let map = build_env_map(&[ + ("experimental_otel_enabled", "1"), + ("experimental_otel_protocol", "grpc"), + ("experimental_otel_endpoint", "https://example.com/otel"), + ("experimental_otel_timeout_ms", "15000"), + ("experimental_otel_headers", "auth=token123"), + ("experimental_otel_resource", "service.name=test"), + ("experimental_otel_metrics_run_summary", "1"), + ]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let opts = result.unwrap(); + assert_eq!(opts.enabled, Some(true)); + assert_eq!(opts.protocol, Some(ExperimentalOtelProtocol::Grpc)); + assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); + assert_eq!(opts.timeout_ms, Some(15000)); + assert_eq!( + opts.headers.unwrap().get("auth"), + Some(&"token123".to_string()) + ); + assert_eq!( + opts.resource.unwrap().get("service.name"), + Some(&"test".to_string()) + ); + assert_eq!(opts.metrics.unwrap().run_summary, Some(true)); + } +} diff --git a/crates/turborepo-lib/src/hash/proto_capnp.rs b/crates/turborepo-lib/src/hash/proto_capnp.rs new file mode 100644 index 0000000000000..47f7b5a299f4c --- /dev/null +++ b/crates/turborepo-lib/src/hash/proto_capnp.rs @@ -0,0 +1,3954 @@ +// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler. +// DO NOT EDIT. +// source: src/hash/proto.capnp + +pub mod task_hashable { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_global_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_global_hash(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_task_dependency_hashes(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_task_dependency_hashes(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + #[inline] + pub fn get_package_dir(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(2), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_package_dir(&self) -> bool { + !self.reader.get_pointer_field(2).is_null() + } + #[inline] + pub fn get_hash_of_files(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(3), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_hash_of_files(&self) -> bool { + !self.reader.get_pointer_field(3).is_null() + } + #[inline] + pub fn get_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(4), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_external_deps_hash(&self) -> bool { + !self.reader.get_pointer_field(4).is_null() + } + #[inline] + pub fn get_task(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(5), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_task(&self) -> bool { + !self.reader.get_pointer_field(5).is_null() + } + #[inline] + pub fn get_outputs( + self, + ) -> ::capnp::Result> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(6), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_outputs(&self) -> bool { + !self.reader.get_pointer_field(6).is_null() + } + #[inline] + pub fn get_pass_thru_args(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(7), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_pass_thru_args(&self) -> bool { + !self.reader.get_pointer_field(7).is_null() + } + #[inline] + pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(8), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_env(&self) -> bool { + !self.reader.get_pointer_field(8).is_null() + } + #[inline] + pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(9), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_resolved_env_vars(&self) -> bool { + !self.reader.get_pointer_field(9).is_null() + } + #[inline] + pub fn get_pass_thru_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(10), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_pass_thru_env(&self) -> bool { + !self.reader.get_pointer_field(10).is_null() + } + #[inline] + pub fn get_env_mode( + self, + ) -> ::core::result::Result< + crate::hash::proto_capnp::task_hashable::EnvMode, + ::capnp::NotInSchema, + > { + ::core::convert::TryInto::try_into(self.reader.get_data_field::(0)) + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 1, + pointers: 11, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_global_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_global_hash(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_global_hash(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_global_hash(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_task_dependency_hashes( + self, + ) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_task_dependency_hashes( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + } + #[inline] + pub fn init_task_dependency_hashes(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(1), + size, + ) + } + #[inline] + pub fn has_task_dependency_hashes(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + #[inline] + pub fn get_package_dir(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(2), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_package_dir(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(2).set_text(value); + } + #[inline] + pub fn init_package_dir(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(2).init_text(size) + } + #[inline] + pub fn has_package_dir(&self) -> bool { + !self.builder.is_pointer_field_null(2) + } + #[inline] + pub fn get_hash_of_files(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(3), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_hash_of_files(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(3).set_text(value); + } + #[inline] + pub fn init_hash_of_files(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(3).init_text(size) + } + #[inline] + pub fn has_hash_of_files(&self) -> bool { + !self.builder.is_pointer_field_null(3) + } + #[inline] + pub fn get_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(4), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_external_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(4).set_text(value); + } + #[inline] + pub fn init_external_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(4).init_text(size) + } + #[inline] + pub fn has_external_deps_hash(&self) -> bool { + !self.builder.is_pointer_field_null(4) + } + #[inline] + pub fn get_task(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(5), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_task(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(5).set_text(value); + } + #[inline] + pub fn init_task(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(5).init_text(size) + } + #[inline] + pub fn has_task(&self) -> bool { + !self.builder.is_pointer_field_null(5) + } + #[inline] + pub fn get_outputs( + self, + ) -> ::capnp::Result> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(6), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_outputs( + &mut self, + value: crate::hash::proto_capnp::task_outputs::Reader<'_>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(6), + value, + false, + ) + } + #[inline] + pub fn init_outputs(self) -> crate::hash::proto_capnp::task_outputs::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(6), 0) + } + #[inline] + pub fn has_outputs(&self) -> bool { + !self.builder.is_pointer_field_null(6) + } + #[inline] + pub fn get_pass_thru_args(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(7), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_pass_thru_args( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(7), + value, + false, + ) + } + #[inline] + pub fn init_pass_thru_args(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(7), + size, + ) + } + #[inline] + pub fn has_pass_thru_args(&self) -> bool { + !self.builder.is_pointer_field_null(7) + } + #[inline] + pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(8), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_env(&mut self, value: ::capnp::text_list::Reader<'a>) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(8), + value, + false, + ) + } + #[inline] + pub fn init_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(8), + size, + ) + } + #[inline] + pub fn has_env(&self) -> bool { + !self.builder.is_pointer_field_null(8) + } + #[inline] + pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(9), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_resolved_env_vars( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(9), + value, + false, + ) + } + #[inline] + pub fn init_resolved_env_vars(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(9), + size, + ) + } + #[inline] + pub fn has_resolved_env_vars(&self) -> bool { + !self.builder.is_pointer_field_null(9) + } + #[inline] + pub fn get_pass_thru_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(10), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_pass_thru_env( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(10), + value, + false, + ) + } + #[inline] + pub fn init_pass_thru_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(10), + size, + ) + } + #[inline] + pub fn has_pass_thru_env(&self) -> bool { + !self.builder.is_pointer_field_null(10) + } + #[inline] + pub fn get_env_mode( + self, + ) -> ::core::result::Result< + crate::hash::proto_capnp::task_hashable::EnvMode, + ::capnp::NotInSchema, + > { + ::core::convert::TryInto::try_into(self.builder.get_data_field::(0)) + } + #[inline] + pub fn set_env_mode(&mut self, value: crate::hash::proto_capnp::task_hashable::EnvMode) { + self.builder.set_data_field::(0, value as u16); + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline { + pub fn get_outputs(&self) -> crate::hash::proto_capnp::task_outputs::Pipeline { + ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(6)) + } + } + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 233] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(121, 228, 245, 78, 235, 156, 240, 225), + ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(11, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(22, 0, 0, 0, 197, 1, 0, 0), + ::capnp::word(21, 0, 0, 0, 18, 1, 0, 0), + ::capnp::word(37, 0, 0, 0, 23, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 0, 0, 0, 167, 2, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), + ::capnp::word(107, 72, 97, 115, 104, 97, 98, 108), + ::capnp::word(101, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(4, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), + ::capnp::word(1, 0, 0, 0, 66, 0, 0, 0), + ::capnp::word(69, 110, 118, 77, 111, 100, 101, 0), + ::capnp::word(48, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(65, 1, 0, 0, 90, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(64, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(76, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(73, 1, 0, 0, 170, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(76, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(104, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(2, 0, 0, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 1, 0, 0, 90, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(100, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(112, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(3, 0, 0, 0, 3, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 3, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(109, 1, 0, 0, 98, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(108, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(120, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(4, 0, 0, 0, 4, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 4, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(117, 1, 0, 0, 138, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(120, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(132, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(5, 0, 0, 0, 5, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 5, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(129, 1, 0, 0, 42, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(124, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(136, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(6, 0, 0, 0, 6, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 6, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(133, 1, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(128, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(140, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(7, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(137, 1, 0, 0, 106, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(136, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(164, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 8, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 8, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(161, 1, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(156, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(184, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(9, 0, 0, 0, 9, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 9, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(181, 1, 0, 0, 130, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(180, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(208, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(10, 0, 0, 0, 10, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 10, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(205, 1, 0, 0, 98, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(204, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(232, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(11, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 11, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(229, 1, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(224, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(236, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(103, 108, 111, 98, 97, 108, 72, 97), + ::capnp::word(115, 104, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(116, 97, 115, 107, 68, 101, 112, 101), + ::capnp::word(110, 100, 101, 110, 99, 121, 72, 97), + ::capnp::word(115, 104, 101, 115, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 97, 99, 107, 97, 103, 101, 68), + ::capnp::word(105, 114, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(104, 97, 115, 104, 79, 102, 70, 105), + ::capnp::word(108, 101, 115, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 120, 116, 101, 114, 110, 97, 108), + ::capnp::word(68, 101, 112, 115, 72, 97, 115, 104), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(116, 97, 115, 107, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(111, 117, 116, 112, 117, 116, 115, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(103, 162, 171, 232, 252, 0, 131, 213), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 97, 115, 115, 84, 104, 114, 117), + ::capnp::word(65, 114, 103, 115, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 110, 118, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(114, 101, 115, 111, 108, 118, 101, 100), + ::capnp::word(69, 110, 118, 86, 97, 114, 115, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 97, 115, 115, 84, 104, 114, 117), + ::capnp::word(69, 110, 118, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 110, 118, 77, 111, 100, 101, 0), + ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 2 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 3 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 4 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 5 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 6 => ::introspect(), + 7 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 8 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 9 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 10 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 11 => ::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xe1f0_9ceb_4ef5_e479; + } + + #[repr(u16)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum EnvMode { + Loose = 0, + Strict = 1, + } + + impl ::capnp::introspect::Introspect for EnvMode { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Enum(::capnp::introspect::RawEnumSchema { + encoded_node: &env_mode::ENCODED_NODE, + annotation_types: env_mode::get_annotation_types, + }) + .into() + } + } + impl<'a> ::core::convert::From for ::capnp::dynamic_value::Reader<'a> { + fn from(e: EnvMode) -> Self { + ::capnp::dynamic_value::Enum::new( + e.into(), + ::capnp::introspect::RawEnumSchema { + encoded_node: &env_mode::ENCODED_NODE, + annotation_types: env_mode::get_annotation_types, + } + .into(), + ) + .into() + } + } + impl ::core::convert::TryFrom for EnvMode { + type Error = ::capnp::NotInSchema; + fn try_from( + value: u16, + ) -> ::core::result::Result>::Error> + { + match value { + 0 => ::core::result::Result::Ok(Self::Loose), + 1 => ::core::result::Result::Ok(Self::Strict), + n => ::core::result::Result::Err(::capnp::NotInSchema(n)), + } + } + } + impl From for u16 { + #[inline] + fn from(x: EnvMode) -> u16 { + x as u16 + } + } + impl ::capnp::traits::HasTypeId for EnvMode { + const TYPE_ID: u64 = 0x8dc0_8a1d_29f6_9b16u64; + } + mod env_mode { + pub static ENCODED_NODE: [::capnp::Word; 29] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), + ::capnp::word(34, 0, 0, 0, 2, 0, 0, 0), + ::capnp::word(121, 228, 245, 78, 235, 156, 240, 225), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(142, 1, 0, 0, 195, 1, 0, 0), + ::capnp::word(21, 0, 0, 0, 82, 1, 0, 0), + ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(37, 0, 0, 0, 55, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), + ::capnp::word(107, 72, 97, 115, 104, 97, 98, 108), + ::capnp::word(101, 46, 69, 110, 118, 77, 111, 100), + ::capnp::word(101, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 1, 0, 2, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(17, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(9, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(108, 111, 111, 115, 101, 0, 0, 0), + ::capnp::word(115, 116, 114, 105, 99, 116, 0, 0), + ]; + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + } +} + +pub mod task_outputs { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_inclusions(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_inclusions(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_exclusions(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_exclusions(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_inclusions(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_inclusions( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_inclusions(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) + } + #[inline] + pub fn has_inclusions(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_exclusions(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_exclusions( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + } + #[inline] + pub fn init_exclusions(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(1), + size, + ) + } + #[inline] + pub fn has_exclusions(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 60] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(103, 162, 171, 232, 252, 0, 131, 213), + ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(199, 1, 0, 0, 24, 2, 0, 0), + ::capnp::word(21, 0, 0, 0, 10, 1, 0, 0), + ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(33, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), + ::capnp::word(107, 79, 117, 116, 112, 117, 116, 115), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 90, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(68, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(65, 0, 0, 0, 90, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(64, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(92, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(105, 110, 99, 108, 117, 115, 105, 111), + ::capnp::word(110, 115, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 120, 99, 108, 117, 115, 105, 111), + ::capnp::word(110, 115, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xd583_00fc_e8ab_a267; + } +} + +pub mod global_hashable { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_global_cache_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_global_cache_key(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_global_file_hash_map( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Reader< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + > { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_global_file_hash_map(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + #[inline] + pub fn get_root_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(2), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_root_external_deps_hash(&self) -> bool { + !self.reader.get_pointer_field(2).is_null() + } + #[inline] + pub fn get_root_internal_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(3), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_root_internal_deps_hash(&self) -> bool { + !self.reader.get_pointer_field(3).is_null() + } + #[inline] + pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(4), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_env(&self) -> bool { + !self.reader.get_pointer_field(4).is_null() + } + #[inline] + pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(5), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_resolved_env_vars(&self) -> bool { + !self.reader.get_pointer_field(5).is_null() + } + #[inline] + pub fn get_pass_through_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(6), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_pass_through_env(&self) -> bool { + !self.reader.get_pointer_field(6).is_null() + } + #[inline] + pub fn get_env_mode( + self, + ) -> ::core::result::Result< + crate::hash::proto_capnp::global_hashable::EnvMode, + ::capnp::NotInSchema, + > { + ::core::convert::TryInto::try_into(self.reader.get_data_field::(0)) + } + #[inline] + pub fn get_framework_inference(self) -> bool { + self.reader.get_bool_field(16) + } + #[inline] + pub fn get_engines( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Reader< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + > { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(7), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_engines(&self) -> bool { + !self.reader.get_pointer_field(7).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 1, + pointers: 8, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_global_cache_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_global_cache_key(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_global_cache_key(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_global_cache_key(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_global_file_hash_map( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Builder< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + > { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_global_file_hash_map( + &mut self, + value: ::capnp::struct_list::Reader< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(1), + value, + false, + ) + } + #[inline] + pub fn init_global_file_hash_map( + self, + size: u32, + ) -> ::capnp::struct_list::Builder< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + > { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(1), + size, + ) + } + #[inline] + pub fn has_global_file_hash_map(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + #[inline] + pub fn get_root_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(2), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_root_external_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(2).set_text(value); + } + #[inline] + pub fn init_root_external_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(2).init_text(size) + } + #[inline] + pub fn has_root_external_deps_hash(&self) -> bool { + !self.builder.is_pointer_field_null(2) + } + #[inline] + pub fn get_root_internal_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(3), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_root_internal_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(3).set_text(value); + } + #[inline] + pub fn init_root_internal_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(3).init_text(size) + } + #[inline] + pub fn has_root_internal_deps_hash(&self) -> bool { + !self.builder.is_pointer_field_null(3) + } + #[inline] + pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(4), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_env(&mut self, value: ::capnp::text_list::Reader<'a>) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(4), + value, + false, + ) + } + #[inline] + pub fn init_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(4), + size, + ) + } + #[inline] + pub fn has_env(&self) -> bool { + !self.builder.is_pointer_field_null(4) + } + #[inline] + pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(5), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_resolved_env_vars( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(5), + value, + false, + ) + } + #[inline] + pub fn init_resolved_env_vars(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(5), + size, + ) + } + #[inline] + pub fn has_resolved_env_vars(&self) -> bool { + !self.builder.is_pointer_field_null(5) + } + #[inline] + pub fn get_pass_through_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(6), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_pass_through_env( + &mut self, + value: ::capnp::text_list::Reader<'a>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(6), + value, + false, + ) + } + #[inline] + pub fn init_pass_through_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(6), + size, + ) + } + #[inline] + pub fn has_pass_through_env(&self) -> bool { + !self.builder.is_pointer_field_null(6) + } + #[inline] + pub fn get_env_mode( + self, + ) -> ::core::result::Result< + crate::hash::proto_capnp::global_hashable::EnvMode, + ::capnp::NotInSchema, + > { + ::core::convert::TryInto::try_into(self.builder.get_data_field::(0)) + } + #[inline] + pub fn set_env_mode(&mut self, value: crate::hash::proto_capnp::global_hashable::EnvMode) { + self.builder.set_data_field::(0, value as u16); + } + #[inline] + pub fn get_framework_inference(self) -> bool { + self.builder.get_bool_field(16) + } + #[inline] + pub fn set_framework_inference(&mut self, value: bool) { + self.builder.set_bool_field(16, value); + } + #[inline] + pub fn get_engines( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Builder< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + > { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(7), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_engines( + &mut self, + value: ::capnp::struct_list::Reader< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + >, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(7), + value, + false, + ) + } + #[inline] + pub fn init_engines( + self, + size: u32, + ) -> ::capnp::struct_list::Builder< + 'a, + crate::hash::proto_capnp::global_hashable::entry::Owned, + > { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(7), + size, + ) + } + #[inline] + pub fn has_engines(&self) -> bool { + !self.builder.is_pointer_field_null(7) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 207] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), + ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(8, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(26, 2, 0, 0, 207, 3, 0, 0), + ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), + ::capnp::word(37, 0, 0, 0, 39, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(57, 0, 0, 0, 55, 2, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), + ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), + ::capnp::word(98, 108, 101, 0, 0, 0, 0, 0), + ::capnp::word(8, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), + ::capnp::word(9, 0, 0, 0, 66, 0, 0, 0), + ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), + ::capnp::word(5, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(69, 110, 118, 77, 111, 100, 101, 0), + ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(9, 1, 0, 0, 122, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(8, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(20, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(17, 1, 0, 0, 146, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(20, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(48, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(2, 0, 0, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 1, 0, 0, 170, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(48, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(60, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(3, 0, 0, 0, 3, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 3, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(57, 1, 0, 0, 170, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(60, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(72, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(4, 0, 0, 0, 4, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 4, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(69, 1, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(64, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(92, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(5, 0, 0, 0, 5, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 5, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(89, 1, 0, 0, 130, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(88, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(116, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(6, 0, 0, 0, 6, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 6, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(113, 1, 0, 0, 122, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(140, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(7, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(137, 1, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(132, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(144, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 16, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 8, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(141, 1, 0, 0, 154, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(144, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(156, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(9, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 9, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(153, 1, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(148, 1, 0, 0, 3, 0, 1, 0), + ::capnp::word(176, 1, 0, 0, 2, 0, 1, 0), + ::capnp::word(103, 108, 111, 98, 97, 108, 67, 97), + ::capnp::word(99, 104, 101, 75, 101, 121, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(103, 108, 111, 98, 97, 108, 70, 105), + ::capnp::word(108, 101, 72, 97, 115, 104, 77, 97), + ::capnp::word(112, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(114, 111, 111, 116, 69, 120, 116, 101), + ::capnp::word(114, 110, 97, 108, 68, 101, 112, 115), + ::capnp::word(72, 97, 115, 104, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(114, 111, 111, 116, 73, 110, 116, 101), + ::capnp::word(114, 110, 97, 108, 68, 101, 112, 115), + ::capnp::word(72, 97, 115, 104, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 110, 118, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(114, 101, 115, 111, 108, 118, 101, 100), + ::capnp::word(69, 110, 118, 86, 97, 114, 115, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(112, 97, 115, 115, 84, 104, 114, 111), + ::capnp::word(117, 103, 104, 69, 110, 118, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 110, 118, 77, 111, 100, 101, 0), + ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(102, 114, 97, 109, 101, 119, 111, 114), + ::capnp::word(107, 73, 110, 102, 101, 114, 101, 110), + ::capnp::word(99, 101, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(101, 110, 103, 105, 110, 101, 115, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 2 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 3 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 4 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 5 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 6 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), + 7 => ::introspect(), + 8 => ::introspect(), + 9 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xea0b_3688_577e_30b4; + } + + #[repr(u16)] + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub enum EnvMode { + Loose = 0, + Strict = 1, + } + + impl ::capnp::introspect::Introspect for EnvMode { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Enum(::capnp::introspect::RawEnumSchema { + encoded_node: &env_mode::ENCODED_NODE, + annotation_types: env_mode::get_annotation_types, + }) + .into() + } + } + impl<'a> ::core::convert::From for ::capnp::dynamic_value::Reader<'a> { + fn from(e: EnvMode) -> Self { + ::capnp::dynamic_value::Enum::new( + e.into(), + ::capnp::introspect::RawEnumSchema { + encoded_node: &env_mode::ENCODED_NODE, + annotation_types: env_mode::get_annotation_types, + } + .into(), + ) + .into() + } + } + impl ::core::convert::TryFrom for EnvMode { + type Error = ::capnp::NotInSchema; + fn try_from( + value: u16, + ) -> ::core::result::Result>::Error> + { + match value { + 0 => ::core::result::Result::Ok(Self::Loose), + 1 => ::core::result::Result::Ok(Self::Strict), + n => ::core::result::Result::Err(::capnp::NotInSchema(n)), + } + } + } + impl From for u16 { + #[inline] + fn from(x: EnvMode) -> u16 { + x as u16 + } + } + impl ::capnp::traits::HasTypeId for EnvMode { + const TYPE_ID: u64 = 0xab42_00df_8263_c5d4u64; + } + mod env_mode { + pub static ENCODED_NODE: [::capnp::Word; 29] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), + ::capnp::word(36, 0, 0, 0, 2, 0, 0, 0), + ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(98, 3, 0, 0, 145, 3, 0, 0), + ::capnp::word(21, 0, 0, 0, 98, 1, 0, 0), + ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(37, 0, 0, 0, 55, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), + ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), + ::capnp::word(98, 108, 101, 46, 69, 110, 118, 77), + ::capnp::word(111, 100, 101, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 1, 0, 2, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(17, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(9, 0, 0, 0, 58, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(108, 111, 111, 115, 101, 0, 0, 0), + ::capnp::word(115, 116, 114, 105, 99, 116, 0, 0), + ]; + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + } + + pub mod entry { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_value(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + _size: u32, + ) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_value(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_value(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(1).set_text(value); + } + #[inline] + pub fn init_value(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(1).init_text(size) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 51] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), + ::capnp::word(36, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(149, 3, 0, 0, 205, 3, 0, 0), + ::capnp::word(21, 0, 0, 0, 82, 1, 0, 0), + ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(37, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), + ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), + ::capnp::word(98, 108, 101, 46, 69, 110, 116, 114), + ::capnp::word(121, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xdd6c_3d39_4436_cf49; + } + } +} + +pub mod lock_file_packages { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_packages( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::package::Owned>, + > { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_packages(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 1, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_packages( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::package::Owned>, + > { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_packages( + &mut self, + value: ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::package::Owned>, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_packages( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::package::Owned> { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) + } + #[inline] + pub fn has_packages(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 40] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(5, 35, 145, 20, 154, 180, 112, 180), + ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(209, 3, 0, 0, 10, 4, 0, 0), + ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), + ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(33, 0, 0, 0, 63, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 76, 111, 99), + ::capnp::word(107, 70, 105, 108, 101, 80, 97, 99), + ::capnp::word(107, 97, 103, 101, 115, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(4, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(13, 0, 0, 0, 74, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(40, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(112, 97, 99, 107, 97, 103, 101, 115), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(120, 27, 143, 105, 53, 137, 208, 194), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xb470_b49a_1491_2305; + } +} + +pub mod package { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_version(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_version(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + #[inline] + pub fn get_found(self) -> bool { + self.reader.get_bool_field(0) + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 1, + pointers: 2, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_version(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_version(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(1).set_text(value); + } + #[inline] + pub fn init_version(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(1).init_text(size) + } + #[inline] + pub fn has_version(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + #[inline] + pub fn get_found(self) -> bool { + self.builder.get_bool_field(0) + } + #[inline] + pub fn set_found(&mut self, value: bool) { + self.builder.set_bool_field(0, value); + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 64] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(120, 27, 143, 105, 53, 137, 208, 194), + ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 4, 0, 0, 84, 4, 0, 0), + ::capnp::word(21, 0, 0, 0, 234, 0, 0, 0), + ::capnp::word(33, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(29, 0, 0, 0, 175, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 80, 97, 99), + ::capnp::word(107, 97, 103, 101, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(12, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(69, 0, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(64, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(76, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(73, 0, 0, 0, 66, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(68, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(80, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(2, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(77, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(72, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(84, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(118, 101, 114, 115, 105, 111, 110, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(102, 111, 117, 110, 100, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 2 => ::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xc2d0_8935_698f_1b78; + } +} + +pub mod file_hashes { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_file_hashes( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::file_hashes::entry::Owned>, + > { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_file_hashes(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 1, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_file_hashes( + self, + ) -> ::capnp::Result< + ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::file_hashes::entry::Owned>, + > { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_file_hashes( + &mut self, + value: ::capnp::struct_list::Reader< + 'a, + crate::hash::proto_capnp::file_hashes::entry::Owned, + >, + ) -> ::capnp::Result<()> { + ::capnp::traits::SetPointerBuilder::set_pointer_builder( + self.builder.reborrow().get_pointer_field(0), + value, + false, + ) + } + #[inline] + pub fn init_file_hashes( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::file_hashes::entry::Owned> + { + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) + } + #[inline] + pub fn has_file_hashes(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 42] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(143, 27, 194, 114, 193, 13, 17, 237), + ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), + ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(86, 4, 0, 0, 197, 4, 0, 0), + ::capnp::word(21, 0, 0, 0, 2, 1, 0, 0), + ::capnp::word(33, 0, 0, 0, 23, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 63, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 70, 105, 108), + ::capnp::word(101, 72, 97, 115, 104, 101, 115, 0), + ::capnp::word(4, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), + ::capnp::word(1, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), + ::capnp::word(4, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(13, 0, 0, 0, 90, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(40, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(102, 105, 108, 101, 72, 97, 115, 104), + ::capnp::word(101, 115, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::struct_list::Owned< + crate::hash::proto_capnp::file_hashes::entry::Owned, + > as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0xed11_0dc1_72c2_1b8f; + } + + pub mod entry { + #[derive(Copy, Clone)] + pub struct Owned(()); + impl ::capnp::introspect::Introspect for Owned { + fn introspect() -> ::capnp::introspect::Type { + ::capnp::introspect::TypeVariant::Struct( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ) + .into() + } + } + impl ::capnp::traits::Owned for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::OwnedStruct for Owned { + type Reader<'a> = Reader<'a>; + type Builder<'a> = Builder<'a>; + } + impl ::capnp::traits::Pipelined for Owned { + type Pipeline = Pipeline; + } + + pub struct Reader<'a> { + reader: ::capnp::private::layout::StructReader<'a>, + } + impl<'a> ::core::marker::Copy for Reader<'a> {} + impl<'a> ::core::clone::Clone for Reader<'a> { + fn clone(&self) -> Self { + *self + } + } + + impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { + fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { + Self { reader } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { + fn from(reader: Reader<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Reader::new( + reader.reader, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::core::fmt::Debug for Reader<'a> { + fn fmt( + &self, + f: &mut ::core::fmt::Formatter<'_>, + ) -> ::core::result::Result<(), ::core::fmt::Error> { + core::fmt::Debug::fmt( + &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), + f, + ) + } + } + + impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { + fn get_from_pointer( + reader: &::capnp::private::layout::PointerReader<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok(reader.get_struct(default)?.into()) + } + } + + impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { + fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { + self.reader + } + } + + impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { + fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { + self.reader + .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) + } + } + + impl<'a> Reader<'a> { + pub fn reborrow(&self) -> Reader<'_> { + Self { ..*self } + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.reader.total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.reader.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_value(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.reader.get_pointer_field(1).is_null() + } + } + + pub struct Builder<'a> { + builder: ::capnp::private::layout::StructBuilder<'a>, + } + impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { + const STRUCT_SIZE: ::capnp::private::layout::StructSize = + ::capnp::private::layout::StructSize { + data: 0, + pointers: 2, + }; + } + impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { + const TYPE_ID: u64 = _private::TYPE_ID; + } + impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { + fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { + Self { builder } + } + } + + impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { + fn from(builder: Builder<'a>) -> Self { + Self::Struct(::capnp::dynamic_struct::Builder::new( + builder.builder, + ::capnp::schema::StructSchema::new( + ::capnp::introspect::RawBrandedStructSchema { + generic: &_private::RAW_SCHEMA, + field_types: _private::get_field_types, + annotation_types: _private::get_annotation_types, + }, + ), + )) + } + } + + impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { + fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { + self.builder + .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) + } + } + + impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { + fn init_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + _size: u32, + ) -> Self { + builder + .init_struct(::STRUCT_SIZE) + .into() + } + fn get_from_pointer( + builder: ::capnp::private::layout::PointerBuilder<'a>, + default: ::core::option::Option<&'a [::capnp::Word]>, + ) -> ::capnp::Result { + ::core::result::Result::Ok( + builder + .get_struct( + ::STRUCT_SIZE, + default, + )? + .into(), + ) + } + } + + impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { + fn set_pointer_builder( + mut pointer: ::capnp::private::layout::PointerBuilder<'_>, + value: Self, + canonicalize: bool, + ) -> ::capnp::Result<()> { + pointer.set_struct(&value.reader, canonicalize) + } + } + + impl<'a> Builder<'a> { + pub fn into_reader(self) -> Reader<'a> { + self.builder.into_reader().into() + } + pub fn reborrow(&mut self) -> Builder<'_> { + Builder { + builder: self.builder.reborrow(), + } + } + pub fn reborrow_as_reader(&self) -> Reader<'_> { + self.builder.as_reader().into() + } + + pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { + self.builder.as_reader().total_size() + } + #[inline] + pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(0), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + #[inline] + pub fn has_key(&self) -> bool { + !self.builder.is_pointer_field_null(0) + } + #[inline] + pub fn get_value(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] + pub fn set_value(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.reborrow().get_pointer_field(1).set_text(value); + } + #[inline] + pub fn init_value(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(1).init_text(size) + } + #[inline] + pub fn has_value(&self) -> bool { + !self.builder.is_pointer_field_null(1) + } + } + + pub struct Pipeline { + _typeless: ::capnp::any_pointer::Pipeline, + } + impl ::capnp::capability::FromTypelessPipeline for Pipeline { + fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { + Self { + _typeless: typeless, + } + } + } + impl Pipeline {} + mod _private { + pub static ENCODED_NODE: [::capnp::Word; 50] = [ + ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), + ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), + ::capnp::word(32, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(143, 27, 194, 114, 193, 13, 17, 237), + ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(139, 4, 0, 0, 195, 4, 0, 0), + ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), + ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(33, 0, 0, 0, 119, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), + ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), + ::capnp::word(97, 112, 110, 112, 58, 70, 105, 108), + ::capnp::word(101, 72, 97, 115, 104, 101, 115, 46), + ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), + ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(41, 0, 0, 0, 34, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(45, 0, 0, 0, 50, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), + ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), + ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), + ]; + pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { + match index { + 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), + _ => panic!("invalid field index {}", index), + } + } + pub fn get_annotation_types( + child_index: Option, + index: u32, + ) -> ::capnp::introspect::Type { + panic!("invalid annotation indices ({:?}, {}) ", child_index, index) + } + pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = + ::capnp::introspect::RawStructSchema { + encoded_node: &ENCODED_NODE, + nonunion_members: NONUNION_MEMBERS, + members_by_discriminant: MEMBERS_BY_DISCRIMINANT, + }; + pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; + pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; + pub const TYPE_ID: u64 = 0x8932_f743_3db8_9d99; + } + } +} diff --git a/crates/turborepo-lib/src/observability/otel.rs b/crates/turborepo-lib/src/observability/otel.rs index 3c7e6044a0ee2..17ed0e0cf13d2 100644 --- a/crates/turborepo-lib/src/observability/otel.rs +++ b/crates/turborepo-lib/src/observability/otel.rs @@ -155,3 +155,129 @@ fn build_task_payload(task: &TaskSummary) -> TaskMetricsPayload { exit_code, } } + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use super::*; + + #[test] + fn test_config_from_options_enabled_false() { + let mut options = ExperimentalOtelOptions::default(); + options.enabled = Some(false); + let result = config_from_options(&options); + assert!(result.is_none()); + } + + #[test] + fn test_config_from_options_no_endpoint() { + let options = ExperimentalOtelOptions::default(); + let result = config_from_options(&options); + assert!(result.is_none()); + } + + #[test] + fn test_config_from_options_empty_endpoint() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some(" ".to_string()); + let result = config_from_options(&options); + assert!(result.is_none()); + } + + #[test] + fn test_config_from_options_defaults() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some("https://example.com/otel".to_string()); + let result = config_from_options(&options); + assert!(result.is_some()); + let config = result.unwrap(); + assert_eq!(config.endpoint, "https://example.com/otel"); + assert_eq!(config.protocol, turborepo_otel::Protocol::Grpc); + assert_eq!(config.timeout.as_millis(), 10_000); + assert_eq!(config.metrics.run_summary, true); + assert_eq!(config.metrics.task_details, false); + } + + #[test] + fn test_config_from_options_http_protobuf() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some("https://example.com/otel".to_string()); + options.protocol = Some(ExperimentalOtelProtocol::HttpProtobuf); + let result = config_from_options(&options); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + turborepo_otel::Protocol::HttpProtobuf + ); + } + + #[test] + fn test_config_from_options_custom_timeout() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some("https://example.com/otel".to_string()); + options.timeout_ms = Some(15000); + let result = config_from_options(&options); + assert!(result.is_some()); + assert_eq!(result.unwrap().timeout.as_millis(), 15_000); + } + + #[test] + fn test_config_from_options_headers() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some("https://example.com/otel".to_string()); + let mut headers = BTreeMap::new(); + headers.insert("auth".to_string(), "token123".to_string()); + options.headers = Some(headers); + let result = config_from_options(&options); + assert!(result.is_some()); + let config = result.unwrap(); + assert_eq!(config.headers.get("auth"), Some(&"token123".to_string())); + } + + #[test] + fn test_config_from_options_resource() { + let mut options = ExperimentalOtelOptions::default(); + options.endpoint = Some("https://example.com/otel".to_string()); + let mut resource = BTreeMap::new(); + resource.insert("service.name".to_string(), "my-service".to_string()); + resource.insert("env".to_string(), "production".to_string()); + options.resource = Some(resource); + let result = config_from_options(&options); + assert!(result.is_some()); + let config = result.unwrap(); + assert_eq!( + config.resource_attributes.get("service.name"), + Some(&"my-service".to_string()) + ); + assert_eq!( + config.resource_attributes.get("env"), + Some(&"production".to_string()) + ); + } + + #[test] + fn test_metrics_config_defaults() { + let result = metrics_config(None); + assert_eq!(result.run_summary, true); + assert_eq!(result.task_details, false); + } + + #[test] + fn test_metrics_config_run_summary_override() { + let mut metrics = ExperimentalOtelMetricsOptions::default(); + metrics.run_summary = Some(false); + let result = metrics_config(Some(&metrics)); + assert_eq!(result.run_summary, false); + assert_eq!(result.task_details, false); + } + + #[test] + fn test_metrics_config_task_details_override() { + let mut metrics = ExperimentalOtelMetricsOptions::default(); + metrics.task_details = Some(true); + let result = metrics_config(Some(&metrics)); + assert_eq!(result.run_summary, true); + assert_eq!(result.task_details, true); + } +} diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml index c61ee8ac89d23..23fb53111d8ad 100644 --- a/crates/turborepo-otel/Cargo.toml +++ b/crates/turborepo-otel/Cargo.toml @@ -2,6 +2,7 @@ name = "turborepo-otel" version = "0.1.0" edition = "2024" +license = "MIT" [dependencies] opentelemetry = { version = "0.23", features = ["metrics"] } diff --git a/crates/turborepo-otel/src/lib.rs b/crates/turborepo-otel/src/lib.rs index c8195dd2af9e8..c5ad13acdb4bb 100644 --- a/crates/turborepo-otel/src/lib.rs +++ b/crates/turborepo-otel/src/lib.rs @@ -371,3 +371,189 @@ fn build_run_attributes(payload: &RunMetricsPayload) -> Vec { } attrs } + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use super::*; + + #[test] + fn test_handle_try_new_empty_endpoint() { + let config = Config { + endpoint: "".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: BTreeMap::new(), + metrics: MetricsConfig::default(), + }; + let result = Handle::try_new(config); + assert!(result.is_err()); + match result.unwrap_err() { + Error::MissingEndpoint => {} + _ => panic!("Expected MissingEndpoint error"), + } + } + + #[test] + fn test_handle_try_new_whitespace_endpoint() { + let config = Config { + endpoint: " ".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: BTreeMap::new(), + metrics: MetricsConfig::default(), + }; + let result = Handle::try_new(config); + assert!(result.is_err()); + match result.unwrap_err() { + Error::MissingEndpoint => {} + _ => panic!("Expected MissingEndpoint error"), + } + } + + #[test] + fn test_build_metadata_valid() { + let mut headers = BTreeMap::new(); + headers.insert("authorization".to_string(), "Bearer token123".to_string()); + headers.insert("x-custom-header".to_string(), "value".to_string()); + + let result = build_metadata(&headers); + assert!(result.is_ok()); + let metadata = result.unwrap(); + assert_eq!(metadata.len(), 2); + } + + #[test] + fn test_build_metadata_invalid_key() { + let mut headers = BTreeMap::new(); + headers.insert("\0invalid".to_string(), "value".to_string()); + + let result = build_metadata(&headers); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidHeader(key) => { + assert_eq!(key, "\0invalid"); + } + _ => panic!("Expected InvalidHeader error"), + } + } + + #[test] + fn test_build_metadata_invalid_value() { + let mut headers = BTreeMap::new(); + headers.insert("valid-key".to_string(), "\0invalid-value".to_string()); + + let result = build_metadata(&headers); + assert!(result.is_err()); + match result.unwrap_err() { + Error::InvalidHeader(key) => { + assert_eq!(key, "valid-key"); + } + _ => panic!("Expected InvalidHeader error"), + } + } + + #[test] + fn test_build_resource_default_service_name() { + let config = Config { + endpoint: "https://example.com".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: BTreeMap::new(), + metrics: MetricsConfig::default(), + }; + let resource = build_resource(&config); + let attrs: Vec<_> = resource + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + assert!( + attrs + .iter() + .any(|(k, v)| *k == SERVICE_NAME && *v == "turborepo") + ); + } + + #[test] + fn test_build_resource_custom_service_name() { + let mut resource_attrs = BTreeMap::new(); + resource_attrs.insert("service.name".to_string(), "my-service".to_string()); + let config = Config { + endpoint: "https://example.com".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: resource_attrs, + metrics: MetricsConfig::default(), + }; + let resource = build_resource(&config); + let attrs: Vec<_> = resource + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + assert!( + attrs + .iter() + .any(|(k, v)| *k == SERVICE_NAME && *v == "my-service") + ); + } + + #[test] + fn test_build_resource_additional_attributes() { + let mut resource_attrs = BTreeMap::new(); + resource_attrs.insert("env".to_string(), "production".to_string()); + resource_attrs.insert("version".to_string(), "1.0.0".to_string()); + let config = Config { + endpoint: "https://example.com".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: resource_attrs, + metrics: MetricsConfig::default(), + }; + let resource = build_resource(&config); + let attrs: Vec<_> = resource + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + assert_eq!(attrs.len(), 3); + assert!( + attrs + .iter() + .any(|(k, v)| *k == SERVICE_NAME && *v == "turborepo") + ); + assert!(attrs.iter().any(|(k, v)| *k == "env" && *v == "production")); + assert!(attrs.iter().any(|(k, v)| *k == "version" && *v == "1.0.0")); + } + + #[test] + fn test_build_resource_no_duplicate_service_name() { + let mut resource_attrs = BTreeMap::new(); + resource_attrs.insert("service.name".to_string(), "custom".to_string()); + resource_attrs.insert("env".to_string(), "production".to_string()); + let config = Config { + endpoint: "https://example.com".to_string(), + protocol: Protocol::Grpc, + headers: BTreeMap::new(), + timeout: Duration::from_secs(10), + resource_attributes: resource_attrs, + metrics: MetricsConfig::default(), + }; + let resource = build_resource(&config); + let attrs: Vec<_> = resource + .iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect(); + let service_name_count = attrs.iter().filter(|(k, _)| *k == SERVICE_NAME).count(); + assert_eq!(service_name_count, 1); + assert!( + attrs + .iter() + .any(|(k, v)| *k == SERVICE_NAME && *v == "custom") + ); + } +} diff --git a/turborepo-tests/integration/tests/other/experimental-otel.t b/turborepo-tests/integration/tests/other/experimental-otel.t new file mode 100644 index 0000000000000..5731bf52efdf3 --- /dev/null +++ b/turborepo-tests/integration/tests/other/experimental-otel.t @@ -0,0 +1,36 @@ +Setup + $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh + +Test that OTEL exporter can be enabled via environment variables + $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 + $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 + $ ${TURBO} run build --filter=my-app + .*build.*my-app (re) + [0] + +Test that OTEL exporter can be enabled via CLI flags + $ unset TURBO_EXPERIMENTAL_OTEL_ENABLED + $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT + $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 + .*build.*my-app (re) + [0] + +Test that OTEL exporter works with http/protobuf protocol + $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 --experimental-otel-protocol=http-protobuf + .*build.*my-app (re) + [0] + +Test that OTEL exporter can be disabled via environment variable + $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=0 + $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 + $ ${TURBO} run build --filter=my-app + .*build.*my-app (re) + [0] + +Test that OTEL exporter requires endpoint when enabled + $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 + $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT + $ ${TURBO} run build --filter=my-app + .*build.*my-app (re) + [0] + From 5f1a7d1e7a08301644f8860978639e2e25765004 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:02:47 -0700 Subject: [PATCH 06/29] Formatting fixes --- crates/turborepo-lib/src/cli/error.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/turborepo-lib/src/cli/error.rs b/crates/turborepo-lib/src/cli/error.rs index 1241d09168062..833aee28e6767 100644 --- a/crates/turborepo-lib/src/cli/error.rs +++ b/crates/turborepo-lib/src/cli/error.rs @@ -4,12 +4,12 @@ use itertools::Itertools; use miette::Diagnostic; use thiserror::Error; use turborepo_repository::package_graph; -use turborepo_signals::{listeners::get_signal, SignalHandler}; +use turborepo_signals::{SignalHandler, listeners::get_signal}; use turborepo_telemetry::events::command::CommandEventBuilder; -use turborepo_ui::{color, BOLD, GREY}; +use turborepo_ui::{BOLD, GREY, color}; use crate::{ - commands::{bin, generate, get_mfe_port, link, login, ls, prune, CommandBase}, + commands::{CommandBase, bin, generate, get_mfe_port, link, login, ls, prune}, daemon::DaemonError, query, rewrite_json::RewriteError, From 5c715698bc1807322b277054ac8a4562f04663bb Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:09:11 -0700 Subject: [PATCH 07/29] More linting and formatting fixes --- crates/turborepo-lib/src/cli/mod.rs | 117 +++++++++++------- .../turborepo-lib/src/observability/otel.rs | 78 +++++++----- 2 files changed, 118 insertions(+), 77 deletions(-) diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 150ee16935af4..4980a69d07b18 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -1859,10 +1859,7 @@ mod test { use pretty_assertions::assert_eq; use super::{ExperimentalOtelCliArgs, ExperimentalOtelProtocol}; - use crate::{ - cli::{ContinueMode, ExecutionArgs, LinkTarget, RunArgs}, - config::ExperimentalOtelOptions, - }; + use crate::cli::{ContinueMode, ExecutionArgs, LinkTarget, RunArgs}; struct CommandTestCase { command: &'static str, @@ -3511,8 +3508,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_enabled() { - let mut args = ExperimentalOtelCliArgs::default(); - args.enabled = Some(true); + let args = ExperimentalOtelCliArgs { + enabled: Some(true), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); assert_eq!(result.unwrap().enabled, Some(true)); @@ -3520,8 +3519,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_protocol() { - let mut args = ExperimentalOtelCliArgs::default(); - args.protocol = Some(ExperimentalOtelProtocol::Grpc); + let args = ExperimentalOtelCliArgs { + protocol: Some(ExperimentalOtelProtocol::Grpc), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); assert_eq!( @@ -3532,8 +3533,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_protocol_http_protobuf() { - let mut args = ExperimentalOtelCliArgs::default(); - args.protocol = Some(ExperimentalOtelProtocol::HttpProtobuf); + let args = ExperimentalOtelCliArgs { + protocol: Some(ExperimentalOtelProtocol::HttpProtobuf), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); assert_eq!( @@ -3544,8 +3547,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_endpoint() { - let mut args = ExperimentalOtelCliArgs::default(); - args.endpoint = Some("https://example.com/otel".to_string()); + let args = ExperimentalOtelCliArgs { + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); assert_eq!( @@ -3556,8 +3561,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_timeout_ms() { - let mut args = ExperimentalOtelCliArgs::default(); - args.timeout_ms = Some(5000); + let args = ExperimentalOtelCliArgs { + timeout_ms: Some(5000), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); assert_eq!(result.unwrap().timeout_ms, Some(5000)); @@ -3565,8 +3572,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_headers_single() { - let mut args = ExperimentalOtelCliArgs::default(); - args.headers = vec![("key1".to_string(), "value1".to_string())]; + let args = ExperimentalOtelCliArgs { + headers: vec![("key1".to_string(), "value1".to_string())], + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let headers = result.unwrap().headers.unwrap(); @@ -3575,11 +3584,13 @@ mod test { #[test] fn test_experimental_otel_cli_args_headers_multiple() { - let mut args = ExperimentalOtelCliArgs::default(); - args.headers = vec![ - ("key1".to_string(), "value1".to_string()), - ("key2".to_string(), "value2".to_string()), - ]; + let args = ExperimentalOtelCliArgs { + headers: vec![ + ("key1".to_string(), "value1".to_string()), + ("key2".to_string(), "value2".to_string()), + ], + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let headers = result.unwrap().headers.unwrap(); @@ -3589,16 +3600,20 @@ mod test { #[test] fn test_experimental_otel_cli_args_headers_empty() { - let mut args = ExperimentalOtelCliArgs::default(); - args.headers = vec![]; + let args = ExperimentalOtelCliArgs { + headers: vec![], + ..Default::default() + }; let result = args.to_config(); assert_eq!(result, None); } #[test] fn test_experimental_otel_cli_args_resource_single() { - let mut args = ExperimentalOtelCliArgs::default(); - args.resource_attributes = vec![("service.name".to_string(), "my-service".to_string())]; + let args = ExperimentalOtelCliArgs { + resource_attributes: vec![("service.name".to_string(), "my-service".to_string())], + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let resource = result.unwrap().resource.unwrap(); @@ -3610,11 +3625,13 @@ mod test { #[test] fn test_experimental_otel_cli_args_resource_multiple() { - let mut args = ExperimentalOtelCliArgs::default(); - args.resource_attributes = vec![ - ("service.name".to_string(), "my-service".to_string()), - ("env".to_string(), "production".to_string()), - ]; + let args = ExperimentalOtelCliArgs { + resource_attributes: vec![ + ("service.name".to_string(), "my-service".to_string()), + ("env".to_string(), "production".to_string()), + ], + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let resource = result.unwrap().resource.unwrap(); @@ -3627,8 +3644,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_metrics_run_summary() { - let mut args = ExperimentalOtelCliArgs::default(); - args.metrics_run_summary = Some(true); + let args = ExperimentalOtelCliArgs { + metrics_run_summary: Some(true), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let metrics = result.unwrap().metrics.unwrap(); @@ -3637,8 +3656,10 @@ mod test { #[test] fn test_experimental_otel_cli_args_metrics_task_details() { - let mut args = ExperimentalOtelCliArgs::default(); - args.metrics_task_details = Some(true); + let args = ExperimentalOtelCliArgs { + metrics_task_details: Some(true), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let metrics = result.unwrap().metrics.unwrap(); @@ -3647,9 +3668,11 @@ mod test { #[test] fn test_experimental_otel_cli_args_metrics_both() { - let mut args = ExperimentalOtelCliArgs::default(); - args.metrics_run_summary = Some(true); - args.metrics_task_details = Some(false); + let args = ExperimentalOtelCliArgs { + metrics_run_summary: Some(true), + metrics_task_details: Some(false), + ..Default::default() + }; let result = args.to_config(); assert!(result.is_some()); let metrics = result.unwrap().metrics.unwrap(); @@ -3659,16 +3682,16 @@ mod test { #[test] fn test_experimental_otel_cli_args_combined() { - let mut args = ExperimentalOtelCliArgs::default(); - args.enabled = Some(true); - args.protocol = Some(ExperimentalOtelProtocol::Grpc); - args.endpoint = Some("https://example.com/otel".to_string()); - args.timeout_ms = Some(15000); - args.headers = vec![("auth".to_string(), "token123".to_string())]; - args.resource_attributes = vec![("service.name".to_string(), "test".to_string())]; - args.metrics_run_summary = Some(true); - args.metrics_task_details = Some(false); - + let args = ExperimentalOtelCliArgs { + enabled: Some(true), + protocol: Some(ExperimentalOtelProtocol::Grpc), + endpoint: Some("https://example.com/otel".to_string()), + timeout_ms: Some(15000), + headers: vec![("auth".to_string(), "token123".to_string())], + resource_attributes: vec![("service.name".to_string(), "test".to_string())], + metrics_run_summary: Some(true), + metrics_task_details: Some(false), + }; let result = args.to_config(); assert!(result.is_some()); let opts = result.unwrap(); diff --git a/crates/turborepo-lib/src/observability/otel.rs b/crates/turborepo-lib/src/observability/otel.rs index 17ed0e0cf13d2..88093db0ed082 100644 --- a/crates/turborepo-lib/src/observability/otel.rs +++ b/crates/turborepo-lib/src/observability/otel.rs @@ -164,8 +164,10 @@ mod tests { #[test] fn test_config_from_options_enabled_false() { - let mut options = ExperimentalOtelOptions::default(); - options.enabled = Some(false); + let options = ExperimentalOtelOptions { + enabled: Some(false), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_none()); } @@ -179,31 +181,37 @@ mod tests { #[test] fn test_config_from_options_empty_endpoint() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some(" ".to_string()); + let options = ExperimentalOtelOptions { + endpoint: Some(" ".to_string()), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_none()); } #[test] fn test_config_from_options_defaults() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some("https://example.com/otel".to_string()); + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_some()); let config = result.unwrap(); assert_eq!(config.endpoint, "https://example.com/otel"); assert_eq!(config.protocol, turborepo_otel::Protocol::Grpc); assert_eq!(config.timeout.as_millis(), 10_000); - assert_eq!(config.metrics.run_summary, true); - assert_eq!(config.metrics.task_details, false); + assert!(config.metrics.run_summary); + assert!(!config.metrics.task_details); } #[test] fn test_config_from_options_http_protobuf() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some("https://example.com/otel".to_string()); - options.protocol = Some(ExperimentalOtelProtocol::HttpProtobuf); + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + protocol: Some(ExperimentalOtelProtocol::HttpProtobuf), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_some()); assert_eq!( @@ -214,9 +222,11 @@ mod tests { #[test] fn test_config_from_options_custom_timeout() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some("https://example.com/otel".to_string()); - options.timeout_ms = Some(15000); + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + timeout_ms: Some(15000), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_some()); assert_eq!(result.unwrap().timeout.as_millis(), 15_000); @@ -224,11 +234,13 @@ mod tests { #[test] fn test_config_from_options_headers() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some("https://example.com/otel".to_string()); let mut headers = BTreeMap::new(); headers.insert("auth".to_string(), "token123".to_string()); - options.headers = Some(headers); + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + headers: Some(headers), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_some()); let config = result.unwrap(); @@ -237,12 +249,14 @@ mod tests { #[test] fn test_config_from_options_resource() { - let mut options = ExperimentalOtelOptions::default(); - options.endpoint = Some("https://example.com/otel".to_string()); let mut resource = BTreeMap::new(); resource.insert("service.name".to_string(), "my-service".to_string()); resource.insert("env".to_string(), "production".to_string()); - options.resource = Some(resource); + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + resource: Some(resource), + ..Default::default() + }; let result = config_from_options(&options); assert!(result.is_some()); let config = result.unwrap(); @@ -259,25 +273,29 @@ mod tests { #[test] fn test_metrics_config_defaults() { let result = metrics_config(None); - assert_eq!(result.run_summary, true); - assert_eq!(result.task_details, false); + assert!(result.run_summary); + assert!(!result.task_details); } #[test] fn test_metrics_config_run_summary_override() { - let mut metrics = ExperimentalOtelMetricsOptions::default(); - metrics.run_summary = Some(false); + let metrics = ExperimentalOtelMetricsOptions { + run_summary: Some(false), + ..Default::default() + }; let result = metrics_config(Some(&metrics)); - assert_eq!(result.run_summary, false); - assert_eq!(result.task_details, false); + assert!(!result.run_summary); + assert!(!result.task_details); } #[test] fn test_metrics_config_task_details_override() { - let mut metrics = ExperimentalOtelMetricsOptions::default(); - metrics.task_details = Some(true); + let metrics = ExperimentalOtelMetricsOptions { + task_details: Some(true), + ..Default::default() + }; let result = metrics_config(Some(&metrics)); - assert_eq!(result.run_summary, true); - assert_eq!(result.task_details, true); + assert!(result.run_summary); + assert!(result.task_details); } } From deb57007e973b220fd0039d0205a7525f884aa10 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:12:45 -0700 Subject: [PATCH 08/29] Try again to fix the formatting issues --- crates/turborepo-lib/src/cli/error.rs | 6 +-- crates/turborepo-lib/src/cli/mod.rs | 71 +++++++++++++-------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/crates/turborepo-lib/src/cli/error.rs b/crates/turborepo-lib/src/cli/error.rs index 833aee28e6767..1241d09168062 100644 --- a/crates/turborepo-lib/src/cli/error.rs +++ b/crates/turborepo-lib/src/cli/error.rs @@ -4,12 +4,12 @@ use itertools::Itertools; use miette::Diagnostic; use thiserror::Error; use turborepo_repository::package_graph; -use turborepo_signals::{SignalHandler, listeners::get_signal}; +use turborepo_signals::{listeners::get_signal, SignalHandler}; use turborepo_telemetry::events::command::CommandEventBuilder; -use turborepo_ui::{BOLD, GREY, color}; +use turborepo_ui::{color, BOLD, GREY}; use crate::{ - commands::{CommandBase, bin, generate, get_mfe_port, link, login, ls, prune}, + commands::{bin, generate, get_mfe_port, link, login, ls, prune, CommandBase}, daemon::DaemonError, query, rewrite_json::RewriteError, diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 4980a69d07b18..5de6736c9f674 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -10,10 +10,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, - builder::NonEmptyStringValueParser, + builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, + ValueEnum, }; -use clap_complete::{Shell, generate}; +use clap_complete::{generate, Shell}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -21,17 +21,16 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - TelemetryHandle, - events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, - init_telemetry, track_usage, + events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, + init_telemetry, track_usage, TelemetryHandle, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, - login, logout, ls, prune, query, run, scan, telemetry, unlink, + bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, + ls, prune, query, run, scan, telemetry, unlink, CommandBase, }, config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, get_version, @@ -1620,7 +1619,11 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { Ok(0) } else { Ok(1) } + if scan::run(base).await { + Ok(0) + } else { + Ok(1) + } } Command::Config => { CommandEventBuilder::new("config") @@ -3277,17 +3280,15 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!( - Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err() - ); + assert!(Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err()); } #[test] @@ -3428,23 +3429,19 @@ mod test { .collect(), ) .unwrap(); - assert!( - inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package) - ); - assert!( - explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false) - ); + assert!(inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package)); + assert!(explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false)); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] From 1d6dfa0db2b9b957b4f79fa0b8fc16e519429220 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:20:32 -0700 Subject: [PATCH 09/29] Move the observability CLI details out to their own file within the crate --- crates/turborepo-lib/src/cli/mod.rs | 401 ++---------------- crates/turborepo-lib/src/cli/observability.rs | 336 +++++++++++++++ 2 files changed, 376 insertions(+), 361 deletions(-) create mode 100644 crates/turborepo-lib/src/cli/observability.rs diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 5de6736c9f674..d2bd85ef6bcaa 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -1,6 +1,5 @@ use std::{ backtrace::Backtrace, - collections::BTreeMap, env, ffi::OsString, fmt::{self, Display}, @@ -10,10 +9,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, - ValueEnum, + ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, + builder::NonEmptyStringValueParser, }; -use clap_complete::{generate, Shell}; +use clap_complete::{Shell, generate}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -21,18 +20,18 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, - init_telemetry, track_usage, TelemetryHandle, + TelemetryHandle, + events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, + init_telemetry, track_usage, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, - ls, prune, query, run, scan, telemetry, unlink, CommandBase, + CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, + login, logout, ls, prune, query, run, scan, telemetry, unlink, }, - config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, get_version, run::watch::WatchClient, shim::TurboState, @@ -41,6 +40,8 @@ use crate::{ }; mod error; +mod observability; + // Global turbo sets this environment variable to its cwd so that local // turbo can use it for package inference. pub const INVOCATION_DIR_ENV_VAR: &str = "TURBO_INVOCATION_DIR"; @@ -231,7 +232,7 @@ pub struct Args { #[clap(flatten)] pub verbosity: Verbosity, #[clap(flatten)] - pub experimental_otel_args: ExperimentalOtelCliArgs, + pub experimental_otel_args: observability::ExperimentalOtelCliArgs, /// Force a check for a new version of turbo #[clap(long, global = true, hide = true)] pub check_for_update: bool, @@ -302,116 +303,6 @@ fn parse_key_val_pair(s: &str) -> Result<(String, String), String> { Ok((key.to_string(), value.trim().to_string())) } -#[derive(Parser, Clone, Debug, Default, PartialEq)] -pub struct ExperimentalOtelCliArgs { - #[clap( - long = "experimental-otel-enabled", - global = true, - num_args = 0..=1, - default_missing_value = "true" - )] - pub enabled: Option, - #[clap( - long = "experimental-otel-protocol", - value_enum, - global = true, - value_name = "PROTOCOL" - )] - pub protocol: Option, - #[clap(long = "experimental-otel-endpoint", global = true, value_name = "URL")] - pub endpoint: Option, - #[clap( - long = "experimental-otel-timeout-ms", - global = true, - value_name = "MILLISECONDS" - )] - pub timeout_ms: Option, - #[clap( - long = "experimental-otel-header", - global = true, - value_parser = parse_key_val_pair, - value_name = "KEY=VALUE" - )] - pub headers: Vec<(String, String)>, - #[clap( - long = "experimental-otel-resource", - global = true, - value_parser = parse_key_val_pair, - value_name = "KEY=VALUE" - )] - pub resource_attributes: Vec<(String, String)>, - #[clap( - long = "experimental-otel-metrics-run-summary", - global = true, - num_args = 0..=1, - default_missing_value = "true" - )] - pub metrics_run_summary: Option, - #[clap( - long = "experimental-otel-metrics-task-details", - global = true, - num_args = 0..=1, - default_missing_value = "true" - )] - pub metrics_task_details: Option, -} - -impl ExperimentalOtelCliArgs { - pub fn to_config(&self) -> Option { - let mut options = ExperimentalOtelOptions::default(); - let mut touched = false; - - if let Some(enabled) = self.enabled { - options.enabled = Some(enabled); - touched = true; - } - if let Some(protocol) = self.protocol { - options.protocol = Some(protocol); - touched = true; - } - if let Some(endpoint) = &self.endpoint { - options.endpoint = Some(endpoint.clone()); - touched = true; - } - if let Some(timeout) = self.timeout_ms { - options.timeout_ms = Some(timeout); - touched = true; - } - if !self.headers.is_empty() { - let mut map = BTreeMap::new(); - for (key, value) in &self.headers { - map.insert(key.clone(), value.clone()); - } - options.headers = Some(map); - touched = true; - } - if !self.resource_attributes.is_empty() { - let mut map = BTreeMap::new(); - for (key, value) in &self.resource_attributes { - map.insert(key.clone(), value.clone()); - } - options.resource = Some(map); - touched = true; - } - if let Some(value) = self.metrics_run_summary { - options - .metrics - .get_or_insert_with(ExperimentalOtelMetricsOptions::default) - .run_summary = Some(value); - touched = true; - } - if let Some(value) = self.metrics_task_details { - options - .metrics - .get_or_insert_with(ExperimentalOtelMetricsOptions::default) - .task_details = Some(value); - touched = true; - } - - touched.then_some(options) - } -} - #[derive(Subcommand, Copy, Clone, Debug, PartialEq)] pub enum DaemonCommand { /// Restarts the turbo daemon @@ -1619,11 +1510,7 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { - Ok(0) - } else { - Ok(1) - } + if scan::run(base).await { Ok(0) } else { Ok(1) } } Command::Config => { CommandEventBuilder::new("config") @@ -1861,7 +1748,6 @@ mod test { use itertools::Itertools; use pretty_assertions::assert_eq; - use super::{ExperimentalOtelCliArgs, ExperimentalOtelProtocol}; use crate::cli::{ContinueMode, ExecutionArgs, LinkTarget, RunArgs}; struct CommandTestCase { @@ -3280,15 +3166,17 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!(Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err()); + assert!( + Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err() + ); } #[test] @@ -3429,19 +3317,23 @@ mod test { .collect(), ) .unwrap(); - assert!(inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package)); - assert!(explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false)); + assert!( + inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package) + ); + assert!( + explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false) + ); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] @@ -3495,217 +3387,4 @@ mod test { assert_snapshot!(args.join("-").as_str(), err); } } - - #[test] - fn test_experimental_otel_cli_args_empty() { - let args = ExperimentalOtelCliArgs::default(); - let result = args.to_config(); - assert_eq!(result, None); - } - - #[test] - fn test_experimental_otel_cli_args_enabled() { - let args = ExperimentalOtelCliArgs { - enabled: Some(true), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - assert_eq!(result.unwrap().enabled, Some(true)); - } - - #[test] - fn test_experimental_otel_cli_args_protocol() { - let args = ExperimentalOtelCliArgs { - protocol: Some(ExperimentalOtelProtocol::Grpc), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - assert_eq!( - result.unwrap().protocol, - Some(ExperimentalOtelProtocol::Grpc) - ); - } - - #[test] - fn test_experimental_otel_cli_args_protocol_http_protobuf() { - let args = ExperimentalOtelCliArgs { - protocol: Some(ExperimentalOtelProtocol::HttpProtobuf), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - assert_eq!( - result.unwrap().protocol, - Some(ExperimentalOtelProtocol::HttpProtobuf) - ); - } - - #[test] - fn test_experimental_otel_cli_args_endpoint() { - let args = ExperimentalOtelCliArgs { - endpoint: Some("https://example.com/otel".to_string()), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - assert_eq!( - result.unwrap().endpoint, - Some("https://example.com/otel".to_string()) - ); - } - - #[test] - fn test_experimental_otel_cli_args_timeout_ms() { - let args = ExperimentalOtelCliArgs { - timeout_ms: Some(5000), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - assert_eq!(result.unwrap().timeout_ms, Some(5000)); - } - - #[test] - fn test_experimental_otel_cli_args_headers_single() { - let args = ExperimentalOtelCliArgs { - headers: vec![("key1".to_string(), "value1".to_string())], - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let headers = result.unwrap().headers.unwrap(); - assert_eq!(headers.get("key1"), Some(&"value1".to_string())); - } - - #[test] - fn test_experimental_otel_cli_args_headers_multiple() { - let args = ExperimentalOtelCliArgs { - headers: vec![ - ("key1".to_string(), "value1".to_string()), - ("key2".to_string(), "value2".to_string()), - ], - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let headers = result.unwrap().headers.unwrap(); - assert_eq!(headers.get("key1"), Some(&"value1".to_string())); - assert_eq!(headers.get("key2"), Some(&"value2".to_string())); - } - - #[test] - fn test_experimental_otel_cli_args_headers_empty() { - let args = ExperimentalOtelCliArgs { - headers: vec![], - ..Default::default() - }; - let result = args.to_config(); - assert_eq!(result, None); - } - - #[test] - fn test_experimental_otel_cli_args_resource_single() { - let args = ExperimentalOtelCliArgs { - resource_attributes: vec![("service.name".to_string(), "my-service".to_string())], - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let resource = result.unwrap().resource.unwrap(); - assert_eq!( - resource.get("service.name"), - Some(&"my-service".to_string()) - ); - } - - #[test] - fn test_experimental_otel_cli_args_resource_multiple() { - let args = ExperimentalOtelCliArgs { - resource_attributes: vec![ - ("service.name".to_string(), "my-service".to_string()), - ("env".to_string(), "production".to_string()), - ], - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let resource = result.unwrap().resource.unwrap(); - assert_eq!( - resource.get("service.name"), - Some(&"my-service".to_string()) - ); - assert_eq!(resource.get("env"), Some(&"production".to_string())); - } - - #[test] - fn test_experimental_otel_cli_args_metrics_run_summary() { - let args = ExperimentalOtelCliArgs { - metrics_run_summary: Some(true), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let metrics = result.unwrap().metrics.unwrap(); - assert_eq!(metrics.run_summary, Some(true)); - } - - #[test] - fn test_experimental_otel_cli_args_metrics_task_details() { - let args = ExperimentalOtelCliArgs { - metrics_task_details: Some(true), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let metrics = result.unwrap().metrics.unwrap(); - assert_eq!(metrics.task_details, Some(true)); - } - - #[test] - fn test_experimental_otel_cli_args_metrics_both() { - let args = ExperimentalOtelCliArgs { - metrics_run_summary: Some(true), - metrics_task_details: Some(false), - ..Default::default() - }; - let result = args.to_config(); - assert!(result.is_some()); - let metrics = result.unwrap().metrics.unwrap(); - assert_eq!(metrics.run_summary, Some(true)); - assert_eq!(metrics.task_details, Some(false)); - } - - #[test] - fn test_experimental_otel_cli_args_combined() { - let args = ExperimentalOtelCliArgs { - enabled: Some(true), - protocol: Some(ExperimentalOtelProtocol::Grpc), - endpoint: Some("https://example.com/otel".to_string()), - timeout_ms: Some(15000), - headers: vec![("auth".to_string(), "token123".to_string())], - resource_attributes: vec![("service.name".to_string(), "test".to_string())], - metrics_run_summary: Some(true), - metrics_task_details: Some(false), - }; - let result = args.to_config(); - assert!(result.is_some()); - let opts = result.unwrap(); - assert_eq!(opts.enabled, Some(true)); - assert_eq!(opts.protocol, Some(ExperimentalOtelProtocol::Grpc)); - assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); - assert_eq!(opts.timeout_ms, Some(15000)); - assert_eq!( - opts.headers.unwrap().get("auth"), - Some(&"token123".to_string()) - ); - assert_eq!( - opts.resource.unwrap().get("service.name"), - Some(&"test".to_string()) - ); - let metrics = opts.metrics.unwrap(); - assert_eq!(metrics.run_summary, Some(true)); - assert_eq!(metrics.task_details, Some(false)); - } } diff --git a/crates/turborepo-lib/src/cli/observability.rs b/crates/turborepo-lib/src/cli/observability.rs new file mode 100644 index 0000000000000..f8f3a27086405 --- /dev/null +++ b/crates/turborepo-lib/src/cli/observability.rs @@ -0,0 +1,336 @@ +use std::collections::BTreeMap; + +use clap::Parser; + +use crate::{ + cli::parse_key_val_pair, + config::{ExperimentalOtelMetricsOptions, ExperimentalOtelOptions, ExperimentalOtelProtocol}, +}; + +#[derive(Parser, Clone, Debug, Default, PartialEq)] +pub struct ExperimentalOtelCliArgs { + #[clap( + long = "experimental-otel-enabled", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub enabled: Option, + #[clap( + long = "experimental-otel-protocol", + value_enum, + global = true, + value_name = "PROTOCOL" + )] + pub protocol: Option, + #[clap(long = "experimental-otel-endpoint", global = true, value_name = "URL")] + pub endpoint: Option, + #[clap( + long = "experimental-otel-timeout-ms", + global = true, + value_name = "MILLISECONDS" + )] + pub timeout_ms: Option, + #[clap( + long = "experimental-otel-header", + global = true, + value_parser = parse_key_val_pair, + value_name = "KEY=VALUE" + )] + pub headers: Vec<(String, String)>, + #[clap( + long = "experimental-otel-resource", + global = true, + value_parser = parse_key_val_pair, + value_name = "KEY=VALUE" + )] + pub resource_attributes: Vec<(String, String)>, + #[clap( + long = "experimental-otel-metrics-run-summary", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub metrics_run_summary: Option, + #[clap( + long = "experimental-otel-metrics-task-details", + global = true, + num_args = 0..=1, + default_missing_value = "true" + )] + pub metrics_task_details: Option, +} + +impl ExperimentalOtelCliArgs { + pub fn to_config(&self) -> Option { + let mut options = ExperimentalOtelOptions::default(); + let mut touched = false; + + if let Some(enabled) = self.enabled { + options.enabled = Some(enabled); + touched = true; + } + if let Some(protocol) = self.protocol { + options.protocol = Some(protocol); + touched = true; + } + if let Some(endpoint) = &self.endpoint { + options.endpoint = Some(endpoint.clone()); + touched = true; + } + if let Some(timeout) = self.timeout_ms { + options.timeout_ms = Some(timeout); + touched = true; + } + if !self.headers.is_empty() { + let mut map = BTreeMap::new(); + for (key, value) in &self.headers { + map.insert(key.clone(), value.clone()); + } + options.headers = Some(map); + touched = true; + } + if !self.resource_attributes.is_empty() { + let mut map = BTreeMap::new(); + for (key, value) in &self.resource_attributes { + map.insert(key.clone(), value.clone()); + } + options.resource = Some(map); + touched = true; + } + if let Some(value) = self.metrics_run_summary { + options + .metrics + .get_or_insert_with(ExperimentalOtelMetricsOptions::default) + .run_summary = Some(value); + touched = true; + } + if let Some(value) = self.metrics_task_details { + options + .metrics + .get_or_insert_with(ExperimentalOtelMetricsOptions::default) + .task_details = Some(value); + touched = true; + } + + touched.then_some(options) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_experimental_otel_cli_args_empty() { + let args = ExperimentalOtelCliArgs::default(); + let result = args.to_config(); + assert_eq!(result, None); + } + + #[test] + fn test_experimental_otel_cli_args_enabled() { + let args = ExperimentalOtelCliArgs { + enabled: Some(true), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_protocol() { + let args = ExperimentalOtelCliArgs { + protocol: Some(ExperimentalOtelProtocol::Grpc), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::Grpc) + ); + } + + #[test] + fn test_experimental_otel_cli_args_protocol_http_protobuf() { + let args = ExperimentalOtelCliArgs { + protocol: Some(ExperimentalOtelProtocol::HttpProtobuf), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().protocol, + Some(ExperimentalOtelProtocol::HttpProtobuf) + ); + } + + #[test] + fn test_experimental_otel_cli_args_endpoint() { + let args = ExperimentalOtelCliArgs { + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!( + result.unwrap().endpoint, + Some("https://example.com/otel".to_string()) + ); + } + + #[test] + fn test_experimental_otel_cli_args_timeout_ms() { + let args = ExperimentalOtelCliArgs { + timeout_ms: Some(5000), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!(result.unwrap().timeout_ms, Some(5000)); + } + + #[test] + fn test_experimental_otel_cli_args_headers_single() { + let args = ExperimentalOtelCliArgs { + headers: vec![("key1".to_string(), "value1".to_string())], + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_headers_multiple() { + let args = ExperimentalOtelCliArgs { + headers: vec![ + ("key1".to_string(), "value1".to_string()), + ("key2".to_string(), "value2".to_string()), + ], + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let headers = result.unwrap().headers.unwrap(); + assert_eq!(headers.get("key1"), Some(&"value1".to_string())); + assert_eq!(headers.get("key2"), Some(&"value2".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_headers_empty() { + let args = ExperimentalOtelCliArgs { + headers: vec![], + ..Default::default() + }; + let result = args.to_config(); + assert_eq!(result, None); + } + + #[test] + fn test_experimental_otel_cli_args_resource_single() { + let args = ExperimentalOtelCliArgs { + resource_attributes: vec![("service.name".to_string(), "my-service".to_string())], + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + } + + #[test] + fn test_experimental_otel_cli_args_resource_multiple() { + let args = ExperimentalOtelCliArgs { + resource_attributes: vec![ + ("service.name".to_string(), "my-service".to_string()), + ("env".to_string(), "production".to_string()), + ], + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let resource = result.unwrap().resource.unwrap(); + assert_eq!( + resource.get("service.name"), + Some(&"my-service".to_string()) + ); + assert_eq!(resource.get("env"), Some(&"production".to_string())); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_run_summary() { + let args = ExperimentalOtelCliArgs { + metrics_run_summary: Some(true), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_task_details() { + let args = ExperimentalOtelCliArgs { + metrics_task_details: Some(true), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.task_details, Some(true)); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_both() { + let args = ExperimentalOtelCliArgs { + metrics_run_summary: Some(true), + metrics_task_details: Some(false), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + assert_eq!(metrics.task_details, Some(false)); + } + + #[test] + fn test_experimental_otel_cli_args_combined() { + let args = ExperimentalOtelCliArgs { + enabled: Some(true), + protocol: Some(ExperimentalOtelProtocol::Grpc), + endpoint: Some("https://example.com/otel".to_string()), + timeout_ms: Some(15000), + headers: vec![("auth".to_string(), "token123".to_string())], + resource_attributes: vec![("service.name".to_string(), "test".to_string())], + metrics_run_summary: Some(true), + metrics_task_details: Some(false), + }; + let result = args.to_config(); + assert!(result.is_some()); + let opts = result.unwrap(); + assert_eq!(opts.enabled, Some(true)); + assert_eq!(opts.protocol, Some(ExperimentalOtelProtocol::Grpc)); + assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); + assert_eq!(opts.timeout_ms, Some(15000)); + assert_eq!( + opts.headers.unwrap().get("auth"), + Some(&"token123".to_string()) + ); + assert_eq!( + opts.resource.unwrap().get("service.name"), + Some(&"test".to_string()) + ); + let metrics = opts.metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(true)); + assert_eq!(metrics.task_details, Some(false)); + } +} From 939aa56141b2d9d9c17b33dbc22d7706f7c4960b Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:23:22 -0700 Subject: [PATCH 10/29] Reverse more strange formatting issues --- crates/turborepo-lib/src/cli/mod.rs | 71 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index d2bd85ef6bcaa..3257113a12755 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -9,10 +9,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, - builder::NonEmptyStringValueParser, + builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, + ValueEnum, }; -use clap_complete::{Shell, generate}; +use clap_complete::{generate, Shell}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -20,17 +20,16 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - TelemetryHandle, - events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, - init_telemetry, track_usage, + events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, + init_telemetry, track_usage, TelemetryHandle, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, - login, logout, ls, prune, query, run, scan, telemetry, unlink, + bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, + ls, prune, query, run, scan, telemetry, unlink, CommandBase, }, get_version, run::watch::WatchClient, @@ -1510,7 +1509,11 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { Ok(0) } else { Ok(1) } + if scan::run(base).await { + Ok(0) + } else { + Ok(1) + } } Command::Config => { CommandEventBuilder::new("config") @@ -3166,17 +3169,15 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!( - Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err() - ); + assert!(Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err()); } #[test] @@ -3317,23 +3318,19 @@ mod test { .collect(), ) .unwrap(); - assert!( - inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package) - ); - assert!( - explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false) - ); + assert!(inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package)); + assert!(explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false)); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] From 64e8b7f7de7c34055a69920a75a00563fb87d5f3 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:26:58 -0700 Subject: [PATCH 11/29] Add some general parsing tests for key_val_pari --- crates/turborepo-lib/src/cli/mod.rs | 119 ++++++++++++++++++++-------- 1 file changed, 85 insertions(+), 34 deletions(-) diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 3257113a12755..96b48bc8fe8a6 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -9,10 +9,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, - ValueEnum, + ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, + builder::NonEmptyStringValueParser, }; -use clap_complete::{generate, Shell}; +use clap_complete::{Shell, generate}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -20,16 +20,17 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, - init_telemetry, track_usage, TelemetryHandle, + TelemetryHandle, + events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, + init_telemetry, track_usage, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, - ls, prune, query, run, scan, telemetry, unlink, CommandBase, + CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, + login, logout, ls, prune, query, run, scan, telemetry, unlink, }, get_version, run::watch::WatchClient, @@ -1509,11 +1510,7 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { - Ok(0) - } else { - Ok(1) - } + if scan::run(base).await { Ok(0) } else { Ok(1) } } Command::Config => { CommandEventBuilder::new("config") @@ -3169,15 +3166,17 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!(Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err()); + assert!( + Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err() + ); } #[test] @@ -3318,19 +3317,23 @@ mod test { .collect(), ) .unwrap(); - assert!(inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package)); - assert!(explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false)); + assert!( + inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package) + ); + assert!( + explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false) + ); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] @@ -3384,4 +3387,52 @@ mod test { assert_snapshot!(args.join("-").as_str(), err); } } + + #[test] + fn test_parse_key_val_pair_valid() { + let result = super::parse_key_val_pair("key=value"); + assert_eq!(result.unwrap(), ("key".to_string(), "value".to_string())); + } + + #[test] + fn test_parse_key_val_pair_with_whitespace() { + let result = super::parse_key_val_pair(" key = value "); + assert_eq!(result.unwrap(), ("key".to_string(), "value".to_string())); + } + + #[test] + fn test_parse_key_val_pair_multiple_equals() { + let result = super::parse_key_val_pair("key=value=more"); + assert_eq!( + result.unwrap(), + ("key".to_string(), "value=more".to_string()) + ); + } + + #[test] + fn test_parse_key_val_pair_empty_value() { + let result = super::parse_key_val_pair("key="); + assert_eq!(result.unwrap(), ("key".to_string(), "".to_string())); + } + + #[test] + fn test_parse_key_val_pair_no_equals() { + let result = super::parse_key_val_pair("keyvalue"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "must be in key=value format"); + } + + #[test] + fn test_parse_key_val_pair_empty_key() { + let result = super::parse_key_val_pair("=value"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "key cannot be empty"); + } + + #[test] + fn test_parse_key_val_pair_whitespace_only_key() { + let result = super::parse_key_val_pair(" =value"); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), "key cannot be empty"); + } } From 8b607f5f3120d93a57288640932c13bd218665a0 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:30:05 -0700 Subject: [PATCH 12/29] Fix the formatting again --- crates/turborepo-lib/src/cli/mod.rs | 71 ++++++++++++++--------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 96b48bc8fe8a6..6159ca2340c32 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -9,10 +9,10 @@ use std::{ use biome_deserialize_macros::Deserializable; use camino::{Utf8Path, Utf8PathBuf}; use clap::{ - ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, ValueEnum, - builder::NonEmptyStringValueParser, + builder::NonEmptyStringValueParser, ArgAction, ArgGroup, CommandFactory, Parser, Subcommand, + ValueEnum, }; -use clap_complete::{Shell, generate}; +use clap_complete::{generate, Shell}; pub use error::Error; use serde::{Deserialize, Serialize}; use tracing::{debug, error, log::warn}; @@ -20,17 +20,16 @@ use turbopath::AbsoluteSystemPathBuf; use turborepo_api_client::AnonAPIClient; use turborepo_repository::inference::{RepoMode, RepoState}; use turborepo_telemetry::{ - TelemetryHandle, - events::{EventBuilder, EventType, command::CommandEventBuilder, generic::GenericEventBuilder}, - init_telemetry, track_usage, + events::{command::CommandEventBuilder, generic::GenericEventBuilder, EventBuilder, EventType}, + init_telemetry, track_usage, TelemetryHandle, }; use turborepo_ui::{ColorConfig, GREY}; use crate::{ cli::error::print_potential_tasks, commands::{ - CommandBase, bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, - login, logout, ls, prune, query, run, scan, telemetry, unlink, + bin, boundaries, clone, config, daemon, generate, get_mfe_port, info, link, login, logout, + ls, prune, query, run, scan, telemetry, unlink, CommandBase, }, get_version, run::watch::WatchClient, @@ -1510,7 +1509,11 @@ pub async fn run( event.track_call(); let base = CommandBase::new(cli_args.clone(), repo_root, version, color_config)?; event.track_ui_mode(base.opts.run_opts.ui_mode); - if scan::run(base).await { Ok(0) } else { Ok(1) } + if scan::run(base).await { + Ok(0) + } else { + Ok(1) + } } Command::Config => { CommandEventBuilder::new("config") @@ -3166,17 +3169,15 @@ mod test { assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", ""]).is_err()); assert!(Args::try_parse_from(["turbo", "build", "--profile", "foo.json"]).is_ok()); assert!(Args::try_parse_from(["turbo", "build", "--anon-profile", "foo.json"]).is_ok()); - assert!( - Args::try_parse_from([ - "turbo", - "build", - "--profile", - "foo.json", - "--anon-profile", - "bar.json" - ]) - .is_err() - ); + assert!(Args::try_parse_from([ + "turbo", + "build", + "--profile", + "foo.json", + "--anon-profile", + "bar.json" + ]) + .is_err()); } #[test] @@ -3317,23 +3318,19 @@ mod test { .collect(), ) .unwrap(); - assert!( - inferred_run - .execution_args - .as_ref() - .is_some_and(|e| e.single_package) - ); - assert!( - explicit_run - .command - .as_ref() - .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { - Some(execution_args.single_package) - } else { - None - }) - .unwrap_or(false) - ); + assert!(inferred_run + .execution_args + .as_ref() + .is_some_and(|e| e.single_package)); + assert!(explicit_run + .command + .as_ref() + .and_then(|cmd| if let Command::Run { execution_args, .. } = cmd { + Some(execution_args.single_package) + } else { + None + }) + .unwrap_or(false)); } #[test_case::test_case(&["turbo", "watch", "build", "--no-daemon"]; "after watch")] From 6aa6b91d45b18781aa01a58aff8eb71a632381b7 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:34:00 -0700 Subject: [PATCH 13/29] Default experimental-otel-enabled to false --- crates/turborepo-lib/src/cli/observability.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/turborepo-lib/src/cli/observability.rs b/crates/turborepo-lib/src/cli/observability.rs index f8f3a27086405..f93a23e5b96f4 100644 --- a/crates/turborepo-lib/src/cli/observability.rs +++ b/crates/turborepo-lib/src/cli/observability.rs @@ -13,7 +13,7 @@ pub struct ExperimentalOtelCliArgs { long = "experimental-otel-enabled", global = true, num_args = 0..=1, - default_missing_value = "true" + default_missing_value = "false" )] pub enabled: Option, #[clap( From 152f68f4b83d5840994803a8994e96c75d850e4e Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:36:11 -0700 Subject: [PATCH 14/29] Reverse the change to default_missing_value, because it doesn't work the way it first appeared --- crates/turborepo-lib/src/cli/observability.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/turborepo-lib/src/cli/observability.rs b/crates/turborepo-lib/src/cli/observability.rs index f93a23e5b96f4..d7db092fac0cc 100644 --- a/crates/turborepo-lib/src/cli/observability.rs +++ b/crates/turborepo-lib/src/cli/observability.rs @@ -13,9 +13,10 @@ pub struct ExperimentalOtelCliArgs { long = "experimental-otel-enabled", global = true, num_args = 0..=1, - default_missing_value = "false" + default_missing_value = "true" )] pub enabled: Option, + #[clap( long = "experimental-otel-protocol", value_enum, @@ -23,14 +24,17 @@ pub struct ExperimentalOtelCliArgs { value_name = "PROTOCOL" )] pub protocol: Option, + #[clap(long = "experimental-otel-endpoint", global = true, value_name = "URL")] pub endpoint: Option, + #[clap( long = "experimental-otel-timeout-ms", global = true, value_name = "MILLISECONDS" )] pub timeout_ms: Option, + #[clap( long = "experimental-otel-header", global = true, @@ -38,6 +42,7 @@ pub struct ExperimentalOtelCliArgs { value_name = "KEY=VALUE" )] pub headers: Vec<(String, String)>, + #[clap( long = "experimental-otel-resource", global = true, @@ -45,6 +50,7 @@ pub struct ExperimentalOtelCliArgs { value_name = "KEY=VALUE" )] pub resource_attributes: Vec<(String, String)>, + #[clap( long = "experimental-otel-metrics-run-summary", global = true, @@ -52,6 +58,7 @@ pub struct ExperimentalOtelCliArgs { default_missing_value = "true" )] pub metrics_run_summary: Option, + #[clap( long = "experimental-otel-metrics-task-details", global = true, From fbd584d7102f5ab9cddf92548e1b8fcc4af7d15f Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:48:09 -0700 Subject: [PATCH 15/29] Minor tweak around the observability config --- crates/turborepo-lib/src/config/turbo_json.rs | 21 ++++++++++++------- crates/turborepo-lib/src/turbo_json/mod.rs | 6 +++--- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/crates/turborepo-lib/src/config/turbo_json.rs b/crates/turborepo-lib/src/config/turbo_json.rs index 642e81b63a39b..a096ef57da943 100644 --- a/crates/turborepo-lib/src/config/turbo_json.rs +++ b/crates/turborepo-lib/src/config/turbo_json.rs @@ -8,7 +8,8 @@ use super::{ ExperimentalOtelOptions, ExperimentalOtelProtocol, ResolvedConfigurationOptions, }; use crate::turbo_json::{ - RawKeyValue, RawObservabilityOtel, RawRemoteCacheOptions, RawRootTurboJson, RawTurboJson, + RawExperimentalObservability, RawKeyValue, RawObservabilityOtel, RawRemoteCacheOptions, + RawRootTurboJson, RawTurboJson, }; pub struct TurboJsonReader<'a> { @@ -95,13 +96,9 @@ impl<'a> TurboJsonReader<'a> { .map(|f| f.experimental_observability) .unwrap_or(false) { - let raw_otel = turbo_json - .experimental_observability - .and_then(|obs| obs.otel); - if let Some(raw_otel) = raw_otel { - opts.experimental_observability = Some(ExperimentalObservabilityOptions { - otel: Some(convert_raw_observability_otel(raw_otel)?), - }); + if let Some(raw_observability) = turbo_json.experimental_observability { + opts.experimental_observability = + Some(convert_raw_observability(raw_observability)?); } } Ok(opts) @@ -139,6 +136,14 @@ fn convert_key_values(entries: Vec) -> BTreeMap { map } +fn convert_raw_observability( + raw: RawExperimentalObservability, +) -> Result { + Ok(ExperimentalObservabilityOptions { + otel: raw.otel.map(convert_raw_observability_otel).transpose()?, + }) +} + fn convert_raw_observability_otel( raw: RawObservabilityOtel, ) -> Result { diff --git a/crates/turborepo-lib/src/turbo_json/mod.rs b/crates/turborepo-lib/src/turbo_json/mod.rs index 469a19a5592df..80bbd03279aee 100644 --- a/crates/turborepo-lib/src/turbo_json/mod.rs +++ b/crates/turborepo-lib/src/turbo_json/mod.rs @@ -33,8 +33,8 @@ pub use future_flags::FutureFlags; pub use loader::{TurboJsonLoader, TurboJsonReader}; pub use processed::ProcessedTaskDefinition; pub use raw::{ - RawKeyValue, RawObservabilityOtel, RawPackageTurboJson, RawRemoteCacheOptions, - RawRootTurboJson, RawTaskDefinition, RawTurboJson, + RawExperimentalObservability, RawKeyValue, RawObservabilityOtel, RawPackageTurboJson, + RawRemoteCacheOptions, RawRootTurboJson, RawTaskDefinition, RawTurboJson, }; use crate::boundaries::BoundariesConfig; @@ -1174,6 +1174,6 @@ mod tests { let deps = boundaries.dependencies.as_ref().unwrap(); assert!(deps.allow.is_some()); assert!(deps.deny.is_none()); // This should be None, not serialized as - // null + // null } } From d01eaac21f5a863fe18b4af8478cb69409dcd6f5 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 12:55:33 -0700 Subject: [PATCH 16/29] Remove the capnproto workaround --- crates/turborepo-lib/build.rs | 41 +- crates/turborepo-lib/src/hash/proto_capnp.rs | 3954 ------------------ 2 files changed, 3 insertions(+), 3992 deletions(-) delete mode 100644 crates/turborepo-lib/src/hash/proto_capnp.rs diff --git a/crates/turborepo-lib/build.rs b/crates/turborepo-lib/build.rs index 4d8c65946516c..eef97707179f7 100644 --- a/crates/turborepo-lib/build.rs +++ b/crates/turborepo-lib/build.rs @@ -1,11 +1,4 @@ -use std::{fs, path::PathBuf}; - fn main() -> Result<(), Box> { - // Ensure Cargo reruns this script if either the schema or the pregenerated - // bindings change. - println!("cargo:rerun-if-changed=./src/hash/proto.capnp"); - println!("cargo:rerun-if-changed=./src/hash/proto_capnp.rs"); - let tonic_build_result = tonic_build::configure() .build_server(true) .file_descriptor_set_path("src/daemon/file_descriptor_set.bin") @@ -29,38 +22,10 @@ fn main() -> Result<(), Box> { } return Ok(()); - } - - tonic_build_result.expect("tonic_build command"); - if let Err(err) = capnpc_result { - if !use_pregenerated_capnp()? { - // Preserve the previous behavior of failing the build when schema - // compilation fails, but surface the underlying error. - return Err(format!("schema compiler command failed: {err:?}").into()); - } - println!("cargo:warning=capnpc failed ({err:?}); using pre-generated Cap'n Proto bindings"); + } else { + tonic_build_result.expect("tonic_build command"); + capnpc_result.expect("schema compiler command"); } Ok(()) } - -fn use_pregenerated_capnp() -> Result> { - let manifest_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); - let fallback = manifest_dir.join("src/hash/proto_capnp.rs"); - if !fallback.exists() { - return Ok(false); - } - - let out_dir = PathBuf::from(std::env::var("OUT_DIR")?); - let destination = out_dir.join("src/hash/proto_capnp.rs"); - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - fs::copy(&fallback, &destination)?; - println!( - "cargo:warning=Using pre-generated Cap'n Proto bindings from {}", - fallback.display() - ); - - Ok(true) -} diff --git a/crates/turborepo-lib/src/hash/proto_capnp.rs b/crates/turborepo-lib/src/hash/proto_capnp.rs deleted file mode 100644 index 47f7b5a299f4c..0000000000000 --- a/crates/turborepo-lib/src/hash/proto_capnp.rs +++ /dev/null @@ -1,3954 +0,0 @@ -// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler. -// DO NOT EDIT. -// source: src/hash/proto.capnp - -pub mod task_hashable { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_global_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_global_hash(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_task_dependency_hashes(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_task_dependency_hashes(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - #[inline] - pub fn get_package_dir(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(2), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_package_dir(&self) -> bool { - !self.reader.get_pointer_field(2).is_null() - } - #[inline] - pub fn get_hash_of_files(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(3), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_hash_of_files(&self) -> bool { - !self.reader.get_pointer_field(3).is_null() - } - #[inline] - pub fn get_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(4), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_external_deps_hash(&self) -> bool { - !self.reader.get_pointer_field(4).is_null() - } - #[inline] - pub fn get_task(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(5), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_task(&self) -> bool { - !self.reader.get_pointer_field(5).is_null() - } - #[inline] - pub fn get_outputs( - self, - ) -> ::capnp::Result> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(6), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_outputs(&self) -> bool { - !self.reader.get_pointer_field(6).is_null() - } - #[inline] - pub fn get_pass_thru_args(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(7), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_pass_thru_args(&self) -> bool { - !self.reader.get_pointer_field(7).is_null() - } - #[inline] - pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(8), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_env(&self) -> bool { - !self.reader.get_pointer_field(8).is_null() - } - #[inline] - pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(9), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_resolved_env_vars(&self) -> bool { - !self.reader.get_pointer_field(9).is_null() - } - #[inline] - pub fn get_pass_thru_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(10), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_pass_thru_env(&self) -> bool { - !self.reader.get_pointer_field(10).is_null() - } - #[inline] - pub fn get_env_mode( - self, - ) -> ::core::result::Result< - crate::hash::proto_capnp::task_hashable::EnvMode, - ::capnp::NotInSchema, - > { - ::core::convert::TryInto::try_into(self.reader.get_data_field::(0)) - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 1, - pointers: 11, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_global_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_global_hash(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(0).set_text(value); - } - #[inline] - pub fn init_global_hash(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(0).init_text(size) - } - #[inline] - pub fn has_global_hash(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_task_dependency_hashes( - self, - ) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_task_dependency_hashes( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(1), - value, - false, - ) - } - #[inline] - pub fn init_task_dependency_hashes(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(1), - size, - ) - } - #[inline] - pub fn has_task_dependency_hashes(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - #[inline] - pub fn get_package_dir(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(2), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_package_dir(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(2).set_text(value); - } - #[inline] - pub fn init_package_dir(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(2).init_text(size) - } - #[inline] - pub fn has_package_dir(&self) -> bool { - !self.builder.is_pointer_field_null(2) - } - #[inline] - pub fn get_hash_of_files(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(3), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_hash_of_files(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(3).set_text(value); - } - #[inline] - pub fn init_hash_of_files(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(3).init_text(size) - } - #[inline] - pub fn has_hash_of_files(&self) -> bool { - !self.builder.is_pointer_field_null(3) - } - #[inline] - pub fn get_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(4), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_external_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(4).set_text(value); - } - #[inline] - pub fn init_external_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(4).init_text(size) - } - #[inline] - pub fn has_external_deps_hash(&self) -> bool { - !self.builder.is_pointer_field_null(4) - } - #[inline] - pub fn get_task(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(5), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_task(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(5).set_text(value); - } - #[inline] - pub fn init_task(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(5).init_text(size) - } - #[inline] - pub fn has_task(&self) -> bool { - !self.builder.is_pointer_field_null(5) - } - #[inline] - pub fn get_outputs( - self, - ) -> ::capnp::Result> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(6), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_outputs( - &mut self, - value: crate::hash::proto_capnp::task_outputs::Reader<'_>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(6), - value, - false, - ) - } - #[inline] - pub fn init_outputs(self) -> crate::hash::proto_capnp::task_outputs::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(6), 0) - } - #[inline] - pub fn has_outputs(&self) -> bool { - !self.builder.is_pointer_field_null(6) - } - #[inline] - pub fn get_pass_thru_args(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(7), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_pass_thru_args( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(7), - value, - false, - ) - } - #[inline] - pub fn init_pass_thru_args(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(7), - size, - ) - } - #[inline] - pub fn has_pass_thru_args(&self) -> bool { - !self.builder.is_pointer_field_null(7) - } - #[inline] - pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(8), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_env(&mut self, value: ::capnp::text_list::Reader<'a>) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(8), - value, - false, - ) - } - #[inline] - pub fn init_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(8), - size, - ) - } - #[inline] - pub fn has_env(&self) -> bool { - !self.builder.is_pointer_field_null(8) - } - #[inline] - pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(9), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_resolved_env_vars( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(9), - value, - false, - ) - } - #[inline] - pub fn init_resolved_env_vars(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(9), - size, - ) - } - #[inline] - pub fn has_resolved_env_vars(&self) -> bool { - !self.builder.is_pointer_field_null(9) - } - #[inline] - pub fn get_pass_thru_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(10), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_pass_thru_env( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(10), - value, - false, - ) - } - #[inline] - pub fn init_pass_thru_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(10), - size, - ) - } - #[inline] - pub fn has_pass_thru_env(&self) -> bool { - !self.builder.is_pointer_field_null(10) - } - #[inline] - pub fn get_env_mode( - self, - ) -> ::core::result::Result< - crate::hash::proto_capnp::task_hashable::EnvMode, - ::capnp::NotInSchema, - > { - ::core::convert::TryInto::try_into(self.builder.get_data_field::(0)) - } - #[inline] - pub fn set_env_mode(&mut self, value: crate::hash::proto_capnp::task_hashable::EnvMode) { - self.builder.set_data_field::(0, value as u16); - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline { - pub fn get_outputs(&self) -> crate::hash::proto_capnp::task_outputs::Pipeline { - ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(6)) - } - } - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 233] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(121, 228, 245, 78, 235, 156, 240, 225), - ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(11, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(22, 0, 0, 0, 197, 1, 0, 0), - ::capnp::word(21, 0, 0, 0, 18, 1, 0, 0), - ::capnp::word(37, 0, 0, 0, 23, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(45, 0, 0, 0, 167, 2, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), - ::capnp::word(107, 72, 97, 115, 104, 97, 98, 108), - ::capnp::word(101, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(4, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), - ::capnp::word(1, 0, 0, 0, 66, 0, 0, 0), - ::capnp::word(69, 110, 118, 77, 111, 100, 101, 0), - ::capnp::word(48, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(65, 1, 0, 0, 90, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(64, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(76, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(73, 1, 0, 0, 170, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(76, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(104, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(2, 0, 0, 0, 2, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 1, 0, 0, 90, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(100, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(112, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(3, 0, 0, 0, 3, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 3, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(109, 1, 0, 0, 98, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(108, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(120, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(4, 0, 0, 0, 4, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 4, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(117, 1, 0, 0, 138, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(120, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(132, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(5, 0, 0, 0, 5, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 5, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(129, 1, 0, 0, 42, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(124, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(136, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(6, 0, 0, 0, 6, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 6, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(133, 1, 0, 0, 66, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(128, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(140, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(7, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(137, 1, 0, 0, 106, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(136, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(164, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 8, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 8, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(161, 1, 0, 0, 34, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(156, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(184, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(9, 0, 0, 0, 9, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 9, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(181, 1, 0, 0, 130, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(180, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(208, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(10, 0, 0, 0, 10, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 10, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(205, 1, 0, 0, 98, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(204, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(232, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(11, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 11, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(229, 1, 0, 0, 66, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(224, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(236, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(103, 108, 111, 98, 97, 108, 72, 97), - ::capnp::word(115, 104, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(116, 97, 115, 107, 68, 101, 112, 101), - ::capnp::word(110, 100, 101, 110, 99, 121, 72, 97), - ::capnp::word(115, 104, 101, 115, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(112, 97, 99, 107, 97, 103, 101, 68), - ::capnp::word(105, 114, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(104, 97, 115, 104, 79, 102, 70, 105), - ::capnp::word(108, 101, 115, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 120, 116, 101, 114, 110, 97, 108), - ::capnp::word(68, 101, 112, 115, 72, 97, 115, 104), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(116, 97, 115, 107, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(111, 117, 116, 112, 117, 116, 115, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(103, 162, 171, 232, 252, 0, 131, 213), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(112, 97, 115, 115, 84, 104, 114, 117), - ::capnp::word(65, 114, 103, 115, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 110, 118, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(114, 101, 115, 111, 108, 118, 101, 100), - ::capnp::word(69, 110, 118, 86, 97, 114, 115, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(112, 97, 115, 115, 84, 104, 114, 117), - ::capnp::word(69, 110, 118, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 110, 118, 77, 111, 100, 101, 0), - ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 2 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 3 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 4 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 5 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 6 => ::introspect(), - 7 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 8 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 9 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 10 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 11 => ::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xe1f0_9ceb_4ef5_e479; - } - - #[repr(u16)] - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum EnvMode { - Loose = 0, - Strict = 1, - } - - impl ::capnp::introspect::Introspect for EnvMode { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Enum(::capnp::introspect::RawEnumSchema { - encoded_node: &env_mode::ENCODED_NODE, - annotation_types: env_mode::get_annotation_types, - }) - .into() - } - } - impl<'a> ::core::convert::From for ::capnp::dynamic_value::Reader<'a> { - fn from(e: EnvMode) -> Self { - ::capnp::dynamic_value::Enum::new( - e.into(), - ::capnp::introspect::RawEnumSchema { - encoded_node: &env_mode::ENCODED_NODE, - annotation_types: env_mode::get_annotation_types, - } - .into(), - ) - .into() - } - } - impl ::core::convert::TryFrom for EnvMode { - type Error = ::capnp::NotInSchema; - fn try_from( - value: u16, - ) -> ::core::result::Result>::Error> - { - match value { - 0 => ::core::result::Result::Ok(Self::Loose), - 1 => ::core::result::Result::Ok(Self::Strict), - n => ::core::result::Result::Err(::capnp::NotInSchema(n)), - } - } - } - impl From for u16 { - #[inline] - fn from(x: EnvMode) -> u16 { - x as u16 - } - } - impl ::capnp::traits::HasTypeId for EnvMode { - const TYPE_ID: u64 = 0x8dc0_8a1d_29f6_9b16u64; - } - mod env_mode { - pub static ENCODED_NODE: [::capnp::Word; 29] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(22, 155, 246, 41, 29, 138, 192, 141), - ::capnp::word(34, 0, 0, 0, 2, 0, 0, 0), - ::capnp::word(121, 228, 245, 78, 235, 156, 240, 225), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(142, 1, 0, 0, 195, 1, 0, 0), - ::capnp::word(21, 0, 0, 0, 82, 1, 0, 0), - ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(37, 0, 0, 0, 55, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), - ::capnp::word(107, 72, 97, 115, 104, 97, 98, 108), - ::capnp::word(101, 46, 69, 110, 118, 77, 111, 100), - ::capnp::word(101, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 1, 0, 2, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(17, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(9, 0, 0, 0, 58, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(108, 111, 111, 115, 101, 0, 0, 0), - ::capnp::word(115, 116, 114, 105, 99, 116, 0, 0), - ]; - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - } -} - -pub mod task_outputs { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_inclusions(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_inclusions(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_exclusions(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_exclusions(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 0, - pointers: 2, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_inclusions(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_inclusions( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(0), - value, - false, - ) - } - #[inline] - pub fn init_inclusions(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(0), - size, - ) - } - #[inline] - pub fn has_inclusions(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_exclusions(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_exclusions( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(1), - value, - false, - ) - } - #[inline] - pub fn init_exclusions(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(1), - size, - ) - } - #[inline] - pub fn has_exclusions(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 60] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(103, 162, 171, 232, 252, 0, 131, 213), - ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(199, 1, 0, 0, 24, 2, 0, 0), - ::capnp::word(21, 0, 0, 0, 10, 1, 0, 0), - ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(33, 0, 0, 0, 119, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 84, 97, 115), - ::capnp::word(107, 79, 117, 116, 112, 117, 116, 115), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(41, 0, 0, 0, 90, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(68, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(65, 0, 0, 0, 90, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(64, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(92, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(105, 110, 99, 108, 117, 115, 105, 111), - ::capnp::word(110, 115, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 120, 99, 108, 117, 115, 105, 111), - ::capnp::word(110, 115, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xd583_00fc_e8ab_a267; - } -} - -pub mod global_hashable { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_global_cache_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_global_cache_key(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_global_file_hash_map( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Reader< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - > { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_global_file_hash_map(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - #[inline] - pub fn get_root_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(2), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_root_external_deps_hash(&self) -> bool { - !self.reader.get_pointer_field(2).is_null() - } - #[inline] - pub fn get_root_internal_deps_hash(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(3), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_root_internal_deps_hash(&self) -> bool { - !self.reader.get_pointer_field(3).is_null() - } - #[inline] - pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(4), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_env(&self) -> bool { - !self.reader.get_pointer_field(4).is_null() - } - #[inline] - pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(5), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_resolved_env_vars(&self) -> bool { - !self.reader.get_pointer_field(5).is_null() - } - #[inline] - pub fn get_pass_through_env(self) -> ::capnp::Result<::capnp::text_list::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(6), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_pass_through_env(&self) -> bool { - !self.reader.get_pointer_field(6).is_null() - } - #[inline] - pub fn get_env_mode( - self, - ) -> ::core::result::Result< - crate::hash::proto_capnp::global_hashable::EnvMode, - ::capnp::NotInSchema, - > { - ::core::convert::TryInto::try_into(self.reader.get_data_field::(0)) - } - #[inline] - pub fn get_framework_inference(self) -> bool { - self.reader.get_bool_field(16) - } - #[inline] - pub fn get_engines( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Reader< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - > { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(7), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_engines(&self) -> bool { - !self.reader.get_pointer_field(7).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 1, - pointers: 8, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_global_cache_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_global_cache_key(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(0).set_text(value); - } - #[inline] - pub fn init_global_cache_key(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(0).init_text(size) - } - #[inline] - pub fn has_global_cache_key(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_global_file_hash_map( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Builder< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - > { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_global_file_hash_map( - &mut self, - value: ::capnp::struct_list::Reader< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(1), - value, - false, - ) - } - #[inline] - pub fn init_global_file_hash_map( - self, - size: u32, - ) -> ::capnp::struct_list::Builder< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - > { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(1), - size, - ) - } - #[inline] - pub fn has_global_file_hash_map(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - #[inline] - pub fn get_root_external_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(2), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_root_external_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(2).set_text(value); - } - #[inline] - pub fn init_root_external_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(2).init_text(size) - } - #[inline] - pub fn has_root_external_deps_hash(&self) -> bool { - !self.builder.is_pointer_field_null(2) - } - #[inline] - pub fn get_root_internal_deps_hash(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(3), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_root_internal_deps_hash(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(3).set_text(value); - } - #[inline] - pub fn init_root_internal_deps_hash(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(3).init_text(size) - } - #[inline] - pub fn has_root_internal_deps_hash(&self) -> bool { - !self.builder.is_pointer_field_null(3) - } - #[inline] - pub fn get_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(4), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_env(&mut self, value: ::capnp::text_list::Reader<'a>) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(4), - value, - false, - ) - } - #[inline] - pub fn init_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(4), - size, - ) - } - #[inline] - pub fn has_env(&self) -> bool { - !self.builder.is_pointer_field_null(4) - } - #[inline] - pub fn get_resolved_env_vars(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(5), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_resolved_env_vars( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(5), - value, - false, - ) - } - #[inline] - pub fn init_resolved_env_vars(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(5), - size, - ) - } - #[inline] - pub fn has_resolved_env_vars(&self) -> bool { - !self.builder.is_pointer_field_null(5) - } - #[inline] - pub fn get_pass_through_env(self) -> ::capnp::Result<::capnp::text_list::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(6), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_pass_through_env( - &mut self, - value: ::capnp::text_list::Reader<'a>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(6), - value, - false, - ) - } - #[inline] - pub fn init_pass_through_env(self, size: u32) -> ::capnp::text_list::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(6), - size, - ) - } - #[inline] - pub fn has_pass_through_env(&self) -> bool { - !self.builder.is_pointer_field_null(6) - } - #[inline] - pub fn get_env_mode( - self, - ) -> ::core::result::Result< - crate::hash::proto_capnp::global_hashable::EnvMode, - ::capnp::NotInSchema, - > { - ::core::convert::TryInto::try_into(self.builder.get_data_field::(0)) - } - #[inline] - pub fn set_env_mode(&mut self, value: crate::hash::proto_capnp::global_hashable::EnvMode) { - self.builder.set_data_field::(0, value as u16); - } - #[inline] - pub fn get_framework_inference(self) -> bool { - self.builder.get_bool_field(16) - } - #[inline] - pub fn set_framework_inference(&mut self, value: bool) { - self.builder.set_bool_field(16, value); - } - #[inline] - pub fn get_engines( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Builder< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - > { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(7), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_engines( - &mut self, - value: ::capnp::struct_list::Reader< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - >, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(7), - value, - false, - ) - } - #[inline] - pub fn init_engines( - self, - size: u32, - ) -> ::capnp::struct_list::Builder< - 'a, - crate::hash::proto_capnp::global_hashable::entry::Owned, - > { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(7), - size, - ) - } - #[inline] - pub fn has_engines(&self) -> bool { - !self.builder.is_pointer_field_null(7) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 207] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), - ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(8, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(26, 2, 0, 0, 207, 3, 0, 0), - ::capnp::word(21, 0, 0, 0, 34, 1, 0, 0), - ::capnp::word(37, 0, 0, 0, 39, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(57, 0, 0, 0, 55, 2, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), - ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), - ::capnp::word(98, 108, 101, 0, 0, 0, 0, 0), - ::capnp::word(8, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), - ::capnp::word(9, 0, 0, 0, 66, 0, 0, 0), - ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), - ::capnp::word(5, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(69, 110, 118, 77, 111, 100, 101, 0), - ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), - ::capnp::word(40, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(9, 1, 0, 0, 122, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(8, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(20, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(17, 1, 0, 0, 146, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(20, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(48, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(2, 0, 0, 0, 2, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(45, 1, 0, 0, 170, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(48, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(60, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(3, 0, 0, 0, 3, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 3, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(57, 1, 0, 0, 170, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(60, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(72, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(4, 0, 0, 0, 4, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 4, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(69, 1, 0, 0, 34, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(64, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(92, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(5, 0, 0, 0, 5, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 5, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(89, 1, 0, 0, 130, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(88, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(116, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(6, 0, 0, 0, 6, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 6, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(113, 1, 0, 0, 122, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(112, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(140, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(7, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(137, 1, 0, 0, 66, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(132, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(144, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 16, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 8, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(141, 1, 0, 0, 154, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(144, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(156, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(9, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 9, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(153, 1, 0, 0, 66, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(148, 1, 0, 0, 3, 0, 1, 0), - ::capnp::word(176, 1, 0, 0, 2, 0, 1, 0), - ::capnp::word(103, 108, 111, 98, 97, 108, 67, 97), - ::capnp::word(99, 104, 101, 75, 101, 121, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(103, 108, 111, 98, 97, 108, 70, 105), - ::capnp::word(108, 101, 72, 97, 115, 104, 77, 97), - ::capnp::word(112, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(114, 111, 111, 116, 69, 120, 116, 101), - ::capnp::word(114, 110, 97, 108, 68, 101, 112, 115), - ::capnp::word(72, 97, 115, 104, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(114, 111, 111, 116, 73, 110, 116, 101), - ::capnp::word(114, 110, 97, 108, 68, 101, 112, 115), - ::capnp::word(72, 97, 115, 104, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 110, 118, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(114, 101, 115, 111, 108, 118, 101, 100), - ::capnp::word(69, 110, 118, 86, 97, 114, 115, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(112, 97, 115, 115, 84, 104, 114, 111), - ::capnp::word(117, 103, 104, 69, 110, 118, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 110, 118, 77, 111, 100, 101, 0), - ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(15, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(102, 114, 97, 109, 101, 119, 111, 114), - ::capnp::word(107, 73, 110, 102, 101, 114, 101, 110), - ::capnp::word(99, 101, 0, 0, 0, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(101, 110, 103, 105, 110, 101, 115, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 2 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 3 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 4 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 5 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 6 => <::capnp::text_list::Owned as ::capnp::introspect::Introspect>::introspect(), - 7 => ::introspect(), - 8 => ::introspect(), - 9 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xea0b_3688_577e_30b4; - } - - #[repr(u16)] - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum EnvMode { - Loose = 0, - Strict = 1, - } - - impl ::capnp::introspect::Introspect for EnvMode { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Enum(::capnp::introspect::RawEnumSchema { - encoded_node: &env_mode::ENCODED_NODE, - annotation_types: env_mode::get_annotation_types, - }) - .into() - } - } - impl<'a> ::core::convert::From for ::capnp::dynamic_value::Reader<'a> { - fn from(e: EnvMode) -> Self { - ::capnp::dynamic_value::Enum::new( - e.into(), - ::capnp::introspect::RawEnumSchema { - encoded_node: &env_mode::ENCODED_NODE, - annotation_types: env_mode::get_annotation_types, - } - .into(), - ) - .into() - } - } - impl ::core::convert::TryFrom for EnvMode { - type Error = ::capnp::NotInSchema; - fn try_from( - value: u16, - ) -> ::core::result::Result>::Error> - { - match value { - 0 => ::core::result::Result::Ok(Self::Loose), - 1 => ::core::result::Result::Ok(Self::Strict), - n => ::core::result::Result::Err(::capnp::NotInSchema(n)), - } - } - } - impl From for u16 { - #[inline] - fn from(x: EnvMode) -> u16 { - x as u16 - } - } - impl ::capnp::traits::HasTypeId for EnvMode { - const TYPE_ID: u64 = 0xab42_00df_8263_c5d4u64; - } - mod env_mode { - pub static ENCODED_NODE: [::capnp::Word; 29] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(212, 197, 99, 130, 223, 0, 66, 171), - ::capnp::word(36, 0, 0, 0, 2, 0, 0, 0), - ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(98, 3, 0, 0, 145, 3, 0, 0), - ::capnp::word(21, 0, 0, 0, 98, 1, 0, 0), - ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(37, 0, 0, 0, 55, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), - ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), - ::capnp::word(98, 108, 101, 46, 69, 110, 118, 77), - ::capnp::word(111, 100, 101, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 1, 0, 2, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(17, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(9, 0, 0, 0, 58, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(108, 111, 111, 115, 101, 0, 0, 0), - ::capnp::word(115, 116, 114, 105, 99, 116, 0, 0), - ]; - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - } - - pub mod entry { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_value(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_value(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 0, - pointers: 2, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - _size: u32, - ) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(0).set_text(value); - } - #[inline] - pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(0).init_text(size) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_value(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_value(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(1).set_text(value); - } - #[inline] - pub fn init_value(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(1).init_text(size) - } - #[inline] - pub fn has_value(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 51] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(73, 207, 54, 68, 57, 61, 108, 221), - ::capnp::word(36, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(180, 48, 126, 87, 136, 54, 11, 234), - ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(149, 3, 0, 0, 205, 3, 0, 0), - ::capnp::word(21, 0, 0, 0, 82, 1, 0, 0), - ::capnp::word(41, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(37, 0, 0, 0, 119, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 71, 108, 111), - ::capnp::word(98, 97, 108, 72, 97, 115, 104, 97), - ::capnp::word(98, 108, 101, 46, 69, 110, 116, 114), - ::capnp::word(121, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(41, 0, 0, 0, 34, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(45, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xdd6c_3d39_4436_cf49; - } - } -} - -pub mod lock_file_packages { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_packages( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::package::Owned>, - > { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_packages(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 0, - pointers: 1, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_packages( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::package::Owned>, - > { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_packages( - &mut self, - value: ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::package::Owned>, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(0), - value, - false, - ) - } - #[inline] - pub fn init_packages( - self, - size: u32, - ) -> ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::package::Owned> { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(0), - size, - ) - } - #[inline] - pub fn has_packages(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 40] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(5, 35, 145, 20, 154, 180, 112, 180), - ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(209, 3, 0, 0, 10, 4, 0, 0), - ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), - ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(33, 0, 0, 0, 63, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 76, 111, 99), - ::capnp::word(107, 70, 105, 108, 101, 80, 97, 99), - ::capnp::word(107, 97, 103, 101, 115, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(4, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(13, 0, 0, 0, 74, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(40, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(112, 97, 99, 107, 97, 103, 101, 115), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(120, 27, 143, 105, 53, 137, 208, 194), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::struct_list::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xb470_b49a_1491_2305; - } -} - -pub mod package { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_version(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_version(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - #[inline] - pub fn get_found(self) -> bool { - self.reader.get_bool_field(0) - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 1, - pointers: 2, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(0).set_text(value); - } - #[inline] - pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(0).init_text(size) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_version(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_version(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(1).set_text(value); - } - #[inline] - pub fn init_version(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(1).init_text(size) - } - #[inline] - pub fn has_version(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - #[inline] - pub fn get_found(self) -> bool { - self.builder.get_bool_field(0) - } - #[inline] - pub fn set_found(&mut self, value: bool) { - self.builder.set_bool_field(0, value); - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 64] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(120, 27, 143, 105, 53, 137, 208, 194), - ::capnp::word(21, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 4, 0, 0, 84, 4, 0, 0), - ::capnp::word(21, 0, 0, 0, 234, 0, 0, 0), - ::capnp::word(33, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(29, 0, 0, 0, 175, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 80, 97, 99), - ::capnp::word(107, 97, 103, 101, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(12, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(69, 0, 0, 0, 34, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(64, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(76, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(73, 0, 0, 0, 66, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(68, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(80, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(2, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 2, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(77, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(72, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(84, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(118, 101, 114, 115, 105, 111, 110, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(102, 111, 117, 110, 100, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(1, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 2 => ::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1, 2]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xc2d0_8935_698f_1b78; - } -} - -pub mod file_hashes { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_file_hashes( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Reader<'a, crate::hash::proto_capnp::file_hashes::entry::Owned>, - > { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_file_hashes(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 0, - pointers: 1, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new(::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_file_hashes( - self, - ) -> ::capnp::Result< - ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::file_hashes::entry::Owned>, - > { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_file_hashes( - &mut self, - value: ::capnp::struct_list::Reader< - 'a, - crate::hash::proto_capnp::file_hashes::entry::Owned, - >, - ) -> ::capnp::Result<()> { - ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.reborrow().get_pointer_field(0), - value, - false, - ) - } - #[inline] - pub fn init_file_hashes( - self, - size: u32, - ) -> ::capnp::struct_list::Builder<'a, crate::hash::proto_capnp::file_hashes::entry::Owned> - { - ::capnp::traits::FromPointerBuilder::init_pointer( - self.builder.get_pointer_field(0), - size, - ) - } - #[inline] - pub fn has_file_hashes(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 42] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(143, 27, 194, 114, 193, 13, 17, 237), - ::capnp::word(21, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(99, 176, 174, 73, 1, 230, 221, 225), - ::capnp::word(1, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(86, 4, 0, 0, 197, 4, 0, 0), - ::capnp::word(21, 0, 0, 0, 2, 1, 0, 0), - ::capnp::word(33, 0, 0, 0, 23, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(41, 0, 0, 0, 63, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 70, 105, 108), - ::capnp::word(101, 72, 97, 115, 104, 101, 115, 0), - ::capnp::word(4, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), - ::capnp::word(1, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), - ::capnp::word(4, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(13, 0, 0, 0, 90, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(40, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(102, 105, 108, 101, 72, 97, 115, 104), - ::capnp::word(101, 115, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(16, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(14, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::struct_list::Owned< - crate::hash::proto_capnp::file_hashes::entry::Owned, - > as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0xed11_0dc1_72c2_1b8f; - } - - pub mod entry { - #[derive(Copy, Clone)] - pub struct Owned(()); - impl ::capnp::introspect::Introspect for Owned { - fn introspect() -> ::capnp::introspect::Type { - ::capnp::introspect::TypeVariant::Struct( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ) - .into() - } - } - impl ::capnp::traits::Owned for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::OwnedStruct for Owned { - type Reader<'a> = Reader<'a>; - type Builder<'a> = Builder<'a>; - } - impl ::capnp::traits::Pipelined for Owned { - type Pipeline = Pipeline; - } - - pub struct Reader<'a> { - reader: ::capnp::private::layout::StructReader<'a>, - } - impl<'a> ::core::marker::Copy for Reader<'a> {} - impl<'a> ::core::clone::Clone for Reader<'a> { - fn clone(&self) -> Self { - *self - } - } - - impl<'a> ::capnp::traits::HasTypeId for Reader<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructReader<'a>> for Reader<'a> { - fn from(reader: ::capnp::private::layout::StructReader<'a>) -> Self { - Self { reader } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Reader<'a> { - fn from(reader: Reader<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Reader::new( - reader.reader, - ::capnp::schema::StructSchema::new( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ), - )) - } - } - - impl<'a> ::core::fmt::Debug for Reader<'a> { - fn fmt( - &self, - f: &mut ::core::fmt::Formatter<'_>, - ) -> ::core::result::Result<(), ::core::fmt::Error> { - core::fmt::Debug::fmt( - &::core::convert::Into::<::capnp::dynamic_value::Reader<'_>>::into(*self), - f, - ) - } - } - - impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> { - fn get_from_pointer( - reader: &::capnp::private::layout::PointerReader<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok(reader.get_struct(default)?.into()) - } - } - - impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> { - fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> { - self.reader - } - } - - impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> { - fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) { - self.reader - .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table)) - } - } - - impl<'a> Reader<'a> { - pub fn reborrow(&self) -> Reader<'_> { - Self { ..*self } - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.reader.total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.reader.get_pointer_field(0).is_null() - } - #[inline] - pub fn get_value(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { - ::capnp::traits::FromPointerReader::get_from_pointer( - &self.reader.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn has_value(&self) -> bool { - !self.reader.get_pointer_field(1).is_null() - } - } - - pub struct Builder<'a> { - builder: ::capnp::private::layout::StructBuilder<'a>, - } - impl<'a> ::capnp::traits::HasStructSize for Builder<'a> { - const STRUCT_SIZE: ::capnp::private::layout::StructSize = - ::capnp::private::layout::StructSize { - data: 0, - pointers: 2, - }; - } - impl<'a> ::capnp::traits::HasTypeId for Builder<'a> { - const TYPE_ID: u64 = _private::TYPE_ID; - } - impl<'a> ::core::convert::From<::capnp::private::layout::StructBuilder<'a>> for Builder<'a> { - fn from(builder: ::capnp::private::layout::StructBuilder<'a>) -> Self { - Self { builder } - } - } - - impl<'a> ::core::convert::From> for ::capnp::dynamic_value::Builder<'a> { - fn from(builder: Builder<'a>) -> Self { - Self::Struct(::capnp::dynamic_struct::Builder::new( - builder.builder, - ::capnp::schema::StructSchema::new( - ::capnp::introspect::RawBrandedStructSchema { - generic: &_private::RAW_SCHEMA, - field_types: _private::get_field_types, - annotation_types: _private::get_annotation_types, - }, - ), - )) - } - } - - impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> { - fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) { - self.builder - .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table)) - } - } - - impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> { - fn init_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - _size: u32, - ) -> Self { - builder - .init_struct(::STRUCT_SIZE) - .into() - } - fn get_from_pointer( - builder: ::capnp::private::layout::PointerBuilder<'a>, - default: ::core::option::Option<&'a [::capnp::Word]>, - ) -> ::capnp::Result { - ::core::result::Result::Ok( - builder - .get_struct( - ::STRUCT_SIZE, - default, - )? - .into(), - ) - } - } - - impl<'a> ::capnp::traits::SetPointerBuilder for Reader<'a> { - fn set_pointer_builder( - mut pointer: ::capnp::private::layout::PointerBuilder<'_>, - value: Self, - canonicalize: bool, - ) -> ::capnp::Result<()> { - pointer.set_struct(&value.reader, canonicalize) - } - } - - impl<'a> Builder<'a> { - pub fn into_reader(self) -> Reader<'a> { - self.builder.into_reader().into() - } - pub fn reborrow(&mut self) -> Builder<'_> { - Builder { - builder: self.builder.reborrow(), - } - } - pub fn reborrow_as_reader(&self) -> Reader<'_> { - self.builder.as_reader().into() - } - - pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> { - self.builder.as_reader().total_size() - } - #[inline] - pub fn get_key(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(0), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_key(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(0).set_text(value); - } - #[inline] - pub fn init_key(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(0).init_text(size) - } - #[inline] - pub fn has_key(&self) -> bool { - !self.builder.is_pointer_field_null(0) - } - #[inline] - pub fn get_value(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { - ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), - ::core::option::Option::None, - ) - } - #[inline] - pub fn set_value(&mut self, value: ::capnp::text::Reader<'_>) { - self.builder.reborrow().get_pointer_field(1).set_text(value); - } - #[inline] - pub fn init_value(self, size: u32) -> ::capnp::text::Builder<'a> { - self.builder.get_pointer_field(1).init_text(size) - } - #[inline] - pub fn has_value(&self) -> bool { - !self.builder.is_pointer_field_null(1) - } - } - - pub struct Pipeline { - _typeless: ::capnp::any_pointer::Pipeline, - } - impl ::capnp::capability::FromTypelessPipeline for Pipeline { - fn new(typeless: ::capnp::any_pointer::Pipeline) -> Self { - Self { - _typeless: typeless, - } - } - } - impl Pipeline {} - mod _private { - pub static ENCODED_NODE: [::capnp::Word; 50] = [ - ::capnp::word(0, 0, 0, 0, 6, 0, 6, 0), - ::capnp::word(153, 157, 184, 61, 67, 247, 50, 137), - ::capnp::word(32, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(143, 27, 194, 114, 193, 13, 17, 237), - ::capnp::word(2, 0, 7, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(139, 4, 0, 0, 195, 4, 0, 0), - ::capnp::word(21, 0, 0, 0, 50, 1, 0, 0), - ::capnp::word(37, 0, 0, 0, 7, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(33, 0, 0, 0, 119, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(115, 114, 99, 47, 104, 97, 115, 104), - ::capnp::word(47, 112, 114, 111, 116, 111, 46, 99), - ::capnp::word(97, 112, 110, 112, 58, 70, 105, 108), - ::capnp::word(101, 72, 97, 115, 104, 101, 115, 46), - ::capnp::word(69, 110, 116, 114, 121, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 1, 0, 1, 0), - ::capnp::word(8, 0, 0, 0, 3, 0, 4, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(41, 0, 0, 0, 34, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(36, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(48, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(1, 0, 0, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 1, 0, 1, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(45, 0, 0, 0, 50, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(40, 0, 0, 0, 3, 0, 1, 0), - ::capnp::word(52, 0, 0, 0, 2, 0, 1, 0), - ::capnp::word(107, 101, 121, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(118, 97, 108, 117, 101, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(12, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ::capnp::word(0, 0, 0, 0, 0, 0, 0, 0), - ]; - pub fn get_field_types(index: u16) -> ::capnp::introspect::Type { - match index { - 0 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - 1 => <::capnp::text::Owned as ::capnp::introspect::Introspect>::introspect(), - _ => panic!("invalid field index {}", index), - } - } - pub fn get_annotation_types( - child_index: Option, - index: u32, - ) -> ::capnp::introspect::Type { - panic!("invalid annotation indices ({:?}, {}) ", child_index, index) - } - pub static RAW_SCHEMA: ::capnp::introspect::RawStructSchema = - ::capnp::introspect::RawStructSchema { - encoded_node: &ENCODED_NODE, - nonunion_members: NONUNION_MEMBERS, - members_by_discriminant: MEMBERS_BY_DISCRIMINANT, - }; - pub static NONUNION_MEMBERS: &[u16] = &[0, 1]; - pub static MEMBERS_BY_DISCRIMINANT: &[u16] = &[]; - pub const TYPE_ID: u64 = 0x8932_f743_3db8_9d99; - } - } -} From 29a4de436f079b0f0acc3b92005b6265d193c488 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:10:13 -0700 Subject: [PATCH 17/29] Hide otel behind a feature flag --- .devcontainer/devcontainer.json | 9 +++------ CONTRIBUTING.md | 12 +++++++++++- crates/turborepo-lib/Cargo.toml | 3 ++- crates/turborepo-lib/src/observability/mod.rs | 7 +++++++ .../turborepo-lib/src/observability/otel_disabled.rs | 7 +++++++ crates/turborepo-lib/src/run/builder.rs | 12 ++++++------ crates/turborepo/Cargo.toml | 1 + 7 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 crates/turborepo-lib/src/observability/otel_disabled.rs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index ba7d10135d950..80583d8eb8821 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,11 +4,7 @@ "dockerfile": "Dockerfile", "context": "." }, - "runArgs": [ - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined" - ], + "runArgs": ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], "features": { "ghcr.io/devcontainers/features/github-cli:1": {}, "ghcr.io/devcontainers/features/git:1": {} @@ -26,6 +22,7 @@ ], "settings": { "rust-analyzer.cargo.buildScripts.enable": true, + "rust-analyzer.cargo.features": ["otel"], "rust-analyzer.checkOnSave.command": "clippy", "rust-analyzer.rustfmt.rangeFormatting.enable": true, "editor.defaultFormatter": "esbenp.prettier-vscode", @@ -48,4 +45,4 @@ "source=${localWorkspaceFolder}/.devcontainer/cache,target=/home/vscode/.cache,type=bind,consistency=cached", "source=${localWorkspaceFolder}/.devcontainer/cargo,target=/usr/local/cargo,type=bind,consistency=cached" ] -} \ No newline at end of file +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 34c9137adcb01..fa55264793915 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ Thank you for your interest in contributing to Turborepo! - [General dependencies](#general-dependencies) - - [Optional dependencies](#optional-dependencies) +- [Optional dependencies](#optional-dependencies) - [Structure of the repository](#structure-of-the-repository) - [Building Turborepo](#building-turborepo) - [TLS Implementation](#tls-implementation) @@ -69,6 +69,16 @@ and `rustls-tls` features. By default, the `rustls-tls` feature is selected so that `cargo build` works out of the box. If you wish to select `native-tls`, you may do so by running `cargo build --no-default-features --features native-tls`. +### OpenTelemetry Observability + +Turborepo includes optional OpenTelemetry (OTel) support for exporting metrics. OTel is an experimental feature and is **not** included in default builds. If you wish to build `turbo` with OTel support, you can enable it by running: + +```bash +cargo build -p turbo --features otel +``` + +Note that when OTel is disabled at compile time (the default), the `experimentalObservability` configuration in `turbo.json` and related CLI flags will be ignored (they will not error, but no metrics will be exported). IDEs using the devcontainer configuration will have OTel enabled automatically for development purposes. + ## Running tests > [!IMPORTANT] diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index fc8a3b651acb9..12c8c2a366cb3 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -13,6 +13,7 @@ rustls-tls = ["turborepo-api-client/rustls-tls", "turbo-updater/rustls-tls"] daemon-package-discovery = [] daemon-file-hashing = [] +otel = ["dep:turborepo-otel"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dev-dependencies] @@ -138,7 +139,7 @@ turborepo-graph-utils = { path = "../turborepo-graph-utils" } turborepo-lockfiles = { workspace = true } turborepo-microfrontends = { workspace = true } turborepo-microfrontends-proxy = { workspace = true } -turborepo-otel = { workspace = true } +turborepo-otel = { workspace = true, optional = true } turborepo-process = { workspace = true } turborepo-repository = { path = "../turborepo-repository" } turborepo-scm = { workspace = true, features = ["git2"] } diff --git a/crates/turborepo-lib/src/observability/mod.rs b/crates/turborepo-lib/src/observability/mod.rs index 0e872d45508de..3cb92c205b347 100644 --- a/crates/turborepo-lib/src/observability/mod.rs +++ b/crates/turborepo-lib/src/observability/mod.rs @@ -22,8 +22,15 @@ use std::sync::Arc; use crate::{config::ExperimentalObservabilityOptions, run::summary::RunSummary}; +#[cfg(feature = "otel")] mod otel; +#[cfg(not(feature = "otel"))] +mod otel_disabled; + +#[cfg(not(feature = "otel"))] +use otel_disabled as otel; + /// Trait for observing completed Turborepo runs, allowing different /// observability backends like OpenTelemetry to be plugged in. pub(crate) trait RunObserver: Send + Sync { diff --git a/crates/turborepo-lib/src/observability/otel_disabled.rs b/crates/turborepo-lib/src/observability/otel_disabled.rs new file mode 100644 index 0000000000000..32dedf4f35cbe --- /dev/null +++ b/crates/turborepo-lib/src/observability/otel_disabled.rs @@ -0,0 +1,7 @@ +use crate::config::ExperimentalOtelOptions; + +/// Initialize an OpenTelemetry observability handle from configuration options. +/// Returns `None` when OTel is disabled at compile time. +pub(crate) fn try_init_otel(_options: &ExperimentalOtelOptions) -> Option { + None +} diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 88d40440c875e..42caba50edbe2 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -8,7 +8,7 @@ use std::{ use chrono::Local; use tracing::debug; use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf}; -use turborepo_analytics::{start_analytics, AnalyticsHandle, AnalyticsSender}; +use turborepo_analytics::{AnalyticsHandle, AnalyticsSender, start_analytics}; use turborepo_api_client::{APIAuth, APIClient}; use turborepo_cache::AsyncCache; use turborepo_env::EnvironmentVariableMap; @@ -24,10 +24,10 @@ use turborepo_scm::SCM; use turborepo_signals::SignalHandler; use turborepo_task_id::TaskName; use turborepo_telemetry::events::{ + EventBuilder, TrackedErrors, command::CommandEventBuilder, generic::{DaemonInitStatus, GenericEventBuilder}, repo::{RepoEventBuilder, RepoType}, - EventBuilder, TrackedErrors, }; use turborepo_ui::{ColorConfig, ColorSelector}; #[cfg(feature = "daemon-package-discovery")] @@ -40,17 +40,17 @@ use { }; use crate::{ + DaemonConnector, cli::DryRunMode, commands::CommandBase, config::resolve_turbo_config_path, engine::{Engine, EngineBuilder}, microfrontends::MicrofrontendsConfigs, - observability::Handle as ObservabilityHandle, + observability, opts::Opts, - run::{scope, task_access::TaskAccess, Error, Run, RunCache}, + run::{Error, Run, RunCache, scope, task_access::TaskAccess}, shim::TurboState, turbo_json::{TurboJson, TurboJsonLoader, TurboJsonReader, UIMode}, - DaemonConnector, }; pub struct RunBuilder { @@ -485,7 +485,7 @@ impl RunBuilder { .unwrap_or_else(|| self.will_execute_tasks()); let observability_handle = match self.opts.experimental_observability.as_ref() { - Some(opts) => ObservabilityHandle::try_init(opts), + Some(opts) => observability::Handle::try_init(opts), None => None, }; diff --git a/crates/turborepo/Cargo.toml b/crates/turborepo/Cargo.toml index c38a3018992ee..26b47fd8fa6c4 100644 --- a/crates/turborepo/Cargo.toml +++ b/crates/turborepo/Cargo.toml @@ -13,6 +13,7 @@ default = ["rustls-tls", "turborepo-lib/daemon-package-discovery"] native-tls = ["turborepo-lib/native-tls"] rustls-tls = ["turborepo-lib/rustls-tls"] pprof = ["turborepo-lib/pprof"] +otel = ["turborepo-lib/otel"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [build-dependencies] From 04e22fcffb9395011be676f91916f5803e4ae7a3 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:14:29 -0700 Subject: [PATCH 18/29] Add comments to explain the pub(crate) properties --- crates/turborepo-lib/src/run/summary/execution.rs | 6 ++++++ crates/turborepo-lib/src/run/summary/mod.rs | 10 +++++++++- crates/turborepo-lib/src/run/summary/scm.rs | 2 ++ crates/turborepo-lib/src/run/summary/task.rs | 5 +++++ crates/turborepo-lib/src/turbo_json/mod.rs | 2 +- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/turborepo-lib/src/run/summary/execution.rs b/crates/turborepo-lib/src/run/summary/execution.rs index d09c6dd90bc80..b3ef0758752c3 100644 --- a/crates/turborepo-lib/src/run/summary/execution.rs +++ b/crates/turborepo-lib/src/run/summary/execution.rs @@ -39,10 +39,13 @@ pub struct ExecutionSummary<'a> { cached: usize, // number of tasks that started attempted: usize, + // Used in observability/otel.rs to calculate duration_ms pub(crate) start_time: i64, + // Used in observability/otel.rs to calculate duration_ms pub(crate) end_time: i64, #[serde(skip)] duration: TurboDuration, + // Used in observability/otel.rs to populate RunMetricsPayload pub(crate) exit_code: i32, } @@ -166,14 +169,17 @@ impl<'a> ExecutionSummary<'a> { self.success + self.cached } + // Used in observability/otel.rs to populate RunMetricsPayload.attempted_tasks pub(crate) fn attempted(&self) -> usize { self.attempted } + // Used in observability/otel.rs to populate RunMetricsPayload.failed_tasks pub(crate) fn failed(&self) -> usize { self.failed } + // Used in observability/otel.rs to populate RunMetricsPayload.cached_tasks pub(crate) fn cached(&self) -> usize { self.cached } diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index e89d11db83459..81b6c45f72bfa 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -29,7 +29,10 @@ use turborepo_scm::SCM; use turborepo_task_id::TaskId; use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; -pub(crate) use self::task::{CacheStatus, TaskSummary}; +#[allow(unused_imports)] +pub(crate) use self::task::CacheStatus; +// Re-exported for use in observability/otel.rs +pub(crate) use self::task::TaskSummary; use self::{ execution::TaskState, task::SinglePackageTaskSummary, task_factory::TaskSummaryFactory, }; @@ -317,22 +320,27 @@ impl<'a> From<&'a RunSummary<'a>> for SinglePackageRunSummary<'a> { } impl<'a> RunSummary<'a> { + // Used in observability/otel.rs to populate RunMetricsPayload.run_id pub(crate) fn id(&self) -> &Ksuid { &self.id } + // Used in observability/otel.rs to populate RunMetricsPayload.turbo_version pub(crate) fn turbo_version(&self) -> &'static str { self.turbo_version } + // Used in observability/otel.rs to access execution summary for metrics pub(crate) fn execution_summary(&self) -> Option<&ExecutionSummary<'a>> { self.execution.as_ref() } + // Used in observability/otel.rs to iterate over tasks for TaskMetricsPayload pub(crate) fn tasks(&self) -> &[TaskSummary] { &self.tasks } + // Used in observability/otel.rs to populate RunMetricsPayload SCM fields pub(crate) fn scm_state(&self) -> &SCMState { &self.scm } diff --git a/crates/turborepo-lib/src/run/summary/scm.rs b/crates/turborepo-lib/src/run/summary/scm.rs index 35d45854afd99..781693398eb6a 100644 --- a/crates/turborepo-lib/src/run/summary/scm.rs +++ b/crates/turborepo-lib/src/run/summary/scm.rs @@ -51,10 +51,12 @@ impl SCMState { state } + // Used in observability/otel.rs to populate RunMetricsPayload.scm_branch pub(crate) fn branch(&self) -> Option<&str> { self.branch.as_deref() } + // Used in observability/otel.rs to populate RunMetricsPayload.scm_revision pub(crate) fn sha(&self) -> Option<&str> { self.sha.as_deref() } diff --git a/crates/turborepo-lib/src/run/summary/task.rs b/crates/turborepo-lib/src/run/summary/task.rs index 8f33107473a01..a8cb2f874730e 100644 --- a/crates/turborepo-lib/src/run/summary/task.rs +++ b/crates/turborepo-lib/src/run/summary/task.rs @@ -29,6 +29,7 @@ pub struct TaskCacheSummary { #[derive(Debug, Serialize, Copy, Clone)] #[serde(rename_all = "UPPERCASE")] +// Used in observability/otel.rs to map to TaskCacheStatus pub(crate) enum CacheStatus { Hit, Miss, @@ -122,14 +123,18 @@ pub struct TaskEnvVarSummary { } impl TaskCacheSummary { + // Used in observability/otel.rs to populate TaskMetricsPayload.cache_status pub(crate) fn status(&self) -> CacheStatus { self.status } + // Used in observability/otel.rs to populate + // TaskMetricsPayload.cache_time_saved_ms pub(crate) fn time_saved(&self) -> u64 { self.time_saved } + // Used in observability/otel.rs to populate TaskMetricsPayload.cache_source pub(crate) fn cache_source_label(&self) -> Option<&'static str> { self.source.map(|source| match source { CacheSource::Local => "LOCAL", diff --git a/crates/turborepo-lib/src/turbo_json/mod.rs b/crates/turborepo-lib/src/turbo_json/mod.rs index 80bbd03279aee..e3718e69e4a94 100644 --- a/crates/turborepo-lib/src/turbo_json/mod.rs +++ b/crates/turborepo-lib/src/turbo_json/mod.rs @@ -1174,6 +1174,6 @@ mod tests { let deps = boundaries.dependencies.as_ref().unwrap(); assert!(deps.allow.is_some()); assert!(deps.deny.is_none()); // This should be None, not serialized as - // null + // null } } From 9352150eadfeb54b562471b6c8a9c927704a402e Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:17:04 -0700 Subject: [PATCH 19/29] Minor cleanup --- crates/turborepo-lib/src/run/summary/execution.rs | 5 +---- crates/turborepo-lib/src/run/summary/mod.rs | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/crates/turborepo-lib/src/run/summary/execution.rs b/crates/turborepo-lib/src/run/summary/execution.rs index b3ef0758752c3..ff9ad208e71c7 100644 --- a/crates/turborepo-lib/src/run/summary/execution.rs +++ b/crates/turborepo-lib/src/run/summary/execution.rs @@ -5,7 +5,7 @@ use serde::Serialize; use tokio::sync::mpsc; use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath}; use turborepo_task_id::TaskId; -use turborepo_ui::{color, cprintln, ColorConfig, BOLD, BOLD_GREEN, BOLD_RED, MAGENTA, YELLOW}; +use turborepo_ui::{BOLD, BOLD_GREEN, BOLD_RED, ColorConfig, MAGENTA, YELLOW, color, cprintln}; use super::TurboDuration; use crate::run::summary::task::TaskSummary; @@ -39,13 +39,10 @@ pub struct ExecutionSummary<'a> { cached: usize, // number of tasks that started attempted: usize, - // Used in observability/otel.rs to calculate duration_ms pub(crate) start_time: i64, - // Used in observability/otel.rs to calculate duration_ms pub(crate) end_time: i64, #[serde(skip)] duration: TurboDuration, - // Used in observability/otel.rs to populate RunMetricsPayload pub(crate) exit_code: i32, } diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index 81b6c45f72bfa..cc8ec08e7d76d 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -27,12 +27,9 @@ use turborepo_env::EnvironmentVariableMap; use turborepo_repository::package_graph::{PackageGraph, PackageName}; use turborepo_scm::SCM; use turborepo_task_id::TaskId; -use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; +use turborepo_ui::{BOLD, BOLD_CYAN, ColorConfig, GREY, color, cprintln, cwriteln}; -#[allow(unused_imports)] -pub(crate) use self::task::CacheStatus; -// Re-exported for use in observability/otel.rs -pub(crate) use self::task::TaskSummary; +pub(crate) use self::task::TaskSummary; // Re-exported for use in observability/otel.rs use self::{ execution::TaskState, task::SinglePackageTaskSummary, task_factory::TaskSummaryFactory, }; From c865c45339a8574a86599eca93961e68f4709217 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:18:21 -0700 Subject: [PATCH 20/29] Remove an accidental formatting-only change --- crates/turborepo-lib/src/run/summary/execution.rs | 2 +- crates/turborepo-lib/src/run/summary/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/turborepo-lib/src/run/summary/execution.rs b/crates/turborepo-lib/src/run/summary/execution.rs index ff9ad208e71c7..04dbbda581d50 100644 --- a/crates/turborepo-lib/src/run/summary/execution.rs +++ b/crates/turborepo-lib/src/run/summary/execution.rs @@ -5,7 +5,7 @@ use serde::Serialize; use tokio::sync::mpsc; use turbopath::{AbsoluteSystemPathBuf, AnchoredSystemPath}; use turborepo_task_id::TaskId; -use turborepo_ui::{BOLD, BOLD_GREEN, BOLD_RED, ColorConfig, MAGENTA, YELLOW, color, cprintln}; +use turborepo_ui::{color, cprintln, ColorConfig, BOLD, BOLD_GREEN, BOLD_RED, MAGENTA, YELLOW}; use super::TurboDuration; use crate::run::summary::task::TaskSummary; diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index cc8ec08e7d76d..0614c57ae285b 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -27,7 +27,7 @@ use turborepo_env::EnvironmentVariableMap; use turborepo_repository::package_graph::{PackageGraph, PackageName}; use turborepo_scm::SCM; use turborepo_task_id::TaskId; -use turborepo_ui::{BOLD, BOLD_CYAN, ColorConfig, GREY, color, cprintln, cwriteln}; +use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; pub(crate) use self::task::TaskSummary; // Re-exported for use in observability/otel.rs use self::{ From e1b9cbacb8fb1c5d493dd2f45733ea38223fe5e9 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:19:49 -0700 Subject: [PATCH 21/29] Fix more unintentional formatting changes --- crates/turborepo-lib/src/run/builder.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 42caba50edbe2..ccbaccfd595c6 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -8,7 +8,7 @@ use std::{ use chrono::Local; use tracing::debug; use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf}; -use turborepo_analytics::{AnalyticsHandle, AnalyticsSender, start_analytics}; +use turborepo_analytics::{start_analytics, AnalyticsHandle, AnalyticsSender}; use turborepo_api_client::{APIAuth, APIClient}; use turborepo_cache::AsyncCache; use turborepo_env::EnvironmentVariableMap; @@ -24,10 +24,10 @@ use turborepo_scm::SCM; use turborepo_signals::SignalHandler; use turborepo_task_id::TaskName; use turborepo_telemetry::events::{ - EventBuilder, TrackedErrors, command::CommandEventBuilder, generic::{DaemonInitStatus, GenericEventBuilder}, repo::{RepoEventBuilder, RepoType}, + EventBuilder, TrackedErrors, }; use turborepo_ui::{ColorConfig, ColorSelector}; #[cfg(feature = "daemon-package-discovery")] @@ -40,7 +40,6 @@ use { }; use crate::{ - DaemonConnector, cli::DryRunMode, commands::CommandBase, config::resolve_turbo_config_path, @@ -48,9 +47,10 @@ use crate::{ microfrontends::MicrofrontendsConfigs, observability, opts::Opts, - run::{Error, Run, RunCache, scope, task_access::TaskAccess}, + run::{scope, task_access::TaskAccess, Error, Run, RunCache}, shim::TurboState, turbo_json::{TurboJson, TurboJsonLoader, TurboJsonReader, UIMode}, + DaemonConnector, }; pub struct RunBuilder { From 1d3849780c12ed9221ef68372a34f2fcfa5dc8e4 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 13:38:20 -0700 Subject: [PATCH 22/29] Fixes for new test cases --- .../tests/other/experimental-otel.t | 82 +++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/turborepo-tests/integration/tests/other/experimental-otel.t b/turborepo-tests/integration/tests/other/experimental-otel.t index 5731bf52efdf3..7e271b82f108f 100644 --- a/turborepo-tests/integration/tests/other/experimental-otel.t +++ b/turborepo-tests/integration/tests/other/experimental-otel.t @@ -5,32 +5,104 @@ Test that OTEL exporter can be enabled via environment variables $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 $ ${TURBO} run build --filter=my-app - .*build.*my-app (re) + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache miss, executing .* (re) + my-app:build: + my-app:build: > build + my-app:build: > echo building + my-app:build: + my-app:build: building + + + Tasks: 1 successful, 1 total + Cached: 0 cached, 1 total + Time:\s*[\.0-9]+m?s (re) + + WARNING no output files found for task my-app#build. Please check your `outputs` key in `turbo.json` + [0] Test that OTEL exporter can be enabled via CLI flags $ unset TURBO_EXPERIMENTAL_OTEL_ENABLED $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 - .*build.*my-app (re) + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache hit, replaying logs .* (re) + my-app:build: + my-app:build: > build + my-app:build: > echo building + my-app:build: + my-app:build: building + + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) + [0] Test that OTEL exporter works with http/protobuf protocol $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 --experimental-otel-protocol=http-protobuf - .*build.*my-app (re) + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache hit, replaying logs .* (re) + my-app:build: + my-app:build: > build + my-app:build: > echo building + my-app:build: + my-app:build: building + + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) + [0] Test that OTEL exporter can be disabled via environment variable $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=0 $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 $ ${TURBO} run build --filter=my-app - .*build.*my-app (re) + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache hit, replaying logs .* (re) + my-app:build: + my-app:build: > build + my-app:build: > echo building + my-app:build: + my-app:build: building + + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) + [0] Test that OTEL exporter requires endpoint when enabled $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT $ ${TURBO} run build --filter=my-app - .*build.*my-app (re) + \xe2\x80\xa2 Packages in scope: my-app (esc) + \xe2\x80\xa2 Running build in 1 packages (esc) + \xe2\x80\xa2 Remote caching disabled (esc) + my-app:build: cache hit, replaying logs .* (re) + my-app:build: + my-app:build: > build + my-app:build: > echo building + my-app:build: + my-app:build: building + + + Tasks: 1 successful, 1 total + Cached: 1 cached, 1 total + Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) + [0] From f8181608e659353df390a52600a0b6ed27f26155 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 14:09:06 -0700 Subject: [PATCH 23/29] Integration test and documentation updates --- crates/turborepo-lib/src/cli/observability.rs | 35 +++++++ .../src/config/experimental_otel.rs | 44 +++++++++ .../turborepo-lib/src/observability/otel.rs | 99 +++++++++++++++++++ .../content/docs/reference/configuration.mdx | 13 ++- .../tests/other/experimental-otel.t | 21 ++-- 5 files changed, 201 insertions(+), 11 deletions(-) diff --git a/crates/turborepo-lib/src/cli/observability.rs b/crates/turborepo-lib/src/cli/observability.rs index d7db092fac0cc..9270281d226a5 100644 --- a/crates/turborepo-lib/src/cli/observability.rs +++ b/crates/turborepo-lib/src/cli/observability.rs @@ -146,6 +146,17 @@ mod tests { assert_eq!(result.unwrap().enabled, Some(true)); } + #[test] + fn test_experimental_otel_cli_args_disabled() { + let args = ExperimentalOtelCliArgs { + enabled: Some(false), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + assert_eq!(result.unwrap().enabled, Some(false)); + } + #[test] fn test_experimental_otel_cli_args_protocol() { let args = ExperimentalOtelCliArgs { @@ -309,6 +320,30 @@ mod tests { assert_eq!(metrics.task_details, Some(false)); } + #[test] + fn test_experimental_otel_cli_args_metrics_run_summary_disabled() { + let args = ExperimentalOtelCliArgs { + metrics_run_summary: Some(false), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(false)); + } + + #[test] + fn test_experimental_otel_cli_args_metrics_task_details_disabled() { + let args = ExperimentalOtelCliArgs { + metrics_task_details: Some(false), + ..Default::default() + }; + let result = args.to_config(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.task_details, Some(false)); + } + #[test] fn test_experimental_otel_cli_args_combined() { let args = ExperimentalOtelCliArgs { diff --git a/crates/turborepo-lib/src/config/experimental_otel.rs b/crates/turborepo-lib/src/config/experimental_otel.rs index 9d16c638f58a6..bc7d579da9eaf 100644 --- a/crates/turborepo-lib/src/config/experimental_otel.rs +++ b/crates/turborepo-lib/src/config/experimental_otel.rs @@ -458,6 +458,50 @@ mod tests { assert_eq!(metrics.task_details, Some(false)); } + #[test] + fn test_from_env_map_enabled_with_endpoint() { + let map = build_env_map(&[ + ("experimental_otel_enabled", "1"), + ("experimental_otel_endpoint", "https://example.com/otel"), + ]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let opts = result.unwrap(); + assert_eq!(opts.enabled, Some(true)); + assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); + } + + #[test] + fn test_from_env_map_disabled_with_endpoint() { + let map = build_env_map(&[ + ("experimental_otel_enabled", "0"), + ("experimental_otel_endpoint", "https://example.com/otel"), + ]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let opts = result.unwrap(); + assert_eq!(opts.enabled, Some(false)); + assert_eq!(opts.endpoint, Some("https://example.com/otel".to_string())); + } + + #[test] + fn test_from_env_map_metrics_run_summary_disabled() { + let map = build_env_map(&[("experimental_otel_metrics_run_summary", "0")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.run_summary, Some(false)); + } + + #[test] + fn test_from_env_map_metrics_task_details_disabled() { + let map = build_env_map(&[("experimental_otel_metrics_task_details", "0")]); + let result = ExperimentalOtelOptions::from_env_map(&map).unwrap(); + assert!(result.is_some()); + let metrics = result.unwrap().metrics.unwrap(); + assert_eq!(metrics.task_details, Some(false)); + } + #[test] fn test_from_env_map_combined() { let map = build_env_map(&[ diff --git a/crates/turborepo-lib/src/observability/otel.rs b/crates/turborepo-lib/src/observability/otel.rs index 88093db0ed082..4dc34f549f5f2 100644 --- a/crates/turborepo-lib/src/observability/otel.rs +++ b/crates/turborepo-lib/src/observability/otel.rs @@ -172,6 +172,17 @@ mod tests { assert!(result.is_none()); } + #[test] + fn test_config_from_options_enabled_false_with_endpoint() { + let options = ExperimentalOtelOptions { + enabled: Some(false), + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; + let result = config_from_options(&options); + assert!(result.is_none()); + } + #[test] fn test_config_from_options_no_endpoint() { let options = ExperimentalOtelOptions::default(); @@ -205,6 +216,44 @@ mod tests { assert!(!config.metrics.task_details); } + #[test] + fn test_config_from_options_enabled_none_with_endpoint() { + let options = ExperimentalOtelOptions { + enabled: None, + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; + let result = config_from_options(&options); + assert!(result.is_some()); + let config = result.unwrap(); + assert_eq!(config.endpoint, "https://example.com/otel"); + assert_eq!(config.protocol, turborepo_otel::Protocol::Grpc); + assert!(config.metrics.run_summary); + assert!(!config.metrics.task_details); + } + + #[test] + fn test_config_from_options_enabled_true_no_endpoint() { + let options = ExperimentalOtelOptions { + enabled: Some(true), + endpoint: None, + ..Default::default() + }; + let result = config_from_options(&options); + assert!(result.is_none()); + } + + #[test] + fn test_config_from_options_enabled_true_whitespace_endpoint() { + let options = ExperimentalOtelOptions { + enabled: Some(true), + endpoint: Some(" ".to_string()), + ..Default::default() + }; + let result = config_from_options(&options); + assert!(result.is_none()); + } + #[test] fn test_config_from_options_http_protobuf() { let options = ExperimentalOtelOptions { @@ -298,4 +347,54 @@ mod tests { assert!(result.run_summary); assert!(result.task_details); } + + #[test] + fn test_config_from_options_metrics_toggles() { + let options = ExperimentalOtelOptions { + endpoint: Some("https://example.com/otel".to_string()), + metrics: Some(ExperimentalOtelMetricsOptions { + run_summary: Some(false), + task_details: Some(true), + }), + ..Default::default() + }; + let result = config_from_options(&options); + assert!(result.is_some()); + let config = result.unwrap(); + assert!(!config.metrics.run_summary); + assert!(config.metrics.task_details); + } + + #[test] + fn test_try_init_otel_swallows_initialization_errors() { + let options = ExperimentalOtelOptions { + enabled: Some(true), + endpoint: Some("invalid://endpoint".to_string()), + ..Default::default() + }; + let result = try_init_otel(&options); + assert!(result.is_none()); + } + + #[test] + fn test_try_init_otel_returns_none_for_disabled() { + let options = ExperimentalOtelOptions { + enabled: Some(false), + endpoint: Some("https://example.com/otel".to_string()), + ..Default::default() + }; + let result = try_init_otel(&options); + assert!(result.is_none()); + } + + #[test] + fn test_try_init_otel_returns_none_for_no_endpoint() { + let options = ExperimentalOtelOptions { + enabled: Some(true), + endpoint: None, + ..Default::default() + }; + let result = try_init_otel(&options); + assert!(result.is_none()); + } } diff --git a/docs/site/content/docs/reference/configuration.mdx b/docs/site/content/docs/reference/configuration.mdx index 546034e4a483b..9e0a46a8f27f0 100644 --- a/docs/site/content/docs/reference/configuration.mdx +++ b/docs/site/content/docs/reference/configuration.mdx @@ -724,6 +724,13 @@ Default: `false` When enabled, Turborepo will honor the `experimentalObservability.otel` configuration block (if present) to send run summaries to an OpenTelemetry Protocol (OTLP) collector. + + Invalid or incomplete OTEL configuration (e.g., missing endpoint, invalid + protocol) results in metrics being disabled rather than causing runs to fail. + Turborepo will continue executing tasks normally even if the exporter cannot + be initialized. + + ## Experimental observability Experimental @@ -784,6 +791,8 @@ The OTLP collector endpoint URL. For example: - Datadog: `"https://api.datadoghq.com/api/v2/otlp"` - Custom collector: `"http://localhost:4317"` (gRPC) or `"http://localhost:4318"` (HTTP) +If the endpoint is missing or empty when OTEL is enabled, the exporter will not be initialized and metrics will be disabled. The run will continue normally. + #### `experimentalObservability.otel.headers` Optional HTTP headers to include with export requests. Useful for authentication (e.g., API keys) or custom metadata. @@ -854,7 +863,9 @@ Export per-task metrics: Exporter failures are logged but do not cause the run to fail. If the collector is unavailable or misconfigured, Turborepo will continue executing - tasks normally. + tasks normally. Invalid or incomplete configuration (e.g., missing endpoint + when enabled) results in the exporter not being initialized, and metrics will + be disabled for that run. ### Environment variables diff --git a/turborepo-tests/integration/tests/other/experimental-otel.t b/turborepo-tests/integration/tests/other/experimental-otel.t index 7e271b82f108f..30f0e04784478 100644 --- a/turborepo-tests/integration/tests/other/experimental-otel.t +++ b/turborepo-tests/integration/tests/other/experimental-otel.t @@ -1,7 +1,13 @@ +# Smoke tests for experimental OTEL configuration. +# These tests verify that enabling/disabling OTEL via environment variables and CLI flags +# does not break normal turbo run behavior. Exporter correctness is primarily covered +# by Rust unit tests in crates/turborepo-lib/src/config/experimental_otel.rs and +# crates/turborepo-lib/src/observability/otel.rs. + Setup $ . ${TESTDIR}/../../../helpers/setup_integration_test.sh -Test that OTEL exporter can be enabled via environment variables +Smoke test: OTEL enabled via environment variables does not break turbo run $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 $ ${TURBO} run build --filter=my-app @@ -15,7 +21,6 @@ Test that OTEL exporter can be enabled via environment variables my-app:build: my-app:build: building - Tasks: 1 successful, 1 total Cached: 0 cached, 1 total Time:\s*[\.0-9]+m?s (re) @@ -24,7 +29,7 @@ Test that OTEL exporter can be enabled via environment variables [0] -Test that OTEL exporter can be enabled via CLI flags +Smoke test: OTEL enabled via CLI flags does not break turbo run $ unset TURBO_EXPERIMENTAL_OTEL_ENABLED $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 @@ -38,14 +43,13 @@ Test that OTEL exporter can be enabled via CLI flags my-app:build: my-app:build: building - Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) [0] -Test that OTEL exporter works with http/protobuf protocol +Smoke test: http/protobuf protocol flag is accepted without error $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 --experimental-otel-protocol=http-protobuf \xe2\x80\xa2 Packages in scope: my-app (esc) \xe2\x80\xa2 Running build in 1 packages (esc) @@ -57,14 +61,13 @@ Test that OTEL exporter works with http/protobuf protocol my-app:build: my-app:build: building - Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) [0] -Test that OTEL exporter can be disabled via environment variable +Smoke test: OTEL disabled via environment variable does not break turbo run $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=0 $ export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://localhost:4318 $ ${TURBO} run build --filter=my-app @@ -78,14 +81,13 @@ Test that OTEL exporter can be disabled via environment variable my-app:build: my-app:build: building - Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) [0] -Test that OTEL exporter requires endpoint when enabled +Smoke test: enabled via env without endpoint is a no-op (exporter not configured) $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 $ unset TURBO_EXPERIMENTAL_OTEL_ENDPOINT $ ${TURBO} run build --filter=my-app @@ -99,7 +101,6 @@ Test that OTEL exporter requires endpoint when enabled my-app:build: my-app:build: building - Tasks: 1 successful, 1 total Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) From b138c2e7cd3ae22c79e891817cc9e370855227a4 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 14:12:12 -0700 Subject: [PATCH 24/29] Add more terms to the dictionary --- docs/site/dictionary.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/site/dictionary.txt b/docs/site/dictionary.txt index 56047ba81b5ea..6db9fb60d287c 100644 --- a/docs/site/dictionary.txt +++ b/docs/site/dictionary.txt @@ -293,3 +293,5 @@ scm SCM datadog Datadog +otel +OTEL From 5e7d1b2abd5cb5c0a9382a8d1f13e3281ff5e58e Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Mon, 17 Nov 2025 14:21:50 -0700 Subject: [PATCH 25/29] Another try at getting experimental-otel integration tests working --- turborepo-tests/integration/tests/other/experimental-otel.t | 5 ----- 1 file changed, 5 deletions(-) diff --git a/turborepo-tests/integration/tests/other/experimental-otel.t b/turborepo-tests/integration/tests/other/experimental-otel.t index 30f0e04784478..55c240df5f327 100644 --- a/turborepo-tests/integration/tests/other/experimental-otel.t +++ b/turborepo-tests/integration/tests/other/experimental-otel.t @@ -27,7 +27,6 @@ Smoke test: OTEL enabled via environment variables does not break turbo run WARNING no output files found for task my-app#build. Please check your `outputs` key in `turbo.json` - [0] Smoke test: OTEL enabled via CLI flags does not break turbo run $ unset TURBO_EXPERIMENTAL_OTEL_ENABLED @@ -47,7 +46,6 @@ Smoke test: OTEL enabled via CLI flags does not break turbo run Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) - [0] Smoke test: http/protobuf protocol flag is accepted without error $ ${TURBO} run build --filter=my-app --experimental-otel-enabled --experimental-otel-endpoint=http://localhost:4318 --experimental-otel-protocol=http-protobuf @@ -65,7 +63,6 @@ Smoke test: http/protobuf protocol flag is accepted without error Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) - [0] Smoke test: OTEL disabled via environment variable does not break turbo run $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=0 @@ -85,7 +82,6 @@ Smoke test: OTEL disabled via environment variable does not break turbo run Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) - [0] Smoke test: enabled via env without endpoint is a no-op (exporter not configured) $ export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 @@ -105,5 +101,4 @@ Smoke test: enabled via env without endpoint is a no-op (exporter not configured Cached: 1 cached, 1 total Time:\s*[\.0-9]+m?s\s*>>> FULL TURBO (re) - [0] From df3d078c58454c7508a33d6637625045e5c759f4 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Tue, 18 Nov 2025 08:08:18 -0700 Subject: [PATCH 26/29] Fit the turborepo-otel crate into the workspace correctly --- crates/turborepo-otel/Cargo.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml index 23fb53111d8ad..d91f138899fe8 100644 --- a/crates/turborepo-otel/Cargo.toml +++ b/crates/turborepo-otel/Cargo.toml @@ -1,24 +1,24 @@ [package] name = "turborepo-otel" version = "0.1.0" -edition = "2024" +edition = { workspace = true } license = "MIT" [dependencies] -opentelemetry = { version = "0.23", features = ["metrics"] } -opentelemetry-otlp = { version = "0.16", features = [ +opentelemetry = { version = "0.31", features = ["metrics"] } +opentelemetry-otlp = { version = "0.31", features = [ "grpc-tonic", "http-proto", "metrics", ] } -opentelemetry-semantic-conventions = "0.15" -opentelemetry_sdk = { version = "0.23", features = ["rt-tokio", "metrics"] } -serde = { version = "1", features = ["derive"], optional = true } -serde_json = { version = "1", optional = true } -thiserror = "1.0" -tokio = { version = "1", features = ["rt", "macros", "sync"] } -tonic = "0.11" -tracing = "0.1" +opentelemetry-semantic-conventions = "0.31" +opentelemetry_sdk = { version = "0.31", features = ["rt-tokio", "metrics"] } +serde = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["full"] } +tonic = { workspace = true } +tracing = { workspace = true } +turborepo-errors = { workspace = true } [features] default = [] From 65620482d42d8184b58cf608dfbc43ac24d2d858 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Tue, 18 Nov 2025 08:39:01 -0700 Subject: [PATCH 27/29] Adapt to otlp 0.31 --- Cargo.lock | 266 ++++++++++++++++++++++++------- crates/turborepo-otel/Cargo.toml | 8 +- crates/turborepo-otel/src/lib.rs | 77 ++++----- 3 files changed, 245 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5888da597c8c7..3c458fa2a39d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -533,7 +533,7 @@ dependencies = [ "serde_path_to_error", "serde_urlencoded", "sha1", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-tungstenite 0.21.0", "tower 0.4.13", @@ -570,7 +570,7 @@ dependencies = [ "serde_path_to_error", "serde_urlencoded", "sha1", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-tungstenite 0.26.2", "tower 0.5.2", @@ -631,7 +631,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", @@ -2676,6 +2676,19 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.4.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -2694,9 +2707,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -2707,7 +2720,6 @@ dependencies = [ "pin-project-lite", "socket2 0.5.6", "tokio", - "tower 0.4.13", "tower-service", "tracing", ] @@ -3862,85 +3874,82 @@ dependencies = [ [[package]] name = "opentelemetry" -version = "0.23.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b69a91d4893e713e06f724597ad630f1fa76057a5e1026c0ca67054a9032a76" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" dependencies = [ "futures-core", "futures-sink", "js-sys", - "once_cell", "pin-project-lite", - "thiserror 1.0.63", + "thiserror 2.0.12", + "tracing", ] [[package]] name = "opentelemetry-http" -version = "0.12.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0ba633e55c5ea6f431875ba55e71664f2fa5d3a90bd34ec9302eecc41c865dd" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" dependencies = [ "async-trait", "bytes", - "http 0.2.11", + "http 1.1.0", "opentelemetry", + "reqwest", ] [[package]] name = "opentelemetry-otlp" -version = "0.16.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a94c69209c05319cdf7460c6d4c055ed102be242a0a6245835d7bc42c6ec7f54" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ - "async-trait", - "futures-core", - "http 0.2.11", + "http 1.1.0", "opentelemetry", "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", - "prost 0.12.3", - "thiserror 1.0.63", + "prost 0.14.1", + "reqwest", + "thiserror 2.0.12", "tokio", - "tonic", + "tonic 0.14.2", + "tracing", ] [[package]] name = "opentelemetry-proto" -version = "0.6.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984806e6cf27f2b49282e2a05e288f30594f3dbc74eb7a6e99422bc48ed78162" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ "opentelemetry", "opentelemetry_sdk", - "prost 0.12.3", - "tonic", + "prost 0.14.1", + "tonic 0.14.2", + "tonic-prost", ] [[package]] name = "opentelemetry-semantic-conventions" -version = "0.15.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1869fb4bb9b35c5ba8a1e40c9b128a7b4c010d07091e864a29da19e4fe2ca4d7" +checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" [[package]] name = "opentelemetry_sdk" -version = "0.23.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae312d58eaa90a82d2e627fd86e075cf5230b3f11794e2ed74199ebbe572d4fd" +checksum = "e14ae4f5991976fd48df6d843de219ca6d31b01daaab2dad5af2badeded372bd" dependencies = [ - "async-trait", "futures-channel", "futures-executor", "futures-util", - "glob", - "lazy_static", - "once_cell", "opentelemetry", - "ordered-float", "percent-encoding", - "rand 0.8.5", - "thiserror 1.0.63", + "rand 0.9.1", + "thiserror 2.0.12", "tokio", "tokio-stream", ] @@ -3951,15 +3960,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] - [[package]] name = "ordered-multimap" version = "0.7.3" @@ -4483,6 +4483,16 @@ dependencies = [ "prost-derive 0.12.3", ] +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive 0.14.1", +] + [[package]] name = "prost-build" version = "0.11.8" @@ -4531,6 +4541,19 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "prost-types" version = "0.11.8" @@ -4865,7 +4888,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", "tokio-rustls", @@ -5513,6 +5536,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "spin" version = "0.9.8" @@ -5880,9 +5913,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -6258,9 +6291,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -6365,7 +6398,7 @@ dependencies = [ "http 0.2.11", "http-body 0.4.5", "hyper 0.14.28", - "hyper-timeout", + "hyper-timeout 0.4.1", "percent-encoding", "pin-project", "prost 0.12.3", @@ -6377,6 +6410,35 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +dependencies = [ + "async-trait", + "axum 0.8.4", + "base64 0.22.1", + "bytes", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-timeout 0.5.2", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2 0.6.1", + "sync_wrapper 1.0.2", + "tokio", + "tokio-stream", + "tower 0.5.2", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tonic-build" version = "0.8.4" @@ -6390,6 +6452,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tonic-prost" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +dependencies = [ + "bytes", + "prost 0.14.1", + "tonic 0.14.2", +] + [[package]] name = "tower" version = "0.4.13" @@ -6418,9 +6491,12 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap 2.2.6", "pin-project-lite", - "sync_wrapper 1.0.1", + "slab", + "sync_wrapper 1.0.2", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -7053,7 +7129,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tonic", + "tonic 0.11.0", "tonic-build", "tower 0.4.13", "tower-http", @@ -7210,7 +7286,7 @@ dependencies = [ "serde_json", "thiserror 1.0.63", "tokio", - "tonic", + "tonic 0.14.2", "tracing", ] @@ -7936,6 +8012,12 @@ dependencies = [ "windows-targets 0.48.1", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-registry" version = "0.2.0" @@ -8017,6 +8099,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -8056,13 +8147,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -8081,6 +8189,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -8099,6 +8213,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -8117,12 +8237,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -8141,6 +8273,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -8159,6 +8297,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -8177,6 +8321,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -8195,6 +8345,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" version = "0.5.40" diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml index d91f138899fe8..e77eda8f3fd23 100644 --- a/crates/turborepo-otel/Cargo.toml +++ b/crates/turborepo-otel/Cargo.toml @@ -13,12 +13,12 @@ opentelemetry-otlp = { version = "0.31", features = [ ] } opentelemetry-semantic-conventions = "0.31" opentelemetry_sdk = { version = "0.31", features = ["rt-tokio", "metrics"] } -serde = { workspace = true } -serde_json = { workspace = true } +serde = { workspace = true, optional = true } +serde_json = { workspace = true, optional = true } +thiserror = { workspace = true } tokio = { workspace = true, features = ["full"] } -tonic = { workspace = true } +tonic = "0.14" tracing = { workspace = true } -turborepo-errors = { workspace = true } [features] default = [] diff --git a/crates/turborepo-otel/src/lib.rs b/crates/turborepo-otel/src/lib.rs index c5ad13acdb4bb..541d4bdfc1564 100644 --- a/crates/turborepo-otel/src/lib.rs +++ b/crates/turborepo-otel/src/lib.rs @@ -8,17 +8,10 @@ use opentelemetry::{ KeyValue, metrics::{Counter, Histogram, Meter, MeterProvider as _}, }; -use opentelemetry_otlp::WithExportConfig; +use opentelemetry_otlp::{WithExportConfig, WithHttpConfig, WithTonicConfig}; use opentelemetry_sdk::{ Resource, - metrics::{ - PeriodicReader, SdkMeterProvider, - reader::{ - AggregationSelector, DefaultAggregationSelector, DefaultTemporalitySelector, - TemporalitySelector, - }, - }, - runtime::Tokio, + metrics::{PeriodicReader, SdkMeterProvider, Temporality}, }; use opentelemetry_semantic_conventions::resource::SERVICE_NAME; use thiserror::Error; @@ -103,11 +96,9 @@ pub enum Error { #[error("experimentalOtel requires an endpoint")] MissingEndpoint, #[error("failed to build OTLP exporter: {0}")] - Exporter(opentelemetry_otlp::Error), + Exporter(opentelemetry_otlp::ExporterBuildError), #[error("invalid OTLP header `{0}`")] InvalidHeader(String), - #[error("metrics SDK error: {0}")] - Metrics(#[from] opentelemetry::metrics::MetricsError), } struct Instruments { @@ -230,46 +221,44 @@ impl Instruments { fn build_provider(config: &Config) -> Result { let resource = build_resource(config); + let temporality = default_temporality(); let exporter = match config.protocol { Protocol::Grpc => { let export_config = opentelemetry_otlp::ExportConfig { - endpoint: config.endpoint.clone(), - timeout: config.timeout, - ..Default::default() + endpoint: Some(config.endpoint.clone()), + protocol: opentelemetry_otlp::Protocol::Grpc, + timeout: Some(config.timeout), }; - let mut builder = opentelemetry_otlp::new_exporter() - .tonic() + let mut builder = opentelemetry_otlp::MetricExporter::builder() + .with_tonic() + .with_temporality(temporality) .with_export_config(export_config); if !config.headers.is_empty() { builder = builder.with_metadata(build_metadata(&config.headers)?); } - let (aggregation, temporality) = default_selectors(); - builder - .build_metrics_exporter(aggregation, temporality) - .map_err(Error::Metrics)? + builder.build().map_err(Error::Exporter)? } Protocol::HttpProtobuf => { let export_config = opentelemetry_otlp::ExportConfig { - endpoint: config.endpoint.clone(), - timeout: config.timeout, - ..Default::default() + endpoint: Some(config.endpoint.clone()), + protocol: opentelemetry_otlp::Protocol::HttpBinary, + timeout: Some(config.timeout), }; - let mut builder = opentelemetry_otlp::new_exporter() - .http() + let mut builder = opentelemetry_otlp::MetricExporter::builder() + .with_http() + .with_temporality(temporality) .with_export_config(export_config); if !config.headers.is_empty() { let headers: HashMap<_, _> = config.headers.clone().into_iter().collect(); builder = builder.with_headers(headers); } - let (aggregation, temporality) = default_selectors(); - builder - .build_metrics_exporter(aggregation, temporality) - .map_err(Error::Metrics)? + builder.build().map_err(Error::Exporter)? } }; - let reader = PeriodicReader::builder(exporter, Tokio).with_interval(Duration::from_secs(15)); - let reader = reader.build(); + let reader = PeriodicReader::builder(exporter) + .with_interval(Duration::from_secs(15)) + .build(); Ok(SdkMeterProvider::builder() .with_resource(resource) @@ -303,44 +292,38 @@ fn build_resource(config: &Config) -> Resource { } attrs.push(KeyValue::new(key.clone(), value.clone())); } - Resource::new(attrs) + Resource::builder_empty().with_attributes(attrs).build() } -fn default_selectors() -> ( - Box, - Box, -) { - ( - Box::new(DefaultAggregationSelector::new()), - Box::new(DefaultTemporalitySelector::new()), - ) +fn default_temporality() -> Temporality { + Temporality::Cumulative } fn create_instruments(meter: &Meter) -> Instruments { let run_duration = meter .f64_histogram("turbo.run.duration_ms") .with_description("Turborepo run duration in milliseconds") - .init(); + .build(); let run_attempted = meter .u64_counter("turbo.run.tasks.attempted") .with_description("Tasks attempted per run") - .init(); + .build(); let run_failed = meter .u64_counter("turbo.run.tasks.failed") .with_description("Tasks failed per run") - .init(); + .build(); let run_cached = meter .u64_counter("turbo.run.tasks.cached") .with_description("Tasks served from cache per run") - .init(); + .build(); let task_duration = meter .f64_histogram("turbo.task.duration_ms") .with_description("Task execution duration in milliseconds") - .init(); + .build(); let task_cache = meter .u64_counter("turbo.task.cache.events") .with_description("Cache hit/miss events") - .init(); + .build(); Instruments { run_duration, From 6796c5b14aa90e4c03c03026f2d294974ec3e133 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Tue, 18 Nov 2025 12:27:21 -0700 Subject: [PATCH 28/29] Move turborepo-otel to the experimental periodic_reader_with_async_runtime feature from opentelemetry_sdk --- crates/turborepo-lib/src/run/summary/mod.rs | 5 +- crates/turborepo-otel/Cargo.toml | 7 +- .../examples/local-collector/README.md | 137 ++++++++++++++++++ .../local-collector/docker-compose.yml | 27 ++++ .../local-collector/otel-collector.yml | 21 +++ .../examples/local-collector/prometheus.yml | 7 + crates/turborepo-otel/src/lib.rs | 36 ++++- 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 crates/turborepo-otel/examples/local-collector/README.md create mode 100644 crates/turborepo-otel/examples/local-collector/docker-compose.yml create mode 100644 crates/turborepo-otel/examples/local-collector/otel-collector.yml create mode 100644 crates/turborepo-otel/examples/local-collector/prometheus.yml diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index 0614c57ae285b..f4f01978ea8ac 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -27,9 +27,10 @@ use turborepo_env::EnvironmentVariableMap; use turborepo_repository::package_graph::{PackageGraph, PackageName}; use turborepo_scm::SCM; use turborepo_task_id::TaskId; -use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; +use turborepo_ui::{BOLD, BOLD_CYAN, ColorConfig, GREY, color, cprintln, cwriteln}; -pub(crate) use self::task::TaskSummary; // Re-exported for use in observability/otel.rs +/// Re-exported for use in observability/otel.rs +pub(crate) use self::task::{CacheStatus, TaskSummary}; use self::{ execution::TaskState, task::SinglePackageTaskSummary, task_factory::TaskSummaryFactory, }; diff --git a/crates/turborepo-otel/Cargo.toml b/crates/turborepo-otel/Cargo.toml index e77eda8f3fd23..3fe17c4f76e63 100644 --- a/crates/turborepo-otel/Cargo.toml +++ b/crates/turborepo-otel/Cargo.toml @@ -12,7 +12,12 @@ opentelemetry-otlp = { version = "0.31", features = [ "metrics", ] } opentelemetry-semantic-conventions = "0.31" -opentelemetry_sdk = { version = "0.31", features = ["rt-tokio", "metrics"] } +opentelemetry_sdk = { version = "0.31", features = [ + "metrics", + "rt-tokio", + "experimental_async_runtime", + "experimental_metrics_periodicreader_with_async_runtime", +] } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } thiserror = { workspace = true } diff --git a/crates/turborepo-otel/examples/local-collector/README.md b/crates/turborepo-otel/examples/local-collector/README.md new file mode 100644 index 0000000000000..d372748dc8342 --- /dev/null +++ b/crates/turborepo-otel/examples/local-collector/README.md @@ -0,0 +1,137 @@ +# Local OTEL collector example + +This example shows how to build the `turbo` binary with the **OpenTelemetry (OTEL)** feature enabled and send metrics to a local collector running via **Docker Compose**. It’s intended as a lightweight, local integration harness for the OTEL exporter. + +## 1. Prerequisites + +- **Docker & docker compose** installed and running +- **Rust toolchain** (matching this repo’s `rust-toolchain.toml`) +- **pnpm** installed (per `CONTRIBUTING.md`) + +All commands below assume the repo root is `turborepo/`. + +## 2. Build `turbo` with the OTEL feature + +From the repo root: + +```bash +pnpm install +cargo build -p turbo --features otel +``` + +This produces an OTEL-enabled `turbo` binary at: `./target/debug/turbo` + +## 3. Start the local collector stack + +From this example directory: + +```bash +cd crates/turborepo-otel/examples/local-collector +docker compose up -d +``` + +This starts: + +- **`otel-collector`** (OTLP receiver + debug + Prometheus exporter) +- **`prometheus`** (scrapes metrics from the collector) +- **`grafana`** (optional visualization) + +Ports: + +- **OTLP gRPC**: `4317` +- **OTLP HTTP**: `4318` +- **Collector metrics / Prometheus exporter**: `8888`, `8889` +- **Prometheus UI**: `9090` +- **Grafana UI**: `3000` + +You can confirm the collector is ready: + +```bash +docker compose logs otel-collector +``` + +You should see a line similar to: + +```text +Everything is ready. Begin running and processing data. +``` + +## 4. Configure `turbo` to send metrics to the local collector + +In a new shell, from the repo root, export the OTEL env vars: + +```bash +cd /path/to/turborepo + +export TURBO_EXPERIMENTAL_OTEL_ENABLED=1 +export TURBO_EXPERIMENTAL_OTEL_PROTOCOL=grpc +export TURBO_EXPERIMENTAL_OTEL_ENDPOINT=http://127.0.0.1:4317 +export TURBO_EXPERIMENTAL_OTEL_RESOURCE="service.name=turborepo,env=local" +# Optional (defaults shown) +export TURBO_EXPERIMENTAL_OTEL_METRICS_RUN_SUMMARY=1 +export TURBO_EXPERIMENTAL_OTEL_METRICS_TASK_DETAILS=0 +``` + +These environment variables bypass `turbo.json` and directly configure the OTEL exporter. + +## 5. Run a task and emit metrics + +Use the **locally built** OTEL-enabled binary: + +```bash +./target/debug/turbo run lint --filter=turbo-ignore +``` + +You can replace `lint --filter=turbo-ignore` with any real task in this repo; the important part is that the command finishes so a run summary can be exported. + +## 6. Verify metrics reached the collector + +- **Collector logs (debug exporter)**: + + ```bash + cd crates/turborepo-otel/examples/local-collector + docker compose logs --tail=100 otel-collector + ``` + + You should see entries like: + + ```text + Metrics {"otelcol.component.id": "debug", "otelcol.signal": "metrics", "resource metrics": 1, "metrics": 4, "data points": 4} + Resource attributes: + -> env: Str(local) + -> service.name: Str(turborepo) + Metric #0 + -> Name: turbo.run.duration_ms + Metric #1 + -> Name: turbo.run.tasks.attempted + Metric #2 + -> Name: turbo.run.tasks.failed + Metric #3 + -> Name: turbo.run.tasks.cached + ``` + +- **Prometheus UI** (optional): + + - Open `http://localhost:9090` + - Query for metrics such as: + - `turbo.run.duration_ms` + - `turbo.run.tasks.attempted` + - `turbo.run.tasks.failed` + - `turbo.run.tasks.cached` + +- **Grafana UI** (optional): + + - Open `http://localhost:3000` (default credentials are usually `admin` / `admin`) + - Add a Prometheus data source pointing at `http://prometheus:9090` + - Build dashboards using the `turbo.*` metrics + +## 7. Cleanup + +To stop the local collector stack: + +```bash +cd crates/turborepo-otel/examples/local-collector +docker compose down +``` + +The OTEL-enabled `turbo` binary remains available at `./target/debug/turbo`. You can continue using it with the same environment variables to send metrics to this collector or to another OTLP-compatible backend. diff --git a/crates/turborepo-otel/examples/local-collector/docker-compose.yml b/crates/turborepo-otel/examples/local-collector/docker-compose.yml new file mode 100644 index 0000000000000..2c5bdca60836d --- /dev/null +++ b/crates/turborepo-otel/examples/local-collector/docker-compose.yml @@ -0,0 +1,27 @@ +services: + otel-collector: + image: otel/opentelemetry-collector-contrib:0.139.0 + volumes: + - ./otel-collector.yml:/etc/otelcol-contrib/config.yaml + ports: + - 1888:1888 # pprof extension + - 8888:8888 # Prometheus metrics exposed by the Collector + - 8889:8889 # Prometheus exporter metrics + - 13133:13133 # health_check extension + - 4317:4317 # OTLP gRPC receiver + - 4318:4318 # OTLP http receiver + - 55679:55679 # zpages extension + + prometheus: + image: prom/prometheus:latest + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro + ports: + - "9090:9090" + depends_on: [otel-collector] + + grafana: + image: grafana/grafana:latest + ports: + - "3000:3000" + depends_on: [prometheus] diff --git a/crates/turborepo-otel/examples/local-collector/otel-collector.yml b/crates/turborepo-otel/examples/local-collector/otel-collector.yml new file mode 100644 index 0000000000000..b431acd603a57 --- /dev/null +++ b/crates/turborepo-otel/examples/local-collector/otel-collector.yml @@ -0,0 +1,21 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + +exporters: + debug: + verbosity: detailed + prometheus: + endpoint: "0.0.0.0:8889" + resource_to_telemetry_conversion: + enabled: true + +service: + pipelines: + metrics: + receivers: [otlp] + exporters: [debug, prometheus] diff --git a/crates/turborepo-otel/examples/local-collector/prometheus.yml b/crates/turborepo-otel/examples/local-collector/prometheus.yml new file mode 100644 index 0000000000000..4cf1264eb933a --- /dev/null +++ b/crates/turborepo-otel/examples/local-collector/prometheus.yml @@ -0,0 +1,7 @@ +global: + scrape_interval: 5s + +scrape_configs: + - job_name: "otel-collector" + static_configs: + - targets: ["otel-collector:8889"] diff --git a/crates/turborepo-otel/src/lib.rs b/crates/turborepo-otel/src/lib.rs index 541d4bdfc1564..50513343ca182 100644 --- a/crates/turborepo-otel/src/lib.rs +++ b/crates/turborepo-otel/src/lib.rs @@ -11,7 +11,8 @@ use opentelemetry::{ use opentelemetry_otlp::{WithExportConfig, WithHttpConfig, WithTonicConfig}; use opentelemetry_sdk::{ Resource, - metrics::{PeriodicReader, SdkMeterProvider, Temporality}, + metrics::{SdkMeterProvider, Temporality, periodic_reader_with_async_runtime}, + runtime::Tokio, }; use opentelemetry_semantic_conventions::resource::SERVICE_NAME; use thiserror::Error; @@ -138,6 +139,15 @@ impl Handle { let meter = provider.meter("turborepo"); let instruments = Arc::new(create_instruments(&meter)); + tracing::debug!( + target: "turborepo_otel", + "initialized otel exporter: endpoint={} protocol={:?} run_summary={} task_details={}", + config.endpoint, + config.protocol, + config.metrics.run_summary, + config.metrics.task_details + ); + Ok(Self { inner: Arc::new(HandleInner { provider, @@ -148,6 +158,14 @@ impl Handle { } pub fn record_run(&self, payload: &RunMetricsPayload) { + tracing::debug!( + target: "turborepo_otel", + "record_run payload: run_id={} attempted={} failed={} cached={}", + payload.run_id, + payload.attempted_tasks, + payload.failed_tasks, + payload.cached_tasks + ); if self.inner.metrics.run_summary { self.inner.instruments.record_run_summary(payload); } @@ -157,6 +175,7 @@ impl Handle { } pub fn shutdown(self) { + tracing::debug!(target = "turborepo_otel", "shutting down otel exporter"); match Arc::try_unwrap(self.inner) { Ok(inner) => { if let Err(err) = inner.provider.shutdown() { @@ -174,6 +193,13 @@ impl Handle { impl Instruments { fn record_run_summary(&self, payload: &RunMetricsPayload) { + tracing::debug!( + target: "turborepo_otel", + "record_run_summary run_id={} duration_ms={} attempted={}", + payload.run_id, + payload.duration_ms, + payload.attempted_tasks + ); let attrs = build_run_attributes(payload); self.run_duration.record(payload.duration_ms, &attrs); self.run_attempted.add(payload.attempted_tasks, &attrs); @@ -182,6 +208,12 @@ impl Instruments { } fn record_task_details(&self, payload: &RunMetricsPayload) { + tracing::debug!( + target: "turborepo_otel", + "record_task_details run_id={} task_count={}", + payload.run_id, + payload.tasks.len() + ); let base_attrs = build_run_attributes(payload); for task in payload.tasks.iter() { let mut attrs = base_attrs.clone(); @@ -256,7 +288,7 @@ fn build_provider(config: &Config) -> Result { } }; - let reader = PeriodicReader::builder(exporter) + let reader = periodic_reader_with_async_runtime::PeriodicReader::builder(exporter, Tokio) .with_interval(Duration::from_secs(15)) .build(); From 8e02a250356995d73103892ba7ff49598ff381a2 Mon Sep 17 00:00:00 2001 From: Brandon Konkle Date: Tue, 18 Nov 2025 12:30:09 -0700 Subject: [PATCH 29/29] Reverse an unintentional formatting change --- crates/turborepo-lib/src/run/summary/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/turborepo-lib/src/run/summary/mod.rs b/crates/turborepo-lib/src/run/summary/mod.rs index f4f01978ea8ac..7a3a0f09c52e7 100644 --- a/crates/turborepo-lib/src/run/summary/mod.rs +++ b/crates/turborepo-lib/src/run/summary/mod.rs @@ -27,7 +27,7 @@ use turborepo_env::EnvironmentVariableMap; use turborepo_repository::package_graph::{PackageGraph, PackageName}; use turborepo_scm::SCM; use turborepo_task_id::TaskId; -use turborepo_ui::{BOLD, BOLD_CYAN, ColorConfig, GREY, color, cprintln, cwriteln}; +use turborepo_ui::{color, cprintln, cwriteln, ColorConfig, BOLD, BOLD_CYAN, GREY}; /// Re-exported for use in observability/otel.rs pub(crate) use self::task::{CacheStatus, TaskSummary};