1 /**
2 Copyright: Copyright (c) 2019, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module dsnapshot.cmdgroup.restore;
7 
8 import logger = std.experimental.logger;
9 import std.algorithm : map, filter, canFind;
10 import std.array : empty, array;
11 import std.exception : collectException;
12 
13 import dsnapshot.backend;
14 import dsnapshot.config : Config;
15 import dsnapshot.exception;
16 import dsnapshot.from;
17 import dsnapshot.layout_utils;
18 import dsnapshot.process;
19 import dsnapshot.types;
20 
21 version (unittest) {
22     import unit_threaded.assertions;
23 }
24 
25 int cmdRestore(SnapshotConfig[] snapshots, const Config.Restore conf) nothrow {
26     import dsnapshot.layout;
27 
28     if (conf.name.value.empty) {
29         logger.error("No snapshot name specified (-s|--snapshot)").collectException;
30         return 1;
31     }
32     if (conf.restoreTo.empty) {
33         logger.error("No destination is specified (--dst)").collectException;
34         return 1;
35     }
36 
37     foreach (snapshot; snapshots.filter!(a => a.name == conf.name.value)) {
38         try {
39             return restore(snapshot, conf);
40         } catch (SnapshotException e) {
41             e.errMsg.match!(a => a.print).collectException;
42             logger.error(e.msg).collectException;
43         } catch (Exception e) {
44             logger.error(e.msg).collectException;
45             break;
46         }
47     }
48 
49     logger.errorf("No snapshot with the name %s found", conf.name.value).collectException;
50     logger.infof("Available snapshots are: %-(%s, %)",
51             snapshots.map!(a => a.name)).collectException;
52     return 1;
53 }
54 
55 private:
56 
57 int restore(SnapshotConfig snapshot, const Config.Restore rconf) {
58     auto backend = makeSyncBackend(snapshot);
59 
60     auto crypt = makeCrypBackend(snapshot.crypt);
61     open(crypt, backend.flow);
62     scope (exit)
63         crypt.close;
64 
65     // Extract an updated layout of the snapshots at the destination.
66     auto layout = backend.update(snapshot.layout);
67     logger.trace("Updated layout with information from destination: ", layout);
68 
69     backend.restore(layout, snapshot, rconf.time, rconf.restoreTo);
70 
71     return 0;
72 }