diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index 52f99fb..0000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[alias] -runs = "run -- paper 1.19.4-545 --config data/config --backup data/backups --world data/worlds data/paper-1.19.4-545.jar" diff --git a/.gitignore b/.gitignore index 4259b1b..d1bb021 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ target/ # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html -#Cargo.lock +Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk @@ -16,7 +16,3 @@ target/ # Added by cargo /target - -# testing files -*.jar -data/ diff --git a/.woodpecker/build.yml b/.woodpecker/build.yml deleted file mode 100644 index 1073cc7..0000000 --- a/.woodpecker/build.yml +++ /dev/null @@ -1,19 +0,0 @@ -matrix: - ARCH: - - 'amd64' - - 'arm64' - -platform: "linux/${ARCH}" - -branches: - exclude: [main] - -pipeline: - build: - image: 'rust:1.70-alpine3.18' - commands: - - apk add --no-cache build-base - - cargo build --verbose - - cargo test --verbose - # Binaries, even debug ones, should be statically compiled - - '[ "$(readelf -d target/debug/alex | grep NEEDED | wc -l)" = 0 ]' diff --git a/.woodpecker/clippy.yml b/.woodpecker/clippy.yml deleted file mode 100644 index 44a4b69..0000000 --- a/.woodpecker/clippy.yml +++ /dev/null @@ -1,11 +0,0 @@ -platform: 'linux/amd64' - -branches: - exclude: [main] - -pipeline: - clippy: - image: 'rust:1.70' - commands: - - rustup component add clippy - - cargo clippy -- --no-deps -Dwarnings diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml deleted file mode 100644 index 66d066f..0000000 --- a/.woodpecker/lint.yml +++ /dev/null @@ -1,11 +0,0 @@ -platform: 'linux/amd64' - -branches: - exclude: [main] - -pipeline: - lint: - image: 'rust:1.70' - commands: - - rustup component add rustfmt - - cargo fmt -- --check diff --git a/.woodpecker/release.yml b/.woodpecker/release.yml deleted file mode 100644 index 5c4954c..0000000 --- a/.woodpecker/release.yml +++ /dev/null @@ -1,33 +0,0 @@ -matrix: - PLATFORM: - - 'linux/amd64' - # - 'linux/arm64' - -platform: $PLATFORM -branches: [ main ] - -pipeline: - build: - image: 'rust:1.70-alpine3.18' - commands: - - apk add --no-cache build-base - - cargo build --release --verbose - # Ensure the release binary is also statically compiled - - '[ "$(readelf -d target/release/alex | grep NEEDED | wc -l)" = 0 ]' - - du -h target/release/alex - - mv target/release/alex target/release/alex-$(echo '${PLATFORM}' | sed 's:/:-:g')" - when: - event: tag - - publish: - image: 'plugins/gitea-release' - secrets: - - gitea_release_api_key - settings: - base_url: https://git.rustybever.be - files: target/release/alex-* - checksum: - - sha256 - title: ${CI_COMMIT_TAG} - when: - event: tag diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index fa75097..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,17 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) - -## [0.1.0](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.1.0) - -### Added - -* CLI interface -* Working backup command -* Thread for periodic backups -* Env var support diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 5953204..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,601 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "alex" -version = "0.1.0" -dependencies = [ - "chrono", - "clap", - "flate2", - "tar", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" - -[[package]] -name = "anstyle-parse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "time", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "clap" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28" -dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", -] - -[[package]] -name = "clap_builder" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" -dependencies = [ - "anstream", - "anstyle", - "bitflags", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "filetime" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys", -] - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys", -] - -[[package]] -name = "js-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.144" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "log" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" - -[[package]] -name = "proc-macro2" -version = "1.0.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rustix" -version = "0.37.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi", - "winapi", -] - -[[package]] -name = "unicode-ident" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" - -[[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" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "xattr" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" -dependencies = [ - "libc", -] diff --git a/Cargo.toml b/Cargo.toml index dd2f79b..279ad89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,19 @@ [package] -name = "alex" +name = "mc-wrapper" version = "0.1.0" -description = "Wrapper around Minecraft server processes, designed to complement Docker image installations." -authors = ["Jef Roosens"] -edition = "2021" +edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] # Used for creating tarballs for backups -tar = "0.4.38" +tar = "0.4.37" # Used to compress said tarballs using gzip -flate2 = "1.0.26" +flate2 = "1.0.21" # Used for backup filenames -chrono = "0.4.26" -clap = { version = "4.3.1", features = ["derive", "env"] } +chrono = "0.4.19" [profile.release] lto = "fat" codegen-units = 1 panic = "abort" -strip = true diff --git a/src/main.rs b/src/main.rs index 05a6d96..f5cd3e5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,98 +1,18 @@ +use std::io; + mod server; -use clap::Parser; -use server::ServerType; -use std::io; -use std::path::PathBuf; -use std::sync::{Arc, Mutex}; - -#[derive(Parser)] -#[command(author, version, about, long_about = None)] -struct Cli { - /// Type of server - type_: ServerType, - /// Version string for the server, e.g. 1.19.4-545 - server_version: String, - /// Server jar to execute - jar: PathBuf, - - /// Directory where configs are stored, and where the server will run [default: .] - #[arg(long, value_name = "CONFIG_DIR", env = "ALEX_CONFIG_DIR")] - config: Option, - /// Directory where world files will be saved [default: ../worlds] - #[arg(long, value_name = "WORLD_DIR", env = "ALEX_WORLD_DIR")] - world: Option, - /// Directory where backups will be stored [default: ../backups] - #[arg(long, value_name = "BACKUP_DIR", env = "ALEX_WORLD_DIR")] - backup: Option, - /// Java command to run the server jar with - #[arg(long, value_name = "JAVA_CMD", default_value_t = String::from("java"), env = "ALEX_JAVA")] - java: String, - - /// XMS value in megabytes for the server instance - #[arg(long, default_value_t = 1024, env = "ALEX_XMS")] - xms: u64, - /// XMX value in megabytes for the server instance - #[arg(long, default_value_t = 2048, env = "ALEX_XMX")] - xmx: u64, - - /// How many backups to keep - #[arg(short = 'n', long, default_value_t = 7, env = "ALEX_MAX_BACKUPS")] - max_backups: u64, - /// How frequently to perform a backup, in minutes; 0 to disable. - #[arg(short = 't', long, default_value_t = 0, env = "ALEX_FREQUENCY")] - frequency: u64, -} - -fn backups_thread(counter: Arc>, frequency: u64) { - loop { - std::thread::sleep(std::time::Duration::from_secs(frequency * 60)); - - { - let mut server = counter.lock().unwrap(); - - // We explicitely ignore the error here, as we don't want the thread to fail - let _ = server.backup(); - } - } -} - fn main() { - let cli = Cli::parse(); - - let cmd = server::ServerCommand::new(cli.type_, &cli.server_version) - .java(&cli.java) - .jar(cli.jar) - .config(cli.config.unwrap_or(".".into())) - .world(cli.world.unwrap_or("../worlds".into())) - .backup(cli.backup.unwrap_or("../backups".into())) - .xms(cli.xms) - .xmx(cli.xmx) - .max_backups(cli.max_backups); - let counter = Arc::new(Mutex::new(cmd.spawn().expect("Failed to start server."))); - - if cli.frequency > 0 { - let clone = Arc::clone(&counter); - std::thread::spawn(move || backups_thread(clone, cli.frequency)); - } + let mut server = server::Server::spawn(); let stdin = io::stdin(); let input = &mut String::new(); loop { input.clear(); - - if stdin.read_line(input).is_err() { - continue; - }; - - { - let mut server = counter.lock().unwrap(); - - if let Err(e) = server.send_command(input) { - println!("{}", e); - }; - } + stdin.read_line(input); + println!("input: {}", input.trim()); + server.send_command(input); if input.trim() == "stop" { break; diff --git a/src/server.rs b/src/server.rs new file mode 100644 index 0000000..1e8db39 --- /dev/null +++ b/src/server.rs @@ -0,0 +1,60 @@ +use std::io; +use std::io::Write; +use std::process::{Child, Command, Stdio}; +use std::fs::File; +use flate2::Compression; +use flate2::write::GzEncoder; + +pub struct Server { + child: Child, +} + +impl Server { + pub fn spawn() -> Server { + let child = Command::new("/usr/lib/jvm/java-16-openjdk/bin/java") + .arg("-jar") + .arg("paper-1.17.1-259.jar") + .arg("--universe") + .arg("worlds") + .arg("--nogui") + .stdin(Stdio::piped()) + .spawn() + .expect("Couldn't start child process"); + + Server { child } + } + + pub fn send_command(&mut self, cmd: &str) { + match cmd.trim() { + "stop" | "exit" => self.stop(), + "backup" => self.backup(), + s => self.custom(s), + } + } + + fn custom(&mut self, cmd: &str) { + let mut stdin = self.child.stdin.as_ref().unwrap(); + stdin.write_all(format!("{}\n", cmd.trim()).as_bytes()).unwrap(); + stdin.flush().unwrap(); + } + + pub fn stop(&mut self) { + self.custom("stop"); + self.child.wait(); + } + + pub fn backup(&mut self) { + // Make sure the server isn't modifying the files during the backup + self.custom("save-off"); + self.custom("save-all"); + + // Create a gzip-compressed tarball of the worlds folder + let filename = format!("{}", chrono::offset::Local::now().format("backups/%Y-%m-%d_%H-%M-%S.tar.gz")); + let tar_gz = std::fs::File::create(filename).unwrap(); + let enc = GzEncoder::new(tar_gz, Compression::default()); + let mut tar = tar::Builder::new(enc); + tar.append_dir_all("worlds", "worlds").unwrap(); + + self.custom("save-on"); + } +} diff --git a/src/server/command.rs b/src/server/command.rs deleted file mode 100644 index e774bb5..0000000 --- a/src/server/command.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::server::ServerProcess; -use clap::ValueEnum; -use std::fmt; -use std::fs::File; -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -pub enum ServerType { - Paper, - Forge, - Vanilla, -} - -impl fmt::Display for ServerType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - ServerType::Paper => "PaperMC", - ServerType::Forge => "Forge", - ServerType::Vanilla => "Vanilla", - }; - - write!(f, "{}", s) - } -} - -pub struct ServerCommand { - type_: ServerType, - version: String, - java: String, - jar: PathBuf, - config_dir: PathBuf, - world_dir: PathBuf, - backup_dir: PathBuf, - xms: u64, - xmx: u64, - max_backups: u64, -} - -impl ServerCommand { - pub fn new(type_: ServerType, version: &str) -> Self { - ServerCommand { - type_, - version: String::from(version), - java: String::from("java"), - jar: PathBuf::from("server.jar"), - config_dir: PathBuf::from("config"), - world_dir: PathBuf::from("worlds"), - backup_dir: PathBuf::from("backups"), - xms: 1024, - xmx: 2048, - max_backups: 7, - } - } - - pub fn java(mut self, java: &str) -> Self { - self.java = String::from(java); - - self - } - - pub fn jar>(mut self, path: T) -> Self { - self.jar = PathBuf::from(path.as_ref()); - self - } - - pub fn config>(mut self, path: T) -> Self { - self.config_dir = PathBuf::from(path.as_ref()); - self - } - - pub fn world>(mut self, path: T) -> Self { - self.world_dir = PathBuf::from(path.as_ref()); - self - } - - pub fn backup>(mut self, path: T) -> Self { - self.backup_dir = PathBuf::from(path.as_ref()); - - self - } - - pub fn xms(mut self, v: u64) -> Self { - self.xms = v; - self - } - - pub fn xmx(mut self, v: u64) -> Self { - self.xmx = v; - self - } - - pub fn max_backups(mut self, v: u64) -> Self { - self.max_backups = v; - self - } - - fn accept_eula(&self) -> std::io::Result<()> { - let mut eula_path = self.config_dir.clone(); - eula_path.push("eula.txt"); - let mut eula_file = File::create(eula_path)?; - eula_file.write_all(b"eula=true")?; - - Ok(()) - } - - pub fn spawn(self) -> std::io::Result { - // To avoid any issues, we use absolute paths for everything when spawning the process - let jar = self.jar.canonicalize()?; - let config_dir = self.config_dir.canonicalize()?; - let world_dir = self.world_dir.canonicalize()?; - let backup_dir = self.backup_dir.canonicalize()?; - - self.accept_eula()?; - - let child = Command::new(&self.java) - .current_dir(&config_dir) - .arg("-jar") - .arg(&jar) - .arg("--universe") - .arg(&world_dir) - .arg("--nogui") - .stdin(Stdio::piped()) - .spawn()?; - - Ok(ServerProcess::new( - self.type_, - self.version, - config_dir, - world_dir, - backup_dir, - self.max_backups, - child, - )) - } -} diff --git a/src/server/mod.rs b/src/server/mod.rs deleted file mode 100644 index e3e3131..0000000 --- a/src/server/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod command; -mod process; - -pub use command::{ServerCommand, ServerType}; -pub use process::ServerProcess; diff --git a/src/server/process.rs b/src/server/process.rs deleted file mode 100644 index 2b6f6fa..0000000 --- a/src/server/process.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::server::ServerType; -use flate2::write::GzEncoder; -use flate2::Compression; -use std::io::Write; -use std::path::PathBuf; -use std::process::Child; - -#[link(name = "c")] -extern "C" { - fn geteuid() -> u32; - fn getegid() -> u32; -} - -pub struct ServerProcess { - type_: ServerType, - version: String, - config_dir: PathBuf, - world_dir: PathBuf, - backup_dir: PathBuf, - max_backups: u64, - child: Child, -} - -impl ServerProcess { - pub fn new( - type_: ServerType, - version: String, - config_dir: PathBuf, - world_dir: PathBuf, - backup_dir: PathBuf, - max_backups: u64, - child: Child, - ) -> ServerProcess { - ServerProcess { - type_, - version, - config_dir, - world_dir, - backup_dir, - max_backups, - child, - } - } - - pub fn send_command(&mut self, cmd: &str) -> std::io::Result<()> { - match cmd.trim() { - "stop" | "exit" => self.stop()?, - "backup" => self.backup()?, - s => self.custom(s)?, - } - - Ok(()) - } - - fn custom(&mut self, cmd: &str) -> std::io::Result<()> { - let mut stdin = self.child.stdin.as_ref().unwrap(); - stdin.write_all(format!("{}\n", cmd.trim()).as_bytes())?; - stdin.flush()?; - - Ok(()) - } - - pub fn stop(&mut self) -> std::io::Result<()> { - self.custom("stop")?; - self.child.wait()?; - - Ok(()) - } - - /// Perform a backup by disabling the server's save feature and flushing its data, before - /// creating an archive file. - pub fn backup(&mut self) -> std::io::Result<()> { - self.custom("say backing up server")?; - - // Make sure the server isn't modifying the files during the backup - self.custom("save-off")?; - self.custom("save-all")?; - - // TODO implement a better mechanism - // We wait some time to (hopefully) ensure the save-all call has completed - std::thread::sleep(std::time::Duration::from_secs(10)); - - let res = self.create_backup_archive(); - - if res.is_ok() { - self.remove_old_backups()?; - } - - // The server's save feature needs to be enabled again even if the archive failed to create - self.custom("save-on")?; - - self.custom("say server backed up successfully")?; - - res - } - - /// Create a new compressed backup archive of the server's data. - fn create_backup_archive(&mut self) -> std::io::Result<()> { - // Create a gzip-compressed tarball of the worlds folder - let filename = format!( - "{}", - chrono::offset::Local::now().format("%Y-%m-%d_%H-%M-%S.tar.gz") - ); - let path = self.backup_dir.join(filename); - let tar_gz = std::fs::File::create(path)?; - let enc = GzEncoder::new(tar_gz, Compression::default()); - let mut tar = tar::Builder::new(enc); - - tar.append_dir_all("worlds", &self.world_dir)?; - - // We don't store all files in the config, as this would include caches - tar.append_path_with_name( - self.config_dir.join("server.properties"), - "config/server.properties", - )?; - - // We add a file to the backup describing for what version it was made - let info = format!("{} {}", self.type_, self.version); - let info_bytes = info.as_bytes(); - - let mut header = tar::Header::new_gnu(); - header.set_size(info_bytes.len().try_into().unwrap()); - header.set_mode(0o100644); - unsafe { - header.set_gid(getegid().into()); - header.set_uid(geteuid().into()); - } - - tar.append_data(&mut header, "info.txt", info_bytes)?; - - // tar.append_dir_all("config", &self.config_dir)?; - - // Backup file gets finalized in the drop - - Ok(()) - } - - /// Remove the oldest backups - fn remove_old_backups(&mut self) -> std::io::Result<()> { - // The naming format used allows us to sort the backups by name and still get a sorting by - // creation time - let mut backups = std::fs::read_dir(&self.backup_dir)? - .filter_map(|res| res.map(|e| e.path()).ok()) - .collect::>(); - backups.sort(); - - let max_backups: usize = self.max_backups.try_into().unwrap(); - - if backups.len() > max_backups { - let excess_backups = backups.len() - max_backups; - - for backup in &backups[0..excess_backups] { - std::fs::remove_file(backup)?; - } - } - - Ok(()) - } -}