diff --git a/source/dub/generators/compiler.d b/source/dub/generators/compiler.d
new file mode 100644
index 0000000..52056b9
--- /dev/null
+++ b/source/dub/generators/compiler.d
@@ -0,0 +1,11 @@
+/**
+
+ Copyright: © 2012 Matthias Dondorff
+ License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
+ Authors: Matthias Dondorff
+*/
+module dub.generators.compiler;
+
+struct Compiler {
+
+}
\ No newline at end of file
diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d
index 3374bb6..8d30215 100644
--- a/source/dub/generators/visuald.d
+++ b/source/dub/generators/visuald.d
@@ -1,371 +1,446 @@
-/**
- Generator for VisualD project files
-
- Copyright: © 2012 Matthias Dondorff
- License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
- Authors: Matthias Dondorff
-*/
-module dub.generators.visuald;
-
-import std.algorithm;
-import std.array;
-import std.conv;
-import std.format;
-import std.uuid;
-import std.exception;
-
-import vibe.core.file;
-import vibe.core.log;
-
-import dub.dub;
-import dub.package_;
-import dub.packagemanager;
-import dub.generators.generator;
-
-// version = VISUALD_SEPERATE_PROJECT_FILES;
-version = VISUALD_SINGLE_PROJECT_FILE;
-
-class VisualDGenerator : ProjectGenerator {
- private {
- Application m_app;
- PackageManager m_pkgMgr;
- string[string] m_projectUuids;
- bool[string] m_generatedProjects;
- }
-
- this(Application app, PackageManager mgr) {
- m_app = app;
- m_pkgMgr = mgr;
- }
-
- void generateProject() {
- logTrace("About to generate projects for %s, with %s direct dependencies.", m_app.mainPackage().name, to!string(m_app.mainPackage().dependencies().length));
- generateProjects(m_app.mainPackage());
- generateSolution();
- }
-
- private {
- enum Config {
- Release,
- Debug,
- Unittest
- }
-
- void generateSolution() {
- auto ret = appender!(char[])();
-
- // Solution header
- ret.formattedWrite("
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010");
-
- generateSolutionEntries(ret, m_app.mainPackage());
-
- // Global section contains configurations
- ret.formattedWrite("
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Release|Win32 = Release|Win32
- Unittest|Win32 = Unittest|Win32
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution");
-
- generateSolutionConfig(ret, m_app.mainPackage());
-
- // TODO: for all dependencies
-
- ret.formattedWrite("
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal");
-
- // Writing solution file
- logTrace("About to write to .sln file with %s bytes", to!string(ret.data().length));
- auto sln = openFile(m_app.mainPackage().name ~ ".sln", FileMode.CreateTrunc);
- scope(exit) sln.close();
- sln.write(ret.data());
- sln.flush();
- }
-
- void generateSolutionEntries(Appender!(char[]) ret, const Package main) {
- generateSolutionEntry(ret, main);
- version(VISUALD_SEPERATE_PROJECT_FILES) {
- performOnDependencies(main, (const Package pack) { generateSolutionEntries(ret, pack); } );
- }
- version(VISUALD_SINGLE_PROJECT_FILE) {
- enforce(main == m_app.mainPackage());
- }
- }
-
- void generateSolutionEntry(Appender!(char[]) ret, const Package pack) {
- auto projUuid = generateUUID();
- auto projName = pack.name;
- auto projPath = pack.name ~ ".visualdproj";
- auto projectUuid = guid(projName);
-
- // Write project header, like so
- // Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "derelict", "..\inbase\source\derelict.visualdproj", "{905EF5DA-649E-45F9-9C15-6630AA815ACB}"
- ret.formattedWrite("\nProject(\"%s\") = \"%s\", \"%s\", \"%s\"",
- projUuid, projName, projPath, projectUuid);
-
- version(VISUALD_SEPERATE_PROJECT_FILES) {
- if(pack.dependencies.length > 0) {
- ret.formattedWrite("
- ProjectSection(ProjectDependencies) = postProject");
- foreach(id, dependency; pack.dependencies) {
- // TODO: clarify what "uuid = uuid" should mean
- auto uuid = guid(id);
- ret.formattedWrite("
- %s = %s", uuid, uuid);
- }
- ret.formattedWrite("
- EndProjectSection");
- }
- }
-
- ret.formattedWrite("\nEndProject");
- }
-
- void generateSolutionConfig(Appender!(char[]) ret, const Package pack) {
- const string[] sub = [ "ActiveCfg", "Build.0" ];
- const string[] conf = [ "Debug|Win32", "Release|Win32" /*, "Unittest|Win32" */];
- auto projectUuid = guid(pack.name());
- foreach(c; conf)
- foreach(s; sub)
- formattedWrite(ret, "\n\t\t%s.%s.%s = %s", to!string(projectUuid), c, s, c);
- }
-
- void generateProjects(const Package main) {
-
- // TODO: cyclic check
-
- generateProj(main);
-
- version(VISUALD_SEPERATE_PROJECT_FILES)
- {
- m_generatedProjects[main.name] = true;
- performOnDependencies(main, (const Package dependency) {
- if(dependency.name in m_generatedProjects)
- return;
- generateProjects(dependency);
- } );
- }
- }
-
- void generateProj(const Package pack) {
- int i = 0;
- auto ret = appender!(char[])();
-
- auto projName = pack.name;
- ret.formattedWrite(
-"
- %s", guid(projName));
-
- // Several configurations (debug, release, unittest)
- generateProjectConfiguration(ret, pack, Config.Debug);
- generateProjectConfiguration(ret, pack, Config.Release);
- // generateProjectConfiguration(ret, pack, Config.Unittest);
-
- // Add all files
- // TODO: nice folders
- struct SourceFile {
- string pkg;
- Path structurePath;
- Path filePath;
- int opCmp(ref const SourceFile rhs) const { return filePath.opCmp(rhs.filePath); }
- }
- bool[SourceFile] sourceFiles;
- void gatherSources(const(Package) package_, string prefix) {
- logDebug("Gather sources for %s", package_.name);
- if(prefix != "") prefix = "|" ~ prefix ~ "|";
- foreach(source; package_.sources) {
- SourceFile f = { package_.name, source, source };
- sourceFiles[f] = true;
- logDebug("pkg file: %s", source);
- }
- }
- version(VISUALD_SINGLE_PROJECT_FILE) {
- // gather all sources
- enforce(pack == m_app.mainPackage(), "Some setup has gone wrong in VisualD.generateProj()");
- bool[string] gathered;
- void gatherAll(const Package package_) {
- logDebug("Looking at %s", package_.name);
- if(package_.name in gathered)
- return;
- gathered[package_.name] = true;
- gatherSources(package_, ""/*package_.name*/);
- performOnDependencies(package_, (const Package dependency) { gatherAll(dependency); });
- }
- gatherAll(pack);
- }
- version(VISUALD_SEPERATE_PROJECT_FILES) {
- // gather sources for this package only
- gatherSources(pack, "");
- }
-
- // Create folders and files
- // TODO: nice foldering
- version(VISUALD_SINGLE_PROJECT_FILE) {
- SourceFile[] files = sourceFiles.keys;
- sort!("a.pkg > b.pkg")(files);
- string last = "";
- ret.formattedWrite("
- ");
- foreach(source; files) {
- if(last != source.pkg) {
- if(!last.empty)
- ret.formattedWrite("
- ");
- ret.formattedWrite("
- ", source.pkg);
- last = source.pkg;
- }
- ret.formattedWrite("
- ", source.filePath.toString());
- }
- ret.formattedWrite("
-
- ");
- }
- version(VISUALD_SEPERATE_PROJECT_FILES) {
- formattedWrite(ret, "
- ", projName);
- foreach(source, dummy; sourceFiles)
- ret.formattedWrite("\n ", source.filePath.toString());
- ret.formattedWrite("
- ");
- }
- ret.formattedWrite("
-");
-
- logTrace("About to write to '%s.visualdproj' file %s bytes", pack.name, to!string(ret.data().length));
- auto sln = openFile(pack.name ~ ".visualdproj", FileMode.CreateTrunc);
- scope(exit) sln.close();
- sln.write(ret.data());
- sln.flush();
- }
-
- void generateProjectConfiguration(Appender!(char[]) ret, const Package pack, Config type) {
- ret.formattedWrite(
-"\n
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 2
- 0
- 0
- 0
- $(DMDInstallDir)windows\\bin\\dmd.exe
-
-
- $(ConfigurationName)
- $(OutDir)
-
-
- 0
-
-
-
-
- 0
-
-
- 1
- $(IntDir)\\$(TargetName).json
- 0
-
- 0
- DerelictGL_ALL HostWin32
- 0
- 0
- 0
-
-
-
- 0
-
- 1
- $(VisualDInstallDir)cv2pdb\\cv2pdb.exe
- 0
- 0
- 0
-
-
-
- ws2_32.lib gdi32.lib winmm.lib ..\\vibe.d\\lib\\win-i386\\event2.lib ..\\vibe.d\\lib\\win-i386\\eay.lib ..\\vibe.d\\lib\\win-i386\\ssl.lib
-
-
-
- bin\\$(ProjectName)_d.exe
-
-
-
- *.obj;*.cmd;*.build;*.json;*.dep
- ", to!string(type));
- }
-
- void performOnDependencies(const Package main, void delegate(const Package pack) op) {
- // TODO: cyclic check
-
- foreach(id, dependency; main.dependencies) {
- logDebug("Retrieving package %s from package manager.", id);
- auto pack = m_pkgMgr.getBestPackage(id, dependency);
- if(pack is null) {
- logWarn("Package %s (%s) could not be retrieved continuing...", id, to!string(dependency));
- continue;
- }
- logDebug("Performing on retrieved package %s", pack.name);
- op(pack);
- }
- }
-
- string generateUUID() const {
- return "{" ~ randomUUID().toString() ~ "}";
- }
-
- string guid(string projectName) {
- if(projectName !in m_projectUuids)
- m_projectUuids[projectName] = generateUUID();
- return m_projectUuids[projectName];
- }
- }
+/**
+ Generator for VisualD project files
+
+ Copyright: © 2012 Matthias Dondorff
+ License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
+ Authors: Matthias Dondorff
+*/
+module dub.generators.visuald;
+
+import std.algorithm;
+import std.array;
+import std.conv;
+import std.format;
+import std.uuid;
+import std.exception;
+
+import vibe.core.file;
+import vibe.core.log;
+
+import dub.dub;
+import dub.package_;
+import dub.packagemanager;
+import dub.generators.generator;
+
+// version = VISUALD_SEPERATE_PROJECT_FILES;
+version = VISUALD_SINGLE_PROJECT_FILE;
+
+class VisualDGenerator : ProjectGenerator {
+ private {
+ Application m_app;
+ PackageManager m_pkgMgr;
+ string[string] m_projectUuids;
+ bool[string] m_generatedProjects;
+ }
+
+ this(Application app, PackageManager mgr) {
+ m_app = app;
+ m_pkgMgr = mgr;
+ }
+
+ void generateProject() {
+ logTrace("About to generate projects for %s, with %s direct dependencies.", m_app.mainPackage().name, to!string(m_app.mainPackage().dependencies().length));
+ generateProjects(m_app.mainPackage());
+ generateSolution();
+ }
+
+ private {
+ enum Config {
+ Release,
+ Debug,
+ Unittest
+ }
+
+ void generateSolution() {
+ auto ret = appender!(char[])();
+
+ // Solution header
+ ret.formattedWrite("
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010");
+
+ generateSolutionEntries(ret, m_app.mainPackage());
+
+ // Global section contains configurations
+ ret.formattedWrite("
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Unittest|Win32 = Unittest|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution");
+
+ generateSolutionConfig(ret, m_app.mainPackage());
+
+ // TODO: for all dependencies
+
+ ret.formattedWrite("
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal");
+
+ // Writing solution file
+ logTrace("About to write to .sln file with %s bytes", to!string(ret.data().length));
+ auto sln = openFile(m_app.mainPackage().name ~ ".sln", FileMode.CreateTrunc);
+ scope(exit) sln.close();
+ sln.write(ret.data());
+ sln.flush();
+ }
+
+ void generateSolutionEntries(Appender!(char[]) ret, const Package main) {
+ generateSolutionEntry(ret, main);
+ version(VISUALD_SEPERATE_PROJECT_FILES) {
+ performOnDependencies(main, (const Package pack) { generateSolutionEntries(ret, pack); } );
+ }
+ version(VISUALD_SINGLE_PROJECT_FILE) {
+ enforce(main == m_app.mainPackage());
+ }
+ }
+
+ void generateSolutionEntry(Appender!(char[]) ret, const Package pack) {
+ auto projUuid = generateUUID();
+ auto projName = pack.name;
+ auto projPath = pack.name ~ ".visualdproj";
+ auto projectUuid = guid(projName);
+
+ // Write project header, like so
+ // Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "derelict", "..\inbase\source\derelict.visualdproj", "{905EF5DA-649E-45F9-9C15-6630AA815ACB}"
+ ret.formattedWrite("\nProject(\"%s\") = \"%s\", \"%s\", \"%s\"",
+ projUuid, projName, projPath, projectUuid);
+
+ version(VISUALD_SEPERATE_PROJECT_FILES) {
+ if(pack.dependencies.length > 0) {
+ ret.formattedWrite("
+ ProjectSection(ProjectDependencies) = postProject");
+ foreach(id, dependency; pack.dependencies) {
+ // TODO: clarify what "uuid = uuid" should mean
+ auto uuid = guid(id);
+ ret.formattedWrite("
+ %s = %s", uuid, uuid);
+ }
+ ret.formattedWrite("
+ EndProjectSection");
+ }
+ }
+
+ ret.formattedWrite("\nEndProject");
+ }
+
+ void generateSolutionConfig(Appender!(char[]) ret, const Package pack) {
+ const string[] sub = [ "ActiveCfg", "Build.0" ];
+ const string[] conf = [ "Debug|Win32", "Release|Win32" /*, "Unittest|Win32" */];
+ auto projectUuid = guid(pack.name());
+ foreach(c; conf)
+ foreach(s; sub)
+ formattedWrite(ret, "\n\t\t%s.%s.%s = %s", to!string(projectUuid), c, s, c);
+ }
+
+ void generateProjects(const Package main) {
+
+ // TODO: cyclic check
+
+ generateProj(main);
+
+ version(VISUALD_SEPERATE_PROJECT_FILES)
+ {
+ m_generatedProjects[main.name] = true;
+ performOnDependencies(main, (const Package dependency) {
+ if(dependency.name in m_generatedProjects)
+ return;
+ generateProjects(dependency);
+ } );
+ }
+ }
+
+ void generateProj(const Package pack) {
+ int i = 0;
+ auto ret = appender!(char[])();
+
+ auto projName = pack.name;
+ ret.formattedWrite(
+"
+ %s", guid(projName));
+
+ // Several configurations (debug, release, unittest)
+ generateProjectConfiguration(ret, pack, Config.Debug);
+ generateProjectConfiguration(ret, pack, Config.Release);
+ // generateProjectConfiguration(ret, pack, Config.Unittest);
+
+ // Add all files
+ // TODO: nice folders
+ struct SourceFile {
+ string pkg;
+ Path structurePath;
+ Path filePath;
+ int opCmp(ref const SourceFile rhs) const { return filePath.opCmp(rhs.filePath); }
+ }
+ bool[SourceFile] sourceFiles;
+ void gatherSources(const(Package) package_, string prefix) {
+ logDebug("Gather sources for %s", package_.name);
+ if(prefix != "") prefix = "|" ~ prefix ~ "|";
+ foreach(source; package_.sources) {
+ SourceFile f = { package_.name, source, source };
+ sourceFiles[f] = true;
+ logDebug("pkg file: %s", source);
+ }
+ }
+
+ version(VISUALD_SINGLE_PROJECT_FILE) {
+ // gather all sources
+ enforce(pack == m_app.mainPackage(), "Some setup has gone wrong in VisualD.generateProj()");
+ bool[string] gathered;
+ void gatherAll(const Package package_) {
+ logDebug("Looking at %s", package_.name);
+ if(package_.name in gathered)
+ return;
+ gathered[package_.name] = true;
+ gatherSources(package_, ""/*package_.name*/);
+ performOnDependencies(package_, (const Package dependency) { gatherAll(dependency); });
+ }
+ gatherAll(pack);
+ }
+ version(VISUALD_SEPERATE_PROJECT_FILES) {
+ // gather sources for this package only
+ gatherSources(pack, "");
+ }
+
+ // Create folders and files
+ // TODO: nice foldering
+ version(VISUALD_SINGLE_PROJECT_FILE) {
+ SourceFile[] files = sourceFiles.keys;
+ sort!("a.pkg > b.pkg")(files);
+ string last = "";
+ ret.formattedWrite("
+ ");
+ foreach(source; files) {
+ if(last != source.pkg) {
+ if(!last.empty)
+ ret.formattedWrite("
+ ");
+ ret.formattedWrite("
+ ", source.pkg);
+ last = source.pkg;
+ }
+ ret.formattedWrite("
+ ", source.filePath.toString());
+ }
+ ret.formattedWrite("
+
+ ");
+ }
+ version(VISUALD_SEPERATE_PROJECT_FILES) {
+ formattedWrite(ret, "
+ ", projName);
+ foreach(source, dummy; sourceFiles)
+ ret.formattedWrite("\n ", source.filePath.toString());
+ ret.formattedWrite("
+ ");
+ }
+ ret.formattedWrite("
+");
+
+ logTrace("About to write to '%s.visualdproj' file %s bytes", pack.name, to!string(ret.data().length));
+ auto sln = openFile(pack.name ~ ".visualdproj", FileMode.CreateTrunc);
+ scope(exit) sln.close();
+ sln.write(ret.data());
+ sln.flush();
+ }
+
+ void generateProjectConfiguration(Appender!(char[]) ret, const Package pack, Config type) {
+
+
+ string[] getSettingsHelper(BuildSettings bs, in string setting) {
+ // TODO: make nice, compile time string stuff?
+ switch(setting) {
+ case "dflags": return bs.dflags;
+ case "lflags": return bs.lflags;
+ case "libs": return bs.libs;
+ case "files": return bs.files;
+ case "copyFiles": return bs.copyFiles;
+ case "versions": return bs.versions;
+ case "importPaths": return bs.importPaths;
+ case "stringImportPaths": return bs.stringImportPaths;
+ default: assert(false);
+ }
+ }
+ string[] getSettings(in Package pack, in string setting, bool prefixPath) {
+ BuildPlatform platform;
+ platform.platform ~= "windows";
+ platform.architecture ~= "x86";
+ platform.compiler = "dmd";
+ version(VISUALD_SEPERATE_PROJECT_FILES) {
+ assert(false, "Not implemented");
+ }
+ version(VISUALD_SINGLE_PROJECT_FILE) {
+ string[] ret;
+ performOnDependencies(pack, (const Package dep) { ret ~= getSettings(dep, setting, prefixPath); } );
+ if(prefixPath) {
+ string[] itms = getSettingsHelper(pack.getBuildSettings(platform, ""), setting);
+ foreach(i; itms)
+ ret ~= to!string(pack.path) ~ "\\" ~ i;
+ }
+ else
+ ret ~= getSettingsHelper(pack.getBuildSettings(platform, ""), setting);
+ return ret;
+ }
+ }
+
+ string combine(string seperator)(string[] vals) {
+ return reduce!("a~'"~seperator~"'~b")("", vals);
+ }
+
+ // Specify build configuration name
+ ret.formattedWrite("
+ ", to!string(type));
+
+ ret.formattedWrite("
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 2
+ 0
+ 0
+ 0");
+
+ // Compiler ?
+ ret.formattedWrite("
+ $(DMDInstallDir)windows\\bin\\dmd.exe
+
+
+ $(ConfigurationName)
+ $(OutDir)
+
+
+ 0
+
+
+
+
+ 0
+
+
+ 1
+ $(IntDir)\\$(TargetName).json
+ 0
+
+ 0");
+
+ // Add version identifiers
+ string versions = combine!(" ")(getSettings(pack, "versions", false));
+ ret.formattedWrite("
+ %s", versions);
+
+ ret.formattedWrite("
+ 0
+ 0
+ 0
+
+
+
+ 0
+ ");
+
+ // TODO: Mago? Debugger settings!
+ ret.formattedWrite("
+ 1
+ $(VisualDInstallDir)cv2pdb\\cv2pdb.exe
+ 0
+ 0
+ 0
+
+
+ ");
+
+ // Add libraries.
+ string linkLibs = combine!(" ")(getSettings(pack, "libs", false));
+ string addLinkFiles = combine!(" ")(getSettings(pack, "files", true));
+ ret.formattedWrite("
+ %s", linkLibs ~ " " ~ addLinkFiles);
+
+ // Add library paths ( not necessary, libraries have absolute path )
+ ret.formattedWrite("
+
+
+
+ bin\\$(ProjectName)_d.exe
+
+ ");
+
+ // Add a post build command to copy files
+ ret.formattedWrite("
+ ");
+
+ ret.formattedWrite("
+ *.obj;*.cmd;*.build;*.json;*.dep
+ ");
+ }
+
+ void performOnDependencies(const Package main, void delegate(const Package pack) op) {
+ // TODO: cyclic check
+
+ foreach(id, dependency; main.dependencies) {
+ logDebug("Retrieving package %s from package manager.", id);
+ auto pack = m_pkgMgr.getBestPackage(id, dependency);
+ if(pack is null) {
+ logWarn("Package %s (%s) could not be retrieved continuing...", id, to!string(dependency));
+ continue;
+ }
+ logDebug("Performing on retrieved package %s", pack.name);
+ op(pack);
+ }
+ }
+
+ string generateUUID() const {
+ return "{" ~ randomUUID().toString() ~ "}";
+ }
+
+ string guid(string projectName) {
+ if(projectName !in m_projectUuids)
+ m_projectUuids[projectName] = generateUUID();
+ return m_projectUuids[projectName];
+ }
+
+ string libfiles(const Package pack) {
+ return "";
+ }
+ }
}
\ No newline at end of file
diff --git a/source/dub/package_.d b/source/dub/package_.d
index 5321ea6..c80ce2c 100644
--- a/source/dub/package_.d
+++ b/source/dub/package_.d
@@ -1,240 +1,283 @@
-/**
- Stuff with dependencies.
-
- Copyright: © 2012 Matthias Dondorff
- License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
- Authors: Matthias Dondorff
-*/
-module dub.package_;
-
-import dub.dependency;
-import dub.utils;
-
-import std.array;
-import std.conv;
-import std.exception;
-import std.file;
-import vibe.core.file;
-import vibe.data.json;
-import vibe.inet.url;
-
-enum PackageJsonFilename = "package.json";
-
-struct BuildPlatform {
- string[] platform;
- string[] architecture;
- string compiler;
-}
-
-struct BuildSettings {
- string[] dflags;
- string[] lflags;
- string[] libs;
- string[] files;
- string[] copyFiles;
- string[] versions;
- string[] importPaths;
- string[] stringImportPaths;
-
- void parse(in Json root, BuildPlatform platform)
- {
- addDFlags(getPlatformField(root, "dflags", platform));
- addLFlags(getPlatformField(root, "lflags", platform));
- addLibs(getPlatformField(root, "libs", platform));
- addFiles(getPlatformField(root, "files", platform));
- addCopyFiles(getPlatformField(root, "copyFiles", platform));
- addVersions(getPlatformField(root, "versions", platform));
- addImportDirs(getPlatformField(root, "importPaths", platform));
- addStringImportDirs(getPlatformField(root, "stringImportPaths", platform));
- }
-
- void addDFlags(string[] value) { add(dflags, value); }
- void addLFlags(string[] value) { add(lflags, value); }
- void addLibs(string[] value) { add(libs, value); }
- void addFiles(string[] value) { add(files, value); }
- void addCopyFiles(string[] value) { add(copyFiles, value); }
- void addVersions(string[] value) { add(versions, value); }
- void addImportDirs(string[] value) { add(importPaths, value); }
- void addStringImportDirs(string[] value) { add(stringImportPaths, value); }
-
- private void add(ref string[] arr, string[] vals)
- {
- foreach( v; vals ){
- bool found = false;
- foreach( i; 0 .. arr.length )
- if( arr[i] == v ){
- found = true;
- break;
- }
- if( !found ) arr ~= v;
- }
- }
-
- private string[] getPlatformField(in Json json, string name, BuildPlatform platform)
- const {
- auto ret = appender!(string[])();
- foreach( suffix; getPlatformSuffixIterator(platform) ){
- foreach( j; json[name~suffix].opt!(Json[]) )
- ret.put(j.get!string);
- }
- return ret.data;
- }
-}
-
-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;
-}
-
-/// Representing an installed package
-// Json file example:
-// {
-// "name": "MetalCollection",
-// "author": "VariousArtists",
-// "version": "1.0.0",
-// "url": "https://github.org/...",
-// "keywords": "a,b,c",
-// "category": "music.best",
-// "dependencies": {
-// "black-sabbath": ">=1.0.0",
-// "CowboysFromHell": "<1.0.0",
-// "BeneathTheRemains": {"version": "0.4.1", "path": "./beneath-0.4.1"}
-// }
-// "licenses": {
-// ...
-// }
-// }
-class Package {
- static struct LocalPackageDef { string name; Version version_; Path path; }
-
- private {
- InstallLocation m_location;
- Path m_path;
- Json m_meta;
- Dependency[string] m_dependencies;
- LocalPackageDef[] m_localPackageDefs;
- }
-
- this(InstallLocation location, Path root)
- {
- this(jsonFromFile(root ~ PackageJsonFilename), location, root);
- }
-
- this(Json package_info, InstallLocation location = InstallLocation.Local, Path root = Path())
- {
- m_location = location;
- m_path = root;
- m_meta = package_info;
-
- // extract dependencies and local package definitions
- if( auto pd = "dependencies" in package_info ){
- foreach( string pkg, verspec; *pd ) {
- enforce(pkg !in m_dependencies, "The dependency '"~pkg~"' is specified more than once." );
- if( verspec.type == Json.Type.Object ){
- auto ver = verspec["version"].get!string;
- m_dependencies[pkg] = new Dependency("==", ver);
- m_localPackageDefs ~= LocalPackageDef(pkg, Version(ver), Path(verspec.path.get!string()));
- } else 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 string binaryPath() const { return m_meta["binaryPath"].opt!string; }
-
- @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;
- }
-
- BuildSettings getBuildSettings(BuildPlatform platform, string config)
- const {
- BuildSettings ret;
- ret.parse(m_meta, platform);
- if( config.length ){
- auto pcs = "configurations" in m_meta;
- if( !pcs ) return ret;
- auto pc = config in *pcs;
- if( !pc ) return ret;
- ret.parse(*pc, platform);
- }
- return ret;
- }
-
- @property const(Path[]) sources() const {
- Path[] allSources;
- foreach(DirEntry d; dirEntries(to!string(m_path ~ Path("source")), "*.d", SpanMode.depth))
- allSources ~= Path(d.name);
- return allSources;
- }
-
- string getDefaultConfiguration(BuildPlatform platform)
- 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;
- }
-
- string info() const {
- string s;
- s ~= cast(string)m_meta["name"] ~ ", version '" ~ cast(string)m_meta["version"] ~ "'";
- s ~= "\n Dependencies:";
- foreach(string p, ref const Dependency v; m_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();
- Appender!string js;
- toPrettyJson(js, m_meta);
- dstFile.write( js.data );
- }
-}
-
-enum InstallLocation {
- Local,
- ProjectLocal,
- UserWide,
- SystemWide
-}
+/**
+ Stuff with dependencies.
+
+ Copyright: © 2012 Matthias Dondorff
+ License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
+ Authors: Matthias Dondorff
+*/
+module dub.package_;
+
+import dub.dependency;
+import dub.utils;
+
+import std.array;
+import std.conv;
+import std.exception;
+import std.file;
+import vibe.core.file;
+import vibe.data.json;
+import vibe.inet.url;
+
+enum PackageJsonFilename = "package.json";
+
+/// Represents a platform a package can be build upon.
+struct BuildPlatform {
+ /// e.g. ["posix", "windows"]
+ string[] platform;
+ /// e.g. ["x86", "x64"]
+ string[] architecture;
+ /// e.g. "dmd"
+ string compiler;
+}
+
+/// BuildPlatform specific settings, like needed libraries or additional
+/// include paths.
+struct BuildSettings {
+ string[] dflags;
+ string[] lflags;
+ string[] libs;
+ string[] files;
+ string[] copyFiles;
+ string[] versions;
+ string[] importPaths;
+ string[] stringImportPaths;
+
+ void parse(in Json root, BuildPlatform platform)
+ {
+ addDFlags(getPlatformField(root, "dflags", platform));
+ addLFlags(getPlatformField(root, "lflags", platform));
+ addLibs(getPlatformField(root, "libs", platform));
+ addFiles(getPlatformField(root, "files", platform));
+ addCopyFiles(getPlatformField(root, "copyFiles", platform));
+ addVersions(getPlatformField(root, "versions", platform));
+ addImportDirs(getPlatformField(root, "importPaths", platform));
+ addStringImportDirs(getPlatformField(root, "stringImportPaths", platform));
+ }
+
+ void addDFlags(string[] value) { add(dflags, value); }
+ void addLFlags(string[] value) { add(lflags, value); }
+ void addLibs(string[] value) { add(libs, value); }
+ void addFiles(string[] value) { add(files, value); }
+ void addCopyFiles(string[] value) { add(copyFiles, value); }
+ void addVersions(string[] value) { add(versions, value); }
+ void addImportDirs(string[] value) { add(importPaths, value); }
+ void addStringImportDirs(string[] value) { add(stringImportPaths, value); }
+
+ // Adds vals to arr without adding duplicates.
+ private void add(ref string[] arr, string[] vals)
+ {
+ foreach( v; vals ){
+ bool found = false;
+ foreach( i; 0 .. arr.length )
+ if( arr[i] == v ){
+ found = true;
+ break;
+ }
+ if( !found ) arr ~= v;
+ }
+ }
+
+ // Parses json and returns the values of the corresponding field
+ // by the platform.
+ private string[] getPlatformField(in Json json, string name, BuildPlatform platform)
+ const {
+ auto ret = appender!(string[])();
+ foreach( suffix; getPlatformSuffixIterator(platform) ){
+ foreach( j; json[name~suffix].opt!(Json[]) )
+ ret.put(j.get!string);
+ }
+ return ret.data;
+ }
+}
+
+/// 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;
+}
+
+/// Indicates where a package has been or should be installed to.
+enum InstallLocation {
+ Local,
+ ProjectLocal,
+ UserWide,
+ SystemWide
+}
+
+/// Representing an installed package, usually constructed from a json object.
+///
+/// Json file example:
+/// {
+/// "name": "MetalCollection",
+/// "author": "VariousArtists",
+/// "version": "1.0.0",
+/// "url": "https://github.org/...",
+/// "keywords": "a,b,c",
+/// "category": "music.best",
+/// "dependencies": {
+/// "black-sabbath": ">=1.0.0",
+/// "CowboysFromHell": "<1.0.0",
+/// "BeneathTheRemains": {"version": "0.4.1", "path": "./beneath-0.4.1"}
+/// }
+/// "licenses": {
+/// ...
+/// }
+/// "configurations": {
+// TODO: what and how?
+/// }
+// TODO: plain like this or packed together?
+/// "
+/// "dflags-X"
+/// "lflags-X"
+/// "libs-X"
+/// "files-X"
+/// "copyFiles-X"
+/// "versions-X"
+/// "importPaths-X"
+/// "stringImportPaths-X"
+///
+/// }
+/// }
+///
+/// TODO: explain configurations
+class Package {
+ static struct LocalPackageDef { string name; Version version_; Path path; }
+
+ private {
+ InstallLocation m_location;
+ Path m_path;
+ Json m_meta;
+ Dependency[string] m_dependencies;
+ LocalPackageDef[] m_localPackageDefs;
+ }
+
+ this(InstallLocation location, Path root)
+ {
+ this(jsonFromFile(root ~ PackageJsonFilename), location, root);
+ }
+
+ this(Json packageInfo, InstallLocation location = InstallLocation.Local, Path root = Path())
+ {
+ 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 ){
+ auto ver = verspec["version"].get!string;
+ m_dependencies[pkg] = new Dependency("==", ver);
+ m_localPackageDefs ~= LocalPackageDef(pkg, Version(ver), Path(verspec.path.get!string()));
+ } else 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 string binaryPath() const { return m_meta["binaryPath"].opt!string; }
+
+ @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)
+ const {
+ BuildSettings ret;
+ ret.parse(m_meta, platform);
+ if( config.length ){
+ auto pcs = "configurations" in m_meta;
+ if( !pcs ) return ret;
+ auto pc = config in *pcs;
+ if( !pc ) return ret;
+ ret.parse(*pc, platform);
+ }
+ return ret;
+ }
+
+ /// Returns all sources as absolute paths.
+ @property const(Path[]) sources() const {
+ Path[] allSources;
+ foreach(DirEntry d; dirEntries(to!string(m_path ~ Path("source")), "*.d", SpanMode.depth))
+ allSources ~= Path(d.name);
+ return allSources;
+ }
+
+ /// TODO: what is the defaul configuration?
+ string getDefaultConfiguration(BuildPlatform platform)
+ 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;
+ }
+
+ /// 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 ~= "\n Dependencies:";
+ foreach(string p, ref const Dependency v; m_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();
+ Appender!string js;
+ toPrettyJson(js, m_meta);
+ dstFile.write( js.data );
+ }
+}