diff --git a/source/dub/dub.d b/source/dub/dub.d index 7bdf349..38afbad 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -844,7 +844,7 @@ auto basepack = getPackage(basename, dep); if (auto sp = basepack.getSubPackage(subname, true)) { return sp; - } else if (!basepack.exportedPackages.length) { + } else if (!basepack.exportedPackageCount) { logDiagnostic("Sub package %s doesn't exist in %s %s.", name, basename, dep.version_); return null; } diff --git a/source/dub/package_.d b/source/dub/package_.d index b051cf6..ab3d668 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -65,8 +65,6 @@ PathAndFormat m_infoFile; PackageInfo m_info; Package m_parentPackage; - Package[] m_subPackages; - Path[] m_exportedPackages; } static PathAndFormat findPackageFile(Path path) @@ -177,12 +175,6 @@ m_info.configurations ~= ConfigurationInfo("library", lib_settings); } } - - // load all sub packages defined in the package description - foreach(sub; m_info.subPackages) { - enforce(!parentPackage, format("'subPackages' found in '%s'. This is only supported in the main package file for '%s'.", name, parentPackage.name)); - sub.parseAsSubPackage(this); - } simpleLint(); } @@ -200,8 +192,9 @@ @property const(Dependency[string]) dependencies() const { return m_info.dependencies; } @property inout(Package) basePackage() inout { return m_parentPackage ? m_parentPackage.basePackage : this; } @property inout(Package) parentPackage() inout { return m_parentPackage; } - @property inout(Package)[] subPackages() inout { return m_subPackages; } - @property inout(Path[]) exportedPackages() inout { return m_exportedPackages; } + @property inout(SubPackage)[] allSubPackages() inout { return m_info.subPackages; } + @property auto exportedPackages() { return m_info.subPackages.filter!(p => p.referenceName !is null); } + @property auto exportedPackageCount() { return m_info.exportedPackageCount; } @property string[] configurations() const { @@ -211,6 +204,15 @@ return ret.data; } + Package parseImportedPackage(string importedPackage) + { + auto packageFilename = Path(importedPackage); + packageFilename.normalize(); + enforce(!packageFilename.absolute, "Sub package paths must not be absolute: " ~ importedPackage); + enforce(!packageFilename.startsWith(Path("..")), "Sub packages must be in a sub directory, not " ~ importedPackage); + return path.empty ? null : new Package(path ~ packageFilename, PathAndFormat(), this, this.vers); + } + const(Dependency[string]) getDependencies(string config) const { Dependency[string] ret; @@ -239,9 +241,9 @@ inout(Package) getSubPackage(string name, bool silent_fail = false) inout { - foreach (p; m_subPackages) - if (p.name == this.name ~ ":" ~ name) - return p; + foreach (p; m_info.subPackages) + if (p.package_ !is null && p.package_.name == this.name ~ ":" ~ name) + return p.package_; enforce(silent_fail, format("Unknown sub package: %s:%s", this.name, name)); return null; } @@ -477,31 +479,8 @@ static abstract class RawPackage { string package_name; // Should already be lower case - string version_; - - abstract string asImportedPackage() const; - abstract Json toOriginalJson() const; + string version_; abstract void parseInto(Package package_, string parent_name) const; - - protected Package parse(Package parentPackage) - { - return new Package(this, parentPackage.m_path, parentPackage); - } - void parseAsSubPackage(Package parentPackage) - { - string importedPackage = asImportedPackage(); - if (importedPackage !is null) { - auto subPackageFilename = Path(importedPackage); - subPackageFilename.normalize(); - enforce(!subPackageFilename.absolute, "Sub package paths must not be absolute: " ~ importedPackage); - enforce(!subPackageFilename.startsWith(Path("..")), "Sub packages must be in a sub directory, not " ~ importedPackage); - parentPackage.m_exportedPackages ~= subPackageFilename; - if (!parentPackage.path.empty) parentPackage.m_subPackages ~= - new Package(parentPackage.path ~ subPackageFilename, PathAndFormat(), parentPackage, parentPackage.vers); - } else { - parentPackage.m_subPackages ~= parse(parentPackage); - } - } } private static class JsonPackage : RawPackage { @@ -524,39 +503,27 @@ this.package_name = nameLower; } - override string asImportedPackage() const - { - return (json.type == Json.Type.string) ? json.get!string : null; - } - override Json toOriginalJson() const { return json; } override void parseInto(Package package_, string parent_name) const { - package_.info.parseJson(json, parent_name); + package_.info.parseJson(package_, json, parent_name); } } private static class SdlPackage : RawPackage - { - Package parsedPackage; // Used to convert the package to JSON - - override string asImportedPackage() const { throw new Exception("SDL packages not implemented yet"); } - override Json toOriginalJson() const - { - if(parsedPackage !is null) return parsedPackage.info.toJson(); - // otherwise it is an imported package - throw new Exception("SDL packages not implemented yet"); - } + { override void parseInto(Package package_, string parent_name) const { throw new Exception("SDL packages not implemented yet"); } - protected override Package parse(Package parentPackage) - { - parsedPackage = RawPackage.parse(parentPackage); - return parsedPackage; - } } } + +struct SubPackage +{ + string referenceName; + Package package_; +} + /// Specifying package information without any connection to a certain /// retrived package, like Package class is doing. struct PackageInfo { @@ -571,7 +538,9 @@ BuildSettingsTemplate buildSettings; ConfigurationInfo[] configurations; BuildSettingsTemplate[string] buildTypes; - Package.RawPackage[] subPackages; + + size_t exportedPackageCount; + SubPackage[] subPackages; @property const(Dependency)[string] dependencies() const { @@ -590,9 +559,28 @@ if (c.name == name) return c; throw new Exception("Unknown configuration: "~name); + } + void parseSubPackages(Package containingPackage, Json[] subPackagesJson) + { + enforce(!containingPackage.parentPackage, format("'subPackages' found in '%s'. This is only supported in the main package file for '%s'.", + containingPackage.name, containingPackage.parentPackage.name)); + + this.exportedPackageCount = 0; + this.subPackages = new SubPackage[subPackagesJson.length]; + foreach(i, subPackageJson; subPackagesJson) { + // Handle referenced Packages + if(subPackageJson.type == Json.Type.string) { + string packageNameReference = subPackageJson.get!string; + this.subPackages[i] = SubPackage(packageNameReference, + containingPackage.parseImportedPackage(packageNameReference)); + this.exportedPackageCount++; + } else { + this.subPackages[i] = SubPackage(null, + new Package(subPackageJson, containingPackage.m_path, containingPackage)); + } + } } - - void parseJson(Json json, string parent_name) + void parseJson(Package containingPackage, Json json, string parent_name) { foreach( string field, value; json ){ switch(field){ @@ -604,13 +592,7 @@ case "authors": this.authors = deserializeJson!(string[])(value); break; case "copyright": this.copyright = value.get!string; break; case "license": this.license = value.get!string; break; - case "subPackages": - Json[] subPackagesJson = value.opt!(Json[]); - this.subPackages = new Package.RawPackage[subPackagesJson.length]; - foreach(i, subPackageJson; subPackagesJson) { - this.subPackages[i] = new Package.JsonPackage(subPackagesJson[i]); - } - break; + case "subPackages": parseSubPackages(containingPackage, value.opt!(Json[])); break; case "configurations": break; // handled below, after the global settings have been parsed case "buildTypes": foreach (string name, settings; value) { @@ -653,8 +635,12 @@ if( !this.license.empty ) ret.license = this.license; if( !this.subPackages.empty ) { Json[] jsonSubPackages = new Json[this.subPackages.length]; - foreach(i, subPackage; this.subPackages) { - jsonSubPackages[i] = this.subPackages[i].toOriginalJson(); + foreach(i, subPackage; subPackages) { + if(subPackage.referenceName !is null) { + jsonSubPackages[i] = Json(subPackage.referenceName); + } else { + jsonSubPackages[i] = subPackage.package_.m_info.toJson(); + } } ret.subPackages = jsonSubPackages; } diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index ae18464..05a72b7 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -208,9 +208,10 @@ { int handlePackage(Package p) { if (auto ret = del(p)) return ret; - foreach (sp; p.subPackages) - if (auto ret = del(sp)) - return ret; + foreach (sp; p.allSubPackages) + if(sp.package_ !is null) + if (auto ret = del(sp.package_)) + return ret; return 0; } @@ -718,8 +719,8 @@ // Additionally to the internally defined subpackages, whose metadata // is loaded with the main dub.json, load all externally defined // packages after the package is available with all the data. - foreach (sub_path; pack.exportedPackages) { - auto path = pack.path ~ sub_path; + foreach (package_; pack.exportedPackages) { + auto path = pack.path ~ package_.referenceName; if (!existsFile(path)) { logError("Package %s declared a sub-package, definition file is missing: %s", pack.name, path.toNativeString()); continue;