From 627dec9cd9d6deb8bd363c51ddf5bd087b142a9f Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sat, 18 Jan 2025 13:06:34 +0800 Subject: [PATCH] feat: add update-meta-v2.rs --- script-config.json | 6 + script-meta-v2.json | 20 +++ script-meta.json | 10 ++ update-meta.rs => update-meta-v1.rs | 0 update-meta-v2.rs | 208 ++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 script-config.json create mode 100644 script-meta-v2.json rename update-meta.rs => update-meta-v1.rs (100%) create mode 100755 update-meta-v2.rs diff --git a/script-config.json b/script-config.json new file mode 100644 index 0000000..86ea647 --- /dev/null +++ b/script-config.json @@ -0,0 +1,6 @@ +{ + "file_ext": "ts", + "simple_script_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/single-scripts/$NAME", + "project_script_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/$NAME/main.ts", + "skip_dirs": [] +} diff --git a/script-meta-v2.json b/script-meta-v2.json new file mode 100644 index 0000000..31c46a9 --- /dev/null +++ b/script-meta-v2.json @@ -0,0 +1,20 @@ +{ + "access-guard.ts": { + "script_name": "access-guard.ts", + "script_length": 5508, + "script_sha256": "608fb5987c04b9bcfcb7006cb75eac7c8f81346906d3aed7ffd368357e6fa5cb", + "script_full_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/access-guard-ts/main.ts" + }, + "helloworld.ts": { + "script_name": "helloworld.ts", + "script_length": 69, + "script_sha256": "b301944e64def6c3a1ada4e327a7b2c2e37c576a65da5f797998355c51686f76", + "script_full_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/helloworld-ts/main.ts" + }, + "sigstore-verify.ts": { + "script_name": "sigstore-verify.ts", + "script_length": 3511, + "script_sha256": "5d3987d9f838158ab89ca098cd4b142147ab2157b693e48f042d080be4928ff7", + "script_full_url": "https://git.hatter.ink/hatter/ts-scripts/raw/branch/main/sigstore-verify-ts/main.ts" + } +} \ No newline at end of file diff --git a/script-meta.json b/script-meta.json index 36bdab1..20f1662 100644 --- a/script-meta.json +++ b/script-meta.json @@ -1,7 +1,17 @@ { + "access-guard-ts": { + "script_name": "access-guard-ts", + "script_length": 5508, + "script_sha256": "608fb5987c04b9bcfcb7006cb75eac7c8f81346906d3aed7ffd368357e6fa5cb" + }, "helloworld-ts": { "script_name": "helloworld-ts", "script_length": 69, "script_sha256": "b301944e64def6c3a1ada4e327a7b2c2e37c576a65da5f797998355c51686f76" + }, + "sigstore-verify-ts": { + "script_name": "sigstore-verify-ts", + "script_length": 3511, + "script_sha256": "5d3987d9f838158ab89ca098cd4b142147ab2157b693e48f042d080be4928ff7" } } \ No newline at end of file diff --git a/update-meta.rs b/update-meta-v1.rs similarity index 100% rename from update-meta.rs rename to update-meta-v1.rs diff --git a/update-meta-v2.rs b/update-meta-v2.rs new file mode 100755 index 0000000..f14586c --- /dev/null +++ b/update-meta-v2.rs @@ -0,0 +1,208 @@ +#!/usr/bin/env runrs + +//! ```cargo +//! [dependencies] +//! serde = { version = "1.0", features = ["derive"] } +//! serde_json = "1.0" +//! sha256 = "1.5" +//! rust_util = { version = "0.6" } +//! ``` + +use rust_util::{ + debugging, failure_and_exit, iff, opt_result, opt_value_result, success, warning, XResult, +}; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fs; +use std::option::Option; +use std::path::PathBuf; + +const SCRIPT_META_FILE: &str = "script-meta-v2.json"; +const SCRIPT_CONFIG_FILE: &str = "script-config.json"; +const SINGLE_SCRIPTS_DIR: &str = "single-scripts"; + +#[derive(Debug, Deserialize)] +struct ScriptConfig { + file_ext: String, + simple_script_url: String, + project_script_url: String, + script_sub_dir: Option, + skip_dirs: Vec, +} + +impl ScriptConfig { + fn skip_dir(&self, dir: &str) -> bool { + for skip_dir in &self.skip_dirs { + if skip_dir == dir { + return true; + } + } + dir == "update-meta-rs" || dir == SINGLE_SCRIPTS_DIR || dir.starts_with(".") + } +} + +#[derive(Serialize)] +struct ScriptMeta { + script_name: String, + script_length: u64, + script_sha256: String, + script_full_url: String, + #[serde(skip_serializing_if = "Option::is_none")] + single_script_file: Option, +} + +fn main() -> XResult<()> { + if fs::metadata(SCRIPT_CONFIG_FILE).is_err() { + failure_and_exit!("Script config file {} not found.", SCRIPT_CONFIG_FILE); + } + if fs::metadata(SCRIPT_META_FILE).is_err() { + failure_and_exit!("Script meta file {} not found.", SCRIPT_META_FILE); + } + + let script_config_content = opt_result!( + fs::read_to_string(SCRIPT_CONFIG_FILE), + "Read {}, failed: {}", + SCRIPT_CONFIG_FILE + ); + let script_config: ScriptConfig = opt_result!( + serde_json::from_str(&script_config_content), + "Parse {}, failed: {}", + SCRIPT_CONFIG_FILE + ); + debugging!("Script config: {:#?}", script_config); + + let mut script_meta_map = BTreeMap::new(); + + let current_read_dir = opt_result!(fs::read_dir("."), "Read dir '.' failed: {}"); + for dir in current_read_dir { + let dir_entry = opt_result!(dir, "Get dir failed: {}"); + let dir_file_type = opt_result!(dir_entry.file_type(), "Get dir type failed: {}"); + let file_name_os_string = dir_entry.file_name(); + let script_dir = opt_value_result!(file_name_os_string.to_str(), "Cannot get file name."); + if !dir_file_type.is_dir() { + debugging!("Skip none dir: {}", script_dir); + continue; + } + if script_config.skip_dir(&script_dir) { + debugging!("Skip update skip dirs: {}", script_dir); + continue; + } + let abs_dir_entry = std::path::absolute(&dir_entry.path())?; + let mut main_script = abs_dir_entry; + if let Some(sub_dir) = &script_config.script_sub_dir { + main_script = main_script.join(sub_dir); + } + main_script = main_script.join(format!("main.{}", script_config.file_ext)); + + if let Some(script_file_name) = + translate_script_dir_to_script_name(script_dir, &script_config) + { + script_meta_map.insert( + script_file_name.clone(), + read_script_meta( + script_dir, + script_file_name.clone(), + &main_script, + false, + &script_config, + )?, + ); + } + } + + if let Ok(single_script_meta) = fs::metadata(SINGLE_SCRIPTS_DIR) { + if single_script_meta.is_dir() { + let single_scripts_read_dir = + opt_result!(fs::read_dir(SINGLE_SCRIPTS_DIR), "Read dir '.' failed: {}"); + for file in single_scripts_read_dir { + let file_entry = opt_result!(file, "Get dir failed: {}"); + let dir_file_type = opt_result!(file_entry.file_type(), "Get dir type failed: {}"); + let file_name_os_string = file_entry.file_name(); + let script_file = + opt_value_result!(file_name_os_string.to_str(), "Cannot get file name."); + if !dir_file_type.is_file() { + debugging!("Skip none file: {}", script_file); + continue; + } + let abs_file_entry = std::path::absolute(&file_entry.path())?; + let script_file_ext = format!(".{}", script_config.file_ext); + if !script_file.ends_with(&script_file_ext) { + continue; + } + let script_file_name = script_file.to_string(); + if script_meta_map.contains_key(&script_file_name) { + warning!("Script: {script_file_name} exists."); + continue; + } + script_meta_map.insert( + script_file_name.clone(), + read_script_meta( + "", + script_file_name.clone(), + &abs_file_entry, + true, + &script_config, + )?, + ); + } + } + } + + let script_meta_json = serde_json::to_string_pretty(&script_meta_map)?; + + fs::write(SCRIPT_META_FILE, script_meta_json.as_bytes())?; + + success!("Update file: {} succeed.", SCRIPT_META_FILE); + + Ok(()) +} + +// translate filename-ext to filename.ext +fn translate_script_dir_to_script_name( + script_dir: &str, + script_config: &ScriptConfig, +) -> Option { + let script_dir_ext = format!("-{}", script_config.file_ext); + if script_dir.ends_with(&script_dir_ext) { + let remove_ext_dir_name = script_dir + .chars() + .take(script_dir.len() - script_dir_ext.len()) + .collect::(); + Some(format!("{remove_ext_dir_name}.{}", script_config.file_ext)) + } else { + None + } +} + +fn read_script_meta( + script_dir: &str, + script_name: String, + script_path: &PathBuf, + is_simple_script: bool, + script_config: &ScriptConfig, +) -> XResult { + let script_meta = opt_result!( + script_path.metadata(), + "Read file: {:?} meta failed: {}", + script_path + ); + let script_path_content = fs::read(script_path)?; + let script_sha256 = sha256::digest(&script_path_content); + let script_full_url = if is_simple_script { + script_config + .simple_script_url + .replace("$NAME", &script_name) + } else { + script_config + .project_script_url + .replace("$NAME", script_dir) + }; + let single_script_file = iff!(is_simple_script, Some(true), None); + Ok(ScriptMeta { + script_name: script_name.clone(), + script_length: script_meta.len(), + script_sha256, + script_full_url, + single_script_file, + }) +}