整一部分上来

This commit is contained in:
shenjack 2024-04-13 12:42:03 +08:00
parent 22aa619616
commit 22ae6b3326
Signed by: shenjack
GPG Key ID: 7B1134A979775551
5 changed files with 236 additions and 130 deletions

View File

@ -22,4 +22,5 @@ winres = "0.1.0"
winapi = { version = "0.3", features = ["winnt"] } winapi = { version = "0.3", features = ["winnt"] }
[dependencies] [dependencies]
blake3 = "1.5.1"
toml = "0.8" toml = "0.8"

View File

@ -5,13 +5,25 @@ use toml::{from_str, Value as TomlValue};
pub const HELP_MESSAGE_EN: &str = r#"call [options] [--] [arguments] pub const HELP_MESSAGE_EN: &str = r#"call [options] [--] [arguments]
Options: Options:
--hide Hide console window (default) --hide Hide console window
-h Same as --hide
--show Show console window --show Show console window
-s Same as --show
--verbose Show more information
-v Same as --verbose
--chdir=xxx Change working directory to xxx --chdir=xxx Change working directory to xxx
-cd=xxx Same as --chdir=xxx
--bin=xxx Specify executable file --bin=xxx Specify executable file
--config=xxx Specify configuration file --config=xxx Specify configuration file
-cfg=xxx Same as --config=xxx
--help Print this help message(based on system language) --help Print this help message(based on system language)
--help-zh Print this help message(but in Chinese) --help-zh Print this help message()
--help-en Print this help message --help-en Print this help message
Defaults: Defaults:
hide console hide console
@ -21,14 +33,25 @@ Defaults:
pub const HELP_MESSAGE_ZH: &str = r#"call [选项] [--] [参数] pub const HELP_MESSAGE_ZH: &str = r#"call [选项] [--] [参数]
: :
--hide () --hide
-h --hide
--show --show
-s --show
--verbose
-v --verbose
--chdir=xxx xxx --chdir=xxx xxx
-cd=xxx --chdir=xxx
--bin=xxx --bin=xxx
--config=xxx --config=xxx
-cfg=xxx --config=xxx
--help 西() --help 西()
--help-zh 西 --help-zh 西
--help-en 西() --help-en 西(In English)
: :
./lib ./lib
@ -36,6 +59,8 @@ pub const HELP_MESSAGE_ZH: &str = r#"call [选项] [--] [参数]
"#; "#;
pub fn show_help() { pub fn show_help() {
#[cfg(windows)]
crate::win::attach_console();
println!("version: {}", crate::VERSION); println!("version: {}", crate::VERSION);
match std::env::var("LANG") { match std::env::var("LANG") {
Ok(lang) => { Ok(lang) => {
@ -52,41 +77,80 @@ pub fn show_help() {
} }
} }
pub fn get_default_config() -> (bool, Option<String>, String, String, String) {
let hard_default = (
true,
Some("lib".to_string()),
"./main".to_string(),
"run.conf".to_string(),
"".to_string(),
);
hard_default
}
#[derive(Clone)] #[derive(Clone)]
pub struct RawConfig { pub struct RawConfig {
pub show_console: Option<bool>, pub show_console: Option<bool>,
pub verbose: Option<bool>,
pub chdir: Option<String>, pub chdir: Option<String>,
pub bin: Option<String>, pub bin: Option<String>,
pub bin_arg: Option<String>, pub bin_arg: Option<String>,
pub config: Option<String>,
} }
impl Display for RawConfig { impl Display for RawConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!( f.write_str("RawConfig {\n")?;
"RawConfig {{ show_console: {:?}, chdir: {:?}, bin: {:?}, bin_arg: {:?} }}", let _: std::fmt::Result = {
self.show_console, self.chdir, self.bin, self.bin_arg f.write_str(&format!(" show_console: {:?}\n", self.show_console))?;
)) f.write_str(&format!(" verbose: {:?}\n", self.verbose))?;
f.write_str(&format!(" chdir: {:?}\n", self.chdir))?;
f.write_str(&format!(" bin: {:?}\n", self.bin))?;
f.write_str(&format!(" bin_arg: {:?}\n", self.bin_arg))?;
f.write_str(&format!(" config: {:?}\n", self.config))?;
Ok(())
};
f.write_str("}")
} }
} }
impl Default for RawConfig {
fn default() -> Self {
RawConfig {
show_console: Some(true),
verbose: Some(false),
chdir: Some("lib".to_string()),
bin: Some("./main".to_string()),
bin_arg: Some("".to_string()),
config: Some("run.conf".to_string()),
}
}
}
/// 用于合并
///
/// CLI 选项
/// CLI 指定的配置文件
/// 默认路径的配置文件
/// executable 的 builtin 配置 (附带在二进制文件中) (可修改)
/// 最基本的默认配置
impl RawConfig { impl RawConfig {
pub fn new(
show_console: Option<bool>,
verbose: Option<bool>,
chdir: Option<String>,
bin: Option<String>,
bin_arg: Option<String>,
config: Option<String>,
) -> Self {
RawConfig {
show_console,
verbose,
chdir,
bin,
bin_arg,
config,
}
}
/// 从命令行参数中获取配置
/// 包括命令行参数中指定的配置文件
pub fn from_cli() -> Self { pub fn from_cli() -> Self {
let mut show_console = None; let mut show_console = None;
let mut verbose = None;
let mut chdir = None; let mut chdir = None;
let mut bin = None; let mut bin = None;
let mut bin_arg = None; let mut bin_arg = None;
let mut config = None;
let args: Vec<String> = std::env::args().collect(); let args: Vec<String> = std::env::args().collect();
let index = args.iter().position(|x| x == "--"); let index = args.iter().position(|x| x == "--");
if index.is_some() { if index.is_some() {
@ -97,22 +161,72 @@ impl RawConfig {
break; break;
} else if args[i] == "--hide" { } else if args[i] == "--hide" {
show_console = Some(false); show_console = Some(false);
} else if args[i] == "--show" { } else if args[i] == "-h" {
show_console = Some(true); show_console = Some(false);
} else if args[i] == "--verbose" {
verbose = Some(true);
} else if args[i] == "-v" {
verbose = Some(true);
} else if args[i] == "--help" {
show_help();
std::process::exit(0);
} else if args[i] == "--help-zh" {
#[cfg(windows)]
crate::win::attach_console();
println!("{}", HELP_MESSAGE_ZH);
std::process::exit(0);
} else if args[i] == "--help-en" {
#[cfg(windows)]
crate::win::attach_console();
println!("{}", HELP_MESSAGE_EN);
std::process::exit(0);
} else if args[i].starts_with("--chdir=") { } else if args[i].starts_with("--chdir=") {
chdir = Some(args[i][8..].to_string()); chdir = Some(args[i][8..].to_string());
} else if args[i].starts_with("--bin=") { } else if args[i].starts_with("--bin=") {
bin = Some(args[i][6..].to_string()); bin = Some(args[i][6..].to_string());
} else if args[i].starts_with("--config=") {
config = Some(args[i][9..].to_string());
} }
} }
RawConfig { RawConfig {
show_console, show_console,
verbose,
chdir, chdir,
bin, bin,
bin_arg, bin_arg,
config,
} }
} }
/// 从指定的配置文件中更新当前缺少的配置
pub fn update_from_config(&mut self) {
// 从配置文件中获取配置
let possible_config: Option<Self> =
{ Self::from_config(self.config.as_ref().map(|x| PathBuf::from(x))) };
if possible_config.is_some() {
let config = possible_config.unwrap();
if self.show_console.is_none() {
self.show_console = config.show_console;
}
if self.chdir.is_none() {
self.chdir = config.chdir;
}
if self.bin.is_none() {
self.bin = config.bin;
}
if self.bin_arg.is_none() {
self.bin_arg = config.bin_arg;
}
if self.config.is_none() {
self.config = config.config;
}
};
}
pub fn from_executeable() -> Option<Self> {
crate::reader::read_self()
}
pub fn from_config(config_path: Option<PathBuf>) -> Option<Self> { pub fn from_config(config_path: Option<PathBuf>) -> Option<Self> {
if config_path.is_none() { if config_path.is_none() {
let config_path = PathBuf::from("./run.conf"); let config_path = PathBuf::from("./run.conf");
@ -128,22 +242,58 @@ impl RawConfig {
let config_str = std::fs::read_to_string(config_path).ok()?; let config_str = std::fs::read_to_string(config_path).ok()?;
let config_value: TomlValue = from_str(&config_str).ok()?; let config_value: TomlValue = from_str(&config_str).ok()?;
let show_console = config_value.get("show_console").and_then(|x| x.as_bool()); let show_console = config_value.get("show_console").and_then(|x| x.as_bool());
let chdir = config_value.get("chdir").and_then(|x| x.as_str()).map(|x| x.to_string()); let verbose = config_value.get("verbose").and_then(|x| x.as_bool());
let bin = config_value.get("bin").and_then(|x| x.as_str()).map(|x| x.to_string()); let chdir = config_value
let bin_arg = config_value.get("bin_arg").and_then(|x| x.as_str()).map(|x| x.to_string()); .get("chdir")
.and_then(|x| x.as_str())
.map(|x| x.to_string());
let bin = config_value
.get("bin")
.and_then(|x| x.as_str())
.map(|x| x.to_string());
let bin_arg = config_value
.get("bin_arg")
.and_then(|x| x.as_str())
.map(|x| x.to_string());
let config = config_value
.get("config")
.and_then(|x| x.as_str())
.map(|x| x.to_string());
Some(RawConfig { Some(RawConfig {
show_console, show_console,
verbose,
chdir, chdir,
bin, bin,
bin_arg, bin_arg,
config,
}) })
} }
pub fn merge_config(mut self, other: RawConfig) -> Self {
if self.show_console.is_none() {
self.show_console = other.show_console;
}
if self.chdir.is_none() {
self.chdir = other.chdir;
}
if self.bin.is_none() {
self.bin = other.bin;
}
if self.bin_arg.is_none() {
self.bin_arg = other.bin_arg;
}
if self.config.is_none() {
self.config = other.config;
}
self
}
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Config { pub struct Config {
pub show_console: bool, pub show_console: bool,
pub verbose: bool,
pub chdir: Option<String>, pub chdir: Option<String>,
pub bin: String, pub bin: String,
pub bin_arg: Vec<String>, pub bin_arg: Vec<String>,
@ -154,6 +304,7 @@ impl Display for Config {
let mut s = String::new(); let mut s = String::new();
s.push_str("Config {\n"); s.push_str("Config {\n");
s.push_str(&format!(" show_console: {}\n", self.show_console)); s.push_str(&format!(" show_console: {}\n", self.show_console));
s.push_str(&format!(" verbose: {}\n", self.verbose));
s.push_str(&format!(" chdir: {:?}\n", self.chdir)); s.push_str(&format!(" chdir: {:?}\n", self.chdir));
s.push_str(&format!(" bin: {:?}\n", self.bin)); s.push_str(&format!(" bin: {:?}\n", self.bin));
s.push_str(&format!(" bin_arg: {:?}\n", self.bin_arg)); s.push_str(&format!(" bin_arg: {:?}\n", self.bin_arg));
@ -165,106 +316,24 @@ impl Display for Config {
impl Config { impl Config {
pub fn new( pub fn new(
show_console: bool, show_console: bool,
verbose: bool,
chdir: Option<String>, chdir: Option<String>,
bin: String, bin: String,
bin_arg: Vec<String>, bin_arg: Vec<String>,
) -> Self { ) -> Self {
Config { Config {
show_console, show_console,
verbose,
chdir, chdir,
bin, bin,
bin_arg, bin_arg,
} }
} }
pub fn from_config(
config_path: Option<PathBuf>,
) -> Option<(Option<bool>, Option<String>, Option<String>, Option<String>)> {
if config_path.is_none() {
// 判断一下 ./run.conf 是否存在
let config_path = PathBuf::from("./run.conf");
if config_path.exists() {
return Self::from_config(Some(config_path));
}
return None;
}
let config_path = config_path.unwrap();
if !config_path.exists() {
return None;
}
let config_str = std::fs::read_to_string(config_path).unwrap();
let config_value: TomlValue = from_str(&config_str).unwrap();
let show_console = config_value.get("show_console").and_then(|x| x.as_bool());
let chdir = config_value.get("chdir").and_then(|x| x.as_str()).map(|x| x.to_string());
let bin = config_value.get("bin").and_then(|x| x.as_str()).map(|x| x.to_string());
let arg = config_value.get("bin_arg").and_then(|x| x.as_str()).map(|x| x.to_string());
Some((show_console, chdir, bin, arg)) pub fn from_cli() -> Self {
} let cli_conf = RawConfig::from_cli();
let execueable_conf = RawConfig::from_executeable();
pub fn from_cli() -> Option<Self> { todo!("from_cli")
let mut show_console = None;
let mut chdir: Option<String> = None;
let mut bin: Option<String> = None;
let mut config: Option<String> = None;
// -- 表示后面的参数都是可执行文件的参数
let args: Vec<String> = std::env::args().collect();
// 先检查有没有 --help
if args.contains(&"--help".to_string()) {
show_help();
return None;
}
let index = args.iter().position(|x| x == "--");
let bin_arg: Option<Vec<String>>;
if index.is_some() {
bin_arg = Some(args[index.unwrap() + 1..].to_vec());
} else {
bin_arg = None;
}
// 先尝试获取指定的控制台参数
// --hide 表示隐藏控制台
// --show 表示显示控制台
// --chdir 表示切换工作目录
// --chdir=xxx 表示切换工作目录到xxx
// --bin=xxx 表示指定可执行文件
// --config=xxx 表示指定配置文件
// --help 输出上面这一堆东西
for i in 1..args.len() {
if args[i] == "--" {
break;
} else if args[i] == "--hide" {
show_console = Some(false);
} else if args[i] == "--show" {
show_console = Some(true);
} else if args[i].starts_with("--chdir=") {
chdir = Some(args[i][8..].to_string());
} else if args[i].starts_with("--bin=") {
bin = Some(args[i][6..].to_string());
} else if args[i].starts_with("--config=") {
config = Some(args[i][9..].to_string());
}
}
let default_conf: (bool, Option<String>, String, String, String) = get_default_config();
let conf_from_config = Self::from_config(
config
.or(Some(default_conf.3.clone()))
.map(|x| PathBuf::from(x)),
);
// 优先顺序: cli > config > default
if let Some(conf) = conf_from_config {
Some(Self::new(
show_console.unwrap_or(conf.0.unwrap_or(default_conf.0)),
chdir.or(conf.1.or(default_conf.1)),
bin.unwrap_or(conf.2.unwrap_or(default_conf.2)),
bin_arg.unwrap_or(vec![conf.3.unwrap_or(default_conf.3)]),
))
} else {
Some(Self::new(
show_console.unwrap_or(default_conf.0),
chdir.or(default_conf.1),
bin.unwrap_or(default_conf.2),
bin_arg.unwrap_or(vec![default_conf.3]),
))
}
} }
} }

View File

@ -7,21 +7,24 @@ mod other;
#[cfg(windows)] #[cfg(windows)]
mod win; mod win;
mod reader;
mod config; mod config;
mod reader;
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION"); pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const SHOW_CONSOLE: bool = false; pub const SHOW_CONSOLE: bool = false;
fn main() { fn main() {
#[cfg(windows)]
win::init();
let config = config::Config::from_cli(); let config = config::Config::from_cli();
if config.is_none() {
return;
}
let config = config.unwrap();
// 输出相关信息 // 输出相关信息
if config.verbose {
#[cfg(windows)]
win::attach_console();
println!("call {}", VERSION); println!("call {}", VERSION);
println!("config: {}", config); println!("config: {}", config);
}
// 运行 // 运行
#[cfg(windows)] #[cfg(windows)]
win::run(&config); win::run(&config);

View File

@ -6,11 +6,34 @@
//! 大概就这样 //! 大概就这样
//! //!
pub fn merge_self_conf() { use blake3::Hasher;
pub fn read_self() -> Option<crate::config::RawConfig> {
// 先校验最后部分是否为合法的校验码
let mut verify = Hasher::new();
let raw_data = read_self_raw()?;
let raw_data_len = raw_data.len();
let (data, verify_bytes) = raw_data.split_at(raw_data_len - 32);
verify.update(data);
let verify_data = verify.finalize();
if verify_data.as_bytes() != verify_bytes {
println!(
"校验码不匹配 {:?} {:?}",
verify_data.as_bytes(),
verify_bytes
);
return None;
} }
pub fn read_self() -> Option<Vec<u8>> { // 然后解析配置文件
None
}
pub fn read_self_raw() -> Option<Vec<u8>> {
let path = std::env::current_exe().ok()?; let path = std::env::current_exe().ok()?;
std::fs::read(&path).ok() std::fs::read(&path).ok()
} }

View File

@ -2,6 +2,8 @@ use crate::config::Config;
use std::{os::windows::process::CommandExt, process::Command}; use std::{os::windows::process::CommandExt, process::Command};
use winapi::um::{processthreadsapi, wincon, winuser}; use winapi::um::{processthreadsapi, wincon, winuser};
pub static mut FROM_CONSOLE: bool = false;
fn is_launched_from_console() -> bool { fn is_launched_from_console() -> bool {
unsafe { unsafe {
let console_window = wincon::GetConsoleWindow(); let console_window = wincon::GetConsoleWindow();
@ -14,7 +16,7 @@ fn is_launched_from_console() -> bool {
} }
} }
fn attach_console() { pub fn attach_console() {
unsafe { unsafe {
let _out = wincon::AttachConsole(wincon::ATTACH_PARENT_PROCESS); let _out = wincon::AttachConsole(wincon::ATTACH_PARENT_PROCESS);
if _out == 0 { if _out == 0 {
@ -26,17 +28,25 @@ fn attach_console() {
} }
} }
pub fn init() {
unsafe {
FROM_CONSOLE = is_launched_from_console();
}
}
pub fn run(config: &Config) { pub fn run(config: &Config) {
attach_console(); attach_console();
let started_from_console = is_launched_from_console(); if config.verbose {
println!("call {}", crate::VERSION); println!("call {}", crate::VERSION);
println!("config: {}", config); println!("config: {}", config);
}
// 先切换工作目录 // 先切换工作目录
if let Some(chdir) = config.chdir.as_ref() { if let Some(chdir) = config.chdir.as_ref() {
std::env::set_current_dir(chdir).unwrap(); std::env::set_current_dir(chdir).unwrap();
} }
// 如果从终端启动, 且没指定显示终端, 则隐藏 stdout // 如果从终端启动, 且没指定显示终端, 则隐藏 stdout
if started_from_console { if unsafe { FROM_CONSOLE } {
let child; let child;
if config.show_console { if config.show_console {
println!("show_window with stdout"); println!("show_window with stdout");