Files
raven/retired/old_nest.rs
2026-02-15 09:36:04 -05:00

197 lines
5.4 KiB
Rust

#![allow(dead_code)]
use std::collections::HashSet;
use std::fs::{File, OpenOptions};
use std::hash::{self, Hash};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use crate::java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE};
use crate::{DIR_SRC, DIR_TARGET, F_NEST_LOCK, F_NEST_TOML, PROJECT_ROOT};
use anyhow::Context;
use semver::Version;
use serde::{Deserialize, Serialize};
pub static NEST: LazyLock<anyhow::Result<Nest>> =
LazyLock::new(|| Nest::try_from(PROJECT_ROOT.join(F_NEST_TOML.as_path())));
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Nest {
pub package: Package,
}
impl TryFrom<File> for Nest {
type Error = anyhow::Error;
fn try_from(value: File) -> Result<Self, Self::Error> {
let mut value = value;
let mut buf = String::new();
value
.read_to_string(&mut buf)
.context("Failed to read Nest")?;
toml::from_str(buf.as_str()).context("Failed to deserialize Nest")
}
}
impl TryFrom<PathBuf> for Nest {
type Error = anyhow::Error;
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
Nest::try_from(
OpenOptions::new()
.read(true)
.open(value)
.expect("Failed to load Nest.toml"),
)
}
}
// Rename to Prey
// Mark as deprecated soon.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Package {
pub name: String,
pub version: semver::Version,
}
impl Default for Package {
fn default() -> Self {
Self {
name: String::from("MyPackage"),
version: Version::new(0, 1, 0),
}
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct NestLock {
pub classes: HashSet<Class>,
}
impl NestLock {
pub fn load() -> anyhow::Result<NestLock> {
NestLock::try_from(PROJECT_ROOT.join(F_NEST_LOCK.as_path()))
}
/// Update, retaining all classes that still exist and whose paths are still files, rather than
/// being shifted into a package.
pub fn update(&mut self) {
self.classes = self
.classes
.clone()
.into_iter()
.filter_map(|class| {
// Paths are almost correct, except that the target classes are expecting to path
// through:
// target/main/Main.class, not target/Main.class
// target/test/MainTest.class, not target/MainTest.class
if DIR_SRC
.join(&class.path)
.with_extension(JAVA_EXT_SOURCE)
.exists()
&& DIR_TARGET
.join(&class.subpath())
.with_extension(JAVA_EXT_CLASS)
.is_file()
{
return Some(class);
}
None
})
.collect();
}
}
impl TryFrom<File> for NestLock {
type Error = anyhow::Error;
fn try_from(value: File) -> Result<Self, Self::Error> {
let mut value = value;
let mut buf = String::new();
value.read_to_string(&mut buf)?;
toml::from_str(buf.as_str()).context("Failed to deserialize NestLock")
}
}
impl TryFrom<PathBuf> for NestLock {
type Error = anyhow::Error;
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
NestLock::try_from(
OpenOptions::new()
.read(true)
.open(&value)
.with_context(|| format!("Failed to open {}", value.display()))?,
)
.context("")
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct Class {
path: PathBuf,
checksum: String,
}
impl Class {
/// Returns true if the class needs updating.
/// This may also cautionarily return true if it cannot digest the file.
pub fn is_updated(&self) -> bool {
// Still doesn't handle inter-dependency checks.
DIR_TARGET
.join(self.subpath())
.with_extension(JAVA_EXT_CLASS)
.exists()
&& sha256::try_digest(DIR_SRC.join(self.path()).with_extension(JAVA_EXT_SOURCE))
.is_ok_and(|hash| self.checksum == hash)
}
/// Returns the path such that src/ and target/ don't matter.
/// E.g., `main/Main.java` as_subpath is `Main.java`
/// allowing it to match with `target/main/Main.class`
/// because Java diregards the top level subdir in `src/`
fn subpath(&self) -> PathBuf {
let mut p = self.path.components();
p.next(); // Remove the top level dir.
p.as_path().to_path_buf()
}
pub fn path(&self) -> &Path {
self.path.as_path()
}
}
impl Hash for Class {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.path.hash(state);
}
}
impl TryFrom<PathBuf> for Class {
type Error = anyhow::Error;
fn try_from(mut value: PathBuf) -> Result<Self, Self::Error> {
if value.is_relative() {
value = value
.canonicalize()
.context("Failed to canonicalize path")?;
}
Ok(Self {
path: PathBuf::from(
pathsub::sub_paths(value.as_path(), DIR_SRC.as_path())
.context("Failed to subtract paths to get class path")?,
)
.with_extension(""),
checksum: sha256::try_digest(&value)?,
})
}
}