diff --git a/src/handlers.ts b/src/handlers.ts index e2411d4..def0e44 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -4,213 +4,233 @@ import { unlinkSync } from 'fs' import { tmpdir } from 'os' import { join, resolve } from 'path' -import { config, CONFIG_FILE, INSTALL_DIR, VERSION } from './autorestic' +import { config, INSTALL_DIR, VERSION } from './autorestic' import { checkAndConfigureBackends, getEnvFromBackend } from './backend' import { backupAll } from './backup' import { Backends, Flags, Locations } from './types' import { - checkIfCommandIsAvailable, - checkIfResticIsAvailable, - downloadFile, - exec, - filterObjectByKey, - singleToArray, + checkIfCommandIsAvailable, + checkIfResticIsAvailable, + downloadFile, + exec, + filterObjectByKey, + singleToArray, } from './utils' -export type Handlers = { [command: string]: (args: string[], flags: Flags) => void } +export type Handlers = { + [command: string]: (args: string[], flags: Flags) => void +} const parseBackend = (flags: Flags): Backends => { - if (!flags.all && !flags.backend) - throw new Error('No backends specified.'.red - + '\n--all [-a]\t\t\t\tCheck all.' - + '\n--backend [-b] myBackend\t\tSpecify one or more backend', - ) - if (flags.all) - return config.backends - else { - const backends = singleToArray(flags.backend) - for (const backend of backends) - if (!config.backends[backend]) - throw new Error('Invalid backend: '.red + backend) - return filterObjectByKey(config.backends, backends) - } + if (!flags.all && !flags.backend) + throw new Error( + 'No backends specified.'.red + + '\n--all [-a]\t\t\t\tCheck all.' + + '\n--backend [-b] myBackend\t\tSpecify one or more backend' + ) + if (flags.all) return config.backends + else { + const backends = singleToArray(flags.backend) + for (const backend of backends) + if (!config.backends[backend]) + throw new Error('Invalid backend: '.red + backend) + return filterObjectByKey(config.backends, backends) + } } const parseLocations = (flags: Flags): Locations => { - if (!flags.all && !flags.location) - throw new Error('No locations specified.'.red - + '\n--all [-a]\t\t\t\tBackup all.' - + '\n--location [-l] site1\t\t\tSpecify one or more locations', - ) + if (!flags.all && !flags.location) + throw new Error( + 'No locations specified.'.red + + '\n--all [-a]\t\t\t\tBackup all.' + + '\n--location [-l] site1\t\t\tSpecify one or more locations' + ) - if (flags.all) { - return config.locations - } else { - const locations = singleToArray(flags.location) - for (const location of locations) - if (!config.locations[location]) - throw new Error('Invalid location: '.red + location) - return filterObjectByKey(config.locations, locations) - } + if (flags.all) { + return config.locations + } else { + const locations = singleToArray(flags.location) + for (const location of locations) + if (!config.locations[location]) + throw new Error('Invalid location: '.red + location) + return filterObjectByKey(config.locations, locations) + } } const handlers: Handlers = { - check(args, flags) { - checkIfResticIsAvailable() - const backends = parseBackend(flags) - checkAndConfigureBackends(backends) - }, - backup(args, flags) { - checkIfResticIsAvailable() - const locations: Locations = parseLocations(flags) + check(args, flags) { + checkIfResticIsAvailable() + const backends = parseBackend(flags) + checkAndConfigureBackends(backends) + }, + backup(args, flags) { + checkIfResticIsAvailable() + const locations: Locations = parseLocations(flags) - const backends = new Set() - for (const to of Object.values(locations).map(location => location.to)) - Array.isArray(to) ? to.forEach(t => backends.add(t)) : backends.add(to) + const backends = new Set() + for (const to of Object.values(locations).map(location => location.to)) + Array.isArray(to) ? to.forEach(t => backends.add(t)) : backends.add(to) - checkAndConfigureBackends(filterObjectByKey(config.backends, Array.from(backends))) - backupAll(locations) + checkAndConfigureBackends( + filterObjectByKey(config.backends, Array.from(backends)) + ) + backupAll(locations) - console.log('\nFinished!'.underline + ' 🎉') - }, - restore(args, flags) { - checkIfResticIsAvailable() - const locations = parseLocations(flags) - for (const [name, location] of Object.entries(locations)) { - const w = new Writer(name.green + `\t\tRestoring... ⏳`) - const env = getEnvFromBackend(config.backends[Array.isArray(location.to) ? location.to[0] : location.to]) + console.log('\nFinished!'.underline + ' 🎉') + }, + restore(args, flags) { + checkIfResticIsAvailable() + const locations = parseLocations(flags) + for (const [name, location] of Object.entries(locations)) { + const w = new Writer(name.green + `\t\tRestoring... ⏳`) + const env = getEnvFromBackend( + config.backends[ + Array.isArray(location.to) ? location.to[0] : location.to + ] + ) - exec( - 'restic', - ['restore', 'latest', '--path', resolve(location.from), ...args], - { env }, - ) - w.done(name.green + '\t\tDone 🎉') - } - }, - exec(args, flags) { - checkIfResticIsAvailable() - const backends = parseBackend(flags) - for (const [name, backend] of Object.entries(backends)) { - console.log(`\n${name}:\n`.grey.underline) - const env = getEnvFromBackend(backend) + exec( + 'restic', + ['restore', 'latest', '--path', resolve(location.from), ...args], + { env } + ) + w.done(name.green + '\t\tDone 🎉') + } + }, + exec(args, flags) { + checkIfResticIsAvailable() + const backends = parseBackend(flags) + for (const [name, backend] of Object.entries(backends)) { + console.log(`\n${name}:\n`.grey.underline) + const env = getEnvFromBackend(backend) - const { out, err } = exec('restic', args, { env }) - console.log(out, err) - } - }, - async install() { - try { - checkIfResticIsAvailable() - console.log('Restic is already installed') - return - } catch (e) { - } + const { out, err } = exec('restic', args, { env }) + console.log(out, err) + } + }, + async install() { + try { + checkIfResticIsAvailable() + console.log('Restic is already installed') + return + } catch (e) {} - const w = new Writer('Checking latest version... ⏳') - checkIfCommandIsAvailable('bzip2') - const { data: json } = await axios({ - method: 'get', - url: 'https://api.github.com/repos/restic/restic/releases/latest', - responseType: 'json', - }) + const w = new Writer('Checking latest version... ⏳') + checkIfCommandIsAvailable('bzip2') + const { data: json } = await axios({ + method: 'get', + url: 'https://api.github.com/repos/restic/restic/releases/latest', + responseType: 'json', + }) - const archMap: { [a: string]: string } = { - 'x32': '386', - 'x64': 'amd64', - } + const archMap: { [a: string]: string } = { + x32: '386', + x64: 'amd64', + } - w.replaceLn('Downloading binary... 🌎') - const name = `${json.name.replace(' ', '_')}_${process.platform}_${archMap[process.arch]}.bz2` - const dl = json.assets.find((asset: any) => asset.name === name) - if (!dl) return console.log( - 'Cannot get the right binary.'.red, - 'Please see https://bit.ly/2Y1Rzai', - ) + w.replaceLn('Downloading binary... 🌎') + const name = `${json.name.replace(' ', '_')}_${process.platform}_${ + archMap[process.arch] + }.bz2` + const dl = json.assets.find((asset: any) => asset.name === name) + if (!dl) + return console.log( + 'Cannot get the right binary.'.red, + 'Please see https://bit.ly/2Y1Rzai' + ) - const tmp = join(tmpdir(), name) - const extracted = tmp.slice(0, -4) //without the .bz2 + const tmp = join(tmpdir(), name) + const extracted = tmp.slice(0, -4) //without the .bz2 - await downloadFile(dl.browser_download_url, tmp) + await downloadFile(dl.browser_download_url, tmp) - // TODO: Native bz2 - // Decompress - w.replaceLn('Decompressing binary... 📦') - exec('bzip2', ['-dk', tmp]) - unlinkSync(tmp) + // TODO: Native bz2 + // Decompress + w.replaceLn('Decompressing binary... 📦') + exec('bzip2', ['-dk', tmp]) + unlinkSync(tmp) - w.replaceLn(`Moving to ${INSTALL_DIR} 🚙`) - exec('chmod', ['+x', extracted]) - exec('mv', [extracted, INSTALL_DIR + '/restic']) + w.replaceLn(`Moving to ${INSTALL_DIR} 🚙`) + exec('chmod', ['+x', extracted]) + exec('mv', [extracted, INSTALL_DIR + '/restic']) - w.done(`\nFinished! restic is installed under: ${INSTALL_DIR}`.underline + ' 🎉') - }, - uninstall() { - for (const bin of ['restic', 'autorestic']) - try { - unlinkSync(INSTALL_DIR + '/' + bin) - console.log(`Finished! ${bin} was uninstalled`) - } catch (e) { - console.log(`${bin} is already uninstalled`.red) - } - }, - async update() { - checkIfResticIsAvailable() - const w = new Writer('Checking for latest restic version... ⏳') - exec('restic', ['self-update']) + w.done( + `\nFinished! restic is installed under: ${INSTALL_DIR}`.underline + ' 🎉' + ) + }, + uninstall() { + for (const bin of ['restic', 'autorestic']) + try { + unlinkSync(INSTALL_DIR + '/' + bin) + console.log(`Finished! ${bin} was uninstalled`) + } catch (e) { + console.log(`${bin} is already uninstalled`.red) + } + }, + async update() { + checkIfResticIsAvailable() + const w = new Writer('Checking for latest restic version... ⏳') + exec('restic', ['self-update']) + w.replaceLn('Checking for latest autorestic version... ⏳') + const { data: json } = await axios({ + method: 'get', + url: + 'https://api.github.com/repos/cupcakearmy/autorestic/releases/latest', + responseType: 'json', + }) - w.replaceLn('Checking for latest autorestic version... ⏳') - const { data: json } = await axios({ - method: 'get', - url: 'https://api.github.com/repos/cupcakearmy/autorestic/releases/latest', - responseType: 'json', - }) + if (json.tag_name != VERSION) { + const platformMap: { [key: string]: string } = { + darwin: 'macos', + } - if (json.tag_name != VERSION) { - const platformMap: { [key: string]: string } = { - 'darwin': 'macos', - } + const name = `autorestic_${platformMap[process.platform] || + process.platform}_${process.arch}` + const dl = json.assets.find((asset: any) => asset.name === name) - const name = `autorestic_${platformMap[process.platform] || process.platform}_${process.arch}` - const dl = json.assets.find((asset: any) => asset.name === name) + const to = INSTALL_DIR + '/autorestic' + w.replaceLn('Downloading binary... 🌎') + await downloadFile(dl.browser_download_url, to) - const to = INSTALL_DIR + '/autorestic' - w.replaceLn('Downloading binary... 🌎') - await downloadFile(dl.browser_download_url, to) + exec('chmod', ['+x', to]) + } - exec('chmod', ['+x', to]) - } - - w.done('All up to date! 🚀') - }, + w.done('All up to date! 🚀') + }, } export const help = () => { - console.log('\nAutorestic'.blue + ` - ${VERSION} - Easy Restic CLI Utility` - + '\n' - + '\nOptions:'.yellow - + `\n -c, --config Specify config file. Default: ${CONFIG_FILE}` - + '\n' - + '\nCommands:'.yellow - + '\n check [-b, --backend] [-a, --all] Check backends' - + '\n backup [-l, --location] [-a, --all] Backup all or specified locations' - + '\n restore [-l, --location] [-- --target ] Check backends' - + '\n' - + '\n exec [-b, --backend] [-a, --all] -- [native options] Execute native restic command' - + '\n' - + '\n install install restic' - + '\n uninstall uninstall restic' - + '\n update update restic' - + '\n help Show help' - + '\n' - + '\nExamples: '.yellow + 'https://git.io/fjVbg' - + '\n', - ) + console.log( + '\nAutorestic'.blue + + ` - ${VERSION} - Easy Restic CLI Utility` + + '\n' + + '\nOptions:'.yellow + + `\n -c, --config Specify config file. Default: .autorestic.yml` + + '\n' + + '\nCommands:'.yellow + + '\n check [-b, --backend] [-a, --all] Check backends' + + '\n backup [-l, --location] [-a, --all] Backup all or specified locations' + + '\n restore [-l, --location] [-- --target ] Restore all or specified locations' + + '\n' + + '\n exec [-b, --backend] [-a, --all] -- [native options] Execute native restic command' + + '\n' + + '\n install install restic' + + '\n uninstall uninstall restic' + + '\n update update restic' + + '\n help Show help' + + '\n' + + '\nExamples: '.yellow + + 'https://git.io/fjVbg' + + '\n' + ) } export const error = () => { - help() - console.log(`Invalid Command:`.red.underline, `${process.argv.slice(2).join(' ')}`) + help() + console.log( + `Invalid Command:`.red.underline, + `${process.argv.slice(2).join(' ')}` + ) } -export default handlers \ No newline at end of file +export default handlers