Compare commits

..

3 Commits

Author SHA1 Message Date
Ian Wijma 0b686e86d9 Update build.yaml to streamline compilation and packaging process
Keep Running / Build (tar.gz tar.xz tar.zst, x86_64-unknown-linux-musl) (push) Successful in 1m54s Details
Keep Running / Build (zip, x86_64-apple-darwin) (push) Successful in 1m9s Details
Keep Running / Build (zip, x86_64-pc-windows-gnu) (push) Successful in 1m9s Details
This commit simplifies and optimizes the build workflow process by leveraging the rust-build action for compiling and releasing. The "build.yaml" file has been revised to include different targets and types of archives as per the platform. Also, previous separate jobs for checking out, installing dependencies, building project, and creating/uploading archives have been removed. The new strategy is aimed to reduce redundancy, speed up the process, and allow seamless multi-platform build support.
2023-11-20 23:47:04 +11:00
Ian Wijma b0daf0db5f Improve script safety by quoting variables and updating comparisons
This commit updates the `test.sh` script to incorporate best shell scripting practices. Changes include quoting the variables "$SLEEP" and "$EXIT" to handle null or space-containing values better. The arithmetic comparison has been updated to use "bash-style" to improve the script's security. This refactoring aims to enhance the overall efficiency and reliability of the script execution.
2023-11-20 23:40:56 +11:00
Ian Wijma 8581f19127 Remove outdated codebase
This commit deletes the current codebase and configurations because we're switching to rust. This includes src/index.js, package.json, package-lock.json and .gitignore files. A refactor or rewrite app with updated dependencies and code style will be added afterwards.
2023-11-20 23:40:22 +11:00
9 changed files with 464 additions and 1641 deletions

View File

@ -1,42 +1,27 @@
name: Keep Running name: Keep Running
run-name: ${{ gitea.actor }} is running spotify.local CI pipeline 🚀 run-name: ${{ gitea.actor }} is running the Keep Running build process 🚀
on: [push] on: [push]
concurrency: 'true' concurrency: 'true'
jobs: jobs:
Build: Build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-pc-windows-gnu
archive: zip
- target: x86_64-unknown-linux-musl
archive: tar.gz tar.xz tar.zst
- target: x86_64-apple-darwin
archive: zip
steps: steps:
- name: Checkout - uses: actions/checkout@master
uses: actions/checkout@v4 - name: Compile and release
- name: Install dependencies uses: rust-build/rust-build.action@v1.4.4
run: npm ci env:
- name: Building project GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run build
- name: Creating Linux Archive
uses: vimtor/action-zip@v1.1
with: with:
files: out/kr-linux RUSTTARGET: ${{ matrix.target }}
dest: linux.zip ARCHIVE_TYPES: ${{ matrix.archive }}
- name: Upload Linux Archive
uses: actions/upload-artifact@v3
with:
path: linux.zip
- name: Creating MacOS Archive
uses: vimtor/action-zip@v1.1
with:
files: out/kr-macos
dest: macos.zip
- name: Upload MacOS Archive
uses: actions/upload-artifact@v3
with:
path: macos.zip
- name: Creating Windows Archive
uses: vimtor/action-zip@v1.1
with:
files: out/kr-win.exe
dest: windows.zip
- name: Upload Windows Archive
uses: actions/upload-artifact@v3
with:
path: windows.zip

8
.gitignore vendored
View File

@ -1,6 +1,2 @@
.idea/ /target
node_modules/ /.idea
out/
# Random test file...
0

298
Cargo.lock generated Normal file
View File

@ -0,0 +1,298 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "anstyle-parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
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 = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "clap"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"terminal_size",
"unicase",
"unicode-width",
]
[[package]]
name = "clap_derive"
version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "errno"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "kr"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "linux-raw-sys"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustix"
version = "0.38.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
dependencies = [
"bitflags",
"errno",
"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.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "terminal_size"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
dependencies = [
"rustix",
"windows-sys",
]
[[package]]
name = "unicase"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-width"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[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.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
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.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

9
Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "kr"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.8", features = ["derive", "unicode", "wrap_help"] }

View File

@ -1,18 +1,18 @@
#!/bin/bash #!/bin/bash
SLEEP=${1:-'10'} SLEEP=${1:-10}
EXIT=${2:-'0'} EXIT=${2:-0}
echo "Sleeping for $SLEEP seconds..."; echo "Sleeping for $SLEEP seconds...";
sleep $SLEEP; sleep "$SLEEP";
echo "Waking up!"; echo "Waking up!";
if [ $EXIT > 0 ]; then if [ "$EXIT" -gt "0" ]; then
>&2 echo "Exiting with error code $EXIT"; >&2 echo "Exiting with error code $EXIT";
else else
echo "Exiting with error code $EXIT"; echo "Exiting with error code $EXIT";
fi fi
exit $EXIT; exit "$EXIT";

1444
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,30 +0,0 @@
{
"name": "kr",
"version": "1.0.0",
"description": "",
"bin": "src/index.js",
"main": "src/index.js",
"scripts": {
"build": "pkg package.json",
"copy-local": "cp -f out/kr-linux ~/bin/kr",
"build-local": "npm run build && npm run copy-local"
},
"pkg": {
"scripts": "src/**/*.js",
"targets": [
"node18-linux-x64",
"node18-macos-x64",
"node18-win-x64"
],
"outputPath": "out"
},
"author": "Ian Wijma",
"dependencies": {
"pkg": "^5.8.1",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/node": "^20.8.10",
"@types/yargs": "^17.0.29"
}
}

View File

@ -1,123 +0,0 @@
const Yargs = require('yargs');
const {spawn} = require("child_process");
const yargs = Yargs(process.argv.splice(2))
.scriptName('kr')
.usage('kr [args] <process-to-run>')
.help()
.option('_rpm', {
default: 0,
description: 'The amount of Retries Per Minute, before we stop retrying',
type: 'number'
})
.option('_rph', {
default: 0,
description: 'The amount of Retries Per Hour, before we stop retrying',
type: 'number'
})
.option('_delay', {
default: 0,
description: 'Time in seconds we want to delay the restart with.',
type: 'number'
})
const { _ = [], _rpm: rpm, _rph: rph, _delay: delay } = yargs.argv;
const [command, ...args ] = _;
if (!command) {
return yargs.showHelp();
}
const SECONDS_IN_A_MINUTE = 60;
const SECONDS_IN_A_HOUR = 60 * 60;
let historyMax = 4;
let seconds = SECONDS_IN_A_MINUTE;
let restartName = 'minute';
if (rpm && rph) {
return console.error('Currently, can not define both --rpm and --rph, please choose only one.');
} else if (rpm) {
historyMax = rpm
} else if (rph) {
historyMax = rph
seconds = SECONDS_IN_A_HOUR
restartName = 'hour'
}
/** @type {Object<number, string>} */
const history = {};
const getNow = () => Math.ceil(Date.now() / 1000); // Time in seconds
/** @param {string} logs */
const pushHistory = (logs) => history[getNow() + seconds] = logs;
const updateHistory = () => {
const now = getNow();
const clearKeys = Object.keys(history)
.filter((time) => time <= now);
clearKeys.forEach((key) => delete history[key]);
}
const checkHistory = () => Object.keys(history).length <= historyMax;
const restart = () => setTimeout(() => runCommand(delay), delay * 1000);
const spawnCommand = () => {
const [ spawnCommand, ...cmdArgs ] = command.split(' ');
const spawnArgs = [...cmdArgs, ...args];
return spawn(spawnCommand, spawnArgs);
}
const runCommand = () => {
const runner = spawnCommand();
const commandLogs = [];
const pushLog = (logEntry) => commandLogs.push(logEntry);
const trimLog = () => {
if(commandLogs.length > 5000) commandLogs.shift()
};
const clearLogs = () => commandLogs.length = 0;
const getLogs = () => commandLogs.join('\n');
const handleOut = (type, message) => {
pushLog(`[${type}]\t${message}`);
trimLog();
};
const handleExit = (exitCode) => {
if (exitCode === 0) {
console.log(`Exit code: ${exitCode}`);
} else{
console.log(`[CRASH] exit code: ${exitCode}`)
pushHistory(getLogs());
clearLogs();
updateHistory();
if (checkHistory()) {
console.log('Restarting...');
restart();
} else {
console.error(`The process crashed more then ${historyMax} times in the past ${restartName}, stop retrying.`);
console.error(`See below the last crash log:`);
const keys = Object.keys(history);
const lastKey = keys[keys.length-1];
console.log(history[lastKey]);
}
}
}
runner.on('close', (exitCode) => handleExit(exitCode))
runner.stdout.on('data', (data) => console.log(data.toString().trim()))
runner.stdout.on('data', (data) => handleOut('LOG', data.toString().trim()))
runner.stderr.on('data', (data) => handleOut('ERR', data.toString().trim()))
}
// Leggo!~
runCommand();

132
src/main.rs Normal file
View File

@ -0,0 +1,132 @@
use std::process::{Child, Command};
use std::thread::sleep;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use clap::{arg, Parser};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Arguments {
// The amount of times we retry in a span of a minute, before we stop retrying
#[arg(long, default_value_t = 0, conflicts_with = "per_hour")]
per_minute: u8,
// The amount of times we retry in a span of a hour, before we stop retrying
#[arg(long, default_value_t = 0, conflicts_with = "per_minute")]
per_hour: u8,
// The amount of seconds we want to delay the restart with.
#[arg(long, default_value_t = 0)]
delay: u8,
#[arg()]
command: String
}
const SECONDS_IN_A_MINUTE: u16 = 60;
const SECONDS_IN_A_HOUR: u16 = 60 * 60;
struct Retry {
command: String,
history: Vec<u64>,
max_retries: u8,
timespan: u16,
restart_delay: u8,
restart_name: String
}
fn main() {
let arguments = Arguments::parse();
let mut retry: Retry = Retry {
command: arguments.command,
history: Vec::new(),
max_retries: 4,
timespan: SECONDS_IN_A_MINUTE,
restart_delay: arguments.delay,
restart_name: "minute".to_string(),
};
if arguments.per_minute > 0 {
retry.max_retries = arguments.per_minute;
} else if arguments.per_hour > 0 {
retry.max_retries = arguments.per_hour;
retry.timespan = SECONDS_IN_A_HOUR;
retry.restart_name = "hour".to_string();
}
run_command(&mut retry)
}
fn get_now() -> u64 {
return SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
}
fn push_history(retry: &mut Retry) {
retry.history.push(get_now() + u64::from(retry.timespan));
}
fn update_history(retry: &mut Retry) {
let now = get_now();
let clear_times: Vec<u64> = retry
.history
.iter()
.filter(|&time| time <= &now)
.map(|&time| time)
.collect();
for time in clear_times {
retry.history.retain(|&h| h != time);
}
}
fn check_history(retry: &Retry) -> bool {
return retry.history.len().lt(&usize::from(retry.max_retries))
}
fn spawn_process(retry: &Retry) -> std::io::Result<Child> {
let mut command_parts: Vec<String> = retry
.command
.split_whitespace()
.map(|s| s.to_string())
.collect();
let mut command: Command = Command::new(&command_parts[0]);
command_parts.remove(0);
command.args(command_parts);
return command.spawn();
}
fn run_command(retry: &mut Retry) {
let mut process = spawn_process(retry)
.expect("Process failed on startup");
let exit_code = match process.wait() {
Ok(exit_code) => exit_code,
Err(err) => {
eprintln!("Failed to wait for process: {}", err);
return;
}
};
if exit_code.success() {
println!("Exit code: {}", exit_code);
} else {
println!("[CRASH] exit code: {}", exit_code);
push_history(retry);
update_history(retry);
if check_history(retry) {
println!("Restarting...");
restart(retry);
} else {
print!("The process has crashed more then {} times in the past {}, stop restarting", retry.max_retries, retry.restart_name);
}
}
}
fn restart(retry: &mut Retry) {
sleep(Duration::from_secs(u64::from(retry.restart_delay)));
run_command(retry);
}