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 @safe: 11 12 enum ExitStatusType { 13 Ok, 14 Errors 15 } 16 17 struct DextoolVersion { 18 string payload; 19 alias payload this; 20 } 21 22 /// No guarantee regarding the path. May be absolute, relative, contain a '~'. 23 /// The user of this type must do all the safety checks to ensure that the 24 /// datacontained in valid. 25 struct Path { 26 string payload; 27 alias payload this; 28 29 bool empty() @safe pure nothrow const @nogc { 30 return payload.length == 0; 31 } 32 33 bool opEquals(const string s) @safe pure nothrow const @nogc { 34 return payload == s; 35 } 36 37 bool opEquals(const AbsolutePath s) @safe pure nothrow const @nogc { 38 return payload == s.payload; 39 } 40 } 41 42 /** The path is guaranteed to be the absolute path. 43 * 44 * The user of the type has to make an explicit judgment when using the 45 * assignment operator. Either a `Path` and then pay the cost of the path 46 * expansion or an absolute which is already assured to be _ok_. 47 * This divides the domain in two, one unchecked and one checked. 48 */ 49 struct AbsolutePath { 50 import std.path : buildNormalizedPath, asAbsolutePath, asNormalizedPath; 51 import std.utf : toUTF8; 52 53 Path payload; 54 alias payload this; 55 56 invariant { 57 import std.path : isAbsolute; 58 59 assert(payload.empty || payload.isAbsolute); 60 } 61 62 this(Path p) { 63 // the second buildNormalizedPath is needed to correctly resolve "." 64 // otherwise it is resolved to /foo/bar/. 65 payload = buildNormalizedPath(expand(p)).asAbsolutePath.asNormalizedPath.toUTF8.Path; 66 } 67 68 /// Build the normalised path from workdir. 69 this(Path p, Path workdir) { 70 // the second buildNormalizedPath is needed to correctly resolve "." 71 // otherwise it is resolved to /foo/bar/. 72 payload = buildNormalizedPath(expand(workdir), expand(p)) 73 .asAbsolutePath.asNormalizedPath.toUTF8.Path; 74 } 75 76 pure nothrow @nogc void opAssign(AbsolutePath p) { 77 payload = p.payload; 78 } 79 80 pure nothrow const @nogc string opCast(T : string)() { 81 return payload; 82 } 83 84 bool opEquals(const string s) @safe pure nothrow const @nogc { 85 return payload == s; 86 } 87 88 bool opEquals(const Path s) @safe pure nothrow const @nogc { 89 return payload == s.payload; 90 } 91 92 bool opEquals(const AbsolutePath s) @safe pure nothrow const @nogc { 93 return payload == s.payload; 94 } 95 96 private static Path expand(Path p) @trusted { 97 import std.path : expandTilde; 98 99 return p.expandTilde.Path; 100 } 101 } 102 103 /** During construction checks that the file exists on the filesystem. 104 * 105 * If it doesn't exist it will throw an Exception. 106 */ 107 struct Exists(T) { 108 AbsolutePath payload; 109 alias payload this; 110 111 this(AbsolutePath p) { 112 import std.file : exists, FileException; 113 114 if (!exists(p)) { 115 throw new FileException("File do not exist: " ~ cast(string) p); 116 } 117 118 payload = p; 119 } 120 121 this(Exists!T p) { 122 payload = p.payload; 123 } 124 125 void opAssign(Exists!T p) pure nothrow @nogc { 126 payload = p; 127 } 128 } 129 130 auto makeExists(T)(T p) { 131 return Exists!T(p); 132 } 133 134 @("shall always be the absolute path") 135 unittest { 136 import std.algorithm : canFind; 137 import std.path; 138 import unit_threaded; 139 140 AbsolutePath(Path("~/foo")).canFind('~').shouldEqual(false); 141 AbsolutePath(Path("foo")).isAbsolute.shouldEqual(true); 142 } 143 144 @("shall expand . without any trailing /.") 145 unittest { 146 import std.algorithm : canFind; 147 import unit_threaded; 148 149 AbsolutePath(Path(".")).canFind('.').shouldBeFalse; 150 AbsolutePath(Path("."), Path(".")).canFind('.').shouldBeFalse; 151 } 152 153 @("shall be an instantiation of Exists") 154 nothrow unittest { 155 // the file is not expected to exist. 156 157 try { 158 auto p = makeExists(AbsolutePath(Path("foo"))); 159 } catch (Exception e) { 160 } 161 }