1 /** 2 Date: 2015-2017, Joakim Brännström 3 License: MPL-2, Mozilla Public License 2.0 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module dextool.type; 7 8 public import dextool.compilation_db : FilterClangFlag; 9 10 import dextool.utility : asAbsNormPath; 11 12 @safe: 13 14 enum ExitStatusType { 15 Ok, 16 Errors 17 } 18 19 /** Prefix used for prepending generated code with a unique string to avoid 20 * name collisions. 21 * See specific functions for how it is used. 22 */ 23 struct StubPrefix { 24 string payload; 25 alias payload this; 26 } 27 28 /// Prefix used for prepending generated files. 29 struct FilePrefix { 30 string payload; 31 alias payload this; 32 } 33 34 struct MainFileName { 35 string payload; 36 alias payload this; 37 } 38 39 struct MainName { 40 string payload; 41 alias payload this; 42 } 43 44 struct MainNs { 45 string payload; 46 alias payload this; 47 } 48 49 struct MainInterface { 50 string payload; 51 alias payload this; 52 } 53 54 struct DextoolVersion { 55 string payload; 56 alias payload this; 57 } 58 59 struct CustomHeader { 60 string payload; 61 alias payload this; 62 } 63 64 /// The raw arguments from the command line. 65 struct RawCliArguments { 66 string[] payload; 67 alias payload this; 68 } 69 70 /// Used when writing data to files on the filesystem. 71 enum WriteStrategy { 72 overwrite, 73 skip 74 } 75 76 //TODO remove FileNames 77 struct FileNames { 78 string[] payload; 79 alias payload this; 80 } 81 82 struct InFiles { 83 string[] payload; 84 alias payload this; 85 } 86 87 /// No guarantee regarding the path. May be absolute, relative, contain a '~'. 88 /// The user of this type must do all the safety checks to ensure that the 89 /// datacontained in valid. 90 struct Path { 91 string payload; 92 alias payload this; 93 } 94 95 /// ditto 96 struct DirName { 97 Path payload; 98 alias payload this; 99 100 pure nothrow @nogc this(string p) { 101 payload = Path(p); 102 } 103 } 104 105 /// ditto 106 struct FileName { 107 pure @nogc nothrow: 108 109 Path payload; 110 alias payload this; 111 112 this(Path p) { 113 payload = p; 114 } 115 116 pure nothrow @nogc this(string p) { 117 payload = Path(p); 118 } 119 } 120 121 /** The path is guaranteed to be the absolute path. 122 * 123 * The user of the type has to make an explicit judgment when using the 124 * assignment operator. Either a `FileName` and then pay the cost of the path 125 * expansion or an absolute which is already assured to be _ok_. 126 * This divides the domain in two, one unchecked and one checked. 127 */ 128 struct AbsolutePath { 129 import std.path : expandTilde, buildNormalizedPath; 130 131 Path payload; 132 alias payload this; 133 134 invariant { 135 import std.path : isAbsolute; 136 137 assert(payload.length == 0 || payload.isAbsolute); 138 } 139 140 immutable this(AbsolutePath p) { 141 this.payload = p.payload; 142 } 143 144 this(Path p) { 145 auto p_expand = () @trusted { return p.expandTilde; }(); 146 // the second buildNormalizedPath is needed to correctly resolve "." 147 // otherwise it is resolved to /foo/bar/. 148 payload = buildNormalizedPath(p_expand).asAbsNormPath.Path; 149 } 150 151 /// Build the normalised path from workdir. 152 this(Path p, DirName workdir) { 153 auto p_expand = () @trusted { return p.expandTilde; }(); 154 auto workdir_expand = () @trusted { return workdir.expandTilde; }(); 155 // the second buildNormalizedPath is needed to correctly resolve "." 156 // otherwise it is resolved to /foo/bar/. 157 payload = buildNormalizedPath(workdir_expand, p_expand).asAbsNormPath.Path; 158 } 159 160 void opAssign(FileName p) { 161 payload = typeof(this)(p).payload; 162 } 163 164 pure nothrow @nogc void opAssign(AbsolutePath p) { 165 payload = p.payload; 166 } 167 168 pure nothrow const @nogc FileName opCast(T : FileName)() { 169 return FileName(payload); 170 } 171 172 pure nothrow const @nogc string opCast(T : string)() { 173 return payload; 174 } 175 } 176 177 struct AbsoluteFileName { 178 AbsolutePath payload; 179 alias payload this; 180 181 pure nothrow @nogc this(AbsolutePath p) { 182 payload = p; 183 } 184 } 185 186 struct AbsoluteDirectory { 187 AbsolutePath payload; 188 alias payload this; 189 190 pure nothrow @nogc this(AbsolutePath p) { 191 payload = p; 192 } 193 } 194 195 struct ShellCommand { 196 AbsolutePath program; 197 string[] arguments; 198 199 this(string cmd) { 200 import std.uni : isWhite; 201 import std.array : split; 202 203 string[] argv = cmd.split!isWhite; 204 program = Path(argv[0]).AbsolutePath; 205 arguments = argv[1 .. $]; 206 } 207 } 208 209 /** During construction checks that the file exists on the filesystem. 210 * 211 * If it doesn't exist it will throw an Exception. 212 */ 213 struct Exists(T) { 214 AbsolutePath payload; 215 alias payload this; 216 217 this(AbsolutePath p) { 218 import std.file : exists, FileException; 219 220 if (!exists(p)) { 221 throw new FileException("File do not exist: " ~ cast(string) p); 222 } 223 224 payload = p; 225 } 226 227 this(Exists!T p) { 228 payload = p.payload; 229 } 230 231 void opAssign(Exists!T p) pure nothrow @nogc { 232 payload = p; 233 } 234 } 235 236 auto makeExists(T)(T p) { 237 return Exists!T(p); 238 } 239 240 @("shall always be the absolute path") 241 unittest { 242 import std.algorithm : canFind; 243 import std.path; 244 import unit_threaded; 245 246 AbsolutePath(FileName("~/foo")).canFind('~').shouldEqual(false); 247 AbsolutePath(FileName("foo")).isAbsolute.shouldEqual(true); 248 } 249 250 @("shall expand . without any trailing /.") 251 unittest { 252 import std.algorithm : canFind; 253 import unit_threaded; 254 255 AbsolutePath(FileName(".")).canFind('.').shouldBeFalse; 256 AbsolutePath(FileName("."), DirName(".")).canFind('.').shouldBeFalse; 257 } 258 259 @("shall be an instantiation of Exists") 260 nothrow unittest { 261 // the file is not expected to exist. 262 263 try { 264 auto p = makeExists(AbsolutePath(FileName("foo"))); 265 } catch (Exception e) { 266 } 267 }