From 6dc45c983071a1e6678e6aeda22a6323f73c5bda Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 21 Feb 2025 17:39:13 +0800 Subject: [PATCH] feat: use flutter_distrubutor to build linux and macos packages (#7392) * feat: use flutter_distrubutor to build linux packages * feat: verify deb on Linux * chore: update rpm deps * chore: update codesign files * chore: update rpm make_config.yaml * chore: update release.yml * chore: update release.yml * chore: update feed url * chore: rename AppFlowy to appflowy * chore: update CHANGELOG.md (#7397) * chore: create release path if not exist * feat: support appimage * Revert "feat: support appimage" This reverts commit cb7dcf725c9443f5f9d0e3c3ceb4413a4f875e6a. * fix: cp deb/rpm error * feat: support appimage * chore: add linux build script * feat: add macos build script * feat: update linux scripts * chore: update linux scripts * chore: update relesae script * chore: update macos build scripts * chore: rename macOS package name * chore: add keychain in release.yaml * chore: update macos build steps in release.yaml * chore: update macos script desc * chore: remove sudo * feat: support tar.xz package type * feat: support tar.xz package type * chore: add fuse --------- Co-authored-by: Morn --- .github/workflows/release.yml | 230 +++++++------- .../appflowy_flutter/distribute_options.yaml | 31 +- .../appflowy_flutter/linux/CMakeLists.txt | 2 +- .../linux/packaging/appimage/make_config.yaml | 22 ++ .../linux/packaging/deb/make_config.yaml | 3 +- .../linux/packaging/rpm/make_config.yaml | 3 +- .../macos/packaging/assets/background.jpg | Bin 0 -> 20532 bytes .../macos/packaging/dmg/make_config.json | 26 ++ .../macos/packaging/dmg/make_config.yaml | 17 + frontend/scripts/docker-buildfiles/Dockerfile | 6 +- .../flatpack-buildfiles/dbus-interface.xml | 6 +- .../io.appflowy.AppFlowy.desktop | 4 +- .../io.appflowy.AppFlowy.metainfo.xml | 34 +- .../io.appflowy.AppFlowy.service | 4 +- .../scripts/flatpack-buildfiles/launcher.sh | 4 +- .../flutter_release_build/build_linux.sh | 243 ++++++++++++++ .../flutter_release_build/build_macos.sh | 297 ++++++++++++++++++ .../appimage/AppImageBuilder.yml | 4 +- .../linux_distribution/deb/AppFlowy.desktop | 2 +- .../linux_distribution/deb/DEBIAN/postinst | 4 +- .../linux_distribution/deb/DEBIAN/postrm | 4 +- .../linux_distribution/deb/build_deb.sh | 6 +- .../linux_distribution/flatpak/README.md | 2 +- .../io.appflowy.AppFlowy.metainfo.xml | 34 +- .../packaging/io.appflowy.AppFlowy.service | 2 +- .../linux_distribution/packaging/launcher.sh | 6 +- frontend/scripts/linux_installer/postinst | 4 +- 27 files changed, 829 insertions(+), 171 deletions(-) create mode 100644 frontend/appflowy_flutter/linux/packaging/appimage/make_config.yaml create mode 100644 frontend/appflowy_flutter/macos/packaging/assets/background.jpg create mode 100644 frontend/appflowy_flutter/macos/packaging/dmg/make_config.json create mode 100644 frontend/appflowy_flutter/macos/packaging/dmg/make_config.yaml create mode 100755 frontend/scripts/flutter_release_build/build_linux.sh create mode 100755 frontend/scripts/flutter_release_build/build_macos.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 918a2018f7..438169f72d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,9 +128,9 @@ jobs: runs-on: ${{ matrix.job.os }} needs: create-release env: - MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release + MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/build/${{ github.ref_name }} MACOS_X86_ZIP_NAME: AppFlowy-${{ github.ref_name }}-macos-x86_64.zip - MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-x86_64 + MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-x86_64.dmg strategy: fail-fast: false matrix: @@ -158,46 +158,22 @@ jobs: - name: Install prerequisites working-directory: frontend run: | + brew install p7zip cargo install --force --locked cargo-make cargo install --force --locked duckscript_cli + - name: Import codesign certificate + uses: apple-actions/import-codesign-certs@v3 + with: + p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }} + p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + - name: Build AppFlowy working-directory: frontend run: | flutter config --enable-macos-desktop - dart ./scripts/flutter_release_build/build_flowy.dart run . ${{ github.ref_name }} - - - name: Codesign AppFlowy - run: | - echo ${{ secrets.MACOS_CERTIFICATE }} | base64 --decode > certificate.p12 - security create-keychain -p action build.keychain - security default-keychain -s build.keychain - security unlock-keychain -p action build.keychain - security import certificate.p12 -k build.keychain -P ${{ secrets.MACOS_CERTIFICATE_PWD }} -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k action build.keychain - /usr/bin/codesign --force --options runtime --deep --sign "${{ secrets.MACOS_CODESIGN_ID }}" "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" -v - - - name: Create macOS dmg - run: | - brew install create-dmg - create-dmg \ - --volname ${{ env.MACOS_DMG_NAME }} \ - --hide-extension "AppFlowy.app" \ - --background frontend/scripts/dmg_assets/AppFlowyInstallerBackground.jpg \ - --window-size 600 450 \ - --icon-size 94 \ - --icon "AppFlowy.app" 141 249 \ - --app-drop-link 458 249 \ - "${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \ - "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" - - - name: Notarize AppFlowy - run: | - xcrun notarytool submit ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} -v -f "json" --wait - - - name: Archive Asset - working-directory: ${{ env.MACOS_APP_RELEASE_PATH }} - run: zip --symlinks -qr ${{ env.MACOS_X86_ZIP_NAME }} AppFlowy.app + flutter pub global activate flutter_distributor + sh scripts/flutter_release_build/build_macos.sh --build_type dmg --build_arch x86_64 --version ${{ github.ref_name }} --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} - name: Upload Asset uses: actions/upload-release-asset@v1 @@ -215,8 +191,82 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg - asset_name: ${{ env.MACOS_DMG_NAME }}.dmg + asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }} + asset_name: ${{ env.MACOS_DMG_NAME }} + asset_content_type: application/octet-stream + + build-for-macOS-arm64: + name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}] + runs-on: ${{ matrix.job.os }} + needs: create-release + env: + MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/build/${{ github.ref_name }} + MACOS_AARCH64_ZIP_NAME: AppFlowy-${{ github.ref_name }}-macos-arm64.zip + MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-arm64.dmg + strategy: + fail-fast: false + matrix: + job: + - { + targets: "aarch64-apple-darwin", + os: macos-latest, + extra-build-args: "", + } + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Install flutter + uses: subosito/flutter-action@v2 + with: + channel: "stable" + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + targets: ${{ matrix.job.targets }} + components: rustfmt + + - name: Install prerequisites + working-directory: frontend + run: | + brew install p7zip + cargo install --force --locked cargo-make + cargo install --force --locked duckscript_cli + + - name: Import codesign certificate + uses: apple-actions/import-codesign-certs@v3 + with: + p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }} + p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + + - name: Build AppFlowy + working-directory: frontend + run: | + flutter config --enable-macos-desktop + dart pub global activate flutter_distributor + sh scripts/flutter_release_build/build_macos.sh --build_type dmg --build_arch arm64 --version ${{ github.ref_name }} --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} + + - name: Upload Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_AARCH64_ZIP_NAME }} + asset_name: ${{ env.MACOS_AARCH64_ZIP_NAME }} + asset_content_type: application/octet-stream + + - name: Upload DMG Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }} + asset_name: ${{ env.MACOS_DMG_NAME }} asset_content_type: application/octet-stream build-for-macOS-universal: @@ -224,9 +274,9 @@ jobs: runs-on: ${{ matrix.job.os }} needs: create-release env: - MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/macos/Release + MACOS_APP_RELEASE_PATH: frontend/appflowy_flutter/build/${{ github.ref_name }} MACOS_AARCH64_ZIP_NAME: AppFlowy-${{ github.ref_name }}-macos-universal.zip - MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-universal + MACOS_DMG_NAME: AppFlowy-${{ github.ref_name }}-macos-universal.dmg strategy: fail-fast: false matrix: @@ -256,46 +306,22 @@ jobs: - name: Install prerequisites working-directory: frontend run: | + brew install p7zip cargo install --force --locked cargo-make cargo install --force --locked duckscript_cli + - name: Import codesign certificate + uses: apple-actions/import-codesign-certs@v3 + with: + p12-file-base64: ${{ secrets.MACOS_CERTIFICATE }} + p12-password: ${{ secrets.MACOS_CERTIFICATE_PWD }} + - name: Build AppFlowy working-directory: frontend run: | flutter config --enable-macos-desktop - sh scripts/flutter_release_build/build_universal_package_for_macos.sh ${{ github.ref_name }} - - - name: Codesign AppFlowy - run: | - echo ${{ secrets.MACOS_CERTIFICATE }} | base64 --decode > certificate.p12 - security create-keychain -p action build.keychain - security default-keychain -s build.keychain - security unlock-keychain -p action build.keychain - security import certificate.p12 -k build.keychain -P ${{ secrets.MACOS_CERTIFICATE_PWD }} -T /usr/bin/codesign - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k action build.keychain - /usr/bin/codesign --force --options runtime --deep --sign "${{ secrets.MACOS_CODESIGN_ID }}" "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" -v - - - name: Create macOS dmg - run: | - brew install create-dmg - create-dmg \ - --volname ${{ env.MACOS_DMG_NAME }} \ - --hide-extension "AppFlowy.app" \ - --background frontend/scripts/dmg_assets/AppFlowyInstallerBackground.jpg \ - --window-size 600 450 \ - --icon-size 94 \ - --icon "AppFlowy.app" 141 249 \ - --app-drop-link 458 249 \ - "${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg" \ - "${{ env.MACOS_APP_RELEASE_PATH }}/AppFlowy.app" - - - name: Notarize AppFlowy - run: | - xcrun notarytool submit ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} -v -f "json" --wait - - - name: Archive Asset - working-directory: ${{ env.MACOS_APP_RELEASE_PATH }} - run: zip --symlinks -qr ${{ env.MACOS_AARCH64_ZIP_NAME }} AppFlowy.app + dart pub global activate flutter_distributor + sh scripts/flutter_release_build/build_macos.sh --build_type dmg --build_arch universal --version ${{ github.ref_name }} --apple-id ${{ secrets.MACOS_NOTARY_USER }} --team-id ${{ secrets.MACOS_TEAM_ID }} --password ${{ secrets.MACOS_NOTARY_PWD }} - name: Upload Asset uses: actions/upload-release-asset@v1 @@ -313,8 +339,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }}.dmg - asset_name: ${{ env.MACOS_DMG_NAME }}.dmg + asset_path: ${{ env.MACOS_APP_RELEASE_PATH }}/${{ env.MACOS_DMG_NAME }} + asset_name: ${{ env.MACOS_DMG_NAME }} asset_content_type: application/octet-stream build-for-linux: @@ -322,14 +348,12 @@ jobs: runs-on: ${{ matrix.job.os }} needs: create-release env: - LINUX_APP_RELEASE_PATH: frontend/appflowy_flutter/product/${{ github.ref_name }}/linux/Release - LINUX_ZIP_NAME: AppFlowy-${{ matrix.job.target }}-x86_64.tar.gz + LINUX_APP_RELEASE_PATH: frontend/appflowy_flutter/build/${{ github.ref_name }} LINUX_PACKAGE_DEB_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.deb LINUX_PACKAGE_RPM_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.rpm - LINUX_PACKAGE_TMP_RPM_NAME: AppFlowy-${{ github.ref_name }}-2.x86_64.rpm - LINUX_PACKAGE_TMP_APPIMAGE_NAME: AppFlowy-${{ github.ref_name }}-x86_64.AppImage LINUX_PACKAGE_APPIMAGE_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.AppImage - LINUX_PACKAGE_ZIP_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.tar.gz + LINUX_PACKAGE_ZIP_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.zip + LINUX_PACKAGE_TAR_NAME: AppFlowy-${{ github.ref_name }}-linux-x86_64.tar.gz strategy: fail-fast: false @@ -338,7 +362,7 @@ jobs: - { arch: x86_64, target: x86_64-unknown-linux-gnu, - os: ubuntu-20.04, + os: ubuntu-22.04, extra-build-args: "", flutter_profile: production-linux-x86_64, } @@ -364,14 +388,24 @@ jobs: - name: Install prerequisites working-directory: frontend run: | + # Install dependencies sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub sudo apt-get update - sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev - sudo apt-get install keybinder-3.0 - sudo apt-get install -y alien libnotify-dev + sudo apt-get install -y build-essential libsqlite3-dev libssl-dev clang cmake ninja-build pkg-config libgtk-3-dev keybinder-3.0 libnotify-dev + sudo apt install rpm patchelf locate + sudo add-apt-repository universe + sudo apt install libfuse2 + + # Install appimagetool + wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod +x appimagetool + mv appimagetool /usr/local/bin/ + + # Install cargo-make and duckscript source $HOME/.cargo/env cargo install --force --locked cargo-make cargo install --force --locked duckscript_cli + rustup target add ${{ matrix.job.target }} - name: Install gcc-aarch64-linux-gnu @@ -384,30 +418,8 @@ jobs: working-directory: frontend run: | flutter config --enable-linux-desktop - dart ./scripts/flutter_release_build/build_flowy.dart run . ${{ github.ref_name }} - - - name: Archive Asset - working-directory: ${{ env.LINUX_APP_RELEASE_PATH }} - run: tar -czf ${{ env.LINUX_ZIP_NAME }} * - - - name: Build Linux package (.deb) - working-directory: frontend - run: | - sh scripts/linux_distribution/deb/build_deb.sh appflowy_flutter/product/${{ github.ref_name }}/linux/Release ${{ github.ref_name }} ${{ env.LINUX_PACKAGE_DEB_NAME }} - - - name: Build Linux package (.rpm) - working-directory: ${{ env.LINUX_APP_RELEASE_PATH }} - run: | - sudo alien -r ${{ env.LINUX_PACKAGE_DEB_NAME }} - cp -r ${{ env.LINUX_PACKAGE_TMP_RPM_NAME }} ${{ env.LINUX_PACKAGE_RPM_NAME }} - - - name: Build Linux package (.AppImage) - working-directory: frontend - continue-on-error: true - run: | - sh scripts/linux_distribution/appimage/build_appimage.sh ${{ github.ref_name }} - cd .. - cp -r frontend/${{ env.LINUX_PACKAGE_TMP_APPIMAGE_NAME }} ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_APPIMAGE_NAME }} + dart pub global activate flutter_distributor + ./scripts/flutter_release_build/build_linux.sh --build_type all --build_arch x86_64 --version ${{ github.ref_name }} - name: Upload Asset id: upload-release-asset @@ -416,11 +428,11 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ needs.create-release.outputs.upload_url }} - asset_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_ZIP_NAME }} + asset_path: ${{ env.LINUX_APP_RELEASE_PATH }}/${{ env.LINUX_PACKAGE_ZIP_NAME }} asset_name: ${{ env.LINUX_PACKAGE_ZIP_NAME }} asset_content_type: application/octet-stream - - name: Upload Debian package + - name: Upload DEB package id: upload-release-asset-install-package-deb uses: actions/upload-release-asset@v1 env: diff --git a/frontend/appflowy_flutter/distribute_options.yaml b/frontend/appflowy_flutter/distribute_options.yaml index 60f603a938..9ed8a31822 100644 --- a/frontend/appflowy_flutter/distribute_options.yaml +++ b/frontend/appflowy_flutter/distribute_options.yaml @@ -1,12 +1,35 @@ -output: dist/ +output: build/ releases: - - name: dev + - name: prod jobs: - - name: release-dev-linux-deb + - name: release-prod-linux-deb package: platform: linux target: deb - - name: release-dev-linux-rpm + - name: release-prod-linux-rpm package: platform: linux target: rpm + - name: release-prod-linux-appimage + package: + platform: linux + target: appimage + - name: release-prod-linux-zip + package: + platform: linux + target: zip + + # Because the flutter_distribute plugin does not support the deep code-signing for macos, we need to manually sign the app. + # So we don't use the flutter_distribute plugin to distribute the macos app. + # - name: release-prod-macos-dmg + # package: + # platform: macos + # target: dmg + # - name: release-prod-macos-pkg + # package: + # platform: macos + # target: pkg + - name: release-prod-macos-zip + package: + platform: macos + target: zip diff --git a/frontend/appflowy_flutter/linux/CMakeLists.txt b/frontend/appflowy_flutter/linux/CMakeLists.txt index b9f7cce174..14ba0cb311 100644 --- a/frontend/appflowy_flutter/linux/CMakeLists.txt +++ b/frontend/appflowy_flutter/linux/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) project(runner LANGUAGES CXX) -set(BINARY_NAME "AppFlowy") +set(BINARY_NAME "appflowy") set(APPLICATION_ID "io.appflowy.appflowy") cmake_policy(SET CMP0063 NEW) diff --git a/frontend/appflowy_flutter/linux/packaging/appimage/make_config.yaml b/frontend/appflowy_flutter/linux/packaging/appimage/make_config.yaml new file mode 100644 index 0000000000..f7dffe0d3a --- /dev/null +++ b/frontend/appflowy_flutter/linux/packaging/appimage/make_config.yaml @@ -0,0 +1,22 @@ +display_name: AppFlowy + +icon: linux/packaging/assets/logo.png + +keywords: + - AppFlowy + - Office + - Document + - Database + - Note + - Kanban + - Note + +generic_name: AppFlowy + +categories: + - Office + +startup_notify: true + +supported_mime_type: + - x-scheme-handler/appflowy-flutter diff --git a/frontend/appflowy_flutter/linux/packaging/deb/make_config.yaml b/frontend/appflowy_flutter/linux/packaging/deb/make_config.yaml index 801a5dbc02..ff70893ef6 100644 --- a/frontend/appflowy_flutter/linux/packaging/deb/make_config.yaml +++ b/frontend/appflowy_flutter/linux/packaging/deb/make_config.yaml @@ -29,7 +29,8 @@ essential: false section: x11 priority: optional -supportedMimeType: x-scheme-handler/appflowy-flutter +supported_mime_type: + - x-scheme-handler/appflowy-flutter dependencies: - libnotify-bin diff --git a/frontend/appflowy_flutter/linux/packaging/rpm/make_config.yaml b/frontend/appflowy_flutter/linux/packaging/rpm/make_config.yaml index 3fcdea03bc..46fd395ad1 100644 --- a/frontend/appflowy_flutter/linux/packaging/rpm/make_config.yaml +++ b/frontend/appflowy_flutter/linux/packaging/rpm/make_config.yaml @@ -26,7 +26,8 @@ categories: startup_notify: true -supportedMimeType: x-scheme-handler/appflowy-flutter +supported_mime_type: + - x-scheme-handler/appflowy-flutter requires: - libnotify diff --git a/frontend/appflowy_flutter/macos/packaging/assets/background.jpg b/frontend/appflowy_flutter/macos/packaging/assets/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..57e29d8b6a2a81eda76f974e70c876d2169b38e0 GIT binary patch literal 20532 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 - + + @@ -13,4 +13,4 @@ - + \ No newline at end of file diff --git a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.desktop b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.desktop index 9076493bb8..40b241e05d 100644 --- a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.desktop +++ b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.desktop @@ -1,8 +1,8 @@ [Desktop Entry] Type=Application Name=AppFlowy -Icon=io.appflowy.AppFlowy -Exec=AppFlowy %U +Icon=io.appflowy.appflowy +Exec=appflowy %U Categories=Network;Productivity; Keywords=Notes DBusActivatable=true diff --git a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.metainfo.xml b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.metainfo.xml index c9a58b68fa..ea3b476004 100644 --- a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.metainfo.xml +++ b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.metainfo.xml @@ -1,38 +1,46 @@ - io.appflowy.AppFlowy - + io.appflowy.appflowy + AppFlowy - Open Source Notion Alternative - + Open Source Notion Alternative + CC-BY-4.0 AGPL-3.0-only - +

- # Built for teams that need more control and flexibility ## 100% data control You can host AppFlowy wherever you want; no vendor lock-in. + # Built for teams that need more control and flexibility ## 100% data control You can host + AppFlowy wherever you want; no vendor lock-in.

## Unlimited customizations Design and modify AppFlowy your way with an open core codebase.

- ## One codebase supporting multiple platforms AppFlowy is built with Flutter and Rust. What does this mean? Faster development, better native experience, and more reliable performance. + ## One codebase supporting multiple platforms AppFlowy is built with Flutter and Rust. What + does this mean? Faster development, better native experience, and more reliable performance.

- # Built for individuals who care about data security and mobile experience ## 100% control of your data Download and install AppFlowy on your local machine. You own and control your personal data. + # Built for individuals who care about data security and mobile experience ## 100% control of + your data Download and install AppFlowy on your local machine. You own and control your + personal data.

- ## Extensively extensible For those with no coding experience, AppFlowy enables you to create apps that suit your needs. It's built on a community-driven toolbox, including templates, plugins, themes, and more. + ## Extensively extensible For those with no coding experience, AppFlowy enables you to create + apps that suit your needs. It's built on a community-driven toolbox, including templates, + plugins, themes, and more.

- ## Truly native experience Faster, more stable with support for offline mode. It's also better integrated with different devices. Moreover, AppFlowy enables users to access features and possibilities not available on the web. + ## Truly native experience Faster, more stable with support for offline mode. It's also + better integrated with different devices. Moreover, AppFlowy enables users to access features + and possibilities not available on the web.

- - io.appflowy.AppFlowy.desktop + + io.appflowy.appflowy.desktop https://github.com/AppFlowy-IO/appflowy/raw/main/doc/imgs/welcome.png -
+ \ No newline at end of file diff --git a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.service b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.service index 31e32415d0..fed8eabcf1 100644 --- a/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.service +++ b/frontend/scripts/flatpack-buildfiles/io.appflowy.AppFlowy.service @@ -1,3 +1,3 @@ [D-BUS Service] -Name=io.appflowy.AppFlowy -Exec=AppFlowy +Name=io.appflowy.appflowy +Exec=appflowy diff --git a/frontend/scripts/flatpack-buildfiles/launcher.sh b/frontend/scripts/flatpack-buildfiles/launcher.sh index 24b4fdbea4..5cda51d0a9 100644 --- a/frontend/scripts/flatpack-buildfiles/launcher.sh +++ b/frontend/scripts/flatpack-buildfiles/launcher.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -gdbus call --session --dest io.appflowy.AppFlowy \ +gdbus call --session --dest io.appflowy.appflowy \ --object-path /io/appflowy/AppFlowy/Object \ - --method io.appflowy.AppFlowy.Open "['$1']" {} + --method io.appflowy.appflowy.Open "['$1']" {} diff --git a/frontend/scripts/flutter_release_build/build_linux.sh b/frontend/scripts/flutter_release_build/build_linux.sh new file mode 100755 index 0000000000..21f591193a --- /dev/null +++ b/frontend/scripts/flutter_release_build/build_linux.sh @@ -0,0 +1,243 @@ +#!/bin/bash +# This Script is used to build the AppFlowy linux zip, deb, rpm or appimage +# +# Usage: ./scripts/flutter_release_build/build_linux.sh --build_type --build_arch --version [--skip-code-generation] [--skip-rebuild-core] +# +# Options: +# -h, --help Show this help message and exit +# --build_type The type of package to build. Must be one of: +# - all: Build all package types +# - zip: Build only zip package +# - tar.xz: Build only tar.xz package +# - deb: Build only deb package +# - rpm: Build only rpm package +# - appimage: Build only appimage package +# --build_arch The architecture to build. Must be one of: +# - x86_64: Build for x86_64 architecture +# - arm64: Build for arm64 architecture (not supported yet) +# --version The version number (e.g. 0.8.2) +# --skip-code-generation Skip the code generation step +# --skip-rebuild-core Skip the core rebuild step + +show_help() { + echo "Usage: ./scripts/flutter_release_build/build_linux.sh --build_type --build_arch --version [--skip-code-generation] [--skip-rebuild-core]" + echo "" + echo "Options:" + echo " -h, --help Show this help message and exit" + echo "" + echo "Arguments:" + echo " --build_type The type of package to build. Must be one of:" + echo " - all: Build all package types" + echo " - zip: Build only zip package" + echo " - tar.xz: Build only tar.xz package" + echo " - deb: Build only deb package" + echo " - rpm: Build only rpm package" + echo " Please install the \033[33mrpm-build\033[0m and \033[33mpatchelf\033[0m before building the rpm and appimage package." + echo " For more information, please refer to the https://distributor.leanflutter.dev/makers/rpm/." + echo " - appimage: Build only appimage package" + echo " Please install the \033[33mlocate\033[0m and \033[33mappimagetool\033[0m before building the appimage package." + echo " For more information, please refer to the https://distributor.leanflutter.dev/makers/appimage/." + echo " --build_arch The architecture to build. Must be one of:" + echo " - x86_64: Build for x86_64 architecture" + echo " - arm64: Build for arm64 architecture (not supported yet)" + echo " --version The version number (e.g. 0.8.2)" + echo " --skip-code-generation Skip the code generation step. It may save time if you have already generated the code." + echo " --skip-rebuild-core Skip the core rebuild step. It may save time if you have already built the core." + exit 0 +} + +# Check for help flag +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + show_help +fi + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --build_type) + BUILD_TYPE="$2" + shift 2 + ;; + --build_arch) + BUILD_ARCH="$2" + shift 2 + ;; + --version) + VERSION="$2" + shift 2 + ;; + --skip-code-generation) + SKIP_CODE_GENERATION=true + shift + ;; + --skip-rebuild-core) + SKIP_REBUILD_CORE=true + shift + ;; + *) + echo "Unknown parameter: $1" + show_help + exit 1 + ;; + esac +done + +clear_cache() { + echo -e "Clearing the cache..." + rm -rf appflowy_flutter/build/$VERSION/ +} + +info() { + echo -e "🚀 \033[32m$1\033[0m" +} + +error() { + echo -e "🚨 \033[31m$1\033[0m" +} + +# Validate build type argument +if [ -z "$BUILD_TYPE" ]; then + error "Please specify build type with --build_type: all, zip, tar.xz, deb, rpm, appimage" + exit 1 +fi + +# Validate version argument +if [ -z "$VERSION" ]; then + error "Please specify version number with --version (e.g. 0.8.2)" + exit 1 +fi + +# Validate build arch argument +if [ -z "$BUILD_ARCH" ]; then + error "Please specify build arch with --build_arch: x86_64, arm64 or universal" + exit 1 +fi + +if [ "$BUILD_TYPE" != "all" ] && [ "$BUILD_TYPE" != "zip" ] && [ "$BUILD_TYPE" != "tar.xz" ] && [ "$BUILD_TYPE" != "deb" ] && [ "$BUILD_TYPE" != "rpm" ] && [ "$BUILD_TYPE" != "appimage" ]; then + error "Invalid build type. Must be one of: all, zip, tar.xz, deb, rpm, appimage" + exit 1 +fi + +has_built_core=false +has_generated_code=false + +prepare_build() { + info "Preparing build..." + + # Build the rust-lib with version + if [ "$SKIP_REBUILD_CORE" != "true" ] && [ "$has_built_core" != "true" ]; then + cargo make --env APP_VERSION=$VERSION --profile production-linux-$BUILD_ARCH appflowy-core-release + has_built_core=true + fi + + if [ "$SKIP_CODE_GENERATION" != "true" ] && [ "$has_generated_code" != "true" ]; then + cargo make --env APP_VERSION=$VERSION --profile production-linux-$BUILD_ARCH code_generation + has_generated_code=true + fi +} + +build_zip() { + info "Building zip package version $VERSION..." + + prepare_build + + cd appflowy_flutter + flutter_distributor release --name=prod --jobs=release-prod-linux-zip --skip-clean + cd .. + mv appflowy_flutter/build/$VERSION/appflowy-$VERSION+$VERSION-linux.zip appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.zip + + info "Zip package built successfully. The zip package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.zip" +} + +build_deb() { + info "Building deb package version $VERSION..." + + prepare_build + + cd appflowy_flutter + flutter_distributor release --name=prod --jobs=release-prod-linux-deb --skip-clean + cd .. + mv appflowy_flutter/build/$VERSION/appflowy-$VERSION+$VERSION-linux.deb appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.deb + + info "Deb package built successfully. The deb package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.deb" +} + +build_rpm() { + info "Building rpm package version $VERSION..." + + prepare_build + + cd appflowy_flutter + flutter_distributor release --name=prod --jobs=release-prod-linux-rpm --skip-clean + cd .. + mv appflowy_flutter/build/$VERSION/appflowy-$VERSION+$VERSION-linux.rpm appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.rpm + + info "RPM package built successfully. The RPM package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.rpm" +} + +# Function to build AppImage package +build_appimage() { + info "Building AppImage package version $VERSION..." + + prepare_build + + cd appflowy_flutter + flutter_distributor release --name=prod --jobs=release-prod-linux-appimage --skip-clean + cd .. + mv appflowy_flutter/build/$VERSION/appflowy-$VERSION+$VERSION-linux.AppImage appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.AppImage + + info "AppImage package built successfully. The AppImage package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.AppImage" +} + +build_tar_xz() { + info "Building tar.xz package version $VERSION..." + + prepare_build + + # step 1: check if the linux zip package is built, if not, build the zip package + if [ ! -f "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.zip" ]; then + info "Linux zip package is not built. Building the zip package..." + build_zip + fi + + # step 2: unzip the zip package + unzip appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.zip -d appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64 + + # check if the AppFlowy directory exists + if [ ! -d "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64" ]; then + error "AppFlowy directory doesn't exist. Please check the zip package." + exit 1 + fi + + # step 3: build the tar.xz package + tar -cJvf appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.tar.xz appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64/* + + info "Tar.xz package built successfully. The tar.xz package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-linux-x86_64.tar.xz" +} + +clear_cache + +# Build packages based on build type +case $BUILD_TYPE in +"all") + build_zip + build_deb + build_rpm + build_appimage + ;; +"zip") + build_zip + ;; +"deb") + build_deb + ;; +"rpm") + build_rpm + ;; +"appimage") + build_appimage + ;; +"tar.xz") + build_tar_xz + ;; +esac diff --git a/frontend/scripts/flutter_release_build/build_macos.sh b/frontend/scripts/flutter_release_build/build_macos.sh new file mode 100755 index 0000000000..82071bef38 --- /dev/null +++ b/frontend/scripts/flutter_release_build/build_macos.sh @@ -0,0 +1,297 @@ +# This Script is used to build the AppFlowy macOS zip, dmg or pkg +# +# Usage: ./scripts/flutter_release_build/build_macos.sh --build_type --build_arch --version --apple-id --team-id --password [--skip-code-generation] [--skip-rebuild-core] +# +# Options: +# -h, --help Show this help message and exit +# --build_type The type of package to build. Must be one of: +# - all: Build all package types +# - zip: Build only zip package +# - dmg: Build only dmg package +# - tar.xz: Build only tar.xz package +# --build_arch The architecture to build. Must be one of: +# - x86_64: Build for x86_64 architecture +# - arm64: Build for arm64 architecture +# - universal: Build for universal architecture +# --version The version number (e.g. 0.8.2) +# --skip-code-generation Skip the code generation step +# --skip-rebuild-core Skip the core rebuild step +# --apple-id The apple id to use for the notary service +# --team-id The team id to use for the notary service +# --password The password to use for the notary service + +show_help() { + echo "Usage: ./scripts/flutter_release_build/build_macos.sh --build_type --build_arch --version --apple-id --team-id --password [--skip-code-generation] [--skip-rebuild-core]" + echo "" + echo "Options:" + echo " -h, --help Show this help message and exit" + echo "" + echo "Arguments:" + echo " --build_type The type of package to build. Must be one of:" + echo " - all: Build all package types" + echo " - zip: Build only zip package" + echo " Please install the \033[33mp7zip\033[0m before building the zip package." + echo " For more information, please refer to the https://distributor.leanflutter.dev/makers/zip/." + echo " - tar.xz: Build only tar.xz package" + echo " - dmg: Build only dmg package" + echo " Please install the \033[33mappdmg\033[0m before building the dmg package." + echo " For more information, please refer to the https://distributor.leanflutter.dev/makers/dmg/." + echo " --build_arch The architecture to build. Must be one of:" + echo " - x86_64: Build for x86_64 architecture" + echo " - arm64: Build for arm64 architecture" + echo " - universal: Build for universal architecture" + echo " --version The version number (e.g. 0.8.2)" + echo " --skip-code-generation Skip the code generation step. It may save time if you have already generated the code." + echo " --skip-rebuild-core Skip the core rebuild step. It may save time if you have already built the core." + echo " --apple-id The apple id to use for the notary service" + echo " --team-id The team id to use for the notary service" + echo " --password The password to use for the notary service" + exit 0 +} + +# Check for help flag +if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then + show_help +fi + +# Parse named arguments +while [ $# -gt 0 ]; do + case "$1" in + --build_type) + BUILD_TYPE="$2" + shift 2 + ;; + --build_arch) + BUILD_ARCH="$2" + shift 2 + ;; + --version) + VERSION="$2" + shift 2 + ;; + --skip-code-generation) + SKIP_CODE_GENERATION=true + shift + ;; + --skip-rebuild-core) + SKIP_REBUILD_CORE=true + shift + ;; + --apple-id) + APPLE_ID="$2" + shift 2 + ;; + --team-id) + TEAM_ID="$2" + shift 2 + ;; + --password) + PASSWORD="$2" + shift 2 + ;; + *) + echo "Unknown parameter: $1" + show_help + exit 1 + ;; + esac +done + +clear_cache() { + echo "Clearing the cache..." + rm -rf appflowy_flutter/build/$VERSION/ +} + +info() { + echo "🚀 \033[32m$1\033[0m" +} + +error() { + echo "🚨 \033[31m$1\033[0m" +} + +# Validate build type argument +if [ -z "$BUILD_TYPE" ]; then + error "Please specify build type with --build_type: all, zip, dmg, tar.xz" + exit 1 +fi + +# Validate version argument +if [ -z "$VERSION" ]; then + error "Please specify version number with --version (e.g. 0.8.2)" + exit 1 +fi + +# Validate build arch argument +if [ -z "$BUILD_ARCH" ]; then + error "Please specify build arch with --build_arch: x86_64, arm64 or universal" + exit 1 +fi + +if [ "$BUILD_TYPE" != "all" ] && [ "$BUILD_TYPE" != "zip" ] && [ "$BUILD_TYPE" != "dmg" ] && [ "$BUILD_TYPE" != "tar.xz" ]; then + error "Invalid build type. Must be one of: all, zip, dmg, tar.xz" + exit 1 +fi + +prepare_build() { + info "Preparing build..." + + # step 1: build the appflowy-core (rust-lib) based on the build arch + if [ "$SKIP_REBUILD_CORE" != "true" ]; then + if [ "$BUILD_ARCH" = "x86_64" ] || [ "$BUILD_ARCH" = "universal" ]; then + info "Building appflowy-core for x86_64...(This may take a while)" + cargo make --profile production-mac-x86_64 appflowy-core-release + fi + + if [ "$BUILD_ARCH" = "arm64" ] || [ "$BUILD_ARCH" = "universal" ]; then + info "Building appflowy-core for arm64...(This may take a while)" + cargo make --profile production-mac-arm64 appflowy-core-release + fi + + # step 2 (optional): combine these two libdart_ffi.a into one libdart_ffi.a if the build arch is universal + if [ "$BUILD_ARCH" = "universal" ]; then + info "Combining libdart_ffi.a for universal..." + lipo -create \ + rust-lib/target/x86_64-apple-darwin/release/libdart_ffi.a \ + rust-lib/target/aarch64-apple-darwin/release/libdart_ffi.a \ + -output rust-lib/target/libdart_ffi.a + + info "Checking the libdart_ffi.a for universal..." + lipo -archs rust-lib/target/libdart_ffi.a + + cp -rf rust-lib/target/libdart_ffi.a \ + appflowy_flutter/packages/appflowy_backend/macos/ + fi + fi + + # step 3 (optional): generate the flutter code: languages, icons and freezed files. + if [ "$SKIP_CODE_GENERATION" != "true" ]; then + info "Generating the flutter code...(This may take a while)" + cargo make code_generation + fi + + # step 4: build the zip package + info "Building the zip package..." + cd appflowy_flutter + flutter_distributor release --name=prod --jobs=release-prod-macos-zip --skip-clean + cd .. +} + +build_zip() { + info "Building zip package version $VERSION..." + + # step 1: check if the macos zip package is built, if not, build the zip package + if [ ! -f "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip" ]; then + info "macOS zip package is not built. Building the zip package..." + prepare_build + + # step 1.1: move the zip package to the build directory + mv appflowy_flutter/build/$VERSION/appflowy-$VERSION+$VERSION-macos.zip appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip + fi + + # step 2: unzip the zip package and codesign the app + unzip -o appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip + + # step 3: codesign the app + # note: You must install the certificate to the system before codesigning + sudo /usr/bin/codesign --force --options runtime --deep --sign "Developer ID Application: APPFLOWY PTE. LTD" --deep --verbose AppFlowy.app -v + + # step 4: zip the app again + 7z a appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip AppFlowy.app + + info "Zip package built successfully" +} + +build_dmg() { + info "Building DMG package version $VERSION..." + + # step 1: check if the macos zip package is built, if not, build the zip package + if [ ! -f "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip" ]; then + info "macOS zip package is not built. Building the zip package..." + build_zip + fi + + # step 2: unzip the zip package and copy the make_config.json file to the build directory + unzip appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip -d appflowy_flutter/build/$VERSION/ + cp appflowy_flutter/macos/packaging/dmg/make_config.json appflowy_flutter/build/$VERSION/ + + # check if the AppFlowy.app doesn't exist, exit the script + if [ ! -d "appflowy_flutter/build/$VERSION/AppFlowy.app" ]; then + error "AppFlowy.app doesn't exist. Please check the zip package." + exit 1 + fi + + # check if the appdmg has been installed + if ! command -v appdmg &>/dev/null; then + info "appdmg is not installed. Installing appdmg..." + npm install -g appdmg + fi + + # step 3: build the dmg package using appdmg + # note: You must install the appdmg to the system before building the dmg package + appdmg appflowy_flutter/build/$VERSION/make_config.json appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.dmg + + # step 4: clear the temp files + rm -rf appflowy_flutter/build/$VERSION/AppFlowy.app + rm -rf appflowy_flutter/build/$VERSION/make_config.json + + # check if the dmg package is built + if [ ! -f "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.dmg" ]; then + error "DMG package is not built. Please check the build process." + exit 1 + fi + + info "DMG package built successfully. The dmg package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.dmg" + + if [ -z "$APPLE_ID" ] || [ -z "$TEAM_ID" ] || [ -z "$PASSWORD" ]; then + error "The apple id, team id and password are not specified. Please notarize the dmg package manually." + error "xcrun notarytool submit appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.dmg --apple-id --team-id --password -v -f \"json\" --wait" + else + xcrun notarytool submit appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.dmg --apple-id $APPLE_ID --team-id $TEAM_ID --password $PASSWORD -v -f "json" --wait + info "Notarization is completed. Please check the notarization status" + fi +} + +build_tar_xz() { + info "Building tar.xz package version $VERSION..." + + # step 1: check if the macos zip package is built, if not, build the zip package + if [ ! -f "appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip" ]; then + info "macOS zip package is not built. Building the zip package..." + build_zip + fi + + # step 2: unzip the zip package and copy the make_config.json file to the build directory + unzip appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.zip -d appflowy_flutter/build/$VERSION/ + + # check if the AppFlowy.app doesn't exist, exit the script + if [ ! -d "appflowy_flutter/build/$VERSION/AppFlowy.app" ]; then + error "AppFlowy.app doesn't exist. Please check the zip package." + exit 1 + fi + + # step 3: build the tar.xz package + tar -cJvf appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.tar.xz appflowy_flutter/build/$VERSION/AppFlowy.app + + info "Tar.xz package built successfully. The tar.xz package is located at appflowy_flutter/build/$VERSION/AppFlowy-$VERSION-macos-$BUILD_ARCH.tar.xz" +} + +clear_cache + +# Build packages based on build type +case $BUILD_TYPE in +"all") + build_zip + build_dmg + build_tar_xz + ;; +"zip") + build_zip + ;; +"dmg") + build_dmg + ;; +"tar.xz") + build_tar_xz + ;; +esac diff --git a/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml b/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml index cd8103df9e..45d52d6044 100644 --- a/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml +++ b/frontend/scripts/linux_distribution/appimage/AppImageBuilder.yml @@ -11,11 +11,11 @@ script: AppDir: path: ./AppDir app_info: - id: io.appflowy.AppFlowy + id: io.appflowy.appflowy name: AppFlowy icon: appflowy.svg version: [CHANGE_THIS] - exec: AppFlowy + exec: appflowy exec_args: $@ apt: arch: diff --git a/frontend/scripts/linux_distribution/deb/AppFlowy.desktop b/frontend/scripts/linux_distribution/deb/AppFlowy.desktop index e6851f9f42..6b485fc50e 100644 --- a/frontend/scripts/linux_distribution/deb/AppFlowy.desktop +++ b/frontend/scripts/linux_distribution/deb/AppFlowy.desktop @@ -2,7 +2,7 @@ Type=Application Name=AppFlowy Icon=/usr/share/icons/hicolor/scalable/apps/appflowy.svg -Exec=/usr/bin/AppFlowy %U +Exec=/usr/bin/appflowy %U Categories=Network;Productivity; Keywords=Notes Terminal=false diff --git a/frontend/scripts/linux_distribution/deb/DEBIAN/postinst b/frontend/scripts/linux_distribution/deb/DEBIAN/postinst index bf2f79fa97..fbc5b1fc91 100755 --- a/frontend/scripts/linux_distribution/deb/DEBIAN/postinst +++ b/frontend/scripts/linux_distribution/deb/DEBIAN/postinst @@ -1,8 +1,8 @@ #!/usr/bin/env bash -if [ -e /usr/bin/AppFlowy ]; then +if [ -e /usr/bin/appflowy ]; then echo "Symlink already exists, skipping." else echo "Creating Symlink in /usr/bin/appflowy" - ln -s /usr/lib/AppFlowy/AppFlowy /usr/bin/AppFlowy + ln -s /usr/lib/appflowy/appflowy /usr/bin/appflowy ln -s /usr/lib/AppFlowy/launcher.sh /usr/bin/AppFlowyLauncher.sh fi diff --git a/frontend/scripts/linux_distribution/deb/DEBIAN/postrm b/frontend/scripts/linux_distribution/deb/DEBIAN/postrm index 59a680e767..f0131be6f6 100755 --- a/frontend/scripts/linux_distribution/deb/DEBIAN/postrm +++ b/frontend/scripts/linux_distribution/deb/DEBIAN/postrm @@ -1,5 +1,5 @@ #!/usr/bin/env bash -if [ -e /usr/bin/AppFlowy ]; then - rm /usr/bin/AppFlowy +if [ -e /usr/bin/appflowy ]; then + rm /usr/bin/appflowy rm /usr/bin/AppFlowyLauncher.sh fi diff --git a/frontend/scripts/linux_distribution/deb/build_deb.sh b/frontend/scripts/linux_distribution/deb/build_deb.sh index 42fbf7346d..a5fb5bc53a 100644 --- a/frontend/scripts/linux_distribution/deb/build_deb.sh +++ b/frontend/scripts/linux_distribution/deb/build_deb.sh @@ -25,9 +25,9 @@ chmod 0755 $DEBIAN/postinst chmod 0755 $DEBIAN/postrm grep -rl "\[CHANGE_THIS\]" $DEBIAN/control | xargs sed -i "s/\[CHANGE_THIS\]/$VERSION/" -cp -fR $LINUX_RELEASE_PRODUCTION/AppFlowy $LIB -cp ./scripts/linux_distribution/deb/AppFlowy.desktop $APPLICATIONS -cp ./scripts/linux_distribution/packaging/io.appflowy.AppFlowy.metainfo.xml $METAINFO +cp -fR $LINUX_RELEASE_PRODUCTION/appflowy $LIB +cp ./scripts/linux_distribution/deb/appflowy.desktop $APPLICATIONS +cp ./scripts/linux_distribution/packaging/io.appflowy.appflowy.metainfo.xml $METAINFO cp ./scripts/linux_distribution/packaging/appflowy.svg $ICONS # Build the package diff --git a/frontend/scripts/linux_distribution/flatpak/README.md b/frontend/scripts/linux_distribution/flatpak/README.md index 7d90cfd2a6..b1d40056da 100644 --- a/frontend/scripts/linux_distribution/flatpak/README.md +++ b/frontend/scripts/linux_distribution/flatpak/README.md @@ -1 +1 @@ -Please refer to https://github.com/flathub/io.appflowy.AppFlowy repo. +Please refer to https://github.com/flathub/io.appflowy.appflowy repo. diff --git a/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.metainfo.xml b/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.metainfo.xml index c9a58b68fa..ea3b476004 100644 --- a/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.metainfo.xml +++ b/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.metainfo.xml @@ -1,38 +1,46 @@ - io.appflowy.AppFlowy - + io.appflowy.appflowy + AppFlowy - Open Source Notion Alternative - + Open Source Notion Alternative + CC-BY-4.0 AGPL-3.0-only - +

- # Built for teams that need more control and flexibility ## 100% data control You can host AppFlowy wherever you want; no vendor lock-in. + # Built for teams that need more control and flexibility ## 100% data control You can host + AppFlowy wherever you want; no vendor lock-in.

## Unlimited customizations Design and modify AppFlowy your way with an open core codebase.

- ## One codebase supporting multiple platforms AppFlowy is built with Flutter and Rust. What does this mean? Faster development, better native experience, and more reliable performance. + ## One codebase supporting multiple platforms AppFlowy is built with Flutter and Rust. What + does this mean? Faster development, better native experience, and more reliable performance.

- # Built for individuals who care about data security and mobile experience ## 100% control of your data Download and install AppFlowy on your local machine. You own and control your personal data. + # Built for individuals who care about data security and mobile experience ## 100% control of + your data Download and install AppFlowy on your local machine. You own and control your + personal data.

- ## Extensively extensible For those with no coding experience, AppFlowy enables you to create apps that suit your needs. It's built on a community-driven toolbox, including templates, plugins, themes, and more. + ## Extensively extensible For those with no coding experience, AppFlowy enables you to create + apps that suit your needs. It's built on a community-driven toolbox, including templates, + plugins, themes, and more.

- ## Truly native experience Faster, more stable with support for offline mode. It's also better integrated with different devices. Moreover, AppFlowy enables users to access features and possibilities not available on the web. + ## Truly native experience Faster, more stable with support for offline mode. It's also + better integrated with different devices. Moreover, AppFlowy enables users to access features + and possibilities not available on the web.

- - io.appflowy.AppFlowy.desktop + + io.appflowy.appflowy.desktop https://github.com/AppFlowy-IO/appflowy/raw/main/doc/imgs/welcome.png -
+ \ No newline at end of file diff --git a/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.service b/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.service index 31e32415d0..2982dff894 100644 --- a/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.service +++ b/frontend/scripts/linux_distribution/packaging/io.appflowy.AppFlowy.service @@ -1,3 +1,3 @@ [D-BUS Service] -Name=io.appflowy.AppFlowy +Name=io.appflowy.appflowy Exec=AppFlowy diff --git a/frontend/scripts/linux_distribution/packaging/launcher.sh b/frontend/scripts/linux_distribution/packaging/launcher.sh index 24b4fdbea4..263eca6593 100644 --- a/frontend/scripts/linux_distribution/packaging/launcher.sh +++ b/frontend/scripts/linux_distribution/packaging/launcher.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -gdbus call --session --dest io.appflowy.AppFlowy \ - --object-path /io/appflowy/AppFlowy/Object \ - --method io.appflowy.AppFlowy.Open "['$1']" {} +gdbus call --session --dest io.appflowy.appflowy \ + --object-path /io/appflowy/appflowy/Object \ + --method io.appflowy.appflowy.Open "['$1']" {} diff --git a/frontend/scripts/linux_installer/postinst b/frontend/scripts/linux_installer/postinst index 83e1a1043e..82a03114c0 100644 --- a/frontend/scripts/linux_installer/postinst +++ b/frontend/scripts/linux_installer/postinst @@ -1,7 +1,7 @@ #!/usr/bin/env bash -if [ -e /usr/local/bin/AppFlowy ]; then +if [ -e /usr/local/bin/appflowy ]; then echo "Symlink already exists, skipping." else echo "Creating Symlink in /usr/local/bin/appflowy" - ln -s /opt/AppFlowy/AppFlowy /usr/local/bin/AppFlowy + ln -s /opt/appflowy/appflowy /usr/local/bin/appflowy fi