Commit 5b097916 authored by Gilles Caulier's avatar Gilles Caulier 🗼
Browse files

separate ExitTool parser and process classes internal container implementations

CCBUGS: 426938
CCBUGS: 416516
CCBUGS: 360714
parent 183a0547
Pipeline #59802 passed with stage
in 35 minutes and 19 seconds
......@@ -73,7 +73,9 @@ set(libdmetadata_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/containers/captionvalues.cpp
${CMAKE_CURRENT_SOURCE_DIR}/exiftool/exiftoolparser.cpp
${CMAKE_CURRENT_SOURCE_DIR}/exiftool/exiftoolparser_p.cpp
${CMAKE_CURRENT_SOURCE_DIR}/exiftool/exiftoolprocess.cpp
${CMAKE_CURRENT_SOURCE_DIR}/exiftool/exiftoolprocess_p.cpp
)
include_directories(
......
......@@ -21,55 +21,11 @@
*
* ============================================================ */
#include "exiftoolparser.h"
// Qt includes
#include <QDir>
#include <QStringList>
#include <QVariant>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QEventLoop>
// KDE includes
#include <klocalizedstring.h>
// Local includes
#include "metaenginesettings.h"
#include "exiftoolprocess.h"
#include "digikam_config.h"
#include "digikam_debug.h"
#include "exiftoolparser_p.h"
namespace Digikam
{
class Q_DECL_HIDDEN ExifToolParser::Private
{
public:
explicit Private()
: proc (nullptr),
loopLoad (nullptr),
loopChunk(nullptr),
loopApply(nullptr)
{
}
ExifToolProcess* proc;
QEventLoop* loopLoad;
QEventLoop* loopChunk;
QEventLoop* loopApply;
QString parsedPath;
TagsMap parsedMap;
TagsMap ignoredMap;
QList<QMetaObject::Connection> hdls;
};
ExifToolParser::ExifToolParser(QObject* const parent)
: QObject(parent),
d (new Private)
......@@ -135,44 +91,6 @@ QString ExifToolParser::currentErrorString() const
return d->proc->errorString();
}
bool ExifToolParser::prepareProcess()
{
d->parsedPath.clear();
d->parsedMap.clear();
d->ignoredMap.clear();
// Start ExifToolProcess if necessary
d->proc->start();
if (!d->proc->waitForStarted(500))
{
d->proc->kill();
qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifTool process cannot be started ("
<< d->proc->program()
<< ")";
return false;
}
return true;
}
QByteArray ExifToolParser::filePathEncoding(const QFileInfo& fi) const
{
#ifdef Q_OS_WIN
return (QDir::toNativeSeparators(fi.filePath()).toLocal8Bit());
#else
return (QDir::toNativeSeparators(fi.filePath()).toUtf8());
#endif
}
bool ExifToolParser::load(const QString& path)
{
QFileInfo fileInfo(path);
......@@ -182,7 +100,7 @@ bool ExifToolParser::load(const QString& path)
return false;
}
if (!prepareProcess())
if (!d->prepareProcess())
{
return false;
}
......@@ -195,7 +113,7 @@ bool ExifToolParser::load(const QString& path)
cmdArgs << QByteArray("-G:0:1:2:4:6");
cmdArgs << QByteArray("-n");
cmdArgs << QByteArray("-l");
cmdArgs << filePathEncoding(fileInfo);
cmdArgs << d->filePathEncoding(fileInfo);
// Send command to ExifToolProcess
......@@ -224,7 +142,7 @@ bool ExifToolParser::loadChunk(const QString& path)
return false;
}
if (!prepareProcess())
if (!d->prepareProcess())
{
return false;
}
......@@ -233,7 +151,7 @@ bool ExifToolParser::loadChunk(const QString& path)
QByteArrayList cmdArgs;
cmdArgs << QByteArray("-TagsFromFile");
cmdArgs << filePathEncoding(fileInfo);
cmdArgs << d->filePathEncoding(fileInfo);
cmdArgs << QByteArray("-all:all");
cmdArgs << QByteArray("-o");
cmdArgs << QByteArray("-.exv");
......@@ -272,7 +190,7 @@ bool ExifToolParser::applyChanges(const QString& path, const TagsMap& newTags)
return false;
}
if (!prepareProcess())
if (!d->prepareProcess())
{
return false;
}
......@@ -290,7 +208,7 @@ bool ExifToolParser::applyChanges(const QString& path, const TagsMap& newTags)
cmdArgs << QString::fromUtf8("-%1=%2").arg(tagNameExifTool).arg(tagValue).toUtf8();
}
cmdArgs << filePathEncoding(fileInfo);
cmdArgs << d->filePathEncoding(fileInfo);
// Send command to ExifToolProcess
......@@ -315,7 +233,7 @@ void ExifToolParser::slotCmdCompleted(int cmdAction,
const QByteArray& stdOut,
const QByteArray& /*stdErr*/)
{
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool complete command for action" << actionString(cmdAction)
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool complete command for action" << d->actionString(cmdAction)
<< "with elasped time (ms):" << execTime;
/*
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool output:";
......@@ -337,7 +255,7 @@ void ExifToolParser::slotCmdCompleted(int cmdAction,
if (jsonArray.size() == 0)
{
manageEventLoop(cmdAction);
d->manageEventLoop(cmdAction);
return;
}
......@@ -431,84 +349,27 @@ void ExifToolParser::slotCmdCompleted(int cmdAction,
}
}
manageEventLoop(cmdAction);
d->manageEventLoop(cmdAction);
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool parsed command for action" << actionString(cmdAction);
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool parsed command for action" << d->actionString(cmdAction);
qCDebug(DIGIKAM_METAENGINE_LOG) << d->parsedMap.count() << "properties decoded";
}
void ExifToolParser::slotErrorOccurred(int cmdAction, QProcess::ProcessError error)
{
qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifTool process for action" << actionString(cmdAction)
qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifTool process for action" << d->actionString(cmdAction)
<< "exited with error:" << error;
manageEventLoop(cmdAction);
d->manageEventLoop(cmdAction);
}
void ExifToolParser::slotFinished(int cmdAction, int exitCode, QProcess::ExitStatus exitStatus)
{
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool process for action" << actionString(cmdAction)
qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifTool process for action" << d->actionString(cmdAction)
<< "finished with code:" << exitCode
<< "and status" << exitStatus;
manageEventLoop(cmdAction);
}
void ExifToolParser::manageEventLoop(int cmdAction)
{
switch (cmdAction)
{
case ExifToolProcess::LOAD_METADATA:
{
d->loopLoad->quit();
break;
}
case ExifToolProcess::LOAD_CHUNKS:
{
d->loopChunk->quit();
break;
}
case ExifToolProcess::APPLY_CHANGES:
{
d->loopApply->quit();
break;
}
default: // ExifToolProcess::NO_ACTION
{
break;
}
}
}
QString ExifToolParser::actionString(int cmdAction) const
{
switch (cmdAction)
{
case ExifToolProcess::LOAD_METADATA:
{
return QLatin1String("Load Metadata");
}
case ExifToolProcess::LOAD_CHUNKS:
{
return QLatin1String("Load Chunks");
}
case ExifToolProcess::APPLY_CHANGES:
{
return QLatin1String("Apply Changes");
}
default: // ExifToolProcess::NO_ACTION
{
break;
}
}
return QString();
d->manageEventLoop(cmdAction);
}
void ExifToolParser::slotMetaEngineSettingsChanged()
......
......@@ -121,17 +121,6 @@ private Q_SLOTS:
void slotMetaEngineSettingsChanged();
private:
bool prepareProcess();
QByteArray filePathEncoding(const QFileInfo& fi) const;
void manageEventLoop(int cmdAction);
/**
* Returns a string for an action.
*/
QString actionString(int cmdAction) const;
private:
class Private;
......
/* ============================================================
*
* This file is a part of digiKam project
* https://www.digikam.org
*
* Date : 2013-11-28
* Description : ExifTool JSON parser
*
* Copyright (C) 2013-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#include "exiftoolparser_p.h"
namespace Digikam
{
ExifToolParser::Private::Private()
: proc (nullptr),
loopLoad (nullptr),
loopChunk(nullptr),
loopApply(nullptr)
{
}
bool ExifToolParser::Private::prepareProcess()
{
parsedPath.clear();
parsedMap.clear();
ignoredMap.clear();
// Start ExifToolProcess if necessary
proc->start();
if (!proc->waitForStarted(500))
{
proc->kill();
qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifTool process cannot be started ("
<< proc->program()
<< ")";
return false;
}
return true;
}
QByteArray ExifToolParser::Private::filePathEncoding(const QFileInfo& fi) const
{
#ifdef Q_OS_WIN
return (QDir::toNativeSeparators(fi.filePath()).toLocal8Bit());
#else
return (QDir::toNativeSeparators(fi.filePath()).toUtf8());
#endif
}
QString ExifToolParser::Private::actionString(int cmdAction) const
{
switch (cmdAction)
{
case ExifToolProcess::LOAD_METADATA:
{
return QLatin1String("Load Metadata");
}
case ExifToolProcess::LOAD_CHUNKS:
{
return QLatin1String("Load Chunks");
}
case ExifToolProcess::APPLY_CHANGES:
{
return QLatin1String("Apply Changes");
}
default: // ExifToolProcess::NO_ACTION
{
break;
}
}
return QString();
}
void ExifToolParser::Private::manageEventLoop(int cmdAction)
{
switch (cmdAction)
{
case ExifToolProcess::LOAD_METADATA:
{
loopLoad->quit();
break;
}
case ExifToolProcess::LOAD_CHUNKS:
{
loopChunk->quit();
break;
}
case ExifToolProcess::APPLY_CHANGES:
{
loopApply->quit();
break;
}
default: // ExifToolProcess::NO_ACTION
{
break;
}
}
}
} // namespace Digikam
/* ============================================================
*
* This file is a part of digiKam project
* https://www.digikam.org
*
* Date : 2013-11-28
* Description : ExifTool JSON parser
*
* Copyright (C) 2013-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
#ifndef DIGIKAM_EXIFTOOL_PARSER_P_H
#define DIGIKAM_EXIFTOOL_PARSER_P_H
#include "exiftoolparser.h"
// Qt includes
#include <QDir>
#include <QStringList>
#include <QVariant>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QEventLoop>
// KDE includes
#include <klocalizedstring.h>
// Local includes
#include "metaenginesettings.h"
#include "exiftoolprocess.h"
#include "digikam_config.h"
#include "digikam_debug.h"
namespace Digikam
{
class Q_DECL_HIDDEN ExifToolParser::Private
{
public:
explicit Private();
bool prepareProcess();
QByteArray filePathEncoding(const QFileInfo& fi) const;
void manageEventLoop(int cmdAction);
/**
* Returns a string for an action.
*/
QString actionString(int cmdAction) const;
public:
ExifToolProcess* proc;
QEventLoop* loopLoad;
QEventLoop* loopChunk;
QEventLoop* loopApply;
QString parsedPath;
TagsMap parsedMap;
TagsMap ignoredMap;
QList<QMetaObject::Connection> hdls;
};
} // namespace Digikam
#endif // DIGIKAM_EXIFTOOL_PARSER_P_H
......@@ -24,92 +24,14 @@
*
* ============================================================ */
#include "exiftoolprocess.h"
// Qt includes
#include <QFile>
#include <QElapsedTimer>
#include <QList>
#include <QByteArray>
// Local includes
#include "digikam_debug.h"
#include "digikam_globals.h"
#include "exiftoolprocess_p.h"
namespace Digikam
{
class Q_DECL_HIDDEN ExifToolProcess::Private
{
public:
class Command
{
public:
Command()
: id (0),
ac (ExifToolProcess::NO_ACTION)
{
}
int id;
QByteArray argsStr;
ExifToolProcess::Action ac;
};
public:
explicit Private()
: process (nullptr),
cmdRunning (0),
cmdAction (ExifToolProcess::LOAD_METADATA),
writeChannelIsClosed(true),
processError (QProcess::UnknownError)
{
outAwait[0] = false;
outAwait[1] = false;
outReady[0] = false;
outReady[1] = false;
}
public:
QString etExePath;
QString perlExePath;
QProcess* process;
QElapsedTimer execTimer;
QList<Command> cmdQueue;
int cmdRunning;
ExifToolProcess::Action cmdAction;
int outAwait[2]; ///< [0] StandardOutput | [1] ErrorOutput
bool outReady[2]; ///< [0] StandardOutput | [1] ErrorOutput
QByteArray outBuff[2]; ///< [0] StandardOutput | [1] ErrorOutput
bool writeChannelIsClosed;
QProcess::ProcessError processError;
QString errorString;
public:
static const int CMD_ID_MIN = 1;
static const int CMD_ID_MAX = 2000000000;
static int s_nextCmdId; ///< Unique identifier, even in a multi-instances or multi-thread environment
static QMutex s_cmdIdMutex;
};
QMutex ExifToolProcess::Private::s_cmdIdMutex;
int ExifToolProcess::Private::s_nextCmdId = ExifToolProcess::Private::CMD_ID_MIN;
ExifToolProcess::ExifToolProcess(QObject* const parent)
: QObject(parent),
d (new Private)
d (new Private(this))
{
d->process = new QProcess(this);
d->process->setProcessEnvironment(adjustedEnvironmentForAppImage());
......@@ -183,8 +105,8 @@ void ExifToolProcess::start()
if (!QFile::exists(d->etExePath) ||
!(QFile::permissions(d->etExePath) & QFile::ExeUser))
{
setProcessErrorAndEmit(QProcess::FailedToStart,
QString::fromLatin1("ExifTool does not exists or exec permission is missing"));
d->setProcessErrorAndEmit(QProcess::FailedToStart,
QString::fromLatin1("ExifTool does not exists or exec permission is missing"));
return;
}