816 changes: 629 additions & 187 deletions DustMite/dustmite.d

Large diffs are not rendered by default.

210 changes: 200 additions & 10 deletions DustMite/splitter.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import std.path;
import std.range;
import std.string;
import std.traits;
debug import std.stdio;
import std.stdio : stderr;

/// Represents a slice of the original code.
class Entity
Expand Down Expand Up @@ -44,18 +44,19 @@ class Entity
this.tail = tail;
}

string[] comments;

@property string comment()
{
string[] result = comments;
if (isPair)
{
assert(token == DSplitter.Token.none);
return "Pair";
result ~= "Pair";
}
else
if (token)
return DSplitter.tokenText[token];
else
return null;
if (token && DSplitter.tokenText[token])
result ~= DSplitter.tokenText[token];
return result.length ? result.join(" / ") : null;
}

override string toString()
Expand Down Expand Up @@ -161,6 +162,7 @@ private:
/// Override std.string nonsense, which does UTF-8 decoding
bool startsWith(in char[] big, in char[] small) { return big.length >= small.length && big[0..small.length] == small; }
bool startsWith(in char[] big, char c) { return big.length && big[0] == c; }
string strip(string s) { while (s.length && isWhite(s[0])) s = s[1..$]; while (s.length && isWhite(s[$-1])) s = s[0..$-1]; return s; }

immutable ParseRule[] defaultRules =
[
Expand All @@ -171,7 +173,7 @@ immutable ParseRule[] defaultRules =

Entity loadFile(string name, string path, ParseOptions options)
{
debug writeln("Loading ", path);
stderr.writeln("Loading ", path);
auto result = new Entity();
result.filename = name.replace(`\`, `/`);
result.contents = cast(string)read(path);
Expand Down Expand Up @@ -811,6 +813,20 @@ struct DSplitter
}
}

static void postProcessTemplates(ref Entity[] entities)
{
if (!entities.length)
return;
foreach_reverse (i, e; entities[0..$-1])
if (e.token == tokenLookup["!"] && entities[i+1].children.length && entities[i+1].children[0].token == tokenLookup["("])
{
auto dependency = new Entity;
e.dependencies ~= dependency;
entities[i+1].children[0].dependencies ~= dependency;
entities = entities[0..i+1] ~ dependency ~ entities[i+1..$];
}
}

static void postProcessDependencyBlock(ref Entity[] entities)
{
foreach (i, e; entities)
Expand Down Expand Up @@ -941,13 +957,60 @@ struct DSplitter
postProcessParens(e.children);
}

static void postProcess(ref Entity[] entities)
static bool isValidIdentifier(string s)
{
if (!s.length)
return false;
if (!isAlpha(s[0]))
return false;
foreach (c; s[1..$])
if (!isAlphaNum(c))
return false;
return true;
}

/// Get all nodes between (exclusively) two addresses.
/// If either address is empty, then the respective bound is the respective extreme.
static Entity[] nodesBetween(Entity root, size_t[] a, size_t[] b)
{
while (a.length && b.length && a[0] == b[0])
{
root = root.children[a[0]];
a = a[1..$];
b = b[1..$];
}
size_t index0, index1;
Entity[] children0, children1;
if (a.length)
{
index0 = a[0] + 1;
if (a.length > 1)
children0 = nodesBetween(root.children[a[0]], a[1..$], null);
}
else
index0 = 0;

if (b.length)
{
index1 = b[0];
if (b.length > 1)
children1 = nodesBetween(root.children[b[0]], null, b[1..$]);
}
else
index1 = root.children.length;

assert(index0 <= index1);
return children0 ~ root.children[index0 .. index1] ~ children1;
}

static void postProcessRecursive(ref Entity[] entities)
{
foreach (e; entities)
if (e.children.length)
postProcess(e.children);
postProcessRecursive(e.children);

postProcessSimplify(entities);
postProcessTemplates(entities);
postProcessDependency(entities);
postProcessBlockKeywords(entities);
postProcessDependencyBlock(entities);
Expand All @@ -956,6 +1019,133 @@ struct DSplitter
postProcessParens(entities);
}

/// Attempt to link together function arguments / parameters for
/// things that look like calls to the same function, to allow removing
/// unused function arguments / parameters.
static void postProcessArgs(ref Entity[] entities)
{
string lastID;

Entity[][][string] calls;

void visit(Entity entity)
{
auto id = entity.head.strip();
if (entity.token == Token.other && isValidIdentifier(id) && !entity.tail && !entity.children)
lastID = id;
else
if (lastID && entity.token == tokenLookup["("])
{
size_t[] stack;
struct Comma { size_t[] addr, after; }
Comma[] commas;

bool afterComma;

// Find all top-level commas
void visit2(size_t i, Entity entity)
{
stack ~= i;
if (afterComma)
{
commas[$-1].after = stack;
//entity.comments ~= "After-comma %d".format(commas.length);
afterComma = false;
}

if (entity.token == tokenLookup[","])
{
commas ~= Comma(stack);
//entity.comments ~= "Comma %d".format(commas.length);
afterComma = true;
}
else
if (entity.head.length || entity.tail.length)
{}
else
foreach (j, child; entity.children)
visit2(j, child);
stack = stack[0..$-1];
}

foreach (i, child; entity.children)
visit2(i, child);

// Find all nodes between commas, effectively obtaining the arguments
size_t[] last = null;
commas ~= [Comma()];
Entity[][] args;
foreach (i, comma; commas)
{
//Entity entityAt(Entity root, size_t[] address) { return address.length ? entityAt(root.children[address[0]], address[1..$]) : root; }
//entityAt(entity, last).comments ~= "nodesBetween-left %d".format(i);
//entityAt(entity, comma.after).comments ~= "nodesBetween-right %d".format(i);
args ~= nodesBetween(entity, last, comma.after);
last = comma.addr;
}

// Register the arguments
foreach (i, arg; args)
{
debug
foreach (j, e; arg)
e.comments ~= "%s arg %d node %d".format(lastID, i, j);

if (arg.length == 1)
{
if (lastID !in calls)
calls[lastID] = null;
while (calls[lastID].length < i+1)
calls[lastID] ~= null;
calls[lastID][i] ~= arg[0];
}
}

lastID = null;
return;
}
else
if (entity.token == tokenLookup["!"])
{}
else
if (entity.head || entity.tail)
lastID = null;

foreach (child; entity.children)
visit(child);
}

foreach (entity; entities)
visit(entity);

// For each parameter, create a dummy empty node which is a dependency for all of the arguments.
auto callRoot = new Entity();
debug callRoot.comments ~= "Args root";
entities ~= callRoot;

foreach (id, params; calls)
{
auto funRoot = new Entity();
debug funRoot.comments ~= "%s root".format(id);
callRoot.children ~= funRoot;

foreach (i, args; params)
{
auto e = new Entity();
debug e.comments ~= "%s param %d".format(id, i);
funRoot.children ~= e;
foreach (arg; args)
arg.dependencies ~= e;
}
}
}

static void postProcess(ref Entity[] entities)
{
postProcessRecursive(entities);
postProcessArgs(entities);
}

static Entity* firstHead(ref Entity e)
{
if (e.head.length)
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
D tools
=======

[![GitHub tag](https://img.shields.io/github/tag/dlang/tools.svg?maxAge=86400)](#)
[![Build Status](https://travis-ci.org/dlang/tools.svg?branch=master)](https://travis-ci.org/dlang/tools)
[![Issue Stats](https://img.shields.io/issuestats/p/github/dlang/tools.svg?maxAge=2592000)](http://www.issuestats.com/github/dlang/tools)

This repository hosts various tools redistributed with DMD or used
internally during various build tasks.

Expand Down
4 changes: 1 addition & 3 deletions changed.d
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env rdmd
// Written in the D programming language

/**
Expand Down Expand Up @@ -168,15 +169,12 @@ string getChangeLog(string revRange)
if (auto bugs = bugtype in *comp)
{
result ~= format("$(BUGSTITLE %s %s,\n\n", component, bugtype);

result ~= "$(P\n";
foreach (bug; sort!"a.id < b.id"(*bugs))
{
result ~= format("$(LI $(BUGZILLA %s): %s)\n",
bug.id, bug.summary.escapeParens());
}
result ~= ")\n";
result ~= ")\n";
}
}

Expand Down
42 changes: 39 additions & 3 deletions ddemangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import std.algorithm : equal, map;
import std.getopt;
import std.regex;
import std.stdio;
import std.c.stdlib;
import core.stdc.stdlib;

void showhelp(string[] args)
{
Expand All @@ -30,12 +30,37 @@ ENDHELP", args[0]);
exit(1);
}

auto reDemangle = regex(r"\b(_D[0-9a-zA-Z_]+)\b");
auto reDemangle = regex(r"\b_?_D[0-9a-zA-Z_]+\b");

const(char)[] demangleMatch(T)(Captures!(T) m)
if (is(T : const(char)[]))
{
/+ If the second character is an underscore, it may be a D symbol with double leading underscore;
+ in that case, try to demangle it with only one leading underscore.
+/
if (m.hit[1] != '_')
{
return demangle(m.hit);
}
else
{
auto result = demangle(m.hit[1..$]);
if (result == m.hit[1..$])
{
// Demangling failed, return original match with (!) double underscore
return m.hit;
}
else
{
return result;
}
}
}

auto ddemangle(T)(T line)
if (is(T : const(char)[]))
{
return replaceAll!(a => demangle(a.hit))(line, reDemangle);
return replaceAll!(demangleMatch)(line, reDemangle);
}

unittest
Expand All @@ -44,11 +69,19 @@ unittest
"_D2rt4util7console8__assertFiZv",
"random initial junk _D2rt4util7console8__assertFiZv random trailer",
"multiple _D2rt4util7console8__assertFiZv occurrences _D2rt4util7console8__assertFiZv",
"_D6object9Throwable8toStringMFZAya",
"__D6object9Throwable8toStringMFZAya",
"don't match 3 leading underscores ___D6object9Throwable8toStringMFZAya",
"fail demangling __D6object9Throwable8toStringMFZAy"
];
string[] expected = [
"void rt.util.console.__assert(int)",
"random initial junk void rt.util.console.__assert(int) random trailer",
"multiple void rt.util.console.__assert(int) occurrences void rt.util.console.__assert(int)",
"immutable(char)[] object.Throwable.toString()",
"immutable(char)[] object.Throwable.toString()",
"don't match 3 leading underscores ___D6object9Throwable8toStringMFZAya",
"fail demangling __D6object9Throwable8toStringMFZAy"
];

assert(equal(testData.map!ddemangle(), expected));
Expand Down Expand Up @@ -76,7 +109,10 @@ void main(string[] args)
{
auto f = (args.length==2) ? File(args[1], "r") : stdin;
foreach (line; f.byLine())
{
writeln(ddemangle(line));
stdout.flush;
}
}
catch(Exception e)
{
Expand Down
2 changes: 1 addition & 1 deletion dget.d
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int main(string[] args)
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

/// default github users for repo lookup
immutable defaultUsers = ["D-Programming-Deimos", "D-Programming-Language"];
immutable defaultUsers = ["D-Programming-Deimos", "dlang"];

auto resolveRepo(string arg)
{
Expand Down
2 changes: 1 addition & 1 deletion latest-tag
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

set -o errexit
cd $(dirname $0)/../dmd
git fetch --tags git@github.com:D-Programming-Language/dmd
git fetch --tags git@github.com:dlang/dmd
git tag | grep '^v[0-9]\.[0-9]*$' | sed 's/^v//' | sort -nr | head -n 1
3 changes: 3 additions & 0 deletions man/man1/rdmd.1
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ Evaluate code as in perl -e (multiple --eval allowed)
.IP --exclude=\fIpackage\fR
Exclude a package from the build (multiple --exclude allowed)

.IP --include=\fIpackage\fR
Negate an --exclude switch or a package excluded by default

.IP --extra-file=\fIfile\fR
Include an extra source or object in the compilation. Useful
if you need to add an extra object (compiled by another
Expand Down
164 changes: 94 additions & 70 deletions rdmd.d
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ else

private bool chatty, buildOnly, dryRun, force, preserveOutputPaths;
private string exe, userTempDir;
private string[] exclusions = ["std", "etc", "core"]; // packages that are to be excluded
immutable string[] defaultExclusions = ["std", "etc", "core"];
private string[] exclusions = defaultExclusions; // packages that are to be excluded
private string[] extraFiles = [];

version (DigitalMars)
Expand All @@ -53,6 +54,7 @@ else

private string compiler = defaultCompiler;

version(unittest) {} else
int main(string[] args)
{
//writeln("Invoked with: ", args);
Expand Down Expand Up @@ -113,6 +115,14 @@ int main(string[] args)
assert(programPos > 0);
auto argsBeforeProgram = args[0 .. programPos];

/* Catch -main and handle it like --main. This needs to be done, because
rdmd compiles the root file independently from the dependencies, but -main
must be present in only one of the calls to dmd. */
foreach (ref arg; argsBeforeProgram)
{
if (arg == "-main") arg = "--main";
}

bool bailout; // bailout set by functions called in getopt if
// program should exit
string[] loop; // set by --loop
Expand All @@ -130,6 +140,7 @@ int main(string[] args)
"eval", &eval,
"loop", &loop,
"exclude", &exclusions,
"include", (string opt, string p) { exclusions = exclusions.filter!(ex => ex != p).array(); },
"extra-file", &extraFiles,
"force", &force,
"help", { writeln(helpString); bailout = true; },
Expand All @@ -147,7 +158,7 @@ int main(string[] args)
* std.path.buildNormalizedPath(), but some corner cases will break, so it
* has been decided to only allow -of for now.
* To see the full discussion please refer to:
* https://github.com/D-Programming-Language/tools/pull/122
* https://github.com/dlang/tools/pull/122
*/
if ((makeDepend || makeDepFile.ptr) && (!exe.ptr || exe.endsWith(dirSeparator)))
{
Expand Down Expand Up @@ -233,7 +244,8 @@ int main(string[] args)
}

// Fetch dependencies
const myDeps = getDependencies(root, workDir, objDir, compilerFlags);
const myDeps = compileRootAndGetDeps(root, workDir, objDir, compilerFlags,
addStubMain);

// --makedepend mode. Just print dependencies and exit.
if (makeDepend)
Expand Down Expand Up @@ -288,10 +300,10 @@ int main(string[] args)
}

// Have at it
if (chain(root.only, myDeps.byKey).array.anyNewerThan(lastBuildTime))
if (chain(root.only, myDeps.byKey).anyNewerThan(lastBuildTime))
{
immutable result = rebuild(root, exe, workDir, objDir,
myDeps, compilerFlags, addStubMain);
myDeps, compilerFlags);
if (result)
return result;

Expand Down Expand Up @@ -436,13 +448,13 @@ private void unlockWorkPath()
}
}

// Rebuild the executable fullExe starting from modules in myDeps
// Rebuild the executable fullExe from root and myDeps,
// passing the compiler flags compilerFlags. Generates one large
// object file.
// object file for the dependencies.

private int rebuild(string root, string fullExe,
string workDir, string objDir, in string[string] myDeps,
string[] compilerFlags, bool addStubMain)
string[] compilerFlags)
{
version (Windows)
fullExe = fullExe.defaultExtension(".exe");
Expand All @@ -469,46 +481,59 @@ private int rebuild(string root, string fullExe,
}
}

auto fullExeTemp = fullExe ~ ".tmp";
immutable fullExeTemp = fullExe ~ ".tmp";
immutable rootObj = buildPath(objDir, root.baseName(".d") ~ objExt);
immutable depsObj = buildPath(objDir,
root.baseName(".d") ~ ".deps" ~ objExt);

assert(dryRun || std.file.exists(rootObj),
"should have been created by compileRootAndGetDeps");

string[] buildTodo()
int result = 0;
string[] objs = [ rootObj ];

// compile dependencies
if (myDeps.byValue.any!(o => o !is null))
// if there is any source dependency at all
{
auto todo = compilerFlags
~ [ "-of"~fullExeTemp ]
~ [ "-od"~objDir ]
~ [ "-I"~dirName(root) ]
~ [ root ];
auto todo = compilerFlags ~ [
"-c",
"-of" ~ depsObj,
"-I" ~ dirName(root),
];
foreach (k, objectFile; myDeps) {
if(objectFile !is null)
todo ~= [ k ];
}
// Need to add void main(){}?
if (addStubMain)

// Different shells and OS functions have different limits,
// but 1024 seems to be the smallest maximum outside of MS-DOS.
enum maxLength = 1024;
auto commandLength = escapeShellCommand(todo).length;
if (commandLength + compiler.length >= maxLength)
{
auto stubMain = buildPath(myOwnTmpDir, "stubmain.d");
std.file.write(stubMain, "void main(){}");
todo ~= [ stubMain ];
auto rspName = buildPath(workDir, "rdmd.rsp");

// DMD uses Windows-style command-line parsing in response files
// regardless of the operating system it's running on.
std.file.write(rspName,
array(map!escapeWindowsArgument(todo)).join(" "));

todo = [ "@" ~ rspName ];
}
return todo;

result = run([ compiler ] ~ todo);
objs ~= depsObj;
}
auto todo = buildTodo();

// Different shells and OS functions have different limits,
// but 1024 seems to be the smallest maximum outside of MS-DOS.
enum maxLength = 1024;
auto commandLength = escapeShellCommand(todo).length;
if (commandLength + compiler.length >= maxLength)
// link
if (!result)
{
auto rspName = buildPath(workDir, "rdmd.rsp");

// DMD uses Windows-style command-line parsing in response files
// regardless of the operating system it's running on.
std.file.write(rspName, array(map!escapeWindowsArgument(todo)).join(" "));

todo = [ "@"~rspName ];
string[] cmd = [ compiler ] ~ compilerFlags ~
[ "-of" ~ fullExeTemp, "-od" ~ objDir ] ~ objs;
result = run(cmd);
}

immutable result = run([ compiler ] ~ todo);
if (result)
{
// build failed
Expand Down Expand Up @@ -570,13 +595,13 @@ private int exec(string[] args)
return run(args, null, true);
}

// Given module rootModule, returns a mapping of all dependees .d
// source filenames to their corresponding .o files sitting in
// Given module rootModule, compiles it to rdmd.root.o and returns a mapping of
// all dependees .d source filenames to their corresponding .o files sitting in
// directory workDir. The mapping is obtained by running dmd -v against
// rootModule.

private string[string] getDependencies(string rootModule, string workDir,
string objDir, string[] compilerFlags)
private string[string] compileRootAndGetDeps(string rootModule, string workDir,
string objDir, string[] compilerFlags, bool addStubMain)
{
immutable depsFilename = buildPath(workDir, "rdmd.deps");

Expand Down Expand Up @@ -616,7 +641,7 @@ private string[string] getDependencies(string rootModule, string workDir,
scope(exit) collectException(depsReader.close()); // don't care for errors

// Fetch all dependencies and append them to myDeps
auto pattern = regex(r"^(import|file|binary|config|library)\s+([^\(]+)\(?([^\)]*)\)?\s*$");
auto pattern = ctRegex!(r"^(import|file|binary|config|library)\s+([^\(]+)\(?([^\)]*)\)?\s*$");
string[string] result;
foreach (string line; lines(depsReader))
{
Expand Down Expand Up @@ -679,7 +704,7 @@ private string[string] getDependencies(string rootModule, string workDir,
{
// See if the deps file is still in good shape
auto deps = readDepsFile();
auto allDeps = chain(rootModule.only, deps.byKey).array;
auto allDeps = chain(rootModule.only, deps.byKey);
bool mustRebuildDeps = allDeps.anyNewerThan(depsT);
if (!mustRebuildDeps)
{
Expand All @@ -693,10 +718,23 @@ private string[string] getDependencies(string rootModule, string workDir,
immutable rootDir = dirName(rootModule);

// Collect dependencies
auto depsGetter =
// "cd "~shellQuote(rootDir)~" && "
[ compiler ] ~ compilerFlags ~
["-v", "-o-", rootModule, "-I"~rootDir];
auto depsGetter = [ compiler ] ~ compilerFlags ~ [
"-v",
"-c",
"-of" ~ buildPath(objDir, rootModule.baseName(".d") ~ objExt),
rootModule,
"-I" ~ rootDir
];

// Need to add void main(){}?
if (addStubMain)
{
/* TODO: Can be simplified to `depsGetter ~= "-main";` when issue 16440
is fixed. */
auto stubMain = buildPath(myOwnTmpDir, "stubmain.d");
std.file.write(stubMain, "void main(){}");
depsGetter ~= [ stubMain ];
}

scope(failure)
{
Expand All @@ -717,40 +755,25 @@ private string[string] getDependencies(string rootModule, string workDir,
}

// Is any file newer than the given file?
bool anyNewerThan(in string[] files, in string file)
bool anyNewerThan(T)(T files, in string file)
{
yap("stat ", file);
return files.anyNewerThan(file.timeLastModified);
}

// Is any file newer than the given file?
bool anyNewerThan(in string[] files, SysTime t)
bool anyNewerThan(T)(T files, SysTime t)
{
// Experimental: running newerThan in separate threads, one per file
if (false)
{
foreach (source; files)
{
if (source.newerThan(t))
{
return true;
}
}
return false;
}
else
bool result;
foreach (source; taskPool.parallel(files))
{
bool result;
foreach (source; taskPool.parallel(files))
yap("stat ", source);
if (!result && source.newerThan(t))
{
yap("stat ", source);
if (!result && source.newerThan(t))
{
result = true;
}
result = true;
}
return result;
}
return result;
}

/*
Expand Down Expand Up @@ -797,6 +820,7 @@ addition to compiler options, rdmd recognizes the following options:
(implies --chatty)
--eval=code evaluate code as in perl -e (multiple --eval allowed)
--exclude=package exclude a package from the build (multiple --exclude allowed)
--include=package negate --exclude or a standard package (%-(%s, %))
--extra-file=file include an extra source or object in the compilation
(multiple --extra-file allowed)
--force force a rebuild even if apparently not necessary
Expand All @@ -809,7 +833,7 @@ addition to compiler options, rdmd recognizes the following options:
(needs dmd's option `-of` to be present)
--man open web browser on manual page
--shebang rdmd is in a shebang line (put as first argument)
".format(defaultCompiler);
".format(defaultCompiler, defaultExclusions);
}

// For --eval
Expand All @@ -826,7 +850,7 @@ import std.stdio, std.algorithm, std.array, std.ascii, std.base64,
std.numeric, std.outbuffer, std.parallelism, std.path, std.process,
std.random, std.range, std.regex, std.signals, std.socket,
std.socketstream, std.stdint, std.stdio, std.stdiobase, std.stream,
std.string, std.syserror, std.system, std.traits, std.typecons,
std.string, std.windows.syserror, std.system, std.traits, std.typecons,
std.typetuple, std.uni, std.uri, std.utf, std.variant, std.xml, std.zip,
std.zlib;
";
Expand Down
17 changes: 17 additions & 0 deletions rdmd_test.d
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,23 @@ void runTests()
res = execute([rdmdApp, compilerSwitch, "--force", "--exclude=dsubpack", subModObj, subModUser]);
assert(res.status == 0, res.output); // building with the dependency succeeds

/* Test --include. */
auto packFolder2 = tempDir().buildPath("std");
if (packFolder2.exists) packFolder2.rmdirRecurse();
packFolder2.mkdirRecurse();
scope (exit) packFolder2.rmdirRecurse();

string subModSrc2 = packFolder2.buildPath("foo.d");
std.file.write(subModSrc2, "module std.foo; void foobar() { }");

std.file.write(subModUser, "import std.foo; void main() { foobar(); }");

res = execute([rdmdApp, compilerSwitch, "--force", subModUser]);
assert(res.status == 1, res.output); // building without the --include fails

res = execute([rdmdApp, compilerSwitch, "--force", "--include=std", subModUser]);
assert(res.status == 0, res.output); // building with the --include succeeds

/* Test --extra-file. */

string extraFileDi = tempDir().buildPath("extraFile_.di");
Expand Down
44 changes: 44 additions & 0 deletions travis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash

set -uexo pipefail

DIGGER_DIR="../digger"
DIGGER="../digger/digger"

# set to 64-bit by default
if [ -z ${MODEL:-} ] ; then
MODEL=64
fi

test_rdmd() {
# run rdmd internal tests
rdmd -m$MODEL -main -unittest rdmd.d

# compile rdmd & testsuite
dmd -m$MODEL rdmd.d
dmd -m$MODEL rdmd_test.d

# run rdmd testsuite
./rdmd_test
}

build_digger() {
git clone --recursive https://github.com/CyberShadow/Digger "$DIGGER_DIR"
dub --root="$DIGGER_DIR" build
}

install_digger() {
$DIGGER build --model=$MODEL "master"
export PATH=$PWD/result/bin:$PATH
}

if ! [ -d "$DIGGER_DIR" ] ; then
build_digger
fi

install_digger

dmd --version
rdmd --help | head -n 1

test_rdmd
4 changes: 2 additions & 2 deletions update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function installAnew() {
for project in $projects; do
(
cd $wd &&
git clone --quiet git://github.com/D-Programming-Language/$project.git &&
git clone --quiet git://github.com/dlang/$project.git &&
touch $tempdir/$project
) &
done
Expand Down Expand Up @@ -141,7 +141,7 @@ function update() {

function update_project() {
local project=$1
local gitproject="git://github.com/D-Programming-Language/$project.git"
local gitproject="git://github.com/dlang/$project.git"
if ! ( cd "$wd/$project" && \
git checkout master && \
git pull --ff-only $gitproject master && \
Expand Down