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 public import blob_model : Blob; 17 18 import dextool.type : AbsolutePath; 19 20 @safe: 21 22 /** Validate source code locations for analyze and mutation. 23 */ 24 interface ValidateLoc { 25 /// Returns: the root directory that files to be mutated must reside inside 26 AbsolutePath getOutputDir() nothrow; 27 28 /// Returns: if a path should be analyzed for mutation points. 29 bool shouldAnalyze(AbsolutePath p); 30 31 /// ditto 32 bool shouldAnalyze(string p); 33 34 /// Returns: if a mutant are allowed to be written to this path. 35 bool shouldMutate(AbsolutePath p); 36 37 /// Duplicate the instance, 38 ValidateLoc dup(); 39 } 40 41 /** Filesystem I/O from the backend. 42 * 43 * TODO: rename outputDir to workdir. It is the terminology used in git. 44 * 45 * The implementation of the interface shall: 46 * ensure all SafeOutput objects are inside the _output directory_. 47 * 48 * The design is intended to create a clear distinction between output and 49 * input. It is to make it easier to do code review and reason about where 50 * filesystem output is created. 51 */ 52 interface FilesysIO { 53 import dextool.type : Path; 54 import std.stdio : File; 55 56 // these are here so backend do not need to import std.stdio which makes it 57 // easier to review. 58 File getDevNull(); 59 File getStdin(); 60 61 /// Convert a path to be relative to the root of the filesystem. 62 Path toRelativeRoot(Path p); 63 64 /// File output is restricted to this directory 65 AbsolutePath getOutputDir() nothrow; 66 67 /// 68 SafeOutput makeOutput(AbsolutePath p); 69 70 /// 71 Blob makeInput(AbsolutePath p); 72 73 /// Duplicate the instance, 74 FilesysIO dup(); 75 76 protected: 77 void putFile(AbsolutePath fname, const(ubyte)[] data); 78 } 79 80 struct SafeOutput { 81 import std.array : Appender; 82 83 private AbsolutePath fname; 84 private FilesysIO fsys; 85 private Appender!(ubyte[]) buf; 86 private bool is_open; 87 88 @disable this(this); 89 90 this(AbsolutePath fname, FilesysIO fsys) { 91 this.fname = fname; 92 this.fsys = fsys; 93 this.is_open = true; 94 } 95 96 ~this() { 97 close(); 98 } 99 100 // trusted: the data is copied therefore it is safe to cast away const. 101 void write(T)(inout T data) @trusted if (!is(T == ubyte[])) { 102 buf.put(cast(ubyte[]) data); 103 } 104 105 void write(T)(inout T data) if (is(T == ubyte[])) { 106 buf.put(data); 107 } 108 109 void write(Blob b) { 110 buf.put(b.content); 111 } 112 113 void close() { 114 if (is_open) { 115 fsys.putFile(fname, buf.data); 116 buf.clear; 117 } 118 is_open = false; 119 } 120 }