diff --git a/.gitea/workflows/ci-release.yaml b/.gitea/workflows/ci-release.yaml index 684b10c..619032b 100644 --- a/.gitea/workflows/ci-release.yaml +++ b/.gitea/workflows/ci-release.yaml @@ -11,6 +11,7 @@ name: ci-release permissions: contents: write + packages: write jobs: verify: @@ -144,3 +145,38 @@ jobs: -H "Authorization: token ${GITEA_TOKEN}" \ -F "attachment=@${asset}" done + + publish-arch-package: + if: startsWith(github.ref, 'refs/tags/v') + needs: verify + runs-on: [self-hosted, linux, arch, homelab] + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build Arch package + shell: bash + run: | + set -euo pipefail + tag="${GITHUB_REF##*/}" + version="${tag#v}" + test "$version" = "$(tr -d '[:space:]' < VERSION)" + git archive --format=tar.gz --prefix="folderscope-${version}/" HEAD \ + > "packaging/arch/folderscope-${version}.tar.gz" + ( + cd packaging/arch + makepkg --syncdeps --noconfirm --force + ) + + - name: Publish to Gitea Arch registry + shell: bash + run: | + set -euo pipefail + package_file="$(find packaging/arch -maxdepth 1 -type f \ + -name 'folderscope-*.pkg.tar.zst' -print -quit)" + test -n "$package_file" + curl --fail --show-error --user "${GITEA_ACTOR}:${GITEA_TOKEN}" \ + --upload-file "$package_file" \ + "https://gitea.forust.xyz/api/packages/forust/arch/folderscope" diff --git a/.gitignore b/.gitignore index 018b973..e686364 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /build/ /cmake-build-*/ /out/ +/package/ +/dist/ /.idea/ /.vscode/ /CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 65ec4a5..a08dbe0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_AUTOMOC ON) -find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent DBus) +find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent DBus LinguistTools) add_library(folderscope_core STATIC src/search_core.cpp @@ -42,11 +42,37 @@ target_link_libraries(folderscope PRIVATE folderscope_core Qt6::Widgets Qt6::Con target_compile_options(folderscope PRIVATE -Wall -Wextra -Wpedantic) target_compile_definitions(folderscope PRIVATE FOLDERSCOPE_VERSION="${PROJECT_VERSION}") +qt_add_translations(folderscope + TS_FILES translations/folderscope_ru.ts +) + install(TARGETS folderscope RUNTIME DESTINATION bin) -install(FILES packaging/folderscope.desktop +install(FILES packaging/org.folderscope.FolderScope.desktop DESTINATION share/applications) install(FILES packaging/folderscope.svg - DESTINATION share/icons/hicolor/scalable/apps) + DESTINATION share/icons/hicolor/scalable/apps + RENAME org.folderscope.FolderScope.svg) +install(FILES packaging/org.folderscope.FolderScope.metainfo.xml + DESTINATION share/metainfo) +install(FILES packaging/man/folderscope.1 + DESTINATION share/man/man1) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/folderscope_ru.qm" + DESTINATION share/folderscope/translations) + +set(CPACK_PACKAGE_NAME "folderscope") +set(CPACK_PACKAGE_VENDOR "FolderScope contributors") +set(CPACK_PACKAGE_CONTACT "FolderScope contributors") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Fast advanced file search for Linux") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +set(CPACK_GENERATOR "DEB;RPM") +set(CPACK_DEBIAN_PACKAGE_SECTION "utils") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6core6 (>= 6.2), libqt6widgets6 (>= 6.2), libqt6dbus6 (>= 6.2)") +set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) +set(CPACK_RPM_PACKAGE_GROUP "Applications/FileTools") +set(CPACK_RPM_PACKAGE_LICENSE "MIT") +set(CPACK_RPM_PACKAGE_AUTOREQPROV ON) +include(CPack) include(CTest) if (BUILD_TESTING) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..521569b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 FolderScope contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 95d3375..8404e6a 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,47 @@ Install into the current system: cmake --install build ``` +## Packages + +CPack produces native packages after a release build (the output is ignored by +Git): + +```bash +cpack --config build/CPackConfig.cmake -B package +``` + +This creates `.deb` and `.rpm` packages. A Flatpak manifest is available at +`packaging/org.folderscope.FolderScope.yml`: + +```bash +flatpak-builder --user --install --force-clean build-flatpak \ + packaging/org.folderscope.FolderScope.yml +``` + +For Arch, use `packaging/arch/PKGBUILD` with a release tarball named +`folderscope-VERSION.tar.gz`. + +Published releases are also available through the Gitea Arch package registry. +Import its signing key and add the following to `/etc/pacman.conf`: + +```bash +curl -LO https://gitea.forust.xyz/api/packages/forust/arch/repository.key +sudo pacman-key --add repository.key +sudo pacman-key --lsign-key "$(gpg --show-keys --with-colons repository.key | awk -F: '/^fpr:/ {print $10; exit}')" +``` + +```ini +[folderscope] +SigLevel = Required +Server = https://gitea.forust.xyz/api/packages/forust/arch/$repo/$arch +``` + +Then install with `sudo pacman -Syu folderscope` (or `yay -S folderscope`). + +Translations are Qt `.ts` files in `translations/`; CMake compiles and installs +their `.qm` files automatically. The application selects the system locale at +startup. + ## Notes FolderScope targets Linux only. diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD new file mode 100644 index 0000000..a9653ef --- /dev/null +++ b/packaging/arch/PKGBUILD @@ -0,0 +1,23 @@ +pkgname=folderscope +pkgver=0.3.0 +pkgrel=1 +pkgdesc='Fast advanced file search for Linux' +arch=('x86_64') +url='https://gitea.forust.xyz/forust/folderscope' +license=('MIT') +depends=('qt6-base') +makedepends=('cmake' 'ninja') +source=("${pkgname}-${pkgver}.tar.gz") +sha256sums=('SKIP') + +build() { + cmake -S "${srcdir}/${pkgname}-${pkgver}" -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF + cmake --build build +} + +package() { + DESTDIR="${pkgdir}" cmake --install build + install -Dm644 "${srcdir}/${pkgname}-${pkgver}/LICENSE" \ + "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" +} diff --git a/packaging/man/folderscope.1 b/packaging/man/folderscope.1 new file mode 100644 index 0000000..347ed2d --- /dev/null +++ b/packaging/man/folderscope.1 @@ -0,0 +1,16 @@ +.TH FOLDERSCOPE 1 "August 2026" "FolderScope" "User Commands" +.SH NAME +folderscope \- fast advanced file search for Linux +.SH SYNOPSIS +.B folderscope +.SH DESCRIPTION +.B FolderScope +is a graphical file-search application. It searches selected folders without +maintaining an index or background service. Results can be filtered, exported, +opened in a file manager, moved to the desktop Trash, or permanently deleted. +.SH FILES +.TP +.I ~/.config/FolderScope/FolderScope.conf +Per-user settings and search preferences, managed by Qt. +.SH AUTHORS +FolderScope contributors. diff --git a/packaging/org.folderscope.FolderScope.desktop b/packaging/org.folderscope.FolderScope.desktop new file mode 100644 index 0000000..c9f8d0e --- /dev/null +++ b/packaging/org.folderscope.FolderScope.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=FolderScope +Comment=Fast advanced file search +Exec=folderscope +Icon=org.folderscope.FolderScope +Terminal=false +Categories=Utility;FileTools; diff --git a/packaging/org.folderscope.FolderScope.metainfo.xml b/packaging/org.folderscope.FolderScope.metainfo.xml new file mode 100644 index 0000000..b5d16f7 --- /dev/null +++ b/packaging/org.folderscope.FolderScope.metainfo.xml @@ -0,0 +1,14 @@ + + + org.folderscope.FolderScope + FolderScope + Fast advanced file search + MIT + MIT + + Search files in selected folders without an index or background service. + + org.folderscope.FolderScope.desktop + folderscope + + diff --git a/packaging/org.folderscope.FolderScope.yml b/packaging/org.folderscope.FolderScope.yml new file mode 100644 index 0000000..e67e4d6 --- /dev/null +++ b/packaging/org.folderscope.FolderScope.yml @@ -0,0 +1,20 @@ +app-id: org.folderscope.FolderScope +runtime: org.kde.Platform +runtime-version: '6.8' +sdk: org.kde.Sdk +command: folderscope +finish-args: + - --share=ipc + - --socket=fallback-x11 + - --socket=wayland + - --device=dri + - --filesystem=home +modules: + - name: folderscope + buildsystem: cmake-ninja + config-opts: + - -DCMAKE_BUILD_TYPE=Release + - -DBUILD_TESTING=OFF + sources: + - type: dir + path: .. diff --git a/src/main.cpp b/src/main.cpp index bb255f3..da5190d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,10 @@ #include +#include #include +#include #include #include +#include #include "main_window.h" #include "search_core.h" @@ -32,6 +35,14 @@ int main(int argc, char **argv) QApplication app(argc, argv); QCoreApplication::setOrganizationName(QStringLiteral("FolderScope")); QCoreApplication::setApplicationName(QStringLiteral("FolderScope")); + QTranslator translator; + const QString translationsPath = QDir(QCoreApplication::applicationDirPath()) + .filePath(QStringLiteral("../share/folderscope/translations")); + if ((translator.load(QLocale(), QStringLiteral("folderscope"), + QStringLiteral("_"), translationsPath) + || translator.load(QLocale(), QStringLiteral("folderscope"), + QStringLiteral("_"), QStringLiteral(":/i18n")))) + app.installTranslator(&translator); migrateLegacySettings(); QApplication::setStyle(QStringLiteral("Fusion")); qRegisterMetaType(); diff --git a/translations/folderscope_ru.ts b/translations/folderscope_ru.ts new file mode 100644 index 0000000..12b2ecd --- /dev/null +++ b/translations/folderscope_ru.ts @@ -0,0 +1,32 @@ + + + + + MainWindow + FolderScopeFolderScope + Search options…Параметры поиска… + StopОстановить + RefreshОбновить + OpenОткрыть + Open folderОткрыть папку + Open With…Открыть с помощью… + Move To TrashПереместить в корзину + Delete Selected FilesУдалить выбранные файлы + RenameПереименовать + PropertiesСвойства + &File&Файл + &Edit&Правка + &View&Вид + &Options&Настройки + &Help&Справка + Export…Экспорт… + Find…Найти… + Find nextНайти далее + Copy full filenames pathКопировать полные пути + Explorer CopyКопировать + Explorer CutВырезать + AboutО программе + Move %1 selected item(s) to Trash?Переместить в корзину: %1 шт.? + Failed to move %1 item(s) to Trash.Не удалось переместить в корзину: %1 шт. + +
Search files in selected folders without an index or background service.