import colors from 'colors' import { program } from 'commander' import { setCIMode } from 'clitastic' import { unlock, readLock, writeLock, lock } from './lock' import { Config } from './types' import { init } from './config' import info from './handlers/info' import check from './handlers/check' import backup from './handlers/backup' import restore from './handlers/restore' import forget from './handlers/forget' import { cron } from './handlers/cron' import exec from './handlers/exec' import install from './handlers/install' import { uninstall } from './handlers/uninstall' import { upgrade } from './handlers/upgrade' export const VERSION = '0.27' export const INSTALL_DIR = '/usr/local/bin' let requireConfig: boolean = true let error: boolean = false export function hasError() { error = true } process.on('uncaughtException', (err) => { console.log(err.message) unlock() process.exit(1) }) let queue: () => Promise = async () => {} const enqueue = (fn: Function) => (cmd: any) => { queue = async () => fn(cmd.opts()) } program.storeOptionsAsProperties() program.name('autorestic').description('Easy Restic CLI Utility').version(VERSION) program.option('-c, --config ', 'Config file') program.option('-v, --verbose', 'Verbosity', false) program.option('--ci', 'CI Mode. Removes interactivity from the shell', false) program.command('info').action(enqueue(info)) program.on('--help', () => { console.log('') console.log(`${'Docs:'.yellow}\t\thttps://autorestic.vercel.app`) console.log(`${'Examples:'.yellow}\thttps://autorestic.vercel.app/examples`) }) program .command('check') .description('Checks and initializes backend as needed') .option('-b, --backend ') .option('-a, --all') .action(enqueue(check)) program.command('backup').description('Performs a backup').option('-l, --location ').option('-a, --all').action(enqueue(backup)) program .command('restore') .description('Restores data to a specified folder from a location') .requiredOption('-l, --location ') .option('--from ') .requiredOption('--to ', 'Path to save the restored data to') .action(enqueue(restore)) program .command('forget') .description('This will prune and remove data according to your policies') .option('-l, --location ') .option('-a, --all') .option('--dry-run') .action(enqueue(forget)) program .command('cron') .description('Intended to be triggered by an automated system like systemd or crontab.') .option('-a, --all') .action(enqueue(cron)) program .command('exec') .description('Run any native restic command on desired backends') .option('-b, --backend ') .option('-a, --all') .action(({ args, all, backend }) => { queue = async () => exec({ all, backend }, args) }) program.command('install').description('Installs both restic and autorestic to /usr/local/bin').action(enqueue(install)) program.command('uninstall').description('Uninstalls autorestic from the system').action(enqueue(uninstall)) program .command('upgrade') .alias('update') .description('Checks and installs new autorestic versions') .action(() => { requireConfig = false queue = upgrade }) const { verbose, config: configFile, ci } = program.parse(process.argv) export const VERBOSE = verbose export let config: Config setCIMode(ci) if (ci) colors.disable() async function main() { try { if (requireConfig) { config = init(configFile) const { running } = readLock() if (running) { console.log('An instance of autorestic is already running for this config file'.red) process.exit(1) } lock() } await queue() } catch (e) { console.error(e.message) } finally { if (requireConfig) unlock() } if (error) process.exit(1) } main()