Skip to content

Commit

Permalink
commandline: Refactor and streamline special syntaxes
Browse files Browse the repository at this point in the history
All those special syntaxes only trigger if args.length >= 2,
so first we can nest them in a new scope, which also makes
it visually more distinct.

Additionally, the third and second cases were actually inverted:
if the third case was to pass, it means the second case couldn't
have passed (because they check present/absence of an extension,
respectively), so we can swap them and use an else-if.

The result is arguably much more readable, and highlight the fact
that if the first case (stdin) is used, the second case will.
  • Loading branch information
Geod24 committed Jun 10, 2022
1 parent 36ecf32 commit 05e4d41
Showing 1 changed file with 33 additions and 18 deletions.
51 changes: 33 additions & 18 deletions source/dub/commandline.d
Original file line number Diff line number Diff line change
Expand Up @@ -403,28 +403,43 @@ int runDubCommandLine(string[] args)
auto handler = CommandLineHandler(getCommands());
auto commandNames = handler.commandNames();

// special stdin syntax
if (args.length >= 2 && args[1] == "-")
// Special syntaxes need to be handled before regular argument parsing
if (args.length >= 2)
{
auto path = getTempFile("app", ".d");
stdin.byChunk(4096).joiner.toFile(path.toNativeString());
args = args[0] ~ [path.toNativeString()] ~ args[2..$];
}

// Shebang syntax support for files without .d extension
if (args.length >= 2 && !args[1].endsWith(".d") && !args[1].startsWith("-") && !commandNames.canFind(args[1])) {
if (exists(args[1])) {
// Read input source code from stdin
if (args[1] == "-")
{
auto path = getTempFile("app", ".d");
copy(args[1], path.toNativeString());
args[1] = path.toNativeString();
} else if (exists(args[1].setExtension(".d"))) {
args[1] = args[1].setExtension(".d");
stdin.byChunk(4096).joiner.toFile(path.toNativeString());
args = args[0] ~ [path.toNativeString()] ~ args[2..$];
}
}

// special single-file package shebang syntax
if (args.length >= 2 && args[1].endsWith(".d")) {
args = args[0] ~ ["run", "-q", "--temp-build", "--single", args[1], "--"] ~ args[2 ..$];
// Dub has a shebang syntax to be able to use it as script, e.g.
// #/usr/bin/env dub
// With this approach, we need to support the file having
// both the `.d` extension, or having none at all.
// We also need to make sure arguments passed to the script
// are passed to the program, not `dub`, e.g.:
// ./my_dub_script foo bar
// Gives us `args = [ "dub", "./my_dub_script" "foo", "bar" ]`,
// which we need to interpret as:
// `args = [ "dub", "./my_dub_script", "--", "foo", "bar" ]`
if (args[1].endsWith(".d"))
args = args[0] ~ ["run", "-q", "--temp-build", "--single", args[1], "--"] ~ args[2 ..$];

// Here we have a problem: What if the script name is a command name ?
// We have to assume it isn't, and to reduce the risk of false positive
// we only consider the case where the file name is the first argument,
// as the shell invocation cannot be controlled.
else if (!commandNames.canFind(args[1]) && !args[1].startsWith("-")) {
if (exists(args[1])) {
auto path = getTempFile("app", ".d");
copy(args[1], path.toNativeString());
args[1] = path.toNativeString();
} else if (exists(args[1].setExtension(".d"))) {
args[1] = args[1].setExtension(".d");
}
}
}

auto common_args = new CommandArgs(args[1..$]);
Expand Down

0 comments on commit 05e4d41

Please sign in to comment.