1 /+ 2 This file is part of Reloaded Vibes. 3 Copyright (c) 2019 0xEAB 4 5 Distributed under the Boost Software License, Version 1.0. 6 (See accompanying file LICENSE_1_0.txt or copy at 7 https://www.boost.org/LICENSE_1_0.txt) 8 +/ 9 module reloadedvibes.action; 10 11 import std.stdio : stderr, stdout; 12 import std.process : spawnShell, wait; 13 import reloadedvibes.watcher; 14 15 alias Action = void delegate() @safe; 16 17 final class ActionWatcherClient : WatcherClient 18 { 19 private 20 { 21 Action _action; 22 } 23 24 public this(Watcher w, Action action) @safe pure nothrow 25 { 26 super(w); 27 this._action = action; 28 } 29 30 public override void notify() @safe 31 { 32 this._action(); 33 this.setNotified(); 34 } 35 } 36 37 ActionWatcherClient fromCommandLines(Watcher w, string[] commandLines) 38 { 39 enum sepLine = "-------------------------------------------------------------------------------"; 40 enum segmentPre = "----{ "; 41 enum segmentPost = " }"; 42 enum segmentsLength = (segmentPre.length + segmentPost.length); 43 enum embeddedCMDMaxLength = 79 - segmentsLength; 44 45 string[] sep = new string[commandLines.length]; 46 47 foreach (idx, cmd; commandLines) 48 { 49 if (cmd.length >= embeddedCMDMaxLength) 50 { 51 sep[idx] = sepLine ~ "\n" ~ cmd ~ "\n" ~ sepLine ~ "\n"; 52 continue; 53 } 54 55 immutable rest = embeddedCMDMaxLength - cmd.length; 56 sep[idx] = segmentPre ~ cmd ~ segmentPost ~ sepLine[0 .. rest] ~ "\n"; 57 } 58 59 return new ActionWatcherClient(w, delegate() @trusted { 60 foreach (idx, cmd; commandLines) 61 { 62 try 63 { 64 stdout.writeln("\n", sep[idx]); 65 immutable exitCode = spawnShell(cmd).wait(); 66 67 if (exitCode != 0) 68 { 69 stderr.writeln("\n", sepLine, 70 "\nAction {" ~ cmd ~ "} failed with exit code ", exitCode); 71 } 72 } 73 catch (Exception ex) 74 { 75 stderr.writeln("\n", sepLine, "\nAction {" ~ cmd ~ "} failed: ", ex.msg); 76 } 77 finally 78 { 79 stdout.writeln("\n"); 80 } 81 } 82 }); 83 }