diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3af4100..cac0e71 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,7 +30,7 @@ # Latest stable version, update at will os: [ macOS-11, ubuntu-20.04, windows-2019 ] dc: - #- dmd-latest + - dmd-latest - dmd-2.100.2 - ldc-latest - dmd-master diff --git a/README.md b/README.md index f1badb6..87257f8 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,10 @@ Mathias (@Geod24) Lang maintains the Alpine Linux packages. It is currently part of 'edge' and can be installed through `apk --no-cache add -X http://dl-cdn.alpinelinux.org/alpine/edge/testing dub`. +## OpenBSD + +Brian Callahan (bcallah@) maintains the OpenBSD package. Use `pkg_add dub` to install it. + ## Using DUB as a library The [DUB package of DUB](http://code.dlang.org/packages/dub) can be used as a library to load or manipulate packages, or to resemble any functionality of the command line tool. The former task can be achieved by using the [Package class](https://github.com/dlang/dub/blob/master/source/dub/package_.d#L40). For examples on how to replicate the command line functionality, see [commandline.d](https://github.com/dlang/dub/blob/master/source/dub/commandline.d). diff --git a/changelog/colors.dd b/changelog/colors.dd new file mode 100644 index 0000000..c66839f --- /dev/null +++ b/changelog/colors.dd @@ -0,0 +1,6 @@ +The `--color` argument now accepts values `auto`, `never`, `always` + +The previous `automatic`, `on`, `off` values are still supported, but +undocumented, because they are used in almost no other program like this. For +consistency, with other Linux tools especially, we have implemented and switched +the defaults to the widely-used `auto`, `never`, `always` values. diff --git a/scripts/man/.gitignore b/scripts/man/.gitignore index 2c2a370..a893283 100644 --- a/scripts/man/.gitignore +++ b/scripts/man/.gitignore @@ -1,2 +1,3 @@ *.1 +*.md /gen_man diff --git a/scripts/man/gen_man.d b/scripts/man/gen_man.d index aff9118..3d4a127 100755 --- a/scripts/man/gen_man.d +++ b/scripts/man/gen_man.d @@ -3,30 +3,12 @@ dependency "dub" path="../.." +/ -import std.algorithm, std.conv, std.format, std.path, std.range, std.stdio; +import std.algorithm, std.conv, std.format, std.path, std.range; +import std.stdio : File; +import dub.internal.dyaml.stdsumtype; import dub.commandline; -string italic(string w) -{ - return `\fI` ~ w ~ `\fR`; -} - -string bold(string w) -{ - return `\fB` ~ w ~ `\fR`; -} - -string header(string heading) -{ - return ".SH " ~ heading; -} - -string br(string s) -{ - return ".BR " ~ s; -} - -struct Config +static struct Config { import std.datetime; SysTime date; @@ -46,165 +28,443 @@ string cwd; } -void writeHeader(ref File manFile, string manName, const Config config) +struct ManWriter { - static immutable manHeader = + enum Mode + { + man, markdown + } + + File output; + Mode mode; + + string escapeWord(string s) + { + final switch (mode) { + case Mode.man: return s.replace(`\`, `\\`).replace(`-`, `\-`).replace(`.`, `\&.`); + case Mode.markdown: return s.replace(`<`, `<`).replace(`>`, `>`); + } + } + + string escapeFulltext(string s) + { + final switch (mode) { + case Mode.man: return s; + case Mode.markdown: return s.replace(`<`, `<`).replace(`>`, `>`); + } + } + + string italic(string w) + { + final switch (mode) { + case Mode.man: return `\fI` ~ w ~ `\fR`; + case Mode.markdown: return `` ~ w ~ ``; + } + } + + string bold(string w) + { + final switch (mode) { + case Mode.man: return `\fB` ~ w ~ `\fR`; + case Mode.markdown: return `` ~ w ~ ``; + } + } + + string header(string heading) + { + final switch (mode) { + case Mode.man: return ".SH " ~ heading; + case Mode.markdown: return "## " ~ heading; + } + } + + string subheader(string heading) + { + final switch (mode) { + case Mode.man: return ".SS " ~ heading; + case Mode.markdown: return "### " ~ heading; + } + } + + string url(string urlAndText) + { + return url(urlAndText, urlAndText); + } + + string url(string url, string text) + { + final switch (mode) { + case Mode.man: return ".UR" ~ url ~ "\n" ~ text ~ "\n.UE"; + case Mode.markdown: return format!"[%s](%s)"(text, url); + } + } + + string autolink(string s) + { + final switch (mode) { + case Mode.man: return s; + case Mode.markdown: + auto sanitized = s + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("*", ""); + if (sanitized.startsWith("dub") && sanitized.endsWith("(1)")) { + sanitized = sanitized[0 .. $ - 3]; + return url(sanitized ~ ".md", s); + } + return s; + } + } + + /// Links subcommands in the main dub.md file (converts the subcommand name + /// like `init` into a link to `dub-init.md`) + string specialLinkMainCmd(string s) + { + final switch (mode) { + case Mode.man: return s; + case Mode.markdown: return url("dub-" ~ s ~ ".md", s); + } + } + + void write(T...)(T args) + { + output.write(args); + } + + void writeln(T...)(T args) + { + output.writeln(args); + } + + void writefln(T...)(T args) + { + output.writefln(args); + } + + void writeHeader(string manName, const Config config) + { + import std.uni : toLower; + + final switch (mode) + { + case Mode.man: + static immutable manHeader = `.TH %s 1 "%s" "The D Language Foundation" "The D Language Foundation" .SH NAME`; - manFile.writefln(manHeader, manName, config.date.toISOExtString.take(10)); -} + writefln(manHeader, manName, config.date.toISOExtString.take(10)); + break; + case Mode.markdown: + writefln("# %s(1)", manName.toLower); + break; + } + } -void writeFooter(ref File manFile, string seeAlso, const Config config) -{ - static immutable manFooter = -`.SH FILES -\fIdub\&.sdl\fR, \fIdub\&.json\fR -.SH AUTHOR -Copyright (c) 1999-%s by The D Language Foundation -.SH "ONLINE DOCUMENTATION" -.UR http://code.dlang.org/docs/commandline -http://code.dlang.org/docs/commandline -.UE -.SH "SEE ALSO" -%s`; - manFile.writefln(manFooter, config.date.year, seeAlso); + void writeFooter(string seeAlso, const Config config) + { + const manFooter = + header("FILES") ~ '\n' + ~ italic(escapeWord("dub.sdl")) ~ ", " ~ italic(escapeWord("dub.json")) ~ '\n' + ~ header("AUTHOR") ~ '\n' + ~ `Copyright (c) 1999-%s by The D Language Foundation` ~ '\n' + ~ header("ONLINE DOCUMENTATION") ~ '\n' + ~ url(`http://code.dlang.org/docs/commandline`) ~ '\n' + ~ header("SEE ALSO"); + writefln(manFooter, config.date.year); + writeln(seeAlso); + } + + string highlightArguments(string args) + { + import std.regex : regex, replaceAll; + static auto re = regex("<([^>]*)>"); + const reReplacement = escapeWord("<%s>").format(italic(escapeWord(`$1`))); + auto ret = args.replaceAll(re, reReplacement); + if (ret.length) ret ~= ' '; + return ret; + } + + void beginArgs(string cmd) + { + if (mode == Mode.markdown) + writeln("\n
\n"); + } + + void endArgs() + { + if (mode == Mode.markdown) + writeln("\n
\n"); + } + + void writeArgName(string cmd, string name) + { + import std.regex : regex, replaceAll; + final switch ( mode ) + { + case Mode.man: + writeln(".PP"); + writeln(name); + break; + case Mode.markdown: + string nameEscape = name.replaceAll(regex("[^a-zA-Z0-9_-]+"), "-"); + writeln(); + writefln(`
`, cmd, nameEscape); + writefln(``, cmd, nameEscape); + writeln(); + writeln(name); + writeln(); + writeln(`
`); + writeln(); + break; + } + } + + void beginArgDescription() + { + final switch ( mode ) + { + case Mode.man: + writeln(".RS 4"); + break; + case Mode.markdown: + writeln(); + writefln(`
`); + writeln(); + break; + } + } + + void endArgDescription() + { + final switch ( mode ) + { + case Mode.man: + writeln(".RE"); + break; + case Mode.markdown: + writeln(); + writefln(`
`); + writeln(); + break; + } + } + + void writeArgs(string cmdName, CommandArgs args) + { + beginArgs(cmdName); + foreach (arg; args.recognizedArgs) + { + auto names = arg.names.split("|"); + assert(names.length == 1 || names.length == 2); + string sarg = names[0].length == 1 ? names[0] : null; + string larg = names[0].length > 1 ? names[0] : names.length > 1 ? names[1] : null; + string name; + if (sarg !is null) { + name ~= bold(escapeWord("-%s".format(sarg))); + if (larg !is null) + name ~= ", "; + } + if (larg !is null) { + name ~= bold(escapeWord("--%s".format(larg))); + if (arg.defaultValue.match!((bool b) => false, _ => true)) + name ~= escapeWord("=") ~ italic("VALUE"); + } + writeArgName(cmdName, name); + beginArgDescription(); + writeln(arg.helpText.join(mode == Mode.man ? "\n" : "\n\n")); + endArgDescription(); + } + endArgs(); + } + + void writeDefinition(string key, string definition) + { + final switch (mode) + { + case Mode.man: + writeln(".TP"); + writeln(bold(key)); + writeln(definition); + break; + case Mode.markdown: + writeln(`
`); + writeln(); + writeln(bold(key)); + writeln(); + writeln("
"); + writeln(`
`); + writeln(); + writeln(definition); + writeln(); + writeln("
"); + break; + } + } + + void beginDefinitionList() + { + final switch (mode) + { + case Mode.man: + break; + case Mode.markdown: + writeln(); + writeln(`
`); + writeln(); + break; + } + } + + void endDefinitionList() + { + final switch (mode) + { + case Mode.man: + break; + case Mode.markdown: + writeln("\n
\n"); + break; + } + } + + void writeDefaultExitCodes() + { + string[2][] exitCodes = [ + ["0", "DUB succeeded"], + ["1", "usage errors, unknown command line flags"], + ["2", "package not found, package failed to load, miscellaneous error"] + ]; + + final switch (mode) + { + case Mode.man: + foreach (cm; exitCodes) { + writeln(".TP"); + writeln(".BR ", cm[0]); + writeln(cm[1]); + } + break; + case Mode.markdown: + beginDefinitionList(); + foreach (cm; exitCodes) { + writeDefinition(cm[0], cm[1]); + } + endDefinitionList(); + break; + } + } } void writeMainManFile(CommandArgs args, CommandGroup[] commands, - string fileName, const Config config) + string fileName, const Config config) { - auto manFile = File(config.cwd.buildPath(fileName), "w"); + auto manFile = ManWriter( + File(config.cwd.buildPath(fileName), "w"), + fileName.endsWith(".md") ? ManWriter.Mode.markdown : ManWriter.Mode.man + ); manFile.writeHeader("DUB", config); - auto seeAlso = ["dmd(1)", "rdmd(1)"] - .chain(commands.map!(a => a.commands).joiner - .map!(cmd => format("dub-%s(1)", cmd.name))) - .joiner(", ").to!string.bold; + auto seeAlso = [ + manFile.autolink(manFile.bold("dmd") ~ "(1)"), + manFile.autolink(manFile.bold("rdmd") ~ "(1)") + ] + .chain(commands + .map!(a => a.commands) + .joiner + .map!(cmd => manFile.autolink(manFile.bold("dub-" ~ cmd.name) ~ "(1)"))) + .joiner(", ") + .to!string; scope(exit) manFile.writeFooter(seeAlso, config); alias writeln = (m) => manFile.writeln(m); writeln(`dub \- Package and build management system for D`); - writeln("SYNOPSIS".header); - writeln(`.B dub -[\-\-version] -[\fICOMMAND\fR] -[\fIOPTIONS\&.\&.\&.\fR] -[\-\- [\fIAPPLICATION ARGUMENTS\&.\&.\&.\fR]]`); + writeln(manFile.header("SYNOPSIS")); + writeln(manFile.bold("dub") ~ text( + " [", + manFile.escapeWord("--version"), + "] [", + manFile.italic("COMMAND"), + "] [", + manFile.italic(manFile.escapeWord("OPTIONS...")), + "] ", manFile.escapeWord("--"), " [", + manFile.italic(manFile.escapeWord("APPLICATION ARGUMENTS...")), + "]" + )); - writeln("DESCRIPTION".header); - writeln(`Manages the DUB project in the current directory\&. DUB can serve as a build + writeln(manFile.header("DESCRIPTION")); + writeln(`Manages the DUB project in the current directory. DUB can serve as a build system and a package manager, automatically keeping track of project's dependencies \- both downloading them and linking them into the application.`); - writeln(".SH COMMANDS"); + writeln(manFile.header("COMMANDS")); + manFile.beginDefinitionList(); foreach (grp; commands) { foreach (cmd; grp.commands) { - writeln(".TP"); - writeln(cmd.name.bold); - writeln(cmd.helpText.joiner("\n")); + manFile.writeDefinition(manFile.specialLinkMainCmd(cmd.name), cmd.helpText.join( + manFile.mode == ManWriter.Mode.markdown ? "\n\n" : "\n" + )); } - } + } + + - writeln("COMMON OPTIONS".header); - args.writeArgs(manFile); + writeln(manFile.header("COMMON OPTIONS")); + manFile.writeArgs("-", args); } -string highlightArguments(string args) -{ - import std.regex : regex, replaceAll; - static auto re = regex("<([^>]*)>"); - static const reReplacement = "<%s>".format(`$1`.italic); - return args.replaceAll(re, reReplacement); -} - -void writeArgs(CommandArgs args, ref File manFile) -{ - alias write = (m) => manFile.write(m.replace(`-`, `\-`)); - foreach (arg; args.recognizedArgs) - { - auto names = arg.names.split("|"); - assert(names.length == 1 || names.length == 2); - string sarg = names[0].length == 1 ? names[0] : null; - string larg = names[0].length > 1 ? names[0] : names.length > 1 ? names[1] : null; - manFile.writeln(".PP"); - if (sarg !is null) { - write("-%s".format(sarg).bold); - if (larg !is null) - write(", "); - } - if (larg !is null) { - write("--%s".format(larg).bold); - if (!arg.defaultValue.peek!bool) - write("=VALUE"); - } - manFile.writeln; - manFile.writeln(".RS 4"); - manFile.writeln(arg.helpText.join("\n")); - manFile.writeln(".RE"); - } -} - -void writeManFile(Command command, const Config config) +void writeManFile(Command command, const Config config, ManWriter.Mode mode) { import std.uni : toUpper; auto args = new CommandArgs(null); command.prepare(args); - string fileName = format("dub-%s.1", command.name); - auto manFile = File(config.cwd.buildPath(fileName), "w"); + string fileName = format(mode == ManWriter.Mode.markdown ? "dub-%s.md" : "dub-%s.1", command.name); + auto manFile = ManWriter(File(config.cwd.buildPath(fileName), "w"), mode); auto manName = format("DUB-%s", command.name).toUpper; manFile.writeHeader(manName, config); string[] extraRelated; foreach (arg; args.recognizedArgs) { if (arg.names.canFind("rdmd")) - extraRelated ~= "rdmd(1)"; + extraRelated ~= manFile.autolink(manFile.bold("rdmd") ~ "(1)"); } if (command.name == "dustmite") - extraRelated ~= "dustmite(1)"; + extraRelated ~= manFile.autolink(manFile.bold("dustmite") ~ "(1)"); - const seeAlso = ["dub(1)"] - .chain(config.relatedSubCommands.map!(s => s.format!"dub-%s(1)")) + const seeAlso = [manFile.autolink(manFile.bold("dub") ~ "(1)")] + .chain(config.relatedSubCommands.map!(s => manFile.autolink(manFile.bold("dub-" ~ s) ~ "(1)"))) .chain(extraRelated) - .map!bold .joiner(", ") .to!string; scope(exit) manFile.writeFooter(seeAlso, config); alias writeln = (m) => manFile.writeln(m); - manFile.writefln(`dub-%s \- %s`, command.name, command.description); - writeln("SYNOPSIS".header); - writeln("dub %s".format(command.name).bold); - writeln(command.argumentsPattern.highlightArguments); - writeln(`OPTIONS\&.\&.\&.`.italic); + manFile.writefln(`dub-%s \- %s`, command.name, manFile.escapeFulltext(command.description)); + + writeln(manFile.header("SYNOPSIS")); + manFile.write(manFile.bold("dub %s ".format(command.name))); + manFile.write(manFile.highlightArguments(command.argumentsPattern)); + writeln(manFile.italic(manFile.escapeWord(`OPTIONS...`))); if (command.acceptsAppArgs) { - writeln("[-- <%s>]".format("application arguments...".italic)); + writeln("[-- <%s>]".format(manFile.italic(manFile.escapeWord("application arguments...")))); } - writeln("DESCRIPTION".header); - writeln(command.helpText.joiner("\n\n")); - writeln("OPTIONS".header); - args.writeArgs(manFile); + writeln(manFile.header("DESCRIPTION")); + writeln(manFile.escapeFulltext(command.helpText.join("\n\n"))); + writeln(manFile.header("OPTIONS")); + manFile.writeArgs(command.name, args); - static immutable exitStatus = -`.SH EXIT STATUS -.TP -.BR 0 -DUB succeeded -.TP -.BR 1 -usage errors, unknown command line flags -.TP -.BR 2 -package not found, package failed to load, miscellaneous error`; - static immutable exitStatusDustmite = -`.SH EXIT STATUS -Forwards the exit code from ` ~ `dustmite(1)`.bold; - if (command.name == "dustmite") - manFile.writeln(exitStatusDustmite); - else - manFile.writeln(exitStatus); + writeln(manFile.subheader("COMMON OPTIONS")); + manFile.writeln("See ", manFile.autolink(manFile.bold("dub") ~ "(1)")); + + manFile.writeln(manFile.header("EXIT STATUS")); + if (command.name == "dustmite") { + manFile.writeln("Forwards the exit code from " ~ manFile.autolink(manFile.bold(`dustmite`) ~ `(1)`)); + } else { + manFile.writeDefaultExitCodes(); + } } void main() @@ -218,12 +478,13 @@ auto args = new CommandArgs(null); options.prepare(args); args.writeMainManFile(commands, "dub.1", config); + args.writeMainManFile(commands, "dub.md", config); } string[][] relatedSubCommands = [ ["run", "build", "test"], ["test", "dustmite", "lint"], - ["describe", "gemerate"], + ["describe", "generate"], ["add", "fetch"], ["init", "add", "convert"], ["add-path", "remove-path"], @@ -244,6 +505,7 @@ related = related.remove!(c => c == cmd.name); config.relatedSubCommands = related; - cmd.writeManFile(config); + cmd.writeManFile(config, ManWriter.Mode.man); + cmd.writeManFile(config, ManWriter.Mode.markdown); } } diff --git a/source/dub/commandline.d b/source/dub/commandline.d index bb85690..ca5a552 100644 --- a/source/dub/commandline.d +++ b/source/dub/commandline.d @@ -35,7 +35,6 @@ import std.stdio; import std.string; import std.typecons : Tuple, tuple; -import std.variant; /** Retrieves a list of all available commands. @@ -167,7 +166,7 @@ options.root_path = options.root_path.expandTilde.absolutePath.buildNormalizedPath; } - final switch (options.color_mode) with (options.color) + final switch (options.colorMode) with (options.Color) { case automatic: // Use default determined in internal.logging.initLogging(). @@ -466,9 +465,22 @@ } if (cmd is null) { + logInfoNoTag("USAGE: dub [--version] [] [] [-- []]"); + logInfoNoTag(""); logError("Unknown command: %s", command_name_argument.value); - writeln(); - showHelp(handler.commandGroups, common_args); + import std.algorithm.iteration : filter; + import std.uni : toUpper; + foreach (CommandGroup key; handler.commandGroups) + { + foreach (Command command; key.commands) + { + if (levenshteinDistance(command_name_argument.value, command.name) < 4) { + logInfo("Did you mean '%s'?", command.name); + } + } + } + + logInfoNoTag(""); return 1; } @@ -523,11 +535,34 @@ bool help, annotate, bare; string[] registry_urls; string root_path; - enum color { automatic, on, off } // Lower case "color" in support of invalid option error formatting. - color color_mode = color.automatic; + enum Color { automatic, on, off } + Color colorMode = Color.automatic; SkipPackageSuppliers skipRegistry = SkipPackageSuppliers.none; PlacementLocation placementLocation = PlacementLocation.user; + deprecated("Use `Color` instead, the previous naming was a limitation of error message formatting") + alias color = Color; + deprecated("Use `colorMode` instead") + alias color_mode = colorMode; + + private void parseColor(string option, string value) @safe + { + // `automatic`, `on`, `off` are there for backwards compatibility + // `auto`, `always`, `never` is being used for compatibility with most + // other development and linux tools, after evaluating what other tools + // are doing, to help users intuitively pick correct values. + // See https://github.com/dlang/dub/issues/2410 for discussion + if (!value.length || value == "auto" || value == "automatic") + colorMode = Color.automatic; + else if (value == "always" || value == "on") + colorMode = Color.on; + else if (value == "never" || value == "off") + colorMode = Color.off; + else + throw new ConvException("Unable to parse argument '--" ~ option ~ "=" ~ value + ~ "', supported values: --color[=auto], --color=always, --color=never"); + } + /// Parses all common options and stores the result in the struct instance. void prepare(CommandArgs args) { @@ -552,12 +587,12 @@ args.getopt("q|quiet", &quiet, ["Only print warnings and errors"]); args.getopt("verror", &verror, ["Only print errors"]); args.getopt("vquiet", &vquiet, ["Print no messages"]); - args.getopt("color", &color_mode, [ + args.getopt("color", &colorMode, &parseColor, [ "Configure colored output. Accepted values:", - " automatic: Colored output on console/terminal,", + " auto: Colored output on console/terminal,", " unless NO_COLOR is set and non-empty (default)", - " on: Force colors enabled", - " off: Force colors disabled" + " always: Force colors enabled", + " never: Force colors disabled" ]); args.getopt("cache", &placementLocation, ["Puts any fetched packages in the specified location [local|system|user]."]); @@ -574,8 +609,10 @@ */ class CommandArgs { struct Arg { - Variant defaultValue; - Variant value; + alias Value = SumType!(string[], string, bool, int, uint); + + Value defaultValue; + Value value; string names; string[] helpText; bool hidden; @@ -629,20 +666,37 @@ void getopt(T)(string names, T* var, string[] help_text = null, bool hidden=false) { + getopt!T(names, var, null, help_text, hidden); + } + + void getopt(T)(string names, T* var, void delegate(string, string) @safe parseValue, string[] help_text = null, bool hidden=false) + { + import std.traits : OriginalType; + foreach (ref arg; m_recognizedArgs) if (names == arg.names) { assert(help_text is null, format!("Duplicated argument '%s' must not change helptext, consider to remove the duplication")(names)); - *var = arg.value.get!T; + *var = arg.value.match!( + (OriginalType!T v) => cast(T)v, + (_) { + if (false) + return T.init; + assert(false, "value from previous getopt has different type than the current getopt call"); + } + ); return; } assert(help_text.length > 0); Arg arg; - arg.defaultValue = *var; + arg.defaultValue = cast(OriginalType!T)*var; arg.names = names; arg.helpText = help_text; arg.hidden = hidden; - m_args.getopt(config.passThrough, names, var); - arg.value = *var; + if (parseValue is null) + m_args.getopt(config.passThrough, names, var); + else + m_args.getopt(config.passThrough, names, parseValue); + arg.value = cast(OriginalType!T)*var; m_recognizedArgs ~= arg; } @@ -826,7 +880,7 @@ /// Caption of the command category string caption; - /// List of commands contained inthis group + /// List of commands contained in this group Command[] commands; this(string caption, Command[] commands...) @safe pure nothrow @@ -885,8 +939,8 @@ "By default, the current working directory is used.", "", "Custom templates can be defined by packages by providing a sub-package called \"init-exec\". No default source files are added in this case.", - "The \"init-exec\" subpackage is compiled and executed inside the destination folder after the base project directory has been created.", - "Free arguments \"dub init -t custom -- free args\" are passed into the \"init-exec\" subpackage as app arguments." + "The \"init-exec\" sub-package is compiled and executed inside the destination folder after the base project directory has been created.", + "Free arguments \"dub init -t custom -- free args\" are passed into the \"init-exec\" sub-package as app arguments." ]; this.acceptsAppArgs = true; } @@ -1299,7 +1353,7 @@ // the user provided a version manually dep = VersionRange.fromString(packageParts.version_); } else if (packageParts.name.startsWith(":")) { - // Subpackages are always assumed to be present + // Sub-packages are always assumed to be present return 0; } else if (dub.packageManager.getBestPackage(packageParts.name)) { // found locally @@ -2695,13 +2749,16 @@ } else writeWS(longArgColumn); size_t col = longArgColumn; if (larg !is null) { - if (arg.defaultValue.peek!bool) { - writef("--%s", larg); - col += larg.length + 2; - } else { - writef("--%s=VALUE", larg); - col += larg.length + 8; - } + arg.defaultValue.match!( + (bool b) { + writef("--%s", larg); + col += larg.length + 2; + }, + (_) { + writef("--%s=VALUE", larg); + col += larg.length + 8; + } + ); } if (col < descColumn) { writeWS(descColumn - col); diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d index 315dec0..c7b06b0 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -88,7 +88,7 @@ * Merges $(LREF bs) onto `this` BuildSettings instance. This is called for * sourceLibrary dependencies when they are included in the build to be * merged into the root package build settings as well as configuring - * targets for different build types such as release or unittest-cov. + * targets for different build types such as `release` or `unittest-cov`. */ void add(in BuildSettings bs) { @@ -188,14 +188,14 @@ : vals; } - // Append vals to arr without adding duplicates. + // Append `vals` to `arr` without adding duplicates. static void add(ref string[] arr, in string[] vals, bool noDuplicates = true) { // vals might contain duplicates, add each val individually foreach (val; vals) arr ~= filterDuplicates(arr, [val], noDuplicates); } - // Append vals to AA + // Append `vals` to `aa` static void add(ref string[string] aa, in string[string] vals) { // vals might contain duplicated keys, add each val individually @@ -203,7 +203,7 @@ if (key !in aa) aa[key] = val; } - // Update vals to AA + // Update `vals` to `aa` static void update(ref string[string] aa, in string[string] vals) { // If there are duplicate keys, they will be ignored and overwritten. @@ -222,7 +222,7 @@ assert(ary == ["-dip1000", "-vgc", "-dip1001", "-vgc", "-dupflag", "-notdupflag"]); } - // Prepend arr by vals without adding duplicates. + // Prepend `arr` by `vals` without adding duplicates. static void prepend(ref string[] arr, in string[] vals, bool noDuplicates = true) { import std.range : retro; @@ -389,7 +389,7 @@ profileGC = 1<<21, /// Profile runtime allocations pic = 1<<22, /// Generate position independent code betterC = 1<<23, /// Compile in betterC mode (-betterC) - lowmem = 1<<24, /// Compile in lowmem mode (-lowmem) + lowmem = 1<<24, /// Compile in low-memory mode (-lowmem) coverageCTFE = 1<<25, /// Enable code coverage analysis including at compile-time (-cov=ctfe) color = 1<<26, /// Colorize output (-color) diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index 2039747..166f6b5 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -128,7 +128,7 @@ arch_override ); - /// Replace archticture string in `bp.archtiecture` + /// Replace architecture string in `bp.architecture` void replaceArch(const string from, const string to) { const idx = bp.architecture.countUntil(from); diff --git a/source/dub/dependency.d b/source/dub/dependency.d index 95fc57d..4e8be93 100644 --- a/source/dub/dependency.d +++ b/source/dub/dependency.d @@ -104,7 +104,7 @@ this.m_value = rng; } - deprecated("Instantiate the `Repository` struct with the string directy") + deprecated("Instantiate the `Repository` struct with the string directly") this(Repository repository, string spec) @safe { assert(repository.m_ref is null); @@ -875,7 +875,7 @@ * $(LI `"^1.0.0"` - semver compatible version range (same version if 0.x.y, ==major >=minor.patch if x.y.z)) * $(LI `"^1.0"` - same as ^1.0.0) * $(LI `"~master"` - a branch name) - * $(LI `"*" - match any version (see also `VersionRange.Any`)) + * $(LI `"*"` - match any version (see also `VersionRange.Any`)) * ) * * Apart from "$(LT)" and "$(GT)", "$(GT)=" and "$(LT)=" are also valid diff --git a/source/dub/dependencyresolver.d b/source/dub/dependencyresolver.d index 5a1b704..d064c61 100644 --- a/source/dub/dependencyresolver.d +++ b/source/dub/dependencyresolver.d @@ -295,7 +295,7 @@ // recursively mark all required dependencies of the concrete dependency tree markRecursively(root); - // remove all un-marked configurations + // remove all unmarked configurations foreach (p; configs.keys.dup) if (p !in required) configs.remove(p); diff --git a/source/dub/description.d b/source/dub/description.d index f26563b..bf580bd 100644 --- a/source/dub/description.d +++ b/source/dub/description.d @@ -83,8 +83,8 @@ string mainSourceFile; string[] dflags; /// Flags passed to the D compiler string[] lflags; /// Flags passed to the linker - string[] libs; /// Librariy names to link against (typically using "-l") - string[] injectSourceFiles; /// Files that should be injected when this package is dependend upon by a binary image. + string[] libs; /// Library names to link against (typically using "-l") + string[] injectSourceFiles; /// Files that should be injected when this package is dependent upon by a binary image. string[] copyFiles; /// Files to copy to the target directory string[] extraDependencyFiles; /// Files to check for rebuild dub project string[] versions; /// D version identifiers to set diff --git a/source/dub/dub.d b/source/dub/dub.d index d321369..64a1426 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -457,7 +457,7 @@ /** Loads a single file package. - Single-file packages are D files that contain a package receipe comment + Single-file packages are D files that contain a package recipe comment at their top. A recipe comment must be a nested `/+ ... +/` style comment, containing the virtual recipe file name and a colon, followed by the recipe contents (what would normally be in dub.sdl/dub.json). @@ -901,7 +901,7 @@ return m_packageManager.store(path, location, basePackageName, ver); } catch (ZipException e) { logInfo("Failed to extract zip archive for %s %s...", packageId, ver); - // rethrow the exception at the end of the loop + // re-throw the exception at the end of the loop if (i == 0) throw e; } @@ -941,7 +941,7 @@ Params: package_id = Name of the package to be removed - location_ = Specifies the location to look for the given package + location = Specifies the location to look for the given package name/version. resolve_version = Callback to select package version. */ @@ -1005,7 +1005,7 @@ is passed, the package will be removed from the location, if there is only one version retrieved. This will throw an exception, if there are multiple versions retrieved. - location_ = Specifies the location to look for the given package + location = Specifies the location to look for the given package name/version. */ void remove(string package_id, string version_, PlacementLocation location) @@ -1083,7 +1083,7 @@ m_packageManager.addSearchPath(makeAbsolute(path), system ? PlacementLocation.system : PlacementLocation.user); } - /** Unregisters a local directory search path. + /** Deregisters a local directory search path. Params: path = Path to a directory containing package directories @@ -1151,8 +1151,8 @@ preferring "~master". Params: - package_name: The name of the package in question. - prefer_stable: If set to `true` (the default), returns the latest + package_name = The name of the package in question. + prefer_stable = If set to `true` (the default), returns the latest stable version, even if there are newer pre-release versions. See_also: `listPackageVersions` @@ -1176,6 +1176,7 @@ format = Determines the package recipe format to use. recipe_callback = Optional callback that can be used to customize the recipe before it gets written. + app_args = Arguments to provide to the custom initialization routine. */ void createEmptyPackage(NativePath path, string[] deps, string type, PackageFormat format = PackageFormat.sdl, @@ -1516,7 +1517,7 @@ { none = 0, upgrade = 1<<1, /// Upgrade existing packages - preRelease = 1<<2, /// inclde pre-release versions in upgrade + preRelease = 1<<2, /// include pre-release versions in upgrade forceRemove = 1<<3, /// Deprecated, does nothing. select = 1<<4, /// Update the dub.selections.json file with the upgraded versions dryRun = 1<<5, /// Instead of downloading new packages, just print a message to notify the user of their existence @@ -1653,7 +1654,7 @@ auto ret = appender!(TreeNodes[]); auto pack = getPackage(node.pack, node.config); if (!pack) { - // this can hapen when the package description contains syntax errors + // this can happen when the package description contains syntax errors logDebug("Invalid package in dependency tree: %s %s", node.pack, node.config); return null; } @@ -1873,8 +1874,8 @@ * * Versions of dub prior to v1.31.0 used to store artifact under the * project directory, but this led to issues with packages stored on - * read-only filesystem / location, and lingering artifacts scattered - * through the filesystem. + * read-only file system / location, and lingering artifacts scattered + * through the file system. */ NativePath cache; diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index e10d87d..6ea65b5 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -34,19 +34,21 @@ string computeBuildName(string config, in GeneratorSettings settings, const string[][] hashing...) { - import std.digest.sha : SHA256, toHexString; + import std.digest.sha : SHA256; + import std.base64 : Base64URL; SHA256 hash; hash.start(); void addHash(in string[] strings...) { foreach (s; strings) { hash.put(cast(ubyte[])s); hash.put(0); } hash.put(0); } foreach(strings; hashing) addHash(strings); - const hashstr = hash.finish().toHexString(); + addHash(settings.platform.platform); + addHash(settings.platform.architecture); + addHash(settings.platform.compiler); + addHash(settings.platform.compilerVersion); + const hashstr = Base64URL.encode(hash.finish()[0 .. $ / 2]).stripRight("="); - return format("%s-%s-%s-%s-%s_v%s-%s", config, settings.buildType, - settings.platform.platform.join("."), - settings.platform.architecture.join("."), - settings.platform.compiler, settings.platform.compilerVersion, hashstr); + return format("%s-%s-%s", config, settings.buildType, hashstr); } class BuildGenerator : ProjectGenerator { @@ -217,7 +219,7 @@ // perform the actual build bool cached = false; if (settings.rdmd) performRDMDBuild(settings, buildsettings, pack, config, target_path); - else if (settings.direct || !generate_binary) performDirectBuild(settings, buildsettings, pack, config, target_path); + else if (!generate_binary) performDirectBuild(settings, buildsettings, pack, config, target_path); else cached = performCachedBuild(settings, buildsettings, pack, config, build_id, packages, additional_dep_files, target_path); // HACK: cleanup dummy doc files, we shouldn't specialize on buildType @@ -244,8 +246,6 @@ private bool performCachedBuild(GeneratorSettings settings, BuildSettings buildsettings, in Package pack, string config, string build_id, in Package[] packages, in NativePath[] additional_dep_files, out NativePath target_binary_path) { - auto cwd = settings.toolWorkingDirectory; - NativePath target_path; if (settings.tempBuild) { string packageName = pack.basePackage is null ? pack.name : pack.basePackage.name; @@ -266,7 +266,7 @@ if (!isWritableDir(target_path, true)) { if (!settings.tempBuild) - logInfo("Build directory %s is not writable. Falling back to direct build in the system's temp folder.", target_path.relativeTo(cwd).toNativeString()); + logInfo("Build directory %s is not writable. Falling back to direct build in the system's temp folder.", target_path); performDirectBuild(settings, buildsettings, pack, config, target_path); return false; } @@ -280,7 +280,7 @@ // override target path auto cbuildsettings = buildsettings; - cbuildsettings.targetPath = shrinkPath(target_path, cwd); + cbuildsettings.targetPath = target_path.toNativeString(); buildWithCompiler(settings, cbuildsettings); target_binary_path = getTargetPath(cbuildsettings, settings); diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 7cd98ed..72282f7 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -772,8 +772,8 @@ * * Artifacts are usually stored in: * `$DUB_HOME/cache/$PKG_NAME/$PKG_VERSION[/+$SUB_PKG_NAME]/` - * Note that the leading `+` in the subpackage name is to avoid any ambiguity. - * Build artifacts are usually stored in a subfolder named "build", + * Note that the leading `+` in the sub-package name is to avoid any ambiguity. + * Build artifacts are usually stored in a sub-folder named "build", * as their names are based on user-supplied values. * * Params: @@ -812,7 +812,7 @@ bool filterVersions; // only used for generator "build" - bool run, force, direct, rdmd, tempBuild, parallelBuild; + bool run, force, rdmd, tempBuild, parallelBuild; /// single file dub package bool single; @@ -1013,7 +1013,7 @@ /** Runs a list of build commands for a particular package. - This function sets all DUB speficic environment variables and makes sure + This function sets all DUB specific environment variables and makes sure that recursive dub invocations are detected and don't result in infinite command execution loops. The latter could otherwise happen when a command runs "dub describe" or similar functionality. @@ -1053,7 +1053,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_EXE"] = getDUBExePath(settings.platform.compilerBinary).toNativeString(); env["DUB_PLATFORM"] = join(settings.platform.platform, " "); env["DUB_ARCH"] = join(settings.platform.architecture, " "); @@ -1076,7 +1076,6 @@ env["DUB_COMBINED"] = settings.combined? "TRUE" : ""; env["DUB_RUN"] = settings.run? "TRUE" : ""; env["DUB_FORCE"] = settings.force? "TRUE" : ""; - env["DUB_DIRECT"] = settings.direct? "TRUE" : ""; env["DUB_RDMD"] = settings.rdmd? "TRUE" : ""; env["DUB_TEMP_BUILD"] = settings.tempBuild? "TRUE" : ""; env["DUB_PARALLEL_BUILD"] = settings.parallelBuild? "TRUE" : ""; diff --git a/source/dub/init.d b/source/dub/init.d index 8c08fdd..bb7da7f 100644 --- a/source/dub/init.d +++ b/source/dub/init.d @@ -34,6 +34,7 @@ version. type = The type of package skeleton to create. Can currently be "minimal", "vibe.d" or "deimos" + format = Format in which the recipe will be written (SDL / JSON) recipe_callback = Optional callback that can be used to customize the package recipe and the file format used to store it prior to writing it to disk. @@ -163,7 +164,7 @@ * most users. However, this file is not mandatory for `dub` to do its job, * so we do not depend on the content. * One important use case we need to support is people running `dub init` on - * a Github-initialized repository. Those might already contain a `.gitignore` + * a GitHub-initialized repository. Those might already contain a `.gitignore` * (and a README and a LICENSE), thus we should not bail out if the file already * exists, just ignore it. * diff --git a/source/dub/internal/configy/Attributes.d b/source/dub/internal/configy/Attributes.d index 7823471..7829064 100644 --- a/source/dub/internal/configy/Attributes.d +++ b/source/dub/internal/configy/Attributes.d @@ -121,7 +121,7 @@ /******************************************************************************* - A field which carries informations about whether it was set or not + A field which carries information about whether it was set or not Some configurations may need to know which fields were set explicitly while keeping defaults. An example of this is a `struct` where at least one field diff --git a/source/dub/internal/configy/Exceptions.d b/source/dub/internal/configy/Exceptions.d index e225303..00a6349 100644 --- a/source/dub/internal/configy/Exceptions.d +++ b/source/dub/internal/configy/Exceptions.d @@ -97,7 +97,7 @@ public override string toString () scope { - // Need to be overriden otherwise the overload is shadowed + // Need to be overridden, otherwise the overload is shadowed return super.toString(); } diff --git a/source/dub/internal/configy/FieldRef.d b/source/dub/internal/configy/FieldRef.d index a04a23c..1af4b67 100644 --- a/source/dub/internal/configy/FieldRef.d +++ b/source/dub/internal/configy/FieldRef.d @@ -33,7 +33,7 @@ To prevent this from happening, we always pass around a `FieldRef`, which wraps the parent struct type (`T`), the name of the field - as `FieldName`, and other informations. + as `FieldName`, and other information. To avoid any issue, eponymous usage is also avoided, hence the reference needs to be accessed using `Ref`. diff --git a/source/dub/internal/configy/Read.d b/source/dub/internal/configy/Read.d index f807456..44afcf1 100644 --- a/source/dub/internal/configy/Read.d +++ b/source/dub/internal/configy/Read.d @@ -98,7 +98,7 @@ Those forms are mutually exclusive, so a field with a unit suffix will error out if a mapping is used. This prevents surprises and ensures - that the error message, if any, is consistent accross user input. + that the error message, if any, is consistent across user input. To disable or change this behavior, one may use a `Converter` instead. @@ -109,7 +109,7 @@ This can be useful to catch typos or outdated configuration options. Post_Validation: - Some configuration will require validation accross multiple sections. + Some configuration will require validation across multiple sections. For example, two sections may be mutually exclusive as a whole, or may have fields which are mutually exclusive with another section's field(s). This kind of dependence is hard to account for declaratively, @@ -232,7 +232,7 @@ { return getopt( args, - // `caseInsensistive` is the default, but we need something + // `caseInsensitive` is the default, but we need something // with the same type for the ternary passThrough ? config.keepEndOfOptions : config.caseInsensitive, // Also the default, same reasoning @@ -682,7 +682,7 @@ Because a `struct` can be filled from either a mapping or a scalar, this function will first try the converter / fromString / string ctor - methods before defaulting to fieldwise construction. + methods before defaulting to field-wise construction. Note that optional fields are checked before recursion happens, so this method does not do this check. @@ -997,7 +997,7 @@ } } -/// Retun value of `isMappingEnabled` +/// Return value of `isMappingEnabled` private struct EnabledState { /// Used to determine which field controls a mapping enabled state diff --git a/source/dub/internal/dyaml/constructor.d b/source/dub/internal/dyaml/constructor.d index 2a660a6..a24b313 100644 --- a/source/dub/internal/dyaml/constructor.d +++ b/source/dub/internal/dyaml/constructor.d @@ -49,7 +49,7 @@ /** Constructs YAML values. * * Each YAML scalar, sequence or mapping has a tag specifying its data type. - * Constructor uses user-specifyable functions to create a node of desired + * Constructor uses user-specifiable functions to create a node of desired * data type from a scalar, sequence or mapping. * * diff --git a/source/dub/internal/dyaml/node.d b/source/dub/internal/dyaml/node.d index 45a25b7..687337c 100644 --- a/source/dub/internal/dyaml/node.d +++ b/source/dub/internal/dyaml/node.d @@ -429,7 +429,7 @@ /** Equality test. * - * If T is Node, recursively compares all subnodes. + * If T is Node, recursively compares all sub-nodes. * This might be quite expensive if testing entire documents. * * If T is not Node, gets a value of type T from the node and tests @@ -486,7 +486,7 @@ /** Get the value of the node as specified type. * - * If the specifed type does not match type in the node, + * If the specified type does not match type in the node, * conversion is attempted. The stringConversion template * parameter can be used to disable conversion from non-string * types to strings. @@ -494,8 +494,8 @@ * Numeric values are range checked, throwing if out of range of * requested type. * - * Timestamps are stored as std.datetime.SysTime. - * Binary values are decoded and stored as ubyte[]. + * Timestamps are stored as `std.datetime.SysTime`. + * Binary values are decoded and stored as `ubyte[]`. * * To get a null value, use get!YAMLNull . This is to * prevent getting null values for types such as strings or classes. @@ -1126,7 +1126,7 @@ * * If the node is a mapping and no key matches index, a new key-value * pair is added to the mapping. In sequences the index must be in - * range. This ensures behavior siilar to D arrays and associative + * range. This ensures behavior similar to D arrays and associative * arrays. * * To set element at a null index, use YAMLNull for index. @@ -1899,7 +1899,7 @@ assert("a" in iNode); } - /** Remove first (if any) occurence of a value in a collection. + /** Remove first (if any) occurrence of a value in a collection. * * This method can only be called on collection nodes. * @@ -1950,7 +1950,7 @@ * key matches index. * * If the node is a mapping and no key matches index, nothing is removed - * and no exception is thrown. This ensures behavior siilar to D arrays + * and no exception is thrown. This ensures behavior similar to D arrays * and associative arrays. * * Params: index = Index to remove at. diff --git a/source/dub/internal/dyaml/reader.d b/source/dub/internal/dyaml/reader.d index c294ab0..45836ba 100644 --- a/source/dub/internal/dyaml/reader.d +++ b/source/dub/internal/dyaml/reader.d @@ -95,7 +95,7 @@ /// `""` if the buffer is the contents of a string. /// /// Throws: ReaderException on a UTF decoding error or if there are - /// nonprintable Unicode characters illegal in YAML. + /// non-printable Unicode characters illegal in YAML. this(ubyte[] buffer, string name = "") @safe pure { name_ = name; diff --git a/source/dub/internal/dyaml/scanner.d b/source/dub/internal/dyaml/scanner.d index 3be567f..0e652a3 100644 --- a/source/dub/internal/dyaml/scanner.d +++ b/source/dub/internal/dyaml/scanner.d @@ -360,7 +360,7 @@ // restrictive than what the specification requires. // if(pedantic_ && flowLevel_ > 0 && indent_ > column) // { - // throw new ScannerException("Invalid intendation or unclosed '[' or '{'", + // throw new ScannerException("Invalid indentation or unclosed '[' or '{'", // reader_.mark) // } return; @@ -399,7 +399,7 @@ ///Add STREAM-END token. void fetchStreamEnd() @safe { - //Set intendation to -1 . + //Set indentation to -1 . unwindIndent(-1); removePossibleSimpleKey(); allowSimpleKey_ = false; @@ -412,7 +412,7 @@ /// Add DIRECTIVE token. void fetchDirective() @safe { - // Set intendation to -1 . + // Set indentation to -1 . unwindIndent(-1); // Reset simple keys. removePossibleSimpleKey(); @@ -497,7 +497,7 @@ void blockChecks(string type, TokenID id)() { enum context = type ~ " keys are not allowed here"; - // Are we allowed to start a key (not neccesarily a simple one)? + // Are we allowed to start a key (not necessarily a simple one)? enforce(allowSimpleKey_, new ScannerException(context, reader_.mark)); if(addIndent(reader_.column)) @@ -1001,7 +1001,7 @@ /// The specification does not restrict characters for anchors and /// aliases. This may lead to problems, for instance, the document: /// [ *alias, value ] - /// can be interpteted in two ways, as + /// can be interpreted in two ways, as /// [ "value" ] /// and /// [ *alias , "value" ] @@ -1208,7 +1208,7 @@ } } - // If chompint is Keep, we keep (commit) the last scanned line breaks + // If chomping is Keep, we keep (commit) the last scanned line breaks // (which are at the end of the scalar). Otherwise re remove them (end the // transaction). if(chomping == Chomping.keep) { breaksTransaction.commit(); } @@ -1360,7 +1360,7 @@ return endMark; } - /// Scan a qouted flow scalar token with specified quotes. + /// Scan a quoted flow scalar token with specified quotes. Token scanFlowScalar(const ScalarStyle quotes) @safe { const startMark = reader_.mark; @@ -1381,7 +1381,7 @@ return scalarToken(startMark, reader_.mark, slice, quotes); } - /// Scan nonspace characters in a flow scalar. + /// Scan non-space characters in a flow scalar. /// /// Assumes that the caller is building a slice in Reader, and puts the scanned /// characters into that slice. diff --git a/source/dub/internal/dyaml/serializer.d b/source/dub/internal/dyaml/serializer.d index 89402f4..ae0d727 100644 --- a/source/dub/internal/dyaml/serializer.d +++ b/source/dub/internal/dyaml/serializer.d @@ -30,7 +30,7 @@ struct Serializer { private: - ///Resolver used to determine which tags are automaticaly resolvable. + ///Resolver used to determine which tags are automatically resolvable. Resolver resolver_; ///Do all document starts have to be specified explicitly? @@ -56,7 +56,7 @@ * Construct a Serializer. * * Params: - * resolver = Resolver used to determine which tags are automaticaly resolvable. + * resolver = Resolver used to determine which tags are automatically resolvable. * explicitStart = Do all document starts have to be specified explicitly? * explicitEnd = Do all document ends have to be specified explicitly? * YAMLVersion = YAML version string. @@ -108,9 +108,9 @@ * Used to prevent associating every single repeating scalar with an * anchor/alias - only nodes long enough can use anchors. * - * Params: node = Node to check for anchorability. + * Params: node = Node to check for anchor-ability. * - * Returns: True if the node is anchorable, false otherwise. + * Returns: True if the node is anchor-able, false otherwise. */ static bool anchorable(ref Node node) @safe { @@ -142,7 +142,7 @@ assert(anchorable(node6)); } - ///Add an anchor to the node if it's anchorable and not anchored yet. + ///Add an anchor to the node if it's anchor-able and not anchored yet. void anchorNode(ref Node node) @safe { if(!anchorable(node)){return;} @@ -187,7 +187,7 @@ return appender.data; } - ///Serialize a node and all its subnodes. + ///Serialize a node and all its sub-nodes. void serializeNode(EmitterT)(ref EmitterT emitter, ref Node node) @safe { //If the node has an anchor, emit an anchor (as aliasEvent) on the diff --git a/source/dub/internal/logging.d b/source/dub/internal/logging.d index 3a01c45..777cdbb 100644 --- a/source/dub/internal/logging.d +++ b/source/dub/internal/logging.d @@ -2,7 +2,7 @@ Handles all the console output of the Dub package manager, by providing useful methods for handling colored text. The module also disables colors when stdout and stderr are not a TTY in order to avoid ASCII escape sequences in piped - output. The module can autodetect and configure itself in this regard by + output. The module can auto-detect and configure itself in this regard by calling initLogging() at the beginning of the program. But, whether to color text or not can also be set manually with setLoggingColorsEnabled(bool). @@ -12,8 +12,8 @@ '----------' fixed width - the "tag" part can be colored (most oftenly will be) and always has a fixed - width, which is defined as a const at the beginning of this module. + the "tag" part can be colored (most often will be) and always has a fixed + width, which is defined as a constant at the beginning of this module. The output for the log levels debug and diagnostic will be just the plain string. @@ -199,8 +199,8 @@ or tag color required (since there will be no tag). Params: - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logDebug(T...)(string fmt, lazy T args) nothrow { @@ -220,8 +220,8 @@ Params: tag = The string the tag at the beginning of the line should contain tagColor = The color the tag string should have - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logInfo(T...)(string tag, Color tagColor, string fmt, lazy T args) nothrow { @@ -231,11 +231,11 @@ /** Shorthand function to log a message with info level, this version prints an empty tag automatically (which is different from not having a tag - in this - case there will be an identation of tagWidth chars on the left anyway). + case there will be an indentation of tagWidth chars on the left anyway). Params: - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logInfo(T...)(string fmt, lazy T args) nothrow if (!is(T[0] : Color)) { @@ -247,8 +247,8 @@ print a tag at all, it effectively just prints the given string. Params: - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logInfoNoTag(T...)(string fmt, lazy T args) nothrow if (!is(T[0] : Color)) { @@ -261,8 +261,8 @@ Params: tag = The string the tag at the beginning of the line should contain - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logWarnTag(T...)(string tag, string fmt, lazy T args) nothrow { @@ -274,8 +274,8 @@ tag "Warning". The tag color is also fixed to yellow. Params: - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logWarn(T...)(string fmt, lazy T args) nothrow { @@ -288,8 +288,8 @@ Params: tag = The string the tag at the beginning of the line should contain - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logErrorTag(T...)(string tag, string fmt, lazy T args) nothrow { @@ -301,8 +301,8 @@ tag "Error". The tag color is also fixed to red. Params: - level = The log level for the logged message fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void logError(T...)(string fmt, lazy T args) nothrow { @@ -322,6 +322,7 @@ tag = The string the tag at the beginning of the line should contain tagColor = The color the tag string should have fmt = See http://dlang.org/phobos/std_format.html#format-string + args = Arguments matching the format string */ void log(T...)( LogLevel level, @@ -376,14 +377,14 @@ logInfo("Tag", Color.green, "My %s log message", "colored".color(Color.red)); - without worring whether or not colored output is enabled or not. + without worrying whether or not colored output is enabled or not. Also a mode can be specified, such as bold/underline/etc... Params: str = The string to color - color = The color to apply - mode = An optional mode, such as bold/underline/etc... + c = The color to apply + m = An optional mode, such as bold/underline/etc... */ string color(const string str, const Color c, const Mode m = Mode.init) { @@ -402,7 +403,7 @@ Params: str = The string to color - mode = The mode, such as bold/underline/etc... + m = The mode, such as bold/underline/etc... */ string color(const string str, const Mode m = Mode.init) { diff --git a/source/dub/internal/sdlang/ast.d b/source/dub/internal/sdlang/ast.d index deda488..446bc09 100644 --- a/source/dub/internal/sdlang/ast.d +++ b/source/dub/internal/sdlang/ast.d @@ -23,6 +23,8 @@ import dub.internal.sdlang.token; import dub.internal.sdlang.util; +import dub.internal.dyaml.stdsumtype; + class Attribute { Value value; @@ -143,14 +145,14 @@ auto allAttrsIndex = _parent.allAttributes.countUntil(this); _parent.allAttributes.removeIndex(allAttrsIndex); - // Remove from _parent.attributeIndicies - auto sameNamespaceAttrs = _parent.attributeIndicies[_namespace]; - auto attrIndiciesIndex = sameNamespaceAttrs.countUntil(allAttrsIndex); - _parent.attributeIndicies[_namespace].removeIndex(attrIndiciesIndex); + // Remove from _parent.attributeIndices + auto sameNamespaceAttrs = _parent.attributeIndices[_namespace]; + auto attrIndicesIndex = sameNamespaceAttrs.countUntil(allAttrsIndex); + _parent.attributeIndices[_namespace].removeIndex(attrIndicesIndex); - // Fixup other indicies - foreach(ns, ref nsAttrIndicies; _parent.attributeIndicies) - foreach(k, ref v; nsAttrIndicies) + // Fixup other indices + foreach(ns, ref nsAttrIndices; _parent.attributeIndices) + foreach(k, ref v; nsAttrIndices) if(v > allAttrsIndex) v--; @@ -314,8 +316,8 @@ private Tag[] allTags; // In same order as specified in SDL file. private string[] allNamespaces; // In same order as specified in SDL file. - private size_t[][string] attributeIndicies; // allAttributes[ attributes[namespace][i] ] - private size_t[][string] tagIndicies; // allTags[ tags[namespace][i] ] + private size_t[][string] attributeIndices; // allAttributes[ attributes[namespace][i] ] + private size_t[][string] tagIndices; // allTags[ tags[namespace][i] ] private Attribute[][string][string] _attributes; // attributes[namespace or "*"][name][i] private Tag[][string][string] _tags; // tags[namespace or "*"][name][i] @@ -357,7 +359,7 @@ attr._parent = this; allAttributes ~= attr; - attributeIndicies[attr._namespace] ~= allAttributes.length-1; + attributeIndices[attr._namespace] ~= allAttributes.length-1; _attributes[attr._namespace][attr._name] ~= attr; _attributes["*"] [attr._name] ~= attr; @@ -391,7 +393,7 @@ tag._parent = this; allTags ~= tag; - tagIndicies[tag._namespace] ~= allTags.length-1; + tagIndices[tag._namespace] ~= allTags.length-1; _tags[tag._namespace][tag._name] ~= tag; _tags["*"] [tag._name] ~= tag; @@ -431,14 +433,14 @@ auto allTagsIndex = _parent.allTags.countUntil(this); _parent.allTags.removeIndex(allTagsIndex); - // Remove from _parent.tagIndicies - auto sameNamespaceTags = _parent.tagIndicies[_namespace]; - auto tagIndiciesIndex = sameNamespaceTags.countUntil(allTagsIndex); - _parent.tagIndicies[_namespace].removeIndex(tagIndiciesIndex); + // Remove from _parent.tagIndices + auto sameNamespaceTags = _parent.tagIndices[_namespace]; + auto tagIndicesIndex = sameNamespaceTags.countUntil(allTagsIndex); + _parent.tagIndices[_namespace].removeIndex(tagIndicesIndex); - // Fixup other indicies - foreach(ns, ref nsTagIndicies; _parent.tagIndicies) - foreach(k, ref v; nsTagIndicies) + // Fixup other indices + foreach(ns, ref nsTagIndices; _parent.tagIndices) + foreach(k, ref v; nsTagIndices) if(v > allTagsIndex) v--; @@ -450,24 +452,24 @@ private void removeNamespaceIfEmpty(string namespace) { - // If namespace has no attributes, remove it from attributeIndicies/_attributes - if(namespace in attributeIndicies && attributeIndicies[namespace].length == 0) + // If namespace has no attributes, remove it from attributeIndices/_attributes + if(namespace in attributeIndices && attributeIndices[namespace].length == 0) { - attributeIndicies.remove(namespace); + attributeIndices.remove(namespace); _attributes.remove(namespace); } - // If namespace has no tags, remove it from tagIndicies/_tags - if(namespace in tagIndicies && tagIndicies[namespace].length == 0) + // If namespace has no tags, remove it from tagIndices/_tags + if(namespace in tagIndices && tagIndices[namespace].length == 0) { - tagIndicies.remove(namespace); + tagIndices.remove(namespace); _tags.remove(namespace); } // If namespace is now empty, remove it from allNamespaces if( - namespace !in tagIndicies && - namespace !in attributeIndicies + namespace !in tagIndices && + namespace !in attributeIndices ) { auto allNamespacesIndex = allNamespaces.length - allNamespaces.find(namespace).length; @@ -582,7 +584,7 @@ } } - struct MemberRange(T, string allMembers, string memberIndicies, string membersGrouped) + struct MemberRange(T, string allMembers, string memberIndices, string membersGrouped) { private Tag tag; private string namespace; // "*" indicates "all namespaces" (ok since it's not a valid namespace name) @@ -600,8 +602,8 @@ if(namespace == "*") initialEndIndex = mixin("tag."~allMembers~".length"); - else if(namespace in mixin("tag."~memberIndicies)) - initialEndIndex = mixin("tag."~memberIndicies~"[namespace].length"); + else if(namespace in mixin("tag."~memberIndices)) + initialEndIndex = mixin("tag."~memberIndices~"[namespace].length"); else initialEndIndex = 0; @@ -692,7 +694,7 @@ if(namespace == "*") return mixin("tag."~allMembers~"[ frontIndex+index ]"); else - return mixin("tag."~allMembers~"[ tag."~memberIndicies~"[namespace][frontIndex+index] ]"); + return mixin("tag."~allMembers~"[ tag."~memberIndices~"[namespace][frontIndex+index] ]"); } alias NamedMemberRange!(T,membersGrouped) ThisNamedMemberRange; @@ -860,8 +862,8 @@ if(frontIndex == 0 && endIndex == tag.allNamespaces.length) { return - namespace in tag.attributeIndicies || - namespace in tag.tagIndicies; + namespace in tag.attributeIndices || + namespace in tag.tagIndices; } else // Slower fallback method @@ -876,8 +878,8 @@ TagRange tags; } - alias MemberRange!(Attribute, "allAttributes", "attributeIndicies", "_attributes") AttributeRange; - alias MemberRange!(Tag, "allTags", "tagIndicies", "_tags" ) TagRange; + alias MemberRange!(Attribute, "allAttributes", "attributeIndices", "_attributes") AttributeRange; + alias MemberRange!(Tag, "allTags", "tagIndices", "_tags" ) TagRange; static assert(isRandomAccessRange!AttributeRange); static assert(isRandomAccessRange!TagRange); static assert(isRandomAccessRange!NamespaceRange); @@ -1102,7 +1104,10 @@ // Values foreach(val; values) - buf.put(" (%s): %s\n".format(.toString(val.type), val)); + buf.put(" (%s): %s\n".format( + val.match!(v => typeof(v).stringof), + val + )); // Attributes foreach(attrNamespace; _attributes.keys.sort()) @@ -1116,7 +1121,9 @@ buf.put( " %s%s(%s): %s\n".format( - namespaceStr, attr._name, .toString(attr.value.type), attr.value + namespaceStr, attr._name, + attr.value.match!(v => typeof(v).stringof), + attr.value ) ); } diff --git a/source/dub/internal/sdlang/lexer.d b/source/dub/internal/sdlang/lexer.d index 3eb44a8..4fc583f 100644 --- a/source/dub/internal/sdlang/lexer.d +++ b/source/dub/internal/sdlang/lexer.d @@ -462,7 +462,7 @@ static keywordsInited = false; if(!keywordsInited) { - // Value (as a std.variant-based type) can't be statically inited + // Value (as a std.variant-based type) can't be statically initialized keywords[0] = Key("true", Value(true )); keywords[1] = Key("false", Value(false)); keywords[2] = Key("on", Value(true )); @@ -621,7 +621,7 @@ } } else if(isNewline(ch)) - error("Newline not alowed in character literal."); + error("Newline not allowed in character literal."); else value = ch; advanceChar(ErrorOnEOF.Yes); // Skip the character itself @@ -1340,7 +1340,7 @@ /// Advances past whitespace and comments private void eatWhite(bool allowComments=true) { - // -- Comment/Whitepace Lexer ------------- + // -- Comment/Whitespace Lexer ------------- enum State { diff --git a/source/dub/internal/sdlang/parser.d b/source/dub/internal/sdlang/parser.d index 24bb16e..7fd1f38 100644 --- a/source/dub/internal/sdlang/parser.d +++ b/source/dub/internal/sdlang/parser.d @@ -7,7 +7,6 @@ else: import std.file; -import std.variant : Algebraic; import dub.internal.libInputVisitor; @@ -18,6 +17,8 @@ import dub.internal.sdlang.token; import dub.internal.sdlang.util; +import dub.internal.dyaml.stdsumtype; + /// Returns root tag. Tag parseFile(string filename) { @@ -119,7 +120,7 @@ } /// The element of the InputRange returned by pullParseFile and pullParseSource: -alias ParserEvent = Algebraic!( +alias ParserEvent = SumType!( FileStartEvent, FileEndEvent, TagStartEvent, @@ -483,41 +484,41 @@ auto eventRange = inputVisitor!ParserEvent( parser ); foreach(event; eventRange) { - if(auto e = event.peek!TagStartEvent()) - { - auto newTag = new Tag(currTag, e.namespace, e.name); - newTag.location = e.location; + event.match!( + (TagStartEvent e) + { + auto newTag = new Tag(currTag, e.namespace, e.name); + newTag.location = e.location; - currTag = newTag; - } - else if(event.peek!TagEndEvent()) - { - currTag = currTag.parent; + currTag = newTag; + }, + (TagEndEvent _) + { + currTag = currTag.parent; - if(!currTag) - parser.error("Internal Error: Received an extra TagEndEvent"); - } - else if(auto e = event.peek!ValueEvent()) - { - currTag.add(e.value); - } - else if(auto e = event.peek!AttributeEvent()) - { - auto attr = new Attribute(e.namespace, e.name, e.value, e.location); - currTag.add(attr); - } - else if(event.peek!FileStartEvent()) - { - // Do nothing - } - else if(event.peek!FileEndEvent()) - { - // There shouldn't be another parent. - if(currTag.parent) - parser.error("Internal Error: Unexpected end of file, not enough TagEndEvent"); - } - else - parser.error("Internal Error: Received unknown parser event"); + if(!currTag) + parser.error("Internal Error: Received an extra TagEndEvent"); + }, + (ValueEvent e) + { + currTag.add(e.value); + }, + (AttributeEvent e) + { + auto attr = new Attribute(e.namespace, e.name, e.value, e.location); + currTag.add(attr); + }, + (FileStartEvent _) + { + // Do nothing + }, + (FileEndEvent _) + { + // There shouldn't be another parent. + if(currTag.parent) + parser.error("Internal Error: Unexpected end of file, not enough TagEndEvent"); + } + ); } return currTag; diff --git a/source/dub/internal/sdlang/symbol.d b/source/dub/internal/sdlang/symbol.d index 04de244..fd60059 100644 --- a/source/dub/internal/sdlang/symbol.d +++ b/source/dub/internal/sdlang/symbol.d @@ -38,7 +38,7 @@ /// Symbol is essentially the "type" of a Token. /// Token is like an instance of a Symbol. /// -/// This only represents terminals. Nonterminal tokens aren't +/// This only represents terminals. Non-terminal tokens aren't /// constructed since the AST is built directly during parsing. /// /// You can't create a Symbol directly. Instead, use the 'symbol' diff --git a/source/dub/internal/sdlang/token.d b/source/dub/internal/sdlang/token.d index a86ae5d..b11846c 100644 --- a/source/dub/internal/sdlang/token.d +++ b/source/dub/internal/sdlang/token.d @@ -13,7 +13,8 @@ import std.range; import std.string; import std.typetuple; -import std.variant; + +import dub.internal.dyaml.stdsumtype; import dub.internal.sdlang.symbol; import dub.internal.sdlang.util; @@ -58,7 +59,7 @@ } /++ -SDL's datatypes map to D's datatypes as described below. +SDL's data-types map to D's datatypes as described below. Most are straightforward, but take special note of the date/time-related types. Boolean: bool @@ -80,16 +81,16 @@ Date Time (with an unknown timezone): DateTimeFracUnknownZone +/ alias TypeTuple!( + typeof(null), bool, string, dchar, int, long, float, double, real, Date, DateTimeFrac, SysTime, DateTimeFracUnknownZone, Duration, ubyte[], - typeof(null), ) ValueTypes; -alias Algebraic!( ValueTypes ) Value; ///ditto +alias SumType!ValueTypes Value; /// ditto template isSDLSink(T) { @@ -124,16 +125,7 @@ void toSDLString(Sink)(Value value, ref Sink sink) if(isOutputRange!(Sink,char)) { - foreach(T; ValueTypes) - { - if(value.type == typeid(T)) - { - toSDLString( value.get!T(), sink ); - return; - } - } - - throw new Exception("Internal SDLang-D error: Unhandled type of Value. Contains: "~value.toString()); + value.match!(v => toSDLString(v, sink)); } void toSDLString(Sink)(typeof(null) value, ref Sink sink) if(isOutputRange!(Sink,char)) @@ -331,7 +323,7 @@ sink.put(']'); } -/// This only represents terminals. Nonterminals aren't +/// This only represents terminals. Non-terminals aren't /// constructed since the AST is directly built during parsing. struct Token { @@ -362,7 +354,6 @@ { if( this.symbol != b.symbol || - this.value.type != b.value.type || this.value != b.value ) return false; diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 5b68728..28127ef 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -59,7 +59,7 @@ { // The Lock can't be unlinked as someone could try to lock an already // opened fd while a new file with the same name gets created. - // Exclusive filesystem locks (O_EXCL, mkdir) could be deleted but + // Exclusive file system locks (O_EXCL, mkdir) could be deleted but // aren't automatically freed when a process terminates, see #1149. private File f; } @@ -381,11 +381,11 @@ Throws: an Exception if no valid DUB executable is found */ -public string getDUBExePath(in string compilerBinary=null) +public NativePath getDUBExePath(in string compilerBinary=null) { version(DubApplication) { import std.file : thisExePath; - return thisExePath(); + return NativePath(thisExePath()); } else { // this must be dub as a library @@ -418,7 +418,7 @@ .filter!exists; enforce(!dubLocs.empty, "Could not find DUB executable"); - return dubLocs.front.array; + return NativePath(dubLocs.front.array); } } diff --git a/source/dub/internal/vibecompat/core/file.d b/source/dub/internal/vibecompat/core/file.d index 8467857..6de9241 100644 --- a/source/dub/internal/vibecompat/core/file.d +++ b/source/dub/internal/vibecompat/core/file.d @@ -56,7 +56,7 @@ from = NativePath of the source file to = NativePath for the destination file overwrite = If true, any file existing at the destination path will be - overwritten. If this is false, an excpetion will be thrown should + overwritten. If this is false, an exception will be thrown should a file already exist at the destination path. Throws: diff --git a/source/dub/internal/vibecompat/data/json.d b/source/dub/internal/vibecompat/data/json.d index aced940..41900cd 100644 --- a/source/dub/internal/vibecompat/data/json.d +++ b/source/dub/internal/vibecompat/data/json.d @@ -1731,6 +1731,7 @@ Params: dst = References the string output range to which the result is written. json = Specifies the JSON value that is to be stringified. + level = The nesting level at which to write the JSON object (for pretty output). See_Also: Json.toString, writePrettyJsonString */ diff --git a/source/dub/internal/vibecompat/data/serialization.d b/source/dub/internal/vibecompat/data/serialization.d index 8216310..2fac24d 100644 --- a/source/dub/internal/vibecompat/data/serialization.d +++ b/source/dub/internal/vibecompat/data/serialization.d @@ -870,7 +870,7 @@ static struct Box(T) { T value; } - // Also to berepresented as the boxed value when serialized, but has + // Also to be represented as the boxed value when serialized, but has // a different way to access the value. static struct Box2(T) { private T v; diff --git a/source/dub/internal/vibecompat/data/utils.d b/source/dub/internal/vibecompat/data/utils.d index fd75584..64dc9b6 100644 --- a/source/dub/internal/vibecompat/data/utils.d +++ b/source/dub/internal/vibecompat/data/utils.d @@ -127,7 +127,7 @@ /** - Determins if a member is a public, non-static data field. + Determines if a member is a public, non-static data field. */ template isRWPlainField(T, string M) { diff --git a/source/dub/internal/vibecompat/inet/path.d b/source/dub/internal/vibecompat/inet/path.d index 26cad1a..745ebc0 100644 --- a/source/dub/internal/vibecompat/inet/path.d +++ b/source/dub/internal/vibecompat/inet/path.d @@ -145,7 +145,7 @@ return ret.data; } - /// Tests if `rhs` is an anchestor or the same as this path. + /// Tests if `rhs` is an ancestor or the same as this path. bool startsWith(const NativePath rhs) const { if( rhs.m_nodes.length > m_nodes.length ) return false; foreach( i; 0 .. rhs.m_nodes.length ) @@ -186,7 +186,7 @@ /// The parent path @property NativePath parentPath() const { return this[0 .. length-1]; } - /// The ist of path entries of which this path is composed + /// The list of path entries of which this path is composed @property immutable(PathEntry)[] nodes() const { return m_nodes; } /// The number of path entries of which this path is composed @@ -300,7 +300,7 @@ int opCmp(string rhs) const scope @safe pure nothrow @nogc { return m_name.cmp(rhs); } } -/// Joins two path strings. subpath must be relative. +/// Joins two path strings. sub-path must be relative. string joinPath(string basepath, string subpath) { NativePath p1 = NativePath(basepath); diff --git a/source/dub/package_.d b/source/dub/package_.d index 1c5b14f..368f807 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -360,7 +360,7 @@ /** Returns all BuildSettings for the given platform and configuration. - This will gather the effective build settings declared in tha package + This will gather the effective build settings declared in the package recipe for when building on a particular platform and configuration. Root build settings and configuration specific settings will be merged. @@ -760,7 +760,7 @@ if (m_parentPackage) { if (m_parentPackage.path != path) { if (this.recipe.license.length && this.recipe.license != m_parentPackage.recipe.license) - logWarn("Warning: License in subpackage %s is different than it's parent package, this is discouraged.", name); + logWarn("Warning: License in sub-package %s is different than its parent package, this is discouraged.", name); } } if (name.empty) logWarn("Warning: The package in %s has no name.", path); diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 8e0426e..04c82e3 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -89,7 +89,7 @@ * Dub versions because v1.31 eagerly scan all available repositories, * leading to slowdown for the most common operation - `dub build` with * already resolved dependencies. - * From v1.31 onwards, those locations are not scanned eagerly, + * From v1.31 onward, those locations are not scanned eagerly, * unless one of the function requiring eager scanning does, * such as `getBestPackage` - as it needs to iterate the list * of available packages. @@ -100,7 +100,7 @@ /** Instantiate an instance with a single search path - This constructor is used when dub is invoked with the '--bar' CLI switch. + This constructor is used when dub is invoked with the '--bare' CLI switch. The instance will not look up the default repositories (e.g. ~/.dub/packages), using only `path` instead. @@ -340,7 +340,7 @@ /** For a given SCM repository, returns the corresponding package. An SCM repository is provided as its remote URL, the repository is cloned - and in the dependency speicfied commit is checked out. + and in the dependency specified commit is checked out. If the target directory already exists, just returns the package without cloning. @@ -416,7 +416,7 @@ /** * Searches for the latest version of a package matching the version range. * - * This will search the local filesystem only (it doesn't connect + * This will search the local file system only (it doesn't connect * to the registry) for the "best" (highest version) that matches `range`. * An overload with a single version exists to search for an exact version. * @@ -717,7 +717,7 @@ logDebug("Extracting from zip."); - // In a github zip, the actual contents are in a subfolder + // In a GitHub zip, the actual contents are in a sub-folder alias PSegment = typeof(NativePath.init.head); PSegment[] zip_prefix; outer: foreach(ArchiveMember am; archive.directory) { @@ -977,13 +977,13 @@ return digest[].dup; } - /// Adds the package and scans for subpackages. + /// Adds the package and scans for sub-packages. private void addPackages(ref Package[] dst_repos, Package pack) const { // Add the main package. dst_repos ~= pack; - // Additionally to the internally defined subpackages, whose metadata + // Additionally to the internally defined sub-packages, whose metadata // is loaded with the main dub.json, load all externally defined // packages after the package is available with all the data. foreach (spr; pack.subPackages) { @@ -1001,7 +1001,7 @@ sp = Package.load(path, NativePath.init, pack); } else sp = new Package(spr.recipe, pack.path, pack); - // Add the subpackage. + // Add the sub-package. try { dst_repos ~= sp; } catch (Exception e) { @@ -1278,7 +1278,7 @@ auto existing = refresh ? null : this.fromPath; if (this.packagePath !is NativePath.init) { // For the internal location, we use `fromPath` to store packages - // loaded by the user (e.g. the project and its subpackages), + // loaded by the user (e.g. the project and its sub-packages), // so don't clean it. this.fromPath = null; } @@ -1331,7 +1331,7 @@ if (!p) p = Package.load(pack_path, packageFile); mgr.addPackages(this.fromPath, p); } catch (ConfigException exc) { - // Confiy error message already include the path + // Configy error message already include the path logError("Invalid recipe for local package: %S", exc); } catch (Exception e) { logError("Failed to load package in %s: %s", pack_path, e.msg); diff --git a/source/dub/packagesuppliers/maven.d b/source/dub/packagesuppliers/maven.d index 492b13e..7673b2e 100644 --- a/source/dub/packagesuppliers/maven.d +++ b/source/dub/packagesuppliers/maven.d @@ -121,7 +121,7 @@ SearchResult[] searchPackages(string query) { // Only exact search is supported - // This enables retrival of dub packages on dub run + // This enables retrieval of dub packages on dub run auto md = getMetadata(query); if (md.type == Json.Type.null_) return null; diff --git a/source/dub/platform.d b/source/dub/platform.d index 37122d7..6ee31b2 100644 --- a/source/dub/platform.d +++ b/source/dub/platform.d @@ -6,7 +6,7 @@ CI slave machines. It also contains means to match build platforms against a platform - specification string as used in package reciptes. + specification string as used in package recipes. Copyright: © 2012-2017 rejectedsoftware e.K. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. @@ -59,7 +59,7 @@ version(X86) version(CRuntime_DigitalMars) ret ~= "x86_omf"; // Hack: see #1059 // When compiling with --arch=x86_mscoff build_platform.architecture is equal to ["x86"] and canFind below is false. - // This hack prevents unnesessary warning 'Failed to apply the selected architecture x86_mscoff. Got ["x86"]'. + // This hack prevents unnecessary warning 'Failed to apply the selected architecture x86_mscoff. Got ["x86"]'. // And also makes "x86_mscoff" available as a platform specifier in the package recipe version(X86) version(CRuntime_Microsoft) ret ~= "x86_mscoff"; version(X86_64) ret ~= "x86_64"; @@ -177,7 +177,7 @@ `"-dmd"`, `"-arm"`, `"-arm-dmd"`, `"-windows-dmd"` Params: - platform = The build platform to match agains the platform specification + platform = The build platform to match against the platform specification specification = The specification being matched. It must either be an empty string or start with a dash. diff --git a/source/dub/project.d b/source/dub/project.d index 07e79e3..b22f73d 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -227,6 +227,7 @@ /** Adds a test runner configuration for the root package. Params: + settings = The generator settings to use generate_main = Whether to generate the main.d file base_config = Optional base configuration custom_main_file = Optional path to file with custom main entry point @@ -355,13 +356,16 @@ */ void validate() { + bool isSDL = !m_rootPackage.recipePath.empty + && m_rootPackage.recipePath.head.name.endsWith(".sdl"); + // some basic package lint m_rootPackage.warnOnSpecialCompilerFlags(); string nameSuggestion() { string ret; ret ~= `Please modify the "name" field in %s accordingly.`.format(m_rootPackage.recipePath.toNativeString()); if (!m_rootPackage.recipe.buildSettings.targetName.length) { - if (m_rootPackage.recipePath.head.name.endsWith(".sdl")) { + if (isSDL) { ret ~= ` You can then add 'targetName "%s"' to keep the current executable name.`.format(m_rootPackage.name); } else { ret ~= ` You can then add '"targetName": "%s"' to keep the current executable name.`.format(m_rootPackage.name); @@ -370,20 +374,23 @@ return ret; } if (m_rootPackage.name != m_rootPackage.name.toLower()) { - logWarn(`WARNING: DUB package names should always be lower case. %s`, nameSuggestion()); + logWarn(`DUB package names should always be lower case. %s`, nameSuggestion()); } else if (!m_rootPackage.recipe.name.all!(ch => ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '_')) { - logWarn(`WARNING: DUB package names may only contain alphanumeric characters, ` + logWarn(`DUB package names may only contain alphanumeric characters, ` ~ `as well as '-' and '_'. %s`, nameSuggestion()); } enforce(!m_rootPackage.name.canFind(' '), "Aborting due to the package name containing spaces."); foreach (d; m_rootPackage.getAllDependencies()) if (d.spec.isExactVersion && d.spec.version_.isBranch) { - logWarn("WARNING: A deprecated branch based version specification is used " - ~ "for the dependency %s. Please use numbered versions instead. Also " - ~ "note that you can still use the %s file to override a certain " - ~ "dependency to use a branch instead.", - d.name, SelectedVersions.defaultFile); + string suggestion = isSDL + ? format(`dependency "%s" repository="git+" version=""`, d.name) + : format(`"%s": {"repository": "git+", "version": ""}`, d.name); + logWarn("Dependency '%s' depends on git branch '%s', which is deprecated.", + d.name.color(Mode.bold), d.spec.version_.toString.color(Mode.bold)); + logWarnTag("", "Specify the git repository and commit hash in your %s:", + (isSDL ? "dub.sdl" : "dub.json").color(Mode.bold)); + logWarnTag("", "%s", suggestion.color(Mode.bold)); } // search for orphan sub configurations @@ -678,7 +685,7 @@ createEdge(cidx, createConfig(d.name, sc)); } - // create a graph of all possible package configurations (package, config) -> (subpackage, subconfig) + // create a graph of all possible package configurations (package, config) -> (sub-package, sub-config) void determineAllConfigs(in Package p) { auto idx = allconfigs_path.countUntil(p.name); @@ -822,7 +829,6 @@ Params: dst = The `BuildSettings` instance to add the build settings to gsettings = Target generator settings - build_type = Name of the build type for_root_package = Selects if the build settings are for the root package or for one of the dependencies. Unittest flags will only be added to the root package. @@ -1563,7 +1569,7 @@ } if (name == "DUB") { - return getDUBExePath(gsettings.platform.compilerBinary); + return getDUBExePath(gsettings.platform.compilerBinary).toNativeString(); } if (name == "ARCH") { @@ -1916,22 +1922,33 @@ /// The default test runner that gets used if none is provided private immutable DefaultTestRunnerCode = q{ -import core.runtime; - -void main() { - version (D_Coverage) { + version(D_BetterC) { + extern(C) int main() { + foreach (module_; allModules) { + foreach (unitTest; __traits(getUnitTests, module_)) { + unitTest(); + } + } + import core.stdc.stdio : puts; + puts("All unit tests have been run successfully."); + return 0; + } } else { - import std.stdio : writeln; - writeln("All unit tests have been run successfully."); + void main() { + version (D_Coverage) { + } else { + import std.stdio : writeln; + writeln("All unit tests have been run successfully."); + } + } + shared static this() { + version (Have_tested) { + import tested; + import core.runtime; + import std.exception; + Runtime.moduleUnitTester = () => true; + enforce(runUnitTests!allModules(new ConsoleTestResultWriter), "Unit tests failed."); + } + } } -} -shared static this() { - version (Have_tested) { - import tested; - import core.runtime; - import std.exception; - Runtime.moduleUnitTester = () => true; - enforce(runUnitTests!allModules(new ConsoleTestResultWriter), "Unit tests failed."); - } -} }; diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d index ce406bc..909e653 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -112,7 +112,7 @@ @Optional ToolchainRequirements toolchainRequirements; /** - * Speficies an optional list of build configurations + * Specifies an optional list of build configurations * * By default, the first configuration present in the package recipe * will be used, except for special configurations (e.g. "unittest"). @@ -155,7 +155,7 @@ * Sub-packages path or definitions * * Sub-packages allow to break component of a large framework into smaller - * packages. In the recipe file, subpackages entry can take one of two forms: + * packages. In the recipe file, sub-packages entry can take one of two forms: * either the path to a sub-folder where a recipe file exists, * or an object of the same format as a recipe file (or `PackageRecipe`). */ @@ -186,9 +186,9 @@ * Given a YAML parser, recurses into `recipe` or use `path` * depending on the node type. * - * Two formats are supported for `subpackages`: a string format, - * which is just the path to the subpackage, and embedding the - * full subpackage recipe into the parent package recipe. + * Two formats are supported for sub-packages: a string format, + * which is just the path to the sub-package, and embedding the + * full sub-package recipe into the parent package recipe. * * To support such a dual syntax, Configy requires the use * of a `fromYAML` method, as it exposes the underlying format. @@ -338,7 +338,7 @@ * Used by Configy to provide rich error message when parsing. * * Exceptions thrown from `validate` methods will be wrapped with field/file - * informations and rethrown from Configy, providing the user + * information and rethrown from Configy, providing the user * with the location of the configuration that triggered the error. */ public void validate () const diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d index facc603..9e10e49 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -9,6 +9,7 @@ import dub.compilers.compiler; import dub.dependency; +import dub.internal.dyaml.stdsumtype; import dub.internal.logging; import dub.internal.sdlang; import dub.internal.vibecompat.inet.path; @@ -17,8 +18,7 @@ import std.algorithm : map; import std.array : array; import std.conv; -import std.string : startsWith; - +import std.string : startsWith, format; void parseSDL(ref PackageRecipe recipe, string sdl, string parent_name, string filename) { @@ -180,29 +180,29 @@ { enforceSDL(t.values.length != 0, "Missing dependency name.", t); enforceSDL(t.values.length == 1, "Multiple dependency names.", t); - auto pkg = expandPackageName(t.values[0].get!string, package_name, t); + auto pkg = expandPackageName(t.values[0].expect!string(t), package_name, t); enforceSDL(pkg !in bs.dependencies, "The dependency '"~pkg~"' is specified more than once.", t); Dependency dep = Dependency.any; auto attrs = t.attributes; if ("path" in attrs) { - dep = Dependency(NativePath(attrs["path"][0].value.get!string)); + dep = Dependency(NativePath(attrs["path"][0].value.expect!string(t, t.fullName ~ " path"))); } else if ("repository" in attrs) { enforceSDL("version" in attrs, "Missing version specification.", t); - dep = Dependency(Repository(attrs["repository"][0].value.get!string, - attrs["version"][0].value.get!string)); + dep = Dependency(Repository(attrs["repository"][0].value.expect!string(t, t.fullName ~ " repository"), + attrs["version"][0].value.expect!string(t, t.fullName ~ " version"))); } else { enforceSDL("version" in attrs, "Missing version specification.", t); - dep = Dependency(attrs["version"][0].value.get!string); + dep = Dependency(attrs["version"][0].value.expect!string(t, t.fullName ~ " version")); } if ("optional" in attrs) - dep.optional = attrs["optional"][0].value.get!bool; + dep.optional = attrs["optional"][0].value.expect!bool(t, t.fullName ~ " optional"); if ("default" in attrs) - dep.default_ = attrs["default"][0].value.get!bool; + dep.default_ = attrs["default"][0].value.expect!bool(t, t.fullName ~ " default"); bs.dependencies[pkg] = dep; @@ -317,7 +317,7 @@ private void parseToolchainRequirements(ref ToolchainRequirements tr, Tag tag) { foreach (attr; tag.attributes) - tr.addRequirement(attr.name, attr.value.get!string); + tr.addRequirement(attr.name, attr.value.expect!string(tag)); } private Tag toSDL(const ref ToolchainRequirements tr) @@ -334,7 +334,6 @@ private string expandPackageName(string name, string parent_name, Tag tag) { import std.algorithm : canFind; - import std.string : format; if (name.startsWith(":")) { enforceSDL(!parent_name.canFind(':'), format("Short-hand packages syntax not allowed within sub packages: %s -> %s", parent_name, name), tag); return parent_name ~ name; @@ -343,64 +342,79 @@ private string stringTagValue(Tag t, bool allow_child_tags = false) { - import std.string : format; enforceSDL(t.values.length > 0, format("Missing string value for '%s'.", t.fullName), t); enforceSDL(t.values.length == 1, format("Expected only one value for '%s'.", t.fullName), t); - enforceSDL(t.values[0].peek!string !is null, format("Expected value of type string for '%s'.", t.fullName), t); enforceSDL(allow_child_tags || t.tags.length == 0, format("No child tags allowed for '%s'.", t.fullName), t); // Q: should attributes be disallowed, or just ignored for forward compatibility reasons? //enforceSDL(t.attributes.length == 0, format("No attributes allowed for '%s'.", t.fullName), t); - return t.values[0].get!string; + return t.values[0].expect!string(t); +} + +private T expect(T)( + Value value, + Tag errorInfo, + string customFieldName = null, + string file = __FILE__, + int line = __LINE__ +) +{ + return value.match!( + (T v) => v, + (fallback) + { + enforceSDL(false, format("Expected value of type " ~ T.stringof ~ " for '%s', but got %s.", + customFieldName.length ? customFieldName : errorInfo.fullName, + typeof(fallback).stringof), + errorInfo, file, line); + return T.init; + } + ); } private string[] stringArrayTagValue(Tag t, bool allow_child_tags = false) { - import std.string : format; enforceSDL(allow_child_tags || t.tags.length == 0, format("No child tags allowed for '%s'.", t.fullName), t); // Q: should attributes be disallowed, or just ignored for forward compatibility reasons? //enforceSDL(t.attributes.length == 0, format("No attributes allowed for '%s'.", t.fullName), t); string[] ret; - foreach (v; t.values) { - enforceSDL(t.values[0].peek!string !is null, format("Values for '%s' must be strings.", t.fullName), t); - ret ~= v.get!string; + foreach (i, v; t.values) { + ret ~= v.expect!string(t, text(t.fullName, "[", i, "]")); } return ret; } -private void parsePlatformStringArray(Tag t, ref string[][string] dst) +private string getPlatformSuffix(Tag t, string file = __FILE__, int line = __LINE__) { string platform; if ("platform" in t.attributes) - platform = t.attributes["platform"][0].value.get!string; - dst[platform] ~= t.values.map!(v => v.get!string).array; + platform = t.attributes["platform"][0].value.expect!string(t, t.fullName ~ " platform", file, line); + return platform; +} + +private void parsePlatformStringArray(Tag t, ref string[][string] dst) +{ + string platform = t.getPlatformSuffix; + dst[platform] ~= t.values.map!(v => v.expect!string(t)).array; } private void parsePlatformStringAA(Tag t, ref string[string][string] dst) { - import std.string : format; - string platform; - if ("platform" in t.attributes) - platform = t.attributes["platform"][0].value.get!string; + string platform = t.getPlatformSuffix; enforceSDL(t.values.length == 2, format("Values for '%s' must be 2 required.", t.fullName), t); - enforceSDL(t.values[0].peek!string !is null, format("Values for '%s' must be strings.", t.fullName), t); - enforceSDL(t.values[1].peek!string !is null, format("Values for '%s' must be strings.", t.fullName), t); - dst[platform][t.values[0].get!string] = t.values[1].get!string; + dst[platform][t.values[0].expect!string(t)] = t.values[1].expect!string(t); } private void parsePlatformEnumArray(E, Es)(Tag t, ref Es[string] dst) { - string platform; - if ("platform" in t.attributes) - platform = t.attributes["platform"][0].value.get!string; + string platform = t.getPlatformSuffix; foreach (v; t.values) { if (platform !in dst) dst[platform] = Es.init; - dst[platform] |= v.get!string.to!E; + dst[platform] |= v.expect!string(t).to!E; } } private void enforceSDL(bool condition, lazy string message, Tag tag, string file = __FILE__, int line = __LINE__) { - import std.string : format; if (!condition) { throw new Exception(format("%s(%s): Error: %s", tag.location.file, tag.location.line + 1, message), file, line); } diff --git a/source/dub/semver.d b/source/dub/semver.d index 7682e84..3edd6f1 100644 --- a/source/dub/semver.d +++ b/source/dub/semver.d @@ -1,8 +1,8 @@ /** - Implementes version validation and comparison according to the semantic + Implements version validation and comparison according to the semantic versioning specification. - The general format of a semantiv version is: a.b.c[-x.y...][+x.y...] + The general format of a semantic version is: a.b.c[-x.y...][+x.y...] a/b/c must be integer numbers with no leading zeros, and x/y/... must be either numbers or identifiers containing only ASCII alphabetic characters or hyphens. Identifiers may not start with a digit. @@ -229,7 +229,7 @@ minor version will be selected. If the patch or minor versions are skipped, the next major version will be selected. - This function corresponds to the semantivs of the "~>" comparison operator's + This function corresponds to the semantics of the "~>" comparison operator's upper bound. The semantics of this are the same as for the "approximate" version @@ -249,7 +249,7 @@ auto to_inc = splitted.length == 3? 1 : 0; splitted = splitted[0 .. to_inc+1]; splitted[to_inc] = to!string(to!int(splitted[to_inc]) + 1); - // Fill up to three compontents to make valid SemVer version. + // Fill up to three components to make valid SemVer version. while (splitted.length < 3) splitted ~= "0"; return splitted.join("."); } @@ -269,7 +269,7 @@ Prerelease and build metadata information is removed. - This implements the "^" comparison operator, which represents "nonbreaking semver compatibility." + This implements the "^" comparison operator, which represents "non-breaking SemVer compatibility." With 0.x.y releases, any release can break. With x.y.z releases, only major releases can break. */ @@ -299,7 +299,7 @@ /** Takes a partial version and expands it to a valid SemVer version. - This function corresponds to the semantivs of the "~>" comparison operator's + This function corresponds to the semantics of the "~>" comparison operator's lower bound. See_Also: `bumpVersion` @@ -322,7 +322,7 @@ assert("1.0.0" == expandVersion("1")); assert("1.0.0" == expandVersion("1.0")); assert("1.0.0" == expandVersion("1.0.0")); - // These are rather excotic variants... + // These are rather exotic variants... assert("1.0.0-pre.release" == expandVersion("1-pre.release")); assert("1.0.0+meta" == expandVersion("1+meta")); assert("1.0.0-pre.release+meta" == expandVersion("1-pre.release+meta")); @@ -345,7 +345,7 @@ } if (anumber && bnumber) { - // the !empty value might be an indentifier instead of a number, but identifiers always have precedence + // the !empty value might be an identifier instead of a number, but identifiers always have precedence if (aempty != bempty) return bempty - aempty; return res; } else { diff --git a/test/colored-output.sh b/test/colored-output.sh index 84d87f4..71380ff 100755 --- a/test/colored-output.sh +++ b/test/colored-output.sh @@ -4,25 +4,32 @@ cd ${CURR_DIR}/1-exec-simple -# Test that --color=off disables colors correctly -${DUB} build --color=off --compiler=${DC} 2>&1 | { ! \grep $'^\x1b\[' -c; } +# Test that --color=never disables colors correctly +printf "Expecting 0: " +${DUB} build --color=never --compiler=${DC} 2>&1 | { ! \grep $'^\x1b\[' -c; } -# Test that --color=automatic detects no TTY correctly -${DUB} build --color=automatic --compiler=${DC} 2>&1 | { ! \grep $'^\x1b\[' -c; } +# Test that --color=auto detects no TTY correctly +printf "Expecting 0: " +${DUB} build --color=auto --compiler=${DC} 2>&1 | { ! \grep $'^\x1b\[' -c; } -# Test that no --color= has same behaviour as --color=automatic +# Test that no --color= has same behaviour as --color=auto +printf "Expecting 0: " ${DUB} build --compiler=${DC} 2>&1 | { ! \grep $'^\x1b\[' -c; } -# Test that --color=on enables colors in any case -${DUB} build --color=on --compiler=${DC} 2>&1 | \grep $'^\x1b\[' -c +# Test that --color=always enables colors in any case +printf "Expecting non-0: " +${DUB} build --color=always --compiler=${DC} 2>&1 | \grep $'^\x1b\[' -c # Test forwarding to dmd flag -color -# Test that --color=on set dmd flag -color -${DUB} build -v --color=on --compiler=${DC} -f 2>&1 | \grep '\-color' -c +# Test that --color=always set dmd flag -color +printf "Expecting non-0: " +${DUB} build -v --color=always --compiler=${DC} -f 2>&1 | \grep '\-color' -c -# Test that --color=off set no dmd flag -${DUB} build -v --color=off --compiler=${DC} -f 2>&1 | { ! \grep '\-color' -c; } +# Test that --color=never set no dmd flag +printf "Expecting 0: " +${DUB} build -v --color=never --compiler=${DC} -f 2>&1 | { ! \grep '\-color' -c; } -# Test that --color=automatic set no dmd flag -${DUB} build -v --color=automatic --compiler=${DC} -f 2>&1 | { ! \grep '\-color' -c; } +# Test that --color=auto set no dmd flag +printf "Expecting 0: " +${DUB} build -v --color=auto --compiler=${DC} -f 2>&1 | { ! \grep '\-color' -c; } diff --git a/test/issue1636-betterC-dub-test.sh b/test/issue1636-betterC-dub-test.sh new file mode 100755 index 0000000..f2062c6 --- /dev/null +++ b/test/issue1636-betterC-dub-test.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +cd ${CURR_DIR}/issue1636-betterC-dub-test + +${DUB} test | grep -c "TEST_WAS_RUN" > /dev/null diff --git a/test/issue1636-betterC-dub-test/.gitignore b/test/issue1636-betterC-dub-test/.gitignore new file mode 100644 index 0000000..53b683b --- /dev/null +++ b/test/issue1636-betterC-dub-test/.gitignore @@ -0,0 +1,4 @@ +test +*.o +*.exe +.dub diff --git a/test/issue1636-betterC-dub-test/.min_frontend b/test/issue1636-betterC-dub-test/.min_frontend new file mode 100644 index 0000000..67aaf4a --- /dev/null +++ b/test/issue1636-betterC-dub-test/.min_frontend @@ -0,0 +1 @@ +2.078 diff --git a/test/issue1636-betterC-dub-test/.no_run b/test/issue1636-betterC-dub-test/.no_run new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/issue1636-betterC-dub-test/.no_run diff --git a/test/issue1636-betterC-dub-test/dub.json b/test/issue1636-betterC-dub-test/dub.json new file mode 100644 index 0000000..afb1093 --- /dev/null +++ b/test/issue1636-betterC-dub-test/dub.json @@ -0,0 +1,4 @@ +{ + "name": "test", + "buildOptions": ["betterC"] +} diff --git a/test/issue1636-betterC-dub-test/source/lib.d b/test/issue1636-betterC-dub-test/source/lib.d new file mode 100644 index 0000000..1d2807e --- /dev/null +++ b/test/issue1636-betterC-dub-test/source/lib.d @@ -0,0 +1,14 @@ +import core.stdc.stdio : printf; + +version(D_BetterC) {} else static assert(false); + +int foo() +{ + return 2; +} + +unittest +{ + assert(foo == 2); + printf("TEST_WAS_RUN\n"); +} diff --git a/test/issue2051_running_unittests_from_dub_single_file_packages_fails.d b/test/issue2051_running_unittests_from_dub_single_file_packages_fails.d index b7e5fbf..a3caf1d 100644 --- a/test/issue2051_running_unittests_from_dub_single_file_packages_fails.d +++ b/test/issue2051_running_unittests_from_dub_single_file_packages_fails.d @@ -1,5 +1,5 @@ /+ dub.sdl: - name "issue2051_running_unittests_from_dub_single_file_packages_fails" + name "issue2051" +/ import std.algorithm : any; diff --git a/test/issue2574-mistyping-commands.sh b/test/issue2574-mistyping-commands.sh new file mode 100755 index 0000000..b239a2a --- /dev/null +++ b/test/issue2574-mistyping-commands.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +. $(dirname "${BASH_SOURCE[0]}")/common.sh + +$DUB upfrade 2>&1 >/dev/null && die $LINENO '"dub upfrade" should not succeed' + +if [ "$($DUB upfrade 2>&1 | grep -Fc "Unknown command: upfrade")" != "1" ]; then + die $LINENO 'Missing Unknown command line' +fi + +if [ "$($DUB upfrade 2>&1 | grep -Fc "Did you mean 'upgrade'?")" != "1" ]; then + die $LINENO 'Missing upgrade suggestion' +fi + +if [ "$($DUB upfrade 2>&1 | grep -Fc "build")" != "0" ]; then + die $LINENO 'Did not expect to see build as a suggestion and did not want a full list of commands' +fi diff --git a/test/removed-dub-obj.sh b/test/removed-dub-obj.sh index 8a168e2..1334f8b 100755 --- a/test/removed-dub-obj.sh +++ b/test/removed-dub-obj.sh @@ -12,9 +12,9 @@ [ -d "$DUB_CACHE_PATH/obj" ] && die $LINENO "$DUB_CACHE_PATH/obj was found" if [[ ${DC} == *"ldc"* ]]; then - if [ ! -f $DUB_CACHE_PATH/~master/build/library-*ldc*/obj/test.o* ]; then + if [ ! -f $DUB_CACHE_PATH/~master/build/library-*/obj/test.o* ]; then ls -lR $DUB_CACHE_PATH - die $LINENO '$DUB_CACHE_PATH/~master/build/library-*ldc*/obj/test.o* was not found' + die $LINENO '$DUB_CACHE_PATH/~master/build/library-*/obj/test.o* was not found' fi fi