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 }