1 module tagion.tools.Basic; 2 3 import std.path : baseName, buildPath, dirName; 4 import std.typecons : Tuple; 5 import std.file : exists, symlink, remove, thisExePath, 6 getLinkAttributes, attrIsSymlink, FileException; 7 8 import std.stdio; 9 import tagion.utils.Term; 10 11 __gshared static bool __verbose_switch; 12 __gshared static bool __dry_switch; 13 __gshared static File vout; 14 //static uint verbose_mask; 15 16 shared static this() { 17 vout = stdout; 18 } 19 20 @trusted 21 bool verbose_switch() nothrow @nogc { 22 return __verbose_switch; 23 } 24 25 @trusted 26 bool dry_switch() nothrow @nogc { 27 return __dry_switch; 28 } 29 30 @trusted 31 private void __verbosef(Args...)(string fmt, lazy Args args) { 32 vout.writef(fmt, args); 33 } 34 35 @trusted 36 private void __verbose(Args...)(string fmt, lazy Args args) { 37 vout.writefln(fmt, args); 38 } 39 40 @safe 41 void verbose(Args...)(string fmt, lazy Args args) { 42 if (verbose_switch) { 43 __verbose(fmt, args); 44 } 45 } 46 47 @trusted 48 void noboseln(Args...)(string fmt, lazy Args args) { 49 if (!verbose_switch) { 50 __verbose(fmt, args); 51 stdout.flush; 52 } 53 } 54 55 @trusted 56 void nobose(Args...)(string fmt, lazy Args args) { 57 if (!verbose_switch) { 58 __verbosef(fmt, args); 59 stdout.flush; 60 } 61 } 62 63 @trusted 64 void error(const Exception e) { 65 error(e.msg); 66 if (verbose_switch) { 67 stderr.writefln("%s", e); 68 } 69 } 70 71 void error(Args...)(string fmt, lazy Args args) @trusted { 72 import std.format; 73 74 stderr.writefln("%sError: %s%s", RED, format(fmt, args), RESET); 75 } 76 77 void warn(Args...)(string fmt, lazy Args args) @trusted { 78 import std.format; 79 80 vout.writefln("%sWarning:%s%s", YELLOW, format(fmt, args), RESET); 81 } 82 83 void info(Args...)(string fmt, lazy Args args) @trusted { 84 import std.format; 85 86 vout.writefln("%s%s%s", BLUE, format(fmt, args), RESET); 87 } 88 89 void good(Args...)(string fmt, lazy Args args) @trusted { 90 import std.format; 91 92 vout.writefln("%s%s%s", GREEN, format(fmt, args), RESET); 93 } 94 95 alias SubTools = int function(string[])[string]; 96 Result subTool(const SubTools sub_tools, string[] args, const size_t index = 0) { 97 if (args[index].baseName in sub_tools) { 98 return Result(sub_tools[args[index].baseName](args[index .. $]), true); 99 } 100 if (index < 1) { 101 return subTool(sub_tools, args, index + 1); 102 } 103 return Result.init; 104 } 105 106 alias Result = Tuple!(int, "exit_code", bool, "executed"); 107 108 int forceSymLink(const SubTools sub_tools) { 109 foreach (toolname; sub_tools.keys) { 110 const symlink_filename = thisExePath.dirName.buildPath(toolname); 111 if (symlink_filename.exists) { 112 if (symlink_filename.getLinkAttributes.attrIsSymlink) { 113 symlink_filename.remove; 114 } 115 else { 116 stderr.writefln("Error: %s is not a symbolic link", symlink_filename); 117 return 1; 118 } 119 } 120 __verbose("%s -> %s", toolname, thisExePath); 121 symlink(thisExePath, symlink_filename); 122 } 123 return 0; 124 } 125 126 mixin template Main(alias _main, string name = null) { 127 import std.traits : fullyQualifiedName; 128 129 version (ONETOOL) { 130 enum alternative_name = name; 131 enum main_name = fullyQualifiedName!_main; 132 } 133 else { 134 int main(string[] args) { 135 return _main(args); 136 } 137 } 138 }