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 }