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 
38 /** Filesystem I/O from the backend.
39  *
40  * TODO: rename outputDir to workdir. It is the terminology used in git.
41  *
42  * The implementation of the interface shall:
43  *  ensure all SafeOutput objects are inside the _output directory_.
44  *
45  * The design is intended to create a clear distinction between output and
46  * input. It is to make it easier to do code review and reason about where
47  * filesystem output is created.
48  */
49 interface FilesysIO {
50     import dextool.type : Path;
51     import std.stdio : File;
52 
53     // these are here so backend do not need to import std.stdio which makes it
54     // easier to review.
55     File getDevNull();
56     File getStdin();
57 
58     /// Convert a path to be relative to the root of the filesystem.
59     Path toRelativeRoot(Path p);
60 
61     /// File output is restricted to this directory
62     AbsolutePath getOutputDir() nothrow;
63 
64     ///
65     SafeOutput makeOutput(AbsolutePath p);
66 
67     ///
68     Blob makeInput(AbsolutePath p);
69 
70 protected:
71     void putFile(AbsolutePath fname, const(ubyte)[] data);
72 }
73 
74 struct SafeOutput {
75     import std.array : Appender;
76 
77     private AbsolutePath fname;
78     private FilesysIO fsys;
79     private Appender!(ubyte[]) buf;
80     private bool is_open;
81 
82     @disable this(this);
83 
84     this(AbsolutePath fname, FilesysIO fsys) {
85         this.fname = fname;
86         this.fsys = fsys;
87         this.is_open = true;
88     }
89 
90     ~this() {
91         close();
92     }
93 
94     // trusted: the data is copied therefore it is safe to cast away const.
95     void write(T)(inout T data) @trusted if (!is(T == ubyte[])) {
96         buf.put(cast(ubyte[]) data);
97     }
98 
99     void write(T)(inout T data) if (is(T == ubyte[])) {
100         buf.put(data);
101     }
102 
103     void write(Blob b) {
104         buf.put(b.content);
105     }
106 
107     void close() {
108         if (is_open) {
109             fsys.putFile(fname, buf.data);
110             buf.clear;
111         }
112         is_open = false;
113     }
114 }