fix: 架构审查修复 — broadcast、目标校验、import_csv 警告、workspace 元数据统一

- HIGH: CLI 所有修改命令补 broadcast_env_change()
- HIGH: --system/--user 互斥校验,不再静默忽略
- MEDIUM: gui/Cargo.toml 删冗余 serde_json(log 保留,lib.rs 实际使用)
- MEDIUM: import_csv 对跳过行输出 log::warn
- MEDIUM: ProfilePathEntry 从 core 重导出
- LOW: Cargo workspace.package 统一元数据

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 23:52:31 +08:00
parent a553a16a64
commit 1320aa57a8
7 changed files with 43 additions and 31 deletions
+7
View File
@@ -5,3 +5,10 @@ members = [
"gui",
"cli",
]
[workspace.package]
version = "5.0.0"
edition = "2021"
license = "MIT"
authors = ["刘航宇"]
repository = "https://github.com/LHY0125/PathEditor"
+4 -8
View File
@@ -1,16 +1,12 @@
[package]
name = "patheditor-cli"
version = "5.0.0"
description = "PathEditor CLI — command-line interface for Windows PATH management"
authors = ["刘航宇"]
license = "MIT"
edition = "2021"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
[dependencies]
path-editor-core = { path = "../core" }
clap = { version = "4", features = ["derive"] }
serde_json = "1"
[[bin]]
name = "patheditor"
path = "src/main.rs"
+15 -9
View File
@@ -110,14 +110,15 @@ fn exit_err(msg: &str) -> ! {
std::process::exit(1);
}
fn pick_target(system: bool, _user: bool) -> &'static str {
fn ensure_single_target(system: bool, user: bool) -> &'static str {
if system && user { exit_err("不能同时指定 --system 和 --user"); }
if system { "system" } else { "user" }
}
type SaveFn = fn(Vec<String>) -> Result<(), String>;
fn load_and_save(system: bool, f: impl FnOnce(Vec<String>) -> Vec<String>) {
let target = pick_target(system, false);
let target = ensure_single_target(system, false);
let (list, save): (Vec<String>, SaveFn) = if target == "system" {
(core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e)),
core::registry::save_system_paths)
@@ -156,17 +157,18 @@ fn cmd_list(system: bool, user: bool, json_out: bool) {
}
fn cmd_add(path: String, system: bool, user: bool) {
let target = pick_target(system, user);
let target = ensure_single_target(system, user);
load_and_save(system || false, |mut list| {
list.push(path.clone());
list
});
let label = if target == "system" { "系统" } else { "用户" };
println!("已添加到{} PATH: {path}", label);
core::system::broadcast_env_change();
}
fn cmd_remove(index: usize, system: bool) {
let target = pick_target(system, false);
let target = ensure_single_target(system, false);
let mut list = if target == "system" {
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
} else {
@@ -177,10 +179,11 @@ fn cmd_remove(index: usize, system: bool) {
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
save(list).unwrap_or_else(|e| exit_err(&e));
println!("已删除: {removed}");
core::system::broadcast_env_change();
}
fn cmd_edit(index: usize, new_path: String, system: bool) {
let target = pick_target(system, false);
let target = ensure_single_target(system, false);
let mut list = if target == "system" {
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
} else {
@@ -191,6 +194,7 @@ fn cmd_edit(index: usize, new_path: String, system: bool) {
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
save(list).unwrap_or_else(|e| exit_err(&e));
println!("已编辑: {old}{new_path}");
core::system::broadcast_env_change();
}
fn cmd_move(index: usize, steps: usize, system: bool, up: bool) {
@@ -208,10 +212,11 @@ fn cmd_move(index: usize, steps: usize, system: bool, up: bool) {
});
let dir = if up { "上移" } else { "下移" };
println!("{dir} {steps} 格完成");
core::system::broadcast_env_change();
}
fn cmd_clean(system: bool, user: bool, dry_run: bool, json_out: bool) {
let target = pick_target(system, user);
let target = ensure_single_target(system, user);
let list = if target == "system" {
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
} else {
@@ -231,6 +236,7 @@ fn cmd_clean(system: bool, user: bool, dry_run: bool, json_out: bool) {
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
save(kept).unwrap_or_else(|e| exit_err(&e));
println!("清理完成:移除 {} 条,保留 {}", removed.len(), kept_count);
core::system::broadcast_env_change();
if !removed.is_empty() {
for r in &removed { println!(" 已移除: {}", r); }
}
@@ -238,7 +244,7 @@ fn cmd_clean(system: bool, user: bool, dry_run: bool, json_out: bool) {
}
fn cmd_toggle(index: usize, system: bool, user: bool, enable: bool) {
let target = pick_target(system, user);
let target = ensure_single_target(system, user);
let list = if target == "system" {
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
} else {
@@ -357,8 +363,8 @@ fn profile_list(json_out: bool) {
fn profile_save(name: String) {
let sys = core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e));
let usr = core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e));
let sys_entries = sys.into_iter().map(|p| core::profiles::ProfilePathEntry { path: p, enabled: true }).collect();
let usr_entries = usr.into_iter().map(|p| core::profiles::ProfilePathEntry { path: p, enabled: true }).collect();
let sys_entries = sys.into_iter().map(|p| core::ProfilePathEntry { path: p, enabled: true }).collect();
let usr_entries = usr.into_iter().map(|p| core::ProfilePathEntry { path: p, enabled: true }).collect();
core::profiles::save_profile(&name, sys_entries, usr_entries).unwrap_or_else(|e| exit_err(&e));
println!("已保存配置: {name}");
}
+4 -4
View File
@@ -1,10 +1,10 @@
[package]
name = "path-editor-core"
version = "5.0.0"
description = "PathEditor core library — shared between GUI and CLI"
authors = ["刘航宇"]
license = "MIT"
edition = "2021"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
[dependencies]
serde = { version = "1", features = ["derive"] }
+7 -3
View File
@@ -36,13 +36,17 @@ fn import_csv(content: &str) -> Result<(Vec<String>, Vec<String>), String> {
let mut sys = Vec::new();
let mut usr = Vec::new();
for line in content.lines() {
let fields: Vec<&str> = line.split(',').collect();
let trimmed = line.trim();
if trimmed.is_empty() { continue; }
let fields: Vec<&str> = trimmed.split(',').collect();
if fields.len() >= 2 {
match fields[0].trim() {
match fields[0].trim().to_lowercase().as_str() {
"system" | "sys" => sys.push(fields[1].trim().to_string()),
"user" | "usr" => usr.push(fields[1].trim().to_string()),
_ => {}
_ => { log::warn!("import_csv: 无法识别的类型字段,已跳过: {trimmed}"); }
}
} else {
log::warn!("import_csv: 格式不正确(缺逗号),已跳过: {trimmed}");
}
}
if sys.is_empty() && usr.is_empty() {
+1 -1
View File
@@ -6,5 +6,5 @@ pub mod registry;
pub mod scanner;
pub mod system;
pub use profiles::{ProfileData, ProfileMeta};
pub use profiles::{ProfileData, ProfileMeta, ProfilePathEntry};
pub use scanner::{ConflictEntry, ConflictLocation, ToolGroup};
+5 -6
View File
@@ -1,11 +1,11 @@
[package]
name = "patheditor"
version = "5.0.0"
description = "Windows PATH Environment Variable Editor"
authors = ["刘航宇"]
license = "MIT"
repository = "https://github.com/LHY0125/PathEditor"
edition = "2021"
version.workspace = true
edition.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
rust-version = "1.77.2"
[lib]
@@ -17,7 +17,6 @@ tauri-build = { version = "2.6.2", features = [] }
[dependencies]
path-editor-core = { path = "../core" }
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
tauri = { version = "2.11.2", features = [] }