Merge pull request #23 from shibedrill/update-refactor

Update refactor
This commit is contained in:
August 2025-01-08 22:08:48 -05:00 committed by GitHub
commit 48c02fc837
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 1652 additions and 450 deletions

1944
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ name = "shibe-bot"
description = "A Discord bot written in Rust, using Poise."
license = "MIT"
readme = "README.md"
version = "0.4.2"
version = "1.0.0"
edition = "2021"
build = "build.rs"
@ -23,3 +23,10 @@ serde = { version = "1.0.217", features = ["serde_derive"] }
serde_json = "1.0.134"
roux = "2.2.13"
structstruck = "0.4.1"
reqwest = { version = "0.12.12", features = ["json"] }
octocrab = "0.42.1"
tempfile = "3.15.0"
self-replace = "1.5.0"
zip = "2.2.2"
nix = { version = "0.29.0", features = ["process"] }
minreq = { version = "2.13.0", features = ["https"] }

BIN
artifact.zip Normal file

Binary file not shown.

View File

@ -12,11 +12,19 @@ fn main() -> Result<(), Error> {
.add_instructions(&rustc)?
.emit()?;
let git_commit_id = std::process::Command::new("git")
let git_remote_url = std::process::Command::new("git")
.arg("config")
.arg("remote.origin.url")
.output()?;
let git_commit_id_short = std::process::Command::new("git")
.arg("rev-parse")
.arg("--short")
.arg("HEAD")
.output()?;
let git_commit_id = std::process::Command::new("git")
.arg("rev-parse")
.arg("HEAD")
.output()?;
let git_commit_date = std::process::Command::new("git")
.arg("show")
.arg("-s")
@ -38,10 +46,18 @@ fn main() -> Result<(), Error> {
.arg("--format=%ae")
.output()?;
println!(
"cargo:rustc-env=GIT_REMOTE_URL={}",
String::from_utf8(git_remote_url.stdout)?
);
println!(
"cargo:rustc-env=GIT_COMMIT_ID={}",
String::from_utf8(git_commit_id.stdout)?
);
println!(
"cargo:rustc-env=GIT_COMMIT_ID_SHORT={}",
String::from_utf8(git_commit_id_short.stdout)?
);
println!(
"cargo:rustc-env=GIT_COMMIT_DATE={}",
String::from_utf8(git_commit_date.stdout)?

BIN
shibe-bot Executable file

Binary file not shown.

View File

@ -1,6 +1,17 @@
use std::convert::Infallible;
use std::os::unix::process::CommandExt;
use crate::Context;
use crate::Error;
use octocrab;
use std::io::Write;
use self_replace;
use zip;
use minreq;
/// Print version and build information
#[poise::command(slash_command)]
pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
@ -17,7 +28,7 @@ pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
\tTarget triple: {}\n\
\trustc version: {}\n",
env!("CARGO_PKG_VERSION"),
env!("GIT_COMMIT_ID"),
env!("GIT_COMMIT_ID_SHORT"),
env!("GIT_COMMIT_DATE"),
env!("GIT_COMMIT_AUTHOR_NAME"),
env!("GIT_COMMIT_AUTHOR_EMAIL"),
@ -33,33 +44,37 @@ pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
/// Update the bot remotely (Requires updater systemd service)
#[poise::command(slash_command, owners_only, hide_in_help)]
pub async fn update(ctx: Context<'_>) -> Result<(), Error> {
let command_result = std::process::Command::new("systemctl")
.arg("--user")
.arg("restart")
.arg("shibe-bot-update.service")
.spawn();
match command_result {
Ok(_child) => {
ctx.say(format!(
"Initialized restart service successfully.\n\
Expect brief outage soon.\n\
Current version: {}\n\
Timestamp of last build: {}",
env!("CARGO_PKG_VERSION"),
env!("VERGEN_BUILD_TIMESTAMP")
))
.await?;
info!("Initialized restart service successfully");
}
Err(what) => {
ctx.say(format!(
"Failed to initialize restart service. Reason: {}",
what
))
.await?;
error!("Failed to initialize restart service: {}", what);
pub async fn update(ctx: Context<'_>, override_check: bool) -> Result<(), Error> {
// Check if the current commit hash is different from HEAD
let head: octocrab::models::repos::Ref = octocrab::instance()
.get(
"/repos/shibedrill/shibe-bot/git/refs/heads/main",
None::<&octocrab::models::Repository>,
)
.await?;
if let octocrab::models::repos::Object::Commit { sha, url: _ } = head.object {
if sha == env!("GIT_COMMIT_ID") {
if override_check {
info!("Update unnecessary, but check overridden.");
ctx.say("Update unecessary, but check overridden. Updating.").await?;
let Err(what) = self_update();
error!("Update failed: {}", what);
ctx.say(format!("Error occurred while updating: {}", what))
.await?;
} else {
info!("Update unnecessary: Commit ID of remote is same as compiled commit.");
ctx.say("Update unnecessary.").await?;
}
} else {
info!("Update required, latest commit hash: {}", sha);
let Err(what) = self_update();
error!("Update failed: {}", what);
ctx.say(format!("Error occurred while updating: {}", what))
.await?;
}
} else {
ctx.say("Update failed: Object field in response is not a Commit.").await?;
error!("Checking for updates failed: Response field incorrect type");
}
Ok(())
}
@ -99,3 +114,56 @@ pub async fn say(
ctx.say(what).await?;
Ok(())
}
fn self_update() -> Result<Infallible, Error> {
let artifact_url = "https://nightly.link/shibedrill/shibe-bot/workflows/rust/main/artifact.zip";
let tempdir = tempfile::Builder::new().prefix("shibe-bot").tempdir()?;
trace!("Created tempdir successfully: {}", tempdir.path().display());
let response = minreq::get(artifact_url).send()?;
let mut dest = std::fs::File::create_new(tempdir.path().join("artifact.zip"))?;
let content = response.as_bytes();
dest.write_all(&content)?;
trace!("Downloaded latest build artifact successfully");
let mut archive = zip::ZipArchive::new(dest)?;
trace!("Created zip archive reader");
let mut zipped_bin = archive.by_index(0)?;
let new_bin_path = tempdir.path().join("shibe-bot");
let mut new_bin = std::fs::File::create_new(&new_bin_path)?;
trace!("Created new file for binary");
std::io::copy(&mut zipped_bin, &mut new_bin)?;
trace!("Extracted binary successfully");
self_replace::self_replace(&new_bin_path)?;
trace!("Replaced self with new binary successfully");
let new_command_args: Vec<_> = std::env::args_os().skip(1).collect();
let new_command_path = std::env::current_exe()?;
trace!("Got current executable path successfully: {}", new_command_path.display());
Err(Box::new(
std::process::Command::new(new_command_path)
.args(&new_command_args)
.exec(),
))
}
mod test {
#[cfg(test)]
use std::convert::Infallible;
#[cfg(test)]
use crate::Error;
#[test]
fn test_self_update() -> Result<Infallible, Error> {
use pretty_env_logger;
use crate::command::devel::self_update;
pretty_env_logger::init();
self_update()
}
}

View File

@ -89,11 +89,7 @@ pub async fn curbstomp(
} else if target == **ctx.cache().current_user() {
"nice try lol"
} else {
&format!(
"{} made {} eat pavement.",
ctx.author(),
target
)
&format!("{} made {} eat pavement.", ctx.author(), target)
};
ctx.say(response).await?;
info!("Executed command `whack` successfully");

View File

@ -42,12 +42,13 @@ pub async fn info(ctx: Context<'_>) -> Result<(), Error> {
rustc version: {}\n\
Build timestamp: {}\n\
Website: <https://riverdev.carrd.co>\n\
Source code: <https://github.com/shibedrill/shibe-bot>\n\
Source code: <{}>\n\
Poise: <https://docs.rs/poise/latest/poise/>\n\
Rust: <https://www.rust-lang.org/>",
env!("CARGO_PKG_VERSION"),
env!("VERGEN_RUSTC_SEMVER"),
env!("VERGEN_BUILD_TIMESTAMP"),
env!("GIT_REMOTE_URL"),
))
.await?;
info!("Executed command `info` successfully");