Skip to content

Commit 7b5e24f

Browse files
Geod24WebFreak001
authored andcommitted
Use Configy to read dub.selections.json
1 parent 7dcbe07 commit 7b5e24f

File tree

2 files changed

+114
-9
lines changed

2 files changed

+114
-9
lines changed

source/dub/project.d

+17-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import dub.package_;
2020
import dub.packagemanager;
2121
import dub.recipe.selection;
2222

23+
import configy.Read;
24+
2325
import std.algorithm;
2426
import std.array;
2527
import std.conv : to;
@@ -75,14 +77,11 @@ class Project {
7577
m_packageManager = package_manager;
7678
m_rootPackage = pack;
7779

78-
auto selverfile = m_rootPackage.path ~ SelectedVersions.defaultFile;
80+
auto selverfile = (m_rootPackage.path ~ SelectedVersions.defaultFile).toNativeString();
7981
if (existsFile(selverfile)) {
80-
try m_selections = new SelectedVersions(selverfile);
81-
catch(Exception e) {
82-
logWarn("Failed to load %s: %s", SelectedVersions.defaultFile, e.msg);
83-
logDiagnostic("Full error: %s", e.toString().sanitize);
84-
m_selections = new SelectedVersions;
85-
}
82+
auto selected = parseConfigFileSimple!Selected(selverfile);
83+
enforce(!selected.isNull(), "Could not read '" ~ selverfile ~ "'");
84+
m_selections = new SelectedVersions(selected.get());
8685
} else m_selections = new SelectedVersions;
8786

8887
reinit();
@@ -1681,9 +1680,16 @@ final class SelectedVersions {
16811680
enum defaultFile = "dub.selections.json";
16821681

16831682
/// Constructs a new empty version selection.
1684-
public this(Selected data = Selected(FileVersion)) @safe pure nothrow @nogc
1683+
public this(uint version_ = FileVersion) @safe pure nothrow @nogc
1684+
{
1685+
this.m_selections = Selected(version_);
1686+
}
1687+
1688+
/// Constructs a new non-empty version selection.
1689+
public this(Selected data) @safe pure nothrow @nogc
16851690
{
16861691
this.m_selections = data;
1692+
this.m_bare = false;
16871693
}
16881694

16891695
/** Constructs a new version selection from JSON data.
@@ -1700,6 +1706,7 @@ final class SelectedVersions {
17001706

17011707
/** Constructs a new version selections from an existing JSON file.
17021708
*/
1709+
deprecated("JSON deserialization is deprecated")
17031710
this(NativePath path)
17041711
{
17051712
auto json = jsonFromFile(path);
@@ -1838,6 +1845,7 @@ final class SelectedVersions {
18381845
return d.toJson(true);
18391846
}
18401847

1848+
deprecated("JSON deserialization is deprecated")
18411849
static Dependency dependencyFromJson(Json j)
18421850
{
18431851
if (j.type == Json.Type.string)
@@ -1861,6 +1869,7 @@ final class SelectedVersions {
18611869
return serialized;
18621870
}
18631871

1872+
deprecated("JSON deserialization is deprecated")
18641873
private void deserialize(Json json)
18651874
{
18661875
const fileVersion = cast(int)json["fileVersion"];

source/dub/recipe/selection.d

+97-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,108 @@
44
module dub.recipe.selection;
55

66
import dub.dependency;
7+
import dub.internal.vibecompat.core.file : NativePath;
8+
9+
import configy.Attributes;
10+
11+
import std.exception;
712

813
public struct Selected
914
{
1015
/// The current version of the file format
1116
public uint fileVersion;
1217

1318
/// 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")));
15111
}

0 commit comments

Comments
 (0)