1#![deny(unsafe_code)]
8
9use std::sync::OnceLock;
10
11pub mod api;
12pub mod artifact_verify;
13pub mod binary_hash;
14pub mod cargo_path_deps;
15pub mod config;
16pub mod dependency_closure_planner;
17pub mod discovery;
18pub mod e2e;
19pub mod errors;
20pub mod hooks;
21pub mod logging;
22pub mod mock;
23pub mod mock_worker;
24pub mod path_topology;
25pub mod patterns;
26#[cfg(test)]
27mod patterns_security_test;
28#[cfg(test)]
29mod proptest_tests;
30pub mod protocol;
31#[cfg(unix)]
32pub mod remote_compilation;
33#[cfg(unix)]
34pub mod remote_verification;
35pub mod repo_updater_contract;
36pub mod schema_versions;
37#[cfg(unix)]
38pub mod ssh;
39#[cfg(all(test, unix))]
40mod ssh_timeout_test;
41pub mod ssh_utils;
42pub mod test_change;
43pub mod testing;
44pub mod toolchain;
45pub mod types;
46pub mod ui;
47pub mod util;
48
49pub const BUILD_COMMIT_ENV_VARS: &[&str] = &[
50 "RCH_GIT_COMMIT",
51 "VERGEN_GIT_SHA",
52 "GIT_COMMIT",
53 "GITHUB_SHA",
54];
55
56pub fn build_commit() -> Option<&'static str> {
57 [
58 option_env!("RCH_GIT_COMMIT"),
59 option_env!("VERGEN_GIT_SHA"),
60 option_env!("GIT_COMMIT"),
61 option_env!("GITHUB_SHA"),
62 ]
63 .into_iter()
64 .flatten()
65 .map(str::trim)
66 .find(|value| !value.is_empty())
67}
68
69pub fn build_version_value() -> String {
70 build_version_value_with_commit(env!("CARGO_PKG_VERSION"), build_commit())
71}
72
73pub fn build_version_value_static() -> &'static str {
74 static VERSION_VALUE: OnceLock<String> = OnceLock::new();
75
76 VERSION_VALUE.get_or_init(build_version_value).as_str()
77}
78
79pub fn build_version_value_with_commit(package_version: &str, commit: Option<&str>) -> String {
80 let mut value = package_version.to_string();
81
82 if let Some(commit) = commit.map(str::trim).filter(|value| !value.is_empty()) {
83 value.push_str(" (commit ");
84 value.push_str(short_commit(commit));
85 value.push(')');
86 }
87
88 value
89}
90
91fn short_commit(commit: &str) -> &str {
92 commit
93 .char_indices()
94 .nth(12)
95 .map_or(commit, |(index, _)| &commit[..index])
96}
97
98pub use artifact_verify::{
99 ArtifactManifest, FileHash, VerificationFailure, VerificationResult, compute_file_hash,
100 create_manifest, verify_artifacts,
101};
102pub use binary_hash::{
103 BinaryHashResult, binaries_equivalent, binary_contains_marker, compute_binary_hash,
104};
105pub use cargo_path_deps::{
106 CargoPathDependencyEdge, CargoPathDependencyError, CargoPathDependencyErrorKind,
107 CargoPathDependencyGraph, CargoPathDependencyPackage, resolve_cargo_path_dependency_graph,
108 resolve_cargo_path_dependency_graph_with_policy,
109};
110pub use dependency_closure_planner::{
111 DependencyClosurePlan, DependencyClosurePlanState, DependencyPlanIssue, DependencyRiskClass,
112 DependencySyncAction, DependencySyncMetadata, DependencySyncReason,
113 build_dependency_closure_plan, build_dependency_closure_plan_with_policy,
114 plan_dependency_closure_from_graph,
115};
116pub use logging::{LogConfig, LogFormat, LoggingGuards, init_logging};
117pub use mock_worker::MockWorkerServer;
118pub use path_topology::{
119 DEFAULT_ALIAS_PROJECT_ROOT, DEFAULT_CANONICAL_PROJECT_ROOT, NormalizationDecision,
120 NormalizedProjectPath, PathNormalizationError, PathNormalizationErrorKind, PathTopologyPolicy,
121 normalize_project_path, normalize_project_path_with_policy,
122};
123pub use patterns::{
124 Classification, ClassificationDetails, ClassificationTier, CompilationKind, TierDecision,
125 classify_command, classify_command_detailed, split_shell_commands,
126};
127pub use protocol::{HookInput, HookOutput, ToolInput};
128pub use repo_updater_contract::{
129 MockRepoUpdaterAdapter, REPO_UPDATER_ALIAS_PROJECTS_ROOT, REPO_UPDATER_CANONICAL_PROJECTS_ROOT,
130 REPO_UPDATER_CONTRACT_SCHEMA_VERSION, REPO_UPDATER_DEFAULT_BINARY,
131 REPO_UPDATER_MIN_SUPPORTED_VERSION, RepoUpdaterAdapter, RepoUpdaterAdapterCommand,
132 RepoUpdaterAdapterContract, RepoUpdaterAdapterRequest, RepoUpdaterAdapterResponse,
133 RepoUpdaterFailure, RepoUpdaterFailureKind, RepoUpdaterFallbackMode,
134 RepoUpdaterIdempotencyGuarantee, RepoUpdaterJsonEnvelope, RepoUpdaterOutputFormat,
135 RepoUpdaterResponseStatus, RepoUpdaterVersionCompatibility, RepoUpdaterVersionPolicy,
136 build_invocation, classify_exit_code, evaluate_version_compatibility,
137 map_failure_kind_to_error_code, repo_updater_envelope_schema, repo_updater_request_schema,
138 repo_updater_response_schema,
139};
140pub use ssh_utils::{
142 CommandResult, EnvPrefix, build_env_prefix, is_retryable_transport_error,
143 is_retryable_transport_error_text, shell_escape_value,
144};
145#[cfg(unix)]
147pub use ssh::{KnownHostsPolicy, SshClient, SshOptions, SshPool};
148pub use test_change::{TestChangeGuard, TestCodeChange};
149pub use toolchain::{ToolchainInfo, wrap_command_with_color, wrap_command_with_toolchain};
150pub use types::{
151 AffinityConfig, BuildCancellationMetadata, BuildCancellationWorkerHealth, BuildHeartbeatPhase,
152 BuildHeartbeatRequest, BuildLocation, BuildRecord, BuildStats, CircuitBreakerConfig,
153 CircuitState, CircuitStats, ColorMode, CommandPriority, CommandTimingBreakdown,
154 CompilationConfig, CompilationMetrics, CompilationTimer, CompilationTimingBreakdown,
155 EnvironmentConfig, ExecutionConfig, FairnessConfig, FleetConfig, GeneralConfig,
156 MetricsAggregator, OutputConfig, OutputVisibility, PathTopologyConfig, RchConfig,
157 ReleaseRequest, RequiredRuntime, RetryConfig, SavedTimeStats, SelectedWorker, SelectionConfig,
158 SelectionReason, SelectionRequest, SelectionResponse, SelectionStrategy, SelectionWeightConfig,
159 SelfHealingConfig, SelfHealingLogLevel, SelfTestConfig, SelfTestFailureAction, SelfTestWorkers,
160 TransferConfig, WorkerCapabilities, WorkerConfig, WorkerId, WorkerStatus, default_socket_path,
161 validate_remote_base,
162};
163
164pub use testing::{TestLogEntry, TestLogger, TestPhase, TestResult};
166
167pub use config::{
169 ConfigSource, ConfigValueSource, ConfigWarning, EnvError, EnvParser, Profile, Severity,
170 Sourced, validate_config,
171};
172
173pub use discovery::{
175 DiscoveredHost, DiscoverySource, discover_all, parse_shell_aliases,
176 parse_shell_aliases_content, parse_ssh_config, parse_ssh_config_content,
177};
178
179pub use ui::{
181 ErrorPanel, ErrorSeverity, Icons, IntoErrorPanel, OutputContext, RchTheme, ResultExt,
182 anyhow_to_json, anyhow_to_panel, display_anyhow_error, display_error, display_error_with_code,
183 error_to_json, error_to_panel,
184};
185
186pub use errors::{
188 CodeExplanation, CodeNamespace, ErrorCategory, ErrorCode, ErrorEntry, ReliabilityCategoryKind,
189 ReliabilityReasonCode,
190};
191
192pub use schema_versions::current_version as schema_version;
194pub use schema_versions::{ALL_COMPONENTS as SCHEMA_VERSION_COMPONENTS, SchemaComponent};
195
196pub use api::{API_VERSION, ApiError, ApiResponse, ErrorContext, LegacyErrorCode};
198
199pub use hooks::{HookResult, is_claude_code_installed, verify_and_install_claude_code_hook};
201
202#[cfg(test)]
203mod build_version_tests {
204 use super::{BUILD_COMMIT_ENV_VARS, build_version_value_with_commit};
205
206 #[test]
207 fn build_version_value_omits_missing_commit() {
208 assert_eq!(build_version_value_with_commit("1.0.24", None), "1.0.24");
209 }
210
211 #[test]
212 fn build_version_value_trims_and_shortens_commit() {
213 assert_eq!(
214 build_version_value_with_commit(
215 "1.0.24",
216 Some(" 2fa1249a18dfd05ae5e319e8d10bfd3c9ea1af55 "),
217 ),
218 "1.0.24 (commit 2fa1249a18df)"
219 );
220 }
221
222 #[test]
223 fn build_version_value_ignores_empty_commit() {
224 assert_eq!(
225 build_version_value_with_commit("1.0.24", Some(" ")),
226 "1.0.24"
227 );
228 }
229
230 #[test]
231 fn build_commit_env_var_order_is_documented() {
232 assert_eq!(
233 BUILD_COMMIT_ENV_VARS,
234 &[
235 "RCH_GIT_COMMIT",
236 "VERGEN_GIT_SHA",
237 "GIT_COMMIT",
238 "GITHUB_SHA"
239 ]
240 );
241 }
242}