Compare commits

..

7 Commits

Author SHA1 Message Date
Ian Wijma 1a1d539e27 Merge pull request 'topic/rust' (#2) from topic/rust into main
Reviewed-on: #2
2023-11-20 13:10:23 +00:00
Ian Wijma b7583f4db0 Update Cargo.toml for optimized release binary
Configured the `Cargo.toml` to automatically strip symbols, optimize for size, enable Link Time Optimization (LTO), and set codegen-units to 1 for the release profile. This significantly reduces the size and improves the performance of the resulting binary.
2023-11-21 00:08:17 +11:00
Ian Wijma 9392325115 Correct commit message for the given diff:
Add newline character to error message

In this commit, a newline character `\n` was added at the end of the error message in the `print!` function within main.rs. This change ensures the output from the program is properly formatted and readable, increasing the overall user experience when such exceptions are encountered.
2023-11-21 00:08:03 +11:00
Ian Wijma a5dd011506 Renamed workflow and adjusted it to handle releases
In this commit, I've renamed the name of the workflow from build.yaml to release.yaml. It now gets triggered on 'release' instead of 'push'. The job names and some parameters were also altered to fit into the new release context. The aim of this modification is to optimize the project delivery process as the workflow is now focus on handling final product releases.
2023-11-21 00:00:05 +11:00
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
10 changed files with 481 additions and 1650 deletions

View File

@ -1,42 +0,0 @@
name: Keep Running
run-name: ${{ gitea.actor }} is running spotify.local CI pipeline 🚀
on: [push]
concurrency: 'true'
jobs:
Build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Building project
run: npm run build
- name: Creating Linux Archive
uses: vimtor/action-zip@v1.1
with:
files: out/kr-linux
dest: linux.zip
- 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

28
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Releasing
run-name: ${{ gitea.actor }} is building a release releasing 🚀
on:
release:
types: [created]
jobs:
release:
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:
- uses: actions/checkout@master
- name: Compile and release
uses: rust-build/rust-build.action@v1.4.4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
RUSTTARGET: ${{ matrix.target }}
ARCHIVE_TYPES: ${{ matrix.archive }}

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"

16
Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[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"] }
[profile.release]
strip = true # Automatically strip symbols from the binary.
opt-level = "z" # Optimize for size.
lto = true
codegen-units = 1

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\n", retry.max_retries, retry.restart_name);
}
}
}
fn restart(retry: &mut Retry) {
sleep(Duration::from_secs(u64::from(retry.restart_delay)));
run_command(retry);
}