merge: dev pod runtime env
This commit is contained in:
commit
32d20eea01
|
|
@ -3,6 +3,8 @@ use std::fmt;
|
|||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const POD_RUNTIME_COMMAND_ENV: &str = "INSOMNIA_POD_RUNTIME_COMMAND";
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PodRuntimeCommand {
|
||||
pub program: PathBuf,
|
||||
|
|
@ -28,9 +30,29 @@ impl PodRuntimeCommand {
|
|||
/// Resolve the Pod runtime command used for subprocess launches.
|
||||
///
|
||||
/// The default launch path is always the current `insomnia` executable plus
|
||||
/// the unified `pod` prefix argument.
|
||||
/// the unified `pod` prefix argument. During development, a non-empty
|
||||
/// `INSOMNIA_POD_RUNTIME_COMMAND` value replaces only the executable path;
|
||||
/// the `pod` prefix is still added here and the env value is not parsed as a
|
||||
/// shell command.
|
||||
pub fn resolve() -> io::Result<Self> {
|
||||
Self::for_current_exe()
|
||||
Self::resolve_from_env_value(
|
||||
std::env::var_os(POD_RUNTIME_COMMAND_ENV),
|
||||
std::env::current_exe,
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_from_env_value<F>(
|
||||
override_program: Option<OsString>,
|
||||
current_exe: F,
|
||||
) -> io::Result<Self>
|
||||
where
|
||||
F: FnOnce() -> io::Result<PathBuf>,
|
||||
{
|
||||
if let Some(program) = override_program.filter(|program| !program.as_os_str().is_empty()) {
|
||||
return Ok(Self::for_executable(program));
|
||||
}
|
||||
|
||||
Ok(Self::for_executable(current_exe()?))
|
||||
}
|
||||
|
||||
pub fn program(&self) -> &Path {
|
||||
|
|
@ -98,4 +120,49 @@ mod tests {
|
|||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_uses_current_exe_when_override_is_unset() {
|
||||
let command = PodRuntimeCommand::resolve_from_env_value(None, || {
|
||||
Ok(PathBuf::from("/opt/insomnia/bin/insomnia"))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
command,
|
||||
PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_uses_current_exe_when_override_is_empty() {
|
||||
let command = PodRuntimeCommand::resolve_from_env_value(Some(OsString::new()), || {
|
||||
Ok(PathBuf::from("/opt/insomnia/bin/insomnia"))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
command,
|
||||
PodRuntimeCommand::for_executable("/opt/insomnia/bin/insomnia")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_override_replaces_only_program_and_keeps_pod_prefix() {
|
||||
let command = PodRuntimeCommand::resolve_from_env_value(
|
||||
Some(OsString::from("/tmp/rebuilt insomnia")),
|
||||
|| panic!("override must not inspect current_exe"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(command.program(), Path::new("/tmp/rebuilt insomnia"));
|
||||
assert_eq!(command.prefix_args(), [OsString::from("pod")]);
|
||||
assert_eq!(
|
||||
command.argv_with(["--pod", "agent"]),
|
||||
vec!["pod", "--pod", "agent"]
|
||||
.into_iter()
|
||||
.map(OsString::from)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@ pub enum SpawnError {
|
|||
Io(io::Error),
|
||||
/// runtime ディレクトリが解決できなかった (環境変数未設定等)。
|
||||
RuntimeDirUnavailable,
|
||||
PodLaunchFailed(io::Error),
|
||||
PodLaunchFailed {
|
||||
command: PodRuntimeCommand,
|
||||
source: io::Error,
|
||||
},
|
||||
PodExitedEarly {
|
||||
stderr_tail: String,
|
||||
},
|
||||
|
|
@ -68,7 +71,10 @@ impl std::fmt::Display for SpawnError {
|
|||
f,
|
||||
"could not resolve runtime directory (set INSOMNIA_HOME, INSOMNIA_RUNTIME_DIR, XDG_RUNTIME_DIR, or HOME)"
|
||||
),
|
||||
Self::PodLaunchFailed(e) => write!(f, "failed to launch pod: {e}"),
|
||||
Self::PodLaunchFailed { command, source } => write!(
|
||||
f,
|
||||
"failed to launch pod runtime command `{command}`: {source}"
|
||||
),
|
||||
Self::PodExitedEarly { stderr_tail } => {
|
||||
if stderr_tail.is_empty() {
|
||||
write!(f, "pod exited before becoming ready")
|
||||
|
|
@ -85,7 +91,14 @@ impl std::fmt::Display for SpawnError {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SpawnError {}
|
||||
impl std::error::Error for SpawnError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Io(error) | Self::PodLaunchFailed { source: error, .. } => Some(error),
|
||||
Self::RuntimeDirUnavailable | Self::PodExitedEarly { .. } | Self::Timeout => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for SpawnError {
|
||||
fn from(e: io::Error) -> Self {
|
||||
|
|
@ -132,7 +145,12 @@ where
|
|||
.arg("--session-pod-name")
|
||||
.arg(&config.pod_name);
|
||||
}
|
||||
let mut child = command.spawn().map_err(SpawnError::PodLaunchFailed)?;
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|source| SpawnError::PodLaunchFailed {
|
||||
command: config.runtime_command.clone(),
|
||||
source,
|
||||
})?;
|
||||
|
||||
// Default `kill_on_drop = false` plus `process_group(0)` makes this
|
||||
// a detached Pod once startup succeeds: dropping the handle does not
|
||||
|
|
|
|||
|
|
@ -346,7 +346,13 @@ where
|
|||
command.arg("--store").arg(store_dir);
|
||||
}
|
||||
|
||||
let mut child = command.spawn().map_err(PodDiscoveryError::RestoreSpawn)?;
|
||||
let mut child =
|
||||
command
|
||||
.spawn()
|
||||
.map_err(|source| PodDiscoveryError::RestoreLaunchFailed {
|
||||
command: runtime_command.clone(),
|
||||
source,
|
||||
})?;
|
||||
let deadline = tokio::time::Instant::now() + RESTORE_START_TIMEOUT;
|
||||
loop {
|
||||
if probe_socket(socket_path).await.reachable {
|
||||
|
|
@ -545,6 +551,12 @@ pub enum PodDiscoveryError {
|
|||
ScopeLock(#[from] pod_registry::ScopeLockError),
|
||||
#[error("failed to launch restore process: {0}")]
|
||||
RestoreSpawn(io::Error),
|
||||
#[error("failed to launch restore runtime command `{command}`: {source}")]
|
||||
RestoreLaunchFailed {
|
||||
command: PodRuntimeCommand,
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("restore process exited before socket became reachable: {status}")]
|
||||
RestoreExited { status: std::process::ExitStatus },
|
||||
#[error("restore process did not become reachable before timeout")]
|
||||
|
|
@ -779,6 +791,7 @@ fn discovery_error_to_tool_error(error: PodDiscoveryError) -> ToolError {
|
|||
| PodDiscoveryError::PodStore(_)
|
||||
| PodDiscoveryError::ScopeLock(_)
|
||||
| PodDiscoveryError::RestoreSpawn(_)
|
||||
| PodDiscoveryError::RestoreLaunchFailed { .. }
|
||||
| PodDiscoveryError::RestoreExited { .. }
|
||||
| PodDiscoveryError::RestoreTimeout => ToolError::ExecutionFailed(error.to_string()),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
INSOMNIA では、プロセス境界で本当に必要な場合を除き、環境変数の利用を避ける。新しい ambient な入力を増やすより、明示的な profile / manifest / config file / typed secret reference / CLI argument を優先する。
|
||||
|
||||
それでも、path discovery、runtime directory、外部 provider の credential 慣習との移行互換のために、一部の環境変数はまだサポートしている。この文書に載せた環境変数は公開 surface として扱う。ただし、fallback 変数は独立した設定項目ではなく、対応する main key の解決順の一部として扱う。開発・テスト都合だけの環境変数は追加しない。
|
||||
それでも、path discovery、runtime directory、外部 provider の credential 慣習との移行互換のために、一部の環境変数はまだサポートしている。この文書に載せた通常 runtime 用の環境変数は公開 surface として扱う。ただし、fallback 変数は独立した設定項目ではなく、対応する main key の解決順の一部として扱う。開発・テスト都合だけの環境変数は、通常ユーザー向け configuration として扱わない明確な escape hatch に限る。
|
||||
|
||||
## 原則
|
||||
|
||||
|
|
@ -56,6 +56,14 @@ Provider credential は、現在は manifest / profile / catalog の設定から
|
|||
|
||||
Credential env var は interoperability のために現時点では残っているが、長期的に望ましい secret mechanism ではない。現時点では適切なら `auth.file` を優先し、今後は typed secret reference へ寄せる。credential UX のために implicit `.env` loading を追加しないこと。project secret を漏らしやすく、profile ごとの credential model とも相性が悪い。
|
||||
|
||||
## Development-only escape hatches
|
||||
|
||||
これらは dogfooding / self-rebuild / fixture などの開発運用だけの逃げ道であり、通常ユーザー向けの configuration surface ではない。profile、manifest、CLI option の代替として案内しない。
|
||||
|
||||
| 変数 | Context | 備考 |
|
||||
| --- | --- | --- |
|
||||
| `INSOMNIA_POD_RUNTIME_COMMAND` | 開発中に起動中の `insomnia` binary が rebuild され、`std::env::current_exe()` が `target/debug/insomnia (deleted)` のような stale path を返す場合の Pod runtime executable override。 | Unset または empty の場合は既定どおり current executable に `pod` prefix argument を付けて起動する。Non-empty の場合は値を executable path としてそのまま使い、`pod` prefix argument は常に自動追加する。shell parsing や argument splitting は行わないため、値に flags や `pod` を含めない。 |
|
||||
|
||||
## Build / example variables
|
||||
|
||||
これらは通常の application configuration ではない。
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user