diff --git a/source/dub/package_.d b/source/dub/package_.d index 530d5f9..4116d4b 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -38,6 +38,7 @@ PackageInfo m_info; Package m_parentPackage; Package[] m_subPackages; + Path[string] m_exportedPackages; } this(Path root, Package parent = null) @@ -135,34 +136,40 @@ } // load all sub packages defined in the package description - foreach (p; packageInfo.subPackages.opt!(Json[])) - m_subPackages ~= new Package(p, root, this); + foreach (sub; packageInfo.subPackages.opt!(Json[])) { + if (m_parentPackage) { + throw new Exception("'subPackages' found in '" ~ name ~ "'. This is only supported in the main package file for '" ~ m_parentPackage.name ~ "'."); + } + if ("packageDefinition" in sub) { + auto path = Path(sub.packageDefinition.get!string); + enforce("name" in sub, "A subpackage is missing a name in package '" ~ name ~ "'"); + auto sub_name = sub.name.get!string; + enforce(sub_name !in m_exportedPackages, "Subpackage '" ~ sub_name ~ "' defined more than once in '" ~ name ~ "'"); + m_exportedPackages[sub_name] = path; + } + else { + m_subPackages ~= new Package(sub, root, this); + } + } + + simpleLint(); } @property string name() const { - if (m_parentPackage) { - // HACK - if (m_parentPackage.path == m_path) - return m_parentPackage.name ~ ":" ~ m_info.name; - else { - enforce(m_path.startsWith(m_parentPackage.path)); - enforce(m_path.head.toString() == m_info.name, - "Subpackage name (" ~ m_info.name ~ ") is different than the path-head (" ~ m_path.head.toString() ~ "), this gets confusing."); - return m_parentPackage.name ~ "/" ~ m_path[m_parentPackage.path.length .. $].toString(); - } - } + if (m_parentPackage) return m_parentPackage.name ~ ":" ~ m_info.name; else return m_info.name; } @property string vers() const { return m_parentPackage ? m_parentPackage.vers : m_info.version_; } @property Version ver() const { return Version(this.vers); } @property ref inout(PackageInfo) info() inout { return m_info; } @property Path path() const { return m_path; } - @property Path packageInfoFile() const { return m_path ~ "package.json"; } + @property Path packageInfoFile() const { return m_path ~ PackageJsonFilename; } @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[string]) exportedPackages() inout { return m_exportedPackages; } @property string[] configurations() const { @@ -365,6 +372,15 @@ } dst.files = Json(files); } + + private void simpleLint() const { + if (m_parentPackage) { + if (m_parentPackage.path != path) { + if (info.license != m_parentPackage.info.license) logWarn("License in subpackage %s is different than it's parent package, this is discouraged.", name); + } + } + if (name.empty()) logWarn("The package in %s has no name.", path); + } } /// Specifying package information without any connection to a certain diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index d736542..fe6c3d5 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -120,7 +120,9 @@ foreach (p; getPackageIterator()) if (!p.basePackage && p.path == path) return p; - return addPackages(m_temporaryPackages, new Package(path)); + auto pack = new Package(path); + addPackages(m_temporaryPackages, pack); + return pack; } Package getBestPackage(string name, string version_spec) @@ -281,7 +283,9 @@ if( existsFile(destination~PackageJsonFilename) ) logInfo("%s is present with version %s", package_name, package_version); - return addPackages(m_packages, new Package(destination)); + auto pack = new Package(destination); + addPackages(m_packages, pack); + return pack; } /// Removes the given the package. @@ -423,7 +427,9 @@ if( "name" !in info ) info["name"] = path.head.toString(); info["version"] = ver.toString(); - return addPackages(m_temporaryPackages, new Package(info, path)); + auto pack = new Package(info, path); + addPackages(m_temporaryPackages, pack); + return pack; } /// For the given type add another path where packages will be looked up. @@ -583,35 +589,30 @@ } /// Adds the package and scans for subpackages. - private Package addPackages(ref Package[] dst_repos, Package pack) { + private void addPackages(ref Package[] dst_repos, Package pack) const { + // Add the main package. dst_repos ~= pack; - void scanRecurse(Path directory) { - logDebug("- scanning for subpackages, dir %s", directory); - if (existsFile(directory ~ PackageJsonFilename) ) { - // Add the subpackage. - try { - dst_repos ~= new Package(directory, pack); - } catch( Exception e ){ - logError("Failed to load sub-package in %s: %s", directory, e.msg); - logDiagnostic("Full error: %s", e.toString().sanitize()); - } + // Additionally to the internally defined subpackages, whose metadata + // is loaded with the main package.json, load all externally defined + // packages after the package is available with all the data. + foreach ( sub_name, sub_path; pack.exportedPackages ) { + auto path = pack.path ~ sub_path; + if ( !existsFile(path) ) { + logError("Package %s defined sub-package %s, definition file is missing: ", sub_name, path.toNativeString()); + continue; } - try foreach( dir; iterateDirectory(directory) ){ - if( !dir.isDirectory ) continue; - scanRecurse(directory ~ dir.name); + // Add the subpackage. + try { + auto sub_pack = new Package(path, pack); + // Checking the raw name here, instead of the "parent:sub" style. + enforce(sub_pack.info.name == sub_name, "Name of package '" ~ sub_name ~ "' differs in definition in '" ~ path.toNativeString() ~ "'."); + dst_repos ~= sub_pack; + } catch( Exception e ){ + logError("Package '%s': Failed to load sub-package '%s' in %s, error: %s", pack.name, sub_name, path.toNativeString(), e.msg); + logDiagnostic("Full error: %s", e.toString().sanitize()); } - catch(Exception e) logDiagnostic("Failed to scan %s sub-packages: %s", directory, e.toString()); } - - try foreach( dir; iterateDirectory(pack.path) ){ - logDebug("scanning for subpackages, dir %s entry %s", pack.path.toNativeString(), dir.name); - if( !dir.isDirectory ) continue; - scanRecurse(pack.path ~ dir.name); - } - catch(Exception e) logDiagnostic("Failed to scan %s sub-packages: %s", pack.path.toNativeString(), e.toString()); - - return pack; } }