From 41fc737e719dbee68c3a7f4c1ba7dedba2f9d7a7 Mon Sep 17 00:00:00 2001 From: burnintuna Date: Tue, 21 Jul 2026 03:42:51 +0900 Subject: [PATCH] Prepare v0.1.3 AppImage fix --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 11 +-- ...ithub.comicviewer.Comicviewer.metainfo.xml | 1 + docs/INSTALL.ko.md | 40 +++++------ docs/RELEASING.ko.md | 50 +++++++------ packaging/build-appimage.sh | 56 +++++++++------ packaging/build-release-bundle.sh | 9 --- packaging/install-split-release.sh | 70 ------------------- 9 files changed, 87 insertions(+), 154 deletions(-) delete mode 100755 packaging/install-split-release.sh diff --git a/Cargo.lock b/Cargo.lock index d073622..e9fcd45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,7 +182,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "comicviewer" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "chrono", diff --git a/Cargo.toml b/Cargo.toml index c1e03b1..fdc6f00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "comicviewer" -version = "0.1.2" +version = "0.1.3" edition = "2024" description = "A comic archive viewer for local and remote locations" license = "GPL-3.0-or-later" diff --git a/README.md b/README.md index 5021c88..d42fa28 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ XDG-compliant configuration. On CachyOS or Arch Linux: ```sh -sudo pacman -S rust gtk4 sqlite gvfs gvfs-smb +sudo pacman -S rust gtk4 dav1d sqlite gvfs gvfs-smb ``` Run the application with: @@ -28,16 +28,17 @@ Run the application with: cargo run ``` -GVfs provides the FTP and SFTP backends. `gvfs-smb` adds SMB support. These -services must be installed on the host even when Comicviewer is distributed as -an AppImage. +The AppImage uses the host's GTK4 and dav1d libraries. GVfs provides the FTP +and SFTP backends, while `gvfs-smb` adds SMB support. These packages must be +installed on the host. Application files are stored below the standard XDG configuration, data, and cache directories. No runtime state is written into the source tree. ## AppImage -The AppImage build uses `linuxdeploy` and `linuxdeploy-plugin-gtk`: +The AppImage build uses `appimagetool`. The script can extract appimagetool +from a linuxdeploy AppImage when it is not provided directly: ```sh PATH="/path/to/appimage-tools:$PATH" \ diff --git a/data/io.github.comicviewer.Comicviewer.metainfo.xml b/data/io.github.comicviewer.Comicviewer.metainfo.xml index 3bf3ee3..000e0dc 100644 --- a/data/io.github.comicviewer.Comicviewer.metainfo.xml +++ b/data/io.github.comicviewer.Comicviewer.metainfo.xml @@ -26,6 +26,7 @@ + diff --git a/docs/INSTALL.ko.md b/docs/INSTALL.ko.md index 6c5c840..389ae8b 100644 --- a/docs/INSTALL.ko.md +++ b/docs/INSTALL.ko.md @@ -8,33 +8,31 @@ Comicviewer는 CachyOS와 Arch Linux에서 사용할 수 있는 만화 ZIP 뷰 AppImage 실행과 원격 파일 접근에 필요한 패키지를 설치합니다. ```sh -sudo pacman -S fuse2 gvfs gvfs-smb +sudo pacman -S fuse2 gtk4 dav1d gvfs gvfs-smb ``` - `fuse2`: AppImage 마운트 및 실행 +- `gtk4`, `dav1d`: 화면 표시와 이미지 디코딩 - `gvfs`: FTP와 SFTP 접근 - `gvfs-smb`: SMB 공유 접근 ## 2. 권장 방법: 통합 번들로 설치 또는 업데이트 -Release 페이지에서 `v0.1.2` 최신 Release를 열고 다음 파일을 모두 같은 폴더에 -다운로드합니다. 이 Git 서버에서는 대용량 파일 전송이 손상될 수 있어 통합 -번들을 8MiB 단위로 나누어 제공합니다. +Release 페이지에서 다음 두 파일을 같은 폴더에 다운로드합니다. -- `Comicviewer-0.1.2-x86_64-install.sh` -- `Comicviewer-0.1.2-x86_64.tar.gz.sha256` -- `Comicviewer-0.1.2-x86_64.tar.gz.parts.sha256` -- 이름이 `Comicviewer-0.1.2-x86_64.tar.gz.part-`로 시작하는 모든 파일 +- `Comicviewer-0.1.3-x86_64.tar.gz` +- `Comicviewer-0.1.3-x86_64.tar.gz.sha256` -다운로드 폴더에서 설치 스크립트에 실행 권한을 부여하고 실행합니다. +체크섬을 확인하고 압축을 푼 뒤 설치 스크립트를 실행합니다. ```sh -chmod +x Comicviewer-0.1.2-x86_64-install.sh -./Comicviewer-0.1.2-x86_64-install.sh +sha256sum -c Comicviewer-0.1.3-x86_64.tar.gz.sha256 +tar -xzf Comicviewer-0.1.3-x86_64.tar.gz +cd Comicviewer-0.1.3-x86_64 +./install-or-update.sh ``` -스크립트는 각 분할 파일과 조립한 통합 번들, AppImage의 체크섬을 차례로 -검증하고 다음 작업을 수행합니다. +스크립트는 AppImage 체크섬을 검증하고 다음 작업을 수행합니다. - AppImage를 `~/.local/opt/comicviewer/Comicviewer.AppImage`에 설치 - `~/.local/bin/comicviewer` 실행 링크 생성 @@ -47,7 +45,7 @@ chmod +x Comicviewer-0.1.2-x86_64-install.sh 제거하려면 압축을 푼 번들 폴더에서 다음을 실행합니다. ```sh -./Comicviewer-0.1.2-x86_64-install.sh --uninstall +./install-or-update.sh --uninstall ``` 이 명령은 프로그램과 함께 저장한 위치 및 인증정보, 읽기 기록, 원격 ZIP 캐시를 @@ -58,13 +56,13 @@ chmod +x Comicviewer-0.1.2-x86_64-install.sh Release 페이지에서 다음 두 파일을 같은 폴더에 다운로드합니다. -- `Comicviewer-0.1.2-x86_64.AppImage` -- `Comicviewer-0.1.2-x86_64.AppImage.sha256` +- `Comicviewer-0.1.3-x86_64.AppImage` +- `Comicviewer-0.1.3-x86_64.AppImage.sha256` 다운로드한 폴더에서 체크섬을 검증합니다. ```sh -sha256sum -c Comicviewer-0.1.2-x86_64.AppImage.sha256 +sha256sum -c Comicviewer-0.1.3-x86_64.AppImage.sha256 ``` `성공` 또는 `OK`가 표시되어야 합니다. 검증에 실패하면 파일을 실행하지 말고 @@ -75,15 +73,15 @@ sha256sum -c Comicviewer-0.1.2-x86_64.AppImage.sha256 AppImage에 실행 권한을 부여한 뒤 실행합니다. ```sh -chmod +x Comicviewer-0.1.2-x86_64.AppImage -./Comicviewer-0.1.2-x86_64.AppImage +chmod +x Comicviewer-0.1.3-x86_64.AppImage +./Comicviewer-0.1.3-x86_64.AppImage ``` FUSE를 사용할 수 없는 환경에서는 다음과 같이 임시 추출 방식으로 실행할 수 있습니다. ```sh -./Comicviewer-0.1.2-x86_64.AppImage --appimage-extract-and-run +./Comicviewer-0.1.3-x86_64.AppImage --appimage-extract-and-run ``` ## 5. 선택 사항: 수동으로 사용자 계정에 설치 @@ -93,7 +91,7 @@ AppImage를 사용자 전용 프로그램 폴더에 설치하고 명령어로 ```sh mkdir -p ~/.local/opt/comicviewer ~/.local/bin -install -m 755 Comicviewer-0.1.2-x86_64.AppImage \ +install -m 755 Comicviewer-0.1.3-x86_64.AppImage \ ~/.local/opt/comicviewer/Comicviewer.AppImage ln -sfn ~/.local/opt/comicviewer/Comicviewer.AppImage ~/.local/bin/comicviewer ``` diff --git a/docs/RELEASING.ko.md b/docs/RELEASING.ko.md index 46698cd..ab9ff88 100644 --- a/docs/RELEASING.ko.md +++ b/docs/RELEASING.ko.md @@ -8,7 +8,7 @@ Release 첨부 파일로 제공하는 방식을 권장합니다. 버전별 바 절차를 사용합니다. 태그, 프로젝트 버전, AppImage, 통합 번들의 버전은 반드시 같아야 합니다. -예를 들어 `v0.1.2` Release에는 이름에 `0.1.2`가 포함된 파일만 첨부합니다. +예를 들어 `v0.1.3` Release에는 이름에 `0.1.3`이 포함된 파일만 첨부합니다. Git 태그만 푸시하면 첨부 파일은 자동으로 등록되지 않으므로, 마지막 단계에서 Release를 만들고 파일 네 개를 직접 첨부해야 합니다. @@ -32,8 +32,9 @@ cargo test --all-features ## 3. AppImage 빌드 -`linuxdeploy-x86_64.AppImage`와 `linuxdeploy-plugin-gtk.sh`가 있는 도구 -폴더를 지정합니다. +`appimagetool`을 직접 지정하거나, appimagetool을 포함한 +`linuxdeploy-x86_64.AppImage`를 지정합니다. AppImage는 Arch/CachyOS 호스트의 +GTK4와 dav1d를 사용하며 시스템 라이브러리를 내부에 복사하지 않습니다. ```sh PATH="/path/to/appimage-tools:$PATH" \ @@ -55,12 +56,9 @@ AppImage 빌드가 끝나면 다음 스크립트로 체크섬과 통합 `tar.gz` 스크립트는 `Cargo.toml`에서 버전을 읽고 다음 파일을 생성합니다. -- `dist/Comicviewer-0.1.2-x86_64.AppImage.sha256` -- `dist/Comicviewer-0.1.2-x86_64.tar.gz` -- `dist/Comicviewer-0.1.2-x86_64.tar.gz.sha256` -- `dist/Comicviewer-0.1.2-x86_64.tar.gz.parts.sha256` -- `dist/Comicviewer-0.1.2-x86_64.tar.gz.part-*` -- `dist/Comicviewer-0.1.2-x86_64-install.sh` +- `dist/Comicviewer-0.1.3-x86_64.AppImage.sha256` +- `dist/Comicviewer-0.1.3-x86_64.tar.gz` +- `dist/Comicviewer-0.1.3-x86_64.tar.gz.sha256` 통합 번들에는 AppImage, 체크섬, 설치·업데이트 스크립트, 데스크톱 파일, 아이콘, 한국어 설치 안내문이 포함됩니다. `tar.gz`는 실행 권한과 디렉터리 구조를 @@ -69,10 +67,9 @@ AppImage 빌드가 끝나면 다음 스크립트로 체크섬과 통합 `tar.gz` 생성된 번들의 압축 목록과 체크섬을 확인합니다. ```sh -tar -tzf dist/Comicviewer-0.1.2-x86_64.tar.gz +tar -tzf dist/Comicviewer-0.1.3-x86_64.tar.gz cd dist -sha256sum -c Comicviewer-0.1.2-x86_64.tar.gz.sha256 -sha256sum -c Comicviewer-0.1.2-x86_64.tar.gz.parts.sha256 +sha256sum -c Comicviewer-0.1.3-x86_64.tar.gz.sha256 ``` ## 5. 소스 커밋과 태그 @@ -82,10 +79,10 @@ sha256sum -c Comicviewer-0.1.2-x86_64.tar.gz.parts.sha256 ```sh git add Cargo.toml Cargo.lock data packaging README.md docs -git commit -m "Prepare v0.1.2 release" -git tag -a v0.1.2 -m "Comicviewer v0.1.2" +git commit -m "Prepare v0.1.3 release" +git tag -a v0.1.3 -m "Comicviewer v0.1.3" git push origin main -git push origin v0.1.2 +git push origin v0.1.3 ``` 이미 원격에 공개한 태그는 이동하거나 덮어쓰지 않습니다. 수정이 필요하면 새 @@ -96,25 +93,26 @@ git push origin v0.1.2 Git 서버의 Releases 화면에서 푸시한 태그를 선택해 Release를 생성하고 다음 파일을 첨부합니다. -- `Comicviewer-0.1.2-x86_64-install.sh` -- `Comicviewer-0.1.2-x86_64.tar.gz.sha256` -- `Comicviewer-0.1.2-x86_64.tar.gz.parts.sha256` -- `Comicviewer-0.1.2-x86_64.tar.gz.part-*` 전체 +- `Comicviewer-0.1.3-x86_64.tar.gz` +- `Comicviewer-0.1.3-x86_64.tar.gz.sha256` +- `Comicviewer-0.1.3-x86_64.AppImage` +- `Comicviewer-0.1.3-x86_64.AppImage.sha256` -이 서버에서는 대용량 단일 HTTP 다운로드가 손상될 수 있으므로 AppImage와 -통합 `tar.gz` 원본은 직접 첨부하지 않습니다. 각 분할 파일은 8MiB 이하이며, -업로드 후 반드시 원격에서 다시 내려받아 체크섬을 확인합니다. +호스트 라이브러리형 AppImage는 크기가 작지만, 업로드 후에도 반드시 원격에서 +다시 내려받아 체크섬과 실제 실행을 확인합니다. Release 설명에는 주요 변경 사항과 함께 다음 요구사항을 안내합니다. ```text 지원 환경: CachyOS / Arch Linux x86_64 -필수 패키지: fuse2, gvfs, gvfs-smb +필수 패키지: fuse2, gtk4, dav1d, gvfs, gvfs-smb 권장 설치 또는 업데이트: -첨부 파일을 모두 같은 폴더에 다운로드한 뒤 실행합니다. -chmod +x Comicviewer-0.1.2-x86_64-install.sh -./Comicviewer-0.1.2-x86_64-install.sh +tar.gz와 tar.gz.sha256을 같은 폴더에 다운로드한 뒤 실행합니다. +sha256sum -c Comicviewer-0.1.3-x86_64.tar.gz.sha256 +tar -xzf Comicviewer-0.1.3-x86_64.tar.gz +cd Comicviewer-0.1.3-x86_64 +./install-or-update.sh ``` 사용자에게는 [`INSTALL.ko.md`](INSTALL.ko.md) 문서를 함께 안내합니다. diff --git a/packaging/build-appimage.sh b/packaging/build-appimage.sh index 54c1348..087ee51 100755 --- a/packaging/build-appimage.sh +++ b/packaging/build-appimage.sh @@ -3,6 +3,7 @@ set -euo pipefail root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" linuxdeploy="${LINUXDEPLOY:-linuxdeploy-x86_64.AppImage}" +appimagetool="${APPIMAGETOOL:-}" output_dir="${OUTPUT_DIR:-${root_dir}/dist}" package_id="$(cargo pkgid --manifest-path "${root_dir}/Cargo.toml")" version="${package_id##*@}" @@ -16,34 +17,47 @@ trap cleanup EXIT cargo build --manifest-path "${root_dir}/Cargo.toml" --release mkdir -p "${output_dir}" -mkdir -p "${app_dir}/usr/share/metainfo" +mkdir -p \ + "${app_dir}/usr/bin" \ + "${app_dir}/usr/share/applications" \ + "${app_dir}/usr/share/icons/hicolor/scalable/apps" \ + "${app_dir}/usr/share/metainfo" +install -m 0755 "${root_dir}/target/release/comicviewer" "${app_dir}/usr/bin/comicviewer" +install -m 0755 "${root_dir}/packaging/AppRun" "${app_dir}/AppRun" +install -m 0644 \ + "${root_dir}/data/io.github.comicviewer.Comicviewer.desktop" \ + "${app_dir}/io.github.comicviewer.Comicviewer.desktop" +install -m 0644 \ + "${root_dir}/data/io.github.comicviewer.Comicviewer.desktop" \ + "${app_dir}/usr/share/applications/io.github.comicviewer.Comicviewer.desktop" +install -m 0644 \ + "${root_dir}/data/io.github.comicviewer.Comicviewer.svg" \ + "${app_dir}/io.github.comicviewer.Comicviewer.svg" +install -m 0644 \ + "${root_dir}/data/io.github.comicviewer.Comicviewer.svg" \ + "${app_dir}/usr/share/icons/hicolor/scalable/apps/io.github.comicviewer.Comicviewer.svg" install -m 0644 \ "${root_dir}/data/io.github.comicviewer.Comicviewer.metainfo.xml" \ "${app_dir}/usr/share/metainfo/io.github.comicviewer.Comicviewer.appdata.xml" output_path="${output_dir}/Comicviewer-${version}-x86_64.AppImage" -export LDAI_OUTPUT="${output_path}" -export PATH="$(dirname "${linuxdeploy}"):${PATH}" -export APPIMAGE_EXTRACT_AND_RUN=1 -export NO_STRIP=1 -# The GTK plugin assumes this optional module directory exists on every distro. -gtk_plugin="$(command -v linuxdeploy-plugin-gtk.sh || true)" -if [[ -n "${gtk_plugin}" ]] && [[ ! -d "$(pkg-config --variable=libdir gtk4)/gtk-4.0" ]]; then - patched_plugin="${work_dir}/linuxdeploy-plugin-gtk.sh" - cp "${gtk_plugin}" "${patched_plugin}" - sed -i 's| copy_lib_tree "$gtk4_libdir" "$APPDIR/"| if [ -d "$gtk4_libdir" ]; then copy_lib_tree "$gtk4_libdir" "$APPDIR/"; fi|' "${patched_plugin}" - chmod +x "${patched_plugin}" - export PATH="${work_dir}:${PATH}" +if [[ -z "${appimagetool}" ]]; then + linuxdeploy_path="$(command -v "${linuxdeploy}" || true)" + if [[ -z "${linuxdeploy_path}" ]]; then + printf '%s\n' "APPIMAGETOOL 또는 LINUXDEPLOY를 지정하세요." >&2 + exit 1 + fi + tool_dir="${work_dir}/appimage-tools" + mkdir -p "${tool_dir}" + ( + cd "${tool_dir}" + "${linuxdeploy_path}" --appimage-extract >/dev/null + ) + appimagetool="${tool_dir}/squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool" fi -"${linuxdeploy}" \ - --appdir "${app_dir}" \ - --executable "${root_dir}/target/release/comicviewer" \ - --desktop-file "${root_dir}/data/io.github.comicviewer.Comicviewer.desktop" \ - --icon-file "${root_dir}/data/io.github.comicviewer.Comicviewer.svg" \ - --custom-apprun "${root_dir}/packaging/AppRun" \ - --plugin gtk \ - --output appimage +env ARCH=x86_64 APPIMAGE_EXTRACT_AND_RUN=1 \ + "${appimagetool}" "${app_dir}" "${output_path}" echo "Created ${output_path}" diff --git a/packaging/build-release-bundle.sh b/packaging/build-release-bundle.sh index b676a1a..39b44bd 100755 --- a/packaging/build-release-bundle.sh +++ b/packaging/build-release-bundle.sh @@ -10,8 +10,6 @@ appimage="${root_dir}/dist/${appimage_name}" checksum="${appimage}.sha256" archive="${root_dir}/dist/${bundle_name}.tar.gz" archive_checksum="${archive}.sha256" -parts_checksum="${archive}.parts.sha256" -split_installer="${root_dir}/dist/${bundle_name}-install.sh" work_dir="$(mktemp -d)" bundle_dir="${work_dir}/${bundle_name}" archive_mtime="${SOURCE_DATE_EPOCH:-$(git -C "${root_dir}" log -1 --format=%ct)}" @@ -51,14 +49,7 @@ tar --sort=name --owner=0 --group=0 --numeric-owner --mtime="@${archive_mtime}" ( cd "${root_dir}/dist" sha256sum "$(basename "${archive}")" > "$(basename "${archive_checksum}")" - rm -f "$(basename "${archive}").part-"* "$(basename "${parts_checksum}")" - split --bytes=8M --numeric-suffixes=0 --suffix-length=2 \ - "$(basename "${archive}")" "$(basename "${archive}").part-" - sha256sum "$(basename "${archive}").part-"* > "$(basename "${parts_checksum}")" ) -install -m 0755 "${root_dir}/packaging/install-split-release.sh" "${split_installer}" printf 'Created %s\n' "${archive}" printf 'Created %s\n' "${archive_checksum}" -printf 'Created %s and split parts\n' "${parts_checksum}" -printf 'Created %s\n' "${split_installer}" diff --git a/packaging/install-split-release.sh b/packaging/install-split-release.sh deleted file mode 100755 index 88fe2c6..0000000 --- a/packaging/install-split-release.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" -temporary_archive="" -extract_dir="" - -case "$#:${1:-}" in - 0:) action="" ;; - 1:--uninstall) action="--uninstall" ;; - *) - printf '사용법: %s [--uninstall]\n' "$(basename -- "$0")" >&2 - exit 2 - ;; -esac - -cleanup() { - [ -z "${temporary_archive}" ] || rm -f "${temporary_archive}" - [ -z "${extract_dir}" ] || rm -rf "${extract_dir}" -} -trap cleanup EXIT HUP INT TERM - -set -- "${script_dir}"/Comicviewer-*-x86_64.tar.gz.parts.sha256 -if [ "$#" -ne 1 ] || [ ! -f "$1" ]; then - printf '%s\n' "분할 파일 체크섬 목록 한 개를 찾을 수 없습니다." >&2 - exit 1 -fi - -parts_checksum="$1" -archive_name="$(basename -- "${parts_checksum%.parts.sha256}")" -archive_checksum="${script_dir}/${archive_name}.sha256" - -if [ ! -f "${archive_checksum}" ]; then - printf '필수 파일이 없습니다: %s\n' "$(basename -- "${archive_checksum}")" >&2 - exit 1 -fi - -set -- "${script_dir}/${archive_name}.part-"* -if [ ! -f "$1" ]; then - printf '%s\n' "분할 번들 파일을 찾을 수 없습니다." >&2 - exit 1 -fi - -(cd "${script_dir}" && sha256sum -c "$(basename -- "${parts_checksum}")") - -temporary_archive="$(mktemp "${TMPDIR:-/tmp}/comicviewer-bundle.XXXXXX.tar.gz")" -cat "$@" > "${temporary_archive}" - -IFS=' ' read -r expected_checksum _ < "${archive_checksum}" -actual_checksum="$(sha256sum "${temporary_archive}")" -actual_checksum="${actual_checksum%% *}" -if [ "${actual_checksum}" != "${expected_checksum}" ]; then - printf '%s\n' "조립한 통합 번들의 체크섬이 일치하지 않습니다." >&2 - exit 1 -fi - -extract_dir="$(mktemp -d "${TMPDIR:-/tmp}/comicviewer-install.XXXXXX")" -tar -xzf "${temporary_archive}" -C "${extract_dir}" -bundle_dir="${extract_dir}/${archive_name%.tar.gz}" - -if [ ! -x "${bundle_dir}/install-or-update.sh" ]; then - printf '%s\n' "통합 번들에서 설치 스크립트를 찾을 수 없습니다." >&2 - exit 1 -fi - -if [ -n "${action}" ]; then - "${bundle_dir}/install-or-update.sh" "${action}" -else - "${bundle_dir}/install-or-update.sh" -fi