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.config;
7 
8 import logger = std.experimental.logger;
9 import std.stdio : writeln;
10 
11 import colorlog;
12 
13 public import dsnapshot.types;
14 
15 struct Config {
16     import std.datetime : SysTime, Duration;
17     import std.variant : Algebraic, visit;
18     static import std.getopt;
19 
20     struct Help {
21         std.getopt.GetoptResult helpInfo;
22     }
23 
24     struct Backup {
25         /// The name of the snapshot to backup. If none is specified then all are backed up.
26         Name name;
27         /// If the user wants to resume an interrupted backup.
28         bool resume;
29         /// Force a backup to be taken even though it isn't time for it
30         bool forceBackup;
31         /// Adjusts the margin used when calculating if a new snapshot should be taken.
32         Duration newSnapshotMargin;
33         ///
34         int[] ignoreRsyncErrorCodes;
35         std.getopt.GetoptResult helpInfo;
36     }
37 
38     struct Remotecmd {
39         /// Single path to modify on the remote host.
40         string path;
41         RemoteSubCmd cmd;
42         std.getopt.GetoptResult helpInfo;
43     }
44 
45     struct Admin {
46         /// Name of the snapshot to administrate.
47         Name[] names;
48 
49         enum Cmd {
50             list,
51             diskusage,
52         }
53 
54         Cmd cmd;
55 
56         std.getopt.GetoptResult helpInfo;
57     }
58 
59     struct Restore {
60         /// The name of the snapshot to restore.
61         Name name;
62         /// The time to restore.
63         SysTime time;
64         /// Path to restore the named snapshot to.
65         string restoreTo;
66         /// Delete files from restoreTo if they have been removed in src
67         bool deleteFromTo;
68 
69         std.getopt.GetoptResult helpInfo;
70     }
71 
72     struct Verifyconfig {
73         std.getopt.GetoptResult helpInfo;
74     }
75 
76     struct Watch {
77         /// The name of the snapshot to backup.
78         Name name;
79         /// Max number of snapshots to create before exiting.
80         ulong maxSnapshots = ulong.max;
81         std.getopt.GetoptResult helpInfo;
82     }
83 
84     struct Global {
85         /// Configuration file to read
86         Path confFile;
87 
88         VerboseMode verbosity;
89         bool help = true;
90         string progName;
91     }
92 
93     alias Type = Algebraic!(Help, Backup, Remotecmd, Restore, Verifyconfig, Admin, Watch);
94     Type data;
95 
96     Global global;
97     SnapshotConfig[] snapshots;
98 
99     void printHelp() {
100         import std.format : format;
101         import std.getopt : defaultGetoptPrinter;
102         import std.path : baseName;
103         import std.string : toLower;
104 
105         static void printGroup(std.getopt.GetoptResult helpInfo, string progName, string name) {
106             defaultGetoptPrinter(format("usage: %s %s <options>\n", progName,
107                     name), helpInfo.options);
108         }
109 
110         static void printHelpGroup(std.getopt.GetoptResult helpInfo, string progName) {
111             defaultGetoptPrinter(format("usage: %s <command>\n", progName), helpInfo.options);
112             writeln("Command groups:");
113             static foreach (T; Type.AllowedTypes) {
114                 writeln("  ", T.stringof.toLower);
115             }
116         }
117 
118         import std.meta : AliasSeq;
119 
120         template printers(T...) {
121             static if (T.length == 1) {
122                 static if (is(T[0] == Config.Help))
123                     alias printers = (T[0] a) => printHelpGroup(a.helpInfo, global.progName);
124                 else
125                     alias printers = (T[0] a) => printGroup(a.helpInfo,
126                             global.progName, T[0].stringof.toLower);
127             } else {
128                 alias printers = AliasSeq!(printers!(T[0]), printers!(T[1 .. $]));
129             }
130         }
131 
132         data.visit!(printers!(Type.AllowedTypes));
133 
134         if (data.type == typeid(Verifyconfig)) {
135             writeln("Verify the configuration file without actually executing it");
136         }
137     }
138 }