|
4 | 4 | module dub.recipe.selection;
|
5 | 5 |
|
6 | 6 | import dub.dependency;
|
| 7 | +import dub.internal.vibecompat.core.file : NativePath; |
| 8 | + |
| 9 | +import configy.Attributes; |
| 10 | + |
| 11 | +import std.exception; |
7 | 12 |
|
8 | 13 | public struct Selected
|
9 | 14 | {
|
10 | 15 | /// The current version of the file format
|
11 | 16 | public uint fileVersion;
|
12 | 17 |
|
13 | 18 | /// The selected package and their matching versions
|
14 |
| - public Dependency[string] versions; |
| 19 | + public YAMLSelectedDependency[string] versions; |
| 20 | +} |
| 21 | + |
| 22 | + |
| 23 | +/// Actual representation of a dependency as permitted in `dub.selections.json` |
| 24 | +private struct SelectedDependency |
| 25 | +{ |
| 26 | + @Optional @Name("version") string version_; |
| 27 | + @Optional string path; |
| 28 | + @Optional string repository; |
| 29 | + |
| 30 | + public void validate () const scope @safe pure |
| 31 | + { |
| 32 | + enforce(this.version_.length || this.path.length || this.repository.length, |
| 33 | + "Need to provide a version string, or an object with one of the following fields: `version`, `path`, or `repository`"); |
| 34 | + enforce(!this.path.length || !this.repository.length, |
| 35 | + "Cannot provide a `path` dependency if a repository dependency is used"); |
| 36 | + enforce(!this.path.length || !this.version_.length, |
| 37 | + "Cannot provide a `path` dependency if a `version` dependency is used"); |
| 38 | + enforce(!this.repository.length || this.version_.length, |
| 39 | + "Cannot provide a `repository` dependency without a `version`"); |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +/// Wrapper around `SelectedDependency` to do deserialization but still provide |
| 44 | +/// a `Dependency` object to client code. |
| 45 | +private struct YAMLSelectedDependency |
| 46 | +{ |
| 47 | + private SelectedDependency representation; |
| 48 | + |
| 49 | + public Dependency actual; |
| 50 | + alias actual this; |
| 51 | + |
| 52 | + /// Constructor, used in `fromYAML` |
| 53 | + public this (inout(Dependency) dep) inout @safe pure nothrow @nogc |
| 54 | + { |
| 55 | + this.actual = dep; |
| 56 | + } |
| 57 | + |
| 58 | + /// Allow external code to assign to this object as if it was a `Dependency` |
| 59 | + public ref YAMLSelectedDependency opAssign (Dependency dep) return pure nothrow @nogc |
| 60 | + { |
| 61 | + this.actual = dep; |
| 62 | + return this; |
| 63 | + } |
| 64 | + |
| 65 | + /// Read a `Dependency` from the config file - Required to support both short and long form |
| 66 | + static YAMLSelectedDependency fromYAML (scope ConfigParser!YAMLSelectedDependency p) |
| 67 | + { |
| 68 | + import dyaml.node; |
| 69 | + |
| 70 | + if (p.node.nodeID == NodeID.scalar) |
| 71 | + return YAMLSelectedDependency(Dependency(Version(p.node.as!string))); |
| 72 | + |
| 73 | + auto d = p.parseField!"representation"; |
| 74 | + if (d.path.length) |
| 75 | + return YAMLSelectedDependency(Dependency(NativePath(d.path))); |
| 76 | + else |
| 77 | + { |
| 78 | + assert(d.version_.length); |
| 79 | + if (d.repository.length) |
| 80 | + return YAMLSelectedDependency(Dependency(Repository(d.repository, d.version_))); |
| 81 | + return YAMLSelectedDependency(Dependency(Version(d.version_))); |
| 82 | + } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +// Ensure we can read all type of dependencies |
| 87 | +unittest |
| 88 | +{ |
| 89 | + import configy.Read : parseConfigString; |
| 90 | + import dub.internal.vibecompat.core.file : NativePath; |
| 91 | + |
| 92 | + immutable string content = `{ |
| 93 | + "fileVersion": 1, |
| 94 | + "versions": { |
| 95 | + "simple": "1.5.6", |
| 96 | + "branch": "~master", |
| 97 | + "branch2": "~main", |
| 98 | + "path": { "path": "../some/where" }, |
| 99 | + "repository": { "repository": "git+https://github.com/dlang/dub", "version": "123456123456123456" } |
| 100 | + } |
| 101 | +}`; |
| 102 | + |
| 103 | + auto s = parseConfigString!Selected(content, "/dev/null"); |
| 104 | + assert(s.fileVersion == 1); |
| 105 | + assert(s.versions.length == 5); |
| 106 | + assert(s.versions["simple"] == Dependency(Version("1.5.6"))); |
| 107 | + assert(s.versions["branch"] == Dependency(Version("~master"))); |
| 108 | + assert(s.versions["branch2"] == Dependency(Version("~main"))); |
| 109 | + assert(s.versions["path"] == Dependency(NativePath("../some/where"))); |
| 110 | + assert(s.versions["repository"] == Dependency(Repository("git+https://github.com/dlang/dub", "123456123456123456"))); |
15 | 111 | }
|
0 commit comments