1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "jsongenerator.h"
30#include "logging.h"
31#include "packagefilter.h"
32#include "qdocgenerator.h"
33#include "scanner.h"
34
35#include <QtCore/qcommandlineparser.h>
36#include <QtCore/qcoreapplication.h>
37#include <QtCore/qdir.h>
38#include <QtCore/qfile.h>
39
40#include <iostream>
41
42
43int main(int argc, char *argv[])
44{
45 QCoreApplication a(argc, argv);
46 a.setApplicationName(QStringLiteral("Qt Attributions Scanner"));
47 a.setApplicationVersion(QStringLiteral("1.1"));
48
49 QCommandLineParser parser;
50 parser.setApplicationDescription(tr(key: "Processes attribution files in Qt sources."));
51 parser.addPositionalArgument(QStringLiteral("path"),
52 description: tr(key: "Path to a qt_attribution.json/README.chromium file, "
53 "or a directory to be scannned recursively."));
54 parser.addHelpOption();
55 parser.addVersionOption();
56
57 QCommandLineOption generatorOption(QStringLiteral("output-format"),
58 tr(key: "Output format (\"qdoc\", \"json\")."),
59 QStringLiteral("generator"),
60 QStringLiteral("qdoc"));
61 QCommandLineOption inputFormatOption(QStringLiteral("input-files"),
62 tr(key: "Input files (\"qt_attributions\" scans for qt_attribution.json, "
63 "\"chromium_attributions\" for README.Chromium, \"all\" for both)."),
64 QStringLiteral("input_format"),
65 QStringLiteral("qt_attributions"));
66 QCommandLineOption filterOption(QStringLiteral("filter"),
67 tr(key: "Filter packages according to <filter> (e.g. QDocModule=qtcore)"),
68 QStringLiteral("expression"));
69 QCommandLineOption baseDirOption(QStringLiteral("basedir"),
70 tr(key: "Paths in documentation are made relative to this "
71 "directory."),
72 QStringLiteral("directory"));
73 QCommandLineOption outputOption({ QStringLiteral("o"), QStringLiteral("output") },
74 tr(key: "Write generated data to <file>."),
75 QStringLiteral("file"));
76 QCommandLineOption verboseOption(QStringLiteral("verbose"),
77 tr(key: "Verbose output."));
78 QCommandLineOption silentOption({ QStringLiteral("s"), QStringLiteral("silent") },
79 tr(key: "Minimal output."));
80
81 parser.addOption(commandLineOption: generatorOption);
82 parser.addOption(commandLineOption: inputFormatOption);
83 parser.addOption(commandLineOption: filterOption);
84 parser.addOption(commandLineOption: baseDirOption);
85 parser.addOption(commandLineOption: outputOption);
86 parser.addOption(commandLineOption: verboseOption);
87 parser.addOption(commandLineOption: silentOption);
88
89 parser.process(arguments: a.arguments());
90
91 LogLevel logLevel = NormalLog;
92 if (parser.isSet(option: verboseOption) && parser.isSet(option: silentOption)) {
93 std::cerr << qPrintable(tr("--verbose and --silent cannot be set simultaneously.")) << std::endl;
94 parser.showHelp(exitCode: 1);
95 }
96
97 if (parser.isSet(option: verboseOption))
98 logLevel = VerboseLog;
99 else if (parser.isSet(option: silentOption))
100 logLevel = SilentLog;
101
102 if (parser.positionalArguments().size() != 1)
103 parser.showHelp(exitCode: 2);
104
105 const QString path = parser.positionalArguments().constLast();
106
107 QString inputFormat = parser.value(option: inputFormatOption);
108 Scanner::InputFormats formats;
109 if (inputFormat == QLatin1String("qt_attributions"))
110 formats = Scanner::InputFormat::QtAttributions;
111 else if (inputFormat == QLatin1String("chromium_attributions"))
112 formats = Scanner::InputFormat::ChromiumAttributions;
113 else if (inputFormat == QLatin1String("all"))
114 formats = Scanner::InputFormat::QtAttributions | Scanner::InputFormat::ChromiumAttributions;
115 else {
116 std::cerr << qPrintable(tr("%1 is not a valid input-files argument").arg(inputFormat)) << std::endl << std::endl;
117 parser.showHelp(exitCode: 8);
118 }
119
120 // Parse the attribution files
121 QVector<Package> packages;
122 const QFileInfo pathInfo(path);
123 if (pathInfo.isDir()) {
124 if (logLevel == VerboseLog)
125 std::cerr << qPrintable(tr("Recursively scanning %1 for attribution files...").arg(
126 QDir::toNativeSeparators(path))) << std::endl;
127 packages = Scanner::scanDirectory(directory: path, inputFormats: formats, logLevel);
128 } else if (pathInfo.isFile()) {
129 packages = Scanner::readFile(filePath: path, logLevel);
130 } else {
131 std::cerr << qPrintable(tr("%1 is not a valid file or directory.").arg(
132 QDir::toNativeSeparators(path))) << std::endl << std::endl;
133 parser.showHelp(exitCode: 7);
134 }
135
136 // Apply the filter
137 if (parser.isSet(option: filterOption)) {
138 PackageFilter filter(parser.value(option: filterOption));
139 if (filter.type == PackageFilter::InvalidFilter)
140 return 4;
141 packages.erase(abegin: std::remove_if(first: packages.begin(), last: packages.end(),
142 pred: [&filter](const Package &p) { return !filter(p); }),
143 aend: packages.end());
144 }
145
146 if (logLevel == VerboseLog)
147 std::cerr << qPrintable(tr("%1 packages found.").arg(packages.size())) << std::endl;
148
149 // Prepare the output text stream
150 QTextStream out(stdout);
151 QFile outFile(parser.value(option: outputOption));
152 if (!outFile.fileName().isEmpty()) {
153 if (!outFile.open(flags: QFile::WriteOnly)) {
154 std::cerr << qPrintable(tr("Cannot open %1 for writing.").arg(
155 QDir::toNativeSeparators(outFile.fileName())))
156 << std::endl;
157 return 5;
158 }
159 out.setDevice(&outFile);
160 }
161
162 // Generate the output and write it
163 QString generator = parser.value(option: generatorOption);
164 out.setCodec("UTF-8");
165 if (generator == QLatin1String("qdoc")) {
166 QString baseDirectory = parser.value(option: baseDirOption);
167 if (baseDirectory.isEmpty()) {
168 if (pathInfo.isDir()) {
169 // include top level module name in printed paths
170 baseDirectory = pathInfo.dir().absoluteFilePath(QStringLiteral(".."));
171 } else {
172 baseDirectory = pathInfo.absoluteDir().absoluteFilePath(QStringLiteral(".."));
173 }
174 }
175
176 QDocGenerator::generate(out, packages, baseDirectory, logLevel);
177 } else if (generator == QLatin1String("json")) {
178 JsonGenerator::generate(out, packages, logLevel);
179 } else {
180 std::cerr << qPrintable(tr("Unknown output-format %1.").arg(generator)) << std::endl;
181 return 6;
182 }
183
184 if (logLevel == VerboseLog)
185 std::cerr << qPrintable(tr("Processing is done.")) << std::endl;
186
187 return 0;
188}
189

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