1 /** 2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.backend.interface_; 11 12 import std.exception : collectException; 13 import std.stdio : File; 14 import logger = std.experimental.logger; 15 16 import dextool.type : AbsolutePath; 17 18 @safe: 19 20 /** Validate source code locations for analyze and mutation. 21 */ 22 interface ValidateLoc { 23 /// Returns: the root directory that files to be mutated must reside inside 24 AbsolutePath getOutputDir() nothrow; 25 26 /// Returns: if a path should be analyzed for mutation points. 27 bool shouldAnalyze(AbsolutePath p); 28 29 /// ditto 30 bool shouldAnalyze(string p); 31 32 /// Returns: if a mutant are allowed to be written to this path. 33 bool shouldMutate(AbsolutePath p); 34 } 35 36 /** Filesystem I/O from the backend. 37 * 38 * TODO: rename outputDir to workdir. It is the terminology used in git. 39 * 40 * The implementation of the interface shall: 41 * ensure all SafeOutput objects are inside the _output directory_. 42 * 43 * The design is intended to create a clear distinction between output and 44 * input. It is to make it easier to do code review and reason about where 45 * filesystem output is created. 46 */ 47 interface FilesysIO { 48 import std.stdio : File; 49 50 // these are here so backend do not need to import std.stdio which makes it 51 // easier to review. 52 File getDevNull(); 53 File getStdin(); 54 55 /// File output is restricted to this directory 56 AbsolutePath getOutputDir() nothrow; 57 58 /// 59 SafeOutput makeOutput(AbsolutePath p); 60 61 /// 62 SafeInput makeInput(AbsolutePath p); 63 64 protected: 65 void putFile(AbsolutePath fname, const(ubyte)[] data); 66 } 67 68 struct SafeOutput { 69 import std.array : Appender; 70 71 private AbsolutePath fname; 72 private FilesysIO fsys; 73 private Appender!(ubyte[]) buf; 74 private bool is_open; 75 76 @disable this(this); 77 78 this(AbsolutePath fname, FilesysIO fsys) { 79 this.fname = fname; 80 this.fsys = fsys; 81 this.is_open = true; 82 } 83 84 ~this() { 85 close(); 86 } 87 88 // trusted: the data is copied therefore it is safe to cast away const. 89 void write(T)(inout T data) @trusted if (!is(T == ubyte[])) { 90 buf.put(cast(ubyte[]) data); 91 } 92 93 void write(T)(inout T data) if (is(T == ubyte[])) { 94 buf.put(data); 95 } 96 97 void close() { 98 if (is_open) { 99 fsys.putFile(fname, buf.data); 100 buf.clear; 101 } 102 is_open = false; 103 } 104 } 105 106 struct SafeInput { 107 private ubyte[] data; 108 109 this(ubyte[] data) { 110 this.data = data; 111 } 112 113 ubyte[] read() { 114 return data; 115 } 116 }