Unlucky Launcher v0.2.0
CI / runtime smoke (macos arm64, probe) (push) Skipped
CI / fmt (rustfmt --check) (push) Canceled after 0s
CI / clippy (ubuntu-latest) (push) Canceled after 0s
CI / clippy (windows-latest) (push) Canceled after 0s
CI / test (ubuntu-latest) (push) Canceled after 0s
CI / test (windows-latest) (push) Canceled after 0s
CI / build release (ubuntu-latest) (push) Canceled after 0s
CI / build release (windows-latest) (push) Canceled after 0s
CI / runtime smoke (ubuntu x64, xvfb) (push) Canceled after 0s
Guards / core 零 UI 守门 (push) Canceled after 0s
Guards / presenter 零 UI 守门 (push) Canceled after 0s
Guards / design 零第三方依赖守门 (push) Canceled after 0s
Guards / unsafe 落点守门(集合必须恰好一个文件) (push) Canceled after 0s
Guards / 文件行数 ≤400 守门 (push) Canceled after 0s
Guards / 依赖许可与来源(cargo-deny) (push) Canceled after 0s

首个 iced + Material 3 Expressive 版本的源码快照。
完整历史与日常提交在 dev 分支;main 只放阶段性快照。
This commit is contained in:
AskaEth committed 2026-11-05 14:22:11 +08:00
commit 8a8e5ca0c0
1079 files changed
+208035

No files matched your search

+141
View File
@@ -0,0 +1,141 @@
//! `ull java vendors`:四家发行版的可用性 / 镜像 / 当前优先级顺序(D23)。
//!
//! 从 `commands/java.rs` 拆出来(那边 list/install 已经占满一屏)。这里只读不写:
//! 不联网、不改配置,把 `mirrors.json` 的表与设置里的优先级排成一张人读 + `--json` 的对照表。
//!
//! 存在的意义是**可观测**:用户问「国内为什么默认走 Oracle 而不是微软」时,命令要能直接答
//! (顺序 + 每家的镜像与实测吞吐),而不是让人翻文档。
use serde_json::{json, Value};
use unlucky_core::download::MirrorTable;
use unlucky_core::game::java::{vendor, JdkVendor};
use super::java::{region_profile, JavaSettings};
use crate::context::Ctx;
use crate::error::CliError;
use crate::output::Report;
/// `ull java vendors`。
///
/// # Errors
///
/// 设置文件坏掉时退化为默认值;命令本身不产生用户错误。
pub fn vendors(ctx: &Ctx) -> Result<Report, CliError> {
let settings = JavaSettings::load(ctx);
let domestic = region_profile(ctx).is_domestic();
let order = vendor::order(&settings.priority, domestic);
let table = MirrorTable::builtin();
let rows: Vec<Value> = order
.iter()
.enumerate()
.map(|(index, item)| vendor_json(&table, *item, index))
.collect();
let priority_source = if settings.priority.is_empty() {
"region_default"
} else {
"java.vendorPriority"
};
let data = json!({
"region": if domestic { "domestic" } else { "global" },
"priority_source": priority_source,
"order": vendor::ids(&order),
"vendors": rows,
});
let mut human = vec![format!(
"发行版顺序({},来源 {}):{}",
if domestic { "国内" } else { "国外" },
if settings.priority.is_empty() {
"地区默认序"
} else {
"java.vendorPriority"
},
vendor::ids(&order).join(" → ")
)];
for row in &rows {
human.push(format!(
" {} {} {} 支持 Java {}",
row["rank"].as_u64().unwrap_or(0),
row["vendor"].as_str().unwrap_or("?"),
row["display"].as_str().unwrap_or(""),
join_numbers(&row["majors"], "/")
));
for source in row["sources"].as_array().into_iter().flatten() {
if let Some(text) = source.as_str() {
human.push(format!(" 源:{text}"));
}
}
}
Ok(Report::new(data, human))
}
/// 一家的 `--json` 形状(源清单按家取,缺表时为空数组而不是报错)。
fn vendor_json(table: &MirrorTable, item: JdkVendor, index: usize) -> Value {
let sources: Vec<String> = match item {
JdkVendor::Temurin => table
.adoptium
.iter()
.filter(|mirror| mirror.enabled)
.map(|mirror| {
format!(
"{}{}",
mirror.name,
if mirror.latest_only {
"(只留最新补丁)"
} else {
""
}
)
})
.chain(std::iter::once(
"GitHub 官方(国内套 gh-proxy)".to_string(),
))
.collect(),
JdkVendor::Oracle => table
.oracle_mirrors()
.map(|mirror| match mirror.speed.trim() {
"" => format!("{} {}", mirror.name, mirror.base()),
speed => format!("{} {} {}", mirror.name, mirror.base(), speed),
})
.collect(),
JdkVendor::Microsoft => table
.microsoft_openjdk()
.map(|microsoft| {
let speed = if microsoft.measured_speed.trim().is_empty() {
"实测约 400 KB/s".to_string()
} else {
microsoft.measured_speed.clone()
};
vec![format!(
"aka.ms → VS CDN({speed});无国内镜像、无 GitHub 资产"
)]
})
.unwrap_or_default(),
JdkVendor::Zulu => table
.zulu()
.map(|zulu| vec![format!("{}({})", zulu.api, zulu.measured_speed)])
.unwrap_or_default(),
};
json!({
"rank": index + 1,
"vendor": item.id(),
"display": item.display(),
"majors": item.hint_majors(),
"supported": (8..=99u32).filter(|major| item.supports(*major)).collect::<Vec<_>>(),
"sources": sources,
})
}
/// JSON 数字数组 → `21/17/11` 这种分隔串。
fn join_numbers(value: &Value, separator: &str) -> String {
value
.as_array()
.map(|items| {
items
.iter()
.filter_map(Value::as_u64)
.map(|number| number.to_string())
.collect::<Vec<_>>()
.join(separator)
})
.unwrap_or_default()
}