19int main(
int argc,
char *argv[])
21 QCoreApplication a(argc, argv);
22 a.setApplicationName(u"Qt Attributions Scanner"_s);
23 a.setApplicationVersion(u"1.3"_s);
25 QCommandLineParser parser;
26 parser.setApplicationDescription(tr(
"Processes attribution files in Qt sources."));
27 parser.addPositionalArgument(u"paths"_s,
28 tr(
"Paths to qt_attribution.json/README.chromium files, "
29 "or directories to be scannned recursively."));
30 parser.addHelpOption();
31 parser.addVersionOption();
33 QCommandLineOption generatorOption(u"output-format"_s,
34 tr(
"Output format (\"qdoc\", \"json\")."),
35 u"generator"_s, u"qdoc"_s);
36 QCommandLineOption inputFormatOption(u"input-files"_s,
37 tr(
"Input files (\"qt_attributions\" scans for "
38 "qt_attribution.json, \"chromium_attributions\" for "
39 "README.Chromium, \"all\" for both)."),
41 u"qt_attributions"_s);
42 QCommandLineOption filterOption(u"filter"_s,
43 tr(
"Filter packages according to <filter> "
44 "(e.g. QDocModule=qtcore)"),
46 QCommandLineOption baseDirOption(u"basedir"_s,
47 tr(
"Paths in documentation are made relative to this "
50 QCommandLineOption noCheckPathsOption(
52 tr(
"Do not check whether referenced file paths exist in basedir."));
53 QCommandLineOption outputOption({ u"o"_s, u"output"_s },
54 tr(
"Write generated data to <file>."),
56 QCommandLineOption verboseOption(u"verbose"_s, tr(
"Verbose output."));
57 QCommandLineOption silentOption({ u"s"_s, u"silent"_s }, tr(
"Minimal output."));
59 parser.addOption(generatorOption);
60 parser.addOption(inputFormatOption);
61 parser.addOption(filterOption);
62 parser.addOption(baseDirOption);
63 parser.addOption(noCheckPathsOption);
64 parser.addOption(outputOption);
65 parser.addOption(verboseOption);
66 parser.addOption(silentOption);
68 parser.process(a.arguments());
71 Checks checks = Check::All;
72 checks.setFlag(Check::Paths, !parser.isSet(noCheckPathsOption));
75 if (parser.isSet(verboseOption) && parser.isSet(silentOption)) {
76 std::cerr << qPrintable(tr(
"--verbose and --silent cannot be set simultaneously.")) << std::endl;
80 if (parser.isSet(verboseOption))
82 else if (parser.isSet(silentOption))
85 if (parser.positionalArguments().size() == 0)
88 const QStringList paths = parser.positionalArguments();
90 QString inputFormat = parser.value(inputFormatOption);
91 Scanner::InputFormats formats;
92 if (inputFormat ==
"qt_attributions"_L1)
94 else if (inputFormat ==
"chromium_attributions"_L1)
96 else if (inputFormat ==
"all"_L1)
99 std::cerr << qPrintable(tr(
"%1 is not a valid input-files argument").arg(inputFormat)) << std::endl << std::endl;
104 QList<Package> packages;
105 for (
const QString &path: paths) {
106 const QFileInfo pathInfo(path);
107 if (pathInfo.isDir()) {
108 if (logLevel == VerboseLog)
109 std::cerr << qPrintable(tr(
"Recursively scanning %1 for attribution files...").arg(
110 QDir::toNativeSeparators(path))) << std::endl;
111 std::optional<QList<Package>> p
112 = Scanner::scanDirectory(path, formats, checks, logLevel);
116 }
else if (pathInfo.isFile()) {
117 std::optional<QList<Package>> p = Scanner::readFile(path, checks, logLevel);
123 std::cerr << qPrintable(tr(
"%1 is not a valid file or directory.").arg(
124 QDir::toNativeSeparators(path))) << std::endl << std::endl;
130 if (parser.isSet(filterOption)) {
134 packages.erase(std::remove_if(packages.begin(), packages.end(),
135 [&filter](
const Package &p) {
return !filter(p); }),
139 if (logLevel == VerboseLog)
140 std::cerr << qPrintable(tr(
"%1 packages found.").arg(packages.size())) << std::endl;
143 QFile outFile(parser.value(outputOption));
144 QTextStream out(stdout);
145 if (!outFile.fileName().isEmpty()) {
146 if (!outFile.open(QFile::WriteOnly)) {
147 std::cerr << qPrintable(tr(
"Cannot open %1 for writing.").arg(
148 QDir::toNativeSeparators(outFile.fileName())))
152 out.setDevice(&outFile);
156 QString generator = parser.value(generatorOption);
157 if (generator ==
"qdoc"_L1) {
158 QString baseDirectory = parser.value(baseDirOption);
159 if (baseDirectory.isEmpty()) {
160 if (paths.size() != 1) {
161 std::cerr << qPrintable(tr(
"baseDir option is not optional."));
165 const QFileInfo pathInfo(paths.last());
166 if (pathInfo.isDir()) {
168 baseDirectory = pathInfo.dir().absoluteFilePath(u".."_s);
170 baseDirectory = pathInfo.absoluteDir().absoluteFilePath(u".."_s);
175 }
else if (generator ==
"json"_L1) {
178 std::cerr << qPrintable(tr(
"Unknown output-format %1.").arg(generator)) << std::endl;
182 if (logLevel == VerboseLog)
183 std::cerr << qPrintable(tr(
"Processing is done.")) << std::endl;