Add pedantic argument to allow returning a non-zero exit code in case of errors
This is especially useful to check whether a file is complete, e.g. one might use `tageditor info --validate --pedantic --files …` to check whether the specified files are ok. (If they were truncated there's be an error about it and the command would return a non-zero exit code. Without pedantic this would just return in a non-zero exit code if the file couldn't be parsed at all.)
This commit is contained in:
parent
1e77e0b9e1
commit
b7016f98a2
|
@ -29,9 +29,10 @@ using namespace QtUtilities;
|
|||
|
||||
namespace Cli {
|
||||
|
||||
SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg)
|
||||
SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg, Argument &pedanticArg)
|
||||
: filesArg(filesArg)
|
||||
, verboseArg(verboseArg)
|
||||
, pedanticArg(pedanticArg)
|
||||
, quietArg("quiet", 'q', "suppress printing progress information")
|
||||
, docTitleArg("doc-title", 'd', "specifies the document title (has no affect if not supported by the container)",
|
||||
{ "title of first segment", "title of second segment" })
|
||||
|
@ -152,6 +153,13 @@ int main(int argc, char *argv[])
|
|||
timeSpanFormatArg.setPreDefinedCompletionValues("measures colons seconds");
|
||||
// verbose option
|
||||
ConfigValueArgument verboseArg("verbose", 'v', "be verbose, print debug and info messages");
|
||||
// pedantic options
|
||||
ConfigValueArgument pedanticArg("pedantic", '\0',
|
||||
"return non-zero exit code if a non-fatal problem has been encountered that is at least as severe as the specified severity (or critical if "
|
||||
"none specified)",
|
||||
{ "critical/warning/info/debug" });
|
||||
pedanticArg.setRequiredValueCount(Argument::varValueCount);
|
||||
pedanticArg.setPreDefinedCompletionValues("error warning info debug");
|
||||
// input/output file/files
|
||||
ConfigValueArgument fileArg("file", 'f', "specifies the path of the file to be opened", { "path" });
|
||||
ConfigValueArgument defaultFileArg(fileArg);
|
||||
|
@ -167,8 +175,9 @@ int main(int argc, char *argv[])
|
|||
ConfigValueArgument validateArg(
|
||||
"validate", 'c', "validates the file integrity as accurately as possible; the structure of the file will be parsed completely");
|
||||
OperationArgument displayFileInfoArg("info", 'i', "displays general file information", PROJECT_NAME " info -f /some/dir/*.m4a");
|
||||
displayFileInfoArg.setCallback(std::bind(Cli::displayFileInfo, _1, std::cref(filesArg), std::cref(verboseArg), std::cref(validateArg)));
|
||||
displayFileInfoArg.setSubArguments({ &filesArg, &validateArg, &verboseArg });
|
||||
displayFileInfoArg.setCallback(
|
||||
std::bind(Cli::displayFileInfo, _1, std::cref(filesArg), std::cref(verboseArg), std::cref(pedanticArg), std::cref(validateArg)));
|
||||
displayFileInfoArg.setSubArguments({ &filesArg, &validateArg, &verboseArg, &pedanticArg });
|
||||
// display tag info
|
||||
ConfigValueArgument fieldsArg("fields", 'n', "specifies the field names to be displayed", { "title", "album", "artist", "trackpos" });
|
||||
fieldsArg.setRequiredValueCount(Argument::varValueCount);
|
||||
|
@ -177,11 +186,11 @@ int main(int argc, char *argv[])
|
|||
OperationArgument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)",
|
||||
PROJECT_NAME " get title album artist -f /some/dir/*.m4a");
|
||||
ConfigValueArgument showUnsupportedArg("show-unsupported", 'u', "shows unsupported fields (has only effect when no field names specified)");
|
||||
displayTagInfoArg.setCallback(
|
||||
std::bind(Cli::displayTagInfo, std::cref(fieldsArg), std::cref(showUnsupportedArg), std::cref(filesArg), std::cref(verboseArg)));
|
||||
displayTagInfoArg.setSubArguments({ &fieldsArg, &showUnsupportedArg, &filesArg, &verboseArg });
|
||||
displayTagInfoArg.setCallback(std::bind(Cli::displayTagInfo, std::cref(fieldsArg), std::cref(showUnsupportedArg), std::cref(filesArg),
|
||||
std::cref(verboseArg), std::cref(pedanticArg)));
|
||||
displayTagInfoArg.setSubArguments({ &fieldsArg, &showUnsupportedArg, &filesArg, &verboseArg, &pedanticArg });
|
||||
// set tag info
|
||||
Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg);
|
||||
Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg, pedanticArg);
|
||||
// extract cover
|
||||
ConfigValueArgument fieldArg("field", 'n', "specifies the field to be extracted", { "field name" });
|
||||
fieldArg.setImplicit(true);
|
||||
|
|
|
@ -160,40 +160,58 @@ string incremented(const string &str, unsigned int toIncrement)
|
|||
return res;
|
||||
}
|
||||
|
||||
void printDiagMessages(const Diagnostics &diag, const char *head, bool beVerbose)
|
||||
void printDiagMessages(const Diagnostics &diag, const char *head, bool beVerbose, const CppUtilities::Argument *pedanticArg)
|
||||
{
|
||||
if (diag.empty()) {
|
||||
return;
|
||||
}
|
||||
if (!beVerbose) {
|
||||
for (const auto &message : diag) {
|
||||
switch (message.level()) {
|
||||
case DiagLevel::Debug:
|
||||
case DiagLevel::Information:
|
||||
break;
|
||||
default:
|
||||
goto printDiagMsg;
|
||||
}
|
||||
|
||||
// set exit code to failure if there are diag messages considered bad enough
|
||||
auto minLevel = beVerbose ? DiagLevel::Information : DiagLevel::Warning;
|
||||
auto badExitLevel = DiagLevel::Fatal;
|
||||
if (pedanticArg && pedanticArg->isPresent()) {
|
||||
const auto &values = pedanticArg->values();
|
||||
if (values.empty() || values.front() == "error"sv || values.front() == "critical"sv) {
|
||||
badExitLevel = DiagLevel::Critical;
|
||||
} else if (values.front() == "warning"sv) {
|
||||
badExitLevel = DiagLevel::Warning;
|
||||
} else if (values.front() == "info"sv) {
|
||||
badExitLevel = minLevel = DiagLevel::Information;
|
||||
} else {
|
||||
badExitLevel = minLevel = DiagLevel::Debug;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
printDiagMsg:
|
||||
// set exit code if there are severe enough messages and check whether there's something to print
|
||||
auto hasAnythingToPrint = false;
|
||||
for (const auto &message : diag) {
|
||||
if (message.level() >= badExitLevel) {
|
||||
exitCode = EXIT_PARSING_FAILURE;
|
||||
}
|
||||
if (message.level() >= minLevel) {
|
||||
hasAnythingToPrint = true;
|
||||
}
|
||||
if (exitCode != EXIT_SUCCESS && hasAnythingToPrint) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// print diag messages if there's anything to print
|
||||
if (!hasAnythingToPrint) {
|
||||
return;
|
||||
}
|
||||
if (head) {
|
||||
cerr << " - " << head << endl;
|
||||
}
|
||||
for (const auto &message : diag) {
|
||||
if (message.level() < minLevel) {
|
||||
continue;
|
||||
}
|
||||
switch (message.level()) {
|
||||
case DiagLevel::Debug:
|
||||
if (!beVerbose) {
|
||||
continue;
|
||||
}
|
||||
cerr << " Debug ";
|
||||
break;
|
||||
case DiagLevel::Information:
|
||||
if (!beVerbose) {
|
||||
continue;
|
||||
}
|
||||
cerr << " Information ";
|
||||
break;
|
||||
case DiagLevel::Warning:
|
||||
|
@ -210,9 +228,6 @@ printDiagMsg:
|
|||
setStyle(cerr, TextAttribute::Bold);
|
||||
cerr << " Error ";
|
||||
setStyle(cerr, TextAttribute::Reset);
|
||||
if (message.level() == DiagLevel::Fatal && exitCode == EXIT_SUCCESS) {
|
||||
exitCode = EXIT_PARSING_FAILURE;
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
|
|
@ -258,7 +258,8 @@ constexpr bool isDigit(char c)
|
|||
|
||||
std::string incremented(const std::string &str, unsigned int toIncrement = 1);
|
||||
|
||||
void printDiagMessages(const TagParser::Diagnostics &diag, const char *head = nullptr, bool beVerbose = false);
|
||||
void printDiagMessages(
|
||||
const TagParser::Diagnostics &diag, const char *head = nullptr, bool beVerbose = false, const CppUtilities::Argument *pedanticArg = nullptr);
|
||||
void printProperty(const char *propName, std::string_view value, const char *suffix = nullptr, CppUtilities::Indentation indentation = 4);
|
||||
void printProperty(const char *propName, ElementPosition elementPosition, const char *suffix = nullptr, CppUtilities::Indentation indentation = 4);
|
||||
|
||||
|
|
|
@ -167,7 +167,8 @@ void generateFileInfo(const ArgumentOccurrence &, const Argument &inputFileArg,
|
|||
#endif
|
||||
}
|
||||
|
||||
void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const Argument &verboseArg, const Argument &validateArg)
|
||||
void displayFileInfo(
|
||||
const ArgumentOccurrence &, const Argument &filesArg, const Argument &verboseArg, const Argument &pedanticArg, const Argument &validateArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
|
||||
|
@ -348,12 +349,13 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const
|
|||
exitCode = EXIT_IO_FAILURE;
|
||||
}
|
||||
|
||||
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent());
|
||||
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent(), &pedanticArg);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void displayTagInfo(const Argument &fieldsArg, const Argument &showUnsupportedArg, const Argument &filesArg, const Argument &verboseArg)
|
||||
void displayTagInfo(
|
||||
const Argument &fieldsArg, const Argument &showUnsupportedArg, const Argument &filesArg, const Argument &verboseArg, const Argument &pedanticArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
|
||||
|
@ -412,7 +414,7 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &showUnsupportedAr
|
|||
cerr << Phrases::Error << "An IO error occurred when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
||||
exitCode = EXIT_IO_FAILURE;
|
||||
}
|
||||
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent());
|
||||
printDiagMessages(diag, "Diagnostic messages:", verboseArg.isPresent(), &pedanticArg);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
@ -952,7 +954,7 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
exitCode = EXIT_IO_FAILURE;
|
||||
}
|
||||
|
||||
printDiagMessages(diag, "Diagnostic messages:", args.verboseArg.isPresent());
|
||||
printDiagMessages(diag, "Diagnostic messages:", args.verboseArg.isPresent(), &args.pedanticArg);
|
||||
|
||||
// continue with next file
|
||||
++fileIndex;
|
||||
|
|
|
@ -13,9 +13,10 @@ class Argument;
|
|||
namespace Cli {
|
||||
|
||||
struct SetTagInfoArgs {
|
||||
SetTagInfoArgs(CppUtilities::Argument &filesArg, CppUtilities::Argument &verboseArg);
|
||||
SetTagInfoArgs(CppUtilities::Argument &filesArg, CppUtilities::Argument &verboseArg, CppUtilities::Argument &pedanticArg);
|
||||
CppUtilities::Argument &filesArg;
|
||||
CppUtilities::Argument &verboseArg;
|
||||
CppUtilities::Argument &pedanticArg;
|
||||
CppUtilities::ConfigValueArgument quietArg;
|
||||
CppUtilities::ConfigValueArgument docTitleArg;
|
||||
CppUtilities::ConfigValueArgument removeOtherFieldsArg;
|
||||
|
@ -56,11 +57,11 @@ extern int exitCode;
|
|||
void applyGeneralConfig(const CppUtilities::Argument &timeSapnFormatArg);
|
||||
void printFieldNames(const CppUtilities::ArgumentOccurrence &occurrence);
|
||||
void displayFileInfo(const CppUtilities::ArgumentOccurrence &, const CppUtilities::Argument &filesArg, const CppUtilities::Argument &verboseArg,
|
||||
const CppUtilities::Argument &validateArg);
|
||||
const CppUtilities::Argument &pedanticArg, const CppUtilities::Argument &validateArg);
|
||||
void generateFileInfo(const CppUtilities::ArgumentOccurrence &, const CppUtilities::Argument &inputFileArg,
|
||||
const CppUtilities::Argument &outputFileArg, const CppUtilities::Argument &validateArg);
|
||||
void displayTagInfo(const CppUtilities::Argument &fieldsArg, const CppUtilities::Argument &showUnsupportedArg, const CppUtilities::Argument &filesArg,
|
||||
const CppUtilities::Argument &verboseArg);
|
||||
const CppUtilities::Argument &verboseArg, const CppUtilities::Argument &pedanticArg);
|
||||
void setTagInfo(const Cli::SetTagInfoArgs &args);
|
||||
void extractField(const CppUtilities::Argument &fieldArg, const CppUtilities::Argument &attachmentArg, const CppUtilities::Argument &inputFilesArg,
|
||||
const CppUtilities::Argument &outputFileArg, const CppUtilities::Argument &indexArg, const CppUtilities::Argument &verboseArg);
|
||||
|
|
Loading…
Reference in New Issue