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     }
23     catch (Exception ex) {
24     }
25     if (rval.isEmpty) {
26         try {
27             logger.errorf("Unable to read/write file '%s'", filename);
28         }
29         catch (Exception ex) {
30         }
31     }
32 
33     return rval;
34 }
35 
36 ///TODO don't catch Exception, catch the specific.
37 auto tryWriting(T)(string fname, T data, WriteStrategy strategy = WriteStrategy.overwrite) @trusted nothrow {
38     import std.exception;
39 
40     static auto action(T)(string fname, T data, WriteStrategy strategy) {
41         import std.file : exists;
42 
43         debug logger.tracef("Trying to write to (%s): %s", strategy, fname);
44 
45         if (strategy == WriteStrategy.skip && exists(fname)) {
46             logger.info("File already exist, skipping: ", fname);
47             return ExitStatusType.Ok;
48         }
49 
50         auto f = tryOpenFile(fname, "w");
51 
52         if (f.isEmpty) {
53             return ExitStatusType.Errors;
54         }
55         scope (exit)
56             f.close();
57 
58         f.rawWrite(cast(void[]) data);
59 
60         return ExitStatusType.Ok;
61     }
62 
63     auto status = ExitStatusType.Errors;
64 
65     try {
66         status = action(fname, data, strategy);
67     }
68     catch (Exception ex) {
69     }
70 
71     try {
72         final switch (status) with (ExitStatusType) {
73         case Ok:
74             break;
75         case Errors:
76             logger.error("Failed to write file: ", fname);
77             break;
78         }
79     }
80     catch (Exception ex) {
81     }
82 
83     return status;
84 }
85 
86 /** Try to write the data to the destination directory.
87  *
88  * If the directory do not exist try and create it.
89  */
90 ExitStatusType writeFileData(T)(ref T data) {
91     import std.path : dirName;
92 
93     static ExitStatusType tryMkdir(string path) nothrow {
94         import std.file : isDir, mkdirRecurse;
95 
96         try {
97             if (path.isDir) {
98                 return ExitStatusType.Ok;
99             }
100         }
101         catch (Exception ex) {
102         }
103 
104         try {
105             mkdirRecurse(path);
106             return ExitStatusType.Ok;
107         }
108         catch (Exception ex) {
109         }
110 
111         return ExitStatusType.Errors;
112     }
113 
114     foreach (p; data) {
115         if (tryMkdir(p.filename.dirName) == ExitStatusType.Errors) {
116             logger.error("Unable to create destination directory: ", p.filename.dirName);
117         }
118 
119         auto status = tryWriting(p.filename, p.data, p.strategy);
120         if (status != ExitStatusType.Ok) {
121             return ExitStatusType.Errors;
122         }
123     }
124 
125     return ExitStatusType.Ok;
126 }