fix: auto-install embedded rulesets for installed binary

This commit is contained in:
2025-12-31 23:21:45 -05:00
parent fb62779f53
commit 3b27855b09
3 changed files with 135 additions and 34 deletions

View File

@@ -0,0 +1,45 @@
pub const FILES: &[(&str, &str)] = &[
(
"containers.toml",
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rulesets/containers.toml"
)),
),
(
"decode.toml",
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../rulesets/decode.toml")),
),
(
"probe.toml",
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../rulesets/probe.toml")),
),
(
"codecs-video.toml",
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rulesets/codecs-video.toml"
)),
),
(
"codecs-audio.toml",
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rulesets/codecs-audio.toml"
)),
),
(
"transport.toml",
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rulesets/transport.toml"
)),
),
(
"timestamps.toml",
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../rulesets/timestamps.toml"
)),
),
];

View File

@@ -1,6 +1,8 @@
use std::path::PathBuf;
use anyhow::Result;
use directories::ProjectDirs;
use fs_err as fs;
use crate::scan::ProbeData;
@@ -8,6 +10,7 @@ mod loader;
mod lint;
mod matcher;
mod model;
mod embedded;
use model::Rule;
@@ -22,23 +25,14 @@ pub struct RuleSet {
impl RuleSet {
pub fn load() -> Result<Self> {
let mut candidates = Vec::new();
if let Ok(current) = std::env::current_dir() {
candidates.push(current.join("rulesets"));
if let Some(ruleset) = load_compiled_from_candidates()? {
return Ok(ruleset);
}
if let Ok(exe) = std::env::current_exe() {
if let Some(parent) = exe.parent() {
candidates.push(parent.join("rulesets"));
}
}
for dir in candidates {
let rules = loader::load_rules_from_dir(&dir)?;
if !rules.is_empty() {
let compiled = loader::compile_rules(rules)?;
return Ok(Self { rules: compiled });
if let Some(dir) = data_ruleset_dir() {
install_embedded_rulesets(&dir)?;
if let Some(ruleset) = load_compiled_from_candidates()? {
return Ok(ruleset);
}
}
@@ -72,21 +66,13 @@ impl RuleSet {
}
pub fn load_raw_rules() -> Result<Vec<Rule>> {
let mut candidates = Vec::new();
if let Ok(current) = std::env::current_dir() {
candidates.push(current.join("rulesets"));
if let Some(rules) = load_raw_from_candidates()? {
return Ok(rules);
}
if let Ok(exe) = std::env::current_exe() {
if let Some(parent) = exe.parent() {
candidates.push(parent.join("rulesets"));
}
}
for dir in candidates {
let rules = loader::load_rules_from_dir(&dir)?;
if !rules.is_empty() {
if let Some(dir) = data_ruleset_dir() {
install_embedded_rulesets(&dir)?;
if let Some(rules) = load_raw_from_candidates()? {
return Ok(rules);
}
}
@@ -114,17 +100,14 @@ pub fn build_context(probe: &ProbeData) -> RuleContext {
}
pub fn ruleset_dir_for_display() -> Result<PathBuf> {
if let Ok(current) = std::env::current_dir() {
let dir = current.join("rulesets");
for dir in candidate_ruleset_dirs() {
if dir.exists() {
return Ok(dir);
}
}
if let Ok(exe) = std::env::current_exe() {
if let Some(parent) = exe.parent() {
return Ok(parent.join("rulesets"));
}
if let Some(dir) = data_ruleset_dir() {
return Ok(dir);
}
Err(anyhow::anyhow!("No ruleset directory found"))
@@ -140,3 +123,74 @@ pub fn ensure_ruleset_loaded(ruleset: &RuleSet) -> Result<()> {
}
Ok(())
}
fn candidate_ruleset_dirs() -> Vec<PathBuf> {
let mut candidates = Vec::new();
if let Ok(current) = std::env::current_dir() {
candidates.push(current.join("rulesets"));
}
if let Ok(exe) = std::env::current_exe() {
if let Some(parent) = exe.parent() {
candidates.push(parent.join("rulesets"));
}
}
if let Some(dir) = data_ruleset_dir() {
candidates.push(dir);
}
if let Some(dir) = config_ruleset_dir() {
candidates.push(dir);
}
candidates
}
fn data_ruleset_dir() -> Option<PathBuf> {
ProjectDirs::from("cc", "44r0n", "vid-repair").map(|dirs| dirs.data_dir().join("rulesets"))
}
fn config_ruleset_dir() -> Option<PathBuf> {
ProjectDirs::from("cc", "44r0n", "vid-repair").map(|dirs| dirs.config_dir().join("rulesets"))
}
fn load_compiled_from_candidates() -> Result<Option<RuleSet>> {
for dir in candidate_ruleset_dirs() {
let rules = loader::load_rules_from_dir(&dir)?;
if !rules.is_empty() {
let compiled = loader::compile_rules(rules)?;
return Ok(Some(RuleSet { rules: compiled }));
}
}
Ok(None)
}
fn load_raw_from_candidates() -> Result<Option<Vec<Rule>>> {
for dir in candidate_ruleset_dirs() {
let rules = loader::load_rules_from_dir(&dir)?;
if !rules.is_empty() {
return Ok(Some(rules));
}
}
Ok(None)
}
fn install_embedded_rulesets(dir: &std::path::Path) -> Result<()> {
if dir.exists() && dir.is_file() {
return Ok(());
}
fs::create_dir_all(dir)?;
for (name, contents) in embedded::FILES {
let path = dir.join(name);
if path.exists() {
continue;
}
fs::write(&path, contents)?;
}
Ok(())
}