File indexing completed on 2024-05-05 04:38:45

0001 /*
0002     SPDX-FileCopyrightText: 2016 Anton Anikin <anton.anikin@htower.ru>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kdevformatfile.h"
0008 #include "wildcardhelpers.h"
0009 
0010 #include <QDir>
0011 #include <QFile>
0012 #include <QFileInfo>
0013 #include <QProcess>
0014 
0015 #include <utility>
0016 
0017 namespace KDevelop {
0018 
0019 KDevFormatFile::KDevFormatFile(const QString& origFilePath, const QString& tempFilePath)
0020     : formatFileName{QStringLiteral("format_sources")}
0021     , m_origFilePath(origFilePath)
0022     , m_tempFilePath(tempFilePath)
0023 {
0024 }
0025 
0026 bool KDevFormatFile::find()
0027 {
0028     QDir srcDir(QFileInfo(m_origFilePath).canonicalPath());
0029 
0030     do {
0031         if (srcDir.exists(formatFileName)) {
0032             QDir::setCurrent(srcDir.canonicalPath());
0033 
0034             qStdOut() << "found \""
0035                       << QFileInfo(srcDir.canonicalPath() + QDir::separator() + formatFileName).canonicalFilePath()
0036                       << "\"\n";
0037             return true;
0038         }
0039     } while (!srcDir.isRoot() && srcDir.cdUp());
0040 
0041     return false;
0042 }
0043 
0044 bool KDevFormatFile::read()
0045 {
0046     constexpr QChar delimiter = QLatin1Char(':');
0047 
0048     QFile formatFile(formatFileName);
0049     if (!formatFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
0050         qStdOut() << "unable to open \"" << formatFileName << "\"\n";
0051         return false;
0052     }
0053 
0054     int lineNumber = 0;
0055     while (!formatFile.atEnd()) {
0056         ++lineNumber;
0057 
0058         QString line = QString::fromUtf8(formatFile.readLine().trimmed());
0059         if (line.isEmpty() || line.startsWith(QLatin1Char('#')))
0060             continue;
0061 
0062         if (line.indexOf(delimiter) < 0) {
0063             // We found the simple syntax without wildcards, and only with the command
0064             m_formatLines.append({QStringList{}, std::move(line)});
0065         } else {
0066             // We found the correct syntax with "wildcards : command"
0067 
0068             QStringList wildcards = line.section(delimiter, 0, 0).split(QLatin1Char(' '), Qt::SkipEmptyParts);
0069             QString command = line.section(delimiter, 1).trimmed();
0070 
0071             if (wildcards.isEmpty()) {
0072                 qStdOut() << formatFileName << ":" << lineNumber
0073                           << ": error: empty wildcard, skip the line\n";
0074                 continue;
0075             }
0076             m_formatLines.append({std::move(wildcards), std::move(command)});
0077         }
0078     }
0079 
0080     if (m_formatLines.isEmpty()) {
0081         qStdOut() << formatFileName << ": error: no commands are found\n";
0082         return false;
0083     }
0084 
0085     return true;
0086 }
0087 
0088 bool KDevFormatFile::apply()
0089 {
0090     for (const KDevFormatLine& formatLine : qAsConst(m_formatLines)) {
0091         if (formatLine.wildcards.isEmpty()) {
0092             qStdOut() << "matched \"" << m_origFilePath << "\" without wildcard";
0093             return executeCommand(formatLine.command);
0094         }
0095 
0096         const QChar dirSeparator = QDir::separator();
0097         for (const QString& wildcard : formatLine.wildcards) {
0098             const QString pattern = QDir::current().canonicalPath() + dirSeparator + wildcard.trimmed();
0099             if (WildcardHelpers::matchSinglePattern(pattern, m_origFilePath)) {
0100                 qStdOut() << "matched \"" << m_origFilePath << "\" with wildcard \"" << wildcard << '\"';
0101                 return executeCommand(formatLine.command);
0102             }
0103         }
0104     }
0105 
0106     qStdOut() << formatFileName << ": error: no commands applicable to \"" << m_origFilePath << "\"\n";
0107     return false;
0108 }
0109 
0110 bool KDevFormatFile::executeCommand(QString command)
0111 {
0112     if (command.isEmpty()) {
0113         qStdOut() << ", empty command => nothing to do\n";
0114         return true;
0115     }
0116     qStdOut() << ", using command \"" << command << "\"\n";
0117 
0118     command.replace(QLatin1String("$ORIGFILE"), m_origFilePath);
0119     command.replace(QLatin1String("$TMPFILE"), m_tempFilePath);
0120 
0121 #ifdef Q_OS_WIN
0122     const QString interpreter = QStringLiteral("cmd");
0123     const QStringList arguments{QStringLiteral("/c"), command};
0124 #else
0125     const QString interpreter = QStringLiteral("sh");
0126     const QStringList arguments{QStringLiteral("-c"), command};
0127 #endif
0128     const int execResult = QProcess::execute(interpreter, arguments);
0129 
0130     if (execResult != 0) {
0131         const QString interpreterDescription = QLatin1String("interpreter ") + interpreter;
0132         if (execResult == -2) {
0133             qStdOut() << "error: " << interpreterDescription << " failed to start\n";
0134             return false;
0135         }
0136         if (execResult == -1) {
0137             qStdOut() << "error: " << interpreterDescription << " crashed\n";
0138             return false;
0139         }
0140         qStdOut() << "warning: " << interpreterDescription << " exited with code " << execResult << '\n';
0141     }
0142 
0143     return true;
0144 }
0145 
0146 }