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" serde_json = "1.0.134"
roux = "2.2.13" roux = "2.2.13"
structstruck = "0.4.1" 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)? .add_instructions(&rustc)?
.emit()?; .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("rev-parse")
.arg("--short") .arg("--short")
.arg("HEAD") .arg("HEAD")
.output()?; .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") let git_commit_date = std::process::Command::new("git")
.arg("show") .arg("show")
.arg("-s") .arg("-s")
@ -38,10 +46,18 @@ fn main() -> Result<(), Error> {
.arg("--format=%ae") .arg("--format=%ae")
.output()?; .output()?;
println!(
"cargo:rustc-env=GIT_REMOTE_URL={}",
String::from_utf8(git_remote_url.stdout)?
);
println!( println!(
"cargo:rustc-env=GIT_COMMIT_ID={}", "cargo:rustc-env=GIT_COMMIT_ID={}",
String::from_utf8(git_commit_id.stdout)? String::from_utf8(git_commit_id.stdout)?
); );
println!(
"cargo:rustc-env=GIT_COMMIT_ID_SHORT={}",
String::from_utf8(git_commit_id_short.stdout)?
);
println!( println!(
"cargo:rustc-env=GIT_COMMIT_DATE={}", "cargo:rustc-env=GIT_COMMIT_DATE={}",
String::from_utf8(git_commit_date.stdout)? 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::Context;
use crate::Error; use crate::Error;
use octocrab;
use std::io::Write;
use self_replace;
use zip;
/// Print version and build information /// Print version and build information
#[poise::command(slash_command)] #[poise::command(slash_command)]
pub async fn version(ctx: Context<'_>) -> Result<(), Error> { pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
@ -17,7 +26,7 @@ pub async fn version(ctx: Context<'_>) -> Result<(), Error> {
\tTarget triple: {}\n\ \tTarget triple: {}\n\
\trustc version: {}\n", \trustc version: {}\n",
env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_VERSION"),
env!("GIT_COMMIT_ID"), env!("GIT_COMMIT_ID_SHORT"),
env!("GIT_COMMIT_DATE"), env!("GIT_COMMIT_DATE"),
env!("GIT_COMMIT_AUTHOR_NAME"), env!("GIT_COMMIT_AUTHOR_NAME"),
env!("GIT_COMMIT_AUTHOR_EMAIL"), 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) /// Update the bot remotely (Requires updater systemd service)
#[poise::command(slash_command, owners_only, hide_in_help)] #[poise::command(slash_command, owners_only, hide_in_help)]
pub async fn update(ctx: Context<'_>) -> Result<(), Error> { pub async fn update(ctx: Context<'_>) -> Result<(), Error> {
let command_result = std::process::Command::new("systemctl") // Check if the current commit hash is different from HEAD
.arg("--user") let head: octocrab::models::repos::Ref = octocrab::instance()
.arg("restart") .get(
.arg("shibe-bot-update.service") "/repos/shibedrill/shibe-bot/git/refs/heads/main",
.spawn(); None::<&octocrab::models::Repository>,
match command_result { )
Ok(_child) => { .await?;
ctx.say(format!( if let octocrab::models::repos::Object::Commit { sha, url: _ } = head.object {
"Initialized restart service successfully.\n\ if sha == env!("GIT_COMMIT_ID") {
Expect brief outage soon.\n\ info!("Update unnecessary: Commit ID of remote is same as compiled commit.");
Current version: {}\n\ } else {
Timestamp of last build: {}", info!("Update required, latest commit hash: {}", sha);
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);
} }
} else {
} }
Ok(()) Ok(())
} }
@ -99,3 +96,39 @@ pub async fn say(
ctx.say(what).await?; ctx.say(what).await?;
Ok(()) 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() { } else if target == **ctx.cache().current_user() {
"nice try lol" "nice try lol"
} else { } else {
&format!( &format!("{} made {} eat pavement.", ctx.author(), target)
"{} made {} eat pavement.",
ctx.author(),
target
)
}; };
ctx.say(response).await?; ctx.say(response).await?;
info!("Executed command `whack` successfully"); info!("Executed command `whack` successfully");

View File

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