From 7020cfb8b65793d871b23a76e111f8a652eead72 Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:37:40 -0500 Subject: [PATCH 01/22] Update templates (including future ones) --- templates/Nest.toml | 19 +++++++++++++++++++ templates/Prey.lock | 7 +++++++ templates/Prey.toml | 5 +++++ 3 files changed, 31 insertions(+) create mode 100644 templates/Nest.toml create mode 100644 templates/Prey.lock create mode 100644 templates/Prey.toml diff --git a/templates/Nest.toml b/templates/Nest.toml new file mode 100644 index 0000000..b331834 --- /dev/null +++ b/templates/Nest.toml @@ -0,0 +1,19 @@ +[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.lock b/templates/Prey.lock new file mode 100644 index 0000000..b76564a --- /dev/null +++ b/templates/Prey.lock @@ -0,0 +1,7 @@ +[[classes]] +path = "Main" +checksum = "24dffb40073ff21878cf879bf8c67d189ad600115f9a8ecead11a3ca6c086767" + +[[classes]] +path = "Cli" +checksum = "24dffb40073ff21878cf879bf8c67d189ad600115f9a8ecead11a3ca6c086767" diff --git a/templates/Prey.toml b/templates/Prey.toml new file mode 100644 index 0000000..1399585 --- /dev/null +++ b/templates/Prey.toml @@ -0,0 +1,5 @@ +[package] +name = "main" +version = "0.1.0" +is_test = false +entry_point = "Main" -- 2.49.1 From de7c0e6409ca76884a4c270d14f473823fde4b28 Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:38:22 -0500 Subject: [PATCH 02/22] Add pathsub; Add a bunch of metadata. --- Cargo.toml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fa363ba..c3f6124 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,18 +2,25 @@ name = "raven" version = "0.1.0" edition = "2024" -authors = ["Olivia Brooks", "Adrian Long"] -repository = "https://gitea.cutieguwu.ca/Cutieguwu/raven" 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 [dependencies] anyhow = "1.0" bytesize = "2.3" -ron = "0.12" +# hard-xml = "1.41" +pathsub = "0.1.1" +ron = "0.12.0" sha256 = "1.6" -subprocess = "0.2" -toml = "0.9" +subprocess = "0.2.13" +toml = "0.9.11" [dependencies.clap] version = "4.5" @@ -25,4 +32,4 @@ features = ["serde"] [dependencies.serde] version = "1.0" -features =["derive"] +features = ["derive"] -- 2.49.1 From dda863e512fe9d1785822218aaf7bb7601a28326 Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:38:39 -0500 Subject: [PATCH 03/22] Make us Zed users happy. --- .zed/settings.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .zed/settings.json diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 0000000..b1eee26 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,9 @@ +// Folder-specific settings +// +// For a full list of overridable settings, and general information on folder-specific settings, +// see the documentation: https://zed.dev/docs/configuring-zed#settings-files +{ + "file_types": { + "TOML": ["lock"], + }, +} -- 2.49.1 From e41d4bcd767712cff00f1714e18514a2f4326e39 Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Sun, 15 Feb 2026 09:36:04 -0500 Subject: [PATCH 04/22] Most of the refactor. Need to switch machines. --- .zed/debug.json | 18 + Cargo.lock | 280 ++++++-- Cargo.toml | 52 +- crates/cli/Cargo.toml | 15 + crates/cli/src/lib.rs | 153 ++++ crates/core/Cargo.toml | 29 + .../src/main => crates/core/assets}/Main.java | 0 .../test => crates/core/assets}/MainTest.java | 0 crates/core/src/class.rs | 10 + crates/core/src/dependency.rs | 43 ++ crates/core/src/error.rs | 25 + crates/core/src/lib.rs | 13 + crates/core/src/meta.rs | 40 ++ crates/core/src/nest.rs | 105 +++ crates/core/src/package.rs | 56 ++ crates/core/src/prelude.rs | 9 + crates/core/src/prey.rs | 78 ++ crates/core/src/workspace.rs | 272 +++++++ crates/fs/Cargo.toml | 14 + src/fs.rs => crates/fs/src/lib.rs | 5 +- crates/io/Cargo.toml | 15 + crates/io/src/error.rs | 11 + src/io.rs => crates/io/src/lib.rs | 12 +- crates/java/Cargo.toml | 21 + crates/java/src/compiler.rs | 80 +++ crates/java/src/error.rs | 19 + crates/java/src/lib.rs | 49 ++ src/java.rs => crates/java/src/runtime.rs | 110 +-- crates/path/Cargo.toml | 14 + crates/path/src/lib.rs | 151 ++++ crates/pom/Cargo.toml | 18 + crates/pom/src/error.rs | 12 + crates/pom/src/lib.rs | 25 + crates/pom/src/xml.rs | 118 +++ crates/raven/Cargo.lock | 671 ++++++++++++++++++ crates/raven/Cargo.toml | 24 + crates/raven/src/env.rs | 19 + crates/raven/src/main.rs | 98 +++ crates/raven/src/manager.rs | 11 + retired/nest_lib_rs_old/class.rs | 114 +++ retired/nest_lib_rs_old/dependency.rs | 7 + retired/nest_lib_rs_old/error.rs | 35 + retired/nest_lib_rs_old/lib.rs | 45 ++ retired/nest_lib_rs_old/lock.rs | 99 +++ retired/nest_lib_rs_old/meta.rs | 62 ++ retired/nest_lib_rs_old/nest.rs | 130 ++++ retired/nest_lib_rs_old/package.rs | 38 + retired/nest_lib_rs_old/prelude.rs | 10 + retired/nest_lib_rs_old/prey.rs | 127 ++++ retired/nest_lib_rs_old/workspace.rs | 8 + src/nest.rs => retired/old_nest.rs | 105 ++- src/cli.rs | 61 -- src/env.rs | 41 -- src/main.rs | 272 ------- templates/Nest.toml | 19 - templates/Prey.toml | 5 - templates/demo/Nest.toml | 26 + templates/{ => demo/src/main}/Prey.lock | 2 +- templates/demo/src/main/Prey.toml | 6 + templates/imports.rs | 17 - templates/pom.xml | 84 +++ 61 files changed, 3390 insertions(+), 618 deletions(-) create mode 100644 .zed/debug.json create mode 100644 crates/cli/Cargo.toml create mode 100644 crates/cli/src/lib.rs create mode 100644 crates/core/Cargo.toml rename {assets/src/main => crates/core/assets}/Main.java (100%) rename {assets/src/test => crates/core/assets}/MainTest.java (100%) create mode 100644 crates/core/src/class.rs create mode 100644 crates/core/src/dependency.rs create mode 100644 crates/core/src/error.rs create mode 100644 crates/core/src/lib.rs create mode 100644 crates/core/src/meta.rs create mode 100644 crates/core/src/nest.rs create mode 100644 crates/core/src/package.rs create mode 100644 crates/core/src/prelude.rs create mode 100644 crates/core/src/prey.rs create mode 100644 crates/core/src/workspace.rs create mode 100644 crates/fs/Cargo.toml rename src/fs.rs => crates/fs/src/lib.rs (74%) create mode 100644 crates/io/Cargo.toml create mode 100644 crates/io/src/error.rs rename src/io.rs => crates/io/src/lib.rs (65%) create mode 100644 crates/java/Cargo.toml create mode 100644 crates/java/src/compiler.rs create mode 100644 crates/java/src/error.rs create mode 100644 crates/java/src/lib.rs rename src/java.rs => crates/java/src/runtime.rs (54%) create mode 100644 crates/path/Cargo.toml create mode 100644 crates/path/src/lib.rs create mode 100644 crates/pom/Cargo.toml create mode 100644 crates/pom/src/error.rs create mode 100644 crates/pom/src/lib.rs create mode 100644 crates/pom/src/xml.rs create mode 100644 crates/raven/Cargo.lock create mode 100644 crates/raven/Cargo.toml create mode 100644 crates/raven/src/env.rs create mode 100644 crates/raven/src/main.rs create mode 100644 crates/raven/src/manager.rs create mode 100644 retired/nest_lib_rs_old/class.rs create mode 100644 retired/nest_lib_rs_old/dependency.rs create mode 100644 retired/nest_lib_rs_old/error.rs create mode 100644 retired/nest_lib_rs_old/lib.rs create mode 100644 retired/nest_lib_rs_old/lock.rs create mode 100644 retired/nest_lib_rs_old/meta.rs create mode 100644 retired/nest_lib_rs_old/nest.rs create mode 100644 retired/nest_lib_rs_old/package.rs create mode 100644 retired/nest_lib_rs_old/prelude.rs create mode 100644 retired/nest_lib_rs_old/prey.rs create mode 100644 retired/nest_lib_rs_old/workspace.rs rename src/nest.rs => retired/old_nest.rs (55%) delete mode 100644 src/cli.rs delete mode 100644 src/env.rs delete mode 100644 src/main.rs delete mode 100644 templates/Nest.toml delete mode 100644 templates/Prey.toml create mode 100644 templates/demo/Nest.toml rename templates/{ => demo/src/main}/Prey.lock (84%) create mode 100644 templates/demo/src/main/Prey.toml delete mode 100644 templates/imports.rs create mode 100644 templates/pom.xml 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} + + + -- 2.49.1 From a9fb52d8d7733860a7191614f099d7ed7546b05f Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 09:50:36 -0500 Subject: [PATCH 05/22] Bump version numbers. --- Cargo.lock | 8 ++++---- crates/cli/Cargo.toml | 2 +- crates/core/src/workspace.rs | 5 ++--- crates/io/Cargo.toml | 2 +- crates/java/Cargo.toml | 2 +- crates/raven/Cargo.toml | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c12d1cd..1ee2f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,7 +144,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "clap", ] @@ -330,7 +330,7 @@ dependencies = [ [[package]] name = "io" -version = "0.1.0" +version = "0.2.0" dependencies = [ "derive_more", "subprocess", @@ -344,7 +344,7 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "java" -version = "0.1.0" +version = "0.2.0" dependencies = [ "bytesize", "derive_more", @@ -433,7 +433,7 @@ dependencies = [ [[package]] name = "raven" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", "bytesize", diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 93aed44..1960a8c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cli" -version = "0.1.0" +version = "0.2.0" edition.workspace = true license.workspace = true diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 9fc5885..7923841 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -3,13 +3,12 @@ use std::fs::{OpenOptions, read_dir}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; -use fs::{self, expand_files}; +use fs::expand_files; use io::run_process; -use java::{self, JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; +use java::{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; diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml index f849c5e..e87e5e8 100644 --- a/crates/io/Cargo.toml +++ b/crates/io/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "io" -version = "0.1.0" +version = "0.2.0" edition.workspace = true license.workspace = true diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml index 7d5a326..66e88a7 100644 --- a/crates/java/Cargo.toml +++ b/crates/java/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "java" -version = "0.1.0" +version = "0.2.0" edition.workspace = true license.workspace = true diff --git a/crates/raven/Cargo.toml b/crates/raven/Cargo.toml index 32d0f6c..ad08a98 100644 --- a/crates/raven/Cargo.toml +++ b/crates/raven/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "raven" -version = "0.1.0" +version = "0.2.0" edition.workspace = true license.workspace = true -- 2.49.1 From 0fad1b74bc776bf6270410d9a7b4b17c12cbedeb Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 12:25:03 -0500 Subject: [PATCH 06/22] Try to work on build some more. --- crates/core/src/class.rs | 25 +++++++++++++++++++++++++ crates/core/src/dependency.rs | 11 +++++++++-- crates/core/src/package.rs | 34 ++++++++++++++++++++++++++++++++-- crates/core/src/prey.rs | 33 ++++++++++++++++++++++++++++++--- crates/core/src/workspace.rs | 18 ++++++++++++++++++ 5 files changed, 114 insertions(+), 7 deletions(-) diff --git a/crates/core/src/class.rs b/crates/core/src/class.rs index 7a486ba..c26de32 100644 --- a/crates/core/src/class.rs +++ b/crates/core/src/class.rs @@ -8,3 +8,28 @@ pub struct Class { pub path: PathBuf, pub checksum: String, } + +impl Class { + pub fn is_updated(&self) -> crate::Result { + // If the path is local and that file has not been updated. + Ok(self.checksum == sha256::try_digest(self.path.clone())?) + } + + pub fn update(&mut self) -> crate::Result<()> { + self.checksum = sha256::try_digest(self.path.clone())?; + Ok(()) + } +} + +// TODO: Make it clearer that this is for general files, +// not nests. +impl TryFrom for Class { + type Error = crate::Error; + + fn try_from(value: PathBuf) -> Result { + Ok(Self { + path: value.clone(), + checksum: sha256::try_digest(value)?, + }) + } +} diff --git a/crates/core/src/dependency.rs b/crates/core/src/dependency.rs index 190972a..a18223b 100644 --- a/crates/core/src/dependency.rs +++ b/crates/core/src/dependency.rs @@ -7,7 +7,8 @@ use crate::package::PackageHandler; #[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Dependency { name: String, - version: Version, + #[serde(skip_serializing_if = ">::is_none")] + version: Option, pub checksum: String, #[serde(skip_serializing_if = ">::is_none")] source: Option, // Path / URL @@ -24,13 +25,19 @@ impl Dependency { // TODO: Convert from reverse domain name to path. return self.name.clone(); } + + pub fn is_updated(&self) -> crate::Result { + // If the path is local and that file has not been updated. + Ok(self.source.as_ref().is_some_and(|path| is_url(path)) + && self.checksum == sha256::try_digest(self.source.as_ref().unwrap())?) + } } impl From for Dependency { fn from(value: PackageHandler) -> Self { Dependency { name: value.name(), - version: value.version(), + version: Some(value.version()), checksum: String::new(), source: None, } diff --git a/crates/core/src/package.rs b/crates/core/src/package.rs index 97506ff..6debff9 100644 --- a/crates/core/src/package.rs +++ b/crates/core/src/package.rs @@ -1,8 +1,10 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; +use fs::expand_files; use serde::{Deserialize, Serialize}; +use crate::class::Class; use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey, PreyLock}; /// Hashing is only based off the Prey. @@ -15,6 +17,8 @@ pub struct PackageHandler { } impl PackageHandler { + const DIR_JAVA: &str = "java/"; + pub fn new>(package_root: P, target_dir: P) -> crate::Result { let package_root = package_root.as_ref().to_path_buf(); @@ -26,8 +30,6 @@ impl PackageHandler { }) } - pub fn update_class_cache(&self) {} - pub fn entry_point(&self) -> PathBuf { self.prey.entry_point() } @@ -39,6 +41,34 @@ impl PackageHandler { pub fn version(&self) -> semver::Version { self.prey.version() } + + pub fn get_update_targets(&mut self) -> crate::Result> { + let mut targets = vec![]; + + if self.prey_lock.is_none() { + // Try to pass a reference to the class so that there's mutability of the object + // available at the workspace level instead of parsing all the way down the + // tree. How I do this, idk. My brain is friend from a few days of JS. + + self.prey_lock = Some(PreyLock::from(expand_files(Self::DIR_JAVA)?)); + return Ok(self + .prey_lock + .clone() + .unwrap() + .classes + .iter() + .map(|mut *class| &mut class) + .collect()); + } + + for mut tracked in self.prey_lock.unwrap().classes { + if !tracked.is_updated()? { + targets.push(&mut tracked); + } + } + + Ok(targets) + } } impl Hash for PackageHandler { diff --git a/crates/core/src/prey.rs b/crates/core/src/prey.rs index c11b71d..afc83be 100644 --- a/crates/core/src/prey.rs +++ b/crates/core/src/prey.rs @@ -1,13 +1,14 @@ use std::collections::HashSet; use std::fs::{File, OpenOptions}; use std::io::Read; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use crate::class::Class; use crate::meta::Meta; use crate::package::Package; +use crate::prelude::Dependency; pub const F_PREY_TOML: &str = "Prey.toml"; pub const F_PREY_LOCK: &str = "Prey.lock"; @@ -53,11 +54,19 @@ impl TryFrom for Prey { } /// Data struct -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)] pub struct PreyLock { - classes: HashSet, + pub classes: HashSet, } +impl PreyLock { + pub fn with_class(&mut self, class: Class) -> &mut Self { + self.classes.insert(class); + self + } +} + +/// Load the PreyLock from Prey.lock file. impl TryFrom for PreyLock { type Error = crate::Error; @@ -76,3 +85,21 @@ impl TryFrom for PreyLock { Ok(toml::from_str(buf.as_str())?) } } + +impl From> for PreyLock { + fn from(value: Vec) -> Self { + let mut lock = Self::default(); + lock.classes = value + .iter() + .filter_map(|f| { + let dep = Class::try_from(f.to_owned()); + if dep.is_ok() { + Some(dep.unwrap()) + } else { + None + } + }) + .collect(); + lock + } +} diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 7923841..6d34dd3 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -139,6 +139,24 @@ impl WorkspaceHandler { // This is the naive build pub fn build(&mut self) -> crate::Result<()> { + let mut targets = vec![]; + + for (_name, mut handler) in self.packages.clone() { + targets.append(&mut handler.get_update_targets()?); + } + + let compiler = java::compiler::CompilerBuilder::new() + .class_path(Self::DIR_TARGET) + .class_path(Self::DIR_TARGET) + .build(); + + for target in targets { + // Possibly come up with a source file handler for this? + if let Ok(_) = compiler.clone().compile(target) { + // No, this does not run O(1) + } + } + Ok(()) } -- 2.49.1 From 79629391c512ac9b53f9b7a3ad0b6db23eeef0fb Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 17:39:48 -0500 Subject: [PATCH 07/22] I think I finished it... --- Cargo.lock | 28 ------ Cargo.toml | 2 - crates/cli/Cargo.toml | 1 - crates/cli/src/lib.rs | 4 +- crates/core/Cargo.toml | 1 - crates/core/src/dependency.rs | 2 +- crates/core/src/error.rs | 2 +- crates/core/src/lib.rs | 2 - crates/core/src/nest.rs | 7 +- crates/core/src/package.rs | 42 ++++----- crates/core/src/prey.rs | 17 +++- crates/core/src/workspace.rs | 148 +++++++++++++++++++++--------- crates/fs/Cargo.toml | 1 - crates/io/Cargo.toml | 1 - crates/io/src/error.rs | 2 +- crates/java/Cargo.toml | 1 - crates/java/src/error.rs | 2 +- crates/path/Cargo.toml | 14 --- crates/path/src/lib.rs | 151 ------------------------------- crates/pom/Cargo.toml | 1 - crates/pom/src/error.rs | 2 +- crates/raven/Cargo.toml | 2 - crates/raven/src/env.rs | 19 ---- crates/raven/src/main.rs | 100 +++++--------------- crates/raven/src/manager.rs | 11 --- demo/.java-version | 1 + demo/Nest.toml | 8 ++ demo/src/main/Prey.toml | 6 ++ demo/src/main/java/Main.java | 10 ++ demo/src/test/Prey.toml | 6 ++ demo/src/test/java/MainTest.java | 10 ++ demo/target/Main.class | Bin 0 -> 471 bytes demo/target/MainTest.class | Bin 0 -> 631 bytes 33 files changed, 215 insertions(+), 389 deletions(-) delete mode 100644 crates/path/Cargo.toml delete mode 100644 crates/path/src/lib.rs delete mode 100644 crates/raven/src/env.rs delete mode 100644 crates/raven/src/manager.rs create mode 100644 demo/.java-version create mode 100644 demo/Nest.toml create mode 100644 demo/src/main/Prey.toml create mode 100644 demo/src/main/java/Main.java create mode 100644 demo/src/test/Prey.toml create mode 100644 demo/src/test/java/MainTest.java create mode 100644 demo/target/Main.class create mode 100644 demo/target/MainTest.class diff --git a/Cargo.lock b/Cargo.lock index 1ee2f6f..a9cbd7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,26 +155,6 @@ 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" @@ -383,13 +363,6 @@ 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" @@ -442,7 +415,6 @@ dependencies = [ "fs", "io", "java", - "path", "toml", ] diff --git a/Cargo.toml b/Cargo.toml index 265e5d2..ecaa01c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ license = "MIT" repository = "https://gitea.cutieguwu.ca/Cutieguwu/raven" publish = false -test = true [workspace.dependencies] # @@ -21,7 +20,6 @@ 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" } diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 1960a8c..dfb1e04 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -8,7 +8,6 @@ description = "Raven's CLI" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies.clap] version = "4.5" diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index b45c8ed..c014835 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -19,7 +19,7 @@ pub enum Command { New { #[clap(flatten)] type_: ProjectFlag, - name: String, + project_name: String, }, /// Create a new raven project in an existing directory Init, @@ -49,7 +49,7 @@ pub struct Assertions { assertions: bool, } -impl Into for Assertions { +impl Into for &Assertions { fn into(self) -> bool { self.assertions } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 4a062ea..ec1d14d 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -8,7 +8,6 @@ description = "Raven's core, including metadata tooling and resources" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] derive_more.workspace = true diff --git a/crates/core/src/dependency.rs b/crates/core/src/dependency.rs index a18223b..36342a9 100644 --- a/crates/core/src/dependency.rs +++ b/crates/core/src/dependency.rs @@ -45,6 +45,6 @@ impl From for Dependency { } /// TODO: This is just a placeholder at present. -fn is_url(path: S) -> bool { +fn is_url(_path: S) -> bool { return false; } diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index ec13601..cf7da5d 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -1,6 +1,6 @@ use derive_more::{Display, From}; -pub type Result = core::result::Result; +pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index b11cf46..88f608f 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - pub mod class; pub mod dependency; pub mod error; diff --git a/crates/core/src/nest.rs b/crates/core/src/nest.rs index 4b458df..07c5cf2 100644 --- a/crates/core/src/nest.rs +++ b/crates/core/src/nest.rs @@ -5,8 +5,8 @@ use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; +use crate::dependency::Dependency; use crate::meta::Meta; -use crate::prelude::Dependency; use crate::workspace::Workspace; pub const F_NEST_TOML: &str = "Nest.toml"; @@ -30,6 +30,11 @@ impl Nest { } pub fn write>(&self, path: P) -> crate::Result<()> { + let mut path = path.as_ref().to_path_buf(); + if path.is_dir() { + path = path.join(F_NEST_TOML); + } + Ok(OpenOptions::new() .write(true) .create(true) diff --git a/crates/core/src/package.rs b/crates/core/src/package.rs index 6debff9..0bc47b1 100644 --- a/crates/core/src/package.rs +++ b/crates/core/src/package.rs @@ -19,8 +19,8 @@ pub struct PackageHandler { impl PackageHandler { const DIR_JAVA: &str = "java/"; - pub fn new>(package_root: P, target_dir: P) -> crate::Result { - let package_root = package_root.as_ref().to_path_buf(); + pub fn new>(src_dir: P, package_root: P, target_dir: P) -> crate::Result { + let package_root = src_dir.as_ref().join(package_root.as_ref()); Ok(Self { prey: Prey::try_from(package_root.join(F_PREY_TOML))?, @@ -42,32 +42,32 @@ impl PackageHandler { self.prey.version() } - pub fn get_update_targets(&mut self) -> crate::Result> { - let mut targets = vec![]; - + pub fn get_update_targets(&mut self) -> crate::Result> { if self.prey_lock.is_none() { // Try to pass a reference to the class so that there's mutability of the object // available at the workspace level instead of parsing all the way down the // tree. How I do this, idk. My brain is friend from a few days of JS. - self.prey_lock = Some(PreyLock::from(expand_files(Self::DIR_JAVA)?)); - return Ok(self - .prey_lock - .clone() - .unwrap() - .classes - .iter() - .map(|mut *class| &mut class) - .collect()); + self.prey_lock = Some(PreyLock::from(expand_files( + self.package_root.join(Self::DIR_JAVA), + )?)); + return Ok(self.prey_lock.as_ref().unwrap().classes.iter().collect()); } - for mut tracked in self.prey_lock.unwrap().classes { - if !tracked.is_updated()? { - targets.push(&mut tracked); - } - } - - Ok(targets) + Ok(self + .prey_lock + .as_ref() + .unwrap() + .classes + .iter() + .filter_map(|tracked| { + if tracked.is_updated().is_ok_and(|v| v == true) { + Some(tracked) + } else { + None + } + }) + .collect()) } } diff --git a/crates/core/src/prey.rs b/crates/core/src/prey.rs index afc83be..08e2705 100644 --- a/crates/core/src/prey.rs +++ b/crates/core/src/prey.rs @@ -1,14 +1,12 @@ -use std::collections::HashSet; use std::fs::{File, OpenOptions}; use std::io::Read; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use serde::{Deserialize, Serialize}; use crate::class::Class; use crate::meta::Meta; use crate::package::Package; -use crate::prelude::Dependency; pub const F_PREY_TOML: &str = "Prey.toml"; pub const F_PREY_LOCK: &str = "Prey.lock"; @@ -21,6 +19,15 @@ pub struct Prey { } impl Prey { + pub fn new(name: S) -> Self { + Self { + package: Package { + entry_point: PathBuf::from(""), + }, + meta: Meta::new(name), + } + } + pub fn entry_point(&self) -> PathBuf { self.package.entry_point.clone() } @@ -56,12 +63,12 @@ impl TryFrom for Prey { /// Data struct #[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)] pub struct PreyLock { - pub classes: HashSet, + pub classes: Vec, } impl PreyLock { pub fn with_class(&mut self, class: Class) -> &mut Self { - self.classes.insert(class); + self.classes.push(class); self } } diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 6d34dd3..477a989 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -11,8 +11,9 @@ use serde::{Deserialize, Serialize}; use crate::Error; use crate::nest::{F_NEST_LOCK, F_NEST_TOML, Nest, NestLock}; use crate::package::PackageHandler; -use crate::prey::F_PREY_TOML; +use crate::prey::{F_PREY_TOML, Prey}; +#[derive(Debug)] pub struct WorkspaceHandler { nest: Nest, nest_lock: Option, @@ -56,7 +57,7 @@ impl WorkspaceHandler { } pub fn write(&self) -> crate::Result<()> { - self.nest.write(self.project_root.join(F_NEST_TOML))?; + self.write_nest()?; if let Option::Some(lock) = self.nest_lock.clone() { lock.write(self.project_root.join(F_NEST_LOCK))?; @@ -65,8 +66,6 @@ impl WorkspaceHandler { Ok(()) } - //pub fn refresh_packages(&mut self) -> crate::Result<()> {} - /* /// Future `build` method. pub fn compile(&self, target: Option) -> crate::Result<()> { @@ -87,13 +86,9 @@ impl WorkspaceHandler { Ok(()) } - - fn make_compiler_job>(target: P) { - // Generate dependency tree. - } */ - pub fn init(&mut self) -> crate::Result<()> { + pub fn init(&mut self) -> crate::Result<&mut Self> { let is_empty = read_dir(self.project_root.as_path()).is_ok_and(|tree| tree.count() == 0); // ORDER MATTERS. THIS MUST COME FIRST. @@ -103,10 +98,7 @@ impl WorkspaceHandler { // Make .java-version self.write_java_version()?; - // Make src/, target/, test/ - self.write_dir_tree()?; - - if !is_empty { + if is_empty { self.write_example_project()?; self.discover_packages()?; @@ -134,30 +126,72 @@ impl WorkspaceHandler { } } - Ok(()) + Ok(self) } // This is the naive build - pub fn build(&mut self) -> crate::Result<()> { + pub fn build(&mut self) -> crate::Result<&mut Self> { let mut targets = vec![]; - for (_name, mut handler) in self.packages.clone() { + for handler in self.packages.values_mut() { targets.append(&mut handler.get_update_targets()?); } let compiler = java::compiler::CompilerBuilder::new() .class_path(Self::DIR_TARGET) - .class_path(Self::DIR_TARGET) + .destination(Self::DIR_TARGET) .build(); - for target in targets { + for target in targets.iter() { // Possibly come up with a source file handler for this? - if let Ok(_) = compiler.clone().compile(target) { + if let Ok(_) = compiler.clone().compile(target.path.as_path()) { // No, this does not run O(1) + //target.update()?; } } - Ok(()) + Ok(self) + } + + pub fn run>( + &mut self, + entry_point: Option

, + assertions: bool, + ) -> crate::Result<&mut Self> { + let mut entry_point = if entry_point.is_none() { + self.nest.default_package() + } else { + entry_point.unwrap().as_ref().to_path_buf() + }; + + if !entry_point.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. + entry_point = entry_point.join( + self.packages + .get(&entry_point) + .ok_or(Error::UnknownPackage)? + .entry_point(), + ); + } + + // JRE pathing will be messed up without this. + std::env::set_current_dir(Self::DIR_TARGET)?; + + java::runtime::JVMBuilder::new(Self::DIR_TARGET) + .assertions(assertions) + .monitor(true) + .build() + .run(entry_point)?; + + Ok(self) + } + + pub fn clean(&mut self) -> crate::Result<&mut Self> { + std::fs::remove_file(self.project_root.join(F_NEST_LOCK))?; + std::fs::remove_dir_all(Self::DIR_TARGET)?; + Ok(self) } /// Add any newly created packages. @@ -174,7 +208,7 @@ impl WorkspaceHandler { // Yes, I know this looks like shit. // That's because it is. - for file in read_dir(Self::DIR_SRC)? + for file in read_dir(self.project_root.join(Self::DIR_SRC))? // Get directories .filter_map(|entry| { if entry.as_ref().is_ok_and(|entry| entry.path().is_dir()) { @@ -203,12 +237,22 @@ impl WorkspaceHandler { }) .flatten() { - let package_root = - pathsub::sub_paths(file.as_path(), PathBuf::from(Self::DIR_SRC).as_path()).unwrap(); + let package_root = pathsub::sub_paths( + file.as_path(), + self.project_root.join(Self::DIR_SRC).as_path(), + ) + .unwrap() + .parent() + .unwrap() + .to_path_buf(); self.packages.insert( package_root.to_path_buf(), - PackageHandler::new(package_root, PathBuf::from(Self::DIR_TARGET))?, + PackageHandler::new( + self.project_root.join(Self::DIR_SRC), + package_root, + self.project_root.join(Self::DIR_TARGET), + )?, ); } @@ -216,15 +260,7 @@ impl WorkspaceHandler { } 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(()) + Ok(self.nest.write(self.project_root.clone())?) } fn write_java_version(&self) -> crate::Result<()> { @@ -251,22 +287,46 @@ impl WorkspaceHandler { Ok(()) } - fn write_example_project(&self) -> std::io::Result<()> { + fn write_example_project(&self) -> crate::Result<()> { + let main: PathBuf = PathBuf::from(Self::DIR_SRC).join("main/"); + let test: PathBuf = PathBuf::from(Self::DIR_SRC).join("test/"); + + // Make src/, target/, test/ + self.write_dir_tree()?; + + // Make src/main/Prey.toml + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(main.join(F_PREY_TOML)) + { + f.write_all(toml::to_string_pretty(&Prey::new("main"))?.as_bytes())?; + } + // 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), - ) { + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(main.join("java/Main").with_extension(JAVA_EXT_SOURCE)) + { f.write_all(include_bytes!("../assets/Main.java"))?; } + // Make src/test/Prey.toml + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(test.join(F_PREY_TOML)) + { + f.write_all(toml::to_string_pretty(&Prey::new("test"))?.as_bytes())?; + } + // 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), - ) { + if let Result::Ok(mut f) = OpenOptions::new() + .write(true) + .create_new(true) + .open(test.join("java/MainTest").with_extension(JAVA_EXT_SOURCE)) + { f.write_all(include_bytes!("../assets/MainTest.java"))?; } diff --git a/crates/fs/Cargo.toml b/crates/fs/Cargo.toml index 2ce3924..c9c8c8e 100644 --- a/crates/fs/Cargo.toml +++ b/crates/fs/Cargo.toml @@ -8,7 +8,6 @@ description = "Raven's FS utilities" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] derive_more.workspace = true diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml index e87e5e8..c41e5a0 100644 --- a/crates/io/Cargo.toml +++ b/crates/io/Cargo.toml @@ -8,7 +8,6 @@ description = "Raven's IO utilities" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] derive_more.workspace = true diff --git a/crates/io/src/error.rs b/crates/io/src/error.rs index 69a7ec7..c5df1d1 100644 --- a/crates/io/src/error.rs +++ b/crates/io/src/error.rs @@ -1,6 +1,6 @@ use derive_more::{Display, From}; -pub type Result = core::result::Result; +pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml index 66e88a7..215d26c 100644 --- a/crates/java/Cargo.toml +++ b/crates/java/Cargo.toml @@ -11,7 +11,6 @@ description = "Tools for interfacing with the Java Development Kit" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] bytesize.workspace = true diff --git a/crates/java/src/error.rs b/crates/java/src/error.rs index 54ed1b4..e7791f4 100644 --- a/crates/java/src/error.rs +++ b/crates/java/src/error.rs @@ -1,6 +1,6 @@ use derive_more::{Display, From}; -pub type Result = core::result::Result; +pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { diff --git a/crates/path/Cargo.toml b/crates/path/Cargo.toml deleted file mode 100644 index 5f3bcc8..0000000 --- a/crates/path/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[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 deleted file mode 100644 index b8bbb2e..0000000 --- a/crates/path/src/lib.rs +++ /dev/null @@ -1,151 +0,0 @@ -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 index 266b875..2715308 100644 --- a/crates/pom/Cargo.toml +++ b/crates/pom/Cargo.toml @@ -8,7 +8,6 @@ description = "Library for serializing and deserializing Maven's POM" repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] derive_more.workspace = true diff --git a/crates/pom/src/error.rs b/crates/pom/src/error.rs index 567db1b..4ec9dde 100644 --- a/crates/pom/src/error.rs +++ b/crates/pom/src/error.rs @@ -1,6 +1,6 @@ use derive_more::{Display, From}; -pub type Result = core::result::Result; +pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { diff --git a/crates/raven/Cargo.toml b/crates/raven/Cargo.toml index ad08a98..6026a1b 100644 --- a/crates/raven/Cargo.toml +++ b/crates/raven/Cargo.toml @@ -10,7 +10,6 @@ categories = ["development-tools::build-utils"] repository.workspace = true publish.workspace = true -test.workspace = true [dependencies] anyhow.workspace = true @@ -20,5 +19,4 @@ 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 deleted file mode 100644 index 706c977..0000000 --- a/crates/raven/src/env.rs +++ /dev/null @@ -1,19 +0,0 @@ -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 index 1cc735c..df07529 100644 --- a/crates/raven/src/main.rs +++ b/crates/raven/src/main.rs @@ -1,68 +1,37 @@ -mod env; -mod manager; - -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; +use core::prelude::WorkspaceHandler; +use anyhow::anyhow; 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()?), - }; + // type_ is yet unused. + if let Command::New { project_name, .. } = &CLI_ARGS.command { + new(project_name.to_owned())?; + } - // 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(), - }; + let project_root = std::env::current_dir()?; - 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)?; - } + let mut wh: WorkspaceHandler = match &CLI_ARGS.command { + Command::New { .. } | Command::Init => WorkspaceHandler::new(project_root), + _ => WorkspaceHandler::load(project_root), + } + .map_err(|err| anyhow!(err))?; + + dbg!(); + match &CLI_ARGS.command { + Command::New { .. } | Command::Init => wh.init(), + Command::Build => wh.build(), 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), + } => wh + .build() + .map_err(|err| anyhow!(err))? + .run(entry_point.to_owned(), assertions.into()), + Command::Clean => wh.clean(), + Command::Test { .. } => unimplemented!(), } + .map_err(|err| anyhow!(err))?; Ok(()) } @@ -75,24 +44,3 @@ fn new(project_name: String) -> anyhow::Result<()> { 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 deleted file mode 100644 index 6aeabe2..0000000 --- a/crates/raven/src/manager.rs +++ /dev/null @@ -1,11 +0,0 @@ -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/demo/.java-version b/demo/.java-version new file mode 100644 index 0000000..aabe6ec --- /dev/null +++ b/demo/.java-version @@ -0,0 +1 @@ +21 diff --git a/demo/Nest.toml b/demo/Nest.toml new file mode 100644 index 0000000..f936757 --- /dev/null +++ b/demo/Nest.toml @@ -0,0 +1,8 @@ +dependencies = [] + +[workspace] +default_package = "main" + +[meta] +name = "demo" +version = "0.1.0" diff --git a/demo/src/main/Prey.toml b/demo/src/main/Prey.toml new file mode 100644 index 0000000..f2dc644 --- /dev/null +++ b/demo/src/main/Prey.toml @@ -0,0 +1,6 @@ +[package] +entry_point = "" + +[meta] +name = "main" +version = "0.1.0" diff --git a/demo/src/main/java/Main.java b/demo/src/main/java/Main.java new file mode 100644 index 0000000..52b9fad --- /dev/null +++ b/demo/src/main/java/Main.java @@ -0,0 +1,10 @@ +public class Main { + + public static void main(String[] args) { + System.out.println("Hello, world!"); + } + + public static int add(int a, int b) { + return a + b; + } +} diff --git a/demo/src/test/Prey.toml b/demo/src/test/Prey.toml new file mode 100644 index 0000000..078176b --- /dev/null +++ b/demo/src/test/Prey.toml @@ -0,0 +1,6 @@ +[package] +entry_point = "" + +[meta] +name = "test" +version = "0.1.0" diff --git a/demo/src/test/java/MainTest.java b/demo/src/test/java/MainTest.java new file mode 100644 index 0000000..ed111a6 --- /dev/null +++ b/demo/src/test/java/MainTest.java @@ -0,0 +1,10 @@ +public class MainTest { + + public static void main(String[] args) { + testAdd(); + } + + public static void testAdd() { + assert Main.add(2, 2) == 4; + } +} diff --git a/demo/target/Main.class b/demo/target/Main.class new file mode 100644 index 0000000000000000000000000000000000000000..96e9d9392c88cf3ce06669fca0c797bd985acbc7 GIT binary patch literal 471 zcmZvZ+e*Vg5QhJ4lBS8Nt*x!vgS8hzDqH#Xf@y2bllr1?(OcmeB8@*8Q z!Uyo7#Mvkmp?fhiJM;e^!|vDj$0vYev}|Ocna~{=$TAdX{DF6U9!|TLey*LH%@6 StKUASzy&-aai6)GYgQY0RSAf(dMCSIY1;8eEL55t8c zXIiNskl@aTs+chezU=JI{O321eg1#{2%v$_9&)fGY#$Et0;MzcTdj3fc)E7jKGU5< zAir)xlYAGjYV~6eE(#K!j}ex;`^tnzIwqM+$TWhWK#HP|QH%*puBbTHQDS;wylrCD z?&?55oOl?=gv6weDZCS~nL>OOP}He4oAstdMWC8B(-?AgqNo>nD8uqFgIS3=AM;oc z7|X<4T`DV34s>iH9lYhX5|#8RK!co6)vaEjDR0k&`k;T&*3l6+NP&yAopSBxUdC)C zkqJ+~)sF>=#Oa*xt6u}XyWZ&zR^+vM{ivgN4Reaa<*YIWi?o;=EnSqVydApPpmC9> z^F6)h$qKU0ms^M%7UBb)9Oiq0083<9%6|6RcaWKqzmlOAK@0pp1NBDg2daPIUt-E} z?og6f7 Date: Sun, 15 Feb 2026 19:38:20 -0500 Subject: [PATCH 08/22] Bump subprocess and toml. Also remove the demo project I accidentally pushed. --- Cargo.lock | 29 ++++++------------ Cargo.toml | 5 ++- crates/core/Cargo.toml | 2 +- crates/core/src/error.rs | 5 +-- crates/core/src/workspace.rs | 9 ++++-- crates/io/Cargo.toml | 14 --------- crates/io/src/error.rs | 11 ------- crates/io/src/lib.rs | 30 ------------------ crates/java/Cargo.toml | 2 +- crates/java/src/compiler.rs | 21 +++++++++++++ crates/java/src/error.rs | 5 +-- crates/java/src/lib.rs | 10 +++--- crates/java/src/runtime.rs | 51 +++++++++++++++---------------- crates/raven/Cargo.toml | 1 - crates/raven/src/main.rs | 1 - demo/.java-version | 1 - demo/Nest.toml | 8 ----- demo/src/main/Prey.toml | 6 ---- demo/src/main/java/Main.java | 10 ------ demo/src/test/Prey.toml | 6 ---- demo/src/test/java/MainTest.java | 10 ------ demo/target/Main.class | Bin 471 -> 0 bytes demo/target/MainTest.class | Bin 631 -> 0 bytes 23 files changed, 73 insertions(+), 164 deletions(-) delete mode 100644 crates/io/Cargo.toml delete mode 100644 crates/io/src/error.rs delete mode 100644 crates/io/src/lib.rs delete mode 100644 demo/.java-version delete mode 100644 demo/Nest.toml delete mode 100644 demo/src/main/Prey.toml delete mode 100644 demo/src/main/java/Main.java delete mode 100644 demo/src/test/Prey.toml delete mode 100644 demo/src/test/java/MainTest.java delete mode 100644 demo/target/Main.class delete mode 100644 demo/target/MainTest.class diff --git a/Cargo.lock b/Cargo.lock index a9cbd7d..b3049d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,12 +171,12 @@ dependencies = [ "anyhow", "derive_more", "fs", - "io", "java", "pathsub", "semver", "serde", "sha256", + "subprocess", "toml", ] @@ -308,14 +308,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "io" -version = "0.2.0" -dependencies = [ - "derive_more", - "subprocess", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -329,8 +321,8 @@ dependencies = [ "bytesize", "derive_more", "fs", - "io", "semver", + "subprocess", ] [[package]] @@ -413,7 +405,6 @@ dependencies = [ "cli", "core", "fs", - "io", "java", "toml", ] @@ -529,9 +520,9 @@ dependencies = [ [[package]] name = "subprocess" -version = "0.2.14" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09969f0abcf65111c0cbdd8bfaa292ca3c38b46bc8ecc7270467af2f4acb172" +checksum = "98e067360c7f5a302e35c9f9cd24cb583c378fbedc73d0237284dbdd0650fcc5" dependencies = [ "libc", "winapi", @@ -571,9 +562,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "1.0.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "bbe30f93627849fa362d4a602212d41bb237dc2bd0f8ba0b2ce785012e124220" dependencies = [ "indexmap", "serde_core", @@ -586,18 +577,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.0.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" dependencies = [ "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index ecaa01c..b224154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ publish = false # cli = { path = "crates/cli" } fs = { path = "crates/fs" } -io = { path = "crates/io" } java = { path = "crates/java" } core = { path = "crates/core" } pom = { path = "crates/pom" } @@ -34,8 +33,8 @@ lenient_semver = "0.4.2" pathsub = "0.1.1" ron = "0.12.0" sha256 = "1.6" -subprocess = "0.2.13" -toml = "0.9.11" +subprocess = "1.0" +toml = "1.0" derive_more = { version = "2.1", features = ["display", "from"] } semver = { version = "1.0",features = ["serde"] } diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ec1d14d..ce125dd 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -12,12 +12,12 @@ publish.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 +subprocess.workspace = true toml.workspace = true [dependencies.anyhow] diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index cf7da5d..521ebfe 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -5,16 +5,13 @@ pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { #[from] - Io(io::Error), + Io(std::io::Error), #[from] Java(java::Error), MissingFileName, - #[from] - StdIo(std::io::Error), - #[from] TomlDeserialize(toml::de::Error), diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 477a989..df65763 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -2,11 +2,12 @@ use std::collections::HashMap; use std::fs::{OpenOptions, read_dir}; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use std::time::Duration; use fs::expand_files; -use io::run_process; use java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; use serde::{Deserialize, Serialize}; +use subprocess::Exec; use crate::Error; use crate::nest::{F_NEST_LOCK, F_NEST_TOML, Nest, NestLock}; @@ -102,7 +103,11 @@ impl WorkspaceHandler { self.write_example_project()?; self.discover_packages()?; - run_process(&["git", "init", "."])?; + Exec::cmd("git") + .arg("init") + .arg(".") + .start()? + .wait_timeout(Duration::from_secs(10))?; } // Append to .gitignore diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml deleted file mode 100644 index c41e5a0..0000000 --- a/crates/io/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "io" -version = "0.2.0" -edition.workspace = true -license.workspace = true - -description = "Raven's IO utilities" -repository.workspace = true - -publish.workspace = true - -[dependencies] -derive_more.workspace = true -subprocess.workspace = true diff --git a/crates/io/src/error.rs b/crates/io/src/error.rs deleted file mode 100644 index c5df1d1..0000000 --- a/crates/io/src/error.rs +++ /dev/null @@ -1,11 +0,0 @@ -use derive_more::{Display, From}; - -pub type Result = std::result::Result; - -#[derive(Debug, From, Display)] -pub enum Error { - #[from] - Io(std::io::Error), - #[from] - Popen(subprocess::PopenError), -} diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs deleted file mode 100644 index 8608558..0000000 --- a/crates/io/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -mod error; - -use std::ffi; - -pub use error::{Error, Result}; - -pub fn run_process(argv: &[S]) -> Result<(Option, Option)> -where - S: AsRef, -{ - let mut process = subprocess::Popen::create( - argv, - subprocess::PopenConfig { - stdout: subprocess::Redirection::Pipe, - ..Default::default() - }, - )?; - - let result = process.communicate(None)?; - - if process - .wait_timeout(std::time::Duration::from_secs(5)) - .is_err() - || process.exit_status().is_none() - { - process.terminate()?; - } - - Ok(result) -} diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml index 215d26c..4d160bd 100644 --- a/crates/java/Cargo.toml +++ b/crates/java/Cargo.toml @@ -16,5 +16,5 @@ publish.workspace = true bytesize.workspace = true derive_more.workspace = true fs.workspace = true -io.workspace = true semver.workspace = true +subprocess.workspace = true diff --git a/crates/java/src/compiler.rs b/crates/java/src/compiler.rs index bfa9038..e685536 100644 --- a/crates/java/src/compiler.rs +++ b/crates/java/src/compiler.rs @@ -1,5 +1,8 @@ use std::path::{Path, PathBuf}; +use subprocess::Exec; +use subprocess::Redirection; + use crate::JAVA_BIN_COMPILER; use crate::Result; @@ -45,6 +48,7 @@ pub struct Compiler { } impl Compiler { + /* pub fn compile>(self, path: P) -> Result<(Option, Option)> { let mut cmd: Vec = vec![JAVA_BIN_COMPILER.to_string()]; @@ -62,6 +66,23 @@ impl Compiler { Ok(io::run_process(cmd.as_slice())?) } + */ + + pub fn compile>(self, path: P) -> Result { + Ok(Exec::cmd(JAVA_BIN_COMPILER) + .args( + self.flags + .clone() + .into_iter() + .flat_map(|f| Into::>::into(f)), + ) + .arg(path.as_ref()) + .stdout(Redirection::Pipe) + .detached() + .start()? + .wait()? + .success()) + } } #[derive(Debug, Clone)] diff --git a/crates/java/src/error.rs b/crates/java/src/error.rs index e7791f4..7d9b7d6 100644 --- a/crates/java/src/error.rs +++ b/crates/java/src/error.rs @@ -7,13 +7,10 @@ pub enum Error { EmptyStdout, #[from] - Io(io::Error), + Io(std::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 index 22b5e0f..2caae94 100644 --- a/crates/java/src/lib.rs +++ b/crates/java/src/lib.rs @@ -6,6 +6,7 @@ use std::str::FromStr; pub use error::{Error, Result}; use runtime::VMFlag; +use subprocess::Exec; pub const JAVA_BIN_VM: &str = "java"; pub const JAVA_BIN_COMPILER: &str = "javac"; @@ -41,9 +42,8 @@ pub fn get_javac_ver() -> Result { /// 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)?, - ) + Ok(Exec::cmd(JAVA_BIN_VM) + .arg(VMFlag::Version.to_string().as_str()) + .capture()? + .stdout_str()) } diff --git a/crates/java/src/runtime.rs b/crates/java/src/runtime.rs index 9f14d2d..7b18bc1 100644 --- a/crates/java/src/runtime.rs +++ b/crates/java/src/runtime.rs @@ -5,6 +5,7 @@ use crate::JAVA_BIN_VM; use crate::Result; use bytesize::ByteSize; +use subprocess::Exec; #[derive(Debug, Default, Clone)] pub struct JVMBuilder { @@ -74,36 +75,32 @@ pub struct JVM { } impl JVM { - pub fn run>(self, entry_point: P) -> Result<(Option, Option)> { - let mut cmd = vec![JAVA_BIN_VM.to_string()]; + pub fn run>(self, entry_point: P) -> Result<()> { + let capture = Exec::cmd(JAVA_BIN_VM) + .args( + self.flags + .clone() + .into_iter() + .flat_map(|f| Into::>::into(f)), + ) + .arg(entry_point.as_ref()) + .capture()?; - cmd.extend( - self.flags - .clone() - .into_iter() - .flat_map(|f| Into::>::into(f)), - ); - - cmd.push(entry_point.as_ref().to_path_buf().display().to_string()); - - let result = io::run_process(cmd.as_slice())?; - - if self.monitor { - let (stdout, stderr) = &result; - - if let Option::Some(stdout) = stdout - && stdout.len() > 0 - { - print!("{stdout}"); - } - if let Option::Some(stderr) = stderr - && stderr.len() > 0 - { - eprintln!("{stderr}"); - } + if !self.monitor { + return Ok(()); } - Ok(result) + let stdout = capture.stdout_str(); + if stdout.len() > 0 { + println!("{stdout}"); + } + + let stderr = capture.stderr_str(); + if stderr.len() > 0 { + eprintln!("{stderr}"); + } + + Ok(()) } } diff --git a/crates/raven/Cargo.toml b/crates/raven/Cargo.toml index 6026a1b..e9492b1 100644 --- a/crates/raven/Cargo.toml +++ b/crates/raven/Cargo.toml @@ -17,6 +17,5 @@ bytesize.workspace = true cli.workspace = true core.workspace = true fs.workspace = true -io.workspace = true java.workspace = true toml.workspace = true diff --git a/crates/raven/src/main.rs b/crates/raven/src/main.rs index df07529..ef2d7ee 100644 --- a/crates/raven/src/main.rs +++ b/crates/raven/src/main.rs @@ -17,7 +17,6 @@ fn main() -> anyhow::Result<()> { } .map_err(|err| anyhow!(err))?; - dbg!(); match &CLI_ARGS.command { Command::New { .. } | Command::Init => wh.init(), Command::Build => wh.build(), diff --git a/demo/.java-version b/demo/.java-version deleted file mode 100644 index aabe6ec..0000000 --- a/demo/.java-version +++ /dev/null @@ -1 +0,0 @@ -21 diff --git a/demo/Nest.toml b/demo/Nest.toml deleted file mode 100644 index f936757..0000000 --- a/demo/Nest.toml +++ /dev/null @@ -1,8 +0,0 @@ -dependencies = [] - -[workspace] -default_package = "main" - -[meta] -name = "demo" -version = "0.1.0" diff --git a/demo/src/main/Prey.toml b/demo/src/main/Prey.toml deleted file mode 100644 index f2dc644..0000000 --- a/demo/src/main/Prey.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -entry_point = "" - -[meta] -name = "main" -version = "0.1.0" diff --git a/demo/src/main/java/Main.java b/demo/src/main/java/Main.java deleted file mode 100644 index 52b9fad..0000000 --- a/demo/src/main/java/Main.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Main { - - public static void main(String[] args) { - System.out.println("Hello, world!"); - } - - public static int add(int a, int b) { - return a + b; - } -} diff --git a/demo/src/test/Prey.toml b/demo/src/test/Prey.toml deleted file mode 100644 index 078176b..0000000 --- a/demo/src/test/Prey.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -entry_point = "" - -[meta] -name = "test" -version = "0.1.0" diff --git a/demo/src/test/java/MainTest.java b/demo/src/test/java/MainTest.java deleted file mode 100644 index ed111a6..0000000 --- a/demo/src/test/java/MainTest.java +++ /dev/null @@ -1,10 +0,0 @@ -public class MainTest { - - public static void main(String[] args) { - testAdd(); - } - - public static void testAdd() { - assert Main.add(2, 2) == 4; - } -} diff --git a/demo/target/Main.class b/demo/target/Main.class deleted file mode 100644 index 96e9d9392c88cf3ce06669fca0c797bd985acbc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 471 zcmZvZ+e*Vg5QhJ4lBS8Nt*x!vgS8hzDqH#Xf@y2bllr1?(OcmeB8@*8Q z!Uyo7#Mvkmp?fhiJM;e^!|vDj$0vYev}|Ocna~{=$TAdX{DF6U9!|TLey*LH%@6 StKUASzy&-aai6)GYgQY0RSAf(dMCSIY1;8eEL55t8c zXIiNskl@aTs+chezU=JI{O321eg1#{2%v$_9&)fGY#$Et0;MzcTdj3fc)E7jKGU5< zAir)xlYAGjYV~6eE(#K!j}ex;`^tnzIwqM+$TWhWK#HP|QH%*puBbTHQDS;wylrCD z?&?55oOl?=gv6weDZCS~nL>OOP}He4oAstdMWC8B(-?AgqNo>nD8uqFgIS3=AM;oc z7|X<4T`DV34s>iH9lYhX5|#8RK!co6)vaEjDR0k&`k;T&*3l6+NP&yAopSBxUdC)C zkqJ+~)sF>=#Oa*xt6u}XyWZ&zR^+vM{ivgN4Reaa<*YIWi?o;=EnSqVydApPpmC9> z^F6)h$qKU0ms^M%7UBb)9Oiq0083<9%6|6RcaWKqzmlOAK@0pp1NBDg2daPIUt-E} z?og6f7 Date: Sun, 15 Feb 2026 19:46:59 -0500 Subject: [PATCH 09/22] Shed old reference materials. --- retired/nest_lib_rs_old/class.rs | 114 --------------- retired/nest_lib_rs_old/dependency.rs | 7 - retired/nest_lib_rs_old/error.rs | 35 ----- retired/nest_lib_rs_old/lib.rs | 45 ------ retired/nest_lib_rs_old/lock.rs | 99 ------------- retired/nest_lib_rs_old/meta.rs | 62 -------- retired/nest_lib_rs_old/nest.rs | 130 ----------------- retired/nest_lib_rs_old/package.rs | 38 ----- retired/nest_lib_rs_old/prelude.rs | 10 -- retired/nest_lib_rs_old/prey.rs | 127 ----------------- retired/nest_lib_rs_old/workspace.rs | 8 -- retired/old_nest.rs | 196 -------------------------- 12 files changed, 871 deletions(-) delete mode 100644 retired/nest_lib_rs_old/class.rs delete mode 100644 retired/nest_lib_rs_old/dependency.rs delete mode 100644 retired/nest_lib_rs_old/error.rs delete mode 100644 retired/nest_lib_rs_old/lib.rs delete mode 100644 retired/nest_lib_rs_old/lock.rs delete mode 100644 retired/nest_lib_rs_old/meta.rs delete mode 100644 retired/nest_lib_rs_old/nest.rs delete mode 100644 retired/nest_lib_rs_old/package.rs delete mode 100644 retired/nest_lib_rs_old/prelude.rs delete mode 100644 retired/nest_lib_rs_old/prey.rs delete mode 100644 retired/nest_lib_rs_old/workspace.rs delete mode 100644 retired/old_nest.rs diff --git a/retired/nest_lib_rs_old/class.rs b/retired/nest_lib_rs_old/class.rs deleted file mode 100644 index 5225fbc..0000000 --- a/retired/nest_lib_rs_old/class.rs +++ /dev/null @@ -1,114 +0,0 @@ -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 deleted file mode 100644 index ed0547a..0000000 --- a/retired/nest_lib_rs_old/dependency.rs +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 1f7817f..0000000 --- a/retired/nest_lib_rs_old/error.rs +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index ce258ee..0000000 --- a/retired/nest_lib_rs_old/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 02f488f..0000000 --- a/retired/nest_lib_rs_old/lock.rs +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index bffe130..0000000 --- a/retired/nest_lib_rs_old/meta.rs +++ /dev/null @@ -1,62 +0,0 @@ -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 deleted file mode 100644 index bc4255d..0000000 --- a/retired/nest_lib_rs_old/nest.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 6ab2b6a..0000000 --- a/retired/nest_lib_rs_old/package.rs +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 69d35f3..0000000 --- a/retired/nest_lib_rs_old/prelude.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![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 deleted file mode 100644 index abaf8fb..0000000 --- a/retired/nest_lib_rs_old/prey.rs +++ /dev/null @@ -1,127 +0,0 @@ -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 deleted file mode 100644 index cd788aa..0000000 --- a/retired/nest_lib_rs_old/workspace.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::path::PathBuf; - -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -pub struct Workspace { - pub default_package: PathBuf, -} diff --git a/retired/old_nest.rs b/retired/old_nest.rs deleted file mode 100644 index 2361388..0000000 --- a/retired/old_nest.rs +++ /dev/null @@ -1,196 +0,0 @@ -#![allow(dead_code)] - -use std::collections::HashSet; -use std::fs::{File, OpenOptions}; -use std::hash::{self, Hash}; -use std::io::Read; -use std::path::{Path, PathBuf}; -use std::sync::LazyLock; - -use crate::java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; -use crate::{DIR_SRC, DIR_TARGET, F_NEST_LOCK, F_NEST_TOML, PROJECT_ROOT}; - -use anyhow::Context; -use semver::Version; -use serde::{Deserialize, Serialize}; - -pub static NEST: LazyLock> = - LazyLock::new(|| Nest::try_from(PROJECT_ROOT.join(F_NEST_TOML.as_path()))); - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Nest { - pub package: Package, -} - -impl TryFrom for Nest { - type Error = anyhow::Error; - - fn try_from(value: File) -> Result { - let mut value = value; - let mut buf = String::new(); - value - .read_to_string(&mut buf) - .context("Failed to read Nest")?; - - toml::from_str(buf.as_str()).context("Failed to deserialize Nest") - } -} - -impl TryFrom for Nest { - type Error = anyhow::Error; - - fn try_from(value: PathBuf) -> Result { - Nest::try_from( - OpenOptions::new() - .read(true) - .open(value) - .expect("Failed to load Nest.toml"), - ) - } -} - -// Rename to Prey -// Mark as deprecated soon. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Package { - pub name: String, - pub version: semver::Version, -} - -impl Default for Package { - fn default() -> Self { - Self { - name: String::from("MyPackage"), - version: Version::new(0, 1, 0), - } - } -} - -#[derive(Debug, Default, Deserialize, Serialize)] -pub struct NestLock { - pub classes: HashSet, -} - -impl NestLock { - pub fn load() -> anyhow::Result { - NestLock::try_from(PROJECT_ROOT.join(F_NEST_LOCK.as_path())) - } - - /// Update, retaining all classes that still exist and whose paths are still files, rather than - /// being shifted into a package. - pub fn update(&mut self) { - self.classes = self - .classes - .clone() - .into_iter() - .filter_map(|class| { - // Paths are almost correct, except that the target classes are expecting to path - // through: - // target/main/Main.class, not target/Main.class - // target/test/MainTest.class, not target/MainTest.class - - if DIR_SRC - .join(&class.path) - .with_extension(JAVA_EXT_SOURCE) - .exists() - && DIR_TARGET - .join(&class.subpath()) - .with_extension(JAVA_EXT_CLASS) - .is_file() - { - return Some(class); - } - - None - }) - .collect(); - } -} - -impl TryFrom for NestLock { - type Error = anyhow::Error; - - fn try_from(value: File) -> Result { - let mut value = value; - let mut buf = String::new(); - - value.read_to_string(&mut buf)?; - toml::from_str(buf.as_str()).context("Failed to deserialize NestLock") - } -} - -impl TryFrom for NestLock { - type Error = anyhow::Error; - - fn try_from(value: PathBuf) -> Result { - NestLock::try_from( - OpenOptions::new() - .read(true) - .open(&value) - .with_context(|| format!("Failed to open {}", value.display()))?, - ) - .context("") - } -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub struct Class { - path: PathBuf, - checksum: String, -} - -impl Class { - /// Returns true if the class needs updating. - /// This may also cautionarily return true if it cannot digest the file. - pub fn is_updated(&self) -> bool { - // Still doesn't handle inter-dependency checks. - - DIR_TARGET - .join(self.subpath()) - .with_extension(JAVA_EXT_CLASS) - .exists() - && sha256::try_digest(DIR_SRC.join(self.path()).with_extension(JAVA_EXT_SOURCE)) - .is_ok_and(|hash| self.checksum == hash) - } - - /// Returns the path such that src/ and target/ don't matter. - /// E.g., `main/Main.java` as_subpath is `Main.java` - /// allowing it to match with `target/main/Main.class` - /// because Java diregards the top level subdir in `src/` - fn subpath(&self) -> PathBuf { - let mut p = self.path.components(); - p.next(); // Remove the top level dir. - p.as_path().to_path_buf() - } - - pub fn path(&self) -> &Path { - self.path.as_path() - } -} - -impl Hash for Class { - fn hash(&self, state: &mut H) { - self.path.hash(state); - } -} - -impl TryFrom for Class { - type Error = anyhow::Error; - - fn try_from(mut value: PathBuf) -> Result { - if value.is_relative() { - value = value - .canonicalize() - .context("Failed to canonicalize path")?; - } - - Ok(Self { - path: PathBuf::from( - pathsub::sub_paths(value.as_path(), DIR_SRC.as_path()) - .context("Failed to subtract paths to get class path")?, - ) - .with_extension(""), - checksum: sha256::try_digest(&value)?, - }) - } -} -- 2.49.1 From 17f7b9dca9e4ee7943d63d9407aed6c136dc9c34 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:15:26 -0500 Subject: [PATCH 10/22] Resolve some pathing issues; cleanup. --- crates/core/Cargo.toml | 2 +- crates/core/src/prey.rs | 7 +++++- crates/core/src/workspace.rs | 48 ++++++++++-------------------------- 3 files changed, 20 insertions(+), 37 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index ce125dd..c3b39fc 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core" -version = "0.1.0" +version = "0.1.1" edition.workspace = true license.workspace = true diff --git a/crates/core/src/prey.rs b/crates/core/src/prey.rs index 08e2705..25ae61c 100644 --- a/crates/core/src/prey.rs +++ b/crates/core/src/prey.rs @@ -1,6 +1,6 @@ use std::fs::{File, OpenOptions}; use std::io::Read; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; @@ -28,6 +28,11 @@ impl Prey { } } + pub fn with_entry_point>(&mut self, entry_point: P) -> &mut Self { + self.package.entry_point = entry_point.as_ref().to_path_buf(); + self + } + pub fn entry_point(&self) -> PathBuf { self.package.entry_point.clone() } diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index df65763..81e6267 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -67,32 +67,10 @@ impl WorkspaceHandler { Ok(()) } - /* - /// 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(()) - } - */ - pub fn init(&mut self) -> crate::Result<&mut Self> { + // ORDER MATTERS. 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()?; @@ -150,7 +128,7 @@ impl WorkspaceHandler { for target in targets.iter() { // Possibly come up with a source file handler for this? if let Ok(_) = compiler.clone().compile(target.path.as_path()) { - // No, this does not run O(1) + // TODO: Prevent unnecessary recompile //target.update()?; } } @@ -173,17 +151,13 @@ impl WorkspaceHandler { // 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. - entry_point = entry_point.join( - self.packages - .get(&entry_point) - .ok_or(Error::UnknownPackage)? - .entry_point(), - ); + entry_point = self + .packages + .get(&entry_point) + .ok_or(Error::UnknownPackage)? + .entry_point(); } - // JRE pathing will be messed up without this. - std::env::set_current_dir(Self::DIR_TARGET)?; - java::runtime::JVMBuilder::new(Self::DIR_TARGET) .assertions(assertions) .monitor(true) @@ -305,7 +279,9 @@ impl WorkspaceHandler { .create_new(true) .open(main.join(F_PREY_TOML)) { - f.write_all(toml::to_string_pretty(&Prey::new("main"))?.as_bytes())?; + f.write_all( + toml::to_string_pretty(&Prey::new("main").with_entry_point("Main"))?.as_bytes(), + )?; } // Make src/main/Main.java @@ -323,7 +299,9 @@ impl WorkspaceHandler { .create_new(true) .open(test.join(F_PREY_TOML)) { - f.write_all(toml::to_string_pretty(&Prey::new("test"))?.as_bytes())?; + f.write_all( + toml::to_string_pretty(&Prey::new("test").with_entry_point("MainTest"))?.as_bytes(), + )?; } // Make src/test/MainTest.java -- 2.49.1 From e1827b13f4251e9bf7a691b89851c5af39b28e9e Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:16:32 -0500 Subject: [PATCH 11/22] Fix some issues with clap using the cli crate's versioning. --- crates/cli/Cargo.toml | 2 +- crates/cli/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index dfb1e04..26cfc41 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cli" -version = "0.2.0" +version = "0.2.1" edition.workspace = true license.workspace = true diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index c014835..6931437 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -6,8 +6,7 @@ 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}")] +#[clap(name = "Raven", version = "0.2.0")] pub struct CliArgs { #[command(subcommand)] pub command: Command, -- 2.49.1 From 68743619f27f9a9dfb5cdc253bb66b81a72a8197 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:16:47 -0500 Subject: [PATCH 12/22] Bump java crate version. --- Cargo.lock | 6 +++--- crates/java/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b3049d4..35b0274 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,7 +144,7 @@ checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cli" -version = "0.2.0" +version = "0.2.1" dependencies = [ "clap", ] @@ -166,7 +166,7 @@ dependencies = [ [[package]] name = "core" -version = "0.1.0" +version = "0.1.1" dependencies = [ "anyhow", "derive_more", @@ -316,7 +316,7 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "java" -version = "0.2.0" +version = "0.2.1" dependencies = [ "bytesize", "derive_more", diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml index 4d160bd..a3ca566 100644 --- a/crates/java/Cargo.toml +++ b/crates/java/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "java" -version = "0.2.0" +version = "0.2.1" edition.workspace = true license.workspace = true -- 2.49.1 From 4404aba65f5a5db71828ff4e4d20545be4599dc3 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:22:12 -0500 Subject: [PATCH 13/22] Update Cargo.lock --- Cargo.lock | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 35b0274..a8b258b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "async-trait" @@ -66,14 +66,14 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -86,9 +86,9 @@ dependencies = [ [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "bytesize" @@ -104,9 +104,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" -version = "4.5.56" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ "clap_builder", "clap_derive", @@ -114,9 +114,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.56" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ "anstream", "anstyle", @@ -133,14 +133,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] name = "clap_lex" -version = "0.7.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cli" @@ -218,7 +218,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.114", + "syn 2.0.116", "unicode-xid", ] @@ -339,15 +339,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.180" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "once_cell_polyfill" @@ -455,7 +455,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -515,7 +515,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.116", ] [[package]] @@ -541,9 +541,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -607,9 +607,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" -- 2.49.1 From a3c208555a63405caf0a05e546ec80a45a2484b5 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:27:57 -0500 Subject: [PATCH 14/22] Add better handling of undefined entry points. --- Cargo.lock | 2 +- crates/core/Cargo.toml | 2 +- crates/core/src/error.rs | 2 ++ crates/core/src/workspace.rs | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8b258b..0e92fd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,7 +166,7 @@ dependencies = [ [[package]] name = "core" -version = "0.1.1" +version = "0.1.2" dependencies = [ "anyhow", "derive_more", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index c3b39fc..d215fe3 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core" -version = "0.1.1" +version = "0.1.2" edition.workspace = true license.workspace = true diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 521ebfe..da6f2d3 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -18,5 +18,7 @@ pub enum Error { #[from] TomlSerialize(toml::ser::Error), + UndefinedEntryPoint, + UnknownPackage, } diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 81e6267..f74621d 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -158,6 +158,10 @@ impl WorkspaceHandler { .entry_point(); } + if entry_point.file_name().is_none() { + return Err(Error::UndefinedEntryPoint); + } + java::runtime::JVMBuilder::new(Self::DIR_TARGET) .assertions(assertions) .monitor(true) -- 2.49.1 From cfb6f5fb34e02f7d662ea05e6d97661cd5ee2af0 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:36:54 -0500 Subject: [PATCH 15/22] Fix `raven clean` --- Cargo.lock | 2 +- crates/core/Cargo.toml | 2 +- crates/core/src/workspace.rs | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e92fd2..d691551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,7 +166,7 @@ dependencies = [ [[package]] name = "core" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "derive_more", diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index d215fe3..f13ae2f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core" -version = "0.1.2" +version = "0.1.3" edition.workspace = true license.workspace = true diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index f74621d..3f6ec70 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -172,8 +172,12 @@ impl WorkspaceHandler { } pub fn clean(&mut self) -> crate::Result<&mut Self> { - std::fs::remove_file(self.project_root.join(F_NEST_LOCK))?; - std::fs::remove_dir_all(Self::DIR_TARGET)?; + if let Err(err) = std::fs::remove_file(self.project_root.join(F_NEST_LOCK)) { + if err.kind() != std::io::ErrorKind::NotFound { + return Err(Error::from(err)); + } + } + let _ = std::fs::remove_dir_all(Self::DIR_TARGET); Ok(self) } -- 2.49.1 From dcbf67e2034c9581e453d924939acf2265388217 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Sun, 15 Feb 2026 20:41:56 -0500 Subject: [PATCH 16/22] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a94467..1de7495 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,12 @@ WSL *may* affect the behaviour of raven. Quirks to be worked out. ```bash raven new demo cd demo -raven run main.Main +raven run main ``` ## Raven commands + +```bash Usage: raven Commands: @@ -47,6 +49,7 @@ Commands: Options: -h, --help Print help -V, --version Print version +``` ## Future plans -- 2.49.1 From 1009a84c063bd4bbd8a176a0822b092172cf19a3 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Mon, 16 Feb 2026 20:40:36 -0500 Subject: [PATCH 17/22] Improve javac version fetching. --- crates/java/Cargo.toml | 2 +- crates/java/src/compiler.rs | 37 ++++++++++++++++-------------------- crates/java/src/lib.rs | 38 +++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/crates/java/Cargo.toml b/crates/java/Cargo.toml index a3ca566..56d05c5 100644 --- a/crates/java/Cargo.toml +++ b/crates/java/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "java" -version = "0.2.1" +version = "0.2.2" edition.workspace = true license.workspace = true diff --git a/crates/java/src/compiler.rs b/crates/java/src/compiler.rs index e685536..9f6d46c 100644 --- a/crates/java/src/compiler.rs +++ b/crates/java/src/compiler.rs @@ -1,9 +1,11 @@ +use std::fmt::Display; use std::path::{Path, PathBuf}; use subprocess::Exec; use subprocess::Redirection; use crate::JAVA_BIN_COMPILER; +use crate::JAVA_EXT_SOURCE; use crate::Result; #[derive(Debug, Default, Clone)] @@ -48,26 +50,6 @@ pub struct Compiler { } 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())?) - } - */ - pub fn compile>(self, path: P) -> Result { Ok(Exec::cmd(JAVA_BIN_COMPILER) .args( @@ -76,7 +58,7 @@ impl Compiler { .into_iter() .flat_map(|f| Into::>::into(f)), ) - .arg(path.as_ref()) + .arg(path.as_ref().with_extension(JAVA_EXT_SOURCE)) .stdout(Redirection::Pipe) .detached() .start()? @@ -89,6 +71,7 @@ impl Compiler { pub enum CompilerFlag { Classpath { path: PathBuf }, Destination { path: PathBuf }, + Version, } impl Into> for CompilerFlag { @@ -96,6 +79,18 @@ impl Into> for CompilerFlag { match self { Self::Classpath { path } => vec!["-classpath".to_string(), path.display().to_string()], Self::Destination { path } => vec!["-d".to_string(), path.display().to_string()], + Self::Version => vec!["--version".to_string()], + } + } +} + +// TODO: Clean this up a bit? +impl Display for CompilerFlag { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Classpath { path } => write!(f, "-classpath {}", path.display()), + Self::Destination { path } => write!(f, "-d {}", path.display()), + Self::Version => write!(f, "--version"), } } } diff --git a/crates/java/src/lib.rs b/crates/java/src/lib.rs index 2caae94..ab1391c 100644 --- a/crates/java/src/lib.rs +++ b/crates/java/src/lib.rs @@ -8,6 +8,8 @@ pub use error::{Error, Result}; use runtime::VMFlag; use subprocess::Exec; +use crate::compiler::CompilerFlag; + pub const JAVA_BIN_VM: &str = "java"; pub const JAVA_BIN_COMPILER: &str = "javac"; @@ -16,24 +18,22 @@ 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) - */ +/// Uses the javac binary to get information about the install compiler. +pub fn get_javac_version() -> Result { + // Try to pull from javac first. + if let Ok(version) = semver::Version::from_str( + Exec::cmd(JAVA_BIN_COMPILER) + .arg(CompilerFlag::Version.to_string()) + .capture()? + .stdout_str() + .replace("javac", "") + .trim(), + ) { + return Ok(version); + } 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)?, @@ -42,8 +42,14 @@ pub fn get_javac_ver() -> Result { /// Calls the java binary, returning the complete stdout version information. fn get_java_version_info() -> 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) + */ Ok(Exec::cmd(JAVA_BIN_VM) - .arg(VMFlag::Version.to_string().as_str()) + .arg(VMFlag::Version.to_string()) .capture()? .stdout_str()) } -- 2.49.1 From f0d22e6b793af4edaa49e4b071df719bae4c8ffe Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Mon, 16 Feb 2026 20:41:31 -0500 Subject: [PATCH 18/22] Speed up brute force building with Prey.lock hashing and caching. --- crates/core/Cargo.toml | 2 +- crates/core/src/class.rs | 52 +++++++++++++++++---------- crates/core/src/dependency.rs | 3 +- crates/core/src/error.rs | 6 ++++ crates/core/src/nest.rs | 10 +++--- crates/core/src/package.rs | 55 ++++++++++++++-------------- crates/core/src/prey.rs | 66 +++++++++++++++++++++++----------- crates/core/src/workspace.rs | 68 ++++++++++++++++++++++++++--------- 8 files changed, 170 insertions(+), 92 deletions(-) diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index f13ae2f..0fdd923 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "core" -version = "0.1.3" +version = "0.1.4" edition.workspace = true license.workspace = true diff --git a/crates/core/src/class.rs b/crates/core/src/class.rs index c26de32..7f3a71a 100644 --- a/crates/core/src/class.rs +++ b/crates/core/src/class.rs @@ -1,35 +1,49 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; use serde::{Deserialize, Serialize}; +use crate::{Error, Result}; + /// Data struct #[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Class { + /// Path relative to PACKAGE/java, without file extension. pub path: PathBuf, pub checksum: String, } impl Class { - pub fn is_updated(&self) -> crate::Result { - // If the path is local and that file has not been updated. - Ok(self.checksum == sha256::try_digest(self.path.clone())?) + pub fn new>(package_src_root: P, file_path: P) -> Result { + let mut file_path = file_path.as_ref().to_path_buf(); + if file_path.is_absolute() { + file_path = pathsub::sub_paths(file_path.as_path(), package_src_root.as_ref()) + .ok_or(Error::MismatchedPackage)?; + } + + Ok(Self { + path: dbg!(file_path.with_extension("")), + checksum: sha256::try_digest(package_src_root.as_ref().join(file_path))?, + }) } - pub fn update(&mut self) -> crate::Result<()> { - self.checksum = sha256::try_digest(self.path.clone())?; + pub fn is_updated>(&self, class_path: P) -> Result { + // If the path is local and that file has not been updated. + Ok(class_path + .as_ref() + .join(self.path.as_path()) + .with_extension(JAVA_EXT_CLASS) + .exists() + && self.checksum == sha256::try_digest(self.path.clone())?) + } + + pub fn update>(&mut self, package_src_root: P) -> Result<()> { + self.checksum = sha256::try_digest(dbg!( + package_src_root + .as_ref() + .join(self.path.as_path()) + .with_extension(JAVA_EXT_SOURCE), + ))?; Ok(()) } } - -// TODO: Make it clearer that this is for general files, -// not nests. -impl TryFrom for Class { - type Error = crate::Error; - - fn try_from(value: PathBuf) -> Result { - Ok(Self { - path: value.clone(), - checksum: sha256::try_digest(value)?, - }) - } -} diff --git a/crates/core/src/dependency.rs b/crates/core/src/dependency.rs index 36342a9..ce45527 100644 --- a/crates/core/src/dependency.rs +++ b/crates/core/src/dependency.rs @@ -1,6 +1,7 @@ use semver::Version; use serde::{Deserialize, Serialize}; +use crate::Result; use crate::package::PackageHandler; /// Data struct @@ -26,7 +27,7 @@ impl Dependency { return self.name.clone(); } - pub fn is_updated(&self) -> crate::Result { + pub fn is_updated(&self) -> Result { // If the path is local and that file has not been updated. Ok(self.source.as_ref().is_some_and(|path| is_url(path)) && self.checksum == sha256::try_digest(self.source.as_ref().unwrap())?) diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index da6f2d3..5a030ab 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -4,6 +4,10 @@ pub type Result = std::result::Result; #[derive(Debug, From, Display)] pub enum Error { + /// Attempted to replace a value in a hash collection, + /// but there was no prime present when one was expected. + AbsentPrimeHashingError, + #[from] Io(std::io::Error), @@ -12,6 +16,8 @@ pub enum Error { MissingFileName, + MismatchedPackage, + #[from] TomlDeserialize(toml::de::Error), diff --git a/crates/core/src/nest.rs b/crates/core/src/nest.rs index 07c5cf2..c13c8c2 100644 --- a/crates/core/src/nest.rs +++ b/crates/core/src/nest.rs @@ -29,16 +29,16 @@ impl Nest { } } - pub fn write>(&self, path: P) -> crate::Result<()> { - let mut path = path.as_ref().to_path_buf(); - if path.is_dir() { - path = path.join(F_NEST_TOML); + pub fn write>(&self, project_root: P) -> crate::Result<()> { + let mut project_root = project_root.as_ref().to_path_buf(); + if project_root.is_dir() { + project_root = project_root.join(F_NEST_TOML); } Ok(OpenOptions::new() .write(true) .create(true) - .open(path)? + .open(project_root)? .write_all(toml::to_string_pretty(&self)?.as_bytes())?) } diff --git a/crates/core/src/package.rs b/crates/core/src/package.rs index 0bc47b1..4991dc4 100644 --- a/crates/core/src/package.rs +++ b/crates/core/src/package.rs @@ -1,30 +1,35 @@ use std::hash::Hash; use std::path::{Path, PathBuf}; -use fs::expand_files; use serde::{Deserialize, Serialize}; use crate::class::Class; use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey, PreyLock}; +pub const DIR_JAVA: &str = "java/"; + /// Hashing is only based off the Prey. #[derive(Debug, Clone, PartialEq, Eq)] pub struct PackageHandler { prey: Prey, - prey_lock: Option, + prey_lock: PreyLock, + /// Path relative to WORKSPACE/src package_root: PathBuf, target_dir: PathBuf, } impl PackageHandler { - const DIR_JAVA: &str = "java/"; - pub fn new>(src_dir: P, package_root: P, target_dir: P) -> crate::Result { let package_root = src_dir.as_ref().join(package_root.as_ref()); + let prey_lock = if let Ok(prey_lock) = PreyLock::try_from(package_root.join(F_PREY_LOCK)) { + prey_lock + } else { + PreyLock::new(package_root.clone(), package_root.join(DIR_JAVA))? + }; Ok(Self { prey: Prey::try_from(package_root.join(F_PREY_TOML))?, - prey_lock: PreyLock::try_from(package_root.join(F_PREY_LOCK)).ok(), + prey_lock, package_root, target_dir: target_dir.as_ref().to_path_buf(), }) @@ -42,32 +47,26 @@ impl PackageHandler { self.prey.version() } - pub fn get_update_targets(&mut self) -> crate::Result> { - if self.prey_lock.is_none() { - // Try to pass a reference to the class so that there's mutability of the object - // available at the workspace level instead of parsing all the way down the - // tree. How I do this, idk. My brain is friend from a few days of JS. + pub fn prey_lock(&mut self) -> &mut PreyLock { + &mut self.prey_lock + } - self.prey_lock = Some(PreyLock::from(expand_files( - self.package_root.join(Self::DIR_JAVA), - )?)); - return Ok(self.prey_lock.as_ref().unwrap().classes.iter().collect()); - } - - Ok(self - .prey_lock - .as_ref() - .unwrap() - .classes + pub fn get_outdated>(&self, class_path: P) -> Vec { + self.prey_lock + .clone() + .classes() .iter() - .filter_map(|tracked| { - if tracked.is_updated().is_ok_and(|v| v == true) { - Some(tracked) - } else { - None - } + .filter(|class| { + class + .is_updated(class_path.as_ref()) + .is_ok_and(|b| b == false) }) - .collect()) + .cloned() + .collect() + } + + pub fn write_lock(&self) -> crate::Result<()> { + self.prey_lock.write(self.package_root.as_path()) } } diff --git a/crates/core/src/prey.rs b/crates/core/src/prey.rs index 25ae61c..e4dd707 100644 --- a/crates/core/src/prey.rs +++ b/crates/core/src/prey.rs @@ -1,7 +1,9 @@ +use std::collections::HashSet; use std::fs::{File, OpenOptions}; -use std::io::Read; +use std::io::{Read, Write}; use std::path::{Path, PathBuf}; +use fs::expand_files; use serde::{Deserialize, Serialize}; use crate::class::Class; @@ -68,14 +70,54 @@ impl TryFrom for Prey { /// Data struct #[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)] pub struct PreyLock { - pub classes: Vec, + classes: HashSet, } impl PreyLock { + pub fn new>(package_root: P, package_src_root: P) -> crate::Result { + Ok(Self::from_paths( + expand_files(package_root)?, + package_src_root, + )) + } + + pub fn from_paths>(paths: Vec, package_src_root: P) -> Self { + let mut lock = Self::default(); + lock.classes = paths + .iter() + .filter_map(|f| { + let dep = Class::new(package_src_root.as_ref().to_path_buf(), f.to_owned()); + if dep.is_ok() { + Some(dep.unwrap()) + } else { + None + } + }) + .collect(); + lock + } + + pub fn write>(&self, package_root: P) -> crate::Result<()> { + let mut package_root = package_root.as_ref().to_path_buf(); + if package_root.is_dir() { + package_root = package_root.join(F_PREY_LOCK); + } + + Ok(OpenOptions::new() + .write(true) + .create(true) + .open(package_root)? + .write_all(toml::to_string_pretty(&self)?.as_bytes())?) + } + pub fn with_class(&mut self, class: Class) -> &mut Self { - self.classes.push(class); + self.classes.insert(class); self } + + pub fn classes(&mut self) -> &mut HashSet { + &mut self.classes + } } /// Load the PreyLock from Prey.lock file. @@ -97,21 +139,3 @@ impl TryFrom for PreyLock { Ok(toml::from_str(buf.as_str())?) } } - -impl From> for PreyLock { - fn from(value: Vec) -> Self { - let mut lock = Self::default(); - lock.classes = value - .iter() - .filter_map(|f| { - let dep = Class::try_from(f.to_owned()); - if dep.is_ok() { - Some(dep.unwrap()) - } else { - None - } - }) - .collect(); - lock - } -} diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index 3f6ec70..c435729 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -9,10 +9,10 @@ use java::{JAVA_EXT_CLASS, JAVA_EXT_SOURCE}; use serde::{Deserialize, Serialize}; use subprocess::Exec; -use crate::Error; use crate::nest::{F_NEST_LOCK, F_NEST_TOML, Nest, NestLock}; use crate::package::PackageHandler; -use crate::prey::{F_PREY_TOML, Prey}; +use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey}; +use crate::{Error, package}; #[derive(Debug)] pub struct WorkspaceHandler { @@ -57,13 +57,15 @@ impl WorkspaceHandler { Ok(workspace_manager) } - pub fn write(&self) -> crate::Result<()> { - self.write_nest()?; - + pub fn write_locks(&self) -> crate::Result<()> { if let Option::Some(lock) = self.nest_lock.clone() { lock.write(self.project_root.join(F_NEST_LOCK))?; } + for handler in self.packages.values() { + handler.write_lock()?; + } + Ok(()) } @@ -114,25 +116,39 @@ impl WorkspaceHandler { // This is the naive build pub fn build(&mut self) -> crate::Result<&mut Self> { - let mut targets = vec![]; - - for handler in self.packages.values_mut() { - targets.append(&mut handler.get_update_targets()?); - } - let compiler = java::compiler::CompilerBuilder::new() .class_path(Self::DIR_TARGET) .destination(Self::DIR_TARGET) .build(); - for target in targets.iter() { - // Possibly come up with a source file handler for this? - if let Ok(_) = compiler.clone().compile(target.path.as_path()) { - // TODO: Prevent unnecessary recompile - //target.update()?; + // No unintentional deep copying anywhere, right? + // Probably not. We'll see. + for handler in self.packages.values_mut() { + let package_src_root = self + .project_root + .join(Self::DIR_SRC) + .join(handler.name()) + .join(package::DIR_JAVA); + let targets = handler.get_outdated(self.project_root.join(Self::DIR_TARGET)); + + for mut target in targets { + dbg!(&target); + if let Ok(true) = compiler + .clone() + .compile(package_src_root.join(target.path.as_path())) + { + target.update(package_src_root.as_path())?; + handler + .prey_lock() + .classes() + .replace(target) + .ok_or(Error::AbsentPrimeHashingError)?; + } } } + self.write_locks()?; + Ok(self) } @@ -172,12 +188,30 @@ impl WorkspaceHandler { } pub fn clean(&mut self) -> crate::Result<&mut Self> { + // Clear Nest.lock if let Err(err) = std::fs::remove_file(self.project_root.join(F_NEST_LOCK)) { if err.kind() != std::io::ErrorKind::NotFound { return Err(Error::from(err)); } } + + // Clear src/**/Prey.lock + for handler in self.packages.values() { + if let Err(err) = std::fs::remove_file( + self.project_root + .join(Self::DIR_SRC) + .join(handler.name()) + .join(F_PREY_LOCK), + ) { + if err.kind() != std::io::ErrorKind::NotFound { + return Err(Error::from(err)); + } + } + } + + // Clear target/ let _ = std::fs::remove_dir_all(Self::DIR_TARGET); + Ok(self) } @@ -256,7 +290,7 @@ impl WorkspaceHandler { .create_new(true) .open(java::F_JAVA_VERSION) { - f.write_all(format!("{}\n", java::get_javac_ver()?.major.to_string()).as_bytes())?; + f.write_all(format!("{}\n", java::get_javac_version()?.major.to_string()).as_bytes())?; } Ok(()) -- 2.49.1 From 6ad82c3339602eb71af4b56af3b6a59739e44ee6 Mon Sep 17 00:00:00 2001 From: Cutieguwu Date: Mon, 16 Feb 2026 20:41:34 -0500 Subject: [PATCH 19/22] Update Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d691551..fdc1e90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,7 +166,7 @@ dependencies = [ [[package]] name = "core" -version = "0.1.3" +version = "0.1.4" dependencies = [ "anyhow", "derive_more", @@ -316,7 +316,7 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "java" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bytesize", "derive_more", -- 2.49.1 From fee63a2d4b8c5d31c17818a37bbd712337e0757c Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:45:53 -0500 Subject: [PATCH 20/22] Add documentation. --- crates/raven/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/raven/src/main.rs b/crates/raven/src/main.rs index ef2d7ee..3f815be 100644 --- a/crates/raven/src/main.rs +++ b/crates/raven/src/main.rs @@ -5,6 +5,11 @@ use cli::{CLI_ARGS, Command}; fn main() -> anyhow::Result<()> { // type_ is yet unused. + + // `raven new` requires special behaviour. + // This will call the "new" part of the command, + // changing the cwd, before calling WorkspaceHandler.init() + // on the actual workspace directory. if let Command::New { project_name, .. } = &CLI_ARGS.command { new(project_name.to_owned())?; } @@ -35,7 +40,10 @@ fn main() -> anyhow::Result<()> { Ok(()) } +/// Creates a new project directory and enters it. fn new(project_name: String) -> anyhow::Result<()> { + // Because this messes around with the CWD, this should live external to any + // instance of a `WorkspaceHandler`. let cwd = std::env::current_dir()?.join(project_name); std::fs::create_dir(&cwd)?; -- 2.49.1 From 4e961dac405283c9a0dc688b9bcf6c3d1e54390b Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Sun, 22 Feb 2026 13:46:03 -0500 Subject: [PATCH 21/22] Add documentation. --- crates/core/src/workspace.rs | 91 +++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/crates/core/src/workspace.rs b/crates/core/src/workspace.rs index c435729..8ad18d6 100644 --- a/crates/core/src/workspace.rs +++ b/crates/core/src/workspace.rs @@ -14,6 +14,10 @@ use crate::package::PackageHandler; use crate::prey::{F_PREY_LOCK, F_PREY_TOML, Prey}; use crate::{Error, package}; +/// Represents a raven workspace. +/// +/// [`WorkspaceHandler`] manages project compilation, cache writing, +/// and tracking of all packages that make up the workspace. #[derive(Debug)] pub struct WorkspaceHandler { nest: Nest, @@ -26,6 +30,13 @@ impl WorkspaceHandler { const DIR_SRC: &str = "src/"; const DIR_TARGET: &str = "target/"; + /// Creates a new [`WorkspaceHandler`] instance at the provided path. + /// + /// # Errors + /// + /// * [`Error::Io`] if the `project_root` cannot be canonicalized. + /// * [`Error::MissingFileName`] if a name for the workspace cannot be derived + /// from the `project_root` pub fn new>(project_root: P) -> crate::Result { let project_root = project_root.as_ref().canonicalize()?; @@ -42,6 +53,14 @@ impl WorkspaceHandler { }) } + /// Loads an existing workspace from the provided path. + /// + /// # Errors + /// + /// * [`Error::Io`] for any number of IO-related errors. + /// Unwrap the [`std::io::Error`] for further information. + /// * [`Error::MissingFileName`] if a name for the workspace cannot be derived + /// from the `project_root` pub fn load>(project_root: P) -> crate::Result { let project_root = project_root.as_ref().canonicalize()?; @@ -57,6 +76,7 @@ impl WorkspaceHandler { Ok(workspace_manager) } + /// Writes all lock files (Nest.toml, src/**/Prey.toml) to the disk. pub fn write_locks(&self) -> crate::Result<()> { if let Option::Some(lock) = self.nest_lock.clone() { lock.write(self.project_root.join(F_NEST_LOCK))?; @@ -69,6 +89,26 @@ impl WorkspaceHandler { Ok(()) } + /// Initializes a new workspace. + /// + /// # Behaviour + /// + /// Init will avoid overwriting or adding an example project if raven is being integrated into + /// an existing workspace codebase. + /// + /// Init will always write: + /// + /// * Nest.toml + /// * .java-version + /// * Attempt to append to .gitignore + /// + /// If this is an empty workspace, init will include: + /// + /// * Calling `git init` + /// * Writing an example project. + /// * Automatic package discovery. + /// + /// # Errors pub fn init(&mut self) -> crate::Result<&mut Self> { // ORDER MATTERS. let is_empty = read_dir(self.project_root.as_path()).is_ok_and(|tree| tree.count() == 0); @@ -114,7 +154,18 @@ impl WorkspaceHandler { Ok(self) } - // This is the naive build + /// This is a naive build; it attempts to build every source file individually. + /// + /// It calls [`PackageHandler::get_outdated()`] on all known packages to determine + /// compile targets. + /// + /// It will then attempt to write all locks to update the caches and avoid attempting to + /// needlessly recompile targets. + /// + /// # Errors + /// + /// * [`Error::AbsentPrimeError`] + /// * [`Error::Io`] pub fn build(&mut self) -> crate::Result<&mut Self> { let compiler = java::compiler::CompilerBuilder::new() .class_path(Self::DIR_TARGET) @@ -152,6 +203,20 @@ impl WorkspaceHandler { Ok(self) } + /// Attempts to call the JVM to run, in order of precedence: + /// + /// 1. Provided entry point which includes a specific source file. + /// 2. Provided entry point to a package, using that package's default entry point + /// defined in it's `Prey.toml` + /// 3. The workspace's default package defined in `Nest.toml`, and that package's default + /// entry point as defined in it's `Prey.toml`. + /// + /// # Errors + /// + /// * [`Error::UnknownPackage`] if the package cannot be found. + /// * [`Error::UndefinedEntryPoint`] if no fallback entry point can be found. + /// * [`Error::Io`] + /// * [`Error::Java`] pub fn run>( &mut self, entry_point: Option

, @@ -187,6 +252,11 @@ impl WorkspaceHandler { Ok(self) } + /// Cleans the workspace of it's caches: + /// + /// * `target/` + /// * Nest.lock + /// * Prey.lock pub fn clean(&mut self) -> crate::Result<&mut Self> { // Clear Nest.lock if let Err(err) = std::fs::remove_file(self.project_root.join(F_NEST_LOCK)) { @@ -215,7 +285,14 @@ impl WorkspaceHandler { Ok(self) } - /// Add any newly created packages. + /// Scan for newly created packages, wrapping them in [`PackageHandler`]s + /// and adding them to the [`WorkspaceHandler`]'s package map. + /// + /// Packages are identified by their `Prey.toml` manifests. + /// + /// # Errors + /// + /// * [`Error::Io`] fn discover_packages(&mut self) -> crate::Result<()> { // Scan the src/ directory for entries, // filter out the files, @@ -280,10 +357,18 @@ impl WorkspaceHandler { Ok(()) } + /// Writes the [`WorkspaceHandler`]'s `Nest.toml` to disk. fn write_nest(&self) -> crate::Result<()> { Ok(self.nest.write(self.project_root.clone())?) } + /// Writes a `.java-version` file for `jenv` to the disk with an automatically parsed + /// java version from [`java::get_javac_version()`]. + /// + /// # Errors + /// + /// * [`Error::Io`] + /// * [`Error::Java`] fn write_java_version(&self) -> crate::Result<()> { if let Result::Ok(mut f) = OpenOptions::new() .write(true) @@ -296,6 +381,7 @@ impl WorkspaceHandler { Ok(()) } + /// Writes an example project tree to disk. fn write_dir_tree(&self) -> std::io::Result<()> { for dir in [ format!("{}main/java", Self::DIR_SRC), @@ -308,6 +394,7 @@ impl WorkspaceHandler { Ok(()) } + /// Writes an example project to disk. fn write_example_project(&self) -> crate::Result<()> { let main: PathBuf = PathBuf::from(Self::DIR_SRC).join("main/"); let test: PathBuf = PathBuf::from(Self::DIR_SRC).join("test/"); -- 2.49.1 From 3636916ac320c61b108c9b83e5106df56ccf972d Mon Sep 17 00:00:00 2001 From: Olivia Brooks <109807080+Cutieguwu@users.noreply.github.com> Date: Sun, 22 Feb 2026 15:18:09 -0500 Subject: [PATCH 22/22] Add documentation. --- crates/core/src/class.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/core/src/class.rs b/crates/core/src/class.rs index 7f3a71a..accec4e 100644 --- a/crates/core/src/class.rs +++ b/crates/core/src/class.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use crate::{Error, Result}; -/// Data struct +/// [`Class`] represents a source file. It is a handler. #[derive(Debug, Clone, Deserialize, Serialize, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Class { /// Path relative to PACKAGE/java, without file extension. @@ -14,6 +14,13 @@ pub struct Class { } impl Class { + /// Creates a new [`Class`]. + /// + /// # Error + /// + /// * [`Error::MismatchedPackage`] if the provided `file_path` is absolute, and cannot be + /// subtracted to just its relative path within its parent package. + /// * [`Error::Io`] if the source file cannot be loaded and digested. pub fn new>(package_src_root: P, file_path: P) -> Result { let mut file_path = file_path.as_ref().to_path_buf(); if file_path.is_absolute() { @@ -27,6 +34,17 @@ impl Class { }) } + /// Returns a boolean representing if the class is up to date. + /// + /// # Criteria + /// + /// * The class path is local. + /// * The class has been compiled to `target/` + /// * The class' source file has not been updated. + /// + /// # Errors + /// + /// * [`Error::Io`] pub fn is_updated>(&self, class_path: P) -> Result { // If the path is local and that file has not been updated. Ok(class_path @@ -37,6 +55,13 @@ impl Class { && self.checksum == sha256::try_digest(self.path.clone())?) } + /// Updates the class' checksum. + /// + /// Only call this if you know that the class has been compiled successfully. + /// + /// # Errors + /// + /// * [`Error::Io`] if the source file cannot be loaded and digested. pub fn update>(&mut self, package_src_root: P) -> Result<()> { self.checksum = sha256::try_digest(dbg!( package_src_root -- 2.49.1