|
15 | 15 | module dub.platform;
|
16 | 16 |
|
17 | 17 | import std.array;
|
18 |
| -public import dub.data.platform; |
19 | 18 |
|
20 | 19 | // archCheck, compilerCheck, and platformCheck are used below and in
|
21 | 20 | // generatePlatformProbeFile, so they've been extracted into these strings
|
@@ -171,3 +170,119 @@ string determineCompiler()
|
171 | 170 | {
|
172 | 171 | mixin(compilerCheck);
|
173 | 172 | }
|
| 173 | + |
| 174 | +/** Matches a platform specification string against a build platform. |
| 175 | +
|
| 176 | + Specifications are build upon the following scheme, where each component |
| 177 | + is optional (indicated by []), but the order is obligatory: |
| 178 | + "[-platform][-architecture][-compiler]" |
| 179 | +
|
| 180 | + So the following strings are valid specifications: `"-windows-x86-dmd"`, |
| 181 | + `"-dmd"`, `"-arm"`, `"-arm-dmd"`, `"-windows-dmd"` |
| 182 | +
|
| 183 | + Params: |
| 184 | + platform = The build platform to match against the platform specification |
| 185 | + specification = The specification being matched. It must either be an |
| 186 | + empty string or start with a dash. |
| 187 | +
|
| 188 | + Returns: |
| 189 | + `true` if the given specification matches the build platform, `false` |
| 190 | + otherwise. Using an empty string as the platform specification will |
| 191 | + always result in a match. |
| 192 | +*/ |
| 193 | +bool matchesSpecification(in BuildPlatform platform, const(char)[] specification) |
| 194 | +{ |
| 195 | + import std.string : chompPrefix, format; |
| 196 | + import std.algorithm : canFind, splitter; |
| 197 | + import std.exception : enforce; |
| 198 | + |
| 199 | + if (specification.empty) return true; |
| 200 | + if (platform == BuildPlatform.any) return true; |
| 201 | + |
| 202 | + auto splitted = specification.chompPrefix("-").splitter('-'); |
| 203 | + enforce(!splitted.empty, format("Platform specification, if present, must not be empty: \"%s\"", specification)); |
| 204 | + |
| 205 | + if (platform.platform.canFind(splitted.front)) { |
| 206 | + splitted.popFront(); |
| 207 | + if (splitted.empty) |
| 208 | + return true; |
| 209 | + } |
| 210 | + if (platform.architecture.canFind(splitted.front)) { |
| 211 | + splitted.popFront(); |
| 212 | + if (splitted.empty) |
| 213 | + return true; |
| 214 | + } |
| 215 | + if (platform.compiler == splitted.front) { |
| 216 | + splitted.popFront(); |
| 217 | + enforce(splitted.empty, "No valid specification! The compiler has to be the last element: " ~ specification); |
| 218 | + return true; |
| 219 | + } |
| 220 | + return false; |
| 221 | +} |
| 222 | + |
| 223 | +/// |
| 224 | +unittest { |
| 225 | + auto platform = BuildPlatform(["posix", "linux"], ["x86_64"], "dmd"); |
| 226 | + assert(platform.matchesSpecification("")); |
| 227 | + assert(platform.matchesSpecification("posix")); |
| 228 | + assert(platform.matchesSpecification("linux")); |
| 229 | + assert(platform.matchesSpecification("linux-dmd")); |
| 230 | + assert(platform.matchesSpecification("linux-x86_64-dmd")); |
| 231 | + assert(platform.matchesSpecification("x86_64")); |
| 232 | + assert(!platform.matchesSpecification("windows")); |
| 233 | + assert(!platform.matchesSpecification("ldc")); |
| 234 | + assert(!platform.matchesSpecification("windows-dmd")); |
| 235 | + |
| 236 | + // Before PR#2279, a leading '-' was required |
| 237 | + assert(platform.matchesSpecification("-x86_64")); |
| 238 | +} |
| 239 | + |
| 240 | +/// Represents a platform a package can be build upon. |
| 241 | +struct BuildPlatform { |
| 242 | + /// Special constant used to denote matching any build platform. |
| 243 | + enum any = BuildPlatform(null, null, null, null, -1); |
| 244 | + |
| 245 | + /// Platform identifiers, e.g. ["posix", "windows"] |
| 246 | + string[] platform; |
| 247 | + /// CPU architecture identifiers, e.g. ["x86", "x86_64"] |
| 248 | + string[] architecture; |
| 249 | + /// Canonical compiler name e.g. "dmd" |
| 250 | + string compiler; |
| 251 | + /// Compiler binary name e.g. "ldmd2" |
| 252 | + string compilerBinary; |
| 253 | + /// Compiled frontend version (e.g. `2067` for frontend versions 2.067.x) |
| 254 | + int frontendVersion; |
| 255 | + /// Compiler version e.g. "1.11.0" |
| 256 | + string compilerVersion; |
| 257 | + /// Frontend version string from frontendVersion |
| 258 | + /// e.g: 2067 => "2.067" |
| 259 | + string frontendVersionString() const |
| 260 | + { |
| 261 | + import std.format : format; |
| 262 | + |
| 263 | + const maj = frontendVersion / 1000; |
| 264 | + const min = frontendVersion % 1000; |
| 265 | + return format("%d.%03d", maj, min); |
| 266 | + } |
| 267 | + /// |
| 268 | + unittest |
| 269 | + { |
| 270 | + BuildPlatform bp; |
| 271 | + bp.frontendVersion = 2067; |
| 272 | + assert(bp.frontendVersionString == "2.067"); |
| 273 | + } |
| 274 | + |
| 275 | + /// Checks to see if platform field contains windows |
| 276 | + bool isWindows() const { |
| 277 | + import std.algorithm : canFind; |
| 278 | + return this.platform.canFind("windows"); |
| 279 | + } |
| 280 | + /// |
| 281 | + unittest { |
| 282 | + BuildPlatform bp; |
| 283 | + bp.platform = ["windows"]; |
| 284 | + assert(bp.isWindows); |
| 285 | + bp.platform = ["posix"]; |
| 286 | + assert(!bp.isWindows); |
| 287 | + } |
| 288 | +} |
0 commit comments