hpk 0.3.12

HPK archiver for Haemimont Engine game files (Tropico 3-5, Omerta, Victor Vran, Surviving Mars etc.)
Documentation
use std::path::{Path, PathBuf};

use clap::{arg, ArgMatches, Command};
use glob::Pattern;

use crate::CliResult;

pub fn cmd() -> Command {
    fn input_parser(value: &str) -> Result<PathBuf, String> {
        let file = Path::new(value);
        match file.metadata() {
            Ok(ref md) if md.is_file() => Ok(file.to_path_buf()),
            Ok(_) | Err(_) => Err(String::from("Not a valid file")),
        }
    }

    Command::new("list")
        .about("List the content of a hpk archive")
        .display_order(20)
        .arg(arg!(<file> "hpk archive").value_parser(input_parser))
        .arg(arg!([paths]...).value_parser(Pattern::new))
}

pub fn execute(matches: &ArgMatches) -> CliResult {
    let input = matches.get_one::<PathBuf>("file").expect("required arg");
    let paths = matches
        .get_many::<Pattern>("paths")
        .map(Iterator::collect::<Vec<_>>)
        .unwrap_or_default();

    let walk = hpk::walk(input)?;

    fn matches_path(path: &Path, paths: &[&Pattern]) -> bool {
        if paths.is_empty() {
            return true;
        }
        for p in paths {
            if p.matches_path(path) {
                return true;
            }
        }
        false
    }

    for dent in walk.flatten() {
        if !matches_path(dent.path(), &paths) {
            continue;
        }
        if !dent.is_dir() {
            println!("{}", dent.path().display());
        }
    }
    Ok(())
}