localbackup
Version:
Utility to make local backups easily and without the hassle.
125 lines (105 loc) • 4.07 kB
text/typescript
import path from 'node:path'
import clear from 'clear'
import chalk from 'chalk'
import boxen from 'boxen'
import yesno from 'yesno'
import dayjs from 'dayjs'
import fse from 'fs-extra'
import { program } from 'commander'
import { DATE_FORMAT } from './constants'
import { createTempBackup } from './createTempBackup'
import { deleteOldBackups } from './deleteOldBackups'
import { storageProvidersNames } from './storageProviders'
import { uploadBackup } from './uploadBackup'
import { deleteTempBackup } from './deleteTempBackup'
clear()
console.log(chalk.green(boxen(chalk.bold('Local Backup 🦄'), { padding: 1, borderStyle: 'double' })))
console.log('')
program
.option('-y, --yes', 'answer yes to all questions', false)
.requiredOption('-s, --source <string>', 'full path of the file or directory to be backed up')
.requiredOption('-d, --destdir <string>', 'full path of the destination directory where the backup file will be stored')
.option('-t, --filetype <string>', 'file type of the backup file (zip or tar)', 'zip')
.option('-p, --prefix <string>', 'prefix to be added to the backup file name', 'backup')
.option('-k, --keeplast <number>', 'number of backups to keep (olders with the same prefix will be deleted)')
.option('-sp, --storageprovider <string>', `storage provider to use (${storageProvidersNames.join(', ')})`, 'local')
// Show help if no arguments are passed
if (process.argv.length < 3) {
program.help()
}
program.parse()
const options = program.opts<{
yes: boolean
source: string
destdir: string
filetype: 'zip' | 'tar'
prefix: string
keeplast: string | undefined
storageprovider: string
}>()
async function main (): Promise<void> {
// Check if the file type is valid
if (!['zip', 'tar'].includes(options.filetype)) {
console.log(chalk.red('\nInvalid file type, please use zip or tar\n'))
return
}
// Check if the storage provider is valid
if (!storageProvidersNames.includes(options.storageprovider)) {
console.log(chalk.red(`\nInvalid storage provider, please use one of the following: ${storageProvidersNames.join(', ')}\n`))
return
}
const source = path.normalize(options.source)
const targetDir = path.normalize(options.destdir)
const destinationFileName = `${options.prefix}-${dayjs().format(DATE_FORMAT)}.${options.filetype}`
const destinationFilePath = path.join(targetDir, destinationFileName)
// Check if the source file/dir exists
if (!fse.existsSync(source)) {
console.log(chalk.red('\nThe source file or directory does not exist\n'))
return
}
console.log(chalk.bold.yellow('You are about to make a backup with the following parameters:'))
console.log('')
console.log(chalk.bold('Source file/dir:'), source)
console.log(chalk.bold('Target directory:'), targetDir)
console.log(chalk.bold('Target file path:'), destinationFilePath)
console.log('')
if (!options.yes) {
const ok = await yesno({
question: 'Are you sure you want to continue? [y/n]:'
})
console.log('')
if (!ok) {
console.log(chalk.red('Aborted!\n'))
return
}
}
// Create local temporal backup
const compressedFilePath = await createTempBackup({
source,
destinationFileName,
fileType: options.filetype
})
// Upload backup to provider
await uploadBackup({
storageProvider: options.storageprovider,
localFilePath: compressedFilePath,
destinationFilePath
})
// Delete temporal backup
await deleteTempBackup({
localFilePath: compressedFilePath
})
// Delete old backups from provider
await deleteOldBackups({
storageProvider: options.storageprovider,
prefix: options.prefix,
targetDirectory: targetDir,
fileType: options.filetype,
keepLast: options.keeplast
})
console.log(chalk.green('\nBackup completed successfully!\n'))
console.log(chalk.bold('Please give this project a star on GitHub if you like it:'))
console.log(chalk.bgBlue.bold('⭐️ https://github.com/eduardolat/localbackup\n'))
}
main().catch(console.error)