overhaul self-update

This commit is contained in:
August 2025-01-08 21:02:28 -05:00
parent 4d0e68446d
commit 413ebf043b
Signed by: shibedrill
GPG Key ID: 5FE0CB25945EFAA2
6 changed files with 1269 additions and 147 deletions

1298
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -23,3 +23,9 @@ 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"] }

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)?

View File

@ -1,6 +1,15 @@
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;
/// Print version and build information
#[poise::command(slash_command)]
pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
@ -17,7 +26,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"),
@ -34,32 +43,20 @@ 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);
// 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") {
info!("Update unnecessary: Commit ID of remote is same as compiled commit.");
} else {
info!("Update required, latest commit hash: {}", sha);
}
} else {
}
Ok(())
}
@ -99,3 +96,39 @@ pub async fn say(
ctx.say(what).await?;
Ok(())
}
async 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()?;
let response = reqwest::get(artifact_url).await?;
let mut dest = {
let fname = response
.url()
.path_segments()
.and_then(|segments| segments.last())
.and_then(|name| if name.is_empty() { None } else { Some(name) })
.unwrap_or("tmp");
let fname = tempdir.path().join(fname);
std::fs::File::create(fname)?
};
let content = response.bytes().await?;
dest.write_all(&content)?;
let mut archive = zip::ZipArchive::new(dest)?;
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)?;
std::io::copy(&mut zipped_bin, &mut new_bin)?;
self_replace::self_replace(&new_bin_path)?;
let new_command_args: Vec<_> = std::env::args_os().skip(1).collect();
let new_command_path = std::env::current_exe()?;
Err(Box::new(std::process::Command::new(new_command_path)
.args(&new_command_args)
.exec()))
}

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");