diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index d1710e7..7128f05 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -76,37 +76,6 @@ string[] preBuildCommands; string[] postBuildCommands; - void parse(in Json root, BuildPlatform platform) - { - foreach(string name, value; root){ - auto components = name.split("-"); - if( !matchesPlatform(components[1 .. $], platform) ) - continue; - - const(string[]) entries(){ - enforce(value.type == Json.Type.Array, "Field "~name~" must be of type string[]."); - return value.get!(Json[]).map!(j => j.get!string).array(); - } - - switch(components[0]){ - default: break; - case "dflags": addDFlags(entries()); break; - case "lflags": addLFlags(entries()); break; - case "libs": addLibs(entries()); break; - case "sourceFiles": - case "files": addSourceFiles(entries()); break; - case "copyFiles": addCopyFiles(entries()); break; - case "versions": addVersions(entries()); break; - case "importPaths": addImportPaths(entries()); break; - case "stringImportPaths": addStringImportPaths(entries()); break; - case "preGenerateCommands": addPreGenerateCommands(entries()); break; - case "postGenerateCommands": addPostGenerateCommands(entries()); break; - case "preBuildCommands": addPreBuildCommands(entries()); break; - case "postBuildCommands": addPostBuildCommands(entries()); break; - } - } - } - void addDFlags(in string[] value...) { add(dflags, value); } void addLFlags(in string[] value...) { add(lflags, value); } void addLibs(in string[] value...) { add(libs, value); } @@ -138,16 +107,6 @@ if( !found ) arr ~= v; } } - - bool matchesPlatform(string[] platform_parts, BuildPlatform platform) - { - if( platform_parts.length == 0 ) return true; - // TODO: optimize - foreach( suffix; getPlatformSuffixIterator(platform) ) - if( suffix == "-"~platform_parts.join("-") ) - return true; - return false; - } } /// Represents a platform a package can be build upon. @@ -178,39 +137,3 @@ private { Compiler[] s_compilers; } - -/// Based on the BuildPlatform, creates an iterator with all suffixes. -/// -/// Suffixes are build upon the following scheme, where each component -/// is optional (indicated by []), but the order is obligatory. -/// "[-platform][-architecture][-compiler]" -/// -/// So the following strings are valid suffixes: -/// "-windows-x86-dmd" -/// "-dmd" -/// "-arm" -/// -int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform) -{ - int iterator(scope int delegate(ref string s) del) - { - auto c = platform.compiler; - int delwrap(string s) { return del(s); } - if( auto ret = delwrap(null) ) return ret; - if( auto ret = delwrap("-"~c) ) return ret; - foreach( p; platform.platform ){ - if( auto ret = delwrap("-"~p) ) return ret; - if( auto ret = delwrap("-"~p~"-"~c) ) return ret; - foreach( a; platform.architecture ){ - if( auto ret = delwrap("-"~p~"-"~a) ) return ret; - if( auto ret = delwrap("-"~p~"-"~a~"-"~c) ) return ret; - } - } - foreach( a; platform.architecture ){ - if( auto ret = delwrap("-"~a) ) return ret; - if( auto ret = delwrap("-"~a~"-"~c) ) return ret; - } - return 0; - } - return &iterator; -} diff --git a/source/dub/dependency.d b/source/dub/dependency.d index bca2df2..2f5d844 100644 --- a/source/dub/dependency.d +++ b/source/dub/dependency.d @@ -149,6 +149,8 @@ Version m_versA; string m_cmpB; Version m_versB; + Path m_path; + string m_configuration = "library"; } this( string ves ) { @@ -199,19 +201,27 @@ } } - this(string cmp, string ver) + this(in Version ver) { - m_cmpA = cmp; - m_versB = m_versA = Version(ver); - m_cmpB = "=="; + m_cmpA = ">="; + m_cmpB = "<="; + m_versA = ver; + m_versB = ver; } - + this(const Dependency o) { m_cmpA = o.m_cmpA; m_versA = Version(o.m_versA); m_cmpB = o.m_cmpB; m_versB = Version(o.m_versB); enforce( m_cmpA != "==" || m_cmpB == "=="); enforce(m_versA <= m_versB); + m_path = o.m_path; + m_configuration = o.m_configuration; } + + @property void path(Path value) { m_path = value; } + @property Path path() const { return m_path; } + + @property Version version_() const { assert(m_versA == m_versB); return m_versA; } override string toString() const { string r; @@ -231,7 +241,7 @@ { if (this is b) return true; if (b is null) return false; if (typeid(this) != typeid(b)) return false; Dependency o = cast(Dependency) b; - return o.m_cmpA == m_cmpA && o.m_cmpB == m_cmpB && o.m_versA == m_versA && o.m_versB == m_versB; + return o.m_cmpA == m_cmpA && o.m_cmpB == m_cmpB && o.m_versA == m_versA && o.m_versB == m_versB && o.m_configuration == m_configuration; } bool valid() const { @@ -265,6 +275,8 @@ return new Dependency(this); if(!o.valid()) return new Dependency(o); + if( m_configuration != o.m_configuration ) + return new Dependency(">=1.0.0 <=0.0.0"); Version a = m_versA > o.m_versA? m_versA : o.m_versA; Version b = m_versB < o.m_versB? m_versB : o.m_versB; diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index 7c0df1d..784cb20 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -203,7 +203,7 @@ } version(VISUALD_SEPERATE_PROJECT_FILES){ - auto files = pack.getBuildSettings(settings.platform, settings.config, pack is m_app.mainPackage); + auto files = pack.getBuildSettings(settings.platform, m_app.getPackageConfig(pack, settings.config)); bool[SourceFile] sourceFiles; foreach(s; files.sourceFiles){ diff --git a/source/dub/package_.d b/source/dub/package_.d index 902c701..2f48f8d 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -17,6 +17,7 @@ import std.exception; import std.file; import std.range; +import std.string; import vibecompat.core.log; import vibecompat.core.file; import vibecompat.data.json; @@ -83,9 +84,7 @@ private { InstallLocation m_location; Path m_path; - Json m_meta; - Dependency[string] m_dependencies; - LocalPackageDef[] m_localPackageDefs; + PackageInfo m_info; } this(InstallLocation location, Path root) @@ -97,91 +96,47 @@ { m_location = location; m_path = root; - m_meta = packageInfo; - - // extract dependencies and local package definitions - if( auto pd = "dependencies" in packageInfo ){ - foreach( string pkg, verspec; *pd ) { - enforce(pkg !in m_dependencies, "The dependency '"~pkg~"' is specified more than once." ); - if( verspec.type == Json.Type.Object ){ - // full blown specifier - auto ver = verspec["version"].get!string; - m_dependencies[pkg] = new Dependency("==", ver); - m_localPackageDefs ~= LocalPackageDef(pkg, Version(ver), Path(verspec.path.get!string())); - } else { - // canonical "package-id": "version" - m_dependencies[pkg] = new Dependency(verspec.get!string()); - } - } - } - } - - @property string name() const { return cast(string)m_meta["name"]; } - @property string vers() const { return cast(string)m_meta["version"]; } - @property Version ver() const { return Version(m_meta["version"].get!string); } - @property installLocation() const { return m_location; } - @property Path path() const { return m_path; } - @property const(Url) url() const { return Url.parse(cast(string)m_meta["url"]); } - @property const(Dependency[string]) dependencies() const { return m_dependencies; } - @property const(LocalPackageDef)[] localPackageDefs() const { return m_localPackageDefs; } - @property Path binaryPath() - const { - auto p = m_meta["binaryPath"].opt!string; - if( !p.length ) return this.path; - return this.path ~ Path(p); - } - - @property string[] configurations() - const { - auto pv = "configurations" in m_meta; - if( !pv ) return null; - auto ret = appender!(string[])(); - foreach( string k, _; *pv ) - ret.put(k); - return ret.data; - } - - /// Returns all BuildSettings for the given platform and config. - BuildSettings getBuildSettings(BuildPlatform platform, string config, bool app = false) - const { - BuildSettings ret; - ret.parse(m_meta, platform); - if( config.length ){ - if( auto pcs = "configurations" in m_meta ){ - if( auto pc = config in *pcs ){ - ret.parse(*pc, platform); - } - } - } // check for default string import folders - if( ret.stringImportPaths.empty ){ - foreach(defvf; ["views"]){ - auto p = this.path ~ defvf; - if( existsFile(p) ){ - ret.addStringImportPaths(defvf); - } + foreach(defvf; ["views"]){ + auto p = m_path ~ defvf; + if( existsFile(p) ) + m_info.buildSettings.stringImportPaths[""] ~= defvf; + } + + string[] app_files; + auto pkg_name = packageInfo.name.get!string(); + + // check for default source folders + foreach(defsf; ["source", "src"]){ + auto p = m_path ~ defsf; + if( existsFile(p) ){ + m_info.sourcePaths ~= defsf; + m_info.buildSettings.importPaths[""] ~= defsf; + if( existsFile(p ~ "app.d") ) app_files ~= defsf ~ "/app.d"; + else if( existsFile(p ~ (pkg_name~".d")) ) app_files ~= defsf ~ "/"~pkg_name~".d"; } } + // parse the JSON description + m_info.parseJson(packageInfo); + + // generate default configurations if none are defined + if( m_info.configurations.length == 0 ){ + if( app_files.length ){ + BuildSettingsTemplate app_settings; + app_settings.sourceFiles[""] = app_files; + m_info.configurations["application"] = app_settings; + } + + BuildSettingsTemplate lib_settings; + m_info.configurations["library"] = lib_settings; + } // determine all source folders Path[] source_paths; - if( auto psp = "sourcePath" in m_meta ) - source_paths ~= this.path ~ Path(psp.get!string()); - - if( auto psps = "sourcePaths" in m_meta ){ - foreach(p; *psps) - source_paths ~= this.path ~ p.get!string(); - } else if( source_paths.empty ){ - foreach(defsf; ["source", "src"]){ - auto p = this.path ~ defsf; - if( existsFile(p) ){ - source_paths ~= p; - ret.addImportPaths(defsf); - } - } - } + foreach(p; m_info.sourcePaths) + source_paths ~= this.path ~ p; logTrace("Source paths for %s: %s", this.name, source_paths); // gather all source files @@ -195,14 +150,42 @@ // spawns internal compiler/linker error if(isDir(d.name)) continue; auto p = Path(d.name); - auto src = p.relativeTo(this.path).toNativeString(); - if( app || !isAppSource(src) ) - sources ~= src; + auto src = p.relativeTo(this.path); + if( !app_files.map!(p => Path(p))().canFind(src) ) + sources ~= src.toNativeString(); } } logTrace("allSources: %s", sources); - ret.addSourceFiles(sources); + m_info.buildSettings.sourceFiles[""] ~= sources; + } + + @property string name() const { return m_info.name; } + @property string vers() const { return m_info.version_; } + @property Version ver() const { return Version(m_info.version_); } + @property installLocation() const { return m_location; } + @property Path path() const { return m_path; } + @property const(Dependency[string]) dependencies() const { return m_info.dependencies; } + @property Path binaryPath() + const { + auto p = m_info.binaryPath; + if( !p.length ) return this.path; + return this.path ~ Path(p); + } + + @property string[] configurations() + const { + auto ret = appender!(string[])(); + foreach( config; m_info.configurations.byKey ) + ret.put(config); + return ret.data; + } + /// Returns all BuildSettings for the given platform and config. + BuildSettings getBuildSettings(BuildPlatform platform, string config) + const { + BuildSettings ret; + m_info.buildSettings.getPlatformSettings(ret, platform); + m_info.configurations[config].getPlatformSettings(ret, platform); return ret; } @@ -213,56 +196,280 @@ return ps == Path("source/app.d") || ps == Path("src/app.d"); } - /// TODO: what is the defaul configuration? - string getDefaultConfiguration(BuildPlatform platform) + /// Returns the default configuration to build for the given platform + string getDefaultConfiguration(BuildPlatform platform, bool is_app = false) const { string ret; - auto cfgs = m_meta["configurations"].opt!(Json[string]); - foreach( suffix; getPlatformSuffixIterator(platform) ) - if( auto pv = ("default"~suffix) in cfgs ) - ret = pv.get!string(); - return ret; + foreach(suffix; getPlatformSuffixIterator(platform)) + if( auto pc = suffix in m_info.defaultConfiguration ) + return *pc; + return is_app ? "application" : "library"; } /// Humanly readible information of this package and its dependencies. string info() const { string s; - s ~= cast(string)m_meta["name"] ~ ", version '" ~ cast(string)m_meta["version"] ~ "'"; + s ~= m_info.name ~ ", version '" ~ m_info.version_ ~ "'"; s ~= "\n Dependencies:"; - foreach(string p, ref const Dependency v; m_dependencies) + foreach(string p, ref const Dependency v; m_info.dependencies) s ~= "\n " ~ p ~ ", version '" ~ to!string(v) ~ "'"; return s; } - /// direct access to the json of this package - @property ref Json json() { return m_meta; } - /// Writes the json file back to the filesystem void writeJson(Path path) { auto dstFile = openFile((path~PackageJsonFilename).toString(), FileMode.CreateTrunc); scope(exit) dstFile.close(); - dstFile.writePrettyJsonString(m_meta); + dstFile.writePrettyJsonString(m_info.toJson()); + assert(false); } /// Adds an dependency, if the package is already a dependency and it cannot be /// merged with the supplied dependency, an exception will be generated. void addDependency(string packageId, const Dependency dependency) { Dependency dep = new Dependency(dependency); - if(packageId in m_dependencies) { - dep = dependency.merge(m_dependencies[packageId]); + if(packageId in m_info.dependencies) { + dep = dependency.merge(m_info.dependencies[packageId]); if(!dep.valid()) throw new Exception("Cannot merge with existing dependency."); } - m_dependencies[packageId] = dep; - Json[string] empty; - if("dependencies" !in m_meta) m_meta["dependencies"] = empty; - m_meta["dependencies"][packageId] = Json(to!string(dep)); + m_info.dependencies[packageId] = dep; } /// Removes a dependecy. void removeDependency(string packageId) { - if(packageId !in m_dependencies) - return; - m_dependencies.remove(packageId); - m_meta.remove(packageId); + if (packageId in m_info.dependencies) + m_info.dependencies.remove(packageId); } } + +struct PackageInfo { + string name; + string version_; + string binaryPath; + string description; + string homepage; + string[] authors; + string copyright; + string license; + Dependency[string] dependencies; + string[] sourcePaths; + BuildSettingsTemplate buildSettings; + string[string] defaultConfiguration; + BuildSettingsTemplate[string] configurations; + + void parseJson(Json json) + { + foreach( string field, value; json ){ + switch(field){ + default: + auto didx = std.string.indexOf(field, "-"); + string basename, suffix; + if( didx >= 0 ) basename = field[0 .. didx], suffix = field[didx .. $]; + else basename = field; + if( basename == "defaultConfiguration" ){ + this.defaultConfiguration[suffix] = value.get!string(); + } + break; + case "name": this.name = value.get!string; break; + case "version": this.version_ = value.get!string; break; + case "binaryPath": this.binaryPath = value.get!string; break; + case "description": this.description = value.get!string; break; + case "homepage": this.homepage = value.get!string; break; + 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 "dependencies": + foreach( string pkg, verspec; value ) { + enforce(pkg !in this.dependencies, "The dependency '"~pkg~"' is specified more than once." ); + Dependency dep; + if( verspec.type == Json.Type.Object ){ + auto ver = verspec["version"].get!string; + if( auto pp = "path" in verspec ){ + dep = new Dependency(Version(ver)); + dep.path = Path(verspec.path.get!string()); + } else dep = new Dependency(ver); + } else { + // canonical "package-id": "version" + dep = new Dependency(verspec.get!string()); + } + this.dependencies[pkg] = dep; + } + break; + case "sourcePath": this.sourcePaths = [value.get!string()]; break; // deprecated + case "sourcePaths": this.sourcePaths = deserializeJson!(string[])(value); break; + case "configurations": + foreach( string config, settings; value ){ + BuildSettingsTemplate bs; + bs.parseJson(settings); + this.configurations[config] = bs; + } + break; + } + } + + // parse build settings + this.buildSettings.parseJson(json); + + enforce(this.name.length > 0, "The package \"name\" field is missing or empty."); + } + + Json toJson() + const { + auto ret = Json.EmptyObject; + ret.name = this.name; + if( !this.version_.empty ) ret["version"] = this.version_; + if( !this.description.empty ) ret.description = this.description; + if( !this.homepage.empty ) ret.homepage = this.homepage; + if( !this.authors.empty ) ret.authors = serializeToJson(this.authors); + if( !this.copyright.empty ) ret.copyright = this.copyright; + if( !this.license.empty ) ret.license = this.license; + if( this.dependencies ){ + auto deps = Json.EmptyObject; + foreach( pack, d; this.dependencies ){ + if( d.path.empty ){ + deps[pack] = d.toString(); + } else deps[pack] = serializeToJson(["version": d.version_.toString(), "path": d.path.toString()]); + } + ret.dependencies = deps; + } + if( !this.sourcePaths.empty ) ret.sourcePaths = serializeToJson(this.sourcePaths); + if( this.configurations ){ + auto configs = Json.EmptyObject; + foreach( suffix, conf; defaultConfiguration ) + configs["default"~suffix] = conf; + foreach(config, settings; this.configurations) + configs[config] = settings.toJson(); + ret.configurations = configs; + } + return ret; + } +} + +struct BuildSettingsTemplate { + string[][string] dflags; + string[][string] lflags; + string[][string] libs; + string[][string] sourceFiles; + string[][string] copyFiles; + string[][string] versions; + string[][string] importPaths; + string[][string] stringImportPaths; + string[][string] preGenerateCommands; + string[][string] postGenerateCommands; + string[][string] preBuildCommands; + string[][string] postBuildCommands; + + void parseJson(Json json) + { + foreach(string name, value; json) + { + auto idx = std.string.indexOf(name, "-"); + string basename, suffix; + if( idx >= 0 ) basename = name[0 .. idx], suffix = name[idx .. $]; + else basename = name; + switch(basename){ + default: break; + case "dflags": this.dflags[suffix] = deserializeJson!(string[])(value); break; + case "lflags": this.lflags[suffix] = deserializeJson!(string[])(value); break; + case "libs": this.libs[suffix] = deserializeJson!(string[])(value); break; + case "sourceFiles": this.sourceFiles[suffix] = deserializeJson!(string[])(value); break; + case "copyFiles": this.copyFiles[suffix] = deserializeJson!(string[])(value); break; + case "versions": this.versions[suffix] = deserializeJson!(string[])(value); break; + case "importPaths": this.importPaths[suffix] = deserializeJson!(string[])(value); break; + case "stringImportPaths": this.stringImportPaths[suffix] = deserializeJson!(string[])(value); break; + case "preGenerateCommands": this.preGenerateCommands[suffix] = deserializeJson!(string[])(value); break; + case "postGenerateCommands": this.postGenerateCommands[suffix] = deserializeJson!(string[])(value); break; + case "preBuildCommands": this.preBuildCommands[suffix] = deserializeJson!(string[])(value); break; + case "postBuildCommands": this.postBuildCommands[suffix] = deserializeJson!(string[])(value); break; + } + } + } + + Json toJson() + const { + auto ret = Json.EmptyObject; + foreach(suffix, arr; dflags) ret["dflags"~suffix] = serializeToJson(arr); + foreach(suffix, arr; lflags) ret["lflags"~suffix] = serializeToJson(arr); + foreach(suffix, arr; libs) ret["libs"~suffix] = serializeToJson(arr); + foreach(suffix, arr; sourceFiles) ret["sourceFiles"~suffix] = serializeToJson(arr); + foreach(suffix, arr; copyFiles) ret["copyFiles"~suffix] = serializeToJson(arr); + foreach(suffix, arr; versions) ret["versions"~suffix] = serializeToJson(arr); + foreach(suffix, arr; importPaths) ret["importPaths"~suffix] = serializeToJson(arr); + foreach(suffix, arr; stringImportPaths) ret["stringImportPaths"~suffix] = serializeToJson(arr); + foreach(suffix, arr; preGenerateCommands) ret["preGenerateCommands"~suffix] = serializeToJson(arr); + foreach(suffix, arr; postGenerateCommands) ret["postGenerateCommands"~suffix] = serializeToJson(arr); + foreach(suffix, arr; preBuildCommands) ret["preBuildCommands"~suffix] = serializeToJson(arr); + foreach(suffix, arr; postBuildCommands) ret["postBuildCommands"~suffix] = serializeToJson(arr); + return ret; + } + + void getPlatformSettings(ref BuildSettings dst, BuildPlatform platform) + const { + getPlatformSetting!("dflags", "addDFlags")(dst, platform); + getPlatformSetting!("lflags", "addLFlags")(dst, platform); + getPlatformSetting!("libs", "addLibs")(dst, platform); + getPlatformSetting!("sourceFiles", "addSourceFiles")(dst, platform); + getPlatformSetting!("copyFiles", "addCopyFiles")(dst, platform); + getPlatformSetting!("versions", "addVersions")(dst, platform); + getPlatformSetting!("importPaths", "addImportPaths")(dst, platform); + getPlatformSetting!("stringImportPaths", "addStringImportPaths")(dst, platform); + getPlatformSetting!("preGenerateCommands", "addPreGenerateCommands")(dst, platform); + getPlatformSetting!("postGenerateCommands", "addPostGenerateCommands")(dst, platform); + getPlatformSetting!("preBuildCommands", "addPreBuildCommands")(dst, platform); + getPlatformSetting!("postBuildCommands", "addPostBuildCommands")(dst, platform); + } + + void getPlatformSetting(string name, string addname)(ref BuildSettings dst, BuildPlatform platform) + const { + foreach(suffix, values; __traits(getMember, this, name)){ + if( matchesPlatform(suffix, platform) ) + __traits(getMember, dst, addname)(values); + } + } +} + +private bool matchesPlatform(string suffix, BuildPlatform platform) +{ + if( suffix.length == 0 ) return true; + // TODO: optimize + foreach( psuffix; getPlatformSuffixIterator(platform) ) + if( psuffix == suffix ) + return true; + return false; +} + +/// Based on the BuildPlatform, creates an iterator with all suffixes. +/// +/// Suffixes are build upon the following scheme, where each component +/// is optional (indicated by []), but the order is obligatory. +/// "[-platform][-architecture][-compiler]" +/// +/// So the following strings are valid suffixes: +/// "-windows-x86-dmd" +/// "-dmd" +/// "-arm" +/// +private int delegate(scope int delegate(ref string)) getPlatformSuffixIterator(BuildPlatform platform) +{ + int iterator(scope int delegate(ref string s) del) + { + auto c = platform.compiler; + int delwrap(string s) { return del(s); } + if( auto ret = delwrap(null) ) return ret; + if( auto ret = delwrap("-"~c) ) return ret; + foreach( p; platform.platform ){ + if( auto ret = delwrap("-"~p) ) return ret; + if( auto ret = delwrap("-"~p~"-"~c) ) return ret; + foreach( a; platform.architecture ){ + if( auto ret = delwrap("-"~p~"-"~a) ) return ret; + if( auto ret = delwrap("-"~p~"-"~a~"-"~c) ) return ret; + } + } + foreach( a; platform.architecture ){ + if( auto ret = delwrap("-"~a) ) return ret; + if( auto ret = delwrap("-"~a~"-"~c) ) return ret; + } + return 0; + } + return &iterator; +} diff --git a/source/dub/project.d b/source/dub/project.d index 3245b76..2ee8754 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -121,12 +121,7 @@ string getDefaultConfiguration(BuildPlatform platform) const { - string ret; - foreach(p; getTopologicalPackageList(true)){ - auto c = p.getDefaultConfiguration(platform); - if( c.length ) ret = c; - } - return ret; + return m_main.getDefaultConfiguration(platform, true); } @@ -167,20 +162,20 @@ void collectDependenciesRec(Package pack) { logDebug("Collecting dependencies for %s", pack.name); - foreach( ldef; pack.localPackageDefs ){ - Path path = ldef.path; - if( !path.absolute ) path = pack.path ~ path; - logDebug("Adding local %s %s", path, ldef.version_); - m_packageManager.addLocalPackage(path, ldef.version_, LocalPackageType.temporary); - } - foreach( name, vspec; pack.dependencies ){ - auto p = m_packageManager.getBestPackage(name, vspec); - if( !m_dependencies.canFind(p) ){ - logDebug("Found dependency %s %s: %s", name, vspec.toString(), p !is null); - if( p ){ - m_dependencies ~= p; - collectDependenciesRec(p); + if( !vspec.path.empty ){ + Path path = vspec.path; + if( !path.absolute ) path = pack.path ~ path; + logDebug("Adding local %s %s", path, vspec.version_); + m_packageManager.addLocalPackage(path, vspec.version_, LocalPackageType.temporary); + } else { + auto p = m_packageManager.getBestPackage(name, vspec); + if( !m_dependencies.canFind(p) ){ + logDebug("Found dependency %s %s: %s", name, vspec.toString(), p !is null); + if( p ){ + m_dependencies ~= p; + collectDependenciesRec(p); + } } } //enforce(p !is null, "Failed to resolve dependency "~name~" "~vspec.toString()); @@ -192,23 +187,19 @@ /// Returns the applications name. @property string name() const { return m_main ? m_main.name : "app"; } - @property string[] configurations() + @property string[] configurations() const { return m_main.configurations; } + + string getPackageConfig(in Package pack, string config) const { - string[] ret; - if( m_main ) ret = m_main.configurations; - foreach( p; m_dependencies ){ - auto cfgs = p.configurations; - foreach( c; cfgs ) - if( !ret.canFind(c) ) ret ~= c; - } - return ret; + if( pack is m_main ) return config; + else return "library"; // TODO: determine user choices } /// Returns the DFLAGS void addBuildSettings(ref BuildSettings dst, BuildPlatform platform, string config) const { foreach(pkg; this.getTopologicalPackageList()){ - processVars(dst, pkg.path.toNativeString(), pkg.getBuildSettings(platform, config, pkg is m_main)); + processVars(dst, pkg.path.toNativeString(), pkg.getBuildSettings(platform, getPackageConfig(pkg, config))); } // add version identifiers for available packages @@ -520,7 +511,7 @@ pack = pkg; type = id; packageId = pkg.name; - vers = new immutable(Dependency)("==", pkg.vers); + vers = new immutable(Dependency)(pkg.ver); issuer = issue; }