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.remote;
7 
8 import logger = std.experimental.logger;
9 
10 import dsnapshot.config;
11 import dsnapshot.types;
12 
13 int cmdRemote(const Config.Remotecmd conf) nothrow {
14     import std.algorithm : map, filter;
15     import std.exception : collectException;
16     import std.file : dirEntries, SpanMode, exists, mkdirRecurse, rmdirRecurse, rename;
17     import std.path : baseName;
18     import std.stdio : writeln;
19 
20     final switch (conf.cmd) {
21     case RemoteSubCmd.none:
22         break;
23     case RemoteSubCmd.lsDirs:
24         try {
25             foreach (p; dirEntries(conf.path, SpanMode.shallow).filter!(a => a.isDir)
26                     .map!(a => a.name.baseName)) {
27                 writeln(p);
28             }
29         } catch (Exception e) {
30         }
31         break;
32     case RemoteSubCmd.mkdirRecurse:
33         try {
34             if (!exists(conf.path))
35                 mkdirRecurse(conf.path);
36         } catch (Exception e) {
37             logger.warning(e.msg).collectException;
38         }
39         break;
40     case RemoteSubCmd.rmdirRecurse:
41         if (!exists(conf.path))
42             return 0;
43 
44         try {
45             // can fail because a directory is write protected.
46             rmdirRecurse(conf.path);
47             return 0;
48         } catch (Exception e) {
49         }
50 
51         try {
52             foreach (const p; dirEntries(conf.path, SpanMode.depth).filter!(a => a.isDir)) {
53                 import core.sys.posix.sys.stat;
54                 import std.file : getAttributes, setAttributes;
55 
56                 const attrs = getAttributes(p);
57                 setAttributes(p, attrs | S_IRWXU);
58             }
59             rmdirRecurse(conf.path);
60         } catch (Exception e) {
61             logger.warning(e.msg).collectException;
62         }
63         break;
64     case RemoteSubCmd.publishSnapshot:
65         if (!exists(conf.path)) {
66             logger.infof("Snapshot %s do not exist", conf.path).collectException;
67             return 1;
68         }
69 
70         publishSnapshot(conf.path);
71         break;
72     }
73     return 0;
74 }
75 
76 /// Publish a snapshot that has the status "in-progress".
77 int publishSnapshot(const string snapshot) nothrow {
78     import std.algorithm : map, filter;
79     import std.exception : collectException;
80     import std.file : dirEntries, SpanMode, exists, mkdirRecurse, rmdirRecurse, rename;
81     import std.path : baseName;
82     import std.stdio : writeln;
83 
84     const dst = () {
85         if (snapshot.length < snapshotInProgressSuffix.length)
86             return null;
87         return snapshot[0 .. $ - snapshotInProgressSuffix.length];
88     }();
89 
90     if (exists(dst)) {
91         logger.errorf("Destination %s already exist thus unable to publish snapshot %s",
92                 dst, snapshot).collectException;
93         return 1;
94     }
95 
96     try {
97         rename(snapshot, dst);
98     } catch (Exception e) {
99         logger.error(e.msg).collectException;
100         return 1;
101     }
102 
103     return 0;
104 }