diff --git a/source/app.d b/source/app.d
index 6b300b1..9394dda 100644
--- a/source/app.d
+++ b/source/app.d
@@ -238,6 +238,7 @@
logDebug("Generating using %s", generator);
dub.generateProject(generator, gensettings);
+ if( build_type == "ddox" ) dub.runDdox();
break;
}
@@ -308,7 +309,7 @@
remove-local
Removes a local package directory
list-locals Prints a list of all locals
generate Generates project files using the specified generator:
- visuald, mono-d, build, rdmd
+ visuald, mono-d, build, rdmd
General options:
--annotate Do not execute dependency installations, just print
@@ -318,13 +319,16 @@
--vquiet No output
Build/run options:
- --build=NAME Specifies the type of build to perform. Valid names:
- debug (default), release, unittest, profile, docs,
- plain
+ --build=NAME Specifies the type of build to perform. Note that
+ setting the DFLAGS environment variable will override
+ the build type with custom flags.
+ Possible names:
+ debug (default), plain, release, unittest, profile,
+ docs, ddox
--config=NAME Builds the specified configuration. Configurations can
be defined in package.json
--compiler=NAME Uses one of the supported compilers:
- dmd (default), gcc, ldc, gdmd, ldmd
+ dmd (default), gcc, ldc, gdmd, ldmd
--arch=NAME Force a different architecture (e.g. x86 or x86_64)
--nodeps Do not check dependencies for 'run' or 'build'
--print-builds Prints the list of available build types
diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d
index 81ed9fc..d1710e7 100644
--- a/source/dub/compilers/compiler.d
+++ b/source/dub/compilers/compiler.d
@@ -13,6 +13,7 @@
import std.algorithm;
import std.array;
+import std.exception;
import vibecompat.data.json;
import vibecompat.inet.path;
@@ -65,36 +66,68 @@
string[] dflags;
string[] lflags;
string[] libs;
- string[] files;
+ string[] sourceFiles;
string[] copyFiles;
string[] versions;
string[] importPaths;
string[] stringImportPaths;
+ string[] preGenerateCommands;
+ string[] postGenerateCommands;
+ string[] preBuildCommands;
+ string[] postBuildCommands;
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));
+ 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(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); }
+ void addDFlags(in string[] value...) { add(dflags, value); }
+ void addLFlags(in string[] value...) { add(lflags, value); }
+ void addLibs(in string[] value...) { add(libs, value); }
+ void addSourceFiles(in string[] value...) { add(sourceFiles, value); }
+ void addCopyFiles(in string[] value...) { add(copyFiles, value); }
+ void addVersions(in string[] value...) { add(versions, value); }
+ void addImportPaths(in string[] value...) { add(importPaths, value); }
+ void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); }
+ void addPreGenerateCommands(in string[] value...) { add(preGenerateCommands, value, false); }
+ void addPostGenerateCommands(in string[] value...) { add(postGenerateCommands, value, false); }
+ void addPreBuildCommands(in string[] value...) { add(preBuildCommands, value, false); }
+ void addPostBuildCommands(in string[] value...) { add(postBuildCommands, value, false); }
// Adds vals to arr without adding duplicates.
- private void add(ref string[] arr, string[] vals)
+ private void add(ref string[] arr, in string[] vals, bool no_duplicates = true)
{
+ if( !no_duplicates ){
+ arr ~= vals;
+ return;
+ }
+
foreach( v; vals ){
bool found = false;
foreach( i; 0 .. arr.length )
@@ -106,16 +139,14 @@
}
}
- // 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;
+ 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;
}
}
@@ -133,7 +164,7 @@
dflags = 1<<0,
lflags = 1<<1,
libs = 1<<2,
- files = 1<<3,
+ sourceFiles = 1<<3,
copyFiles = 1<<4,
versions = 1<<5,
importPaths = 1<<6,
@@ -141,7 +172,7 @@
none = 0,
commandLine = dflags|copyFiles,
commandLineSeparate = commandLine|lflags,
- all = dflags|lflags|libs|files|copyFiles|versions|importPaths|stringImportPaths
+ all = dflags|lflags|libs|sourceFiles|copyFiles|versions|importPaths|stringImportPaths
}
private {
diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d
index 4d0f1e3..fb3f6ff 100644
--- a/source/dub/compilers/dmd.d
+++ b/source/dub/compilers/dmd.d
@@ -56,7 +56,7 @@
} catch( Exception e ){
logDebug("pkg-config failed: %s", e.msg);
logDebug("Falling back to direct -lxyz flags.");
- version(Windows) settings.addFiles(settings.libs.map!(l => l~".lib")().array());
+ version(Windows) settings.addSourceFiles(settings.libs.map!(l => l~".lib")().array());
else settings.addLFlags(settings.libs.map!(l => "-l"~l)().array());
}
settings.libs = null;
@@ -77,9 +77,9 @@
settings.stringImportPaths = null;
}
- if( !(fields & BuildSetting.files) ){
- settings.addDFlags(settings.files);
- settings.files = null;
+ if( !(fields & BuildSetting.sourceFiles) ){
+ settings.addDFlags(settings.sourceFiles);
+ settings.sourceFiles = null;
}
if( !(fields & BuildSetting.lflags) ){
diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d
index 39a47de..707c413 100644
--- a/source/dub/compilers/gdc.d
+++ b/source/dub/compilers/gdc.d
@@ -117,9 +117,9 @@
settings.stringImportPaths = null;
}
- if( !(fields & BuildSetting.files) ){
- settings.addDFlags(settings.files);
- settings.files = null;
+ if( !(fields & BuildSetting.sourceFiles) ){
+ settings.addDFlags(settings.sourceFiles);
+ settings.sourceFiles = null;
}
if( !(fields & BuildSetting.lflags) ){
diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d
index d94a67c..abfb71c 100644
--- a/source/dub/compilers/ldc.d
+++ b/source/dub/compilers/ldc.d
@@ -74,9 +74,9 @@
settings.stringImportPaths = null;
}
- if( !(fields & BuildSetting.files) ){
- settings.addDFlags(settings.files);
- settings.files = null;
+ if( !(fields & BuildSetting.sourceFiles) ){
+ settings.addDFlags(settings.sourceFiles);
+ settings.sourceFiles = null;
}
if( !(fields & BuildSetting.lflags) ){
diff --git a/source/dub/dub.d b/source/dub/dub.d
index a9b2be8..0694fc8 100644
--- a/source/dub/dub.d
+++ b/source/dub/dub.d
@@ -95,18 +95,18 @@
void loadPackageFromCwd()
{
- m_root = m_cwd;
+ loadPackage(m_cwd);
+ }
+
+ void loadPackage(Path path)
+ {
+ m_root = path;
m_packageManager.projectPackagePath = m_root ~ ".dub/packages/";
m_project = new Project(m_packageManager, m_root);
}
string getDefaultConfiguration(BuildPlatform platform) const { return m_project.getDefaultConfiguration(platform); }
- /// Lists all installed modules
- void list() {
- logInfo(m_project.info());
- }
-
/// Performs installation and uninstallation as necessary for
/// the application.
/// @param options bit combination of UpdateOptions
@@ -170,25 +170,20 @@
m_project.createZip(zipFile);
}
- /// Prints some information to the log.
- void info() {
- logInfo("Status for %s", m_root);
- logInfo("\n" ~ m_project.info());
- }
/// Gets all installed packages as a "packageId" = "version" associative array
string[string] installedPackages() const { return m_project.installedPackagesIDs(); }
/// Installs the package matching the dependency into the application.
- void install(string packageId, const Dependency dep, InstallLocation location = InstallLocation.projectLocal)
+ Package install(string packageId, const Dependency dep, InstallLocation location = InstallLocation.projectLocal)
{
auto pinfo = m_packageSupplier.packageJson(packageId, dep);
string ver = pinfo["version"].get!string;
- if( m_packageManager.hasPackage(packageId, ver, location) ){
+ if( auto pack = m_packageManager.getPackage(packageId, ver, location) ){
logInfo("Package %s %s (%s) is already installed with the latest version, skipping upgrade.",
packageId, ver, location);
- return;
+ return pack;
}
logInfo("Downloading %s %s...", packageId, ver);
@@ -203,7 +198,7 @@
scope(exit) remove(sTempFile);
logInfo("Installing %s %s...", packageId, ver);
- m_packageManager.install(tempFile, pinfo, location);
+ return m_packageManager.install(tempFile, pinfo, location);
}
/// Uninstalls a given package from the list of installed modules.
@@ -345,4 +340,43 @@
//Act smug to the user.
logInfo("Successfully created an empty project in '"~path.toNativeString()~"'.");
}
+
+ void runDdox()
+ {
+ auto ddox_pack = m_packageManager.getBestPackage("ddox", ">=0.0.0");
+ if( !ddox_pack ){
+ logInfo("DDOX is not installed, performing user wide installation.");
+ ddox_pack = install("ddox", new Dependency(">=0.0.0"), InstallLocation.userWide);
+ }
+
+ version(Windows) auto ddox_exe = "ddox.exe";
+ else auto ddox_exe = "ddox";
+
+ if( !existsFile(ddox_pack.path~ddox_exe) ){
+ logInfo("DDOX in %s is not built, performing build now.", ddox_pack.path.toNativeString());
+
+ auto ddox_dub = new Dub(m_packageSupplier);
+ ddox_dub.loadPackage(ddox_pack.path);
+
+ GeneratorSettings settings;
+ settings.compilerBinary = "dmd";
+ settings.compiler = getCompiler(settings.compilerBinary);
+ settings.platform = settings.compiler.determinePlatform(settings.buildSettings, settings.compilerBinary);
+ settings.buildType = "debug";
+ ddox_dub.generateProject("build", settings);
+
+ //runCommands(["cd "~ddox_pack.path.toNativeString()~" && dub build -v"]);
+ }
+
+ auto p = ddox_pack.path;
+ p.endsWithSlash = true;
+ auto dub_path = p.toNativeString();
+
+ string[] commands;
+ commands ~= dub_path~"ddox filter --min-protection=Protected docs.json";
+ commands ~= dub_path~"ddox generate-html docs.json docs";
+ version(Windows) commands ~= "xcopy /S /D "~dub_path~"public\\* docs\\";
+ else commands ~= "cp -r "~dub_path~"public/* docs/";
+ runCommands(commands);
+ }
}
diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d
index 7ed19b2..1d592e5 100644
--- a/source/dub/generators/build.d
+++ b/source/dub/generators/build.d
@@ -12,6 +12,7 @@
import dub.package_;
import dub.packagemanager;
import dub.project;
+import dub.utils;
import std.algorithm;
import std.array;
@@ -40,11 +41,11 @@
void generateProject(GeneratorSettings settings)
{
-
//Added check for existance of [AppNameInPackagejson].d
//If exists, use that as the starting file.
auto outfile = getBinName(m_project);
auto mainsrc = getMainSourceFile(m_project);
+ auto cwd = Path(getcwd());
logDebug("Application output name is '%s'", outfile);
@@ -64,31 +65,35 @@
foreach(s; pack.sources){
if( pack !is m_project.mainPackage && s == Path("source/app.d") )
continue;
- auto relpath = (pack.path ~ s).relativeTo(m_project.mainPackage.path);
- buildsettings.addFiles(relpath.toNativeString());
+ auto relpath = (pack.path ~ s).relativeTo(cwd);
+ buildsettings.addSourceFiles(relpath.toNativeString());
}
}
addPackageFiles(m_project.mainPackage);
- foreach(dep; m_project.installedPackages)
+ foreach(dep; m_project.dependencies)
addPackageFiles(dep);
+ auto generate_binary = !buildsettings.dflags.canFind("-o-");
+
// setup for command line
settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine);
Path run_exe_file;
- if( !settings.run ){
- settings.compiler.setTarget(buildsettings, m_project.binaryPath~outfile);
- } else {
- import std.random;
- auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-";
- auto tmp = environment.get("TEMP");
- if( !tmp.length ) tmp = environment.get("TMP");
- if( !tmp.length ){
- version(Posix) tmp = "/tmp";
- else tmp = ".";
+ if( generate_binary ){
+ if( !settings.run ){
+ settings.compiler.setTarget(buildsettings, m_project.binaryPath~outfile);
+ } else {
+ import std.random;
+ auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-";
+ auto tmp = environment.get("TEMP");
+ if( !tmp.length ) tmp = environment.get("TMP");
+ if( !tmp.length ){
+ version(Posix) tmp = "/tmp";
+ else tmp = ".";
+ }
+ run_exe_file = Path(tmp~"/.rdmd/source/"~rnd~outfile);
+ settings.compiler.setTarget(buildsettings, run_exe_file);
}
- run_exe_file = Path(tmp~"/.rdmd/source/"~rnd~outfile);
- settings.compiler.setTarget(buildsettings, run_exe_file);
}
string[] flags = buildsettings.dflags;
@@ -96,30 +101,53 @@
if( settings.config.length ) logInfo("Building configuration "~settings.config~", build type "~settings.buildType);
else logInfo("Building default configuration, build type "~settings.buildType);
- logInfo("Running %s", settings.compilerBinary ~ " " ~ join(flags, " "));
+ if( buildsettings.preGenerateCommands.length ){
+ logInfo("Running pre-generate commands...");
+ runCommands(buildsettings.preGenerateCommands);
+ }
+
+ if( buildsettings.postGenerateCommands.length ){
+ logInfo("Running post-generate commands...");
+ runCommands(buildsettings.postGenerateCommands);
+ }
+
+ if( buildsettings.preBuildCommands.length ){
+ logInfo("Running pre-build commands...");
+ runCommands(buildsettings.preBuildCommands);
+ }
+
+ logInfo("Running %s...", settings.compilerBinary);
+ logDebug("%s %s", settings.compilerBinary, join(flags, " "));
auto compiler_pid = spawnProcess(settings.compilerBinary, flags);
auto result = compiler_pid.wait();
enforce(result == 0, "Build command failed with exit code "~to!string(result));
- // TODO: move to a common place - this is not generator specific
- if( buildsettings.copyFiles.length ){
- logInfo("Copying files...");
- foreach( f; buildsettings.copyFiles ){
- auto src = Path(f);
- auto dst = (run_exe_file.empty ? m_project.binaryPath : run_exe_file.parentPath) ~ Path(f).head;
- logDebug(" %s to %s", src.toNativeString(), dst.toNativeString());
- try copyFile(src, dst, true);
- catch logWarn("Failed to copy to %s", dst.toNativeString());
- }
+ if( buildsettings.postBuildCommands.length ){
+ logInfo("Running post-build commands...");
+ runCommands(buildsettings.postBuildCommands);
}
- if( settings.run ){
- auto prg_pid = spawnProcess(run_exe_file.toNativeString(), settings.runArgs);
- result = prg_pid.wait();
- remove(run_exe_file.toNativeString());
- foreach( f; buildsettings.copyFiles )
- remove((run_exe_file.parentPath ~ Path(f).head).toNativeString());
- enforce(result == 0, "Program exited with code "~to!string(result));
+ if( generate_binary ){
+ // TODO: move to a common place - this is not generator specific
+ if( buildsettings.copyFiles.length ){
+ logInfo("Copying files...");
+ foreach( f; buildsettings.copyFiles ){
+ auto src = Path(f);
+ auto dst = (run_exe_file.empty ? m_project.binaryPath : run_exe_file.parentPath) ~ Path(f).head;
+ logDebug(" %s to %s", src.toNativeString(), dst.toNativeString());
+ try copyFile(src, dst, true);
+ catch logWarn("Failed to copy to %s", dst.toNativeString());
+ }
+ }
+
+ if( settings.run ){
+ auto prg_pid = spawnProcess(run_exe_file.toNativeString(), settings.runArgs);
+ result = prg_pid.wait();
+ remove(run_exe_file.toNativeString());
+ foreach( f; buildsettings.copyFiles )
+ remove((run_exe_file.parentPath ~ Path(f).head).toNativeString());
+ enforce(result == 0, "Program exited with code "~to!string(result));
+ }
}
}
}
diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d
index e832d98..c64ead6 100644
--- a/source/dub/generators/generator.d
+++ b/source/dub/generators/generator.d
@@ -79,6 +79,7 @@
case "release": dst.addDFlags("-release", "-O", "-inline"); break;
case "unittest": dst.addDFlags("-g", "-unittest"); break;
case "profile": dst.addDFlags("-g", "-O", "-inline", "-profile"); break;
- case "docs": dst.addDFlags("-c", "-o-", "-D", "-Dfdocs", "-Xfdocs.json"); break;
+ case "docs": dst.addDFlags("-c", "-o-", "-D", "-Dddocs"); break;
+ case "ddox": dst.addDFlags("-c", "-o-", "-D", "-Df__dummy.html", "-Xfdocs.json"); break;
}
}
diff --git a/source/dub/generators/monod.d b/source/dub/generators/monod.d
index e3db7e4..72b4cee 100644
--- a/source/dub/generators/monod.d
+++ b/source/dub/generators/monod.d
@@ -12,6 +12,7 @@
import dub.package_;
import dub.packagemanager;
import dub.project;
+import dub.utils;
import std.algorithm;
import std.array;
@@ -24,6 +25,8 @@
import vibecompat.core.log;
+// TODO: handle pre/post build commands
+
class MonoDGenerator : ProjectGenerator {
private {
Project m_app;
@@ -42,9 +45,21 @@
void generateProject(GeneratorSettings settings)
{
+ auto buildsettings = settings.buildSettings;
+
+ if( buildsettings.preGenerateCommands.length ){
+ logInfo("Running pre-generate commands...");
+ runCommands(buildsettings.preGenerateCommands);
+ }
+
logTrace("About to generate projects for %s, with %s direct dependencies.", m_app.mainPackage().name, m_app.mainPackage().dependencies().length);
generateProjects(m_app.mainPackage(), settings);
generateSolution(settings);
+
+ if( buildsettings.postGenerateCommands.length ){
+ logInfo("Running post-generate commands...");
+ runCommands(buildsettings.postGenerateCommands);
+ }
}
private void generateSolution(GeneratorSettings settings)
@@ -239,7 +254,7 @@
continue;
generateSourceEntry(p.path ~s, p.path);
}
- foreach( s; buildsettings.files )
+ foreach( s; buildsettings.sourceFiles )
generateSourceEntry(Path(s), p.path);
}
@@ -247,7 +262,7 @@
sln.put(" \n");
generateSources(pack);
if( m_singleProject )
- foreach(dep; m_app.installedPackages)
+ foreach(dep; m_app.dependencies)
generateSources(dep);
sln.put(" \n");
sln.put("");
diff --git a/source/dub/generators/rdmd.d b/source/dub/generators/rdmd.d
index 8602001..2d11159 100644
--- a/source/dub/generators/rdmd.d
+++ b/source/dub/generators/rdmd.d
@@ -12,7 +12,9 @@
import dub.package_;
import dub.packagemanager;
import dub.project;
+import dub.utils;
+import std.algorithm;
import std.array;
import std.conv;
import std.exception;
@@ -39,7 +41,6 @@
void generateProject(GeneratorSettings settings)
{
-
//Added check for existance of [AppNameInPackagejson].d
//If exists, use that as the starting file.
auto outfile = getBinName(m_project);
@@ -47,26 +48,6 @@
logDebug("Application output name is '%s'", outfile);
- // Create start script, which will be used by the calling bash/cmd script.
- // build "rdmd --force %DFLAGS% -I%~dp0..\source -Jviews -Isource @deps.txt %LIBS% source\app.d" ~ application arguments
- // or with "/" instead of "\"
- string[] flags = ["--force", "--build-only", "--compiler="~settings.compilerBinary];
- Path run_exe_file;
- if( !settings.run ){
- flags ~= "-of"~(m_project.binaryPath~outfile).toNativeString();
- } else {
- import std.random;
- auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-";
- auto tmp = environment.get("TEMP");
- if( !tmp.length ) tmp = environment.get("TMP");
- if( !tmp.length ){
- version(Posix) tmp = "/tmp";
- else tmp = ".";
- }
- run_exe_file = Path(tmp~"/.rdmd/source/"~rnd~outfile);
- flags ~= "-of"~run_exe_file.toNativeString();
- }
-
auto buildsettings = settings.buildSettings;
m_project.addBuildSettings(buildsettings, settings.platform, settings.config);
buildsettings.addDFlags(["-w"/*, "-property"*/]);
@@ -78,37 +59,84 @@
addBuildTypeFlags(buildsettings, settings.buildType);
}
+ auto generate_binary = !buildsettings.dflags.canFind("-o-");
+
+ // Create start script, which will be used by the calling bash/cmd script.
+ // build "rdmd --force %DFLAGS% -I%~dp0..\source -Jviews -Isource @deps.txt %LIBS% source\app.d" ~ application arguments
+ // or with "/" instead of "\"
+ string[] flags = ["--force", "--build-only", "--compiler="~settings.compilerBinary];
+ Path run_exe_file;
+ if( generate_binary ){
+ if( !settings.run ){
+ flags ~= "-of"~(m_project.binaryPath~outfile).toNativeString();
+ } else {
+ import std.random;
+ auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-";
+ auto tmp = environment.get("TEMP");
+ if( !tmp.length ) tmp = environment.get("TMP");
+ if( !tmp.length ){
+ version(Posix) tmp = "/tmp";
+ else tmp = ".";
+ }
+ run_exe_file = Path(tmp~"/.rdmd/source/"~rnd~outfile);
+ flags ~= "-of"~run_exe_file.toNativeString();
+ }
+ }
+
settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine);
flags ~= buildsettings.dflags;
flags ~= (mainsrc).toNativeString();
+ if( buildsettings.preGenerateCommands.length ){
+ logInfo("Running pre-generate commands...");
+ runCommands(buildsettings.preGenerateCommands);
+ }
+
+ if( buildsettings.postGenerateCommands.length ){
+ logInfo("Running post-generate commands...");
+ runCommands(buildsettings.postGenerateCommands);
+ }
+
+ if( buildsettings.preBuildCommands.length ){
+ logInfo("Running pre-build commands...");
+ runCommands(buildsettings.preBuildCommands);
+ }
+
if( settings.config.length ) logInfo("Building configuration "~settings.config~", build type "~settings.buildType);
else logInfo("Building default configuration, build type "~settings.buildType);
- logInfo("Running %s", "rdmd " ~ join(flags, " "));
+ logInfo("Running rdmd...");
+ logDebug("rdmd %s", join(flags, " "));
auto rdmd_pid = spawnProcess("rdmd", flags);
auto result = rdmd_pid.wait();
enforce(result == 0, "Build command failed with exit code "~to!string(result));
- // TODO: move to a common place - this is not generator specific
- if( buildsettings.copyFiles.length ){
- logInfo("Copying files...");
- foreach( f; buildsettings.copyFiles ){
- auto src = Path(f);
- auto dst = (run_exe_file.empty ? m_project.binaryPath : run_exe_file.parentPath) ~ Path(f).head;
- logDebug(" %s to %s", src.toNativeString(), dst.toNativeString());
- try copyFile(src, dst, true);
- catch logWarn("Failed to copy to %s", dst.toNativeString());
- }
+ if( buildsettings.postBuildCommands.length ){
+ logInfo("Running post-build commands...");
+ runCommands(buildsettings.postBuildCommands);
}
- if( settings.run ){
- auto prg_pid = spawnProcess(run_exe_file.toNativeString(), settings.runArgs);
- result = prg_pid.wait();
- remove(run_exe_file.toNativeString());
- foreach( f; buildsettings.copyFiles )
- remove((run_exe_file.parentPath ~ Path(f).head).toNativeString());
- enforce(result == 0, "Program exited with code "~to!string(result));
+ if( generate_binary ){
+ // TODO: move to a common place - this is not generator specific
+ if( buildsettings.copyFiles.length ){
+ logInfo("Copying files...");
+ foreach( f; buildsettings.copyFiles ){
+ auto src = Path(f);
+ auto dst = (run_exe_file.empty ? m_project.binaryPath : run_exe_file.parentPath) ~ Path(f).head;
+ logDebug(" %s to %s", src.toNativeString(), dst.toNativeString());
+ try copyFile(src, dst, true);
+ catch logWarn("Failed to copy to %s", dst.toNativeString());
+ }
+ }
+
+ if( settings.run ){
+ auto prg_pid = spawnProcess(run_exe_file.toNativeString(), settings.runArgs);
+ result = prg_pid.wait();
+ remove(run_exe_file.toNativeString());
+ foreach( f; buildsettings.copyFiles )
+ remove((run_exe_file.parentPath ~ Path(f).head).toNativeString());
+ enforce(result == 0, "Program exited with code "~to!string(result));
+ }
}
}
}
diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d
index 6e52a52..38b5ee3 100644
--- a/source/dub/generators/visuald.d
+++ b/source/dub/generators/visuald.d
@@ -12,6 +12,7 @@
import dub.package_;
import dub.packagemanager;
import dub.project;
+import dub.utils;
import std.algorithm;
import std.array;
@@ -29,6 +30,9 @@
// Dubbing is developing dub...
//version = DUBBING;
+// TODO: handle pre/post build commands
+
+
class VisualDGenerator : ProjectGenerator {
private {
Project m_app;
@@ -42,10 +46,22 @@
}
void generateProject(GeneratorSettings settings) {
+ auto buildsettings = settings.buildSettings;
+
+ if( buildsettings.preGenerateCommands.length ){
+ logInfo("Running pre-generate commands...");
+ runCommands(buildsettings.preGenerateCommands);
+ }
+
logTrace("About to generate projects for %s, with %s direct dependencies.", m_app.mainPackage().name, m_app.mainPackage().dependencies().length);
generateProjects(m_app.mainPackage(), settings);
generateSolution();
logInfo("VisualD project generated.");
+
+ if( buildsettings.postGenerateCommands.length ){
+ logInfo("Running post-generate commands...");
+ runCommands(buildsettings.postGenerateCommands);
+ }
}
private {
@@ -286,7 +302,7 @@
// Add libraries, system libs need to be suffixed by ".lib".
string linkLibs = join(map!(a => a~".lib")(getSettings!"libs"()), " ");
- string addLinkFiles = join(getSettings!"files"(), " ");
+ string addLinkFiles = join(getSettings!"sourceFiles"(), " ");
ret.formattedWrite("
%s", linkLibs ~ " " ~ addLinkFiles);
diff --git a/source/dub/package_.d b/source/dub/package_.d
index 03ebe04..f1d2b2b 100644
--- a/source/dub/package_.d
+++ b/source/dub/package_.d
@@ -124,7 +124,12 @@
@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 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 {
@@ -148,6 +153,9 @@
if( !pc ) return ret;
ret.parse(*pc, platform);
}
+
+ // TODO: add all sources and "source"/"src" as import paths
+ // TODO: add "views" as string import path
return ret;
}
@@ -190,12 +198,26 @@
spaths ~= map!(p => Path(p.get!string()))((*multipleSourcePaths)[]).array;
}
if (spaths.empty) {
- spaths ~= Path("source");
+ if( existsFile(path ~ "source") ) spaths ~= Path("source");
+ else if( existsFile(path ~ "src") ) spaths ~= Path("src");
}
return spaths;
}
+ @property const(Path[]) appSources()
+ const {
+ Path[] ret;
+ if( auto as = "appSources" in m_meta ){
+ foreach(src; *as)
+ ret ~= Path(src.get!string());
+ } else {
+ if( existsFile(m_path ~ "source/app.d") ) ret ~= Path("source/app.d");
+ else if( existsFile(m_path ~ ("source/"~name()~".d")) ) ret ~= Path("source/"~name()~".d");
+ }
+ return ret;
+ }
+
/// TODO: what is the defaul configuration?
string getDefaultConfiguration(BuildPlatform platform)
const {
diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d
index 5b177f5..129bff0 100644
--- a/source/dub/packagemanager.d
+++ b/source/dub/packagemanager.d
@@ -66,13 +66,13 @@
return null;
}
- bool hasPackage(string name, string ver, InstallLocation location)
+ Package getPackage(string name, string ver, InstallLocation location)
{
foreach(ep; getPackageIterator(name)){
if( ep.installLocation == location && ep.vers == ver )
- return true;
+ return ep;
}
- return false;
+ return null;
}
Package getBestPackage(string name, string version_spec)
diff --git a/source/dub/project.d b/source/dub/project.d
index 2726f6c..3478c88 100644
--- a/source/dub/project.d
+++ b/source/dub/project.d
@@ -54,10 +54,7 @@
reinit();
}
- @property Path binaryPath() const
- {
- return m_main.binaryPath.length ? Path(m_main.binaryPath) : Path("./");
- }
+ @property Path binaryPath() const { return m_main.binaryPath; }
/// Gathers information
@property string info()
@@ -81,20 +78,47 @@
}
/// List of installed Packages
- @property const(Package[]) installedPackages() const { return m_dependencies; }
+ @property const(Package[]) dependencies() const { return m_dependencies; }
/// Main package.
@property const (Package) mainPackage() const { return m_main; }
+ /** Allows iteration of the dependency tree in topological order (children first)
+ */
+ @property int delegate(int delegate(ref const Package)) topologicalPackageList()
+ const {
+ int iterator(int delegate(ref const Package) del)
+ {
+ int ret = 0;
+ bool[const(Package)] visited;
+ void perform_rec(in Package p){
+ if( p in visited ) return;
+ visited[p] = true;
+
+ foreach(d; p.dependencies.byKey)
+ foreach(dp; m_dependencies)
+ if( dp.name == d ){
+ perform_rec(dp);
+ if( ret ) return;
+ break;
+ }
+
+ ret = del(p);
+ if( ret ) return;
+ }
+ perform_rec(m_main);
+ return ret;
+ }
+ return &iterator;
+ }
+
string getDefaultConfiguration(BuildPlatform platform)
const {
string ret;
- foreach( p; m_dependencies ){
+ foreach(p; topologicalPackageList){
auto c = p.getDefaultConfiguration(platform);
if( c.length ) ret = c;
}
- auto c = m_main.getDefaultConfiguration(platform);
- if( c ) ret = c;
return ret;
}
@@ -108,6 +132,11 @@
/// Rereads the applications state.
void reinit() {
+ scope(failure){
+ logDebug("Failed to parse package.json. Assuming defaults.");
+ m_main = new Package(serializeToJson(["name": ""]), InstallLocation.local, m_root);
+ }
+
m_dependencies = null;
m_main = null;
m_packageManager.refresh();
@@ -174,25 +203,22 @@
void addImportPath(string path, bool src)
{
if( !exists(path) ) return;
- if( src ) dst.addImportDirs([path]);
- else dst.addStringImportDirs([path]);
+ if( src ) dst.addImportPaths([path]);
+ else dst.addStringImportPaths([path]);
}
- if( m_main ) processVars(dst, ".", m_main.getBuildSettings(platform, config));
- addImportPath("source", true);
- addImportPath("views", false);
-
- foreach( pkg; m_dependencies ){
+ foreach(pkg; this.topologicalPackageList){
processVars(dst, pkg.path.toNativeString(), pkg.getBuildSettings(platform, config));
addImportPath((pkg.path ~ "source").toNativeString(), true);
addImportPath((pkg.path ~ "views").toNativeString(), false);
}
// add version identifiers for available packages
- foreach(pack; this.installedPackages)
+ foreach(pack; this.dependencies)
dst.addVersions(["Have_" ~ stripDlangSpecialChars(pack.name)]);
}
+
/// Actions which can be performed to update the application.
Action[] determineActions(PackageSupplier packageSupplier, int option) {
scope(exit) writeDubJson();
@@ -518,11 +544,15 @@
dst.addDFlags(processVars(project_path, settings.dflags));
dst.addLFlags(processVars(project_path, settings.lflags));
dst.addLibs(processVars(project_path, settings.libs));
- dst.addFiles(processVars(project_path, settings.files, true));
+ dst.addSourceFiles(processVars(project_path, settings.sourceFiles, true));
dst.addCopyFiles(processVars(project_path, settings.copyFiles, true));
dst.addVersions(processVars(project_path, settings.versions));
- dst.addImportDirs(processVars(project_path, settings.importPaths, true));
- dst.addStringImportDirs(processVars(project_path, settings.stringImportPaths, true));
+ dst.addImportPaths(processVars(project_path, settings.importPaths, true));
+ dst.addStringImportPaths(processVars(project_path, settings.stringImportPaths, true));
+ dst.addPreGenerateCommands(processVars(project_path, settings.preGenerateCommands));
+ dst.addPostGenerateCommands(processVars(project_path, settings.postGenerateCommands));
+ dst.addPreBuildCommands(processVars(project_path, settings.preBuildCommands));
+ dst.addPostBuildCommands(processVars(project_path, settings.postBuildCommands));
}
private string[] processVars(string project_path, string[] vars, bool are_paths = false)
diff --git a/source/dub/utils.d b/source/dub/utils.d
index 8ea6c54..a054ebb 100644
--- a/source/dub/utils.d
+++ b/source/dub/utils.d
@@ -20,6 +20,7 @@
import std.zip;
import std.typecons;
import std.conv;
+import stdx.process;
package bool isEmptyDir(Path p) {
@@ -70,3 +71,13 @@
return str[3 ..$];
return str;
}
+
+void runCommands(string[] commands)
+{
+ foreach(cmd; commands){
+ logDebug("Running %s", cmd);
+ auto pipes = pipeShell(cmd, Redirect.none);
+ auto exitcode = pipes.pid.wait();
+ enforce(exitcode == 0, "Command failed with exit code "~to!string(exitcode));
+ }
+}