From 383689e3ad42a4a7ea264468887f610fbee7b51c Mon Sep 17 00:00:00 2001 From: Simo Lin Date: Mon, 1 Dec 2025 22:51:57 -0800 Subject: [PATCH] [model-gateway] fix version output (#14276) --- sgl-router/Cargo.toml | 2 +- .../bindings/python/sglang_router/cli.py | 13 +- sgl-router/bindings/python/src/lib.rs | 10 +- sgl-router/build.rs | 198 ++++++++---------- sgl-router/src/main.rs | 4 +- sgl-router/src/version.rs | 62 ++---- 6 files changed, 120 insertions(+), 169 deletions(-) diff --git a/sgl-router/Cargo.toml b/sgl-router/Cargo.toml index 3bce45436..3535f4e03 100644 --- a/sgl-router/Cargo.toml +++ b/sgl-router/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sglang-router" -version = "0.2.2" +version = "0.2.3" edition = "2021" [features] diff --git a/sgl-router/bindings/python/sglang_router/cli.py b/sgl-router/bindings/python/sglang_router/cli.py index ef385078a..1447211b2 100755 --- a/sgl-router/bindings/python/sglang_router/cli.py +++ b/sgl-router/bindings/python/sglang_router/cli.py @@ -15,7 +15,10 @@ import os import sys from typing import List, Optional -from sglang_router.sglang_router_rs import get_short_version_string, get_version_string +from sglang_router.sglang_router_rs import ( + get_verbose_version_string, + get_version_string, +) def create_parser() -> argparse.ArgumentParser: @@ -54,11 +57,11 @@ def main(argv: Optional[List[str]] = None) -> None: argv = sys.argv[1:] # Handle version flags before parsing - if argv and argv[0] in ["--version", "-V"]: - if argv[0] == "--version": - print(get_version_string()) + if argv and argv[0] in ["--version", "-V", "--version-verbose"]: + if argv[0] == "--version-verbose": + print(get_verbose_version_string()) else: - print(get_short_version_string()) + print(get_version_string()) sys.exit(0) # Handle empty command - show help diff --git a/sgl-router/bindings/python/src/lib.rs b/sgl-router/bindings/python/src/lib.rs index 000734ecc..16e5c225b 100644 --- a/sgl-router/bindings/python/src/lib.rs +++ b/sgl-router/bindings/python/src/lib.rs @@ -704,16 +704,16 @@ impl Router { } } -/// Get formatted version information string with full build details +/// Get simple version string (default for --version) #[pyfunction] fn get_version_string() -> String { version::get_version_string() } -/// Get short version information string +/// Get verbose version information string with full build details (for --version-verbose) #[pyfunction] -fn get_short_version_string() -> String { - version::get_short_version_string() +fn get_verbose_version_string() -> String { + version::get_verbose_version_string() } #[pymodule] @@ -725,6 +725,6 @@ fn sglang_router_rs(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_function(wrap_pyfunction!(get_version_string, m)?)?; - m.add_function(wrap_pyfunction!(get_short_version_string, m)?)?; + m.add_function(wrap_pyfunction!(get_verbose_version_string, m)?)?; Ok(()) } diff --git a/sgl-router/build.rs b/sgl-router/build.rs index 3fe81974b..57a02656b 100644 --- a/sgl-router/build.rs +++ b/sgl-router/build.rs @@ -1,25 +1,27 @@ use std::process::Command; -// Default values for version and project name when pyproject.toml is unavailable const DEFAULT_VERSION: &str = "0.0.0"; -const DEFAULT_PROJECT_NAME: &str = "sgl-router"; +const DEFAULT_PROJECT_NAME: &str = "sgl-model-gateway"; + +/// Set a compile-time environment variable with the SGL_MODEL_GATEWAY_ prefix +macro_rules! set_env { + ($name:expr, $value:expr) => { + println!("cargo:rustc-env=SGL_MODEL_GATEWAY_{}={}", $name, $value); + }; +} fn main() -> Result<(), Box> { - // Only regenerate if proto files change + // Rebuild triggers println!("cargo:rerun-if-changed=src/proto/sglang_scheduler.proto"); println!("cargo:rerun-if-changed=src/proto/vllm_engine.proto"); - println!("cargo:rerun-if-changed=pyproject.toml"); + println!("cargo:rerun-if-changed=Cargo.toml"); - // Configure tonic-prost-build for gRPC code generation + // Compile protobuf files tonic_prost_build::configure() - // Generate both client and server code .build_server(true) .build_client(true) - // Add serde Serialize for model info messages (we only need to serialize to labels) .type_attribute("GetModelInfoResponse", "#[derive(serde::Serialize)]") - // Allow proto3 optional fields .protoc_arg("--experimental_allow_proto3_optional") - // Compile both proto files .compile_protos( &[ "src/proto/sglang_scheduler.proto", @@ -28,131 +30,95 @@ fn main() -> Result<(), Box> { &["src/proto"], )?; - println!("cargo:info=Protobuf compilation completed successfully"); + // Set version info environment variables + let version = read_cargo_version().unwrap_or_else(|_| DEFAULT_VERSION.to_string()); + let target = std::env::var("TARGET").unwrap_or_else(|_| get_rustc_host().unwrap_or_default()); + let profile = std::env::var("PROFILE").unwrap_or_default(); - // Read version and project name from pyproject.toml with fallback - let version = - read_field_from_pyproject("version").unwrap_or_else(|_| DEFAULT_VERSION.to_string()); - let project_name = - read_field_from_pyproject("name").unwrap_or_else(|_| DEFAULT_PROJECT_NAME.to_string()); - println!("cargo:rustc-env=SGL_ROUTER_VERSION={}", version); - println!("cargo:rustc-env=SGL_ROUTER_PROJECT_NAME={}", project_name); - - // Generate build time (UTC) - let build_time = chrono::Utc::now() - .format("%Y-%m-%d %H:%M:%S UTC") - .to_string(); - println!("cargo:rustc-env=SGL_ROUTER_BUILD_TIME={}", build_time); - - // Try to get Git branch - let git_branch = get_git_branch().unwrap_or_else(|| "unknown".to_string()); - println!("cargo:rustc-env=SGL_ROUTER_GIT_BRANCH={}", git_branch); - - // Try to get Git commit hash - let git_commit = get_git_commit().unwrap_or_else(|| "unknown".to_string()); - println!("cargo:rustc-env=SGL_ROUTER_GIT_COMMIT={}", git_commit); - - // Try to get Git status (clean/dirty) - let git_status = get_git_status().unwrap_or_else(|| "unknown".to_string()); - println!("cargo:rustc-env=SGL_ROUTER_GIT_STATUS={}", git_status); - - // Get Rustc version - let rustc_version = get_rustc_version().unwrap_or_else(|| "unknown".to_string()); - println!("cargo:rustc-env=SGL_ROUTER_RUSTC_VERSION={}", rustc_version); - - // Get Cargo version - let cargo_version = get_cargo_version().unwrap_or_else(|| "unknown".to_string()); - println!("cargo:rustc-env=SGL_ROUTER_CARGO_VERSION={}", cargo_version); - - // Get target triple (platform) - let target_triple = std::env::var("TARGET").unwrap_or_else(|_| { - // Try to get from rustc if not set - get_target_from_rustc().unwrap_or_else(|| "unknown".to_string()) - }); - println!("cargo:rustc-env=SGL_ROUTER_TARGET_TRIPLE={}", target_triple); - - // Get build mode (debug/release) - let build_mode = if std::env::var("PROFILE").unwrap_or_default() == "release" { - "release" - } else { - "debug" - }; - println!("cargo:rustc-env=SGL_ROUTER_BUILD_MODE={}", build_mode); + set_env!("PROJECT_NAME", DEFAULT_PROJECT_NAME); + set_env!("VERSION", version); + set_env!( + "BUILD_TIME", + chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC") + ); + set_env!( + "BUILD_MODE", + if profile == "release" { + "release" + } else { + "debug" + } + ); + set_env!("TARGET_TRIPLE", target); + set_env!( + "GIT_BRANCH", + git_branch().unwrap_or_else(|| "unknown".into()) + ); + set_env!( + "GIT_COMMIT", + git_commit().unwrap_or_else(|| "unknown".into()) + ); + set_env!( + "GIT_STATUS", + git_status().unwrap_or_else(|| "unknown".into()) + ); + set_env!( + "RUSTC_VERSION", + rustc_version().unwrap_or_else(|| "unknown".into()) + ); + set_env!( + "CARGO_VERSION", + cargo_version().unwrap_or_else(|| "unknown".into()) + ); Ok(()) } -fn read_field_from_pyproject(field: &str) -> Result> { - let content = std::fs::read_to_string("pyproject.toml")?; +fn read_cargo_version() -> Result> { + let content = std::fs::read_to_string("Cargo.toml")?; let toml: toml::Value = toml::from_str(&content)?; - - // Navigate to [project] section - let project = toml - .get("project") - .ok_or("Missing [project] section in pyproject.toml")?; - - // Get the field value - let value = project - .get(field) - .ok_or_else(|| format!("Missing '{}' field in [project] section", field))?; - - // Convert to string - match value { - toml::Value::String(s) => Ok(s.clone()), - toml::Value::Integer(i) => Ok(i.to_string()), - toml::Value::Float(f) => Ok(f.to_string()), - toml::Value::Boolean(b) => Ok(b.to_string()), - _ => Err(format!("Field '{}' is not a string value", field).into()), - } + toml.get("package") + .and_then(|p| p.get("version")) + .and_then(|v| v.as_str()) + .map(String::from) + .ok_or_else(|| "Missing version in Cargo.toml".into()) } -/// Execute a command and return its output as a trimmed string -fn run_command(command: &str, args: &[&str]) -> Option { - let output = Command::new(command).args(args).output().ok()?; - - if output.status.success() { - String::from_utf8(output.stdout) - .ok() - .map(|s| s.trim().to_string()) - } else { - None - } +fn run_cmd(cmd: &str, args: &[&str]) -> Option { + Command::new(cmd) + .args(args) + .output() + .ok() + .filter(|o| o.status.success()) + .and_then(|o| String::from_utf8(o.stdout).ok()) + .map(|s| s.trim().to_string()) } -fn get_git_branch() -> Option { - run_command("git", &["rev-parse", "--abbrev-ref", "HEAD"]) +fn git_branch() -> Option { + run_cmd("git", &["rev-parse", "--abbrev-ref", "HEAD"]) } -fn get_git_commit() -> Option { - run_command("git", &["rev-parse", "--short", "HEAD"]) +fn git_commit() -> Option { + run_cmd("git", &["rev-parse", "--short", "HEAD"]) } -fn get_git_status() -> Option { - // Check if there are uncommitted changes - let output = run_command("git", &["status", "--porcelain"])?; - if output.is_empty() { - Some("clean".to_string()) - } else { - Some("dirty".to_string()) - } +fn git_status() -> Option { + run_cmd("git", &["status", "--porcelain"]) + .map(|s| if s.is_empty() { "clean" } else { "dirty" }.into()) } -fn get_rustc_version() -> Option { - run_command("rustc", &["--version"]) +fn rustc_version() -> Option { + run_cmd("rustc", &["--version"]) } -fn get_cargo_version() -> Option { - run_command("cargo", &["--version"]) +fn cargo_version() -> Option { + run_cmd("cargo", &["--version"]) } -fn get_target_from_rustc() -> Option { - let output_str = run_command("rustc", &["-vV"])?; - for line in output_str.lines() { - if line.starts_with("host: ") { - if let Some(host) = line.strip_prefix("host: ") { - return Some(host.trim().to_string()); - } - } - } - None +fn get_rustc_host() -> Option { + run_cmd("rustc", &["-vV"])? + .lines() + .find(|l| l.starts_with("host: ")) + .and_then(|l| l.strip_prefix("host: ")) + .map(|s| s.trim().to_string()) } diff --git a/sgl-router/src/main.rs b/sgl-router/src/main.rs index 968a35aa8..2ea5ee82a 100644 --- a/sgl-router/src/main.rs +++ b/sgl-router/src/main.rs @@ -691,8 +691,8 @@ fn main() -> Result<(), Box> { println!("{}", version::get_version_string()); return Ok(()); } - if arg == "-v" { - println!("{}", version::get_short_version_string()); + if arg == "--version-verbose" { + println!("{}", version::get_verbose_version_string()); return Ok(()); } } diff --git a/sgl-router/src/version.rs b/sgl-router/src/version.rs index 76c0c3b38..1c4726f14 100644 --- a/sgl-router/src/version.rs +++ b/sgl-router/src/version.rs @@ -2,38 +2,30 @@ //! //! Provides version information including version number, build time, and Git metadata. -/// Project name from pyproject.toml (set at compile time) -pub const PROJECT_NAME: &str = env!("SGL_ROUTER_PROJECT_NAME"); +macro_rules! build_env { + ($name:ident) => { + env!(concat!("SGL_MODEL_GATEWAY_", stringify!($name))) + }; +} -/// Version string from pyproject.toml (set at compile time) -pub const VERSION: &str = env!("SGL_ROUTER_VERSION"); +pub const PROJECT_NAME: &str = build_env!(PROJECT_NAME); +pub const VERSION: &str = build_env!(VERSION); +pub const BUILD_TIME: &str = build_env!(BUILD_TIME); +pub const GIT_BRANCH: &str = build_env!(GIT_BRANCH); +pub const GIT_COMMIT: &str = build_env!(GIT_COMMIT); +pub const GIT_STATUS: &str = build_env!(GIT_STATUS); +pub const RUSTC_VERSION: &str = build_env!(RUSTC_VERSION); +pub const CARGO_VERSION: &str = build_env!(CARGO_VERSION); +pub const TARGET_TRIPLE: &str = build_env!(TARGET_TRIPLE); +pub const BUILD_MODE: &str = build_env!(BUILD_MODE); -/// Build time in UTC format (set at compile time) -pub const BUILD_TIME: &str = env!("SGL_ROUTER_BUILD_TIME"); - -/// Git branch name (set at compile time, "unknown" if not available) -pub const GIT_BRANCH: &str = env!("SGL_ROUTER_GIT_BRANCH"); - -/// Git commit hash (short) (set at compile time, "unknown" if not available) -pub const GIT_COMMIT: &str = env!("SGL_ROUTER_GIT_COMMIT"); - -/// Git repository status (clean/dirty) (set at compile time) -pub const GIT_STATUS: &str = env!("SGL_ROUTER_GIT_STATUS"); - -/// Rustc version (set at compile time) -pub const RUSTC_VERSION: &str = env!("SGL_ROUTER_RUSTC_VERSION"); - -/// Cargo version (set at compile time) -pub const CARGO_VERSION: &str = env!("SGL_ROUTER_CARGO_VERSION"); - -/// Target triple (platform) (set at compile time) -pub const TARGET_TRIPLE: &str = env!("SGL_ROUTER_TARGET_TRIPLE"); - -/// Build mode (debug/release) (set at compile time) -pub const BUILD_MODE: &str = env!("SGL_ROUTER_BUILD_MODE"); - -/// Get formatted version information string with structured format +/// Get simple version string (default for --version) pub fn get_version_string() -> String { + format!("{} {}", PROJECT_NAME, VERSION) +} + +/// Get verbose version information string with full build details (for --version-verbose) +pub fn get_verbose_version_string() -> String { format!( "{}\n\n\ Build Information:\n\ @@ -47,7 +39,7 @@ Version Control:\n\ Compiler:\n\ {}\n\ {}", - get_title(), + get_version_string(), BUILD_TIME, BUILD_MODE, TARGET_TRIPLE, @@ -59,17 +51,7 @@ Compiler:\n\ ) } -/// Get version title line -pub fn get_title() -> String { - format!("{} version {}", PROJECT_NAME, VERSION) -} - /// Get version number only pub fn get_version() -> &'static str { VERSION } - -/// Get short version information string -pub fn get_short_version_string() -> String { - format!("{} version {}, build {}", PROJECT_NAME, VERSION, GIT_COMMIT) -}