[model-gateway] fix version output (#14276)

This commit is contained in:
Simo Lin
2025-12-01 22:51:57 -08:00
committed by GitHub
parent 236a7c2370
commit 383689e3ad
6 changed files with 120 additions and 169 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "sglang-router" name = "sglang-router"
version = "0.2.2" version = "0.2.3"
edition = "2021" edition = "2021"
[features] [features]
@@ -15,7 +15,10 @@ import os
import sys import sys
from typing import List, Optional 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: def create_parser() -> argparse.ArgumentParser:
@@ -54,11 +57,11 @@ def main(argv: Optional[List[str]] = None) -> None:
argv = sys.argv[1:] argv = sys.argv[1:]
# Handle version flags before parsing # Handle version flags before parsing
if argv and argv[0] in ["--version", "-V"]: if argv and argv[0] in ["--version", "-V", "--version-verbose"]:
if argv[0] == "--version": if argv[0] == "--version-verbose":
print(get_version_string()) print(get_verbose_version_string())
else: else:
print(get_short_version_string()) print(get_version_string())
sys.exit(0) sys.exit(0)
# Handle empty command - show help # Handle empty command - show help
+5 -5
View File
@@ -704,16 +704,16 @@ impl Router {
} }
} }
/// Get formatted version information string with full build details /// Get simple version string (default for --version)
#[pyfunction] #[pyfunction]
fn get_version_string() -> String { fn get_version_string() -> String {
version::get_version_string() version::get_version_string()
} }
/// Get short version information string /// Get verbose version information string with full build details (for --version-verbose)
#[pyfunction] #[pyfunction]
fn get_short_version_string() -> String { fn get_verbose_version_string() -> String {
version::get_short_version_string() version::get_verbose_version_string()
} }
#[pymodule] #[pymodule]
@@ -725,6 +725,6 @@ fn sglang_router_rs(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyPostgresConfig>()?; m.add_class::<PyPostgresConfig>()?;
m.add_class::<Router>()?; m.add_class::<Router>()?;
m.add_function(wrap_pyfunction!(get_version_string, m)?)?; 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(()) Ok(())
} }
+82 -116
View File
@@ -1,25 +1,27 @@
use std::process::Command; 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_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<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
// 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/sglang_scheduler.proto");
println!("cargo:rerun-if-changed=src/proto/vllm_engine.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() tonic_prost_build::configure()
// Generate both client and server code
.build_server(true) .build_server(true)
.build_client(true) .build_client(true)
// Add serde Serialize for model info messages (we only need to serialize to labels)
.type_attribute("GetModelInfoResponse", "#[derive(serde::Serialize)]") .type_attribute("GetModelInfoResponse", "#[derive(serde::Serialize)]")
// Allow proto3 optional fields
.protoc_arg("--experimental_allow_proto3_optional") .protoc_arg("--experimental_allow_proto3_optional")
// Compile both proto files
.compile_protos( .compile_protos(
&[ &[
"src/proto/sglang_scheduler.proto", "src/proto/sglang_scheduler.proto",
@@ -28,131 +30,95 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
&["src/proto"], &["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 set_env!("PROJECT_NAME", DEFAULT_PROJECT_NAME);
let version = set_env!("VERSION", version);
read_field_from_pyproject("version").unwrap_or_else(|_| DEFAULT_VERSION.to_string()); set_env!(
let project_name = "BUILD_TIME",
read_field_from_pyproject("name").unwrap_or_else(|_| DEFAULT_PROJECT_NAME.to_string()); chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC")
println!("cargo:rustc-env=SGL_ROUTER_VERSION={}", version); );
println!("cargo:rustc-env=SGL_ROUTER_PROJECT_NAME={}", project_name); set_env!(
"BUILD_MODE",
// Generate build time (UTC) if profile == "release" {
let build_time = chrono::Utc::now() "release"
.format("%Y-%m-%d %H:%M:%S UTC") } else {
.to_string(); "debug"
println!("cargo:rustc-env=SGL_ROUTER_BUILD_TIME={}", build_time); }
);
// Try to get Git branch set_env!("TARGET_TRIPLE", target);
let git_branch = get_git_branch().unwrap_or_else(|| "unknown".to_string()); set_env!(
println!("cargo:rustc-env=SGL_ROUTER_GIT_BRANCH={}", git_branch); "GIT_BRANCH",
git_branch().unwrap_or_else(|| "unknown".into())
// Try to get Git commit hash );
let git_commit = get_git_commit().unwrap_or_else(|| "unknown".to_string()); set_env!(
println!("cargo:rustc-env=SGL_ROUTER_GIT_COMMIT={}", git_commit); "GIT_COMMIT",
git_commit().unwrap_or_else(|| "unknown".into())
// Try to get Git status (clean/dirty) );
let git_status = get_git_status().unwrap_or_else(|| "unknown".to_string()); set_env!(
println!("cargo:rustc-env=SGL_ROUTER_GIT_STATUS={}", git_status); "GIT_STATUS",
git_status().unwrap_or_else(|| "unknown".into())
// Get Rustc version );
let rustc_version = get_rustc_version().unwrap_or_else(|| "unknown".to_string()); set_env!(
println!("cargo:rustc-env=SGL_ROUTER_RUSTC_VERSION={}", rustc_version); "RUSTC_VERSION",
rustc_version().unwrap_or_else(|| "unknown".into())
// Get Cargo version );
let cargo_version = get_cargo_version().unwrap_or_else(|| "unknown".to_string()); set_env!(
println!("cargo:rustc-env=SGL_ROUTER_CARGO_VERSION={}", cargo_version); "CARGO_VERSION",
cargo_version().unwrap_or_else(|| "unknown".into())
// 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);
Ok(()) Ok(())
} }
fn read_field_from_pyproject(field: &str) -> Result<String, Box<dyn std::error::Error>> { fn read_cargo_version() -> Result<String, Box<dyn std::error::Error>> {
let content = std::fs::read_to_string("pyproject.toml")?; let content = std::fs::read_to_string("Cargo.toml")?;
let toml: toml::Value = toml::from_str(&content)?; let toml: toml::Value = toml::from_str(&content)?;
toml.get("package")
// Navigate to [project] section .and_then(|p| p.get("version"))
let project = toml .and_then(|v| v.as_str())
.get("project") .map(String::from)
.ok_or("Missing [project] section in pyproject.toml")?; .ok_or_else(|| "Missing version in Cargo.toml".into())
// 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()),
}
} }
/// Execute a command and return its output as a trimmed string fn run_cmd(cmd: &str, args: &[&str]) -> Option<String> {
fn run_command(command: &str, args: &[&str]) -> Option<String> { Command::new(cmd)
let output = Command::new(command).args(args).output().ok()?; .args(args)
.output()
if output.status.success() { .ok()
String::from_utf8(output.stdout) .filter(|o| o.status.success())
.ok() .and_then(|o| String::from_utf8(o.stdout).ok())
.map(|s| s.trim().to_string()) .map(|s| s.trim().to_string())
} else {
None
}
} }
fn get_git_branch() -> Option<String> { fn git_branch() -> Option<String> {
run_command("git", &["rev-parse", "--abbrev-ref", "HEAD"]) run_cmd("git", &["rev-parse", "--abbrev-ref", "HEAD"])
} }
fn get_git_commit() -> Option<String> { fn git_commit() -> Option<String> {
run_command("git", &["rev-parse", "--short", "HEAD"]) run_cmd("git", &["rev-parse", "--short", "HEAD"])
} }
fn get_git_status() -> Option<String> { fn git_status() -> Option<String> {
// Check if there are uncommitted changes run_cmd("git", &["status", "--porcelain"])
let output = run_command("git", &["status", "--porcelain"])?; .map(|s| if s.is_empty() { "clean" } else { "dirty" }.into())
if output.is_empty() {
Some("clean".to_string())
} else {
Some("dirty".to_string())
}
} }
fn get_rustc_version() -> Option<String> { fn rustc_version() -> Option<String> {
run_command("rustc", &["--version"]) run_cmd("rustc", &["--version"])
} }
fn get_cargo_version() -> Option<String> { fn cargo_version() -> Option<String> {
run_command("cargo", &["--version"]) run_cmd("cargo", &["--version"])
} }
fn get_target_from_rustc() -> Option<String> { fn get_rustc_host() -> Option<String> {
let output_str = run_command("rustc", &["-vV"])?; run_cmd("rustc", &["-vV"])?
for line in output_str.lines() { .lines()
if line.starts_with("host: ") { .find(|l| l.starts_with("host: "))
if let Some(host) = line.strip_prefix("host: ") { .and_then(|l| l.strip_prefix("host: "))
return Some(host.trim().to_string()); .map(|s| s.trim().to_string())
}
}
}
None
} }
+2 -2
View File
@@ -691,8 +691,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("{}", version::get_version_string()); println!("{}", version::get_version_string());
return Ok(()); return Ok(());
} }
if arg == "-v" { if arg == "--version-verbose" {
println!("{}", version::get_short_version_string()); println!("{}", version::get_verbose_version_string());
return Ok(()); return Ok(());
} }
} }
+22 -40
View File
@@ -2,38 +2,30 @@
//! //!
//! Provides version information including version number, build time, and Git metadata. //! Provides version information including version number, build time, and Git metadata.
/// Project name from pyproject.toml (set at compile time) macro_rules! build_env {
pub const PROJECT_NAME: &str = env!("SGL_ROUTER_PROJECT_NAME"); ($name:ident) => {
env!(concat!("SGL_MODEL_GATEWAY_", stringify!($name)))
};
}
/// Version string from pyproject.toml (set at compile time) pub const PROJECT_NAME: &str = build_env!(PROJECT_NAME);
pub const VERSION: &str = env!("SGL_ROUTER_VERSION"); 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) /// Get simple version string (default for --version)
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
pub fn get_version_string() -> String { 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!( format!(
"{}\n\n\ "{}\n\n\
Build Information:\n\ Build Information:\n\
@@ -47,7 +39,7 @@ Version Control:\n\
Compiler:\n\ Compiler:\n\
{}\n\ {}\n\
{}", {}",
get_title(), get_version_string(),
BUILD_TIME, BUILD_TIME,
BUILD_MODE, BUILD_MODE,
TARGET_TRIPLE, 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 /// Get version number only
pub fn get_version() -> &'static str { pub fn get_version() -> &'static str {
VERSION VERSION
} }
/// Get short version information string
pub fn get_short_version_string() -> String {
format!("{} version {}, build {}", PROJECT_NAME, VERSION, GIT_COMMIT)
}