Compare commits

...

13 Commits

Author SHA1 Message Date
Jef Roosens 3c846f7b2c
chore: update changelog
ci/woodpecker/push/build unknown status Details
ci/woodpecker/push/clippy unknown status Details
ci/woodpecker/push/lint unknown status Details
ci/woodpecker/push/release Pipeline is pending Details
ci/woodpecker/tag/release Pipeline is pending Details
ci/woodpecker/tag/lint Pipeline was successful Details
ci/woodpecker/tag/clippy Pipeline was successful Details
ci/woodpecker/tag/build Pipeline was successful Details
2023-06-05 10:41:55 +02:00
Jef Roosens 3782d3af2e
feat(ci): add release config
ci/woodpecker/push/release unknown status Details
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline was successful Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-05 10:32:50 +02:00
Jef Roosens bef9698fc1
feat: add env vars for flags
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline was successful Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-05 10:06:50 +02:00
Jef Roosens f083d7e701
feat: ability to disable backup thread
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-04 08:57:31 +02:00
Jef Roosens 3c5cdaef4f
chore: started changelog 2023-06-04 08:55:31 +02:00
Jef Roosens 49546a449e
feat: add periodic backups thread
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-03 23:36:43 +02:00
Jef Roosens 7248ea8b90
fix(ci): add build-base to build steps
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-03 17:40:57 +02:00
Jef Roosens d0321f7ed1
feat: started cli interface
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline failed Details
2023-06-03 15:59:47 +02:00
Jef Roosens c5b579b8db
fix(ci): use alpine image for builds
ci/woodpecker/push/lint Pipeline was successful Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details
2023-06-03 15:03:41 +02:00
Jef Roosens ec64638159
chore: add woodpecker config
ci/woodpecker/push/lint Pipeline failed Details
ci/woodpecker/push/clippy Pipeline failed Details
ci/woodpecker/push/build Pipeline failed Details
2023-06-03 15:01:17 +02:00
Jef Roosens 826565dbae
feat: some improvements 2023-06-03 14:18:39 +02:00
Jef Roosens d176fac420
refactor: split process into own module 2023-06-03 12:20:15 +02:00
Jef Roosens c177c04a74
chore: updated deps; renamed project to alex 2023-06-03 10:17:08 +02:00
14 changed files with 1095 additions and 72 deletions

View File

@ -0,0 +1,2 @@
[alias]
runs = "run -- paper 1.19.4-545 --config data/config --backup data/backups --world data/worlds data/paper-1.19.4-545.jar"

6
.gitignore vendored
View File

@ -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,3 +16,7 @@ Cargo.lock
# Added by cargo
/target
# testing files
*.jar
data/

View File

@ -0,0 +1,19 @@
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 ]'

View File

@ -0,0 +1,11 @@
platform: 'linux/amd64'
branches:
exclude: [main]
pipeline:
clippy:
image: 'rust:1.70'
commands:
- rustup component add clippy
- cargo clippy -- --no-deps -Dwarnings

View File

@ -0,0 +1,11 @@
platform: 'linux/amd64'
branches:
exclude: [main]
pipeline:
lint:
image: 'rust:1.70'
commands:
- rustup component add rustfmt
- cargo fmt -- --check

View File

@ -0,0 +1,33 @@
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

17
CHANGELOG.md 100644
View File

@ -0,0 +1,17 @@
# 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

601
Cargo.lock generated 100644
View File

@ -0,0 +1,601 @@
# 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",
]

View File

@ -1,19 +1,23 @@
[package]
name = "mc-wrapper"
name = "alex"
version = "0.1.0"
edition = "2018"
description = "Wrapper around Minecraft server processes, designed to complement Docker image installations."
authors = ["Jef Roosens"]
edition = "2021"
# 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.37"
tar = "0.4.38"
# Used to compress said tarballs using gzip
flate2 = "1.0.21"
flate2 = "1.0.26"
# Used for backup filenames
chrono = "0.4.19"
chrono = "0.4.26"
clap = { version = "4.3.1", features = ["derive", "env"] }
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
strip = true

View File

@ -1,18 +1,98 @@
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<PathBuf>,
/// Directory where world files will be saved [default: ../worlds]
#[arg(long, value_name = "WORLD_DIR", env = "ALEX_WORLD_DIR")]
world: Option<PathBuf>,
/// Directory where backups will be stored [default: ../backups]
#[arg(long, value_name = "BACKUP_DIR", env = "ALEX_WORLD_DIR")]
backup: Option<PathBuf>,
/// 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<Mutex<server::ServerProcess>>, 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 mut server = server::Server::spawn();
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 stdin = io::stdin();
let input = &mut String::new();
loop {
input.clear();
stdin.read_line(input);
println!("input: {}", input.trim());
server.send_command(input);
if stdin.read_line(input).is_err() {
continue;
};
{
let mut server = counter.lock().unwrap();
if let Err(e) = server.send_command(input) {
println!("{}", e);
};
}
if input.trim() == "stop" {
break;

View File

@ -1,60 +0,0 @@
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");
}
}

View File

@ -0,0 +1,137 @@
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<T: AsRef<Path>>(mut self, path: T) -> Self {
self.jar = PathBuf::from(path.as_ref());
self
}
pub fn config<T: AsRef<Path>>(mut self, path: T) -> Self {
self.config_dir = PathBuf::from(path.as_ref());
self
}
pub fn world<T: AsRef<Path>>(mut self, path: T) -> Self {
self.world_dir = PathBuf::from(path.as_ref());
self
}
pub fn backup<T: AsRef<Path>>(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<ServerProcess> {
// 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,
))
}
}

View File

@ -0,0 +1,5 @@
mod command;
mod process;
pub use command::{ServerCommand, ServerType};
pub use process::ServerProcess;

View File

@ -0,0 +1,159 @@
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::<Vec<PathBuf>>();
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(())
}
}