diff --git a/.zed/debug.json b/.zed/debug.json new file mode 100644 index 0000000..67dc089 --- /dev/null +++ b/.zed/debug.json @@ -0,0 +1,18 @@ +// Project-local debug tasks +// +// For more documentation on how to configure debug tasks, +// see: https://zed.dev/docs/debugger +[ + { + "label": "Build & Debug raven new", + "build": { + "command": "cargo", + "args": ["run", "--", "new", "JavaProjectTest"], + }, + "program": "$ZED_WORKTREE_ROOT/target/debug/binary", + // sourceLanguages is required for CodeLLDB (not GDB) when using Rust + "sourceLanguages": ["rust"], + "request": "launch", + "adapter": "CodeLLDB", + }, +] diff --git a/Cargo.lock b/Cargo.lock index abb7af2..c12d1cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -74,9 +74,6 @@ name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -dependencies = [ - "serde_core", -] [[package]] name = "block-buffer" @@ -107,9 +104,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.54" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" dependencies = [ "clap_builder", "clap_derive", @@ -117,9 +114,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" dependencies = [ "anstream", "anstyle", @@ -129,14 +126,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -145,12 +142,64 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +[[package]] +name = "cli" +version = "0.1.0" +dependencies = [ + "clap", +] + [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core" +version = "0.1.0" +dependencies = [ + "anyhow", + "derive_more", + "fs", + "io", + "java", + "pathsub", + "semver", + "serde", + "sha256", + "toml", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -170,6 +219,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.114", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -186,6 +258,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "fs" +version = "0.1.0" +dependencies = [ + "derive_more", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -196,6 +275,31 @@ dependencies = [ "version_check", ] +[[package]] +name = "hard-xml" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b07b8ba970e18a03dbb79f6786b6e4d6f198a0ac839aa5182017001bb8dee17" +dependencies = [ + "hard-xml-derive", + "jetscii", + "lazy_static", + "memchr", + "xmlparser", +] + +[[package]] +name = "hard-xml-derive" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c43e7c3212bd992c11b6b9796563388170950521ae8487f5cdf6f6e792f1c8" +dependencies = [ + "bitflags", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -224,12 +328,43 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "io" +version = "0.1.0" +dependencies = [ + "derive_more", + "subprocess", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "java" +version = "0.1.0" +dependencies = [ + "bytesize", + "derive_more", + "fs", + "io", + "semver", +] + +[[package]] +name = "jetscii" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.180" @@ -237,10 +372,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] -name = "once_cell" -version = "1.21.3" +name = "memchr" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "once_cell_polyfill" @@ -248,12 +383,36 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "path" +version = "0.1.0" +dependencies = [ + "const_format", +] + +[[package]] +name = "pathsub" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dadd38133bcbe43264410412c48614bab4ef899f0792ffc4530dc19ec000a970" + [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "pom" +version = "0.1.0" +dependencies = [ + "derive_more", + "hard-xml", + "semver", + "serde", + "strum", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -265,9 +424,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -278,27 +437,22 @@ version = "0.1.0" dependencies = [ "anyhow", "bytesize", - "clap", - "ron", - "semver", - "serde", - "sha256", - "subprocess", + "cli", + "core", + "fs", + "io", + "java", + "path", "toml", ] [[package]] -name = "ron" -version = "0.12.0" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "bitflags", - "once_cell", - "serde", - "serde_derive", - "typeid", - "unicode-ident", + "semver", ] [[package]] @@ -338,7 +492,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -381,15 +535,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "subprocess" -version = "0.2.13" +name = "strum" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75238edb5be30a9ea3035b945eb9c319dde80e879411cdc9a8978e1ac822960" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "subprocess" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09969f0abcf65111c0cbdd8bfaa292ca3c38b46bc8ecc7270467af2f4acb172" dependencies = [ "libc", "winapi", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.114" @@ -450,12 +636,6 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - [[package]] name = "typenum" version = "1.19.0" @@ -468,6 +648,18 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "utf8parse" version = "0.2.2" @@ -522,3 +714,9 @@ name = "winnow" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" diff --git a/Cargo.toml b/Cargo.toml index c3f6124..265e5d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,35 +1,51 @@ -[package] -name = "raven" -version = "0.1.0" +[workspace] +resolver = "3" +members = ["crates/*"] +default-members = ["crates/*"] + +[workspace.package] edition = "2024" license = "MIT" -authors = ["Olivia Brooks", "Adrian Long"] -description = "A simple build tool for Java" repository = "https://gitea.cutieguwu.ca/Cutieguwu/raven" -keywords = ["java", "tool"] -categories = ["development-tools::build-utils"] publish = false +test = true -[dependencies] +[workspace.dependencies] +# +# Workspace member crates +# +cli = { path = "crates/cli" } +fs = { path = "crates/fs" } +io = { path = "crates/io" } +java = { path = "crates/java" } +core = { path = "crates/core" } +path = { path = "crates/path" } +pom = { path = "crates/pom" } +raven = { path = "crates/raven" } + +# +# External crates +# anyhow = "1.0" bytesize = "2.3" -# hard-xml = "1.41" +const_format = "0.2.35" +hard-xml = "1.41" +lenient_semver = "0.4.2" pathsub = "0.1.1" ron = "0.12.0" sha256 = "1.6" subprocess = "0.2.13" toml = "0.9.11" -[dependencies.clap] -version = "4.5" -features = ["cargo", "derive"] +derive_more = { version = "2.1", features = ["display", "from"] } +semver = { version = "1.0",features = ["serde"] } +serde = { version = "1.0",features = ["derive"] } +strum = { version = "0.27.2", features = ["derive"] } -[dependencies.semver] -version = "1.0" -features = ["serde"] +[workspace.lints.rust] +unsafe_code = "forbid" -[dependencies.serde] -version = "1.0" -features = ["derive"] +[profile.dev] +incremental = true diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 0000000..93aed44 --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "cli" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Raven's CLI" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies.clap] +version = "4.5" +features = ["cargo", "derive"] diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs new file mode 100644 index 0000000..b45c8ed --- /dev/null +++ b/crates/cli/src/lib.rs @@ -0,0 +1,153 @@ +use std::sync::LazyLock; +use std::{fmt::Display, path::PathBuf}; + +use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum}; + +pub static CLI_ARGS: LazyLock = LazyLock::new(|| CliArgs::parse()); + +#[derive(Debug, Parser)] +#[clap(author, version)] +#[command(help_template = "{author-section}\n{usage-heading} {usage}\n\n{all-args}")] +pub struct CliArgs { + #[command(subcommand)] + pub command: Command, +} + +#[derive(Debug, Clone, Subcommand)] +pub enum Command { + /// Create a new raven project + New { + #[clap(flatten)] + type_: ProjectFlag, + name: String, + }, + /// Create a new raven project in an existing directory + Init, + /// Compile the current project + Build, + /// Run the current project + Run { + #[clap(value_hint = clap::ValueHint::DirPath)] + entry_point: Option, + + #[clap(flatten)] + assertions: Assertions, + }, + /// !!! BORKED !!! Run the tests + Test { + #[clap(flatten)] + assertions: Assertions, + }, + /// Remove the target directory and caching + Clean, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Args)] +pub struct Assertions { + /// Disable assertions. + #[arg(short, long = "no-assert", action = ArgAction::SetFalse)] + assertions: bool, +} + +impl Into for Assertions { + fn into(self) -> bool { + self.assertions + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Args)] +#[group(multiple = false)] +pub struct ProjectFlag { + #[arg(long, action = ArgAction::SetTrue)] + _nest: (), + #[arg(long, action = ArgAction::SetTrue)] + _package: (), + + #[arg( + hide = true, + required = false, + short, + long, + default_value_ifs = [ + ("_nest", "true", "nest"), + ("_package", "true", "package"), + ("_nest", "false", "nest"), + ], + )] + pub project_type: ProjectType, +} + +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] +pub enum ProjectType { + #[default] + Nest, + Package, +} + +impl Display for ProjectType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", Self::to_string(&self)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn args_new_w_arg() { + let args: CliArgs = Parser::try_parse_from(["raven", "new", "demo"]).unwrap(); + let type_ = match args.command { + Command::New { type_, .. } => type_, + _ => unreachable!(), + }; + + assert!(type_.project_type == ProjectType::Nest); + } + + #[test] + fn args_new_nest() { + let args: CliArgs = Parser::try_parse_from(["raven", "new", "--nest", "demo"]).unwrap(); + let type_ = match args.command { + Command::New { type_, .. } => type_, + _ => unreachable!(), + }; + + assert!(type_.project_type == ProjectType::Nest); + } + + #[test] + fn args_new_package() { + let args: CliArgs = Parser::try_parse_from(["raven", "new", "--package", "demo"]).unwrap(); + let type_ = match args.command { + Command::New { type_, .. } => type_, + _ => unreachable!(), + }; + + assert!(type_.project_type == ProjectType::Package); + } + + #[test] + fn args_run_assert() { + let args: CliArgs = Parser::try_parse_from(["raven", "run", "Main"]).unwrap(); + let assertions: bool = match args.command { + Command::Run { assertions, .. } => assertions.assertions, + _ => unreachable!(), + }; + + assert!(assertions == true) + } + + #[test] + fn args_run_no_assert() { + let args: CliArgs = + Parser::try_parse_from(["raven", "run", "--no-assert", "Main"]).unwrap(); + let assertions: bool = match args.command { + Command::Run { assertions, .. } => assertions.assertions, + _ => unreachable!(), + }; + + assert!(assertions == false) + } +} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml new file mode 100644 index 0000000..4a062ea --- /dev/null +++ b/crates/core/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "core" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Raven's core, including metadata tooling and resources" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +derive_more.workspace = true +fs.workspace = true +io.workspace = true +java.workspace = true +pathsub.workspace = true +semver.workspace = true +serde.workspace = true +sha256.workspace = true +toml.workspace = true + +[dependencies.anyhow] +workspace = true +optional = true + +[features] +into_anyhow = ["dep:anyhow"] diff --git a/assets/src/main/Main.java b/crates/core/assets/Main.java similarity index 100% rename from assets/src/main/Main.java rename to crates/core/assets/Main.java diff --git a/assets/src/test/MainTest.java b/crates/core/assets/MainTest.java similarity index 100% rename from assets/src/test/MainTest.java rename to crates/core/assets/MainTest.java diff --git a/crates/core/src/class.rs b/crates/core/src/class.rs new file mode 100644 index 0000000..7a486ba --- /dev/null +++ b/crates/core/src/class.rs @@ -0,0 +1,10 @@ +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Class { + pub path: PathBuf, + pub checksum: String, +} diff --git a/crates/core/src/dependency.rs b/crates/core/src/dependency.rs new file mode 100644 index 0000000..190972a --- /dev/null +++ b/crates/core/src/dependency.rs @@ -0,0 +1,43 @@ +use semver::Version; +use serde::{Deserialize, Serialize}; + +use crate::package::PackageHandler; + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Dependency { + name: String, + version: Version, + pub checksum: String, + #[serde(skip_serializing_if = ">::is_none")] + source: Option, // Path / URL +} + +impl Dependency { + /// Returns a path to the dependency in local storage + /// if there is one. + pub fn local_path(&self) -> String { + if self.source.as_ref().is_some_and(|path| !is_url(path)) { + return self.source.clone().unwrap(); + } + + // TODO: Convert from reverse domain name to path. + return self.name.clone(); + } +} + +impl From for Dependency { + fn from(value: PackageHandler) -> Self { + Dependency { + name: value.name(), + version: value.version(), + checksum: String::new(), + source: None, + } + } +} + +/// TODO: This is just a placeholder at present. +fn is_url(path: S) -> bool { + return false; +} diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs new file mode 100644 index 0000000..ec13601 --- /dev/null +++ b/crates/core/src/error.rs @@ -0,0 +1,25 @@ +use derive_more::{Display, From}; + +pub type Result = core::result::Result; + +#[derive(Debug, From, Display)] +pub enum Error { + #[from] + Io(io::Error), + + #[from] + Java(java::Error), + + MissingFileName, + + #[from] + StdIo(std::io::Error), + + #[from] + TomlDeserialize(toml::de::Error), + + #[from] + TomlSerialize(toml::ser::Error), + + UnknownPackage, +} diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs new file mode 100644 index 0000000..b11cf46 --- /dev/null +++ b/crates/core/src/lib.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +pub mod class; +pub mod dependency; +pub mod error; +pub mod meta; +pub mod nest; +pub mod package; +pub mod prelude; +pub mod prey; +pub mod workspace; + +pub use error::{Error, Result}; diff --git a/crates/core/src/meta.rs b/crates/core/src/meta.rs new file mode 100644 index 0000000..3095992 --- /dev/null +++ b/crates/core/src/meta.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +use semver::Version; +use serde::{Deserialize, Serialize}; + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Meta { + pub name: String, + pub version: Version, + #[serde(skip_serializing_if = ">::is_none")] + pub authors: Option>, + #[serde(skip_serializing_if = ">::is_none")] + pub repository: Option, + #[serde(skip_serializing_if = ">::is_none")] + pub license: Option, + #[serde(skip_serializing_if = ">::is_none")] + pub license_file: Option, +} + +impl Meta { + pub fn new(name: S) -> Self { + let mut meta = Self::default(); + meta.name = name.to_string(); + meta + } +} + +impl Default for Meta { + fn default() -> Self { + Meta { + name: String::from("Main"), + version: Version::new(0, 1, 0), + authors: None, + repository: None, + license: None, + license_file: None, + } + } +} diff --git a/crates/core/src/nest.rs b/crates/core/src/nest.rs new file mode 100644 index 0000000..4b458df --- /dev/null +++ b/crates/core/src/nest.rs @@ -0,0 +1,105 @@ +use std::collections::HashSet; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::meta::Meta; +use crate::prelude::Dependency; +use crate::workspace::Workspace; + +pub const F_NEST_TOML: &str = "Nest.toml"; +pub const F_NEST_LOCK: &str = "Nest.lock"; + +/// Data struct +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)] +pub struct Nest { + workspace: Workspace, + meta: Meta, + dependencies: HashSet, +} + +impl Nest { + pub fn new(name: S) -> Self { + Self { + workspace: Workspace::default(), + meta: Meta::new(name), + dependencies: Default::default(), + } + } + + pub fn write>(&self, path: P) -> crate::Result<()> { + Ok(OpenOptions::new() + .write(true) + .create(true) + .open(path)? + .write_all(toml::to_string_pretty(&self)?.as_bytes())?) + } + + pub fn default_package(&self) -> PathBuf { + self.workspace.default_package.clone() + } + + pub fn name(&self) -> String { + self.meta.name.clone() + } + + pub fn set_default_package>(&mut self, package: P) { + self.workspace.default_package = package.as_ref().to_path_buf(); + } +} + +impl TryFrom for Nest { + type Error = crate::Error; + + fn try_from(value: PathBuf) -> Result { + let f = OpenOptions::new().read(true).open(value)?; + Self::try_from(f) + } +} + +impl TryFrom for Nest { + type Error = crate::Error; + + fn try_from(mut value: File) -> Result { + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + Ok(toml::from_str(buf.as_str())?) + } +} + +/// Data struct +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)] +pub struct NestLock { + pub dependencies: Vec, +} + +impl NestLock { + pub fn write>(&self, path: P) -> crate::Result<()> { + Ok(OpenOptions::new() + .write(true) + .create(true) + .open(path)? + .write_all(toml::to_string_pretty(&self)?.as_bytes())?) + } +} + +impl TryFrom for NestLock { + type Error = crate::Error; + + fn try_from(value: PathBuf) -> Result { + let f = OpenOptions::new().read(true).open(value)?; + Self::try_from(f) + } +} + +impl TryFrom for NestLock { + type Error = crate::Error; + + fn try_from(mut value: File) -> Result { + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + Ok(toml::from_str(buf.as_str())?) + } +} diff --git a/crates/core/src/package.rs b/crates/core/src/package.rs new file mode 100644 index 0000000..97506ff --- /dev/null +++ b/crates/core/src/package.rs @@ -0,0 +1,56 @@ +use std::hash::Hash; +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; + +use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey, PreyLock}; + +/// Hashing is only based off the Prey. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PackageHandler { + prey: Prey, + prey_lock: Option, + package_root: PathBuf, + target_dir: PathBuf, +} + +impl PackageHandler { + pub fn new>(package_root: P, target_dir: P) -> crate::Result { + let package_root = package_root.as_ref().to_path_buf(); + + Ok(Self { + prey: Prey::try_from(package_root.join(F_PREY_TOML))?, + prey_lock: PreyLock::try_from(package_root.join(F_PREY_LOCK)).ok(), + package_root, + target_dir: target_dir.as_ref().to_path_buf(), + }) + } + + pub fn update_class_cache(&self) {} + + pub fn entry_point(&self) -> PathBuf { + self.prey.entry_point() + } + + pub fn name(&self) -> String { + self.prey.name() + } + + pub fn version(&self) -> semver::Version { + self.prey.version() + } +} + +impl Hash for PackageHandler { + fn hash(&self, state: &mut H) { + self.prey.hash(state); + } +} + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Package { + pub entry_point: PathBuf, +} + +//impl Into for Package {} diff --git a/crates/core/src/prelude.rs b/crates/core/src/prelude.rs new file mode 100644 index 0000000..2b6b762 --- /dev/null +++ b/crates/core/src/prelude.rs @@ -0,0 +1,9 @@ +#![allow(unused_imports)] + +pub use crate::class::Class; +pub use crate::dependency::Dependency; +pub use crate::meta::Meta; +pub use crate::nest::{F_NEST_LOCK, F_NEST_TOML, Nest, NestLock}; +pub use crate::package::{Package, PackageHandler}; +pub use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey, PreyLock}; +pub use crate::workspace::{Workspace, WorkspaceHandler}; diff --git a/crates/core/src/prey.rs b/crates/core/src/prey.rs new file mode 100644 index 0000000..c11b71d --- /dev/null +++ b/crates/core/src/prey.rs @@ -0,0 +1,78 @@ +use std::collections::HashSet; +use std::fs::{File, OpenOptions}; +use std::io::Read; +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +use crate::class::Class; +use crate::meta::Meta; +use crate::package::Package; + +pub const F_PREY_TOML: &str = "Prey.toml"; +pub const F_PREY_LOCK: &str = "Prey.lock"; + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq)] +pub struct Prey { + package: Package, + meta: Meta, +} + +impl Prey { + pub fn entry_point(&self) -> PathBuf { + self.package.entry_point.clone() + } + + pub fn name(&self) -> String { + self.meta.name.clone() + } + + pub fn version(&self) -> semver::Version { + self.meta.version.clone() + } +} + +impl TryFrom for Prey { + type Error = crate::Error; + + fn try_from(value: PathBuf) -> Result { + let f = OpenOptions::new().read(true).open(value)?; + Self::try_from(f) + } +} + +impl TryFrom for Prey { + type Error = crate::Error; + + fn try_from(mut value: File) -> Result { + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + Ok(toml::from_str(buf.as_str())?) + } +} + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct PreyLock { + classes: HashSet, +} + +impl TryFrom for PreyLock { + type Error = crate::Error; + + fn try_from(value: PathBuf) -> Result { + let f = OpenOptions::new().read(true).open(value)?; + Self::try_from(f) + } +} + +impl TryFrom for PreyLock { + type Error = crate::Error; + + fn try_from(mut value: File) -> Result { + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + Ok(toml::from_str(buf.as_str())?) + } +} diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs new file mode 100644 index 0000000..9fc5885 --- /dev/null +++ b/crates/core/src/workspace.rs @@ -0,0 +1,272 @@ +use std::collections::HashMap; +use std::fs::{OpenOptions, read_dir}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; + +use fs::{self, expand_files}; +use io::run_process; +use java::{self, JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; +use serde::{Deserialize, Serialize}; + +use crate::Error; +use crate::dependency::Dependency; +use crate::nest::{F_NEST_LOCK, F_NEST_TOML, Nest, NestLock}; +use crate::package::PackageHandler; +use crate::prey::F_PREY_TOML; + +pub struct WorkspaceHandler { + nest: Nest, + nest_lock: Option, + project_root: PathBuf, + packages: HashMap, +} + +impl WorkspaceHandler { + const DIR_SRC: &str = "src/"; + const DIR_TARGET: &str = "target/"; + + pub fn new>(project_root: P) -> crate::Result { + let project_root = project_root.as_ref().canonicalize()?; + + Ok(Self { + nest: Nest::new( + project_root + .file_name() + .ok_or(Error::MissingFileName)? + .display(), + ), + nest_lock: None, + packages: HashMap::new(), + project_root, + }) + } + + pub fn load>(project_root: P) -> crate::Result { + let project_root = project_root.as_ref().canonicalize()?; + + let mut workspace_manager = Self { + nest: Nest::try_from(project_root.join(F_NEST_TOML))?, + nest_lock: NestLock::try_from(project_root.join(F_NEST_LOCK)).ok(), + packages: HashMap::new(), + project_root, + }; + + workspace_manager.discover_packages()?; + + Ok(workspace_manager) + } + + pub fn write(&self) -> crate::Result<()> { + self.nest.write(self.project_root.join(F_NEST_TOML))?; + + if let Option::Some(lock) = self.nest_lock.clone() { + lock.write(self.project_root.join(F_NEST_LOCK))?; + } + + Ok(()) + } + + //pub fn refresh_packages(&mut self) -> crate::Result<()> {} + + /* + /// Future `build` method. + pub fn compile(&self, target: Option) -> crate::Result<()> { + let mut target = target.unwrap_or(self.nest.default_package()); + if !target.is_file() { + // Use is_file to skip messing with pathing for src/ + // If target is not a file (explicit entry point), check if it's a known package + // and use that's package's default entry point. + target = target.join( + self.packages + .get(&target) + .ok_or(Error::UnknownPackage)? + .entry_point(), + ); + } + + //java::Compiler::new(); + + Ok(()) + } + + fn make_compiler_job>(target: P) { + // Generate dependency tree. + } + */ + + pub fn init(&mut self) -> crate::Result<()> { + let is_empty = read_dir(self.project_root.as_path()).is_ok_and(|tree| tree.count() == 0); + + // ORDER MATTERS. THIS MUST COME FIRST. + // Make config file. + self.write_nest()?; + + // Make .java-version + self.write_java_version()?; + + // Make src/, target/, test/ + self.write_dir_tree()?; + + if !is_empty { + self.write_example_project()?; + self.discover_packages()?; + + run_process(&["git", "init", "."])?; + } + + // Append to .gitignore + if let Result::Ok(mut f) = OpenOptions::new() + .append(true) + .create(true) + .read(true) + .open(".gitignore") + { + let mut buf = String::new(); + f.read_to_string(&mut buf)?; + + for ignored in [ + "# Automatically added by Raven".to_string(), + Self::DIR_TARGET.to_string(), + format!("*.{}", JAVA_EXT_CLASS), + ] { + if !buf.contains(&ignored) { + f.write(format!("{}\n", ignored).as_bytes())?; + } + } + } + + Ok(()) + } + + // This is the naive build + pub fn build(&mut self) -> crate::Result<()> { + Ok(()) + } + + /// Add any newly created packages. + fn discover_packages(&mut self) -> crate::Result<()> { + // Scan the src/ directory for entries, + // filter out the files, + // then construct PackageManagers for each package + + // Promote *not* using reverse domain name tree structures + // by improving the speed of package discovery by using read_dir + // and checking for an immediate Prey.toml before expanding the + // whole subtree. + // + // Yes, I know this looks like shit. + // That's because it is. + + for file in read_dir(Self::DIR_SRC)? + // Get directories + .filter_map(|entry| { + if entry.as_ref().is_ok_and(|entry| entry.path().is_dir()) { + Some(entry.unwrap().path()) + } else { + None + } + }) + // Get Prey.toml files + .filter_map(|dir| { + Some(if dir.join(F_PREY_TOML).exists() { + vec![dir.join(F_PREY_TOML)] + } else { + expand_files(dir) + .ok()? + .iter() + .filter_map(|file| { + if file.ends_with(PathBuf::from(F_PREY_TOML)) { + Some(file.to_owned()) + } else { + None + } + }) + .collect() + }) + }) + .flatten() + { + let package_root = + pathsub::sub_paths(file.as_path(), PathBuf::from(Self::DIR_SRC).as_path()).unwrap(); + + self.packages.insert( + package_root.to_path_buf(), + PackageHandler::new(package_root, PathBuf::from(Self::DIR_TARGET))?, + ); + } + + Ok(()) + } + + fn write_nest(&self) -> crate::Result<()> { + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(F_NEST_TOML) + { + f.write_all(toml::to_string_pretty(&self.nest)?.as_bytes())?; + } + + Ok(()) + } + + fn write_java_version(&self) -> crate::Result<()> { + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(java::F_JAVA_VERSION) + { + f.write_all(format!("{}\n", java::get_javac_ver()?.major.to_string()).as_bytes())?; + } + + Ok(()) + } + + fn write_dir_tree(&self) -> std::io::Result<()> { + for dir in [ + format!("{}main/java", Self::DIR_SRC), + format!("{}test/java", Self::DIR_SRC), + Self::DIR_TARGET.to_string(), + ] { + std::fs::create_dir_all(std::env::current_dir()?.join(dir))?; + } + + Ok(()) + } + + fn write_example_project(&self) -> std::io::Result<()> { + // Make src/main/Main.java + if let Result::Ok(mut f) = OpenOptions::new().write(true).create_new(true).open( + PathBuf::from(Self::DIR_SRC) + .join("main/java/Main") + .with_extension(JAVA_EXT_SOURCE), + ) { + f.write_all(include_bytes!("../assets/Main.java"))?; + } + + // Make src/test/MainTest.java + if let Result::Ok(mut f) = OpenOptions::new().write(true).create_new(true).open( + PathBuf::from(Self::DIR_SRC) + .join("test/java/MainTest") + .with_extension(JAVA_EXT_SOURCE), + ) { + f.write_all(include_bytes!("../assets/MainTest.java"))?; + } + + Ok(()) + } +} + +/// Data struct +#[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct Workspace { + pub default_package: PathBuf, +} + +impl Default for Workspace { + fn default() -> Self { + Workspace { + default_package: PathBuf::from("main"), + } + } +} diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml new file mode 100644 index 0000000..2ce3924 --- /dev/null +++ b/crates/fs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "fs" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Raven's FS utilities" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +derive_more.workspace = true diff --git a/src/fs.rs b/crates/fs/src/lib.rs similarity index 74% rename from src/fs.rs rename to crates/fs/src/lib.rs index 34d55a8..c15cd3d 100644 --- a/src/fs.rs +++ b/crates/fs/src/lib.rs @@ -1,6 +1,9 @@ use std::path::{Path, PathBuf}; -pub fn expand_files>(path: P) -> anyhow::Result> { +pub const EXT_TOML: &str = ".toml"; +pub const EXT_LOCK: &str = ".lock"; + +pub fn expand_files>(path: P) -> std::io::Result> { let path = path.as_ref(); if path.is_file() { diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml new file mode 100644 index 0000000..f849c5e --- /dev/null +++ b/crates/io/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "io" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Raven's IO utilities" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +derive_more.workspace = true +subprocess.workspace = true diff --git a/crates/io/src/error.rs b/crates/io/src/error.rs new file mode 100644 index 0000000..69a7ec7 --- /dev/null +++ b/crates/io/src/error.rs @@ -0,0 +1,11 @@ +use derive_more::{Display, From}; + +pub type Result = core::result::Result; + +#[derive(Debug, From, Display)] +pub enum Error { + #[from] + Io(std::io::Error), + #[from] + Popen(subprocess::PopenError), +} diff --git a/src/io.rs b/crates/io/src/lib.rs similarity index 65% rename from src/io.rs rename to crates/io/src/lib.rs index b329ec3..8608558 100644 --- a/src/io.rs +++ b/crates/io/src/lib.rs @@ -1,8 +1,10 @@ +mod error; + use std::ffi; -use anyhow::Context; +pub use error::{Error, Result}; -pub fn run_process(argv: &[S]) -> anyhow::Result<(Option, Option)> +pub fn run_process(argv: &[S]) -> Result<(Option, Option)> where S: AsRef, { @@ -14,9 +16,7 @@ where }, )?; - let result = process - .communicate(None) - .context("Failed to communicate with subprocess"); + let result = process.communicate(None)?; if process .wait_timeout(std::time::Duration::from_secs(5)) @@ -26,5 +26,5 @@ where process.terminate()?; } - result + Ok(result) } diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml new file mode 100644 index 0000000..7d5a326 --- /dev/null +++ b/crates/java/Cargo.toml @@ -0,0 +1,21 @@ +# May want to find a better name, more reflective of the JDK part +# than the entire Java language. + +[package] +name = "java" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Tools for interfacing with the Java Development Kit" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +bytesize.workspace = true +derive_more.workspace = true +fs.workspace = true +io.workspace = true +semver.workspace = true diff --git a/crates/java/src/compiler.rs b/crates/java/src/compiler.rs new file mode 100644 index 0000000..bfa9038 --- /dev/null +++ b/crates/java/src/compiler.rs @@ -0,0 +1,80 @@ +use std::path::{Path, PathBuf}; + +use crate::JAVA_BIN_COMPILER; +use crate::Result; + +#[derive(Debug, Default, Clone)] +pub struct CompilerBuilder { + class_path: Option, + destination: Option, +} + +impl CompilerBuilder { + pub fn new() -> Self { + Self::default() + } + + pub fn class_path>(&mut self, class_path: S) -> &mut Self { + self.class_path = Some(class_path.as_ref().to_path_buf()); + self + } + + pub fn destination>(&mut self, destination: S) -> &mut Self { + self.destination = Some(destination.as_ref().to_path_buf()); + self + } + + pub fn build(&self) -> Compiler { + let mut flags = vec![]; + + if let Option::Some(path) = self.destination.to_owned() { + flags.push(CompilerFlag::Destination { path }); + } + + if let Option::Some(path) = self.class_path.to_owned() { + flags.push(CompilerFlag::Classpath { path }); + } + + Compiler { flags } + } +} + +#[derive(Debug, Clone)] +pub struct Compiler { + flags: Vec, +} + +impl Compiler { + pub fn compile>(self, path: P) -> Result<(Option, Option)> { + let mut cmd: Vec = vec![JAVA_BIN_COMPILER.to_string()]; + + cmd.extend( + self.flags + .clone() + .into_iter() + .flat_map(|f| Into::>::into(f)), + ); + cmd.extend( + fs::expand_files(path)? + .into_iter() + .filter_map(|f| Some(f.to_str()?.to_string())), + ); + + Ok(io::run_process(cmd.as_slice())?) + } +} + +#[derive(Debug, Clone)] +pub enum CompilerFlag { + Classpath { path: PathBuf }, + Destination { path: PathBuf }, +} + +impl Into> for CompilerFlag { + fn into(self) -> Vec { + match self { + Self::Classpath { path } => vec!["-classpath".to_string(), path.display().to_string()], + Self::Destination { path } => vec!["-d".to_string(), path.display().to_string()], + } + } +} diff --git a/crates/java/src/error.rs b/crates/java/src/error.rs new file mode 100644 index 0000000..54ed1b4 --- /dev/null +++ b/crates/java/src/error.rs @@ -0,0 +1,19 @@ +use derive_more::{Display, From}; + +pub type Result = core::result::Result; + +#[derive(Debug, From, Display)] +pub enum Error { + EmptyStdout, + + #[from] + Io(io::Error), + + NthOutOfBounds, + + #[from] + Semver(semver::Error), + + #[from] + StdIo(std::io::Error), +} diff --git a/crates/java/src/lib.rs b/crates/java/src/lib.rs new file mode 100644 index 0000000..22b5e0f --- /dev/null +++ b/crates/java/src/lib.rs @@ -0,0 +1,49 @@ +pub mod compiler; +pub mod error; +pub mod runtime; + +use std::str::FromStr; + +pub use error::{Error, Result}; +use runtime::VMFlag; + +pub const JAVA_BIN_VM: &str = "java"; +pub const JAVA_BIN_COMPILER: &str = "javac"; + +pub const JAVA_EXT_SOURCE: &str = "java"; +pub const JAVA_EXT_CLASS: &str = "class"; + +pub const F_JAVA_VERSION: &str = ".java-version"; + +/// Uses the java binary to parse its stdout for version information. +/// +/// This is non-caching. +pub fn get_javac_ver() -> Result { + // TODO: Consider making this pull the version info from javac instead? + + /* + * $ java --version + * openjdk 21.0.9 2025-10-21 + * OpenJDK Runtime Environment (build 21.0.9+10) + * OpenJDK 64-Bit Server VM (build 21.0.9+10, mixed mode, sharing) + */ + + Ok(semver::Version::from_str( + get_java_version_info()? + .lines() + .nth(0) + .ok_or(Error::EmptyStdout)? + .split_ascii_whitespace() + .nth(1) + .ok_or(Error::NthOutOfBounds)?, + )?) +} + +/// Calls the java binary, returning the complete stdout version information. +fn get_java_version_info() -> Result { + Ok( + io::run_process(&[JAVA_BIN_VM, VMFlag::Version.to_string().as_str()])? + .0 + .ok_or(Error::EmptyStdout)?, + ) +} diff --git a/src/java.rs b/crates/java/src/runtime.rs similarity index 54% rename from src/java.rs rename to crates/java/src/runtime.rs index 8b4285e..9f14d2d 100644 --- a/src/java.rs +++ b/crates/java/src/runtime.rs @@ -1,16 +1,11 @@ use std::fmt; use std::path::{Path, PathBuf}; -use anyhow::Context; +use crate::JAVA_BIN_VM; +use crate::Result; + use bytesize::ByteSize; -pub const JAVA_VM: &str = "java"; -pub const JAVA_COMPILER: &str = "javac"; - -pub const JAVA_EXT_SOURCE: &str = "java"; -pub const JAVA_EXT_CLASS: &str = "class"; - -// TODO: Builder-pattern JVM wrapper. #[derive(Debug, Default, Clone)] pub struct JVMBuilder { assertions: bool, @@ -79,11 +74,8 @@ pub struct JVM { } impl JVM { - pub fn run>( - self, - entry_point: P, - ) -> anyhow::Result<(Option, Option)> { - let mut cmd = vec![JAVA_VM.to_string()]; + pub fn run>(self, entry_point: P) -> Result<(Option, Option)> { + let mut cmd = vec![JAVA_BIN_VM.to_string()]; cmd.extend( self.flags @@ -94,11 +86,11 @@ impl JVM { cmd.push(entry_point.as_ref().to_path_buf().display().to_string()); - let result = crate::io::run_process(cmd.as_slice()); + let result = io::run_process(cmd.as_slice())?; + + if self.monitor { + let (stdout, stderr) = &result; - if self.monitor - && let Result::Ok((stdout, stderr)) = &result - { if let Option::Some(stdout) = stdout && stdout.len() > 0 { @@ -111,7 +103,7 @@ impl JVM { } } - result + Ok(result) } } @@ -150,85 +142,3 @@ impl fmt::Display for VMFlag { ) } } - -#[derive(Debug, Default, Clone)] -pub struct CompilerBuilder { - class_path: Option, - destination: Option, -} - -impl CompilerBuilder { - pub fn new() -> Self { - Self::default() - } - - pub fn class_path>(&mut self, class_path: S) -> &mut Self { - self.class_path = Some(class_path.as_ref().to_path_buf()); - self - } - - pub fn destination>(&mut self, destination: S) -> &mut Self { - self.destination = Some(destination.as_ref().to_path_buf()); - self - } - - pub fn build(&self) -> Compiler { - let mut flags = vec![]; - - if let Option::Some(path) = self.destination.to_owned() { - flags.push(CompilerFlag::Destination { path }); - } - - if let Option::Some(path) = self.class_path.to_owned() { - flags.push(CompilerFlag::Classpath { path }); - } - - Compiler { flags } - } -} - -#[derive(Debug, Clone)] -pub struct Compiler { - flags: Vec, -} - -impl Compiler { - pub fn compile>( - self, - path: P, - ) -> anyhow::Result<(Option, Option)> { - let mut cmd: Vec = vec![JAVA_COMPILER.to_string()]; - - cmd.extend( - self.flags - .clone() - .into_iter() - .flat_map(|f| Into::>::into(f)), - ); - cmd.extend(crate::fs::expand_files(path)?.into_iter().filter_map(|f| { - Some( - f.to_str() - .context("Failed to cast PathBuf to &str") - .ok()? - .to_string(), - ) - })); - - crate::io::run_process(cmd.as_slice()) - } -} - -#[derive(Debug, Clone)] -pub enum CompilerFlag { - Classpath { path: PathBuf }, - Destination { path: PathBuf }, -} - -impl Into> for CompilerFlag { - fn into(self) -> Vec { - match self { - Self::Classpath { path } => vec!["-classpath".to_string(), path.display().to_string()], - Self::Destination { path } => vec!["-d".to_string(), path.display().to_string()], - } - } -} diff --git a/crates/path/Cargo.toml b/crates/path/Cargo.toml new file mode 100644 index 0000000..5f3bcc8 --- /dev/null +++ b/crates/path/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "path" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Raven's pathing tools" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +const_format.workspace = true diff --git a/crates/path/src/lib.rs b/crates/path/src/lib.rs new file mode 100644 index 0000000..b8bbb2e --- /dev/null +++ b/crates/path/src/lib.rs @@ -0,0 +1,151 @@ +use std::collections::HashMap; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +//TODO: Clean this up. Shouldn't need duplicated DIR_SRC consts about the workspace. + +const DIR_SRC: &str = "src/"; +const DIR_TARGET: &str = "target/"; + +const DIR_MAIN: &str = const_format::concatcp!(DIR_SRC, "main/"); +const DIR_TEST: &str = const_format::concatcp!(DIR_SRC, "test/"); + +#[derive(Debug, Clone)] +pub struct PathHandler { + root_path: PathBuf, + // This is a short-living binary. This doesn't need an LRU like Moka. + derived_path_cache: HashMap, +} + +impl PathHandler { + pub fn new(root_path: PathBuf) -> Self { + Self::from(root_path) + } + + pub fn root_path(&self) -> PathBuf { + self.root_path.clone() + } + + /// This is a readability helper. + /// Make sure to set the root of this `PathHandler` to the project root. + /// This simply calls upon the root_path() of the `PathHandler`. + pub fn project_root(&self) -> PathBuf { + self.root_path() + } + + pub fn dir_src(&mut self) -> PathBuf { + self.get_path(DIR_SRC) + } + + pub fn dir_target(&mut self) -> PathBuf { + self.get_path(DIR_TARGET) + } + + pub fn dir_main(&mut self) -> PathBuf { + self.get_path(DIR_MAIN) + } + + pub fn dir_test(&mut self) -> PathBuf { + self.get_path(DIR_TEST) + } + + /// Attempts to load from cache, else generates the path and clones it to the cache. + /// Returns the requested path. + fn get_path(&mut self, k: S) -> PathBuf + where + S: ToString + AsRef, + { + self.from_cache(k.as_ref()) + .unwrap_or_else(|| { + self.gen_key(k.to_string(), self.root_path().join(k.to_string())); + self.get_path(k.as_ref()) + }) + .to_path_buf() + } + + /// Attempts to pull the value for the given key from the cache. + fn from_cache>(&self, path_key: S) -> Option { + self.derived_path_cache + .get(path_key.as_ref()) + .and_then(|v| Some(v.to_owned())) + } + + /// Tries to generate a new key-value pair in the cache + fn gen_key(&mut self, k: S, v: P) -> Option + where + P: AsRef, + S: ToString, + { + self.derived_path_cache + .insert(k.to_string(), v.as_ref().to_path_buf()) + } +} + +impl

From

for PathHandler +where + P: AsRef, +{ + fn from(value: P) -> Self { + Self { + root_path: value.as_ref().to_path_buf(), + derived_path_cache: Default::default(), + } + } +} + +pub trait PathHandled { + fn set_path_handler(&mut self, ph: Arc>) {} + + fn with_path_handler(&mut self, ph: Arc>) -> &mut Self { + self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const ROOT: &str = "/root"; + + #[test] + fn ph_get_path() { + let root = PathBuf::from(ROOT); + let expected = root.join(DIR_SRC); + + let mut ph = PathHandler::from(root); + + assert!(ph.dir_src() == expected); + } + + #[test] + fn ph_cache_gen() { + let root = PathBuf::from(ROOT); + let expected = root.join(DIR_SRC); + + let ph = PathHandler::from(root); + + assert!( + ph.derived_path_cache + .get(DIR_SRC) + .is_some_and(|v| *v == expected) + ); + } + + #[test] + fn ph_cache_pull() { + let faux_path = "faux/path"; + + let mut ph = PathHandler::from("false/root"); + ph.derived_path_cache + .insert(faux_path.to_string(), PathBuf::from(faux_path)); + + // Use the method that attempts a fallback. + // By using a false root, this will create a different path to the injected one, + // making it possible to determine if the cache load fails. + // + // I.e. + // Expected: faux/path as PathBuf + // Failed: false/root/faux/path as PathBuf + assert!(ph.get_path(faux_path) == PathBuf::from(faux_path)); + } +} diff --git a/crates/pom/Cargo.toml b/crates/pom/Cargo.toml new file mode 100644 index 0000000..266b875 --- /dev/null +++ b/crates/pom/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "pom" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "Library for serializing and deserializing Maven's POM" +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +derive_more.workspace = true +hard-xml.workspace = true +serde.workspace = true +semver.workspace = true +strum.workspace = true diff --git a/crates/pom/src/error.rs b/crates/pom/src/error.rs new file mode 100644 index 0000000..567db1b --- /dev/null +++ b/crates/pom/src/error.rs @@ -0,0 +1,12 @@ +use derive_more::{Display, From}; + +pub type Result = core::result::Result; + +#[derive(Debug, From, Display)] +pub enum Error { + #[from] + Io(std::io::Error), + + #[from] + Xml(hard_xml::XmlError), +} diff --git a/crates/pom/src/lib.rs b/crates/pom/src/lib.rs new file mode 100644 index 0000000..d717f8d --- /dev/null +++ b/crates/pom/src/lib.rs @@ -0,0 +1,25 @@ +pub mod error; +pub mod xml; + +pub use error::{Error, Result}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct Pom { + model_version: semver::Version, +} + +impl Pom { + pub fn is_empty(&self) -> bool { + self == &Self::default() + } +} + +impl Default for Pom { + fn default() -> Self { + Self { + model_version: semver::Version::new(4, 0, 0), + } + } +} diff --git a/crates/pom/src/xml.rs b/crates/pom/src/xml.rs new file mode 100644 index 0000000..0a49766 --- /dev/null +++ b/crates/pom/src/xml.rs @@ -0,0 +1,118 @@ +use std::{fs::File, io::Read}; + +use crate::Error; + +use hard_xml::{XmlRead, XmlWrite}; +use serde::{Deserialize, Serialize}; +use strum::EnumString; + +// start with the super POM idiot. + +#[derive(Debug, Clone, Deserialize, Serialize, XmlRead, XmlWrite)] +#[xml(tag = "project")] +pub struct Project { + #[xml(attr = "xmlns")] + xmlns: String, + #[xml(attr = "xlmns:xsi")] + xmlns_xsi: String, + #[xml(attr = "xsi:schemaLocation")] + xsi_schema_location: String, + + #[xml(flatten_text = "modelVersion")] + model_version: semver::Version, + + #[xml(flatten_text = "groupId")] + group_id: String, + + #[xml(flatten_text = "artifactId")] + artifact_id: String, + + #[xml(flatten_text = "version")] + version: String, + + #[xml(flatten_text = "packaging")] + packaging: String, + + #[xml(child = "properties")] + properties: Properties, + + #[xml(child = "dependencyManagement")] + dependency_management: DependencyManagement, + + #[xml(child = "dependencies")] + dependencies: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize, XmlRead, XmlWrite)] +#[xml(tag = "properties")] +pub struct Properties { + #[xml(flatten_text = "maven.compiler.source")] + source: String, + + #[xml(flatten_text = "maven.compiler.target")] + target: String, + // lwjgl.version + // lwjgl.natives +} + +#[derive(Debug, Clone, Deserialize, Serialize, XmlRead, XmlWrite)] +#[xml(tag = "dependencyManagement")] +pub struct DependencyManagement { + #[xml(child = "dependencies")] + dependencies: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize, XmlRead, XmlWrite)] +#[xml(tag = "dependency")] +pub struct Dependency { + #[xml(flatten_text = "groupId")] + group_id: String, + + #[xml(flatten_text = "artifactId")] + artifact_id: String, + + #[xml(flatten_text = "version")] + version: semver::Version, + + #[xml(flatten_text = "scope")] + scope: String, + + #[xml(flatten_text = "type")] + type_: String, + + #[xml(flatten_text = "optional")] + optional: bool, + + #[xml(child = "exclusions")] + exclusions: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize, XmlRead, XmlWrite)] +#[xml(tag = "exclusion")] +pub struct Exclusion { + #[xml(flatten_text = "groupId")] + group_id: String, + + #[xml(flatten_text = "artifactId")] + artifact_id: String, +} + +#[derive(Debug, Clone, Copy, Default, Deserialize, Serialize, EnumString)] +#[strum(serialize_all = "camelCase")] +pub enum Packaging { + #[default] + Pom, + Jar, +} + +impl TryFrom for Project { + type Error = Error; + + fn try_from(value: File) -> Result { + let mut value = value; + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + + Ok(Project::from_str(&buf)?) + } +} diff --git a/crates/raven/Cargo.lock b/crates/raven/Cargo.lock new file mode 100644 index 0000000..dd47a29 --- /dev/null +++ b/crates/raven/Cargo.lock @@ -0,0 +1,671 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "bytesize" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "clap_lex" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hard-xml" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b07b8ba970e18a03dbb79f6786b6e4d6f198a0ac839aa5182017001bb8dee17" +dependencies = [ + "hard-xml-derive", + "jetscii", + "lazy_static", + "memchr", + "xmlparser", +] + +[[package]] +name = "hard-xml-derive" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c43e7c3212bd992c11b6b9796563388170950521ae8487f5cdf6f6e792f1c8" +dependencies = [ + "bitflags", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "jetscii" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lenient_semver" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de8de3f4f3754c280ce1c8c42ed8dd26a9c8385c2e5ad4ec5a77e774cea9c1ec" +dependencies = [ + "lenient_semver_parser", + "semver", +] + +[[package]] +name = "lenient_semver_parser" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f650c1d024ddc26b4bb79c3076b30030f2cf2b18292af698c81f7337a64d7d6" +dependencies = [ + "lenient_semver_version_builder", + "semver", +] + +[[package]] +name = "lenient_semver_version_builder" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9049f8ff49f75b946f95557148e70230499c8a642bf2d6528246afc7d0282d17" +dependencies = [ + "semver", +] + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "pathsub" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dadd38133bcbe43264410412c48614bab4ef899f0792ffc4530dc19ec000a970" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "raven" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytesize", + "clap", + "const_format", + "hard-xml", + "lenient_semver", + "pathsub", + "ron", + "semver", + "serde", + "sha256", + "strum", + "subprocess", + "toml", +] + +[[package]] +name = "ron" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32" +dependencies = [ + "bitflags", + "once_cell", + "serde", + "serde_derive", + "typeid", + "unicode-ident", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha256" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6" +dependencies = [ + "async-trait", + "bytes", + "hex", + "sha2", + "tokio", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "subprocess" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75238edb5be30a9ea3035b945eb9c319dde80e879411cdc9a8978e1ac822960" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "pin-project-lite", +] + +[[package]] +name = "toml" +version = "0.9.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" diff --git a/crates/raven/Cargo.toml b/crates/raven/Cargo.toml new file mode 100644 index 0000000..32d0f6c --- /dev/null +++ b/crates/raven/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "raven" +version = "0.1.0" +edition.workspace = true +license.workspace = true + +description = "A simple build tool for Java" +keywords = ["java", "tool"] +categories = ["development-tools::build-utils"] +repository.workspace = true + +publish.workspace = true +test.workspace = true + +[dependencies] +anyhow.workspace = true +bytesize.workspace = true +cli.workspace = true +core.workspace = true +fs.workspace = true +io.workspace = true +java.workspace = true +path.workspace = true +toml.workspace = true diff --git a/crates/raven/src/env.rs b/crates/raven/src/env.rs new file mode 100644 index 0000000..706c977 --- /dev/null +++ b/crates/raven/src/env.rs @@ -0,0 +1,19 @@ +use std::path::PathBuf; + +use anyhow::Context; + +pub fn in_path>(binary: S) -> Result { + std::env::var("PATH").and_then(|paths| { + Ok(paths + .split(":") + .map(|p| PathBuf::from(p).join(binary.as_ref())) + .any(|p| p.exists())) + }) +} + +pub fn get_project_root() -> anyhow::Result { + nest::locate_nest().context( + "Attempted to find Nest.toml, but it could not be located.\n + It's likely that a call for get_project_root occurred before runtime checks were ran.", + ) +} diff --git a/crates/raven/src/main.rs b/crates/raven/src/main.rs new file mode 100644 index 0000000..1cc735c --- /dev/null +++ b/crates/raven/src/main.rs @@ -0,0 +1,98 @@ +mod env; +mod manager; + +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +use cli::{CLI_ARGS, Command}; +use java::{FN_JAVA_VERSION, JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; +//use nest::prelude::{Class, F_NEST_LOCK, F_NEST_TOML, Nest, NestLock, Prey, PreyLock}; +//use path::{PathHandled, PathHandler}; + +use anyhow::{Context, anyhow}; +use bytesize::ByteSize; + +fn main() -> anyhow::Result<()> { + // Ensure that ph is constructed with the assumption that it is at the project root. + let mut ph = match CLI_ARGS.command.clone() { + Command::Init => PathHandler::new(std::env::current_dir()?), + Command::New { name, .. } => PathHandler::new(std::env::current_dir()?.join(name)), + _ => PathHandler::new(crate::env::get_project_root()?), + }; + + // Ensure that Nest.toml exists in the way functions need. + // Init does not need one, but it's easier to deal with the minor unnecessary computation + // of running the default contrustor, thand to fight the compiler. + let mut nest = match CLI_ARGS.command { + Command::Build | Command::Run { .. } => Nest::try_from(ph.project_root().join(F_NEST_TOML)) + .map_err(|err| { + anyhow!( + "No {} found in project directory: {}.\n{}", + F_NEST_TOML, + ph.project_root().display(), + err.to_string() + ) + })?, + _ => Nest::default(), + }; + + match CLI_ARGS.command.clone() { + Command::Init => init(ph)?, + Command::New { name, .. } => { + new(name.to_owned())?; + init(ph)?; + } + Command::Build => { + build(&mut ph, &mut nest)?; + } + Command::Run { + entry_point, + assertions, + } => { + build(&mut ph, &mut nest)?; + run( + &mut ph, + entry_point.unwrap_or(nest.workspace.default_package), + assertions.into(), + )?; + } + Command::Test { assertions } => { + test(&mut ph, assertions.into())?; + } + Command::Clean => clean(&mut ph), + } + + Ok(()) +} + +fn new(project_name: String) -> anyhow::Result<()> { + let cwd = std::env::current_dir()?.join(project_name); + + std::fs::create_dir(&cwd)?; + std::env::set_current_dir(&cwd)?; + + Ok(()) +} + +fn run>( + ph: &mut PathHandler, + entry_point: P, + assertions: bool, +) -> anyhow::Result<(Option, Option)> { + // JRE pathing will be messed up without this. + std::env::set_current_dir(ph.dir_target())?; + + java::runtime::JVMBuilder::new(ph.dir_target()) + .assertions(assertions) + .monitor(true) + .build() + .run(entry_point) + .map_err(|err| anyhow!(err)) +} + +fn clean(ph: &mut PathHandler) { + let _ = std::fs::remove_file(ph.project_root().join(F_NEST_LOCK)); + let _ = std::fs::remove_dir_all(ph.dir_target()); +} diff --git a/crates/raven/src/manager.rs b/crates/raven/src/manager.rs new file mode 100644 index 0000000..6aeabe2 --- /dev/null +++ b/crates/raven/src/manager.rs @@ -0,0 +1,11 @@ +use std::collections::HashSet; + +use nest::prelude::{Nest, NestLock}; +use path::PathHandler; + +pub struct ProjectManager { + ph: PathHandler, + nest: Nest, + nest_lock: NestLock, + // HashSet +} diff --git a/retired/nest_lib_rs_old/class.rs b/retired/nest_lib_rs_old/class.rs new file mode 100644 index 0000000..5225fbc --- /dev/null +++ b/retired/nest_lib_rs_old/class.rs @@ -0,0 +1,114 @@ +use std::hash::{self, Hash}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + +use crate::{Error, Result}; + +use java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; +use path::PathHandler; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Class { + #[serde(skip_deserializing, skip_serializing)] + ph: Option>>, + path: PathBuf, + checksum: String, +} + +impl Class { + pub fn new>(ph: Arc>, path: P, checksum: String) -> Self { + Self { + ph: Some(ph), + path: path.as_ref().to_path_buf(), + checksum, + } + } + + pub fn from_file>(ph: Arc>, path: P) -> Result { + let mut path = path.as_ref().to_path_buf(); + if path.is_relative() { + path = path.canonicalize()?; + } + + let dir_src = ph.try_lock()?.dir_src(); + + Ok(Self { + ph: Some(ph), + path: PathBuf::from( + pathsub::sub_paths(path.as_path(), dir_src.as_path()).ok_or(Error::PathSub)?, + ) + .with_extension(""), + checksum: sha256::try_digest(&path)?, + }) + } + + pub fn path(&self) -> PathBuf { + self.path.clone() + } + + pub fn checksum(&self) -> String { + self.checksum.clone() + } + + /// 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() + } + + /// Returns true if the class needs updating. + /// This may also cautionarily return true if it cannot digest the file. + pub fn is_updated(&mut self) -> Result { + // Still doesn't handle inter-dependency checks. + // Hopefully then I'll clean this horror up. + let mut ph = self + .ph + .as_ref() + .ok_or(Error::MissingPathHandler)? + .try_lock()?; + + Ok(ph + .dir_target() + .join(self.subpath()) + .with_extension(JAVA_EXT_CLASS) + .exists() + && sha256::try_digest( + ph.dir_src() + .join(self.path()) + .with_extension(JAVA_EXT_SOURCE), + ) + .is_ok_and(|hash| self.checksum == hash)) + } + + pub fn set_path_handler(&mut self, ph: Arc>) { + self.ph = Some(ph); + } + + pub fn with_path_handler(&mut self, ph: Arc>) -> &mut Self { + self.ph = Some(ph); + self + } +} + +impl Hash for Class { + fn hash(&self, state: &mut H) { + self.path.hash(state); + } +} + +impl PartialEq for Class { + fn eq(&self, other: &Self) -> bool { + self.path == other.path + } + + fn ne(&self, other: &Self) -> bool { + self.path != other.path + } +} + +impl Eq for Class {} diff --git a/retired/nest_lib_rs_old/dependency.rs b/retired/nest_lib_rs_old/dependency.rs new file mode 100644 index 0000000..ed0547a --- /dev/null +++ b/retired/nest_lib_rs_old/dependency.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Hash, Default, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct Dependency { + name: String, + version: String, +} diff --git a/retired/nest_lib_rs_old/error.rs b/retired/nest_lib_rs_old/error.rs new file mode 100644 index 0000000..1f7817f --- /dev/null +++ b/retired/nest_lib_rs_old/error.rs @@ -0,0 +1,35 @@ +use std::sync::{MutexGuard, PoisonError, TryLockError}; + +use derive_more::{Display, From}; +use path::PathHandler; + +pub type Result = core::result::Result; + +#[derive(Debug, From, Display)] +pub enum Error { + #[from] + Io(std::io::Error), + + MutexLock(String), + + MutexTryLock(String), + + PathSub, + + #[from] + Toml(toml::de::Error), + + MissingPathHandler, +} + +impl From>> for Error { + fn from(value: PoisonError>) -> Self { + Self::MutexLock(value.to_string()) + } +} + +impl From>> for Error { + fn from(value: TryLockError>) -> Self { + Self::MutexTryLock(value.to_string()) + } +} diff --git a/retired/nest_lib_rs_old/lib.rs b/retired/nest_lib_rs_old/lib.rs new file mode 100644 index 0000000..ce258ee --- /dev/null +++ b/retired/nest_lib_rs_old/lib.rs @@ -0,0 +1,45 @@ +mod class; +mod dependency; +mod error; +//mod lock; +mod meta; +mod nest; +mod package; +pub mod prelude; +mod prey; +mod workspace; + +pub use error::{Error, Result}; + +use std::io; +use std::path::PathBuf; + +pub const FN_NEST: &str = "Nest"; +pub const FN_PREY: &str = "Prey"; + +pub const F_NEST_TOML: &str = const_format::concatcp!(FN_NEST, fs::EXT_TOML); +pub const F_NEST_LOCK: &str = const_format::concatcp!(FN_NEST, fs::EXT_LOCK); +pub const F_PREY_TOML: &str = const_format::concatcp!(FN_PREY, fs::EXT_TOML); +pub const F_PREY_LOCK: &str = const_format::concatcp!(FN_PREY, fs::EXT_LOCK); + +/// Return the location of the parent `Nest.toml` as [`PathBuf`] +/// +/// # Errors +/// +/// Possible cases: +/// +/// * `Nest.toml` cannot be located. +/// * Current working directory does not exist. +/// * There are insufficient permissions to access the current directory. +pub fn locate_nest() -> io::Result { + let cwd = std::env::current_dir()?; + let mut probe = cwd.clone(); + + while !probe.join(F_NEST_TOML).exists() { + if !probe.pop() { + return Err(io::ErrorKind::NotFound.into()); + } + } + + Ok(probe) +} diff --git a/retired/nest_lib_rs_old/lock.rs b/retired/nest_lib_rs_old/lock.rs new file mode 100644 index 0000000..02f488f --- /dev/null +++ b/retired/nest_lib_rs_old/lock.rs @@ -0,0 +1,99 @@ +use std::collections::HashSet; +use std::collections::hash_set::Iter; +use std::fs::OpenOptions; +use std::hash::Hash; +use std::io::Read; +use std::path::Path; +use std::sync::{Arc, Mutex}; + +use path::{PathHandled, PathHandler}; +use serde::{Deserialize, Serialize}; + +use crate::Error; + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct Lock { + #[serde(skip_deserializing, skip_serializing)] + ph: Option>>, + inner: HashSet, +} + +impl Lock +where + T: Lockable + Status + Deserialize<'de>, +{ + pub fn new(ph: Arc>, inner: HashSet) -> Self { + Self { + ph: Some(ph), + inner, + } + } + + pub fn load

(ph: Arc>, path: P) -> crate::Result + where + P: AsRef, + { + let mut path = path.as_ref().to_path_buf(); + if path.is_relative() { + path = path.canonicalize()?; + } + + let mut buf = Vec::new(); + OpenOptions::new() + .read(true) + .open(path)? + .read_to_end(&mut buf)?; + + let lock: Lock = toml::from_slice(buf.as_slice())?; + + Ok(lock) + } + + pub fn update(&mut self) -> crate::Result<()> { + let ph = self.ph.as_ref().ok_or(Error::MissingPathHandler)?.clone(); + + self.inner = self + .inner + .clone() + .into_iter() + .filter_map(|mut item| { + let item = item.with_path_handler(Arc::clone(&ph)); + + // If the class is up-to-date and no errors occurred during the check + if item.is_updated().is_ok_and(|b| b == true) { + Some(item.to_owned()) + } else { + None + } + }) + .collect(); + + Ok(()) + } + + pub fn set_path_handler(&mut self, ph: Arc>) { + self.ph = Some(ph); + } + + pub fn with_path_handler(&mut self, ph: Arc>) -> &mut Self { + self.ph = Some(ph); + self + } + + /// Iterates over the entries in `NestLock`. + pub fn iter(&self) -> Iter<'_, T> { + self.inner.iter() + } + + pub fn insert(&mut self, class: T) -> bool { + self.inner.insert(class) + } +} + +pub trait Lockable: Hash + Eq + Clone + PathHandled {} + +trait Status { + type Error; + + fn is_updated(&self) -> Result; +} diff --git a/retired/nest_lib_rs_old/meta.rs b/retired/nest_lib_rs_old/meta.rs new file mode 100644 index 0000000..bffe130 --- /dev/null +++ b/retired/nest_lib_rs_old/meta.rs @@ -0,0 +1,62 @@ +use std::fmt::Display; +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Meta { + name: String, + version: semver::Version, + #[serde(skip_serializing_if = ">::is_none")] + authors: Option>, + #[serde(skip_serializing_if = ">::is_none")] + repository: Option, + #[serde(skip_serializing_if = ">::is_none")] + license: Option, + #[serde(skip_serializing_if = ">::is_none")] + license_file: Option, +} + +impl Meta { + pub fn new(name: S) -> Self { + let mut meta = Self::default(); + meta.name = name.to_string(); + meta + } + + pub fn name(&self) -> String { + self.name.clone() + } +} + +impl Default for Meta { + fn default() -> Self { + Self { + name: Default::default(), + version: semver::Version::new(0, 1, 0), + authors: None, + repository: None, + license: None, + license_file: None, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] +pub enum License { + Mit, + Apache, +} + +impl Display for License { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + License::Mit => "MIT", + License::Apache => "Apache", + } + ) + } +} diff --git a/retired/nest_lib_rs_old/nest.rs b/retired/nest_lib_rs_old/nest.rs new file mode 100644 index 0000000..bc4255d --- /dev/null +++ b/retired/nest_lib_rs_old/nest.rs @@ -0,0 +1,130 @@ +use std::collections::HashSet; +use std::fs::{File, OpenOptions}; +use std::io::Read; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +use crate::Error; +use crate::dependency::Dependency; +use crate::meta::Meta; +use crate::package::Package; +use crate::workspace::Workspace; + +use path::{PathHandled, PathHandler}; +use pom::Pom; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct Nest { + pub workspace: Workspace, + pub meta: Meta, + #[serde(default, skip_serializing_if = "HashSet::is_empty")] + pub dependencies: HashSet, + #[serde(default, skip_serializing_if = "Pom::is_empty")] + pub pom: Pom, +} + +impl Nest { + pub fn new(name: S) -> Self { + Nest { + meta: Meta::new(name), + ..Default::default() + } + } +} + +impl TryFrom for Nest { + type Error = Error; + + fn try_from(value: File) -> Result { + let mut value = value; + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + + Ok(toml::from_str(buf.as_str())?) + } +} + +impl TryFrom for Nest { + type Error = Error; + + fn try_from(value: PathBuf) -> Result { + Nest::try_from(OpenOptions::new().read(true).open(value)?) + } +} + +// TODO: See if NestLock and PreyLock can be combined into one parent struct, +// but with different generics, and merely call upon a is_updated method set +// by the generics implementing a common IsUpdated trait. +// +// Not happening any time soon. An enum could get around the issue of being unable to +// implement Deserialize on a generic. + +#[derive(Debug, Default, Deserialize, Serialize)] +pub struct NestLock { + #[serde(skip_serializing, skip_deserializing)] + ph: Option>>, + pub packages: HashSet, +} + +impl NestLock { + /// Update, retaining all packages that still exist. + /// + /// Presently only supports packages under src/ + pub fn update(&mut self) -> crate::Result<()> { + let dir_src = self + .ph + .as_ref() + .ok_or(Error::MissingPathHandler)? + .try_lock()? + .dir_src(); + + self.packages = self + .packages + .clone() + .into_iter() + .filter_map(|package| { + let path = dir_src.join(package.name()); + + if path.exists() && path.is_dir() { + return Some(package); + } + + None + }) + .collect(); + + Ok(()) + } +} + +impl TryFrom for NestLock { + type Error = Error; + + fn try_from(value: File) -> Result { + let mut value = value; + let mut buf = String::new(); + + value.read_to_string(&mut buf)?; + Ok(toml::from_str(buf.as_str())?) + } +} + +impl TryFrom for NestLock { + type Error = Error; + + fn try_from(value: PathBuf) -> Result { + NestLock::try_from(OpenOptions::new().read(true).open(&value)?) + } +} + +impl PathHandled for NestLock { + fn set_path_handler(&mut self, ph: Arc>) { + self.ph = Some(ph); + } + + fn with_path_handler(&mut self, ph: Arc>) -> &mut Self { + self.ph = Some(ph); + self + } +} diff --git a/retired/nest_lib_rs_old/package.rs b/retired/nest_lib_rs_old/package.rs new file mode 100644 index 0000000..6ab2b6a --- /dev/null +++ b/retired/nest_lib_rs_old/package.rs @@ -0,0 +1,38 @@ +use std::{collections::HashSet, hash::Hash}; + +use serde::{Deserialize, Serialize}; + +use crate::dependency::Dependency; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +pub struct Package { + name: String, + version: semver::Version, + source: String, + checksum: String, + dependencies: HashSet, +} + +impl Package { + pub fn name(&self) -> String { + self.name.clone() + } +} + +impl Default for Package { + fn default() -> Self { + Self { + name: Default::default(), + version: semver::Version::new(0, 1, 0), + source: Default::default(), + checksum: Default::default(), + dependencies: Default::default(), + } + } +} + +impl Hash for Package { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} diff --git a/retired/nest_lib_rs_old/prelude.rs b/retired/nest_lib_rs_old/prelude.rs new file mode 100644 index 0000000..69d35f3 --- /dev/null +++ b/retired/nest_lib_rs_old/prelude.rs @@ -0,0 +1,10 @@ +#![allow(unused_imports)] + +pub use crate::class::Class; +pub use crate::dependency::Dependency; +pub use crate::meta::Meta; +pub use crate::nest::{Nest, NestLock}; +pub use crate::package::Package; +pub use crate::prey::{Prey, PreyLock}; +pub use crate::workspace::Workspace; +pub use crate::{F_NEST_LOCK, F_NEST_TOML, F_PREY_LOCK, F_PREY_TOML, FN_NEST, FN_PREY}; diff --git a/retired/nest_lib_rs_old/prey.rs b/retired/nest_lib_rs_old/prey.rs new file mode 100644 index 0000000..abaf8fb --- /dev/null +++ b/retired/nest_lib_rs_old/prey.rs @@ -0,0 +1,127 @@ +use std::collections::HashSet; +use std::collections::hash_set::Iter; +use std::fs::{File, OpenOptions}; +use std::io::Read; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +use path::{PathHandled, PathHandler}; +use serde::{Deserialize, Serialize}; + +use crate::Error; +use crate::class::Class; +use crate::meta::Meta; +use crate::package::Package; + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct Prey { + package: Package, + meta: Meta, +} + +impl Prey { + pub fn new(name: S) -> Self { + Prey { + package: (), + meta: (), + } + } +} + +impl TryFrom for Prey { + type Error = Error; + + fn try_from(value: File) -> Result { + let mut value = value; + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + + Ok(toml::from_str(buf.as_str())?) + } +} + +impl TryFrom for Prey { + type Error = Error; + + fn try_from(value: PathBuf) -> Result { + Prey::try_from(OpenOptions::new().read(true).open(value)?) + } +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct PreyLock { + #[serde(skip_deserializing, skip_serializing)] + ph: Option>>, + classes: HashSet, +} + +impl PreyLock { + pub fn new(ph: Arc>, classes: HashSet) -> Self { + Self { + ph: Some(ph), + classes, + } + } + + pub fn update(&mut self) -> crate::Result<()> { + let ph = self.ph.as_ref().ok_or(Error::MissingPathHandler)?.clone(); + + self.classes = self + .classes + .clone() + .into_iter() + .filter_map(|mut class| { + let class = class.with_path_handler(Arc::clone(&ph)); + + // If the class is up-to-date and no errors occurred during the check + if class.is_updated().is_ok_and(|b| b == true) { + Some(class.to_owned()) + } else { + None + } + }) + .collect(); + + Ok(()) + } + + /// Iterates over the entries in `PreyLock`. + pub fn iter(&self) -> Iter<'_, Class> { + self.classes.iter() + } + + pub fn insert(&mut self, class: Class) -> bool { + self.classes.insert(class) + } +} + +impl TryFrom for PreyLock { + type Error = Error; + + fn try_from(value: File) -> Result { + let mut value = value; + let mut buf = String::new(); + value.read_to_string(&mut buf)?; + + Ok(toml::from_str(buf.as_str())?) + } +} + +impl TryFrom for PreyLock { + type Error = Error; + + fn try_from(value: PathBuf) -> Result { + PreyLock::try_from(OpenOptions::new().read(true).open(value)?) + } +} + +impl PathHandled for PreyLock { + fn set_path_handler(&mut self, ph: Arc>) { + self.ph = Some(ph); + } + + fn with_path_handler(&mut self, ph: Arc>) -> &mut Self { + self.ph = Some(ph); + self + } +} diff --git a/retired/nest_lib_rs_old/workspace.rs b/retired/nest_lib_rs_old/workspace.rs new file mode 100644 index 0000000..cd788aa --- /dev/null +++ b/retired/nest_lib_rs_old/workspace.rs @@ -0,0 +1,8 @@ +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct Workspace { + pub default_package: PathBuf, +} diff --git a/src/nest.rs b/retired/old_nest.rs similarity index 55% rename from src/nest.rs rename to retired/old_nest.rs index 1a87251..2361388 100644 --- a/src/nest.rs +++ b/retired/old_nest.rs @@ -1,11 +1,14 @@ -use std::collections::HashMap; +#![allow(dead_code)] + +use std::collections::HashSet; use std::fs::{File, OpenOptions}; +use std::hash::{self, Hash}; use std::io::Read; -use std::path::PathBuf; +use std::path::{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 crate::{DIR_SRC, DIR_TARGET, F_NEST_LOCK, F_NEST_TOML, PROJECT_ROOT}; use anyhow::Context; use semver::Version; @@ -46,6 +49,8 @@ impl TryFrom for Nest { } } +// Rename to Prey +// Mark as deprecated soon. #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Package { pub name: String, @@ -62,23 +67,38 @@ impl Default for Package { } #[derive(Debug, Default, Deserialize, Serialize)] -pub struct NestLock(pub HashMap); +pub struct NestLock { + pub classes: HashSet, +} impl NestLock { pub fn load() -> anyhow::Result { - NestLock::try_from(F_NEST_LOCK.clone()) + 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.0 = self - .0 + self.classes = self + .classes .clone() .into_iter() - .filter_map(|(path, class)| { - if path.exists() && path.is_file() { - return Some((path, class)); + .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 @@ -113,51 +133,64 @@ impl TryFrom for NestLock { } } -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] pub struct Class { - pub name: PathBuf, - pub checksum: String, - pub test: bool, + 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 { - // 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()) + // Still doesn't handle inter-dependency checks. + + DIR_TARGET + .join(self.subpath()) .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) + && 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(&self, state: &mut H) { + self.path.hash(state); } } impl TryFrom for Class { type Error = anyhow::Error; - fn try_from(value: PathBuf) -> Result { + fn try_from(mut value: PathBuf) -> Result { + if value.is_relative() { + value = value + .canonicalize() + .context("Failed to canonicalize path")?; + } + Ok(Self { - name: PathBuf::from( - value - .file_name() - .context("Failed to get file name from PathBuf for class")?, + 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)?, - test: value.is_relative() && value.starts_with(DIR_TEST.as_path()), }) } } diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index fcb1cdc..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::sync::LazyLock; - -use clap::{ArgAction, Parser, Subcommand}; - -pub static CONFIG: LazyLock = LazyLock::new(|| Args::parse()); - -#[derive(Debug, Parser)] -#[clap(author, version)] -#[command(help_template = "{author-section}\n{usage-heading} {usage}\n\n{all-args}")] -pub struct Args { - #[command(subcommand)] - pub command: Command, -} - -#[derive(Debug, Subcommand)] -pub enum Command { - /// Create a new raven project - New { project_name: String }, - /// Create a new raven project in an existing directory - Init, - /// Compile the current project - Build, - /// Run the current project - #[command(arg_required_else_help = true)] - Run { - #[arg(required = true)] - entry_point: String, - - #[clap(flatten)] - assertions: Assertions, - }, - /// !!! BORKED !!! Run the tests - Test { - #[clap(flatten)] - assertions: Assertions, - }, - /// Remove the target directory and caching - Clean, -} - -impl Command { - pub fn depends_on_nest(&self) -> bool { - match self { - Self::Init | Self::New { .. } => false, - _ => true, - } - } -} - -#[derive(Debug, clap::Args)] -pub struct Assertions { - /// Disable assertions. - #[arg(short, long = "no-assert", action = ArgAction::SetFalse)] - disable_assert: bool, -} - -impl Into for &Assertions { - fn into(self) -> bool { - !self.disable_assert - } -} diff --git a/src/env.rs b/src/env.rs deleted file mode 100644 index 42de9e6..0000000 --- a/src/env.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::io; -use std::path::Path; -use std::str::FromStr; -use std::sync::LazyLock; - -use crate::java::{JAVA_VM, VMFlag}; - -use anyhow::Context; - -static JAVA_VERSION: LazyLock = LazyLock::new(|| { - crate::io::run_process(&[JAVA_VM, VMFlag::Version.to_string().as_str()]) - .expect("Failed to call java") - .0 - .expect("Failed to read java version from stdout") -}); - -pub fn get_javac_ver() -> anyhow::Result { - /* - * $ java --version - * openjdk 21.0.9 2025-10-21 - * OpenJDK Runtime Environment (build 21.0.9+10) - * OpenJDK 64-Bit Server VM (build 21.0.9+10, mixed mode, sharing) - */ - - semver::Version::from_str( - JAVA_VERSION - .lines() - .nth(0) - .context("stdout from Java is all f-cked up")? - .split_ascii_whitespace() - .nth(1) - .context("Java version position is all f-cked up")?, - ) - .context("Failed to produce a version struct from string") -} - -pub fn set_cwd>(path: P) -> io::Result<()> { - let mut cwd = crate::PROJECT_ROOT.clone(); - cwd.push(path.as_ref()); - std::env::set_current_dir(cwd.as_path()) -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index ed58804..0000000 --- a/src/main.rs +++ /dev/null @@ -1,272 +0,0 @@ -mod cli; -mod env; -mod fs; -mod io; -mod java; -mod nest; - -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use std::sync::LazyLock; - -use cli::{CONFIG, Command}; -use java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; -use nest::{Class, NEST, NestLock}; - -use anyhow::Context; -use bytesize::ByteSize; - -pub static PROJECT_ROOT: LazyLock = LazyLock::new(|| { - // Start from CWD - let cwd = std::env::current_dir().expect("Failed to get current working directory"); - let mut probe = cwd.clone(); - - while !probe.join(F_NEST_TOML.as_path()).exists() { - if !probe.pop() { - // This is easier than having a Result everywhere. For now. - panic!( - "No {} found in current directory or any ancestor. (cwd: {})", - F_NEST_TOML.display(), - cwd.display() - ) - } - } - - probe -}); - -const DIR_TARGET: LazyLock = LazyLock::new(|| PROJECT_ROOT.join("target/")); -const DIR_SRC: LazyLock = LazyLock::new(|| PROJECT_ROOT.join("src/")); -const DIR_MAIN: LazyLock = LazyLock::new(|| DIR_SRC.join("main/")); -const DIR_TEST: LazyLock = LazyLock::new(|| DIR_SRC.join("test/")); - -const F_NEST_TOML: LazyLock = LazyLock::new(|| PathBuf::from("Nest.toml")); -const F_NEST_LOCK: LazyLock = LazyLock::new(|| PathBuf::from("Nest.lock")); - -fn main() -> anyhow::Result<()> { - // Ensure that Nest.toml exists, if the requested command depends upon it. - if CONFIG.command.depends_on_nest() && NEST.is_err() { - println!("No Nest.toml found in project directory"); - println!("Aborting..."); - return Ok(()); - } - - match &CONFIG.command { - Command::Init => init()?, - Command::New { project_name } => { - new(project_name.to_owned())?; - init()?; - } - Command::Build => { - build()?; - } - Command::Run { - entry_point, - assertions, - } => { - build()?; - run(entry_point, assertions.into())?; - } - Command::Test { assertions } => { - test(assertions.into())?; - } - Command::Clean => clean(), - } - - println!("Done."); - - Ok(()) -} - -fn init() -> anyhow::Result<()> { - let cwd = std::env::current_dir()?; - - let is_empty = std::fs::read_dir(cwd.as_path()).is_ok_and(|tree| tree.count() == 0); - - let project_name = cwd - .file_name() - .context("Invalid directory name")? - .to_str() - .context("Unable to convert OsStr to str")? - .to_owned(); - - // ORDER MATTERS. THIS MUST COME FIRST. - // Make config file. - if let Result::Ok(mut f) = OpenOptions::new() - .write(true) - .create_new(true) - .open(F_NEST_TOML.as_path()) - { - f.write_all( - toml::to_string_pretty(&nest::Nest { - package: nest::Package { - name: project_name.to_owned(), - ..Default::default() - }, - })? - .as_bytes(), - )?; - } - - // Make .java-version - if let Result::Ok(mut f) = OpenOptions::new() - .write(true) - .create_new(true) - .open(PathBuf::from(".java-version")) - { - f.write_all( - { - let mut version = crate::env::get_javac_ver()?.major.to_string(); - version.push('\n'); - version - } - .as_bytes(), - )?; - } - - // Make src, target, tests - for dir in [DIR_SRC, DIR_MAIN, DIR_TARGET, DIR_TEST] { - std::fs::create_dir_all(dir.clone())?; - } - - // Make src/main/Main.java - if let Result::Ok(mut f) = OpenOptions::new().write(true).create_new(is_empty).open( - DIR_MAIN - .clone() - .join("Main") - .with_extension(JAVA_EXT_SOURCE), - ) { - f.write_all(include_bytes!("../assets/src/main/Main.java"))?; - } - - // Make src/test/MainTest.java - if let Result::Ok(mut f) = OpenOptions::new().write(true).create_new(is_empty).open( - DIR_TEST - .clone() - .join("MainTest") - .with_extension(JAVA_EXT_SOURCE), - ) { - f.write_all(include_bytes!("../assets/src/test/MainTest.java"))?; - } - - // git init . - crate::io::run_process(&["git", "init", "."])?; - - // Append to .gitignore - if let Result::Ok(mut f) = OpenOptions::new() - .append(true) - .create(true) - .read(true) - .open(".gitignore") - { - let mut buf = String::new(); - f.read_to_string(&mut buf)?; - - for ignored in [ - format!("{}/", DIR_TARGET.file_name().unwrap().display()), - format!("*.{}", JAVA_EXT_CLASS), - ] { - if !buf.contains(&ignored) { - f.write(format!("{}\n", ignored).as_bytes())?; - } - } - } - - Ok(()) -} - -fn new(project_name: String) -> anyhow::Result<()> { - let cwd = std::env::current_dir()?.join(project_name); - - std::fs::create_dir(&cwd)?; - std::env::set_current_dir(&cwd)?; - - Ok(()) -} - -fn build() -> anyhow::Result<()> { - let mut targets: Vec = crate::fs::expand_files(DIR_SRC.as_path())? - .into_iter() - .filter(|f| { - f.extension() - .is_some_and(|ext| ext.to_str().is_some_and(|ext| ext == JAVA_EXT_SOURCE)) - }) - .collect(); - let mut nest_lock = NestLock::load().unwrap_or_default(); - - nest_lock.update(); - - let mut retained_targets = vec![]; - for path in targets.into_iter() { - if let Option::Some((_path, class)) = nest_lock.0.get_key_value(&path) - && class.is_updated() - { - continue; - } - - retained_targets.push(path); - } - - targets = retained_targets; - - let javac = java::CompilerBuilder::new() - .class_path(DIR_TARGET.as_path()) - .destination(DIR_TARGET.as_path()) - .build(); - - for target in targets { - println!("Compiling {}", target.display()); - if javac.clone().compile(dbg!(target.as_path())).is_ok() - && let Result::Ok(class) = Class::try_from(target.clone()) - { - nest_lock.0.insert(target, class); - } - } - - OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(F_NEST_LOCK.as_path())? - .write_all(toml::to_string_pretty(&nest_lock)?.as_bytes()) - .with_context(|| format!("Failed to write {}", F_NEST_LOCK.display())) -} - -fn run>( - entry_point: P, - assertions: bool, -) -> anyhow::Result<(Option, Option)> { - // JRE pathing will be messed up without this. - crate::env::set_cwd(DIR_TARGET.as_path())?; - - java::JVMBuilder::new(DIR_TARGET.as_path()) - .assertions(assertions) - .monitor(true) - .build() - .run(entry_point) -} - -fn test(assertions: bool) -> anyhow::Result<(Option, Option)> { - java::CompilerBuilder::new() - .class_path(DIR_TARGET.as_path()) - .destination(DIR_TARGET.as_path()) - .build() - .compile(DIR_TEST.as_path())?; - - // Change cwd to avoid Java pathing issues. - crate::env::set_cwd(DIR_TARGET.as_path())?; - - java::JVMBuilder::new(DIR_TARGET.as_path()) - .assertions(assertions) - .ram_min(ByteSize::mib(128)) - .ram_max(ByteSize::mib(512)) - .monitor(true) - .build() - .run(DIR_TARGET.as_path()) -} - -fn clean() { - let _ = std::fs::remove_file(PROJECT_ROOT.join(F_NEST_LOCK.as_path())); - let _ = std::fs::remove_dir_all(DIR_TARGET.join("/*").as_path()); -} diff --git a/templates/Nest.toml b/templates/Nest.toml deleted file mode 100644 index b331834..0000000 --- a/templates/Nest.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "demo" -version = "0.1.0" -#authors = ["Olivia Brooks", "Adrian Long"] -#repository = "https://gitea.cutieguwu.ca/Cutieguwu/raven" -#license = "MIT" - -[dependencies] -anyhow = "1.0" -bytesize = "2.3" -pathsub = "0.1.1" -ron = "0.12" -sha256 = "1.6" -subprocess = "0.2" -toml = "0.9" - -[dependencies.clap] -version = "4.5" -#features = ["cargo", "derive"] diff --git a/templates/Prey.toml b/templates/Prey.toml deleted file mode 100644 index 1399585..0000000 --- a/templates/Prey.toml +++ /dev/null @@ -1,5 +0,0 @@ -[package] -name = "main" -version = "0.1.0" -is_test = false -entry_point = "Main" diff --git a/templates/demo/Nest.toml b/templates/demo/Nest.toml new file mode 100644 index 0000000..f52da64 --- /dev/null +++ b/templates/demo/Nest.toml @@ -0,0 +1,26 @@ +[workspace] +default_package = "main" # PathBuf || String ? + +[meta] +name = "demo" # String +version = "0.1.0" # semver::Version +authors = ["Olivia Brooks", "Adrian Long"] # Option> +repository = "https://gitea.cutieguwu.ca/Cutieguwu/raven" # Option struct? +license = "MIT" # Option +license-file = "LICENSE" + +[dependencies] +anyhow = "1.0" # semver::VersionReq +bytesize = "2.3" +pathsub = "0.1.1" +ron = "0.12" +sha256 = "1.6" +subprocess = "0.2" +toml = "0.9" + +[dependencies.clap] +version = "4.5" +#features = ["cargo", "derive"] # Is this a concept in POM? + +[pom] # Only POM-specific data +model_version = "4.0.0" # semver::Version diff --git a/templates/Prey.lock b/templates/demo/src/main/Prey.lock similarity index 84% rename from templates/Prey.lock rename to templates/demo/src/main/Prey.lock index b76564a..25de180 100644 --- a/templates/Prey.lock +++ b/templates/demo/src/main/Prey.lock @@ -1,5 +1,5 @@ [[classes]] -path = "Main" +path = "Main" # PathBuf to .class checksum = "24dffb40073ff21878cf879bf8c67d189ad600115f9a8ecead11a3ca6c086767" [[classes]] diff --git a/templates/demo/src/main/Prey.toml b/templates/demo/src/main/Prey.toml new file mode 100644 index 0000000..8911e5f --- /dev/null +++ b/templates/demo/src/main/Prey.toml @@ -0,0 +1,6 @@ +[package] +entry_point = "Main" # PathBuf + +[meta] +name = "main" +version = "0.1.0" diff --git a/templates/imports.rs b/templates/imports.rs deleted file mode 100644 index 4e9db5f..0000000 --- a/templates/imports.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Acknowledge sister/child -mod module; - -// std -use std::*; - -// sister/child -use module1::*; - -// parent -use super::*; - -// ancestor of parent -use crate::*; - -// external -use external::*; diff --git a/templates/pom.xml b/templates/pom.xml new file mode 100644 index 0000000..7fb1e6b --- /dev/null +++ b/templates/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + com.viffx + GameEngine + 1.0-SNAPSHOT + + + 21 + 21 + 3.4.0 + natives-windows + + + + + + org.lwjgl + lwjgl-bom + ${lwjgl.version} + import + pom + + + + + + + org.lwjgl + lwjgl + + + org.lwjgl + lwjgl-assimp + + + org.lwjgl + lwjgl-glfw + + + org.lwjgl + lwjgl-openal + + + org.lwjgl + lwjgl-stb + + + org.lwjgl + lwjgl-vulkan + + + org.lwjgl + lwjgl + ${lwjgl.natives} + + + org.lwjgl + lwjgl-assimp + ${lwjgl.natives} + + + org.lwjgl + lwjgl-glfw + ${lwjgl.natives} + + + org.lwjgl + lwjgl-openal + ${lwjgl.natives} + + + org.lwjgl + lwjgl-stb + ${lwjgl.natives} + + +