164 lines
4.4 KiB
Rust
164 lines
4.4 KiB
Rust
use std::collections::HashMap;
|
|
use std::fs::{File, OpenOptions};
|
|
use std::io::Read;
|
|
use std::path::PathBuf;
|
|
use std::sync::LazyLock;
|
|
|
|
use crate::java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE};
|
|
use crate::{DIR_SRC, DIR_TARGET, DIR_TEST, 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"),
|
|
)
|
|
}
|
|
}
|
|
|
|
#[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 HashMap<PathBuf, Class>);
|
|
|
|
impl NestLock {
|
|
pub fn load() -> anyhow::Result<NestLock> {
|
|
NestLock::try_from(F_NEST_LOCK.clone())
|
|
}
|
|
|
|
/// 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.0 = self
|
|
.0
|
|
.clone()
|
|
.into_iter()
|
|
.filter_map(|(path, class)| {
|
|
if path.exists() && path.is_file() {
|
|
return Some((path, 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)]
|
|
pub struct Class {
|
|
pub name: PathBuf,
|
|
pub checksum: String,
|
|
pub test: bool,
|
|
}
|
|
|
|
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 {
|
|
// If the source file exists, hasn't been moved to a package (path is a file) and
|
|
// the associated compiled class file exists in DIR_TARGET
|
|
PROJECT_ROOT
|
|
.join(DIR_TARGET.as_path())
|
|
.join(self.name.as_path())
|
|
.with_extension(JAVA_EXT_CLASS)
|
|
.exists()
|
|
&& sha256::try_digest(
|
|
PROJECT_ROOT
|
|
.join(if self.test {
|
|
DIR_TEST.clone()
|
|
} else {
|
|
DIR_SRC.clone()
|
|
})
|
|
.join(self.name.as_path())
|
|
.with_extension(JAVA_EXT_SOURCE),
|
|
)
|
|
.is_ok_and(|hash| self.checksum == hash)
|
|
}
|
|
}
|
|
|
|
impl TryFrom<PathBuf> for Class {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
|
|
Ok(Self {
|
|
name: PathBuf::from(
|
|
value
|
|
.file_name()
|
|
.context("Failed to get file name from PathBuf for class")?,
|
|
)
|
|
.with_extension(""),
|
|
checksum: sha256::try_digest(&value)?,
|
|
test: value.is_relative() && value.starts_with(DIR_TEST.as_path()),
|
|
})
|
|
}
|
|
}
|