Unify and clarify interactive and --exec command error and parse error handling.

Previously, interactive execution and --exec used two models for how a failed
command would impact other commands in the execution.

As an example, consider:

    fdb> set foo bar ; set bar f\00 ; set baz foo

In interactive mode, this had the effect of {foo=bar, baz=foo}.
In --exec mode, this had the effect of {foo=bar}.

With this change, both now have the effect of {foo=bar}.  This is achieved by
prefixing the last parsed command, which is the one that had the error, with a
fake "parse_error" token.

The execution of this would now look like:

    ERROR: malformed escape sequence
    >>> set foo bar
    ERROR: Command failed to completely parse.
    ERROR: Not running partial or malformed command: set bar

Which indicates how much execution occurred and where it halted, identically in
both modes of execution.
This commit is contained in:
Alex Miller 2017-08-21 13:42:01 -07:00
parent d78b29625c
commit 0c7fd0a23d
1 changed files with 25 additions and 13 deletions

View File

@ -2217,33 +2217,45 @@ ACTOR Future<int> cli(CLIOptions opt, LineNoise* plinenoise) {
state UID randomID = g_random->randomUniqueID();
TraceEvent(SevInfo, "CLICommandLog", randomID).detail("command", printable(StringRef(line)));
bool err, partial;
state std::vector<std::vector<StringRef>> parsed = parseLine(line, err, partial);
if (err) {
LogCommand(line, randomID, "ERROR: malformed escape sequence");
is_error = true;
bool malformed, partial;
state std::vector<std::vector<StringRef>> parsed = parseLine(line, malformed, partial);
if (malformed) LogCommand(line, randomID, "ERROR: malformed escape sequence");
if (partial) LogCommand(line, randomID, "ERROR: unterminated quote");
if (malformed || partial) {
if (parsed.size() > 0) {
// Denote via a special token that the command was a parse failure.
auto& last_command = parsed.back();
last_command.insert(last_command.begin(), StringRef((const uint8_t*)"parse_error", strlen("parse_error")));
}
if (partial) {
LogCommand(line, randomID, "ERROR: unterminated quote");
is_error = true;
}
state bool multi = parsed.size() > 1;
is_error = false;
state std::vector<std::vector<StringRef>>::iterator iter;
for (iter = parsed.begin(); iter != parsed.end(); ++iter) {
state std::vector<StringRef> tokens = *iter;
if (opt.exec.present() && is_error) {
if (is_error) {
printf("WARNING: the previous command failed, the remaining commands will not be executed.\n");
return 1;
break;
}
is_error = false;
if (!tokens.size())
continue;
if (tokencmp(tokens[0], "parse_error")) {
printf("ERROR: Command failed to completely parse.\n");
if (tokens.size() > 1) {
printf("ERROR: Not running partial or malformed command:");
for (auto t = tokens.begin() + 1; t != tokens.end(); ++t)
printf(" %s", formatStringRef(*t, true).c_str());
printf("\n");
}
is_error = true;
continue;
}
if (multi) {
printf(">>>");
for (auto t = tokens.begin(); t != tokens.end(); ++t)