|
@@ -20,6 +20,15 @@ impl TmuxManager {
|
|
|
|
|
|
|
|
let mut parts: Vec<String> = Vec::new();
|
|
let mut parts: Vec<String> = Vec::new();
|
|
|
|
|
|
|
|
|
|
+ // Venv activation — prepend `source <venv>/bin/activate &&` when
|
|
|
|
|
+ // recipe.venv is set. The venv path is expanded for ~ by the
|
|
|
|
|
+ // caller (before_serve runs on the host via SSH, so ~ works).
|
|
|
|
|
+ let venv_prefix = if let Some(ref venv) = recipe.venv {
|
|
|
|
|
+ format!("source {}/bin/activate && ", venv)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ String::new()
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
// Entrypoint — from recipe when present, else hardcoded Python path.
|
|
// Entrypoint — from recipe when present, else hardcoded Python path.
|
|
|
if !recipe.entrypoint.is_empty() {
|
|
if !recipe.entrypoint.is_empty() {
|
|
|
parts.extend(recipe.entrypoint.clone());
|
|
parts.extend(recipe.entrypoint.clone());
|
|
@@ -53,7 +62,7 @@ impl TmuxManager {
|
|
|
parts.extend(vec!["--port".to_string(), recipe.port.to_string()]);
|
|
parts.extend(vec!["--port".to_string(), recipe.port.to_string()]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- parts.join(" ")
|
|
|
|
|
|
|
+ format!("{}{}", venv_prefix, parts.join(" "))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Builds the full sequence of tmux commands for a session, with multi-window layout.
|
|
/// Builds the full sequence of tmux commands for a session, with multi-window layout.
|
|
@@ -145,6 +154,7 @@ mod tests {
|
|
|
after_stop: vec![],
|
|
after_stop: vec![],
|
|
|
solo: None,
|
|
solo: None,
|
|
|
deploy: DeployTarget::Docker,
|
|
deploy: DeployTarget::Docker,
|
|
|
|
|
+ venv: None,
|
|
|
mods: Default::default(),
|
|
mods: Default::default(),
|
|
|
shm_size: String::new(),
|
|
shm_size: String::new(),
|
|
|
sync_image: true,
|
|
sync_image: true,
|
|
@@ -223,4 +233,27 @@ mod tests {
|
|
|
// But port should be present (head node)
|
|
// But port should be present (head node)
|
|
|
assert!(cmd.contains("--port 8000"));
|
|
assert!(cmd.contains("--port 8000"));
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn venv_prefix_prepended() {
|
|
|
|
|
+ let mut r = trecipe();
|
|
|
|
|
+ r.venv = Some("~/venvs/vllm025".into());
|
|
|
|
|
+ let c = tcluster();
|
|
|
|
|
+ let mgr = TmuxManager;
|
|
|
|
|
+ let cmd = mgr.build_launch_command(&r, &c.nodes[0], &c);
|
|
|
|
|
+ assert!(
|
|
|
|
|
+ cmd.starts_with("source ~/venvs/vllm025/bin/activate && vllm serve "),
|
|
|
|
|
+ "cmd: {cmd}"
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[test]
|
|
|
|
|
+ fn venv_prefix_absent_when_unset() {
|
|
|
|
|
+ let r = trecipe();
|
|
|
|
|
+ let c = tcluster();
|
|
|
|
|
+ let mgr = TmuxManager;
|
|
|
|
|
+ let cmd = mgr.build_launch_command(&r, &c.nodes[0], &c);
|
|
|
|
|
+ // No venv → command starts directly with entrypoint
|
|
|
|
|
+ assert!(cmd.starts_with("vllm serve "), "cmd: {cmd}");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|