diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddbaea7..f69bc3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,6 +60,9 @@ jobs: - os: macos-latest gifsicle-path: vendor/gifsicle/gifsicle skip_gifsicle: '' + - os: ubuntu-latest + gifsicle-path: vendor/gifsicle/gifsicle + skip_gifsicle: '' # todo: prebuilt gifsicle.exe for ci and windows release - os: windows-latest gifsicle-path: vendor/gifsicle/gifsicle.exe @@ -100,6 +103,20 @@ jobs: if: runner.os == 'macOS' run: brew install dav1d + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + libxdo-dev \ + libssl-dev \ + libdav1d-dev \ + nasm \ + patchelf + - name: Cache vcpkg (Windows) if: runner.os == 'Windows' uses: actions/cache@v5 @@ -124,7 +141,7 @@ jobs: run: ./scripts/set-vc-runtime-env.ps1 - name: Cache gifsicle binary - if: runner.os == 'macOS' + if: runner.os != 'Windows' uses: actions/cache@v5 id: gifsicle-cache with: @@ -138,3 +155,66 @@ jobs: - name: Rust tests run: npm run ci:rust + + build-linux: + needs: changes + if: needs.changes.outputs.rust == 'true' + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: src-tauri + + - name: Install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + libxdo-dev \ + libssl-dev \ + libdav1d-dev \ + libfuse2 \ + nasm \ + file \ + patchelf + + - name: Cache gifsicle binary + uses: actions/cache@v5 + with: + path: vendor/gifsicle/gifsicle + key: gifsicle-${{ runner.os }}-${{ runner.arch }}-1.96 + + - name: Install dependencies + run: npm ci + env: + HUSKY: 0 + + - name: Build AppImage + run: >- + npm run tauri -- build --bundles appimage + --config '{"bundle":{"createUpdaterArtifacts":false}}' + + - name: Verify AppImage bundle + run: | + appimage="$(find src-tauri/target -name '*.AppImage' -path '*/release/bundle/appimage/*' | head -1)" + if [[ -z "$appimage" ]]; then + echo "build-linux: AppImage bundle not found" + exit 1 + fi + ls -lh "$appimage" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d075678..7bb52e7 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,9 +1,5 @@ name: publish -# Windows release build. Trigger manually after version bump is on main. -# Creates a draft GitHub release for v. -# Then: Mac build locally, upload assets, merge latest.json, publish release. - on: workflow_dispatch: @@ -154,8 +150,86 @@ jobs: - macOS: `DropSlim_*_aarch64.dmg` (Apple Silicon) - Windows: `DropSlim_*_x64-setup.exe` (64-bit) + - Linux: `DropSlim_*_amd64.AppImage` (x86_64) macOS assets are uploaded separately after the local release build. releaseDraft: true prerelease: false args: '--bundles nsis' + + publish-linux: + permissions: + contents: write + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Read app version + id: app + run: | + version=$(node -p "require('./package.json').version") + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "tag=v$version" >> "$GITHUB_OUTPUT" + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: npm + + - name: Install Rust stable + uses: dtolnay/rust-toolchain@stable + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: src-tauri + + - name: Install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libwebkit2gtk-4.1-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev \ + libxdo-dev \ + libssl-dev \ + libdav1d-dev \ + libfuse2 \ + nasm \ + file \ + patchelf + + - name: Cache gifsicle binary + uses: actions/cache@v5 + with: + path: vendor/gifsicle/gifsicle + key: gifsicle-${{ runner.os }}-${{ runner.arch }}-1.96 + + - name: Install dependencies + run: npm ci + env: + HUSKY: 0 + + - name: Build and release + uses: tauri-apps/tauri-action@v0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} + TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} + with: + tagName: ${{ steps.app.outputs.tag }} + releaseName: DropSlim v${{ steps.app.outputs.version }} + releaseBody: | + DropSlim v${{ steps.app.outputs.version }} + + - macOS: `DropSlim_*_aarch64.dmg` (Apple Silicon) + - Windows: `DropSlim_*_x64-setup.exe` (64-bit) + - Linux: `DropSlim_*_amd64.AppImage` (x86_64) + + macOS assets are uploaded separately after the local release build. + releaseDraft: true + prerelease: false + args: '--bundles appimage' diff --git a/.gitignore b/.gitignore index 3262d8b..041727c 100644 --- a/.gitignore +++ b/.gitignore @@ -28,8 +28,6 @@ src-tauri/icons/icon.ico .DS_Store .vscode/* -!.vscode/settings.json -!.vscode/extensions.json *.swp *.swo *~ diff --git a/package.json b/package.json index d1a3a6e..c968fef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dropslim", - "version": "1.4.0", + "version": "1.5.0-linux-test.1", "description": "Optimize your images and graphics in a single drag and drop.", "author": "Martin Farkas", "license": "MIT", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 76ecb06..e79d458 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1348,7 +1348,7 @@ dependencies = [ [[package]] name = "dropslim" -version = "1.4.0" +version = "1.5.0-linux-test.1" dependencies = [ "image", "imagequant", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d8f9dc3..0439db1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dropslim" -version = "1.4.0" +version = "1.5.0-linux-test.1" description = "Optimize your images and graphics in a single drag and drop." authors = ["Martin Farkas"] edition = "2021" diff --git a/src-tauri/src/platform/dialogs/mod.rs b/src-tauri/src/platform/dialogs/mod.rs index db0c33e..937b73d 100644 --- a/src-tauri/src/platform/dialogs/mod.rs +++ b/src-tauri/src/platform/dialogs/mod.rs @@ -2,10 +2,10 @@ mod macos; #[cfg(not(target_os = "macos"))] -mod desktop; +mod non_macos; #[cfg(target_os = "macos")] pub use macos::{pick_paths, pick_save_folder}; #[cfg(not(target_os = "macos"))] -pub use desktop::{pick_paths, pick_save_folder}; +pub use non_macos::{pick_paths, pick_save_folder}; diff --git a/src-tauri/src/platform/dialogs/desktop.rs b/src-tauri/src/platform/dialogs/non_macos.rs similarity index 100% rename from src-tauri/src/platform/dialogs/desktop.rs rename to src-tauri/src/platform/dialogs/non_macos.rs diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 1281fe0..efe337e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -34,17 +34,7 @@ "icon": ["icons/icon.png"], "fileAssociations": [ { - "ext": [ - "png", - "jpg", - "jpeg", - "gif", - "svg", - "webp", - "avif", - "heic", - "heif" - ], + "ext": ["png", "jpg", "jpeg", "gif", "svg", "webp", "avif"], "name": "Image", "role": "Editor" } diff --git a/src-tauri/tauri.linux.conf.json b/src-tauri/tauri.linux.conf.json new file mode 100644 index 0000000..6a6592b --- /dev/null +++ b/src-tauri/tauri.linux.conf.json @@ -0,0 +1,31 @@ +{ + "app": { + "windows": [ + { + "label": "main", + "title": "DropSlim", + "width": 480, + "height": 840, + "minWidth": 480, + "minHeight": 840, + "resizable": true, + "dragDropEnabled": true, + "transparent": false, + "titleBarStyle": "Visible", + "acceptFirstMouse": false + } + ] + }, + "bundle": { + "targets": ["appimage"], + "icon": ["icons/icon.png"], + "resources": { + "resources/": "resources/" + }, + "linux": { + "appimage": { + "bundleMediaFramework": false + } + } + } +} diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json index a1da396..722bfcf 100644 --- a/src-tauri/tauri.macos.conf.json +++ b/src-tauri/tauri.macos.conf.json @@ -11,6 +11,23 @@ "bundle": { "targets": ["dmg", "app"], "icon": ["icons/icon.png", "icons/icon.icns"], + "fileAssociations": [ + { + "ext": [ + "png", + "jpg", + "jpeg", + "gif", + "svg", + "webp", + "avif", + "heic", + "heif" + ], + "name": "Image", + "role": "Editor" + } + ], "macOS": { "minimumSystemVersion": "11.0", "signingIdentity": "-", diff --git a/src-tauri/tests/optimize_integration.rs b/src-tauri/tests/optimize_integration.rs index 45c2c57..451b3f2 100644 --- a/src-tauri/tests/optimize_integration.rs +++ b/src-tauri/tests/optimize_integration.rs @@ -35,17 +35,18 @@ fn create_raster_fixture(dir: &TempDir, name: &str, create: impl FnOnce(&Path)) path } -// skips when gifsicle is missing (e.g. windows ci with ci_skip_gifsicle=1) -// todo: bundle gifsicle.exe and run gif integration tests on windows +// skips tests when gifsicle is missing (e.g. windows ci with ci_skip_gifsicle=1) +// linux/macos build gifsicle from source, windows ci still needs a prebuilt .exe fn require_gifsicle() -> Option { + let binary_name = if cfg!(windows) { + "gifsicle.exe" + } else { + "gifsicle" + }; let gifsicle = project_root() .join("vendor") .join("gifsicle") - .join(if cfg!(windows) { - "gifsicle.exe" - } else { - "gifsicle" - }); + .join(binary_name); if !gifsicle.exists() { eprintln!( diff --git a/test/fixtures/all-formats/sample-no-doctype.svg b/test/fixtures/all-formats/sample-no-doctype.svg new file mode 100644 index 0000000..2e6a287 --- /dev/null +++ b/test/fixtures/all-formats/sample-no-doctype.svg @@ -0,0 +1,9 @@ + + + DropSlim fixture + Used by optimizer integration tests + + + + + diff --git a/test/fixtures/all-formats/sample-with-doctype.svg b/test/fixtures/all-formats/sample-with-doctype.svg new file mode 100644 index 0000000..cbf1878 --- /dev/null +++ b/test/fixtures/all-formats/sample-with-doctype.svg @@ -0,0 +1,10 @@ + + + + + DTD fixture + SVG with DOCTYPE for optimizer integration tests + + + + diff --git a/test/fixtures/all-formats/sample.avif b/test/fixtures/all-formats/sample.avif new file mode 100644 index 0000000..498c3d8 Binary files /dev/null and b/test/fixtures/all-formats/sample.avif differ diff --git a/test/fixtures/all-formats/sample.gif b/test/fixtures/all-formats/sample.gif new file mode 100644 index 0000000..4437361 Binary files /dev/null and b/test/fixtures/all-formats/sample.gif differ diff --git a/test/fixtures/all-formats/sample.heic b/test/fixtures/all-formats/sample.heic new file mode 100644 index 0000000..ed3bb3f Binary files /dev/null and b/test/fixtures/all-formats/sample.heic differ diff --git a/test/fixtures/all-formats/sample.heif b/test/fixtures/all-formats/sample.heif new file mode 100644 index 0000000..ed3bb3f Binary files /dev/null and b/test/fixtures/all-formats/sample.heif differ diff --git a/test/fixtures/all-formats/sample.jpeg b/test/fixtures/all-formats/sample.jpeg new file mode 100644 index 0000000..74a64d8 Binary files /dev/null and b/test/fixtures/all-formats/sample.jpeg differ diff --git a/test/fixtures/all-formats/sample.jpg b/test/fixtures/all-formats/sample.jpg new file mode 100644 index 0000000..74a64d8 Binary files /dev/null and b/test/fixtures/all-formats/sample.jpg differ diff --git a/test/fixtures/all-formats/sample.png b/test/fixtures/all-formats/sample.png new file mode 100644 index 0000000..47097b6 Binary files /dev/null and b/test/fixtures/all-formats/sample.png differ diff --git a/test/fixtures/all-formats/sample.webp b/test/fixtures/all-formats/sample.webp new file mode 100644 index 0000000..2e4111c Binary files /dev/null and b/test/fixtures/all-formats/sample.webp differ diff --git a/ui/main.js b/ui/main.js index 21721b8..c375fe2 100644 --- a/ui/main.js +++ b/ui/main.js @@ -15,6 +15,8 @@ const boot = async () => { document.body.classList.add('platform-desktop') if (osType === 'windows') { document.body.classList.add('platform-win') + } else if (osType === 'linux') { + document.body.classList.add('platform-linux') } }