1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "jsongenerator.h"
5#include "logging.h"
6#include "packagefilter.h"
7#include "qdocgenerator.h"
8#include "scanner.h"
9
10#include <QtCore/qcommandlineparser.h>
11#include <QtCore/qcoreapplication.h>
12#include <QtCore/qdir.h>
13#include <QtCore/qfile.h>
14
15#include <iostream>
16
17using namespace Qt::Literals::StringLiterals;
18
19int main(int argc, char *argv[])
20{
21 QCoreApplication a(argc, argv);
22 a.setApplicationName(u"Qt Attributions Scanner"_s);
23 a.setApplicationVersion(u"1.3"_s);
24
25 QCommandLineParser parser;
26 parser.setApplicationDescription(tr(key: "Processes attribution files in Qt sources."));
27 parser.addPositionalArgument(name: u"paths"_s,
28 description: tr(key: "Paths to qt_attribution.json/README.chromium files, "
29 "or directories to be scannned recursively."));
30 parser.addHelpOption();
31 parser.addVersionOption();
32
33 QCommandLineOption generatorOption(u"output-format"_s,
34 tr(key: "Output format (\"qdoc\", \"json\")."),
35 u"generator"_s, u"qdoc"_s);
36 QCommandLineOption inputFormatOption(u"input-files"_s,
37 tr(key: "Input files (\"qt_attributions\" scans for "
38 "qt_attribution.json, \"chromium_attributions\" for "
39 "README.Chromium, \"all\" for both)."),
40 u"input_format"_s,
41 u"qt_attributions"_s);
42 QCommandLineOption filterOption(u"filter"_s,
43 tr(key: "Filter packages according to <filter> "
44 "(e.g. QDocModule=qtcore)"),
45 u"expression"_s);
46 QCommandLineOption baseDirOption(u"basedir"_s,
47 tr(key: "Paths in documentation are made relative to this "
48 "directory."),
49 u"directory"_s);
50 QCommandLineOption noCheckPathsOption(
51 u"no-check-paths"_s,
52 tr(key: "Do not check whether referenced file paths exist in basedir."));
53 QCommandLineOption outputOption({ u"o"_s, u"output"_s },
54 tr(key: "Write generated data to <file>."),
55 u"file"_s);
56 QCommandLineOption verboseOption(u"verbose"_s, tr(key: "Verbose output."));
57 QCommandLineOption silentOption({ u"s"_s, u"silent"_s }, tr(key: "Minimal output."));
58
59 parser.addOption(commandLineOption: generatorOption);
60 parser.addOption(commandLineOption: inputFormatOption);
61 parser.addOption(commandLineOption: filterOption);
62 parser.addOption(commandLineOption: baseDirOption);
63 parser.addOption(commandLineOption: noCheckPathsOption);
64 parser.addOption(commandLineOption: outputOption);
65 parser.addOption(commandLineOption: verboseOption);
66 parser.addOption(commandLineOption: silentOption);
67
68 parser.process(arguments: a.arguments());
69
70 using Scanner::Checks, Scanner::Check;
71 Checks checks = Check::All;
72 checks.setFlag(flag: Check::Paths, on: !parser.isSet(option: noCheckPathsOption));
73
74 LogLevel logLevel = NormalLog;
75 if (parser.isSet(option: verboseOption) && parser.isSet(option: silentOption)) {
76 std::cerr << qPrintable(tr("--verbose and --silent cannot be set simultaneously.")) << std::endl;
77 parser.showHelp(exitCode: 1);
78 }
79
80 if (parser.isSet(option: verboseOption))
81 logLevel = VerboseLog;
82 else if (parser.isSet(option: silentOption))
83 logLevel = SilentLog;
84
85 if (parser.positionalArguments().size() == 0)
86 parser.showHelp(exitCode: 2);
87
88 const QStringList paths = parser.positionalArguments();
89
90 QString inputFormat = parser.value(option: inputFormatOption);
91 Scanner::InputFormats formats;
92 if (inputFormat == "qt_attributions"_L1)
93 formats = Scanner::InputFormat::QtAttributions;
94 else if (inputFormat == "chromium_attributions"_L1)
95 formats = Scanner::InputFormat::ChromiumAttributions;
96 else if (inputFormat == "all"_L1)
97 formats = Scanner::InputFormat::QtAttributions | Scanner::InputFormat::ChromiumAttributions;
98 else {
99 std::cerr << qPrintable(tr("%1 is not a valid input-files argument").arg(inputFormat)) << std::endl << std::endl;
100 parser.showHelp(exitCode: 8);
101 }
102
103 // Parse the attribution files
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(directory: path, inputFormats: formats, checks, logLevel);
113 if (!p)
114 return 1;
115 packages.append(l: *p);
116 } else if (pathInfo.isFile()) {
117 std::optional<QList<Package>> p = Scanner::readFile(filePath: path, checks, logLevel);
118 if (!p)
119 return 1;
120 packages.append(l: *p);
121
122 } else {
123 std::cerr << qPrintable(tr("%1 is not a valid file or directory.").arg(
124 QDir::toNativeSeparators(path))) << std::endl << std::endl;
125 parser.showHelp(exitCode: 7);
126 }
127 }
128
129 // Apply the filter
130 if (parser.isSet(option: filterOption)) {
131 PackageFilter filter(parser.value(option: filterOption));
132 if (filter.type == PackageFilter::InvalidFilter)
133 return 4;
134 packages.erase(abegin: std::remove_if(first: packages.begin(), last: packages.end(),
135 pred: [&filter](const Package &p) { return !filter(p); }),
136 aend: packages.end());
137 }
138
139 if (logLevel == VerboseLog)
140 std::cerr << qPrintable(tr("%1 packages found.").arg(packages.size())) << std::endl;
141
142 // Prepare the output text stream
143 QFile outFile(parser.value(option: outputOption));
144 QTextStream out(stdout);
145 if (!outFile.fileName().isEmpty()) {
146 if (!outFile.open(flags: QFile::WriteOnly)) {
147 std::cerr << qPrintable(tr("Cannot open %1 for writing.").arg(
148 QDir::toNativeSeparators(outFile.fileName())))
149 << std::endl;
150 return 5;
151 }
152 out.setDevice(&outFile);
153 }
154
155 // Generate the output and write it
156 QString generator = parser.value(option: generatorOption);
157 if (generator == "qdoc"_L1) {
158 QString baseDirectory = parser.value(option: baseDirOption);
159 if (baseDirectory.isEmpty()) {
160 if (paths.size() != 1) {
161 std::cerr << qPrintable(tr("baseDir option is not optional."));
162 return 1;
163 }
164
165 const QFileInfo pathInfo(paths.last());
166 if (pathInfo.isDir()) {
167 // include top level module name in printed paths
168 baseDirectory = pathInfo.dir().absoluteFilePath(fileName: u".."_s);
169 } else {
170 baseDirectory = pathInfo.absoluteDir().absoluteFilePath(fileName: u".."_s);
171 }
172 }
173
174 QDocGenerator::generate(out, packages, baseDirectory, logLevel);
175 } else if (generator == "json"_L1) {
176 JsonGenerator::generate(out, packages, logLevel);
177 } else {
178 std::cerr << qPrintable(tr("Unknown output-format %1.").arg(generator)) << std::endl;
179 return 6;
180 }
181
182 if (logLevel == VerboseLog)
183 std::cerr << qPrintable(tr("Processing is done.")) << std::endl;
184
185 return 0;
186}
187

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qttools/src/qtattributionsscanner/main.cpp