diff options
author | Alfred Wingate <parona@protonmail.com> | 2023-12-06 04:18:16 +0200 |
---|---|---|
committer | Sam James <sam@gentoo.org> | 2023-12-23 18:51:56 +0000 |
commit | 722e022916a4e9ddbfa97eb934277d1adce5f3ec (patch) | |
tree | 19cf74bfb4eaf24648aa2b07dab0caa75a9cb246 /x11-misc/copyq | |
parent | sys-fs/mtd-utils: Remove myself from maintainers (diff) | |
download | gentoo-722e022916a4e9ddbfa97eb934277d1adce5f3ec.tar.gz gentoo-722e022916a4e9ddbfa97eb934277d1adce5f3ec.tar.bz2 gentoo-722e022916a4e9ddbfa97eb934277d1adce5f3ec.zip |
x11-misc/copyq: add 7.1.0
* Renamed misleading kde use flag to notification.
* Reenabled tests, required moving to Openbox which is also used by
upstream. IceWM failed with the mocked clicks
* Removed debug use flag for doing very little. It sets Debug level over
Info level and adds the src path for translation files.
Bug: https://bugs.gentoo.org/916129
Bug: https://bugs.gentoo.org/909077
Closes: https://bugs.gentoo.org/919312
Signed-off-by: Alfred Wingate <parona@protonmail.com>
Signed-off-by: Sam James <sam@gentoo.org>
Diffstat (limited to 'x11-misc/copyq')
-rw-r--r-- | x11-misc/copyq/Manifest | 1 | ||||
-rw-r--r-- | x11-misc/copyq/copyq-7.1.0.ebuild | 138 | ||||
-rw-r--r-- | x11-misc/copyq/files/copyq-7.1.0-fix-gpg-2.1-support.patch | 558 | ||||
-rw-r--r-- | x11-misc/copyq/files/copyq-7.1.0-fix-qt-6.6.0-build.patch | 44 | ||||
-rw-r--r-- | x11-misc/copyq/files/copyq-7.1.0-fix-test-failure-due-to-invalid-regex.patch | 98 | ||||
-rw-r--r-- | x11-misc/copyq/files/copyq-7.1.0-support-plugin-dir-envvar.patch | 26 | ||||
-rw-r--r-- | x11-misc/copyq/metadata.xml | 3 |
7 files changed, 868 insertions, 0 deletions
diff --git a/x11-misc/copyq/Manifest b/x11-misc/copyq/Manifest index f83ff343f119..c839c3a7a2cd 100644 --- a/x11-misc/copyq/Manifest +++ b/x11-misc/copyq/Manifest @@ -1,2 +1,3 @@ DIST copyq-6.4.0.tar.gz 3316278 BLAKE2B 348fdc23a6d0d53ddcc8e2c32b194cfbf6c4d4d2374b972cb81d945e284c42d1e8f6b9ed30e657e43e69ed0f35661adc7875392b5daf653ce895d76afed7c09c SHA512 a97b4ac541ff73129a6283266fb8857d89d571d042829de5793b94e6423a2978f632b22728ca663bccd540bb90fed51c755b432d1d2545f75c227ea2cb0d9581 DIST copyq-7.0.0.tar.gz 3323354 BLAKE2B 3c71bf94ed97d0564f89cb0b9927024df21520cf9eb758ec8c40e8156d9796b3c6df5518b9ad223c12489fe7aca3a067f772719a3a757f9a92e9ec18fe79e38c SHA512 f0b84ddef6791e229c625dbdefab2d3aad5be10d68745addb64d6e2b1546e033f1f95fb1a1218f9fdd19b5fcdddf2d840b2480ad54e0f59a7d5741781b3a43c4 +DIST copyq-7.1.0.tar.gz 3351093 BLAKE2B 758271f6bb54760372b8b5ab84de7c91af874bd72a22c8c22d338705869eab5500fde90808b4bf1288f8bdbad11163283637b81d85c09ccf0d734286dee605b6 SHA512 4320095ab75c361cc3d553c7817951eb6e74d47223f62bf6c1722e0f0b0d3ff59a1762354cf46fe0de064d516d60a467bff9ad9143b12016fc3f9e62139d3909 diff --git a/x11-misc/copyq/copyq-7.1.0.ebuild b/x11-misc/copyq/copyq-7.1.0.ebuild new file mode 100644 index 000000000000..ef1aeb8f372b --- /dev/null +++ b/x11-misc/copyq/copyq-7.1.0.ebuild @@ -0,0 +1,138 @@ +# Copyright 1999-2023 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake optfeature virtualx xdg + +DESCRIPTION="Clipboard manager with advanced features" +HOMEPAGE=" + https://hluk.github.io/CopyQ/ + https://github.com/hluk/CopyQ/ +" +SRC_URI="https://github.com/hluk/${PN}/archive/v${PV}.tar.gz -> ${P}.tar.gz" +S="${WORKDIR}/CopyQ-${PV}" + +LICENSE="GPL-3+" +SLOT="0" +KEYWORDS="~amd64 ~arm64 ~x86 ~amd64-linux ~x86-linux" + +IUSE="notification qt6 test" +# Native notifications are not supported with Qt 6 +# (Bumpers please check when this requirement is lifted). +# src/notifications.cmake +REQUIRED_USE="notification? ( !qt6 )" + +RDEPEND=" + dev-libs/wayland + x11-libs/libX11 + x11-libs/libXtst + !qt6? ( + dev-qt/qtcore:5 + dev-qt/qtdeclarative:5 + dev-qt/qtgui:5 + dev-qt/qtnetwork:5 + dev-qt/qtsvg:5 + dev-qt/qtwayland:5 + dev-qt/qtwidgets:5 + dev-qt/qtx11extras:5 + notification? ( kde-frameworks/knotifications:5 ) + test? ( dev-qt/qttest:5 ) + ) + qt6? ( + dev-qt/qtbase:6=[X,gui,network,test?,widgets,xml(+)] + dev-qt/qtdeclarative:6 + dev-qt/qtsvg:6 + dev-qt/qtwayland:6 + ) +" +DEPEND="${RDEPEND} + x11-base/xorg-proto +" +BDEPEND=" + kde-frameworks/extra-cmake-modules:0 + !qt6? ( + dev-qt/linguist-tools:5 + dev-qt/qtwaylandscanner:5 + ) + qt6? ( + dev-qt/qttools:6[linguist] + dev-util/wayland-scanner + ) + test? ( + app-crypt/gnupg + x11-wm/openbox + ) +" + +PATCHES=( + "${FILESDIR}/copyq-7.1.0-fix-qt-6.6.0-build.patch" + "${FILESDIR}/copyq-7.1.0-fix-test-failure-due-to-invalid-regex.patch" + "${FILESDIR}/copyq-7.1.0-fix-gpg-2.1-support.patch" + "${FILESDIR}/copyq-7.1.0-support-plugin-dir-envvar.patch" +) + +src_prepare() { + cmake_src_prepare + + # FAIL! : Tests::actionDialogAccept() 'NO_ERRORS(m_test->runClient((Args() << "keys" << actionDialogId << "ENTER" << clipboardBrowserId), toByteArray("")))' returned FALSE. + # FAIL! : Tests::actionDialogSelection() 'NO_ERRORS(m_test->runClient((Args() << "keys" << actionDialogId << "ENTER" << clipboardBrowserId), toByteArray("")))' returned FALSE. + # FAIL! : Tests::actionDialogSelectionInputOutput() 'NO_ERRORS(m_test->runClient((Args() << "keys" << actionDialogId << "ENTER" << clipboardBrowserId), toByteArray("")))' returned FALSE. + # FAIL! : Tests::commandShowAt() 'NO_ERRORS(m_test->waitOnOutput((Args() << "visible"), toByteArray("true\n")))' returned FALSE. + sed -Ei -e ' + /Tests::(actionDialog(Accept|Selection(|InputOutput))|commandShow)/,/}/ { + /^\s*\{/ a \ + #if QT_VERSION < QT_VERSION_CHECK(6,0,0)\ + SKIP("Broken on qt5");\ + #endif + }' src/tests/tests.cpp || die +} + +src_configure() { + local mycmakeargs=( + -DPLUGIN_INSTALL_PREFIX="${EPREFIX}/usr/$(get_libdir)/${PN}/plugins" + -DWITH_NATIVE_NOTIFICATIONS=$(usex notification) + -DWITH_QT6=$(usex qt6) + -DWITH_TESTS=$(usex test) + ) + + cmake_src_configure +} + +my_src_test() { + # Don't rerun tests and more logs + local -x COPYQ_TESTS_RERUN_FAILED=0 + local -x COPYQ_LOG_LEVEL=DEBUG + + # Skip test that require network + local -x COPYQ_TESTS_NO_NETWORK=1 + + # Less noise from trying the wayland plugin + local -x QT_QPA_PLATFORM=xcb + + # Make sure copyq doesn't use system installed plugins which may be incompatible. + local -x COPYQ_PLUGIN_DIR="${BUILD_DIR}/plugins" + + # In case the users current system confuses the notification integration + unset KDE_FULL_SESSION XDG_CURRENT_DESKTOP + + mkdir "${HOME}"/.gnupg || die + + ebegin "Starting Openbox" + openbox & # upstream uses Openbox and it doesn't fail like IceWM + sleep 5 + eend 0 + + "${BUILD_DIR}"/copyq tests + + return $? +} + +src_test() { + virtx my_src_test +} + +pkg_postinst() { + xdg_pkg_postinst + optfeature "encryption support" app-crypt/gnupg +} diff --git a/x11-misc/copyq/files/copyq-7.1.0-fix-gpg-2.1-support.patch b/x11-misc/copyq/files/copyq-7.1.0-fix-gpg-2.1-support.patch new file mode 100644 index 000000000000..b06e7e759b84 --- /dev/null +++ b/x11-misc/copyq/files/copyq-7.1.0-fix-gpg-2.1-support.patch @@ -0,0 +1,558 @@ +https://github.com/hluk/CopyQ/pull/2471 +https://github.com/hluk/CopyQ/issues/2463 +https://github.com/hluk/CopyQ/commit/a7a891e1f84c6c046a7bfc904c5fc6ebb98dec94 + +From a7a891e1f84c6c046a7bfc904c5fc6ebb98dec94 Mon Sep 17 00:00:00 2001 +From: Lukas Holecek <hluk@email.cz> +Date: Wed, 20 Sep 2023 19:42:08 +0200 +Subject: [PATCH] itemencrypted: Fix managing keys with gpg 2.1 and above + (#2471) + +* itemencrypted: Fix managing keys with gpg 2.1 and above + +Fixes #2463, #1208 + +* Tests: Avoid skipping itemencrypted tests if gpg is not found + +* Windows: Fix running itemencrypted plugin tests + +* itemencrypted: Fix error logging + +* Ensure config directory exists + +* itemencrypted: Fix handling native/non-native key paths + +* Appveyor: Fix stuck job waiting on gpg-agent +--- a/plugins/itemencrypted/itemencrypted.cpp ++++ b/plugins/itemencrypted/itemencrypted.cpp +@@ -57,20 +57,23 @@ bool waitOrTerminate(QProcess *p, int timeoutMs) + bool verifyProcess(QProcess *p, int timeoutMs = 30000) + { + if ( !waitOrTerminate(p, timeoutMs) ) { +- log( "ItemEncrypt ERROR: Process timed out; stderr: " + p->readAllStandardError(), LogError ); ++ log( QStringLiteral("ItemEncrypt: Process timed out; stderr: %1") ++ .arg(QString::fromUtf8(p->readAllStandardError())), LogError ); + return false; + } + + const int exitCode = p->exitCode(); + if ( p->exitStatus() != QProcess::NormalExit ) { +- log( "ItemEncrypt ERROR: Failed to run GnuPG: " + p->errorString(), LogError ); ++ log( QStringLiteral("ItemEncrypt: Failed to run GnuPG: %1") ++ .arg(p->errorString()), LogError ); + return false; + } + + if (exitCode != 0) { + const QString errors = p->readAllStandardError(); + if ( !errors.isEmpty() ) +- log( "ItemEncrypt ERROR: GnuPG stderr:\n" + errors, LogError ); ++ log( QStringLiteral("ItemEncrypt: GnuPG stderr:\n%1") ++ .arg(errors), LogError ); + return false; + } + +@@ -88,55 +91,106 @@ QString getGpgVersionOutput(const QString &executable) { + return p.readAllStandardOutput(); + } + +-bool checkGpgExecutable(const QString &executable) ++struct GpgVersion { ++ int major; ++ int minor; ++}; ++ ++GpgVersion parseVersion(const QString &versionOutput) + { +- const auto versionOutput = getGpgVersionOutput(executable); +- return versionOutput.contains(" 2."); ++ const int lineEndIndex = versionOutput.indexOf('\n'); ++#if QT_VERSION < QT_VERSION_CHECK(5,15,2) ++ const QStringRef firstLine = versionOutput.midRef(0, lineEndIndex); ++#else ++ const auto firstLine = QStringView{versionOutput}.mid(0, lineEndIndex); ++#endif ++ const QRegularExpression versionRegex(QStringLiteral(R"( (\d+)\.(\d+))")); ++ const QRegularExpressionMatch match = versionRegex.match(firstLine); ++#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) ++ const int major = match.hasMatch() ? match.capturedView(1).toInt() : 0; ++ const int minor = match.hasMatch() ? match.capturedView(2).toInt() : 0; ++#else ++ const int major = match.hasMatch() ? match.capturedRef(1).toInt() : 0; ++ const int minor = match.hasMatch() ? match.capturedRef(2).toInt() : 0; ++#endif ++ return GpgVersion{major, minor}; + } + ++class GpgExecutable { ++public: ++ GpgExecutable() = default; ++ ++ explicit GpgExecutable(const QString &executable) ++ : m_executable(executable) ++ { ++ const auto versionOutput = getGpgVersionOutput(executable); ++ if ( !versionOutput.isEmpty() ) { ++ COPYQ_LOG_VERBOSE( ++ QStringLiteral("ItemEncrypt INFO: '%1 --version' output: %2") ++ .arg(executable, versionOutput) ); ++ ++ const GpgVersion version = parseVersion(versionOutput); ++ m_isSupported = version.major >= 2; ++ COPYQ_LOG( QStringLiteral("ItemEncrypt INFO: %1 gpg version: %2.%3") ++ .arg(m_isSupported ? "Supported" : "Unsupported") ++ .arg(version.major) ++ .arg(version.minor) ); ++ ++ const bool needsSecring = version.major == 2 && version.minor == 0; ++ ++ const QString path = getConfigurationFilePath(""); ++ m_pubring = path + ".pub"; ++ m_pubringNative = QDir::toNativeSeparators(m_pubring); ++ if (needsSecring) { ++ m_secring = path + ".sec"; ++ m_secringNative = QDir::toNativeSeparators(m_secring); ++ } ++ + #ifdef Q_OS_WIN +-bool checkUnixGpg(const QString &executable) +-{ +- static const auto unixGpg = getGpgVersionOutput(executable).contains("Home: /c/"); +- return unixGpg; +-} ++ const bool isUnixGpg = versionOutput.contains("Home: /c/"); ++ if (isUnixGpg) { ++ m_pubringNative = QString(m_pubring).replace(":", "").insert(0, '/'); ++ if (needsSecring) ++ m_secringNative = QString(m_secring).replace(":", "").insert(0, '/'); ++ } + #endif ++ } ++ } ++ ++ const QString &executable() const { return m_executable; } ++ bool isSupported() const { return m_isSupported; } ++ bool needsSecring() const { return !m_secring.isEmpty(); } ++ const QString &pubring() const { return m_pubring; } ++ const QString &secring() const { return m_secring; } ++ const QString &pubringNative() const { return m_pubringNative; } ++ const QString &secringNative() const { return m_secringNative; } ++ ++private: ++ QString m_executable; ++ QString m_pubring; ++ QString m_secring; ++ QString m_pubringNative; ++ QString m_secringNative; ++ bool m_isSupported = false; ++}; + +-QString findGpgExecutable() ++GpgExecutable findGpgExecutable() + { + for (const auto &executable : {"gpg2", "gpg"}) { +- if ( checkGpgExecutable(executable) ) +- return executable; ++ GpgExecutable gpg(executable); ++ if ( gpg.isSupported() ) ++ return gpg; + } + +- return QString(); ++ return GpgExecutable(); + } + +-const QString &gpgExecutable() ++const GpgExecutable &gpgExecutable() + { + static const auto gpg = findGpgExecutable(); + return gpg; + } + +-struct KeyPairPaths { +- KeyPairPaths() +- { +- const QString path = getConfigurationFilePath(""); +- sec = QDir::toNativeSeparators(path + ".sec"); +- pub = QDir::toNativeSeparators(path + ".pub"); +- +-#ifdef Q_OS_WIN +- if (checkUnixGpg(gpgExecutable())) { +- pub = QDir::fromNativeSeparators(pub).replace(":", "").insert(0, '/'); +- sec = QDir::fromNativeSeparators(sec).replace(":", "").insert(0, '/'); +- } +-#endif +- } +- +- QString sec; +- QString pub; +-}; +- + QStringList getDefaultEncryptCommandArguments(const QString &publicKeyPath) + { + return QStringList() << "--trust-model" << "always" << "--recipient" << "copyq" +@@ -146,16 +200,18 @@ QStringList getDefaultEncryptCommandArguments(const QString &publicKeyPath) + + void startGpgProcess(QProcess *p, const QStringList &args, QIODevice::OpenModeFlag mode) + { +- KeyPairPaths keys; +- p->start(gpgExecutable(), getDefaultEncryptCommandArguments(keys.pub) + args, mode); ++ const auto &gpg = gpgExecutable(); ++ p->start(gpg.executable(), getDefaultEncryptCommandArguments(gpg.pubringNative()) + args, mode); + } + + QString importGpgKey() + { +- KeyPairPaths keys; ++ const auto &gpg = gpgExecutable(); ++ if ( !gpg.needsSecring() ) ++ return QString(); + + QProcess p; +- p.start(gpgExecutable(), getDefaultEncryptCommandArguments(keys.pub) << "--import" << keys.sec); ++ p.start(gpg.executable(), getDefaultEncryptCommandArguments(gpg.pubringNative()) << "--import" << gpg.secringNative()); + if ( !verifyProcess(&p) ) + return "Failed to import private key (see log)."; + +@@ -164,18 +220,20 @@ QString importGpgKey() + + QString exportGpgKey() + { +- KeyPairPaths keys; ++ const auto &gpg = gpgExecutable(); ++ if ( !gpg.needsSecring() ) ++ return QString(); + + // Private key already created or exported. +- if ( QFile::exists(keys.sec) ) ++ if ( QFile::exists(gpg.secring()) ) + return QString(); + + QProcess p; +- p.start(gpgExecutable(), getDefaultEncryptCommandArguments(keys.pub) << "--export-secret-key" << "copyq"); ++ p.start(gpg.executable(), getDefaultEncryptCommandArguments(gpg.pubringNative()) << "--export-secret-key" << gpg.secringNative()); + if ( !verifyProcess(&p) ) + return "Failed to export private key (see log)."; + +- QFile secKey(keys.sec); ++ QFile secKey(gpg.secring()); + if ( !secKey.open(QIODevice::WriteOnly) ) + return "Failed to create private key."; + +@@ -240,7 +298,7 @@ bool encryptMimeData(const QVariantMap &data, const QModelIndex &index, QAbstrac + + void startGenerateKeysProcess(QProcess *process, bool useTransientPasswordlessKey = false) + { +- const KeyPairPaths keys; ++ const auto &gpg = gpgExecutable(); + + auto args = QStringList() << "--batch" << "--gen-key"; + +@@ -253,15 +311,19 @@ void startGenerateKeysProcess(QProcess *process, bool useTransientPasswordlessKe + } + + startGpgProcess(process, args, QIODevice::ReadWrite); +- process->write( "\nKey-Type: RSA" +- "\nKey-Usage: encrypt" +- "\nKey-Length: 4096" +- "\nName-Real: copyq" +- + transientOptions + +- "\n%secring " + keys.sec.toUtf8() + +- "\n%pubring " + keys.pub.toUtf8() + +- "\n%commit" +- "\n" ); ++ process->write( ++ "\nKey-Type: RSA" ++ "\nKey-Usage: encrypt" ++ "\nKey-Length: 4096" ++ "\nName-Real: copyq" ++ + transientOptions + ++ "\n%pubring " + gpg.pubringNative().toUtf8() ++ ); ++ ++ if ( gpg.needsSecring() ) ++ process->write("\n%secring " + gpg.secringNative().toUtf8()); ++ ++ process->write("\n%commit\n"); + process->closeWriteChannel(); + } + +@@ -276,7 +338,7 @@ QString exportImportGpgKeys() + + bool isGpgInstalled() + { +- return !gpgExecutable().isEmpty(); ++ return gpgExecutable().isSupported(); + } + + } // namespace +@@ -314,7 +376,7 @@ bool ItemEncryptedSaver::saveItems(const QString &, const QAbstractItemModel &mo + bytes = readGpgOutput(QStringList("--encrypt"), bytes); + if ( bytes.isEmpty() ) { + emitEncryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to read encrypted data"); ++ log("ItemEncrypt: Failed to read encrypted data", LogError); + return false; + } + +@@ -325,7 +387,7 @@ bool ItemEncryptedSaver::saveItems(const QString &, const QAbstractItemModel &mo + + if ( stream.status() != QDataStream::Ok ) { + emitEncryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to write encrypted data"); ++ log("ItemEncrypt: Failed to write encrypted data", LogError); + return false; + } + +@@ -510,17 +572,22 @@ void ItemEncryptedScriptable::pasteEncryptedItems() + + QString ItemEncryptedScriptable::generateTestKeys() + { +- const KeyPairPaths keys; +- for ( const auto &keyFileName : {keys.sec, keys.pub} ) { ++ const auto &gpg = gpgExecutable(); ++ ++ const QStringList keys = gpg.needsSecring() ++ ? QStringList{gpg.pubring(), gpg.secring()} ++ : QStringList{gpg.pubring()}; ++ ++ for (const auto &keyFileName : keys) { + if ( QFile::exists(keyFileName) && !QFile::remove(keyFileName) ) +- return QString("Failed to remove \"%1\"").arg(keys.sec); ++ return QString("Failed to remove \"%1\"").arg(keyFileName); + } + + QProcess process; + startGenerateKeysProcess(&process, true); + + if ( !verifyProcess(&process) ) { +- return QString("ItemEncrypt ERROR: %1; stderr: %2") ++ return QString("ItemEncrypt: %1; stderr: %2") + .arg( process.errorString(), + QString::fromUtf8(process.readAllStandardError()) ); + } +@@ -529,9 +596,9 @@ QString ItemEncryptedScriptable::generateTestKeys() + if ( !error.isEmpty() ) + return error; + +- for ( const auto &keyFileName : {keys.sec, keys.pub} ) { ++ for (const auto &keyFileName : keys) { + if ( !QFile::exists(keyFileName) ) +- return QString("Failed to create \"%1\"").arg(keys.sec); ++ return QString("Failed to create \"%1\"").arg(keyFileName); + } + + return QString(); +@@ -606,19 +673,29 @@ QWidget *ItemEncryptedLoader::createSettingsWidget(QWidget *parent) + m_encryptTabs.join('\n') ); + + if (status() != GpgNotInstalled) { +- KeyPairPaths keys; ++ const auto &gpg = gpgExecutable(); + ui->labelShareInfo->setTextFormat(Qt::RichText); +- ui->labelShareInfo->setText( ItemEncryptedLoader::tr( +- "To share encrypted items on other computer or" +- " session, you'll need public and secret key files:" +- "<ul>" +- "<li>%1</li>" +- "<li>%2<br />(Keep this secret key in a safe place.)</li>" +- "</ul>" +- ) +- .arg( quoteString(keys.pub), +- quoteString(keys.sec) ) +- ); ++ QString text = ItemEncryptedLoader::tr( ++ "To share encrypted items on other computer or" ++ " session, you'll need these secret key files (keep them in a safe place):" ++ ); ++ if (gpg.needsSecring()) { ++ text.append( QStringLiteral( ++ "<ul>" ++ "<li>%1</li>" ++ "<li>%2</li>" ++ "</ul>" ++ ).arg(quoteString(gpg.pubringNative()), quoteString(gpg.secringNative())) ++ ); ++ } else { ++ text.append( QStringLiteral( ++ "<ul>" ++ "<li>%1</li>" ++ "</ul>" ++ ).arg(quoteString(gpg.pubringNative())) ++ ); ++ } ++ ui->labelShareInfo->setText(text); + } + + updateUi(); +@@ -689,7 +766,7 @@ ItemSaverPtr ItemEncryptedLoader::loadItems(const QString &, QAbstractItemModel + const int bytesRead = stream.readRawData(encryptedBytes, 4096); + if (bytesRead == -1) { + emitDecryptFailed(); +- COPYQ_LOG("ItemEncrypted ERROR: Failed to read encrypted data"); ++ log("ItemEncrypted: Failed to read encrypted data", LogError); + return nullptr; + } + p.write(encryptedBytes, bytesRead); +@@ -708,7 +785,7 @@ ItemSaverPtr ItemEncryptedLoader::loadItems(const QString &, QAbstractItemModel + const QByteArray bytes = p.readAllStandardOutput(); + if ( bytes.isEmpty() ) { + emitDecryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to read encrypted data."); ++ log("ItemEncrypt: Failed to read encrypted data", LogError); + verifyProcess(&p); + return nullptr; + } +@@ -719,7 +796,7 @@ ItemSaverPtr ItemEncryptedLoader::loadItems(const QString &, QAbstractItemModel + stream2 >> length; + if ( stream2.status() != QDataStream::Ok ) { + emitDecryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to parse item count!"); ++ log("ItemEncrypt: Failed to parse item count", LogError); + return nullptr; + } + length = qMin(length, static_cast<quint64>(maxItems)) - static_cast<quint64>(model->rowCount()); +@@ -728,7 +805,7 @@ ItemSaverPtr ItemEncryptedLoader::loadItems(const QString &, QAbstractItemModel + for ( int i = 0; i < count && stream2.status() == QDataStream::Ok; ++i ) { + if ( !model->insertRow(i) ) { + emitDecryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to insert item!"); ++ log("ItemEncrypt: Failed to insert item", LogError); + return nullptr; + } + QVariantMap dataMap; +@@ -738,7 +815,7 @@ ItemSaverPtr ItemEncryptedLoader::loadItems(const QString &, QAbstractItemModel + + if ( stream2.status() != QDataStream::Ok ) { + emitDecryptFailed(); +- COPYQ_LOG("ItemEncrypt ERROR: Failed to decrypt item!"); ++ log("ItemEncrypt: Failed to decrypt item", LogError); + return nullptr; + } + +--- a/plugins/itemencrypted/tests/itemencryptedtests.cpp ++++ b/plugins/itemencrypted/tests/itemencryptedtests.cpp +@@ -25,6 +25,8 @@ void ItemEncryptedTests::cleanupTestCase() + void ItemEncryptedTests::init() + { + TEST(m_test->init()); ++ ++ QVERIFY(isGpgInstalled()); + } + + void ItemEncryptedTests::cleanup() +@@ -34,13 +36,10 @@ void ItemEncryptedTests::cleanup() + + void ItemEncryptedTests::encryptDecryptData() + { +- if ( !isGpgInstalled() ) +- SKIP("gpg2 is required to run the test"); +- +- RUN("-e" << "plugins.itemencrypted.generateTestKeys()", "\n"); ++ RUN("plugins.itemencrypted.generateTestKeys()", "\n"); + + // Test gpg errors first. +- RUN("-e" << "plugins.itemencrypted.encrypt(input());print('')", ""); ++ RUN("plugins.itemencrypted.encrypt(input());print('')", ""); + + const QByteArray input("\x00\x01\x02\x03\x04", 5); + QByteArray stdoutActual; +@@ -60,10 +59,7 @@ void ItemEncryptedTests::encryptDecryptItems() + SKIP("Ctrl+L shortcut doesn't seem work on OS X"); + #endif + +- if ( !isGpgInstalled() ) +- SKIP("gpg2 is required to run the test"); +- +- RUN("-e" << "plugins.itemencrypted.generateTestKeys()", "\n"); ++ RUN("plugins.itemencrypted.generateTestKeys()", "\n"); + + // Load commands from the plugin generating keys. + RUN("keys" << "Ctrl+P" << "ENTER", ""); +--- a/src/app/clipboardserver.cpp ++++ b/src/app/clipboardserver.cpp +@@ -124,6 +124,8 @@ ClipboardServer::ClipboardServer(QApplication *app, const QString &sessionName) + + QApplication::setQuitOnLastWindowClosed(false); + ++ ensureSettingsDirectoryExists(); ++ + m_sharedData = std::make_shared<ClipboardBrowserShared>(); + m_sharedData->itemFactory = new ItemFactory(this); + m_sharedData->notifications = new NotificationDaemon(this); +--- a/src/common/config.cpp ++++ b/src/common/config.cpp +@@ -157,6 +157,20 @@ QString getConfigurationFilePathHelper() + + } // namespace + ++bool ensureSettingsDirectoryExists() ++{ ++ QDir settingsDir( settingsDirectoryPath() ); ++ if ( !settingsDir.mkpath(".") ) { ++ log( QStringLiteral("Failed to create the directory for settings: %1") ++ .arg(settingsDir.path()), ++ LogError ); ++ ++ return false; ++ } ++ ++ return true; ++} ++ + const QString &getConfigurationFilePath() + { + static const QString path = getConfigurationFilePathHelper(); +--- a/src/common/config.h ++++ b/src/common/config.h +@@ -9,6 +9,8 @@ class QString; + class QVariant; + class QWidget; + ++bool ensureSettingsDirectoryExists(); ++ + const QString &getConfigurationFilePath(); + + QString getConfigurationFilePath(const char *suffix); +--- a/src/item/itemstore.cpp ++++ b/src/item/itemstore.cpp +@@ -22,20 +22,6 @@ QString itemFileName(const QString &id) + return getConfigurationFilePath("_tab_") + part + QLatin1String(".dat"); + } + +-bool createItemDirectory() +-{ +- QDir settingsDir( settingsDirectoryPath() ); +- if ( !settingsDir.mkpath(".") ) { +- log( QString("Cannot create directory for settings %1!") +- .arg(quoteString(settingsDir.path()) ), +- LogError ); +- +- return false; +- } +- +- return true; +-} +- + void printItemFileError( + const QString &action, const QString &id, const QFileDevice &file) + { +@@ -83,9 +69,6 @@ ItemSaverPtr createTab( + + ItemSaverPtr loadItems(const QString &tabName, QAbstractItemModel &model, ItemFactory *itemFactory, int maxItems) + { +- if ( !createItemDirectory() ) +- return nullptr; +- + const QString tabFileName = itemFileName(tabName); + if ( !QFile::exists(tabFileName) ) + return createTab(tabName, model, itemFactory, maxItems); +@@ -107,7 +90,7 @@ bool saveItems(const QString &tabName, const QAbstractItemModel &model, const It + { + const QString tabFileName = itemFileName(tabName); + +- if ( !createItemDirectory() ) ++ if ( !ensureSettingsDirectoryExists() ) + return false; + + // Save tab data to a new temporary file. diff --git a/x11-misc/copyq/files/copyq-7.1.0-fix-qt-6.6.0-build.patch b/x11-misc/copyq/files/copyq-7.1.0-fix-qt-6.6.0-build.patch new file mode 100644 index 000000000000..2b149ab843bf --- /dev/null +++ b/x11-misc/copyq/files/copyq-7.1.0-fix-qt-6.6.0-build.patch @@ -0,0 +1,44 @@ +https://bugs.gentoo.org/916129 +https://github.com/hluk/CopyQ/pull/2508 +https://github.com/hluk/CopyQ/commit/19e9dd1c2ecb49b14a24159c5ac3bc1b77fdf250 + +From 19e9dd1c2ecb49b14a24159c5ac3bc1b77fdf250 Mon Sep 17 00:00:00 2001 +From: Nick Cao <nickcao@nichi.co> +Date: Tue, 17 Oct 2023 02:08:51 -0400 +Subject: [PATCH] itemfakevim: fix build with qt 6.6.0 (#2508) + +Reference: https://github.com/qt-creator/qt-creator/commit/e56e3b6f374e00179eb0537198437864dddc47f2 +--- a/plugins/itemfakevim/fakevim/fakevimhandler.cpp ++++ b/plugins/itemfakevim/fakevim/fakevimhandler.cpp +@@ -1057,14 +1057,6 @@ inline QString msgMarkNotSet(const QString &text) + return Tr::tr("Mark \"%1\" not set.").arg(text); + } + +-static void initSingleShotTimer(QTimer *timer, int interval, FakeVimHandler::Private *receiver, +- void (FakeVimHandler::Private::*slot)()) +-{ +- timer->setSingleShot(true); +- timer->setInterval(interval); +- QObject::connect(timer, &QTimer::timeout, receiver, slot); +-} +- + class Input + { + public: +@@ -2424,6 +2416,16 @@ class FakeVimHandler::Private : public QObject + FakeVimSettings &s = *fakeVimSettings(); + }; + ++static void initSingleShotTimer(QTimer *timer, ++ int interval, ++ FakeVimHandler::Private *receiver, ++ void (FakeVimHandler::Private::*slot)()) ++{ ++ timer->setSingleShot(true); ++ timer->setInterval(interval); ++ QObject::connect(timer, &QTimer::timeout, receiver, slot); ++} ++ + FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g; + + FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget) diff --git a/x11-misc/copyq/files/copyq-7.1.0-fix-test-failure-due-to-invalid-regex.patch b/x11-misc/copyq/files/copyq-7.1.0-fix-test-failure-due-to-invalid-regex.patch new file mode 100644 index 000000000000..e526f3a89f0b --- /dev/null +++ b/x11-misc/copyq/files/copyq-7.1.0-fix-test-failure-due-to-invalid-regex.patch @@ -0,0 +1,98 @@ +https://github.com/hluk/CopyQ/commit/42c02f2dc74b188ea7982a30c38acaf668bbf76a + +From 42c02f2dc74b188ea7982a30c38acaf668bbf76a Mon Sep 17 00:00:00 2001 +From: Lukas Holecek <hluk@email.cz> +Date: Mon, 4 Sep 2023 21:12:44 +0200 +Subject: [PATCH] Avoid showing warnings about invalid regex + +--- a/src/scriptable/scriptableitemselection.cpp ++++ b/src/scriptable/scriptableitemselection.cpp +@@ -46,10 +46,6 @@ QVector<int> toIntVector(const QJSValue &value) + + QRegularExpression toRegularExpression(const QJSValue &value) + { +- // If argument is invalid/not-regexp, create an invalid regex to match nothing. +- if ( !value.isRegExp() ) +- return QRegularExpression("("); +- + const QVariant variant = value.toVariant(); + QRegularExpression regexp = variant.toRegularExpression(); + +@@ -136,7 +132,7 @@ QJSValue ScriptableItemSelection::selectAll() + + QJSValue ScriptableItemSelection::select(const QJSValue &re, const QString &mimeFormat) + { +- const QVariant regexp = re.isUndefined() ? QVariant() : toRegularExpression(re); ++ const QVariant regexp = re.isRegExp() ? toRegularExpression(re) : QVariant(); + m_proxy->selectionSelect(m_id, regexp, mimeFormat); + return m_self; + } +--- a/src/tests/testinterface.h ++++ b/src/tests/testinterface.h +@@ -85,9 +85,6 @@ class TestInterface { + /// Clean up tabs and items. Return error string on error. + virtual QByteArray cleanup() = 0; + +- /// Ignore given text in logs for current unit test. +- virtual void setIgnoreError(const QByteArray &ignoreError) = 0; +- + /// Platform specific key to remove (usually Delete, Backspace on OS X). + virtual QString shortcutToRemove() = 0; + +--- a/src/tests/tests.cpp ++++ b/src/tests/tests.cpp +@@ -150,8 +150,6 @@ bool testStderr(const QByteArray &stderrData, TestInterface::ReadStderrFlag flag + // Ignore exceptions and errors from clients in application log + // (these are expected in some tests). + static const std::vector<QRegularExpression> ignoreList{ +- plain("[EXPECTED-IN-TEST]"), +- + regex(R"(CopyQ Note \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] <Client-[^\n]*)"), + + // X11 (Linux) +@@ -520,8 +518,6 @@ class TestInterfaceImpl final : public TestInterface { + if (m_server) { + QCoreApplication::processEvents(); + QByteArray output = readLogFile(maxReadLogSize); +- if ( !m_ignoreError.isEmpty() ) +- output.replace(m_ignoreError, "[EXPECTED-IN-TEST] " + m_ignoreError); + if ( flag == ReadAllStderr || !testStderr(output, flag) ) + return decorateOutput("Server STDERR", output); + } +@@ -645,16 +641,10 @@ class TestInterfaceImpl final : public TestInterface { + + QByteArray cleanup() override + { +- m_ignoreError.clear(); + addFailedTest(); + return QByteArray(); + } + +- void setIgnoreError(const QByteArray &ignoreError) override +- { +- m_ignoreError = ignoreError; +- } +- + QString shortcutToRemove() override + { + return ::shortcutToRemove(); +@@ -771,8 +761,6 @@ class TestInterfaceImpl final : public TestInterface { + QStringList m_failed; + + PlatformClipboardPtr m_clipboard; +- +- QByteArray m_ignoreError; + }; + + QString keyNameFor(QKeySequence::StandardKey standardKey) +@@ -2272,9 +2260,8 @@ void Tests::classItemSelection() + RUN(args << "ItemSelection().select(undefined, mimeItemNotes).str()", outRows.arg("0,2")); + + // Match nothing if select() argument is not a regular expression. +- m_test->setIgnoreError("QtWarning: QString::contains: invalid QRegularExpression object"); ++ RUN(args << "add" << "", ""); + RUN(args << "ItemSelection().select('A').str()", outRows.arg("")); +- m_test->setIgnoreError(QByteArray()); + } + + void Tests::classItemSelectionGetCurrent() diff --git a/x11-misc/copyq/files/copyq-7.1.0-support-plugin-dir-envvar.patch b/x11-misc/copyq/files/copyq-7.1.0-support-plugin-dir-envvar.patch new file mode 100644 index 000000000000..21c60f87011b --- /dev/null +++ b/x11-misc/copyq/files/copyq-7.1.0-support-plugin-dir-envvar.patch @@ -0,0 +1,26 @@ +From 32b45b42f0d9dbdaae077f81d11fff7bd2455492 Mon Sep 17 00:00:00 2001 +From: Alfred Wingate <parona@protonmail.com> +Date: Wed, 6 Dec 2023 06:16:36 +0200 +Subject: [PATCH] itemfactory: Add support for setting plugin dir in the + environment + +Signed-off-by: Alfred Wingate <parona@protonmail.com> +--- a/src/item/itemfactory.cpp ++++ b/src/item/itemfactory.cpp +@@ -31,6 +31,13 @@ namespace { + + bool findPluginDir(QDir *pluginsDir) + { ++ QString pluginDirEnv = qEnvironmentVariable("COPYQ_PLUGIN_DIR"); ++ if ( !pluginDirEnv.isEmpty() ) ++ pluginsDir->setPath(pluginDirEnv); ++ ++ if ( pluginsDir->isReadable() ) ++ return true; ++ + #ifdef COPYQ_PLUGIN_PREFIX + pluginsDir->setPath(COPYQ_PLUGIN_PREFIX); + if ( pluginsDir->isReadable() ) +-- +2.43.0 + diff --git a/x11-misc/copyq/metadata.xml b/x11-misc/copyq/metadata.xml index 7606b24718c3..8eb682c0fd8c 100644 --- a/x11-misc/copyq/metadata.xml +++ b/x11-misc/copyq/metadata.xml @@ -5,4 +5,7 @@ <upstream> <remote-id type="github">hluk/CopyQ</remote-id> </upstream> + <use> + <flag name="notification">Build with native notification support (requires <pkg>kde-frameworks/knotifications</pkg>:5)</flag> + </use> </pkgmetadata> |