fix: auto-install embedded rulesets for installed binary
This commit is contained in:
@@ -96,6 +96,8 @@ This section is for contributors and anyone building on the project.
|
||||
## Rulesets 🧩
|
||||
|
||||
Rules are data‑driven and split by domain in `rulesets/*.toml`.
|
||||
When running an installed binary, the first run will auto‑install the default rulesets
|
||||
into the XDG data directory (for example `~/.local/share/vid-repair/rulesets` on Linux).
|
||||
Before shipping changes:
|
||||
|
||||
```bash
|
||||
|
||||
45
vid-repair-core/src/rules/embedded.rs
Normal file
45
vid-repair-core/src/rules/embedded.rs
Normal 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"
|
||||
)),
|
||||
),
|
||||
];
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user