Compare commits

..

2 Commits

Author SHA1 Message Date
Olivia Brooks
4e961dac40 Add documentation. 2026-02-22 13:46:03 -05:00
Olivia Brooks
fee63a2d4b Add documentation. 2026-02-22 13:45:53 -05:00
2 changed files with 97 additions and 2 deletions

View File

@@ -14,6 +14,10 @@ use crate::package::PackageHandler;
use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey}; use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey};
use crate::{Error, package}; use crate::{Error, package};
/// Represents a raven workspace.
///
/// [`WorkspaceHandler`] manages project compilation, cache writing,
/// and tracking of all packages that make up the workspace.
#[derive(Debug)] #[derive(Debug)]
pub struct WorkspaceHandler { pub struct WorkspaceHandler {
nest: Nest, nest: Nest,
@@ -26,6 +30,13 @@ impl WorkspaceHandler {
const DIR_SRC: &str = "src/"; const DIR_SRC: &str = "src/";
const DIR_TARGET: &str = "target/"; const DIR_TARGET: &str = "target/";
/// Creates a new [`WorkspaceHandler`] instance at the provided path.
///
/// # Errors
///
/// * [`Error::Io`] if the `project_root` cannot be canonicalized.
/// * [`Error::MissingFileName`] if a name for the workspace cannot be derived
/// from the `project_root`
pub fn new<P: AsRef<Path>>(project_root: P) -> crate::Result<Self> { pub fn new<P: AsRef<Path>>(project_root: P) -> crate::Result<Self> {
let project_root = project_root.as_ref().canonicalize()?; let project_root = project_root.as_ref().canonicalize()?;
@@ -42,6 +53,14 @@ impl WorkspaceHandler {
}) })
} }
/// Loads an existing workspace from the provided path.
///
/// # Errors
///
/// * [`Error::Io`] for any number of IO-related errors.
/// Unwrap the [`std::io::Error`] for further information.
/// * [`Error::MissingFileName`] if a name for the workspace cannot be derived
/// from the `project_root`
pub fn load<P: AsRef<Path>>(project_root: P) -> crate::Result<Self> { pub fn load<P: AsRef<Path>>(project_root: P) -> crate::Result<Self> {
let project_root = project_root.as_ref().canonicalize()?; let project_root = project_root.as_ref().canonicalize()?;
@@ -57,6 +76,7 @@ impl WorkspaceHandler {
Ok(workspace_manager) Ok(workspace_manager)
} }
/// Writes all lock files (Nest.toml, src/**/Prey.toml) to the disk.
pub fn write_locks(&self) -> crate::Result<()> { pub fn write_locks(&self) -> crate::Result<()> {
if let Option::Some(lock) = self.nest_lock.clone() { if let Option::Some(lock) = self.nest_lock.clone() {
lock.write(self.project_root.join(F_NEST_LOCK))?; lock.write(self.project_root.join(F_NEST_LOCK))?;
@@ -69,6 +89,26 @@ impl WorkspaceHandler {
Ok(()) Ok(())
} }
/// Initializes a new workspace.
///
/// # Behaviour
///
/// Init will avoid overwriting or adding an example project if raven is being integrated into
/// an existing workspace codebase.
///
/// Init will always write:
///
/// * Nest.toml
/// * .java-version
/// * Attempt to append to .gitignore
///
/// If this is an empty workspace, init will include:
///
/// * Calling `git init`
/// * Writing an example project.
/// * Automatic package discovery.
///
/// # Errors
pub fn init(&mut self) -> crate::Result<&mut Self> { pub fn init(&mut self) -> crate::Result<&mut Self> {
// ORDER MATTERS. // ORDER MATTERS.
let is_empty = read_dir(self.project_root.as_path()).is_ok_and(|tree| tree.count() == 0); let is_empty = read_dir(self.project_root.as_path()).is_ok_and(|tree| tree.count() == 0);
@@ -114,7 +154,18 @@ impl WorkspaceHandler {
Ok(self) Ok(self)
} }
// This is the naive build /// This is a naive build; it attempts to build every source file individually.
///
/// It calls [`PackageHandler::get_outdated()`] on all known packages to determine
/// compile targets.
///
/// It will then attempt to write all locks to update the caches and avoid attempting to
/// needlessly recompile targets.
///
/// # Errors
///
/// * [`Error::AbsentPrimeError`]
/// * [`Error::Io`]
pub fn build(&mut self) -> crate::Result<&mut Self> { pub fn build(&mut self) -> crate::Result<&mut Self> {
let compiler = java::compiler::CompilerBuilder::new() let compiler = java::compiler::CompilerBuilder::new()
.class_path(Self::DIR_TARGET) .class_path(Self::DIR_TARGET)
@@ -152,6 +203,20 @@ impl WorkspaceHandler {
Ok(self) Ok(self)
} }
/// Attempts to call the JVM to run, in order of precedence:
///
/// 1. Provided entry point which includes a specific source file.
/// 2. Provided entry point to a package, using that package's default entry point
/// defined in it's `Prey.toml`
/// 3. The workspace's default package defined in `Nest.toml`, and that package's default
/// entry point as defined in it's `Prey.toml`.
///
/// # Errors
///
/// * [`Error::UnknownPackage`] if the package cannot be found.
/// * [`Error::UndefinedEntryPoint`] if no fallback entry point can be found.
/// * [`Error::Io`]
/// * [`Error::Java`]
pub fn run<P: AsRef<Path>>( pub fn run<P: AsRef<Path>>(
&mut self, &mut self,
entry_point: Option<P>, entry_point: Option<P>,
@@ -187,6 +252,11 @@ impl WorkspaceHandler {
Ok(self) Ok(self)
} }
/// Cleans the workspace of it's caches:
///
/// * `target/`
/// * Nest.lock
/// * Prey.lock
pub fn clean(&mut self) -> crate::Result<&mut Self> { pub fn clean(&mut self) -> crate::Result<&mut Self> {
// Clear Nest.lock // Clear Nest.lock
if let Err(err) = std::fs::remove_file(self.project_root.join(F_NEST_LOCK)) { if let Err(err) = std::fs::remove_file(self.project_root.join(F_NEST_LOCK)) {
@@ -215,7 +285,14 @@ impl WorkspaceHandler {
Ok(self) Ok(self)
} }
/// Add any newly created packages. /// Scan for newly created packages, wrapping them in [`PackageHandler`]s
/// and adding them to the [`WorkspaceHandler`]'s package map.
///
/// Packages are identified by their `Prey.toml` manifests.
///
/// # Errors
///
/// * [`Error::Io`]
fn discover_packages(&mut self) -> crate::Result<()> { fn discover_packages(&mut self) -> crate::Result<()> {
// Scan the src/ directory for entries, // Scan the src/ directory for entries,
// filter out the files, // filter out the files,
@@ -280,10 +357,18 @@ impl WorkspaceHandler {
Ok(()) Ok(())
} }
/// Writes the [`WorkspaceHandler`]'s `Nest.toml` to disk.
fn write_nest(&self) -> crate::Result<()> { fn write_nest(&self) -> crate::Result<()> {
Ok(self.nest.write(self.project_root.clone())?) Ok(self.nest.write(self.project_root.clone())?)
} }
/// Writes a `.java-version` file for `jenv` to the disk with an automatically parsed
/// java version from [`java::get_javac_version()`].
///
/// # Errors
///
/// * [`Error::Io`]
/// * [`Error::Java`]
fn write_java_version(&self) -> crate::Result<()> { fn write_java_version(&self) -> crate::Result<()> {
if let Result::Ok(mut f) = OpenOptions::new() if let Result::Ok(mut f) = OpenOptions::new()
.write(true) .write(true)
@@ -296,6 +381,7 @@ impl WorkspaceHandler {
Ok(()) Ok(())
} }
/// Writes an example project tree to disk.
fn write_dir_tree(&self) -> std::io::Result<()> { fn write_dir_tree(&self) -> std::io::Result<()> {
for dir in [ for dir in [
format!("{}main/java", Self::DIR_SRC), format!("{}main/java", Self::DIR_SRC),
@@ -308,6 +394,7 @@ impl WorkspaceHandler {
Ok(()) Ok(())
} }
/// Writes an example project to disk.
fn write_example_project(&self) -> crate::Result<()> { fn write_example_project(&self) -> crate::Result<()> {
let main: PathBuf = PathBuf::from(Self::DIR_SRC).join("main/"); let main: PathBuf = PathBuf::from(Self::DIR_SRC).join("main/");
let test: PathBuf = PathBuf::from(Self::DIR_SRC).join("test/"); let test: PathBuf = PathBuf::from(Self::DIR_SRC).join("test/");

View File

@@ -5,6 +5,11 @@ use cli::{CLI_ARGS, Command};
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
// type_ is yet unused. // type_ is yet unused.
// `raven new` requires special behaviour.
// This will call the "new" part of the command,
// changing the cwd, before calling WorkspaceHandler.init()
// on the actual workspace directory.
if let Command::New { project_name, .. } = &CLI_ARGS.command { if let Command::New { project_name, .. } = &CLI_ARGS.command {
new(project_name.to_owned())?; new(project_name.to_owned())?;
} }
@@ -35,7 +40,10 @@ fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
/// Creates a new project directory and enters it.
fn new(project_name: String) -> anyhow::Result<()> { fn new(project_name: String) -> anyhow::Result<()> {
// Because this messes around with the CWD, this should live external to any
// instance of a `WorkspaceHandler`.
let cwd = std::env::current_dir()?.join(project_name); let cwd = std::env::current_dir()?.join(project_name);
std::fs::create_dir(&cwd)?; std::fs::create_dir(&cwd)?;