wip: 完善

This commit is contained in:
朝夕 2026-04-15 16:32:41 +08:00
parent 2e75b0a466
commit 337158f4b5
14 changed files with 529 additions and 4 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
.idea

314
Cargo.lock generated
View File

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]]
name = "anstream"
version = "1.0.0"
@ -64,6 +73,29 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "clap"
version = "4.6.0"
@ -131,6 +163,18 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "drop_bomb"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encode_unicode"
version = "1.0.0"
@ -201,6 +245,26 @@ dependencies = [
"slab",
]
[[package]]
name = "getopts"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
dependencies = [
"unicode-width",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.5.0"
@ -222,12 +286,33 @@ dependencies = [
"tracing",
]
[[package]]
name = "is-macro"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.18"
@ -240,6 +325,12 @@ version = "0.2.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
[[package]]
name = "log"
version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "memchr"
version = "2.8.0"
@ -276,6 +367,44 @@ dependencies = [
"stfu8",
]
[[package]]
name = "phf"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
@ -288,6 +417,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
@ -306,6 +444,111 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
[[package]]
name = "ruff_python_ast"
version = "0.0.0"
source = "git+https://github.com/astral-sh/ruff?rev=v0.4.0#e751b4ea8260ff83723345d1c7d39d5c776cc8ff"
dependencies = [
"aho-corasick",
"bitflags",
"is-macro",
"itertools",
"once_cell",
"ruff_python_trivia",
"ruff_source_file",
"ruff_text_size",
"rustc-hash",
]
[[package]]
name = "ruff_python_parser"
version = "0.0.0"
source = "git+https://github.com/astral-sh/ruff?rev=v0.4.0#e751b4ea8260ff83723345d1c7d39d5c776cc8ff"
dependencies = [
"anyhow",
"bitflags",
"bstr",
"drop_bomb",
"is-macro",
"itertools",
"memchr",
"ruff_python_ast",
"ruff_text_size",
"rustc-hash",
"static_assertions",
"unicode-ident",
"unicode-normalization",
"unicode_names2",
]
[[package]]
name = "ruff_python_trivia"
version = "0.0.0"
source = "git+https://github.com/astral-sh/ruff?rev=v0.4.0#e751b4ea8260ff83723345d1c7d39d5c776cc8ff"
dependencies = [
"itertools",
"ruff_source_file",
"ruff_text_size",
"unicode-ident",
]
[[package]]
name = "ruff_source_file"
version = "0.0.0"
source = "git+https://github.com/astral-sh/ruff?rev=v0.4.0#e751b4ea8260ff83723345d1c7d39d5c776cc8ff"
dependencies = [
"memchr",
"once_cell",
"ruff_text_size",
]
[[package]]
name = "ruff_text_size"
version = "0.0.0"
source = "git+https://github.com/astral-sh/ruff?rev=v0.4.0#e751b4ea8260ff83723345d1c7d39d5c776cc8ff"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "same-file"
version = "1.0.6"
@ -358,12 +601,24 @@ dependencies = [
"zmij",
]
[[package]]
name = "siphasher"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "std_prelude"
version = "0.2.12"
@ -472,12 +727,43 @@ version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-normalization"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode_names2"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1673eca9782c84de5f81b82e4109dcfb3611c8ba0d52930ec4a9478f547b2dd"
dependencies = [
"phf",
"unicode_names2_generator",
]
[[package]]
name = "unicode_names2_generator"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91e5b84611016120197efd7dc93ef76774f4e084cd73c9fb3ea4a86c570c56e"
dependencies = [
"getopts",
"log",
"phf_codegen",
"rand",
]
[[package]]
name = "utf8parse"
version = "0.2.2"
@ -493,6 +779,8 @@ dependencies = [
"console",
"indicator",
"path_abs",
"ruff_python_ast",
"ruff_python_parser",
"serde",
"serde_json",
"walkdir",
@ -508,6 +796,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "winapi-util"
version = "0.1.11"
@ -532,6 +826,26 @@ dependencies = [
"windows-link",
]
[[package]]
name = "zerocopy"
version = "0.8.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zmij"
version = "1.0.21"

View File

@ -12,3 +12,5 @@ serde_json = "1.0"
path_abs = "0.5"
console = "0.16.3"
indicator = "0.4.4"
ruff_python_parser = { git = "https://github.com/astral-sh/ruff", rev = "v0.4.0" }
ruff_python_ast = { git = "https://github.com/astral-sh/ruff", rev = "v0.4.0" }

View File

@ -0,0 +1,2 @@
pub mod git;
pub mod install;

57
src/installer/git.rs Normal file
View File

@ -0,0 +1,57 @@
use crate::installer::install::Installer;
use std::process::Command;
use anyhow::{Context, Result, anyhow};
use std::fs;
use std::path::Path;
use std::path::PathBuf;
pub struct GitInstaller{
git_repo_url: String,
cache_path: Option<String>,
}
impl GitInstaller {
// 1. 增加一个关联函数 new负责“一键初始化”
pub fn new(git_repo_url: &str, root_cache_path: &str) -> Self {
// 逻辑:从 URL 提取仓库名(总督的直觉)
let repo_name = git_repo_url
.split('/')
.last()
.unwrap_or("default_repo")
.trim_end_matches(".git");
let mut path_buf = PathBuf::from(root_cache_path);
path_buf.push(repo_name);
// 返回实例
Self {
git_repo_url: git_repo_url.to_owned(),
cache_path: Some(path_buf.display().to_string()),
}
}
}
impl Installer for GitInstaller{
fn download(&self) -> Result<()> {
let cache_path = self.cache_path.as_ref()
.context("错误:未初始化缓存路径,请先调用 get_cache_path")?;
if Path::new(cache_path).exists() {
fs::remove_dir_all(cache_path)
.with_context(|| format!("无法清理旧的缓存目录: {}", cache_path))?;
};
println!("viceroy正在安装");
let output = Command::new("git")
.args(["clone",
"--depth",
"1",
&self.git_repo_url,
cache_path])
.output()
.context("执行 Git 失败,请确认系统已安装 git 并配置了 SSH/HTTP 权限")?;
if output.status.success() {
println!("✅ 技能包拉取成功。");
Ok(())
} else {
let err_msg = String::from_utf8_lossy(&output.stderr);
Err(anyhow!("Git 克隆失败: {}", err_msg))
}
}
}

5
src/installer/install.rs Normal file
View File

@ -0,0 +1,5 @@
use anyhow::Result;
pub trait Installer {
fn download(&self) -> Result<()>;
}

View File

@ -1,2 +1,2 @@
mod installer;
mod manifest;
pub mod installer;
pub mod manifest;

View File

@ -1,3 +1,6 @@
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1 @@
mod skill;

4
src/manifest/skill.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod skill;
pub mod model;
pub mod analysis;
pub mod skill_structure_tree;

View File

@ -0,0 +1,53 @@
use crate::manifest::skill::skill_structure_tree::{SkillNode,PythonFuncNode,PythonFileNode};
use walkdir::WalkDir;
use std::path::Path;
use std::collections::HashMap;
use ruff_python_parser::{parse, Mode};
use ruff_python_ast::{Mod, Stmt};
fn analyze_python_file(code: &str) -> PythonFileNode {
let mut func_dict = HashMap::new();
let parsed: Mod = parse(code, Mode::Module).expect("Python 语法错误");
if let Mod::Module(module) = parsed {
for stmt in module.body {
if let Stmt::FunctionDef(func) = stmt {
let func_name = func.name.to_string();
let args = HashMap::new();
let doc = "从 AST 里抠出来的文档".to_string();
func_dict.insert(func_name.clone(), PythonFuncNode {
func_sign: format!("def {}(...)", func_name),
func_args: args,
func_return_type: "Unknown".into(),
func_docs: doc,
});
}
}
}
PythonFileNode {
file_name: "xxx".into(),
func_dict,
}
}
fn main_scan_logic(root_path: &Path) {
let mut root_node = SkillNode::new_folder("root");
for entry in WalkDir::new(root_path).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
if path.is_file() {
let rel_path = path.strip_prefix(root_path).unwrap();
let segments: Vec<&str> = rel_path.iter().map(|s| s.to_str().unwrap()).collect();
let node = if path.extension().and_then(|s| s.to_str()) == Some("py") {
let code = std::fs::read_to_string(path).expect("读取文件失败");
let mut py_node = analyze_python_file(&code);
py_node.file_name = path.file_stem().unwrap().to_string_lossy().into();
SkillNode::Python(py_node)
} else {
let file_name = path.file_name().unwrap().to_string_lossy().into();
SkillNode::File(file_name)
};
root_node.insert_recursive(&segments, node);
}
}
let json = serde_json::to_string_pretty(&root_node).unwrap();
println!("{}", json);
}

View File

@ -0,0 +1,7 @@
pub struct SkillModel{
pub skill_path: String,
}
pub struct SkillRegister{
}

View File

@ -0,0 +1,28 @@
use crate::installer::git;
use crate::installer::install::Installer;
use crate::manifest::skill::model::SkillModel;
use std::path::PathBuf;
impl SkillModel{
fn install(git_repo_url: String, root_cache_path: String, relative_path: String) -> Self{
let git_installer = git::GitInstaller::new(&git_repo_url, &root_cache_path);
if let Err(e) = git_installer.download() {
eprintln!("安装失败: {}", e);
};
let git_repo_name = git_repo_url
.split('/')
.last()
.unwrap_or("default_repo")
.trim_end_matches(".git");
let mut path_builder = PathBuf::from(&root_cache_path);
path_builder.push(git_repo_name);
path_builder.push(&relative_path);
let skill_path = path_builder.to_string_lossy().to_string();
Self{
skill_path,
}
}
fn analysis(&self){
}
}

View File

@ -0,0 +1,47 @@
use std::collections::HashMap;
use serde::Serialize;
#[derive(Serialize)]
pub struct PythonFuncNode{
pub func_sign: String,
pub func_args: HashMap<String, String>,
pub func_return_type: String,
pub func_docs: String,
}
#[derive(Serialize)]
pub struct PythonFileNode{
pub file_name: String,
pub func_dict: HashMap<String, PythonFuncNode>,
}
#[derive(Serialize)]
#[serde(tag = "type", content = "data")]
pub enum SkillNode {
Folder(String, HashMap<String, SkillNode>),
Python(PythonFileNode),
File(String),
}
impl SkillNode {
pub fn new_folder(name: &str) -> Self {
SkillNode::Folder(name.to_string(), HashMap::new())
}
pub fn insert_recursive(&mut self, segments: &[&str], data: SkillNode) {
if let SkillNode::Folder(_name, children) = self {
let current_seg = segments[0];
if segments.len() == 1 {
children.insert(current_seg.to_string(), data);
} else {
let next_node = children
.entry(current_seg.to_string())
.or_insert_with(|| SkillNode::new_folder(current_seg));
next_node.insert_recursive(&segments[1..], data);
}
} else {
panic!("试图在已存在文件{}内保存文件", segments[0]);
}
}
}