neyuki 0.6.1

A small Lua-like scripting language implemented in Rust
//! The local directory installed packages live in.

use std::fs;
use std::path::{Path, PathBuf};

use super::lockfile::LockedPackage;

pub struct PackageStore {
    root_dir: PathBuf,
}

impl Default for PackageStore {
    fn default() -> Self {
        Self::new(".")
    }
}

impl PackageStore {
    pub fn new(project_root: impl Into<PathBuf>) -> Self {
        let p: PathBuf = project_root.into();
        Self {
            root_dir: p.join("neyuki_packages"),
        }
    }

    pub fn packages_dir(&self) -> &Path {
        &self.root_dir
    }

    pub fn ensure_dir_exists(&self) -> Result<(), String> {
        if !self.root_dir.exists() {
            fs::create_dir_all(&self.root_dir)
                .map_err(|e| format!("cannot create neyuki_packages directory: {}", e))?;
        }
        Ok(())
    }

    pub fn install_package(
        &self,
        pkg: &LockedPackage,
        files: &[(&str, &[u8])],
    ) -> Result<PathBuf, String> {
        self.ensure_dir_exists()?;
        let pkg_dir = self.root_dir.join(&pkg.name);
        fs::create_dir_all(&pkg_dir)
            .map_err(|e| format!("cannot create package directory for '{}': {}", pkg.name, e))?;

        for (filename, content) in files {
            let file_path = pkg_dir.join(filename);
            if let Some(parent) = file_path.parent() {
                let _ = fs::create_dir_all(parent);
            }
            fs::write(&file_path, content).map_err(|e| {
                format!(
                    "failed writing package file '{}': {}",
                    file_path.display(),
                    e
                )
            })?;
        }

        Ok(pkg_dir)
    }

    pub fn list_installed(&self) -> Result<Vec<String>, String> {
        if !self.root_dir.exists() {
            return Ok(Vec::new());
        }

        let mut out = Vec::new();
        let entries = fs::read_dir(&self.root_dir)
            .map_err(|e| format!("failed reading neyuki_packages: {}", e))?;

        for entry in entries.flatten() {
            let is_dir = entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false);
            if let (true, Some(name)) = (is_dir, entry.file_name().to_str()) {
                out.push(name.to_string());
            }
        }

        out.sort();
        Ok(out)
    }
}