Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions dstep/driver/Application.d
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ class Application
import std.algorithm;
import std.array;
import std.range;
import std.path;

import dstep.driver.Util : makeDefaultOutputFile;
import dstep.driver.Util : makeDefaultOutputFile, findBasePath;

auto inputFiles = config.inputFiles;

Expand All @@ -130,11 +131,19 @@ class Application
}
else
{
alias fmap = file => Path.buildPath(
config.output,
makeDefaultOutputFile(file, false));

return inputFiles.map!fmap.array;
if (config.output.empty)
{
alias fmap = file => makeDefaultOutputFile(file, false);
return inputFiles.map!fmap.array;
}
else
{
auto basePath = findBasePath(inputFiles);
alias fmap = file => Path.buildPath(
config.output,
makeDefaultOutputFile(relativePath(file, basePath), false));
return inputFiles.map!fmap.array;
}
}
}

Expand Down
86 changes: 86 additions & 0 deletions dstep/driver/Util.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,89 @@ string makeDefaultOutputFile(string inputFile, bool useBaseName = true)

return setExtension(inputFile, "d");
}

string findBasePath(string[] paths)
{
import std.algorithm.iteration : filter, map, reduce;
import std.algorithm.searching : commonPrefix;
import std.array : array;
import std.path : isAbsolute, dirName, pathSplitter, buildPath;

auto absolutePaths = paths.filter!isAbsolute.array;
if (absolutePaths.length == 0)
return ".";

version (Windows)
{
import std.string : replace;
absolutePaths = absolutePaths.map!(p => p.replace("/", "\\")).array;
}

if (absolutePaths.length == 1)
return dirName(absolutePaths[0]);

auto parts = absolutePaths
.map!(p => pathSplitter(dirName(p)).array)
.array;

version (Windows)
{
import std.uni : icmp;
auto common = parts.reduce!((a, b) => commonPrefix!((x, y) => icmp(x, y) == 0)(a, b).array);
}
else
{
auto common = parts.reduce!((a, b) => commonPrefix(a, b).array);
}

if (common.length == 0)
return ".";

return buildPath(common);
}

unittest
{
assert(findBasePath([]) == ".");
assert(findBasePath(["foo/bar.h", "a/b.h", "c.h"]) == ".");
}

version (Posix)
{
unittest
{
assert(findBasePath(["/usr/include/stdio.h"]) == "/usr/include");
assert(findBasePath(["foo.h", "/usr/include/sys/stat.h"]) == "/usr/include/sys");
assert(findBasePath(["/usr/include/stdio.h", "/usr/include/sys/stat.h", "/usr/lib/foo.h"]) == "/usr");
assert(findBasePath(["/usr/include/stdio.h", "/usr/include/string.h", "/usr/include/stdlib.h"]) == "/usr/include");
assert(findBasePath(["usr.h", "/usr/include/stdio.h", "/usr/include/sys/stat.h", "/usr/include/string.h", "include.h"]) == "/usr/include");
assert(findBasePath(["/usr/include/stdio.h", "/usr/Include/stdio.h", "/usR/include/stdio.h"]) == "/");
}
}

version (Windows)
{
unittest
{
assert(findBasePath(["/usr/include/stdio.h"]) == ".");
assert(findBasePath(["foo.h", "/usr/include/sys/stat.h"]) == ".");
assert(findBasePath(["/usr/include/stdio.h", "/usr/include/sys/stat.h", "/usr/lib/foo.h"]) == ".");
assert(findBasePath(["/usr/include/stdio.h", "/usr/include/string.h", "/usr/include/stdlib.h"]) == ".");
assert(findBasePath(["usr.h", "/usr/include/stdio.h", "/usr/include/sys/stat.h", "/usr/include/string.h", "include.h"]) == ".");
assert(findBasePath(["/usr/include/stdio.h", "/usr/Include/stdio.h", "/usR/include/stdio.h"]) == ".");

assert(findBasePath(["C:/usr/include/stdio.h"]) == "C:\\usr\\include");
assert(findBasePath(["foo.h", "C:/usr/include/sys/stat.h"]) == "C:\\usr\\include\\sys");
assert(findBasePath(["C:/usr/include/stdio.h", "C:/usr/include/sys/stat.h", "C:/usr/lib/foo.h"]) == "C:\\usr");
assert(findBasePath(["C:/usr/include/stdio.h", "C:/usr/include/string.h", "C:/usr/include/stdlib.h"]) == "C:\\usr\\include");
assert(findBasePath(["usr.h", "D:/usr/include/stdio.h", "D:/usr/include/sys/stat.h", "D:/usr/include/string.h", "include.h"]) == "D:\\usr\\include");
assert(findBasePath(["E:/usr/include/stdio.h", "E:/usr/Include/stdio.h", "E:/usR/include/stdio.h"]) == "E:\\usr\\include");

assert(findBasePath(["D:\\test.h"]) == "D:\\");
assert(findBasePath(["D:\\a\\b.h", "D:\\a\\c.h"]) == "D:\\a");
assert(findBasePath(["D:\\a\\b.h", "E:\\b.h"]) == ".");
assert(findBasePath(["D:\\B\\a.h", "D:\\b\\c\\D.h", "D:\\B\\c.h"]) == "D:\\B");
assert(findBasePath(["D:/a\\b/d.h", "D:\\a/B\\c.h"]) == "D:\\a\\b");
assert(findBasePath(["C:\\a.h", "D:\\b.h"]) == ".");
}
}
39 changes: 39 additions & 0 deletions tests/functional/Tests.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import tests.support.Assertions;
import std.algorithm : canFind;
import std.process : executeShell;
import std.typecons;
import std.path : absolutePath;

void printClangVersion()
{
Expand Down Expand Up @@ -294,6 +295,44 @@ unittest
assertIssuesWarning("tests/functional/collision.h");
}

// DStep should output to correct directory when using absolute paths.
unittest
{
assertRunsDStepCFiles([
TestFile("tests/functional/graph/subfile1.d", absolutePath("tests/functional/graph/subfile1.h")),
TestFile("tests/functional/include/subfile3.d", absolutePath("tests/functional/include/subfile3.h"))]
);
}

unittest
{
assertRunsDStepCFile(
"tests/functional/functions.d",
absolutePath("tests/functional/functions.h")
);
}

// Output in same directory when single file given and no output specified
unittest
{
assertRunsDStepCFiles(
[TestFile("tests/functional/functions.d", absolutePath("tests/functional/functions.h"))],
["--unspecified-output"],
false);
}

// Output in same directory when using multiple files with no output folder specified
unittest
{
assertRunsDStepCFiles(
[TestFile("tests/functional/aggregate.d", "tests/functional/aggregate.h"),
TestFile("tests/functional/functions.d", "tests/functional/functions.h"),
TestFile("tests/functional/graph/subfile1.d", absolutePath("tests/functional/graph/subfile1.h")),
TestFile("tests/functional/include/subfile3.d", absolutePath("tests/functional/include/subfile3.h"))],
["--unspecified-output"]
);
}

version (OSX):

// Objective-C tests
Expand Down
3 changes: 3 additions & 0 deletions tests/functional/graph/subfile1.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extern (C):

extern __gshared int content;
3 changes: 3 additions & 0 deletions tests/functional/include/subfile3.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extern (C):

void core (int);
60 changes: 41 additions & 19 deletions tests/support/DStepRunner.d
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ auto testRunDStep(
{
import core.exception : AssertError;

import std.algorithm : canFind, map;
import std.file : exists, isFile, readText, rmdirRecurse;
import std.path : buildPath;
import std.algorithm : canFind, map, remove;
import std.file : exists, isFile, readText, mkdirRecurse, rmdirRecurse, copy, getcwd;
import std.path : buildPath, isAbsolute, relativePath, dirName;
import std.range : join;
import std.array : empty;
import std.array : empty, array;

import dstep.driver.Util : makeDefaultOutputFile;
import dstep.driver.Util : makeDefaultOutputFile, findBasePath;

version (OptionalGNUStep)
{
Expand All @@ -48,31 +48,53 @@ auto testRunDStep(
string outputDir = namedTempDir("dstepUnitTest");
scope(exit) rmdirRecurse(outputDir);

auto argumentsLength = arguments.length;
arguments = arguments.remove!(x => x == "--unspecified-output");
bool unspecifiedOutput = arguments.length < argumentsLength;

string[] outputPaths;
string workDir = getcwd();

if (sourcePaths.length == 1)
{
outputPaths ~= buildPath(outputDir,
makeDefaultOutputFile(sourcePaths[0], false));
}
else
auto sourceBasePath = findBasePath(sourcePaths);
foreach (ref sourcePath; sourcePaths)
{
foreach (sourcePath; sourcePaths)
outputPaths ~= buildPath(outputDir,
makeDefaultOutputFile(sourcePath, false));
string path = sourcePath;
if (isAbsolute(sourcePath))
{
path = relativePath(sourcePath, unspecifiedOutput ? workDir : sourceBasePath);
}
if (unspecifiedOutput)
{
auto updatedSourcePath = buildPath(outputDir, path);
mkdirRecurse(dirName(updatedSourcePath));
copy(sourcePath, updatedSourcePath);
if (isAbsolute(sourcePath))
{
sourcePath = updatedSourcePath;
}
}
outputPaths ~= buildPath(outputDir, makeDefaultOutputFile(path, false));
}

auto localCommand = ["./bin/dstep"] ~ sourcePaths ~ arguments;
auto dstepPath = buildPath(workDir, "bin", "dstep");
auto localCommand = [dstepPath] ~ sourcePaths ~ arguments;

if (outputPaths.length == 1)
localCommand ~= ["-o", outputPaths[0]];
if (unspecifiedOutput)
{
workDir = outputDir;
}
else
localCommand ~= ["-o", outputDir];
{
if (outputPaths.length == 1)
localCommand ~= ["-o", outputPaths[0]];
else
localCommand ~= ["-o", outputDir];
}

if (command)
*command = join(localCommand, " ");

auto result = execute(localCommand);
auto result = execute(localCommand, workDir: workDir);

if (outputContents)
outputContents.length = outputPaths.length;
Expand Down