Skip to content

Commit 8d4060f

Browse files
authored
PackageManager: Support directly loading a sub-package via path-based getOrLoadPackage() (#2977)
PackageManager: Support directly loading a sub-package via path-based `getOrLoadPackage()` Signed-off-by: Mathias LANG <[email protected]> Merged-on-behalf-of: Martin Kinkelin <[email protected]>
1 parent b4a73be commit 8d4060f

File tree

5 files changed

+46
-22
lines changed

5 files changed

+46
-22
lines changed

source/dub/commandline.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ class Command {
888888
dub.mainRecipePath = options.recipeFile;
889889
// make the CWD package available so that for example sub packages can reference their
890890
// parent package.
891-
try dub.packageManager.getOrLoadPackage(NativePath(options.root_path), NativePath(options.recipeFile), false, StrictMode.Warn);
891+
try dub.packageManager.getOrLoadPackage(NativePath(options.root_path), NativePath(options.recipeFile), PackageName.init, StrictMode.Warn);
892892
catch (Exception e) {
893893
// by default we ignore CWD package load fails in prepareDUB, since
894894
// they will fail again later when they are actually requested. This

source/dub/dub.d

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ class Dub {
516516
void loadPackage(NativePath path)
517517
{
518518
auto pack = this.m_packageManager.getOrLoadPackage(
519-
path, NativePath.init, false, StrictMode.Warn);
519+
path, NativePath.init, PackageName.init, StrictMode.Warn);
520520
this.loadPackage(pack);
521521
}
522522

@@ -1970,6 +1970,7 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
19701970
import dub.recipe.json;
19711971

19721972
// for sub packages, first try to get them from the base package
1973+
// FIXME: avoid this, PackageManager.getSubPackage() is costly
19731974
if (name.main != name) {
19741975
auto subname = name.sub;
19751976
auto basepack = getPackage(name.main, dep);
@@ -1985,12 +1986,14 @@ private class DependencyVersionResolver : DependencyResolver!(Dependency, Depend
19851986
return m_rootPackage.basePackage;
19861987

19871988
if (!dep.repository.empty) {
1989+
// note: would handle sub-packages directly
19881990
auto ret = m_dub.packageManager.loadSCMPackage(name, dep.repository);
19891991
return ret !is null && dep.matches(ret.version_) ? ret : null;
19901992
}
19911993
if (!dep.path.empty) {
19921994
try {
1993-
return m_dub.packageManager.getOrLoadPackage(dep.path);
1995+
// note: would handle sub-packages directly
1996+
return m_dub.packageManager.getOrLoadPackage(dep.path, NativePath.init, name);
19941997
} catch (Exception e) {
19951998
logDiagnostic("Failed to load path based dependency %s: %s", name, e.msg);
19961999
logDebug("Full error: %s", e.toString().sanitize);

source/dub/packagemanager.d

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ class PackageManager {
271271
foreach (ovr; repo.overrides)
272272
if (ovr.package_ == name.toString() && ovr.source.matches(ver)) {
273273
Package pack = ovr.target.match!(
274-
(NativePath path) => getOrLoadPackage(path),
274+
(NativePath path) => getOrLoadPackage(path, NativePath.init, name),
275275
(Version vers) => getPackage(name, vers, false),
276276
);
277277
if (pack) return pack;
@@ -377,21 +377,42 @@ class PackageManager {
377377
Params:
378378
path = NativePath to the root directory of the package
379379
recipe_path = Optional path to the recipe file of the package
380-
allow_sub_packages = Also return a sub package if it resides in the given folder
380+
name = Optional (sub-)package name if known in advance. Required if a sub-package is to be returned.
381381
mode = Whether to issue errors, warning, or ignore unknown keys in dub.json
382382
383383
Returns: The packages loaded from the given path
384384
Throws: Throws an exception if no package can be loaded
385385
*/
386386
Package getOrLoadPackage(NativePath path, NativePath recipe_path = NativePath.init,
387-
bool allow_sub_packages = false, StrictMode mode = StrictMode.Ignore)
387+
PackageName name = PackageName.init, StrictMode mode = StrictMode.Ignore)
388388
{
389389
path.endsWithSlash = true;
390-
foreach (p; this.m_internal.fromPath)
391-
if (p.path == path && (!p.parentPackage || (allow_sub_packages && p.parentPackage.path != p.path)))
392-
return p;
390+
const nameString = name.toString();
391+
392+
foreach (p; this.m_internal.fromPath) {
393+
if (!nameString.empty) {
394+
if (p.name == nameString && (p.path == path || p.basePackage.path == path))
395+
return p;
396+
} else {
397+
if (p.path == path && !p.parentPackage)
398+
return p;
399+
}
400+
}
401+
393402
auto pack = this.load(path, recipe_path, null, null, mode);
394-
addPackages(this.m_internal.fromPath, pack);
403+
auto nameToResolve = PackageName(pack.name);
404+
405+
if (!nameString.empty) {
406+
nameToResolve = PackageName(nameString);
407+
const loadedName = PackageName(pack.name);
408+
enforce(loadedName == nameToResolve || loadedName == nameToResolve.main,
409+
"Package %s loaded from '%s' does not match expected name %s".format(
410+
loadedName, path.toNativeString(), nameToResolve));
411+
}
412+
413+
pack = addPackagesAndResolveSubPackage(this.m_internal.fromPath, pack, nameToResolve);
414+
enforce(pack !is null, "No sub-package %s in parent package loaded from '%s'".format(
415+
nameToResolve, path.toNativeString()));
395416
return pack;
396417
}
397418

source/dub/project.d

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Project {
6767
logWarn("There was no package description found for the application in '%s'.", project_path.toNativeString());
6868
pack = new Package(PackageRecipe.init, project_path);
6969
} else {
70-
pack = package_manager.getOrLoadPackage(project_path, packageFile, false, StrictMode.Warn);
70+
pack = package_manager.getOrLoadPackage(project_path, packageFile, PackageName.init, StrictMode.Warn);
7171
}
7272

7373
this(package_manager, pack);
@@ -553,8 +553,7 @@ class Project {
553553
p = vspec.visit!(
554554
(NativePath path_) {
555555
auto path = path_.absolute ? path_ : m_rootPackage.path ~ path_;
556-
auto tmp = m_packageManager.getOrLoadPackage(path, NativePath.init, true);
557-
return resolveSubPackage(tmp, subname, true);
556+
return m_packageManager.getOrLoadPackage(path, NativePath.init, dep.name);
558557
},
559558
(Repository repo) {
560559
return m_packageManager.loadSCMPackage(dep.name, repo);
@@ -587,15 +586,11 @@ class Project {
587586
NativePath path = vspec.path;
588587
if (!path.absolute) path = pack.path ~ path;
589588
logDiagnostic("%sAdding local %s in %s", indent, dep.name, path);
590-
p = m_packageManager.getOrLoadPackage(path, NativePath.init, true);
591-
if (p.parentPackage !is null) {
589+
p = m_packageManager.getOrLoadPackage(path, NativePath.init, dep.name);
590+
path.endsWithSlash = true;
591+
if (path != p.basePackage.path) {
592592
logWarn("%sSub package %s must be referenced using the path to it's parent package.", indent, dep.name);
593-
p = p.parentPackage;
594593
}
595-
p = resolveSubPackage(p, subname, false);
596-
enforce(p.name == dep.name.toString(),
597-
format("Path based dependency %s is referenced with a wrong name: %s vs. %s",
598-
path.toNativeString(), dep.name, p.name));
599594
} else {
600595
logDiagnostic("%sMissing dependency %s %s of %s", indent, dep.name, vspec, pack.name);
601596
if (is_desired) m_missingDependencies ~= dep.name.toString();

source/dub/test/subpackages.d

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,19 @@ unittest
4444
{
4545
scope dub = new TestDub((scope Filesystem root) {
4646
root.writeFile(TestDub.ProjectPath ~ "dub.json",
47-
`{ "name": "a", "dependencies": { "b:a": "~>1.0" } }`);
47+
`{ "name": "a", "dependencies": { "b:a": "~>1.0", "c:a": "~>1.0" } }`);
4848
root.writeFile(TestDub.ProjectPath ~ "dub.selections.json",
49-
`{ "fileVersion": 1, "versions": { "b": "1.0.0" } }`);
49+
`{ "fileVersion": 1, "versions": { "b": "1.0.0", "c": { "path": "c" } } }`);
5050
root.writePackageFile("b", "1.0.0",
5151
`{ "name": "b", "version": "1.0.0", "subPackages": [ { "name": "a" } ] }`);
52+
const cDir = TestDub.ProjectPath ~ "c";
53+
root.mkdir(cDir);
54+
root.writeFile(cDir ~ "dub.json",
55+
`{ "name": "c", "version": "1.0.0", "subPackages": [ { "name": "a" } ] }`);
5256
});
5357
dub.loadPackage();
5458

5559
assert(dub.project.hasAllDependencies(), "project has missing dependencies");
5660
assert(dub.project.getDependency("b:a", true), "Missing 'b:a' dependency");
61+
assert(dub.project.getDependency("c:a", true), "Missing 'c:a' dependency");
5762
}

0 commit comments

Comments
 (0)