mirror of
https://github.com/wisdgod/cursor-api.git
synced 2025-12-24 13:38:01 +08:00
This is a special version (since the repository hasn't been updated for a while). It includes partial updates from 0.3 to 0.4, along with several fixes for 0.4.0-pre.13. 这是一个特殊版本(因为一段时间没有更新存储库),它包含0.3至0.4的部分更新以及对0.4.0-pre.13的几处修复。
242 lines
7.8 KiB
Rust
242 lines
7.8 KiB
Rust
include!("src/app/model/version.rs");
|
||
|
||
/// 版本字符串解析错误
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub enum ParseError {
|
||
/// 整体格式错误(如缺少必需部分)
|
||
InvalidFormat,
|
||
/// 数字解析失败
|
||
InvalidNumber,
|
||
/// pre 部分格式错误
|
||
InvalidPreRelease,
|
||
/// build 部分格式错误
|
||
InvalidBuild,
|
||
// /// 正式版不能带 build 标识
|
||
// BuildWithoutPreview,
|
||
}
|
||
|
||
impl core::fmt::Display for ParseError {
|
||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||
match self {
|
||
ParseError::InvalidFormat => write!(f, "invalid version format"),
|
||
ParseError::InvalidNumber => write!(f, "invalid number in version"),
|
||
ParseError::InvalidPreRelease => write!(f, "invalid pre-release format"),
|
||
ParseError::InvalidBuild => write!(f, "invalid build format"),
|
||
// ParseError::BuildWithoutPreview => {
|
||
// write!(f, "build metadata cannot exist without pre-release version")
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
|
||
impl std::error::Error for ParseError {}
|
||
|
||
impl core::str::FromStr for Version {
|
||
type Err = ParseError;
|
||
|
||
fn from_str(s: &str) -> core::result::Result<Self, Self::Err> {
|
||
// 按 '-' 分割基础版本号和扩展部分
|
||
let (base, extension) = match s.split_once('-') {
|
||
Some((base, ext)) => (base, Some(ext)),
|
||
None => (s, None),
|
||
};
|
||
|
||
// 解析基础版本号 major.minor.patch
|
||
let mut parts: [u16; 3] = [0, 0, 0];
|
||
let mut parsed_count = 0;
|
||
for (i, s) in base.split('.').enumerate() {
|
||
if i >= parts.len() {
|
||
return Err(ParseError::InvalidFormat);
|
||
}
|
||
parts[i] = s.parse().map_err(|_| ParseError::InvalidNumber)?;
|
||
parsed_count += 1;
|
||
}
|
||
if parsed_count != 3 {
|
||
return Err(ParseError::InvalidFormat);
|
||
}
|
||
|
||
let major = parts[0];
|
||
let minor = parts[1];
|
||
let patch = parts[2];
|
||
|
||
// 解析扩展部分(如果存在)
|
||
let stage =
|
||
if let Some(ext) = extension { parse_extension(ext)? } else { ReleaseStage::Release };
|
||
|
||
Ok(Version { major, minor, patch, stage })
|
||
}
|
||
}
|
||
|
||
/// 解析扩展部分:pre.X 或 pre.X+build.Y
|
||
fn parse_extension(s: &str) -> core::result::Result<ReleaseStage, ParseError> {
|
||
// 检查是否以 "pre." 开头
|
||
if !s.starts_with("pre.") {
|
||
return Err(ParseError::InvalidPreRelease);
|
||
}
|
||
|
||
// 移除 "pre." 前缀
|
||
let after_pre = &s[4..];
|
||
|
||
// 按 '+' 分割 version 和 build 部分
|
||
let (version_str, build_str) = match after_pre.split_once('+') {
|
||
Some((ver, build_part)) => (ver, Some(build_part)),
|
||
None => (after_pre, None),
|
||
};
|
||
|
||
// 解析 pre 版本号
|
||
let version = version_str.parse().map_err(|_| ParseError::InvalidPreRelease)?;
|
||
|
||
// 解析 build 号(如果存在)
|
||
let build = if let Some(build_part) = build_str {
|
||
// 检查格式是否为 "build.X"
|
||
if !build_part.starts_with("build.") {
|
||
return Err(ParseError::InvalidBuild);
|
||
}
|
||
|
||
let build_num_str = &build_part[6..];
|
||
let build_num = build_num_str.parse().map_err(|_| ParseError::InvalidBuild)?;
|
||
|
||
Some(build_num)
|
||
} else {
|
||
None
|
||
};
|
||
|
||
Ok(ReleaseStage::Preview { version, build })
|
||
}
|
||
|
||
/**
|
||
* 更新版本号函数
|
||
* 此函数会读取 VERSION 文件中的数字,将其加1,然后保存回文件
|
||
* 如果 VERSION 文件不存在或为空,将从1开始计数
|
||
* 只在 release 模式下执行,debug/dev 模式下完全跳过
|
||
*/
|
||
#[cfg(not(debug_assertions))]
|
||
#[cfg(feature = "__preview")]
|
||
fn update_version() -> Result<()> {
|
||
let version_path = "VERSION";
|
||
// VERSION文件的监控已经在main函数中添加,此处无需重复
|
||
|
||
// 读取当前版本号
|
||
let mut version = String::new();
|
||
let mut file = match File::open(version_path) {
|
||
Ok(file) => file,
|
||
Err(_) => {
|
||
// 如果文件不存在或无法打开,从1开始
|
||
println!("cargo:warning=VERSION file not found, creating with initial value 1");
|
||
let mut new_file = File::create(version_path)?;
|
||
new_file.write_all(b"1")?;
|
||
return Ok(());
|
||
}
|
||
};
|
||
|
||
file.read_to_string(&mut version)?;
|
||
|
||
// 确保版本号是有效数字
|
||
#[allow(unused_variables)]
|
||
let version_num = match version.trim().parse::<u64>() {
|
||
Ok(num) => num,
|
||
Err(_) => {
|
||
println!("cargo:warning=Invalid version number in VERSION file. Setting to 1.");
|
||
let mut file = File::create(version_path)?;
|
||
file.write_all(b"1")?;
|
||
return Ok(());
|
||
}
|
||
};
|
||
|
||
#[cfg(not(feature = "__preview_locked"))]
|
||
{
|
||
// 版本号加1
|
||
let new_version = version_num + 1;
|
||
println!(
|
||
"cargo:warning=Release build - bumping version from {version_num} to {new_version}",
|
||
);
|
||
|
||
// 写回文件
|
||
let mut file = File::create(version_path)?;
|
||
write!(file, "{new_version}")?;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
#[allow(unused)]
|
||
fn read_version_number() -> Result<u64> {
|
||
let mut version = String::with_capacity(4);
|
||
match std::fs::File::open("VERSION") {
|
||
Ok(mut file) => {
|
||
use std::io::Read as _;
|
||
file.read_to_string(&mut version)?;
|
||
Ok(version.trim().parse().unwrap_or(1))
|
||
}
|
||
Err(_) => Ok(1),
|
||
}
|
||
}
|
||
|
||
fn generate_build_info() -> Result<()> {
|
||
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||
let dest_path = Path::new(&out_dir).join("build_info.rs");
|
||
// #[cfg(debug_assertions)]
|
||
// let out_dir = "../target/debug/build/build_info.rs";
|
||
// #[cfg(not(debug_assertions))]
|
||
// let out_dir = "../target/release/build/build_info.rs";
|
||
// let dest_path = Path::new(out_dir);
|
||
// if dest_path.is_file() {
|
||
// return Ok(());
|
||
// }
|
||
|
||
let build_timestamp =
|
||
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
|
||
|
||
let build_timestamp_str = chrono::DateTime::from_timestamp(build_timestamp as i64, 0)
|
||
.unwrap()
|
||
.to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
||
|
||
let pkg_version = env!("CARGO_PKG_VERSION");
|
||
|
||
let (version_str, build_version_str) =
|
||
if cfg!(feature = "__preview") && pkg_version.contains("-pre") {
|
||
let build_num = read_version_number()?;
|
||
(
|
||
format!("{pkg_version}+build.{build_num}"),
|
||
format!("pub const BUILD_VERSION: u32 = {build_num};\n"),
|
||
)
|
||
} else {
|
||
(pkg_version.to_string(), String::new())
|
||
};
|
||
|
||
let version: Version = version_str.parse().unwrap();
|
||
|
||
let build_info_content = format!(
|
||
r#"// 此文件由 build.rs 自动生成,请勿手动修改
|
||
use crate::app::model::version::{{Version, ReleaseStage::Preview}};
|
||
|
||
{build_version_str}pub const BUILD_TIMESTAMP: &'static str = {build_timestamp_str:?};
|
||
/// pub const VERSION_STR: &'static str = {version_str:?};
|
||
pub const VERSION: Version = {version:?};
|
||
pub const IS_PRERELEASE: bool = {is_prerelease};
|
||
pub const IS_DEBUG: bool = {is_debug};
|
||
|
||
#[cfg(unix)]
|
||
pub const BUILD_EPOCH: std::time::SystemTime =
|
||
unsafe {{ ::core::intrinsics::transmute(({build_timestamp}i64, 0u32)) }};
|
||
|
||
#[cfg(windows)]
|
||
pub const BUILD_EPOCH: std::time::SystemTime = unsafe {{
|
||
const INTERVALS_PER_SEC: u64 = 10_000_000;
|
||
const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC;
|
||
const TARGET_INTERVALS: u64 = INTERVALS_TO_UNIX_EPOCH + {build_timestamp} * INTERVALS_PER_SEC;
|
||
|
||
::core::intrinsics::transmute((
|
||
TARGET_INTERVALS as u32,
|
||
(TARGET_INTERVALS >> 32) as u32,
|
||
))
|
||
}};
|
||
"#,
|
||
is_prerelease = cfg!(feature = "__preview"),
|
||
is_debug = cfg!(debug_assertions),
|
||
);
|
||
|
||
std::fs::write(dest_path, build_info_content)?;
|
||
Ok(())
|
||
}
|