1 | // Copyright (C) 2024 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 <QCommandLineParser> |
5 | #include <QCoreApplication> |
6 | #include <QDir> |
7 | #include <QFile> |
8 | #include <QFileInfo> |
9 | #include <QJsonArray> |
10 | #include <QJsonDocument> |
11 | #include <QJsonObject> |
12 | |
13 | #include <private/qqmljscompilerstats_p.h> |
14 | #include <private/qqmljscompilerstatsreporter_p.h> |
15 | |
16 | using namespace Qt::Literals::StringLiterals; |
17 | |
18 | bool saveFormattedStats(const QString &stats, const QString &outputPath) |
19 | { |
20 | QString directory = QFileInfo(outputPath).dir().path(); |
21 | if (!QDir().mkpath(dirPath: directory)) { |
22 | qDebug() << "Could not ensure the existence of" << directory; |
23 | return false; |
24 | } |
25 | |
26 | QFile outputFile(outputPath); |
27 | if (!outputFile.open(flags: QIODevice::Text | QIODevice::WriteOnly)) { |
28 | qDebug() << "Could not open file" << outputPath; |
29 | return false; |
30 | } |
31 | |
32 | if (outputFile.write(data: stats.toLatin1()) == -1) { |
33 | qDebug() << "Could not write formatted AOT stats to" << outputPath; |
34 | return false; |
35 | } else { |
36 | qDebug() << "Formatted AOT stats saved to" << outputPath; |
37 | } |
38 | |
39 | return true; |
40 | } |
41 | |
42 | int main(int argc, char **argv) |
43 | { |
44 | QCoreApplication app(argc, argv); |
45 | QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); |
46 | |
47 | QCommandLineParser parser; |
48 | parser.addHelpOption(); |
49 | parser.setApplicationDescription("Internal development tool." ); |
50 | parser.addPositionalArgument(name: "mode" , description: "Choose whether to aggregate or display aotstats files" , |
51 | syntax: "[aggregate|format]" ); |
52 | parser.addPositionalArgument(name: "input" , description: "Aggregate mode: the aotstatslist file to aggregate. " |
53 | "Format mode: the aotstats file to display." ); |
54 | parser.addPositionalArgument(name: "output" , description: "Aggregate mode: the path where to store the " |
55 | "aggregated aotstats. Format mode: the the path where " |
56 | "the formatted output will be saved." ); |
57 | QCommandLineOption emptyModulesOption("empty-modules" , QCoreApplication::translate(context: "main" , key: "Format mode: File containing a list of modules with no QML files." ), "file" ); |
58 | parser.addOption(commandLineOption: emptyModulesOption); |
59 | QCommandLineOption onlyBytecodeModulesOption("only-bytecode-modules" , QCoreApplication::translate(context: "main" , key: "Format mode: File containing a list of modules for which only the bytecode is generated." ), "file" ); |
60 | parser.addOption(commandLineOption: onlyBytecodeModulesOption); |
61 | parser.process(app); |
62 | |
63 | const auto &positionalArgs = parser.positionalArguments(); |
64 | if (positionalArgs.size() != 3) { |
65 | qDebug().noquote() << parser.helpText(); |
66 | return EXIT_FAILURE; |
67 | } |
68 | |
69 | const auto &mode = positionalArgs.first(); |
70 | if (mode == u"aggregate"_s ) { |
71 | const auto aggregated = QQmlJS::AotStats::aggregateAotstatsList(aotstatsListPath: positionalArgs[1]); |
72 | if (!aggregated.has_value()) |
73 | return EXIT_FAILURE; |
74 | if (!aggregated->saveToDisk(filepath: positionalArgs[2])) |
75 | return EXIT_FAILURE; |
76 | |
77 | } else if (mode == u"format"_s ) { |
78 | const auto aotstats = QQmlJS::AotStats::parseAotstatsFile(aotstatsPath: positionalArgs[1]); |
79 | if (!aotstats.has_value()) |
80 | return EXIT_FAILURE; |
81 | |
82 | const auto emptyModules = parser.isSet(option: emptyModulesOption) |
83 | ? QQmlJS::AotStats::readAllLines(path: parser.value(option: emptyModulesOption)) |
84 | : QStringList(); |
85 | const auto onlyBytecodeModules = parser.isSet(option: onlyBytecodeModulesOption) |
86 | ? QQmlJS::AotStats::readAllLines(path: parser.value(option: onlyBytecodeModulesOption)) |
87 | : QStringList(); |
88 | if (!emptyModules || !onlyBytecodeModules) |
89 | return EXIT_FAILURE; |
90 | |
91 | const QQmlJS::AotStatsReporter reporter(aotstats.value(), emptyModules.value(), |
92 | onlyBytecodeModules.value()); |
93 | if (!saveFormattedStats(stats: reporter.format(), outputPath: positionalArgs[2])) |
94 | return EXIT_FAILURE; |
95 | } |
96 | |
97 | return EXIT_SUCCESS; |
98 | } |
99 | |