File indexing completed on 2024-05-19 05:42:03
0001 // ct_lvtclp_codebase_db.m.cpp -*-C++-*-- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtclp_compilerutil.h> 0021 #include <ct_lvtmdb_objectstore.h> 0022 #include <ct_lvtmdb_soci_reader.h> 0023 #include <ct_lvtmdb_soci_writer.h> 0024 0025 #include <algorithm> 0026 #include <cstdlib> 0027 #include <filesystem> 0028 #include <iostream> 0029 #include <string> 0030 #include <vector> 0031 0032 #include <QtGlobal> 0033 0034 #ifdef Q_OS_WINDOWS 0035 #include <stdio.h> 0036 #include <windows.h> 0037 #else 0038 #include <csignal> 0039 #endif 0040 0041 #include <QCommandLineOption> 0042 #include <QCommandLineParser> 0043 #include <QCoreApplication> 0044 #include <QDebug> 0045 #include <QFileInfo> 0046 #include <QJsonDocument> 0047 #include <QJsonObject> 0048 #include <QString> 0049 #include <QStringList> 0050 0051 namespace { 0052 0053 struct CommandLineArgs { 0054 QList<QString> databases; 0055 QString resultingDb; 0056 bool silent = false; 0057 bool force = false; 0058 }; 0059 0060 enum CommandLineParseResult { Ok, Error, Help }; 0061 0062 CommandLineParseResult parseCommandLine(QCommandLineParser& parser, CommandLineArgs& args, std::string& errorMessage) 0063 { 0064 parser.setApplicationDescription("Build code database"); 0065 0066 const QCommandLineOption outputFile({"output", "o"}, "Output database file", "OUTPUT_FILE", ""); 0067 const QCommandLineOption databases("database", 0068 "Path to a single database to be merged. specify it multiple times.", 0069 "DATABASES", 0070 ""); 0071 const QCommandLineOption silent("silent", "supress output"); 0072 const QCommandLineOption force("force", "overwrite the output file if it exists."); 0073 const QCommandLineOption helpOption = parser.addHelpOption(); 0074 0075 parser.addOptions({outputFile, databases, force, silent, helpOption}); 0076 0077 if (!parser.parse(QCoreApplication::arguments())) { 0078 errorMessage = qPrintable(parser.errorText()); 0079 return CommandLineParseResult::Error; 0080 } 0081 0082 if (parser.isSet(force)) { 0083 args.force = true; 0084 } 0085 0086 if (!parser.isSet(outputFile)) { 0087 errorMessage = "Missing output file"; 0088 return CommandLineParseResult::Error; 0089 } 0090 0091 if (!parser.isSet(databases)) { 0092 errorMessage = "Missing database parameter, please specify with --database <filename.db>"; 0093 return CommandLineParseResult::Error; 0094 } 0095 0096 const QString oFile = parser.value(outputFile); 0097 if (!oFile.endsWith("db") || oFile.size() <= 3) { 0098 errorMessage = "output database must be a in the format file.db"; 0099 return CommandLineParseResult::Error; 0100 } 0101 0102 if (parser.isSet(helpOption)) { 0103 return CommandLineParseResult::Help; 0104 } 0105 0106 args.databases = parser.values(databases); 0107 for (const auto& db : std::as_const(args.databases)) { 0108 QFileInfo info(db); 0109 if (!info.exists()) { 0110 errorMessage = (db + " is not a file").toStdString(); 0111 } 0112 } 0113 0114 args.resultingDb = oFile; 0115 args.silent = parser.isSet("silent"); 0116 0117 return CommandLineParseResult::Ok; 0118 } 0119 0120 } // namespace 0121 0122 #ifdef Q_OS_WINDOWS 0123 BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) 0124 { 0125 switch (fdwCtrlType) { 0126 case CTRL_C_EVENT: 0127 exit(1); 0128 0129 case CTRL_CLOSE_EVENT: 0130 exit(1); 0131 default: 0132 return false; 0133 } 0134 return false; 0135 } 0136 #else 0137 void signal_callback_handler(int signum) 0138 { 0139 exit(signum); 0140 } 0141 #endif 0142 0143 int main(int argc, char **argv) 0144 { 0145 QCoreApplication app(argc, argv); 0146 #ifdef Q_OS_WINDOWS 0147 SetConsoleCtrlHandler(CtrlHandler, TRUE); 0148 #else 0149 (void) signal(SIGINT, signal_callback_handler); 0150 #endif 0151 QCommandLineParser parser; 0152 CommandLineArgs args; 0153 std::string errorMessage; 0154 0155 switch (parseCommandLine(parser, args, errorMessage)) { 0156 case CommandLineParseResult::Ok: 0157 break; 0158 case CommandLineParseResult::Error: 0159 if (!errorMessage.empty()) { 0160 std::cerr << errorMessage << "\n\n"; 0161 } 0162 parser.showHelp(); 0163 Q_UNREACHABLE(); 0164 case CommandLineParseResult::Help: 0165 parser.showHelp(); 0166 Q_UNREACHABLE(); 0167 } 0168 0169 std::filesystem::path outputDbPath = args.resultingDb.toStdString(); 0170 if (!args.force && std::filesystem::exists(outputDbPath)) { 0171 qInfo() << "Resulting file already exists and --force was not set. not continuing.\n"; 0172 return 1; 0173 } 0174 0175 const int database_size = args.databases.count(); 0176 int idx = 0; 0177 0178 if (args.force) { 0179 if (std::filesystem::exists(outputDbPath)) { 0180 std::filesystem::remove(outputDbPath); 0181 } 0182 } 0183 0184 for (const QString& db : std::as_const(args.databases)) { 0185 Codethink::lvtmdb::SociReader dbReader; 0186 Codethink::lvtmdb::SociWriter dbWriter; 0187 0188 Codethink::lvtmdb::ObjectStore inMemoryDb; 0189 0190 auto loaded = inMemoryDb.readFromDatabase(dbReader, db.toStdString()); 0191 if (loaded.has_error()) { 0192 std::cout << "Error opening database " << loaded.error().what << "\n"; 0193 return EXIT_FAILURE; 0194 } 0195 0196 if (!args.silent) { 0197 idx += 1; 0198 std::cout << "[" << idx << " of " << database_size << ": Loading data from" << db.toStdString() << "\n"; 0199 } 0200 0201 if (!dbWriter.createOrOpen(outputDbPath.string())) { 0202 std::cerr << "Could not open resulting database\n"; 0203 return EXIT_FAILURE; 0204 } 0205 0206 inMemoryDb.writeToDatabase(dbWriter); 0207 } 0208 0209 std::cout << "Database file saved correctly in " << outputDbPath << "\n"; 0210 return EXIT_SUCCESS; 0211 }