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 }