File indexing completed on 2024-04-28 15:30:46

0001 /*
0002     SPDX-FileCopyrightText: 2010-2018 Dominik Haumann <dhaumann@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #include "kateswapdiffcreator.h"
0007 #include "katedocument.h"
0008 #include "katepartdebug.h"
0009 #include "kateswapfile.h"
0010 
0011 #include <KIO/JobUiDelegateFactory>
0012 #include <KIO/OpenUrlJob>
0013 #include <KLocalizedString>
0014 #include <KMessageBox>
0015 
0016 #include <QDir>
0017 #include <QStandardPaths>
0018 #include <QTextCodec>
0019 
0020 // BEGIN SwapDiffCreator
0021 SwapDiffCreator::SwapDiffCreator(Kate::SwapFile *swapFile)
0022     : QObject(swapFile)
0023     , m_swapFile(swapFile)
0024 {
0025 }
0026 
0027 void SwapDiffCreator::viewDiff()
0028 {
0029     QString path = m_swapFile->fileName();
0030     if (path.isNull()) {
0031         return;
0032     }
0033 
0034     QFile swp(path);
0035     if (!swp.open(QIODevice::ReadOnly)) {
0036         qCWarning(LOG_KTE) << "Can't open swap file";
0037         return;
0038     }
0039 
0040     // create all needed tempfiles
0041     m_originalFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.original")));
0042     m_recoveredFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.recovered")));
0043     m_diffFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.diff")));
0044 
0045     if (!m_originalFile.open() || !m_recoveredFile.open() || !m_diffFile.open()) {
0046         qCWarning(LOG_KTE) << "Can't open temporary files needed for diffing";
0047         return;
0048     }
0049 
0050     // truncate files, just in case
0051     m_originalFile.resize(0);
0052     m_recoveredFile.resize(0);
0053     m_diffFile.resize(0);
0054 
0055     // create a document with the recovered data
0056     KTextEditor::DocumentPrivate recoverDoc;
0057     recoverDoc.setText(m_swapFile->document()->text());
0058 
0059     // store original text in a file as utf-8 and close it
0060     {
0061         QTextStream stream(&m_originalFile);
0062         stream.setCodec(QTextCodec::codecForName("UTF-8"));
0063         stream << recoverDoc.text();
0064     }
0065     m_originalFile.close();
0066 
0067     // recover data
0068     QDataStream stream(&swp);
0069     recoverDoc.swapFile()->recover(stream, false);
0070 
0071     // store recovered text in a file as utf-8 and close it
0072     {
0073         QTextStream stream(&m_recoveredFile);
0074         stream.setCodec(QTextCodec::codecForName("UTF-8"));
0075         stream << recoverDoc.text();
0076     }
0077     m_recoveredFile.close();
0078 
0079     // create a process for diff
0080     m_proc.setProcessChannelMode(QProcess::MergedChannels);
0081 
0082     connect(&m_proc, &QProcess::readyRead, this, &SwapDiffCreator::slotDataAvailable, Qt::UniqueConnection);
0083     connect(&m_proc, &QProcess::finished, this, &SwapDiffCreator::slotDiffFinished, Qt::UniqueConnection);
0084 
0085     // use diff from PATH only => inform if not found at all
0086     const QString fullDiffPath = QStandardPaths::findExecutable(QStringLiteral("diff"));
0087     if (fullDiffPath.isEmpty()) {
0088         KMessageBox::error(m_swapFile->document()->activeView(),
0089                            i18n("The diff command could not be found. Please make sure that "
0090                                 "diff(1) is installed and in your PATH."),
0091                            i18n("Error Creating Diff"));
0092         deleteLater();
0093         return;
0094     }
0095 
0096     // try to start the diff program, might fail, too
0097     m_proc.start(fullDiffPath, QStringList() << QStringLiteral("-u") << m_originalFile.fileName() << m_recoveredFile.fileName());
0098     if (!m_proc.waitForStarted()) {
0099         KMessageBox::error(m_swapFile->document()->activeView(),
0100                            i18n("The diff command '%1' could not be started.").arg(fullDiffPath),
0101                            i18n("Error Creating Diff"));
0102         deleteLater();
0103         return;
0104     }
0105 
0106     // process is up and running, we can write data to it
0107     QTextStream ts(&m_proc);
0108     int lineCount = recoverDoc.lines();
0109     for (int line = 0; line < lineCount; ++line) {
0110         ts << recoverDoc.line(line) << '\n';
0111     }
0112     ts.flush();
0113     m_proc.closeWriteChannel();
0114 }
0115 
0116 void SwapDiffCreator::slotDataAvailable()
0117 {
0118     // collect diff output
0119     m_diffFile.write(m_proc.readAll());
0120 }
0121 
0122 void SwapDiffCreator::slotDiffFinished()
0123 {
0124     // collect last diff output, if any
0125     m_diffFile.write(m_proc.readAll());
0126 
0127     // get the exit status to check whether diff command run successfully
0128     const QProcess::ExitStatus es = m_proc.exitStatus();
0129 
0130     // check exit status
0131     if (es != QProcess::NormalExit) {
0132         KMessageBox::error(m_swapFile->document()->activeView(),
0133                            i18n("The diff command failed. Please make sure that "
0134                                 "diff(1) is installed and in your PATH."),
0135                            i18n("Error Creating Diff"));
0136         deleteLater();
0137         return;
0138     }
0139 
0140     // sanity check: is there any diff content?
0141     if (m_diffFile.size() == 0) {
0142         KMessageBox::information(m_swapFile->document()->activeView(), i18n("The files are identical."), i18n("Diff Output"));
0143         deleteLater();
0144         return;
0145     }
0146 
0147     // close diffFile and avoid removal, KIO::OpenUrlJob will do that later!
0148     m_diffFile.close();
0149     m_diffFile.setAutoRemove(false);
0150 
0151     KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(m_diffFile.fileName()), QStringLiteral("text/x-patch"));
0152     job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, m_swapFile->document()->activeView()));
0153     job->setDeleteTemporaryFile(true); // delete the file, once the client exits
0154     job->start();
0155 
0156     deleteLater();
0157 }
0158 
0159 // END SwapDiffCreator
0160 
0161 #include "moc_kateswapdiffcreator.cpp"