diff --git a/src/run/runner/wall_time/executor.rs b/src/run/runner/wall_time/executor.rs index 1b29e81c..3c61e4a4 100644 --- a/src/run/runner/wall_time/executor.rs +++ b/src/run/runner/wall_time/executor.rs @@ -6,6 +6,7 @@ use crate::run::runner::executor::Executor; use crate::run::runner::helpers::env::{get_base_injected_env, is_codspeed_debug_enabled}; use crate::run::runner::helpers::get_bench_command::get_bench_command; use crate::run::runner::helpers::run_command_with_log_pipe::run_command_with_log_pipe; +use crate::run::runner::wall_time::introspected_golang::setup_introspected_go; use crate::run::runner::{ExecutorName, RunData}; use crate::run::{check_system::SystemInfo, config::Config}; use async_trait::async_trait; @@ -106,7 +107,18 @@ impl WallTimeExecutor { .map(|(k, v)| format!("export {k}={v}",)) .collect::>() .join("\n"); - let combined_env = format!("{system_env}\n{base_injected_env}"); + + // We need to intercept the `go` command to ensure we can run it with our custom runner. + let path_env = std::env::var("PATH").unwrap_or_default(); + let path_env = format!( + "export PATH={}:{}", + setup_introspected_go() + .map_err(|e| anyhow!("failed to setup Go introspection. {}", e))? + .to_string_lossy(), + path_env + ); + + let combined_env = format!("{system_env}\n{base_injected_env}\n{path_env}"); let mut env_file = NamedTempFile::new()?; env_file.write_all(combined_env.as_bytes())?; diff --git a/src/run/runner/wall_time/introspected_golang/go.sh b/src/run/runner/wall_time/introspected_golang/go.sh new file mode 100755 index 00000000..54ebf9c9 --- /dev/null +++ b/src/run/runner/wall_time/introspected_golang/go.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -euo pipefail + +debug_log() { + if [ "${CODSPEED_LOG:-}" = "debug" ]; then + echo "[DEBUG go.sh] $*" >&2 + fi +} + +debug_log "Called with arguments: $*" +debug_log "Number of arguments: $#" + +# Find the real go binary, so that we don't end up in infinite recursion +REAL_GO=$(which -a go | grep -v "$(realpath "$0")" | head -1) +if [ -z "$REAL_GO" ]; then + echo "ERROR: Could not find real go binary" >&2 + exit 1 +fi + +# Check if we have any arguments +if [ $# -eq 0 ]; then + debug_log "No arguments provided, using standard go binary" + "$REAL_GO" + exit $? +fi + +# Check if first argument is "test" +if [ "$1" = "test" ]; then + debug_log "Detected 'test' command, routing to go-runner" + + # Find go-runner or install if not found + GO_RUNNER=$(which go-runner 2>/dev/null || true) + if [ -z "$GO_RUNNER" ]; then + curl -fsSL http://github.com/CodSpeedHQ/runner/releases/latest/download/go-runner-installer.sh | bash -s -- --quiet + GO_RUNNER=$(which go-runner 2>/dev/null || true) + fi + + debug_log "Using go-runner at: $GO_RUNNER" + debug_log "Full command: RUST_LOG=info $GO_RUNNER $*" + + "$GO_RUNNER" "$@" +else + debug_log "Detected non-test command ('$1'), routing to standard go binary" + debug_log "Full command: $REAL_GO $*" + "$REAL_GO" "$@" +fi diff --git a/src/run/runner/wall_time/introspected_golang/mod.rs b/src/run/runner/wall_time/introspected_golang/mod.rs new file mode 100644 index 00000000..02e03aa7 --- /dev/null +++ b/src/run/runner/wall_time/introspected_golang/mod.rs @@ -0,0 +1,19 @@ +use crate::prelude::*; +use std::{env, fs::File, io::Write, os::unix::fs::PermissionsExt, path::PathBuf}; + +const INTROSPECTED_GO_SCRIPT: &str = include_str!("go.sh"); + +/// Creates the `go` script that will replace the `go` binary while running +/// Returns the path to the script folder, which should be added to the PATH environment variable +pub fn setup_introspected_go() -> Result { + let script_folder = env::temp_dir().join("codspeed_introspected_go"); + std::fs::create_dir_all(&script_folder)?; + let script_path = script_folder.join("go"); + let mut script_file = File::create(script_path)?; + script_file.write_all(INTROSPECTED_GO_SCRIPT.as_bytes())?; + // Make the script executable + let mut perms = script_file.metadata()?.permissions(); + perms.set_mode(0o755); + script_file.set_permissions(perms)?; + Ok(script_folder) +} diff --git a/src/run/runner/wall_time/mod.rs b/src/run/runner/wall_time/mod.rs index ca152f25..da8d3bdb 100644 --- a/src/run/runner/wall_time/mod.rs +++ b/src/run/runner/wall_time/mod.rs @@ -1,2 +1,3 @@ pub mod executor; +pub mod introspected_golang; pub mod perf;