Skip to content

Commit

Permalink
prune
Browse files Browse the repository at this point in the history
  • Loading branch information
luludotdev committed Mar 11, 2024
1 parent bff7e0d commit 8dd7e5b
Showing 1 changed file with 61 additions and 5 deletions.
66 changes: 61 additions & 5 deletions backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import * as hex from "https://deno.land/std@0.219.0/encoding/hex.ts";
import * as fs from "https://deno.land/std@0.219.0/fs/mod.ts";
import { Command } from "https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts";
import {
ArgumentValue,
Command,
Type,
ValidationError,
} from "https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts";

function command(name: string, ...args: string[]): Promise<Deno.CommandOutput> {
return new Deno.Command(name, { args }).output();
Expand All @@ -12,8 +17,34 @@ function print(encoded: Uint8Array): void {
console.log(new TextDecoder().decode(encoded));
}

class KeepType extends Type<string> {
private readonly units = ["h", "d", "w", "m", "y"];

public parse({ label, name, value }: ArgumentValue): string {
const [end, ...rest] = value.split("").reverse();
const start = rest.reverse().join("");

if (!this.units.includes(end)) {
throw new ValidationError(
`${label} "${name}" has an invalid unit. Allowed values are: ${
this.units.join(", ")
}`,
);
}

const num = Number.parseInt(start, 10);
if (Number.isNaN(num)) {
throw new ValidationError(`${label} "${name}" is invalid.`);
}

const unit = end.replace("h", "H");
return `${num}${unit}`;
}
}

const cli = new Command()
.name("backup")
.type("keep", new KeepType())
.option("-v --verbose", "Enable verbose logging")
.option(
"--no-init",
Expand All @@ -23,13 +54,17 @@ const cli = new Command()
required: true,
})
.option("-R --repo <path:file>", "Path to borg repo", { required: true })
.option("--rclone-remote <remote:string>", "Rclone remote name")
.option("--rclone-root <root:string>", "Rclone remote root directory", {
default: ".",
.option("--no-prune", "Disable automatic archive pruning")
.option("-K --keep <value:keep>", "Timeframe to keep backups for (eg: 7d)", {
required: true,
})
.option("-S --sync", "Sync repo using rclone", {
depends: ["rclone-remote", "rclone-root"],
})
.option("--rclone-remote <remote:string>", "Rclone remote name")
.option("--rclone-root <root:string>", "Rclone remote root directory", {
default: ".",
})
.arguments("<...PATHS>")
.action(async (args, ...paths) => {
const borg = (...args: string[]) => command("borg", ...args);
Expand All @@ -46,11 +81,14 @@ const cli = new Command()
Deno.exit(1);
}

// TODO: Dry-run
const {
verbose,
init,
name,
repo,
prune,
keep,
sync,
} = args;

Expand Down Expand Up @@ -104,7 +142,25 @@ const cli = new Command()

if (verbose) print(resp.stderr);

// TODO: Automatic prune
if (prune) {
const resp = await borg(
"prune",
repo,
"--stats",
"--keep-last=1",
`--keep-within=${keep}`,
);

if (!resp.success) {
console.log("failed to prune backups");
if (verbose) print(resp.stderr);
Deno.exit(1);
}

if (verbose) print(resp.stderr);

// TODO: Detect borg 1.2.x and compact
}

if (sync) {
const { rcloneRoot, rcloneRemote } = args;
Expand Down

0 comments on commit 8dd7e5b

Please sign in to comment.