1 /**
2 Date: 2015-2017, Joakim Brännström
3 License: MPL-2, Mozilla Public License 2.0
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module dextool.io;
7 
8 import std.stdio : File;
9 import logger = std.experimental.logger;
10 
11 import dextool.type : ExitStatusType, WriteStrategy;
12 
13 ///TODO don't catch Exception, catch the specific.
14 auto tryOpenFile(string filename, string mode) @trusted {
15     import std.exception;
16     import std.typecons : Unique;
17 
18     Unique!File rval;
19 
20     try {
21         rval = Unique!File(new File(filename, mode));
22     } catch (Exception ex) {
23     }
24     if (rval.isEmpty) {
25         try {
26             logger.errorf("Unable to read/write file '%s'", filename);
27         } catch (Exception ex) {
28         }
29     }
30 
31     return rval;
32 }
33 
34 ///TODO don't catch Exception, catch the specific.
35 auto tryWriting(T)(string fname, T data, WriteStrategy strategy = WriteStrategy.overwrite) @trusted nothrow {
36     import std.exception;
37 
38     static auto action(T)(string fname, T data, WriteStrategy strategy) {
39         import std.file : exists;
40 
41         debug logger.tracef("Trying to write to (%s): %s", strategy, fname);
42 
43         if (strategy == WriteStrategy.skip && exists(fname)) {
44             logger.info("File already exist, skipping: ", fname);
45             return ExitStatusType.Ok;
46         }
47 
48         auto f = tryOpenFile(fname, "w");
49 
50         if (f.isEmpty) {
51             return ExitStatusType.Errors;
52         }
53         scope (exit)
54             f.close();
55 
56         f.rawWrite(cast(void[]) data);
57 
58         return ExitStatusType.Ok;
59     }
60 
61     auto status = ExitStatusType.Errors;
62 
63     try {
64         status = action(fname, data, strategy);
65     } catch (Exception ex) {
66     }
67 
68     try {
69         final switch (status) with (ExitStatusType) {
70         case Ok:
71             break;
72         case Errors:
73             logger.error("Failed to write file: ", fname);
74             break;
75         }
76     } catch (Exception ex) {
77     }
78 
79     return status;
80 }
81 
82 /** Try to write the data to the destination directory.
83  *
84  * If the directory do not exist try and create it.
85  */
86 ExitStatusType writeFileData(T)(ref T data) {
87     import std.path : dirName;
88 
89     static ExitStatusType tryMkdir(string path) nothrow {
90         import std.file : isDir, mkdirRecurse;
91 
92         try {
93             if (path.isDir) {
94                 return ExitStatusType.Ok;
95             }
96         } catch (Exception ex) {
97         }
98 
99         try {
100             mkdirRecurse(path);
101             return ExitStatusType.Ok;
102         } catch (Exception ex) {
103         }
104 
105         return ExitStatusType.Errors;
106     }
107 
108     foreach (p; data) {
109         if (tryMkdir(p.filename.dirName) == ExitStatusType.Errors) {
110             logger.error("Unable to create destination directory: ", p.filename.dirName);
111         }
112 
113         auto status = tryWriting(p.filename, p.data, p.strategy);
114         if (status != ExitStatusType.Ok) {
115             return ExitStatusType.Errors;
116         }
117     }
118 
119     return ExitStatusType.Ok;
120 }