1 /** 2 Copyright: Copyright (c) 2019, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dsnapshot.process; 7 8 import logger = std.experimental.logger; 9 import std.process; 10 public import std.process : wait; 11 public import std.typecons : Flag, Yes; 12 13 version (unittest) { 14 import unit_threaded.assertions; 15 } 16 17 class ProcessException : Exception { 18 int exitCode; 19 20 this(int exitCode, string msg = null, string file = __FILE__, int line = __LINE__) @safe pure nothrow { 21 super(msg, file, line); 22 this.exitCode = exitCode; 23 } 24 } 25 26 auto spawnProcessLog(Args...)(const(string)[] cmd_, auto ref Args args) { 27 logger.infof("%-(%s %)", cmd_); 28 return spawnProcess(cmd_, args); 29 } 30 31 /** 32 * Params: 33 * throwOnFailure = if true throws a `ProcessException` when the exit code isn't zero. 34 */ 35 auto spawnProcessLog(Flag!"throwOnFailure" throw_, Args...)(string[] cmd_, auto ref Args args) { 36 logger.infof("%-(%s %)", cmd_); 37 auto pid = spawnProcess(cmd_, args); 38 return WrapPid!(throw_)(pid); 39 } 40 41 /** Blocks until finished. 42 */ 43 auto executeLog(Args...)(const(string)[] cmd_, auto ref Args args) { 44 logger.infof("%-(%s %)", cmd_); 45 return execute(cmd_, args); 46 } 47 48 struct WrapPid(Flag!"throwOnFailure" throw_) { 49 Pid pid; 50 51 auto wait() { 52 auto ec = std.process.wait(pid); 53 54 static if (throw_) { 55 if (ec != 0) 56 throw new ProcessException(ec); 57 } 58 59 return ec; 60 } 61 } 62 63 @("shall throw a ProcessException when the process fails") 64 unittest { 65 spawnProcessLog!(Yes.throwOnFailure)(["false"]).wait.shouldThrow!(ProcessException); 66 }