1 // Scriptlike: Utility to aid in script-like programs. 2 // Written in the D programming language. 3 4 /// Copyright: Copyright (C) 2014-2015 Nick Sabalausky 5 /// License: $(LINK2 https://github.com/Abscissa/scriptlike/blob/master/LICENSE.txt, zlib/libpng) 6 /// Authors: Nick Sabalausky 7 8 module scriptlike.core; 9 10 import std.conv; 11 import std.string; 12 13 /// If true, all commands will be echoed. By default, they will be 14 /// echoed to stdout, but you can override this with scriptlikeCustomEcho. 15 bool scriptlikeEcho = false; 16 17 /// Alias for backwards-compatibility. This will be deprecated in the future. 18 /// You should use scriptlikeEcho insetad. 19 alias scriptlikeTraceCommands = scriptlikeEcho; 20 21 /++ 22 If true, then run, tryRun, file write, file append, and all the echoable 23 commands that modify the filesystem will be echoed to stdout (regardless 24 of scriptlikeEcho) and NOT actually executed. 25 26 Warning! This is NOT a "set it and forget it" switch. You must still take 27 care to write your script in a way that's dryrun-safe. Two things to remember: 28 29 1. ONLY Scriptlike's functions will obey this setting. Calling Phobos 30 functions directly will BYPASS this setting. 31 32 2. If part of your script relies on a command having ACTUALLY been run, then 33 that command will fail. You must avoid that situation or work around it. 34 For example: 35 36 --------------------- 37 run(`date > tempfile`); 38 39 // The following will FAIL or behave INCORRECTLY in dryrun mode: 40 auto data = cast(string)read("tempfile"); 41 run("echo "~data); 42 --------------------- 43 44 That may be an unrealistic example, but it demonstrates the problem: Normally, 45 the code above should run fine (at least on posix). But in dryrun mode, 46 "date" will not actually be run. Therefore, tempfile will neither be created 47 nor overwritten. Result: Either an exception reading a non-existent file, 48 or outdated information will be displayed. 49 50 Scriptlike cannot anticipate or handle such situations. So it's up to you to 51 make sure your script is dryrun-safe. 52 +/ 53 bool scriptlikeDryRun = false; 54 55 /++ 56 By default, scriptlikeEcho and scriptlikeDryRun echo to stdout. 57 You can override this behavior by setting scriptlikeCustomEcho to your own 58 sink delegate. Since this is used for logging, don't forget to flush your output. 59 60 Reset this to null to go back to Scriptlike's default of "echo to stdout" again. 61 62 Note, setting this does not automatically enable echoing. You still need to 63 set either scriptlikeEcho or scriptlikeDryRun to true. 64 +/ 65 void delegate(string) scriptlikeCustomEcho; 66 67 /++ 68 Output text lazily through scriptlike's echo logger. 69 Does nothing if scriptlikeEcho and scriptlikeDryRun are both false. 70 71 The yapFunc version automatically prepends the output with the 72 name of the calling function. Ex: 73 74 ---------------- 75 void foo(int i = 42) { 76 // Outputs: 77 // foo: i = 42 78 yapFunc("i = ", i); 79 } 80 ---------------- 81 +/ 82 void yap(T...)(lazy T args) 83 { 84 import std.stdio; 85 86 if(scriptlikeEcho || scriptlikeDryRun) 87 { 88 if(scriptlikeCustomEcho) 89 scriptlikeCustomEcho(text(args)); 90 else 91 { 92 writeln(args); 93 stdout.flush(); 94 } 95 } 96 } 97 98 ///ditto 99 void yapFunc(string funcName=__FUNCTION__, T...)(lazy T args) 100 { 101 static assert(funcName != ""); 102 103 auto funcNameSimple = funcName.split(".")[$-1]; 104 yap(funcNameSimple, ": ", args); 105 } 106 107 /// Maintained for backwards-compatibility. Will be deprecated. 108 /// Use 'yap' instead. 109 void echoCommand(lazy string msg) 110 { 111 yap(msg); 112 }