diff --git a/src/dda/backup/backup.clj b/src/dda/backup/backup.clj index 6c2eb7a..0664495 100644 --- a/src/dda/backup/backup.clj +++ b/src/dda/backup/backup.clj @@ -2,6 +2,22 @@ (:require [orchestra.core :refer [defn-spec]] [clojure.spec.alpha :as s] - [dda.backup.core :as core] - [dda.backup.management.domain :as domain] - [dda.backup.infrastructure :as i])) \ No newline at end of file + [dda.backup.core.domain :as core] + [dda.backup.backup.domain :as domain] + [dda.backup.management :as mgm] + [dda.backup.infrastructure :as i])) + +(s/def ::config + (s/keys :req-un [::core/restic-repository ::core/backup-path] + :opt-un [::core/certificate-file ::core/directory ::core/debug ::core/dry-run])) + +(defn-spec backup! nil? + [config ::config + files (s/* string?)] + (let [config-w-defaults (merge core/default config)] + (mgm/unlock! config-w-defaults) + (i/execute! + (domain/backup-files-command config-w-defaults files) + config-w-defaults) + (mgm/forget! config-w-defaults) + )) \ No newline at end of file diff --git a/src/dda/backup/backup/domain.clj b/src/dda/backup/backup/domain.clj new file mode 100644 index 0000000..ef57c5e --- /dev/null +++ b/src/dda/backup/backup/domain.clj @@ -0,0 +1,11 @@ +(ns dda.backup.backup.domain + (:require + [orchestra.core :refer [defn-spec]] + [clojure.spec.alpha :as s] + [dda.backup.core.domain :as core])) + +(defn-spec backup-files-command ::core/commands + [config ::core/config + files (s/* string?)] + (let [{:keys [certificate-file password-file restic-repository backup-path]} config] + (core/repo-command config (into ["backup"] files)))) diff --git a/src/dda/backup/core.clj b/src/dda/backup/core.clj index 9f7b290..aa8359b 100644 --- a/src/dda/backup/core.clj +++ b/src/dda/backup/core.clj @@ -3,13 +3,10 @@ [orchestra.core :refer [defn-spec]] )) -(s/def ::command (s/cat - :app string? - :params (s/* string?))) -(s/def ::commands (s/coll-of ::command)) - (s/def ::dry-run boolean?) (s/def ::debug boolean?) (def default {:dry-run false - :debug false}) \ No newline at end of file + :debug false + :days-to-keep 30 + :months-to-keep 12}) \ No newline at end of file diff --git a/src/dda/backup/core/domain.clj b/src/dda/backup/core/domain.clj new file mode 100644 index 0000000..e841aba --- /dev/null +++ b/src/dda/backup/core/domain.clj @@ -0,0 +1,41 @@ +(ns dda.backup.core.domain + (:require + [orchestra.core :refer [defn-spec]] + [clojure.spec.alpha :as s])) + +(s/def ::command (s/cat + :app string? + :params (s/* string?))) +(s/def ::commands (s/coll-of ::command)) + +(s/def ::certificate-file string?) +(s/def ::password-file string?) +(s/def ::restic-repository string?) +(s/def ::backup-path string?) +(s/def ::directory string?) +(s/def ::days-to-keep pos?) +(s/def ::months-to-keep pos?) + +(s/def ::config + (s/keys :req-un [::restic-repository ::backup-path ::days-to-keep ::months-to-keep] + :opt-un [::certificate-file ::password-file ::directory])) + +(defn-spec repo-command ::commands + [config ::config + command ::command] + (let [{:keys [certificate-file password-file directory restic-repository backup-path]} config] + [(into + [] + (concat + (if (some? directory) + [{:dir directory}] + []) + ["restic" "-r" (str restic-repository "/" backup-path) "-v"] + (cond + (some? certificate-file) + ["--cacert" certificate-file] + (some? password-file) + ["--password-file" password-file] + :else + []) + command))])) diff --git a/src/dda/backup/infrastructure.clj b/src/dda/backup/infrastructure.clj index b1f1c38..f8602e0 100644 --- a/src/dda/backup/infrastructure.clj +++ b/src/dda/backup/infrastructure.clj @@ -1,11 +1,11 @@ (ns dda.backup.infrastructure (:require [orchestra.core :refer [defn-spec]] [babashka.tasks :as t] - [dda.backup.core :as core])) + [dda.backup.core.domain :as core])) (defn-spec execute! nil? [commands ::core/command - config any?] + config ::core/config] (let [{:keys [dry-run debug]} config] (doseq [c commands] (when debug diff --git a/src/dda/backup/management.clj b/src/dda/backup/management.clj index 3e7140d..74609fa 100644 --- a/src/dda/backup/management.clj +++ b/src/dda/backup/management.clj @@ -2,13 +2,14 @@ (:require [orchestra.core :refer [defn-spec]] [clojure.spec.alpha :as s] - [dda.backup.core :as core] + [dda.backup.core.domain :as core] [dda.backup.management.domain :as domain] [dda.backup.infrastructure :as i])) (s/def ::config - (s/keys :req-un [::domain/restic-repository ::domain/backup-path] - :opt-un [::domain/certificate-file ::core/debug ::core/dry-run])) + (s/keys :req-un [::core/restic-repository ::core/backup-path] + :opt-un [::core/certificate-file ::core/directory ::core/debug + ::core/dry-run ::core/days-to-keep ::core/months-to-keep])) (defn-spec initalized? boolean? [config ::config] @@ -29,3 +30,8 @@ [config ::config] (let [config-w-defaults (merge core/default config)] (i/execute! (domain/unlock-repo-command config-w-defaults) config-w-defaults))) + +(defn-spec forget! nil? + [config ::config] + (let [config-w-defaults (merge core/default config)] + (i/execute! (domain/forget-command config-w-defaults) config-w-defaults))) diff --git a/src/dda/backup/management/domain.clj b/src/dda/backup/management/domain.clj index 25d86b6..0ac8438 100644 --- a/src/dda/backup/management/domain.clj +++ b/src/dda/backup/management/domain.clj @@ -2,49 +2,28 @@ (:require [orchestra.core :refer [defn-spec]] [clojure.spec.alpha :as s] - [dda.backup.core :as core])) - -(s/def ::restic-repository string?) -(s/def ::backup-path string?) -(s/def ::certificate-file string?) -(s/def ::password-file string?) - -(s/def ::config - (s/keys :req-un [::restic-repository ::backup-path] - :opt-un [::certificate-file ::password-file])) - -(defn repo-command - [config - commands] - (let [{:keys [certificate-file password-file restic-repository backup-path]} config] - [(into - ["restic" "-r" (str restic-repository "/" backup-path) "-v"] - (concat - (cond - (some? certificate-file) - ["--cacert" certificate-file] - (some? password-file) - ["--password-file" password-file] - :else - []) - commands))])) + [dda.backup.core.domain :as core])) (defn-spec check-repo-command ::core/commands - [config ::config] - (let [{:keys [certificate-file password-file restic-repository backup-path]} config] - (repo-command config ["check"]))) + [config ::core/config] + (core/repo-command config ["check"])) (defn-spec init-repo-command ::core/commands - [config ::config] - (let [{:keys [certificate-file password-file restic-repository backup-path]} config] - (repo-command config ["init"]))) + [config ::core/config] + (core/repo-command config ["init"])) (defn-spec unlock-repo-command ::core/commands - [config ::config] - (let [{:keys [certificate-file password-file restic-repository backup-path]} config] - (repo-command config ["--cleanup-cache" "unlock"]))) + [config ::core/config] + (core/repo-command config ["--cleanup-cache" "unlock"])) (defn-spec list-snapshot-command ::core/commands - [config ::config] - (let [{:keys [certificate-file password-file restic-repository backup-path]} config] - (repo-command config ["snapshots"]))) + [config ::core/config] + (core/repo-command config ["snapshots"])) + +(defn-spec forget-command ::core/commands + [config ::core/config] + (let [{:keys [days-to-keep months-to-keep]} config] + (core/repo-command config ["forget" "--group-by" "''" + "--keep-last" "1" + "--keep-daily" (str days-to-keep) + "--keep-monthly" (str months-to-keep) "--prune"]))) diff --git a/test/dda/backup/backup/domain_test.clj b/test/dda/backup/backup/domain_test.clj new file mode 100644 index 0000000..17496d7 --- /dev/null +++ b/test/dda/backup/backup/domain_test.clj @@ -0,0 +1,23 @@ +(ns dda.backup.backup.domain-test + (:require + [clojure.test :refer [deftest is are testing run-tests]] + [clojure.spec.test.alpha :as st] + [dda.backup.backup.domain :as cut])) + +(st/instrument `cut/backup-files-command) + +(deftest should-calculate-backup-files-command + (is (= [[{:dir "dir-to-backup"} + "restic" + "-r" + "repo/dir-at-repo" + "-v" + "backup" + "file2" + "file2"]] + (cut/backup-files-command {:restic-repository "repo" + :backup-path "dir-at-repo" + :directory "dir-to-backup" + :days-to-keep 39 + :months-to-keep 3} + ["file2" "file2"])))) diff --git a/test/dda/backup/core/domain_test.clj b/test/dda/backup/core/domain_test.clj new file mode 100644 index 0000000..84ae9c3 --- /dev/null +++ b/test/dda/backup/core/domain_test.clj @@ -0,0 +1,57 @@ +(ns dda.backup.core.domain-test + (:require + [clojure.test :refer [deftest is are testing run-tests]] + [clojure.spec.alpha :as s] + [clojure.spec.test.alpha :as st] + [dda.backup.core.domain :as cut])) + +(st/instrument `cut/repo-command) + +(deftest should-verify-command + (is (= {:app "restic", :params ["-r" "repo/dir" "-v" "init" "--cacert" "ca"]} + (s/conform ::cut/command ["restic" "-r" "repo/dir" "-v" "init" "--cacert" "ca"])))) + +(deftest should-verify-commands + (is (= [{:app "ls"} + {:app "restic", :params ["-r" "repo/dir" "-v" "init" "--cacert" "ca"]}] + (s/conform ::cut/commands [["ls"] + ["restic" "-r" "repo/dir" "-v" "init" "--cacert" "ca"]])))) + +(deftest should-calculate-repo-command + (is (= [[{:dir "dir"} + "restic" + "-r" + "repo/dir" + "-v" + "--cacert" + "ca" + "backup" + "file1" + "file2"]] + (cut/repo-command {:certificate-file "ca" + :directory "dir" + :restic-repository "repo" + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3} + ["backup" "file1" "file2"]))) + (is (= [["restic" "-r" "repo/dir" "-v" "--cacert" "ca" "snapshots"]] + (cut/repo-command {:certificate-file "ca" + :restic-repository "repo" + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3} + ["snapshots"]))) + (is (= [["restic" "-r" "repo/dir" "-v" "--password-file" "password" "snapshots"]] + (cut/repo-command {:password-file "password" + :restic-repository "repo" + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3} + ["snapshots"]))) + (is (= [["restic" "-r" "repo/dir" "-v" "snapshots"]] + (cut/repo-command {:restic-repository "repo" + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3} + ["snapshots"])))) \ No newline at end of file diff --git a/test/dda/backup/core_test.clj b/test/dda/backup/core_test.clj deleted file mode 100644 index 539dc28..0000000 --- a/test/dda/backup/core_test.clj +++ /dev/null @@ -1,16 +0,0 @@ -(ns dda.backup.core-test - (:require - [clojure.test :refer [deftest is are testing run-tests]] - [clojure.spec.alpha :as s] - [clojure.spec.test.alpha :as st] - [dda.backup.core :as cut])) - -(deftest should-verify-command - (is (= {:app "restic", :params ["-r" "repo/dir" "-v" "init" "--cacert" "ca"]} - (s/conform ::cut/command ["restic" "-r" "repo/dir" "-v" "init" "--cacert" "ca"])))) - -(deftest should-verify-commands - (is (= [{:app "ls"} - {:app "restic", :params ["-r" "repo/dir" "-v" "init" "--cacert" "ca"]}] - (s/conform ::cut/commands [["ls"] - ["restic" "-r" "repo/dir" "-v" "init" "--cacert" "ca"]])))) diff --git a/test/dda/backup/management/domain_test.clj b/test/dda/backup/management/domain_test.clj index 9e542c4..31a326a 100644 --- a/test/dda/backup/management/domain_test.clj +++ b/test/dda/backup/management/domain_test.clj @@ -6,27 +6,27 @@ (st/instrument `cut/init-repo-command) (st/instrument `cut/unlock-repo-command) -(st/instrument `cut/list-snapshot-command) - -(deftest should-calculate-list-snapshot-command - (is (= [["restic" "-r" "repo/dir" "-v" "--cacert" "ca" "snapshots"]] - (cut/list-snapshot-command {:certificate-file "ca" - :restic-repository "repo" - :backup-path "dir"}))) - (is (= [["restic" "-r" "repo/dir" "-v" "--password-file" "password" "snapshots"]] - (cut/list-snapshot-command {:password-file "password" - :restic-repository "repo" - :backup-path "dir"}))) - (is (= [["restic" "-r" "repo/dir" "-v" "snapshots"]] - (cut/list-snapshot-command {:restic-repository "repo" - :backup-path "dir"})))) +(st/instrument `cut/forget-command) (deftest should-calculate-init-repo-command (is (= [["restic" "-r" "repo/dir" "-v" "init"]] (cut/init-repo-command {:restic-repository "repo" - :backup-path "dir"})))) + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3})))) (deftest should-calculate-unlock-repo-command (is (= [["restic" "-r" "repo/dir" "-v" "--cleanup-cache" "unlock"]] (cut/unlock-repo-command {:restic-repository "repo" - :backup-path "dir"})))) + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3})))) + +(deftest should-calculate-forget-command + (is (= [["restic" "-r" "repo/dir" "-v" "forget" + "--group-by" "''" "--keep-last" "1" + "--keep-daily" "39" "--keep-monthly" "3" "--prune"]] + (cut/forget-command {:restic-repository "repo" + :backup-path "dir" + :days-to-keep 39 + :months-to-keep 3}))))