diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index f31f597..8d3dd12 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -15,6 +15,7 @@ import dub.internal.logging; import dub.package_; import dub.recipe.io; +import dub.recipe.selection; import dub.internal.configy.Exceptions; public import dub.internal.configy.Read : StrictMode; @@ -1071,6 +1072,69 @@ return digest[].dup; } + /** + * Writes the selections file (`dub.selections.json`) + * + * The selections file is only used for the root package / project. + * However, due to it being a filesystem interaction, it is managed + * from the `PackageManager`. + * + * Params: + * project = The root package / project to read the selections file for. + * selections = The `SelectionsFile` to write. + * overwrite = Whether to overwrite an existing selections file. + * True by default. + */ + public void writeSelections(in Package project, in Selections!1 selections, + bool overwrite = true) + { + import dub.internal.vibecompat.core.file; + + const path = project.path ~ "dub.selections.json"; + if (!overwrite && existsFile(path)) + return; + writeFile(path, selectionsToString(selections)); + } + + /// Package function to avoid code duplication with deprecated + /// SelectedVersions.save, merge with `writeSelections` in + /// the future. + package static string selectionsToString (in Selections!1 s) + { + Json json = selectionsToJSON(s); + assert(json.type == Json.Type.object); + assert(json.length == 2); + assert(json["versions"].type != Json.Type.undefined); + + auto result = appender!string(); + result.put("{\n\t\"fileVersion\": "); + result.writeJsonString(json["fileVersion"]); + result.put(",\n\t\"versions\": {"); + auto vers = json["versions"].get!(Json[string]); + bool first = true; + foreach (k; vers.byKey.array.sort()) { + if (!first) result.put(","); + else first = false; + result.put("\n\t\t"); + result.writeJsonString(Json(k)); + result.put(": "); + result.writeJsonString(vers[k]); + } + result.put("\n\t}\n}\n"); + return result.data; + } + + /// Ditto + package static Json selectionsToJSON (in Selections!1 s) + { + Json serialized = Json.emptyObject; + serialized["fileVersion"] = s.fileVersion; + serialized["versions"] = Json.emptyObject; + foreach (p, dep; s.versions) + serialized["versions"][p] = dep.toJson(true); + return serialized; + } + /// Adds the package and scans for sub-packages. protected void addPackages(ref Package[] dst_repos, Package pack) { diff --git a/source/dub/project.d b/source/dub/project.d index f28c337..0f4ce82 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -1340,10 +1340,9 @@ const name = PackageName(m_rootPackage.basePackage.name); if (m_selections.hasSelectedVersion(name)) m_selections.deselectVersion(name); - - auto path = m_rootPackage.path ~ SelectedVersions.defaultFile; - if (m_selections.dirty || !existsFile(path)) - m_selections.save(path); + this.m_packageManager.writeSelections( + this.m_rootPackage, this.m_selections.m_selections, + this.m_selections.dirty); } deprecated bool isUpgradeCacheUpToDate() @@ -1967,30 +1966,10 @@ should be used as the file name and the directory should be the root directory of the project's root package. */ + deprecated("Use `PackageManager.writeSelections` to write a `SelectionsFile`") void save(NativePath path) { - Json json = serialize(); - auto result = appender!string(); - - assert(json.type == Json.Type.object); - assert(json.length == 2); - assert(json["versions"].type != Json.Type.undefined); - - result.put("{\n\t\"fileVersion\": "); - result.writeJsonString(json["fileVersion"]); - result.put(",\n\t\"versions\": {"); - auto vers = json["versions"].get!(Json[string]); - bool first = true; - foreach (k; vers.byKey.array.sort()) { - if (!first) result.put(","); - else first = false; - result.put("\n\t\t"); - result.writeJsonString(Json(k)); - result.put(": "); - result.writeJsonString(vers[k]); - } - result.put("\n\t}\n}\n"); - path.writeFile(result.data); + path.writeFile(PackageManager.selectionsToString(this.m_selections)); m_dirty = false; m_bare = false; } @@ -2014,14 +1993,9 @@ else throw new Exception(format("Unexpected type for dependency: %s", j)); } - Json serialize() - const { - Json serialized = Json.emptyObject; - serialized["fileVersion"] = m_selections.fileVersion; - serialized["versions"] = Json.emptyObject; - foreach (p, dep; m_selections.versions) - serialized["versions"][p] = dep.toJson(true); - return serialized; + deprecated("JSON serialization is deprecated") + Json serialize() const { + return PackageManager.selectionsToJSON(this.m_selections); } deprecated("JSON deserialization is deprecated") diff --git a/source/dub/test/base.d b/source/dub/test/base.d index 3c7f173..e05d9ae 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -65,6 +65,7 @@ import dub.packagesuppliers.packagesupplier; import dub.project; import dub.recipe.io : parsePackageRecipe; +import dub.recipe.selection; /// Example of a simple unittest for a project with a single dependency unittest @@ -219,7 +220,7 @@ /// Loads a specific package as the main project package (can be a sub package) public override void loadPackage(Package pack) { - m_project = new Project(m_packageManager, pack, new TestSelectedVersions()); + m_project = new Project(m_packageManager, pack, new SelectedVersions()); } /// Reintroduce parent overloads @@ -238,31 +239,6 @@ } /** - * - */ -public class TestSelectedVersions : SelectedVersions { - import dub.recipe.selection; - - /// Forward to parent's constructor - public this(uint version_ = FileVersion) @safe pure - { - super(version_); - } - - /// Ditto - public this(Selections!1 data) @safe pure nothrow @nogc - { - super(data); - } - - /// Do not do IO - public override void save(NativePath path) - { - // No-op - } -} - -/** * A `PackageManager` suitable to be used in unittests * * This `PackageManager` does not perform any IO. It imitates the base @@ -400,6 +376,16 @@ return false; } + /// Save the `dub.selections.json` to the vfs + public override void writeSelections(in Package project, + in Selections!1 selections, bool overwrite = true) + { + const path = project.path ~ "dub.selections.json"; + if (!overwrite && this.fs.existsFile(path)) + return; + this.fs.writeFile(path, selectionsToString(selections)); + } + /// Add a reachable SCM package to this `PackageManager` public void addTestSCMPackage(in Repository repo, string dub_json) {