File indexing completed on 2024-04-21 16:29:08

0001 /*
0002  *  SPDX-FileCopyrightText: 2019  Andreas Cord-Landwehr <cordlandwehr@kde.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "directoryparser.h"
0008 #include <QCommandLineParser>
0009 #include <QCoreApplication>
0010 #include <QDebug>
0011 #include <iostream>
0012 
0013 int main(int argc, char *argv[])
0014 {
0015     const std::string hightlightOut {"\033[1;34m"};
0016     const std::string defaultOut {"\033[0m"};
0017 
0018     QCoreApplication app(argc, argv);
0019 
0020     QCommandLineParser parser;
0021     parser.setApplicationDescription("Digs into licenses and replaces them with SPDX identifiers");
0022     parser.addHelpOption();
0023     parser.addVersionOption();
0024     parser.addPositionalArgument("directory", QCoreApplication::translate("main", "Source file to copy."));
0025 
0026     QCommandLineOption dryOption(QStringList() << "dry", "only show detected licenses, do not change any file");
0027     parser.addOption(dryOption);
0028 
0029     QCommandLineOption skipParserOption(QStringList() << "skipparser", "use skip parser variant (slower by factor ~5 currently, but maches more)");
0030     parser.addOption(skipParserOption);
0031 
0032     QCommandLineOption forceOption(QStringList() << "f"
0033                                                  << "force",
0034                                    "convert stated directory right away, do not ask");
0035     parser.addOption(forceOption);
0036 
0037     QCommandLineOption licenseConvertOption(QStringList() << "l"
0038                                                           << "licenses",
0039                                             "convert license statements to SPDX-License-Identifier, but nothing else");
0040     parser.addOption(licenseConvertOption);
0041 
0042     QCommandLineOption copyrightConvertOption(QStringList() << "c"
0043                                                             << "copyright",
0044                                               "convert copyright statements to SPDX-FileCopyrightText, but nothing else");
0045     parser.addOption(copyrightConvertOption);
0046 
0047     QCommandLineOption prettyHeaderOption(QStringList() << "p"
0048                                                             << "prettyheader",
0049                                               "perform pretty-print conversion on copyright comment header");
0050     parser.addOption(prettyHeaderOption);
0051 
0052     QCommandLineOption ignorePatternOption(QStringList() << "i"
0053                                                          << "ignore",
0054                                            "Ignore file path matching the pattern",
0055                                            "ignorePattern",
0056                                            "");
0057     parser.addOption(ignorePatternOption);
0058 
0059     parser.process(app);
0060 
0061     const QStringList args = parser.positionalArguments();
0062     if (args.count() == 0) {
0063         qCritical() << "Required license digging directory is missing";
0064         return 1;
0065     }
0066     const QString directory = args.at(0);
0067     const QString ignorePattern = parser.value(ignorePatternOption);
0068 
0069     qInfo() << "Digging recursively all files in directory:" << directory;
0070     DirectoryParser licenseParser;
0071     if (parser.isSet(skipParserOption)) {
0072         licenseParser.setLicenseHeaderParser(DirectoryParser::LicenseParser::SKIP_PARSER);
0073     }
0074 
0075     // print overview if no parameter is set
0076     if (!(parser.isSet(licenseConvertOption) || parser.isSet(copyrightConvertOption) || parser.isSet(forceOption))) {
0077         std::cout << hightlightOut << "==============================" << std::endl << "= LICENSE DETECTION OVERVIEW =" << std::endl << "==============================" << defaultOut << std::endl;
0078         const auto results = licenseParser.parseAll(directory, false, ignorePattern);
0079         int undetectedLicenses = 0;
0080         int detectedLicenses = 0;
0081         for (auto iter = results.constBegin(); iter != results.constEnd(); iter++) {
0082             if (iter.value() == LicenseRegistry::UnknownLicense) {
0083                 ++undetectedLicenses;
0084             } else {
0085                 ++detectedLicenses;
0086             }
0087             qInfo() << iter.key() << " --> " << iter.value();
0088         }
0089         qInfo().nospace() << "\n"
0090                           << "Undetected files: " << undetectedLicenses << " (total: " << (undetectedLicenses + detectedLicenses) << ")";
0091     }
0092 
0093     bool userWantsConversion {false};
0094     if (!(parser.isSet(dryOption) || parser.isSet(licenseConvertOption) || parser.isSet(copyrightConvertOption) || parser.isSet(forceOption))) {
0095         std::string convertAnswer {""};
0096         std::cout << std::endl;
0097         while (convertAnswer != "n" && convertAnswer != "y") {
0098             std::cout << "Perform file conversions? [y/n] ";
0099             std::cin >> convertAnswer;
0100         }
0101         if (convertAnswer == "y") {
0102             userWantsConversion = true;
0103         }
0104         if (convertAnswer == "n") {
0105             std::cout << "Goodbye." << std::endl;
0106             return 0;
0107         }
0108     }
0109 
0110     // actual conversion steps
0111     const bool convertLicense = userWantsConversion || parser.isSet(licenseConvertOption) || parser.isSet(forceOption);
0112 
0113     DirectoryParser::ConvertOptions options = DirectoryParser::ConvertOption::NONE;
0114     if (userWantsConversion || parser.isSet(copyrightConvertOption) || parser.isSet(forceOption)) {
0115         options |= DirectoryParser::ConvertOption::COPYRIGHT_TEXT;
0116     }
0117     if (parser.isSet(prettyHeaderOption)) {
0118         options |= DirectoryParser::ConvertOption::PRETTY;
0119     }
0120 
0121     if (convertLicense) {
0122         std::cout << hightlightOut << "Convert license statements: starting..." << defaultOut << std::endl;
0123         licenseParser.parseAll(directory, true, ignorePattern);
0124         std::cout << hightlightOut << "Convert license statements: DONE." << defaultOut << std::endl;
0125     }
0126 
0127     if (options & DirectoryParser::ConvertOption::COPYRIGHT_TEXT || options & DirectoryParser::ConvertOption::PRETTY) {
0128         std::cout << hightlightOut << "Convert copyright statements: starting..." << defaultOut << std::endl;
0129         licenseParser.convertCopyright(directory, options, ignorePattern);
0130         std::cout << hightlightOut << "Convert copyright statements: DONE." << defaultOut << std::endl;
0131     }
0132 }