Extract a repository concept
This commit is contained in:
parent
c6b267771e
commit
2a96cd2396
10 changed files with 280 additions and 246 deletions
112
Cargo.lock
generated
112
Cargo.lock
generated
|
@ -1,8 +1,36 @@
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace-sys"
|
||||||
|
version = "0.1.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bakare"
|
name = "bakare"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dir-diff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dir-diff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -13,6 +41,11 @@ name = "bitflags"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -34,6 +67,26 @@ dependencies = [
|
||||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "failure"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "failure_derive"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuchsia-zircon"
|
name = "fuchsia-zircon"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -58,6 +111,22 @@ name = "libc"
|
||||||
version = "0.2.45"
|
version = "0.2.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "0.4.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "0.6.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.3.22"
|
version = "0.3.22"
|
||||||
|
@ -168,6 +237,11 @@ dependencies = [
|
||||||
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.24"
|
version = "0.3.24"
|
||||||
|
@ -202,6 +276,27 @@ name = "semver-parser"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "0.15.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synstructure"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.0.5"
|
version = "3.0.5"
|
||||||
|
@ -225,6 +320,11 @@ dependencies = [
|
||||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.2.7"
|
version = "2.2.7"
|
||||||
|
@ -263,14 +363,22 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
"checksum autocfg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e5f34df7a019573fb8bdc7e24a2bfebe51a2a1d6bfdbaeccedb3c41fc574727"
|
||||||
|
"checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5"
|
||||||
|
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
|
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||||
"checksum dir-diff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce6e50ca36311e494793f7629014dc78cd963ba85cd05968ae06a63b867f0b"
|
"checksum dir-diff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce6e50ca36311e494793f7629014dc78cd963ba85cd05968ae06a63b867f0b"
|
||||||
|
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||||
|
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||||
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
|
||||||
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
|
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
|
||||||
|
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||||
|
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||||
"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a"
|
"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a"
|
||||||
|
@ -283,13 +391,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70"
|
"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70"
|
||||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||||
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
|
||||||
|
"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
|
||||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
"checksum syn 0.15.24 (registry+https://github.com/rust-lang/crates.io-index)" = "734ecc29cd36e8123850d9bf21dfd62ef8300aaa8f879aabaa899721808be37c"
|
||||||
|
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||||
"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2"
|
"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2"
|
||||||
"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c"
|
"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c"
|
||||||
|
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
|
@ -9,6 +9,7 @@ license = "AGPL-3.0"
|
||||||
walkdir = "2.2"
|
walkdir = "2.2"
|
||||||
rust-crypto = "0.2"
|
rust-crypto = "0.2"
|
||||||
tempfile = "3.0"
|
tempfile = "3.0"
|
||||||
|
failure = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rust-crypto = "0.2"
|
rust-crypto = "0.2"
|
||||||
|
|
|
@ -1,93 +1,40 @@
|
||||||
use crate::storage::Version;
|
use std::collections::HashMap;
|
||||||
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use walkdir::DirEntry;
|
use walkdir::DirEntry;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::error::BakareError;
|
||||||
|
use crate::repository::Repository;
|
||||||
|
use crate::RepositoryRelativePath;
|
||||||
|
use crate::Version;
|
||||||
|
|
||||||
pub struct Engine<'a> {
|
pub struct Engine<'a> {
|
||||||
source_path: &'a Path,
|
source_path: &'a Path,
|
||||||
repository_path: &'a Path,
|
repository: &'a Repository<'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Index {}
|
|
||||||
|
|
||||||
struct InMemoryIndex {}
|
|
||||||
|
|
||||||
impl InMemoryIndex {
|
|
||||||
fn new() -> Self {
|
|
||||||
InMemoryIndex {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Index for InMemoryIndex {}
|
|
||||||
|
|
||||||
impl<'a> Engine<'a> {
|
impl<'a> Engine<'a> {
|
||||||
pub fn new(source_path: &'a Path, repository_path: &'a Path) -> Self {
|
pub fn new(source_path: &'a Path, repository: &'a Repository) -> Self {
|
||||||
let index = InMemoryIndex::new();
|
|
||||||
Engine::new_with_index(source_path, repository_path, index)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_with_index(source_path: &'a Path, repository_path: &'a Path, index: impl Index) -> Self {
|
|
||||||
Engine {
|
Engine {
|
||||||
source_path,
|
source_path,
|
||||||
repository_path,
|
repository,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backup(&self) -> Result<(), io::Error> {
|
pub fn backup(&self) -> Result<(), BakareError> {
|
||||||
let walker = WalkDir::new(self.source_path);
|
let walker = WalkDir::new(self.source_path);
|
||||||
for maybe_entry in walker {
|
for maybe_entry in walker {
|
||||||
let entry = maybe_entry?;
|
let entry = maybe_entry?;
|
||||||
if entry.path() != self.source_path {
|
if entry.path() != self.source_path {
|
||||||
self.process_entry(&entry)?;
|
self.repository.store_entry(&entry)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_version(&self, path: &Path) -> Version {
|
|
||||||
Version::Newest
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_entry(&self, entry: &DirEntry) -> Result<(), io::Error> {
|
|
||||||
// TODO: remember entry in index
|
|
||||||
|
|
||||||
// TODO: store file data
|
|
||||||
|
|
||||||
if entry.file_type().is_dir() {
|
|
||||||
fs::create_dir(self.repository_path.join(entry.file_name()))?;
|
|
||||||
}
|
|
||||||
if entry.file_type().is_file() {
|
|
||||||
fs::copy(entry.path(), self.repository_path.join(entry.file_name()))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod should {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use tempfile::tempdir;
|
|
||||||
|
|
||||||
use crate::source::Source;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn store_file_where_index_tells_it() -> Result<(), io::Error> {
|
|
||||||
let index = FakeIndex {};
|
|
||||||
|
|
||||||
let source = Source::new()?;
|
|
||||||
let repository = tempdir()?;
|
|
||||||
let engine = Engine::new_with_index(source.path(), repository.path(), index);
|
|
||||||
|
|
||||||
// backup
|
|
||||||
// see if repo contains one file at the faked path
|
|
||||||
assert!(false);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FakeIndex {}
|
|
||||||
|
|
||||||
impl Index for FakeIndex {}
|
|
||||||
}
|
}
|
||||||
|
|
21
src/error.rs
Normal file
21
src/error.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use failure::Fail;
|
||||||
|
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
pub enum BakareError {
|
||||||
|
#[fail(display = "io error")]
|
||||||
|
IOError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for BakareError {
|
||||||
|
fn from(e: io::Error) -> Self {
|
||||||
|
BakareError::IOError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<walkdir::Error> for BakareError {
|
||||||
|
fn from(e: walkdir::Error) -> Self {
|
||||||
|
BakareError::IOError
|
||||||
|
}
|
||||||
|
}
|
20
src/lib.rs
20
src/lib.rs
|
@ -1,6 +1,22 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use failure::Fail;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub mod backup;
|
pub mod backup;
|
||||||
pub mod restore;
|
pub mod restore;
|
||||||
|
|
||||||
pub mod source;
|
pub mod source;
|
||||||
|
|
||||||
mod storage;
|
pub mod repository;
|
||||||
|
|
||||||
|
pub struct Version(String);
|
||||||
|
struct RepositoryRelativePath {}
|
||||||
|
|
||||||
|
struct Index<'a> {
|
||||||
|
versions: HashMap<&'a RepositoryRelativePath, &'a Version>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
68
src/repository.rs
Normal file
68
src/repository.rs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use walkdir::DirEntry;
|
||||||
|
|
||||||
|
use crate::error::BakareError;
|
||||||
|
use crate::Version;
|
||||||
|
|
||||||
|
/// represents a place where backup is stored an can be restored from. E.g. a directory, a cloud service etc
|
||||||
|
pub struct Repository<'a> {
|
||||||
|
path: &'a Path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StoredItemId;
|
||||||
|
pub struct RelativePath;
|
||||||
|
impl<'a> Repository<'a> {
|
||||||
|
pub fn new(path: &Path) -> Result<Repository, BakareError> {
|
||||||
|
Ok(Repository {
|
||||||
|
path
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store_entry(&self, entry: &DirEntry) -> Result<(), BakareError> {
|
||||||
|
// get file id -> contents hash + original path + time of taking notes
|
||||||
|
// get storage path for File
|
||||||
|
// store file contents
|
||||||
|
// remember File
|
||||||
|
|
||||||
|
if entry.file_type().is_dir() {
|
||||||
|
fs::create_dir(self.path.join(entry.file_name()))?;
|
||||||
|
}
|
||||||
|
if entry.file_type().is_file() {
|
||||||
|
fs::copy(entry.path(), self.path.join(entry.file_name()))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn newest_version_for(&self, item: &StoredItemId) -> Result<Version, BakareError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn relative_path(&self, path: &str) -> RelativePath {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_id(&self, path: &RelativePath) -> Result<StoredItemId, BakareError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for Repository<'a> {
|
||||||
|
type Item = StoredItemId;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for &Repository<'a> {
|
||||||
|
type Item = StoredItemId;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,52 +1,47 @@
|
||||||
use crate::storage::Version;
|
use std::error::Error;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use walkdir::DirEntry;
|
use walkdir::DirEntry;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::error::BakareError;
|
||||||
|
use crate::repository::Repository;
|
||||||
|
use crate::repository::StoredItemId;
|
||||||
|
use crate::Version;
|
||||||
|
|
||||||
pub struct Engine<'a> {
|
pub struct Engine<'a> {
|
||||||
repository_path: &'a Path,
|
repository: &'a Repository<'a>,
|
||||||
target_path: &'a Path,
|
target_path: &'a Path,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum WhatToRestore {
|
|
||||||
All,
|
|
||||||
SpecificPath(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Engine<'a> {
|
impl<'a> Engine<'a> {
|
||||||
pub fn new(repository_path: &'a Path, target_path: &'a Path) -> Self {
|
pub fn new(repository: &'a Repository, target_path: &'a Path) -> Self {
|
||||||
Engine {
|
Engine {
|
||||||
repository_path,
|
repository,
|
||||||
target_path,
|
target_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_all(&self) -> Result<(), io::Error> {
|
pub fn restore_all(&self) -> Result<(), BakareError> {
|
||||||
self.restore(WhatToRestore::All)
|
for item in self.repository {
|
||||||
}
|
self.restore(item)?;
|
||||||
|
|
||||||
fn restore(&self, what: WhatToRestore) -> Result<(), io::Error> {
|
|
||||||
self.restore_as_of_version(what, Version::Newest)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn restore_as_of_version(&self, what: WhatToRestore, version: Version) -> Result<(), io::Error> {
|
|
||||||
let walker = WalkDir::new(self.repository_path);
|
|
||||||
for maybe_entry in walker {
|
|
||||||
match maybe_entry {
|
|
||||||
Ok(entry) => {
|
|
||||||
if entry.path() != self.repository_path {
|
|
||||||
self.process_entry(&entry)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(error) => return Err(error.into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_entry(&self, entry: &DirEntry) -> Result<(), io::Error> {
|
fn restore(&self, item: StoredItemId) -> Result<(), BakareError> {
|
||||||
|
let version = self.repository.newest_version_for(&item)?;
|
||||||
|
self.restore_as_of_version(item, version)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore_as_of_version(&self, what: StoredItemId, version: Version) -> Result<(), BakareError> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_entry(&self, entry: &DirEntry) -> Result<(), BakareError> {
|
||||||
if entry.file_type().is_dir() {
|
if entry.file_type().is_dir() {
|
||||||
fs::create_dir(self.target_path.join(entry.file_name()))?;
|
fs::create_dir(self.target_path.join(entry.file_name()))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::fs::File;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
|
131
src/storage.rs
131
src/storage.rs
|
@ -1,131 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
|
||||||
pub enum Version {
|
|
||||||
Newest,
|
|
||||||
Specific(u64),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Version {
|
|
||||||
fn next(self) -> Self {
|
|
||||||
match self {
|
|
||||||
Version::Newest => Version::Newest,
|
|
||||||
Version::Specific(old) => Version::Specific(old + 1),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
struct Hash([u8; 32]);
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct IndexHashEntry {
|
|
||||||
source_paths: HashSet<String>,
|
|
||||||
storage_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct IndexPathEntry {
|
|
||||||
hash: Hash,
|
|
||||||
version: Version,
|
|
||||||
storage_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Index<'a> {
|
|
||||||
file_hashes: HashMap<Hash, IndexHashEntry>,
|
|
||||||
file_paths: HashMap<&'a str, IndexPathEntry>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Index<'a> {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
file_hashes: HashMap::new(),
|
|
||||||
file_paths: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn store(&mut self, source_path: &'a str, hash: Hash) -> (Version, String) {
|
|
||||||
let path_entry = {
|
|
||||||
self.file_paths.get(source_path).map_or_else(
|
|
||||||
|| IndexPathEntry {
|
|
||||||
hash,
|
|
||||||
version: Version::Newest,
|
|
||||||
storage_path: format!("{:X?}", hash.0),
|
|
||||||
},
|
|
||||||
|old_entry| {
|
|
||||||
if old_entry.hash == hash {
|
|
||||||
old_entry.clone() // FIXME optimise
|
|
||||||
} else {
|
|
||||||
IndexPathEntry {
|
|
||||||
hash,
|
|
||||||
version: old_entry.version.next(),
|
|
||||||
storage_path: old_entry.storage_path.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.file_paths.insert(source_path, path_entry.clone());
|
|
||||||
|
|
||||||
let hash_entry = {
|
|
||||||
self.file_hashes.get(&hash).map_or_else(
|
|
||||||
|| {
|
|
||||||
let mut source_paths = HashSet::new();
|
|
||||||
source_paths.insert(source_path.to_string());
|
|
||||||
IndexHashEntry {
|
|
||||||
source_paths,
|
|
||||||
storage_path: format!("{:X?}", hash.0),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|old_entry| {
|
|
||||||
let mut source_paths = old_entry.source_paths.clone();
|
|
||||||
source_paths.insert(source_path.to_string());
|
|
||||||
IndexHashEntry {
|
|
||||||
source_paths,
|
|
||||||
storage_path: old_entry.storage_path.clone(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.file_hashes.insert(hash, hash_entry);
|
|
||||||
(path_entry.version, path_entry.storage_path.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn latest_version_for_path(&self, path: &str) -> Option<Version> {
|
|
||||||
self.file_paths.get(path).map_or(None, |entry| Some(entry.version))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod should {
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
const SOME_HASH: Hash = Hash([1; 32]);
|
|
||||||
const SOME_OTHER_HASH: Hash = Hash([2; 32]);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn support_file_versions() {
|
|
||||||
let mut index = Index::new();
|
|
||||||
let (v1, _) = index.store("/some/path", SOME_HASH);
|
|
||||||
let (v2, _) = index.store("/some/path", SOME_OTHER_HASH);
|
|
||||||
|
|
||||||
assert_eq!(v2, index.latest_version_for_path("/some/path").unwrap());
|
|
||||||
|
|
||||||
assert!(v2 > v1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn support_deduplication() {
|
|
||||||
let mut index = Index::new();
|
|
||||||
let (_, storage_path1) = index.store("/some/path", SOME_HASH);
|
|
||||||
let (_, storage_path2) = index.store("/some/path", SOME_HASH);
|
|
||||||
let (_, storage_path3) = index.store("/some/other/path", SOME_HASH);
|
|
||||||
|
|
||||||
assert_eq!(storage_path1, storage_path2);
|
|
||||||
assert_eq!(storage_path1, storage_path3);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +1,60 @@
|
||||||
use bakare::backup;
|
use bakare::backup;
|
||||||
use bakare::restore;
|
use bakare::restore;
|
||||||
use bakare::restore::WhatToRestore::SpecificPath;
|
|
||||||
|
|
||||||
use bakare::source::Source;
|
use bakare::source::Source;
|
||||||
|
|
||||||
use dir_diff::is_different;
|
use dir_diff::is_different;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Error;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
use bakare::error::BakareError;
|
||||||
|
use bakare::repository::Repository;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn restore_backed_up_files() -> Result<(), Error> {
|
fn restore_backed_up_files() -> Result<(), BakareError> {
|
||||||
let source = Source::new()?;
|
let source = Source::new()?;
|
||||||
let repository = tempdir()?;
|
let repository_path = tempdir()?.into_path();
|
||||||
|
let repository = Repository::new(repository_path.as_path())?;
|
||||||
|
|
||||||
source.write_text_to_file("first", "some contents")?;
|
source.write_text_to_file("first", "some contents")?;
|
||||||
source.write_text_to_file("second", "some contents")?;
|
source.write_text_to_file("second", "some contents")?;
|
||||||
source.write_text_to_file("third", "some other contents")?;
|
source.write_text_to_file("third", "some other contents")?;
|
||||||
|
|
||||||
assert_same_after_restore(source.path(), repository.path())
|
assert_same_after_restore(source.path(), &repository)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn restore_older_version_of_file() -> Result<(), Error> {
|
fn restore_older_version_of_file() -> Result<(), BakareError> {
|
||||||
let source = Source::new()?;
|
let source = Source::new()?;
|
||||||
let repository = tempdir()?;
|
let repository_path = tempdir()?.into_path();
|
||||||
let backup_engine = backup::Engine::new(source.path(), repository.path());
|
let repository = Repository::new(repository_path.as_path())?;
|
||||||
let path = "some path";
|
let backup_engine = backup::Engine::new(source.path(), &repository);
|
||||||
|
let file_path = "some path";
|
||||||
let new_contents = "totally new contents";
|
let new_contents = "totally new contents";
|
||||||
let restore_target = tempdir()?;
|
let restore_target = tempdir()?;
|
||||||
let restore_engine = restore::Engine::new(repository.path(), &restore_target.path());
|
let restore_engine = restore::Engine::new(&repository, &restore_target.path());
|
||||||
let old_contents = "some old contents";
|
let old_contents = "some old contents";
|
||||||
|
|
||||||
source.write_text_to_file(path, old_contents)?;
|
source.write_text_to_file(file_path, old_contents)?;
|
||||||
backup_engine.backup()?;
|
backup_engine.backup()?;
|
||||||
let old_version = backup_engine.file_version(path.as_ref());
|
let repository_path = repository.relative_path(file_path);
|
||||||
|
let file_id = repository.file_id(&repository_path)?;
|
||||||
|
let old_version = repository.newest_version_for(&file_id)?;
|
||||||
|
|
||||||
source.write_text_to_file(path, new_contents)?;
|
source.write_text_to_file(file_path, new_contents)?;
|
||||||
backup_engine.backup()?;
|
backup_engine.backup()?;
|
||||||
|
|
||||||
restore_engine.restore_as_of_version(SpecificPath(path.into()), old_version)?;
|
restore_engine.restore_as_of_version(file_id, old_version)?;
|
||||||
|
|
||||||
assert_target_file_contents(restore_target.path(), path, old_contents)?;
|
assert_target_file_contents(restore_target.path(), file_path, old_contents)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: restore latest version by default
|
// TODO: restore latest version by default
|
||||||
// TODO: deduplicate data
|
// TODO: deduplicate data
|
||||||
|
|
||||||
fn assert_target_file_contents(target: &Path, filename: &str, expected_contents: &str) -> Result<(), Error> {
|
fn assert_target_file_contents(target: &Path, filename: &str, expected_contents: &str) -> Result<(), BakareError> {
|
||||||
let restored_path = target.join(filename);
|
let restored_path = target.join(filename);
|
||||||
let mut actual_contents = String::new();
|
let mut actual_contents = String::new();
|
||||||
File::open(restored_path)?.read_to_string(&mut actual_contents)?;
|
File::open(restored_path)?.read_to_string(&mut actual_contents)?;
|
||||||
|
@ -58,12 +62,12 @@ fn assert_target_file_contents(target: &Path, filename: &str, expected_contents:
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_same_after_restore(source_path: &Path, repository_path: &Path) -> Result<(), Error> {
|
fn assert_same_after_restore(source_path: &Path, repository: &Repository) -> Result<(), BakareError> {
|
||||||
let backup_engine = backup::Engine::new(source_path, repository_path);
|
let backup_engine = backup::Engine::new(source_path, repository);
|
||||||
backup_engine.backup()?;
|
backup_engine.backup()?;
|
||||||
|
|
||||||
let restore_target = tempdir()?;
|
let restore_target = tempdir()?;
|
||||||
let restore_engine = restore::Engine::new(repository_path, &restore_target.path());
|
let restore_engine = restore::Engine::new(repository, &restore_target.path());
|
||||||
restore_engine.restore_all()?;
|
restore_engine.restore_all()?;
|
||||||
|
|
||||||
let are_source_and_target_different = is_different(source_path, &restore_target.path()).unwrap();
|
let are_source_and_target_different = is_different(source_path, &restore_target.path()).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue