diff --git a/build-gdc.sh b/build-gdc.sh index 203f8c9..df0e5ce 100755 --- a/build-gdc.sh +++ b/build-gdc.sh @@ -17,7 +17,7 @@ echo "enum dubVersion = \"$GITVER\";" >> source/dub/version_.d echo Running $GDC... -$GDC -obin/dub -lcurl -w -fversion=DubUseCurl -Isource $* $LIBS @build-files.txt +$GDC -obin/dub -lcurl -w -fversion=DubUseCurl -fversion=DubApplication -Isource $* $LIBS @build-files.txt echo DUB has been built as bin/dub. echo echo You may want to run diff --git a/build.cmd b/build.cmd index f965194..f6d6a34 100644 --- a/build.cmd +++ b/build.cmd @@ -7,7 +7,7 @@ @echo enum dubVersion = "%GITVER%"; >> source\dub\version_.d @echo Executing %DC%... -@%DC% -ofbin\dub.exe -g -debug -w -version=DubUseCurl -Isource curl.lib %* @build-files.txt +@%DC% -ofbin\dub.exe -g -debug -w -version=DubUseCurl -version=DubApplication -Isource curl.lib %* @build-files.txt @if errorlevel 1 exit /b 1 @echo DUB has been built. You probably also want to add the following entry to your diff --git a/build.sh b/build.sh index 1afe076..ba9fffc 100755 --- a/build.sh +++ b/build.sh @@ -56,7 +56,7 @@ MACOSX_DEPLOYMENT_TARGET=10.8 echo Running $DMD... -$DMD -ofbin/dub -g -O -w -version=DubUseCurl -Isource $* $LIBS @build-files.txt +$DMD -ofbin/dub -g -O -w -version=DubUseCurl -version=DubApplication -Isource $* $LIBS @build-files.txt bin/dub --version echo DUB has been built as bin/dub. echo diff --git a/changelog/dubEnvVar.dd b/changelog/dubEnvVar.dd new file mode 100644 index 0000000..b27a8cc --- /dev/null +++ b/changelog/dubEnvVar.dd @@ -0,0 +1,13 @@ +dub now supports `$DUB` variable + +With this release, one can call dub from build commands in the following way: +------ + // dub.sdl: + preBuildCommands "$DUB run --single somebuildscript.d" +----- +This is useful if dub is not in the `$PATH`, or if several versions of dub are installed. + +`$DUB` is also accessible as environment variable in the build commands processes. + +`$DUB` points to the running executable, unless it is used as a library. +In such case, `$DUB` will resolve to the first dub executable found in `$PATH`. diff --git a/dub.sdl b/dub.sdl index 2607c34..3f17241 100644 --- a/dub.sdl +++ b/dub.sdl @@ -11,7 +11,7 @@ targetType "executable" mainSourceFile "source/app.d" libs "curl" - versions "DubUseCurl" + versions "DubUseCurl" "DubApplication" } configuration "library" { diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 5fbc5b0..c375634 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -621,9 +621,9 @@ void runBuildCommands(in string[] commands, in Package pack, in Project proj, in GeneratorSettings settings, in BuildSettings build_settings) { - import std.conv; - import std.process; - import dub.internal.utils; + import dub.internal.utils : getDUBExePath, runCommands; + import std.conv : to, text; + import std.process : environment, escapeShellFileName; string[string] env = environment.toAA(); // TODO: do more elaborate things here @@ -639,6 +639,7 @@ env["DC_BASE"] = settings.platform.compiler; env["D_FRONTEND_VER"] = to!string(settings.platform.frontendVersion); + env["DUB_EXE"] = getDUBExePath(settings.platform.compilerBinary); env["DUB_PLATFORM"] = join(cast(string[])settings.platform.platform," "); env["DUB_ARCH"] = join(cast(string[])settings.platform.architecture," "); diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index ac62e30..42ecdf1 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -430,6 +430,65 @@ return verstr; } + +/** + Get current executable's path if running as DUB executable, + or find a DUB executable if DUB is used as a library. + For the latter, the following locations are checked in order: + $(UL + $(LI current working directory) + $(LI same directory as `compilerBinary` (if supplied)) + $(LI all components of the `$PATH` variable) + ) + Params: + compilerBinary = optional path to a D compiler executable, used to locate DUB executable + Returns: + The path to a valid DUB executable + Throws: + an Exception if no valid DUB executable is found +*/ +public string getDUBExePath(in string compilerBinary=null) +{ + version(DubApplication) { + import std.file : thisExePath; + return thisExePath(); + } + else { + // this must be dub as a library + import std.algorithm : filter, map, splitter; + import std.array : array; + import std.file : exists, getcwd; + import std.path : chainPath, dirName; + import std.range : chain, only, take; + import std.process : environment; + + version(Windows) { + enum exeName = "dub.exe"; + enum pathSep = ';'; + } + else { + enum exeName = "dub"; + enum pathSep = ':'; + } + + auto dubLocs = only( + getcwd().chainPath(exeName), + compilerBinary.dirName.chainPath(exeName), + ) + .take(compilerBinary.length ? 2 : 1) + .chain( + environment.get("PATH", "") + .splitter(pathSep) + .map!(p => p.chainPath(exeName)) + ) + .filter!exists; + + enforce(!dubLocs.empty, "Could not find DUB executable"); + return dubLocs.front.array; + } +} + + version(DubUseCurl) { void setupHTTPClient(ref HTTP conn, uint timeout) { diff --git a/source/dub/project.d b/source/dub/project.d index c441220..46c1ade 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -1213,8 +1213,10 @@ private string getVariable(Project, Package)(string name, in Project project, in Package pack, in GeneratorSettings gsettings) { - import std.process : environment; + import dub.internal.utils : getDUBExePath; + import std.process : environment, escapeShellFileName; import std.uni : asUpperCase; + NativePath path; if (name == "PACKAGE_DIR") path = pack.path; @@ -1238,6 +1240,10 @@ return path.toNativeString(); } + if (name == "DUB") { + return getDUBExePath(gsettings.platform.compilerBinary); + } + if (name == "ARCH") { foreach (a; gsettings.platform.architecture) return a; diff --git a/test/pr1549-dub-exe-var.sh b/test/pr1549-dub-exe-var.sh new file mode 100755 index 0000000..7ad9f55 --- /dev/null +++ b/test/pr1549-dub-exe-var.sh @@ -0,0 +1,11 @@ +#! /usr/bin/env bash +set -e + +. $(dirname "${BASH_SOURCE[0]}")/common.sh + +PR1549=$CURR_DIR/pr1549-dub-exe-var + +${DUB} build --root ${PR1549} +OUTPUT=$(${PR1549}/test-application) + +if [[ "$OUTPUT" != "modified code" ]]; then die "\$DUB build variable was (likely) not evaluated correctly"; fi diff --git a/test/pr1549-dub-exe-var/.gitignore b/test/pr1549-dub-exe-var/.gitignore new file mode 100644 index 0000000..964cd1d --- /dev/null +++ b/test/pr1549-dub-exe-var/.gitignore @@ -0,0 +1,2 @@ +setmsg +setmsg.exe diff --git a/test/pr1549-dub-exe-var/.no_build b/test/pr1549-dub-exe-var/.no_build new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/pr1549-dub-exe-var/.no_build diff --git a/test/pr1549-dub-exe-var/dub.sdl b/test/pr1549-dub-exe-var/dub.sdl new file mode 100644 index 0000000..fdb283a --- /dev/null +++ b/test/pr1549-dub-exe-var/dub.sdl @@ -0,0 +1,4 @@ +name "test-application" +targetType "executable" +preBuildCommands "$DUB run --single $PACKAGE_DIR/setmsg.d -- \"modified code\"" +postBuildCommands "$DUB run --single $PACKAGE_DIR/setmsg.d -- \"unmodified code\"" diff --git a/test/pr1549-dub-exe-var/setmsg.d b/test/pr1549-dub-exe-var/setmsg.d new file mode 100644 index 0000000..6eb7f93 --- /dev/null +++ b/test/pr1549-dub-exe-var/setmsg.d @@ -0,0 +1,21 @@ +/+ dub.sdl: ++/ + +import std.exception; +import std.path; +import std.process; +import std.stdio; + +void main(in string[] args) +{ + enforce(args.length > 1); + const string msg = args[1]; + + const path = buildPath(environment["DUB_PACKAGE_DIR"], "source", "app.d"); + auto file = File(path, "w"); + file.writeln(`import std.stdio;`); + file.writeln(); + file.writeln(`void main() {`); + file.writefln(` writeln("%s");`, msg); + file.writeln(`}`); +} diff --git a/test/pr1549-dub-exe-var/source/app.d b/test/pr1549-dub-exe-var/source/app.d new file mode 100644 index 0000000..e143585 --- /dev/null +++ b/test/pr1549-dub-exe-var/source/app.d @@ -0,0 +1,5 @@ +import std.stdio; + +void main() { + writeln("unmodified code"); +}