import aws.sdk.kotlin.services.s3.S3Client import backup.BackupClient import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.subcommands import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.help import com.github.ajalt.clikt.parameters.types.file import kotlinx.coroutines.runBlocking import kotlin.system.exitProcess fun main(args: Array) = runBlocking { S3Client.fromEnvironment().use { s3 -> S3BackupTool() .subcommands( Create(s3), Restore(s3), RestoreFile(s3), ) .main(args) } } class S3BackupTool : CliktCommand( help = "A simple AWS S3 backup tool. This tool assumes credentials are properly configured using aws-cli.", ) { override fun run() { shortHelp(currentContext) } } class Create(val s3: S3Client) : CliktCommand( help = "Create a backup of a file or directory.", ) { val source by argument().file(mustExist = true).help("File or directory to backup") val bucket by argument().help("Name of S3 bucket to backup to") override fun run() = runBlocking { val backupKey = BackupClient(s3, bucket).upload(source) echo("Successfully created backup with key '$backupKey'") } } class Restore(val s3: S3Client) : CliktCommand( help = "Restore a backup from AWS S3.", ) { val bucket by argument().help("Name of S3 bucket to restore the backup from") val backupKey by argument().help("The S3 key of the backup to restore") val destination by argument().file(mustExist = true).help("Directory to restore to") override fun run() = runBlocking { if (!destination.isDirectory) { echo("Destination must be an existing directory", err = true) exitProcess(1) } BackupClient(s3, bucket).restore(destination.toPath(), backupKey) echo("Successfully restored backup '$backupKey' to '$destination'") } } class RestoreFile(val s3: S3Client) : CliktCommand( help = "Restore a single file from a backup from AWS S3.", ) { val bucket by argument().help("Name of S3 bucket to restore the backup from") val backupKey by argument().help("The S3 key of the backup to restore") val filePath by argument().help("File path within the backup") val destination by argument().file(mustExist = true).help("Directory to restore to") override fun run() = runBlocking { if (!destination.isDirectory) { echo("Destination must be an existing directory", err = true) exitProcess(1) } BackupClient(s3, bucket).restoreFile(destination.toPath(), backupKey, filePath) echo("Successfully restored '$filePath' from backup '$backupKey' to '$destination'") } }