diff --git a/.github/workflows/build-tauri.yml b/.github/workflows/build-tauri.yml new file mode 100644 index 000000000..e6dcea2b9 --- /dev/null +++ b/.github/workflows/build-tauri.yml @@ -0,0 +1,312 @@ +name: Build Tauri + +on: + push: + branches: [master] + tags: + - v* + pull_request: + branches: [master] + #release: + # types: [published] + +jobs: + build: + name: ${{ matrix.os }}, py-${{ matrix.python_version }}, node-${{ matrix.node_version }} + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} + env: + # Whether to build and include extras (like aw-notify and aw-watcher-input) + AW_EXTRAS: true + # sets the macOS version target, see: https://users.rust-lang.org/t/compile-rust-binary-for-older-versions-of-mac-osx/38695 + MACOSX_DEPLOYMENT_TARGET: 10.9 + defaults: + run: + shell: bash + strategy: + fail-fast: false + max-parallel: 5 + matrix: + os: + [ + ubuntu-24.04, + ubuntu-24.04-arm, + windows-latest, + macOS-13, + macos-latest, + ] + python_version: [3.9] + node_version: [22] + skip_rust: [false] + skip_webui: [false] + experimental: [false] + tauri_build: [true] + #include: + # - os: ubuntu-latest + # python_version: 3.9 + # node_version: 20 + # experimental: true + + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: 0 # fetch all branches and tags + + # Build in release mode if: (longer build times) + # - on a tag (release) + # - on the master branch (nightly) + - name: Set environment variables + run: | + echo "RELEASE=${{ startsWith(github.ref_name, 'v') || github.ref_name == 'master' }}" >> $GITHUB_ENV + echo "TAURI_BUILD=${{ matrix.tauri_build }}" >> $GITHUB_ENV + + - name: Set up Python + if: matrix.os != 'macOS-13' + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python_version }} + + # Setup Python version built for older macOS (https://github.com/actions/virtual-environments/issues/1256) + - name: Set up Python for macOS + if: matrix.os == 'macOS-13' + run: | + curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macosx10.9.pkg -o "python.pkg" + + # Python 3.11+ only has *macos11.pkg, so no more *macosx10.9.pkg + # the 'macos11' naming seems to suggest it only supports macos11 and up, + # but the release page says "for macOS 10.9 and later", + # unclear what the resulting binary compatibility will be. + # + # curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg -o "python.pkg" + + sudo installer -pkg python.pkg -target / + echo "/Library/Frameworks/Python.framework/Versions/${{ matrix.python_version }}/bin" >> $GITHUB_PATH + "/Applications/Python ${{ matrix.python_version }}/Install Certificates.command" + env: + # Add the patch number to the Python version (for FTP download link) + PYTHON_VERSION: ${{ matrix.python_version }}.13 + + - name: Set up Node + if: ${{ !matrix.skip_webui }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node_version }} + + - name: Set up Rust + if: ${{ !matrix.skip_rust }} + uses: dtolnay/rust-toolchain@master + id: toolchain + with: + toolchain: stable + + - name: Get npm cache dir + id: npm-cache-dir + run: | + echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT + + - uses: actions/cache@v4 + name: Cache npm + if: ${{ !matrix.skip_webui }} + env: + cache-name: node + with: + path: ${{ steps.npm-cache-dir.outputs.dir }} + key: ${{ matrix.os }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ matrix.os }}-${{ env.cache-name }}- + + - name: Cache cargo build + uses: actions/cache@v4 + # if: ${{ !matrix.skip_rust && (runner.os != 'macOS') }} # cache doesn't seem to behave nicely on macOS, see: https://github.com/ActivityWatch/aw-server-rust/issues/180 + env: + cache-name: cargo-build-target + with: + path: aw-server-rust/target + # key needs to contain rustc_hash due to https://github.com/ActivityWatch/aw-server-rust/issues/180 + key: ${{ matrix.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ matrix.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.rustc_hash }}- + + - name: Install APT dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + # Unsure which of these are actually necessary... + sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev \ + libjavascriptcoregtk-4.1-dev libsoup-3.0-dev xdg-utils + + - name: Install dependencies + run: | + if [ "$RUNNER_OS" == "Windows" ]; then + choco install innosetup + fi + pip3 install poetry==1.3.2 + + # - name: Build + # run: | + # python3 -m venv venv + # source venv/bin/activate || source venv/Scripts/activate + # poetry install + # make build SKIP_WEBUI=${{ matrix.skip_webui }} SKIP_SERVER_RUST=${{ matrix.skip_rust }} + # pip freeze # output Python packages, useful for debugging dependency versions + + - name: Build + uses: nick-fields/retry@v3 + with: + timeout_minutes: 60 + max_attempts: 3 + shell: bash + command: | + python3 -m venv venv + source venv/bin/activate || source venv/Scripts/activate + poetry install + make build SKIP_WEBUI=${{ matrix.skip_webui }} SKIP_SERVER_RUST=${{ matrix.skip_rust }} + pip freeze # output Python packages, useful for debugging dependency versions + + - name: Run tests + uses: nick-fields/retry@v3 + with: + timeout_minutes: 60 + max_attempts: 3 + shell: bash + command: | + source venv/bin/activate || source venv/Scripts/activate + make test SKIP_SERVER_RUST=${{ matrix.skip_rust }} + + # Don't run integration tests on Windows, doesn't work for some reason + # - name: Run integration tests + # if: runner.os != 'Windows' + # run: | + # source venv/bin/activate || source venv/Scripts/activate + # make test-integration + + - name: Package + run: | + source venv/bin/activate || source venv/Scripts/activate + poetry install # run again to ensure we have the correct version of PyInstaller + make package SKIP_SERVER_RUST=${{ matrix.skip_rust }} + + - name: Package dmg + if: runner.os == 'macOS' + run: | + # Load certificates + # Only load key & sign if env vars for signing exists + if [ -n "$APPLE_EMAIL" ]; then + ./scripts/ci/import-macos-p12.sh + fi + + # Build .app and .dmg + source venv/bin/activate + make dist/ActivityWatch.dmg + + # codesign and notarize + if [ -n "$APPLE_EMAIL" ]; then + codesign --verbose -s ${APPLE_PERSONALID} dist/ActivityWatch.dmg + + # Run prechecks + brew install akeru-inc/tap/xcnotary + xcnotary precheck dist/ActivityWatch.app + xcnotary precheck dist/ActivityWatch.dmg + + # Notarize + make dist/notarize + fi + mv dist/ActivityWatch.dmg dist/activitywatch-$(scripts/package/getversion.sh)-macos-x86_64.dmg + env: + APPLE_EMAIL: ${{ secrets.APPLE_EMAIL }} + APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} + APPLE_PERSONALID: ${{ secrets.APPLE_TEAMID }} # APPLE_PERSONAL_ID == APPLE_TEAM_ID for personal accounts + APPLE_TEAMID: ${{ secrets.APPLE_TEAMID }} + CERTIFICATE_MACOS_P12_BASE64: ${{ secrets.CERTIFICATE_MACOS_P12_BASE64 }} + CERTIFICATE_MACOS_P12_PASSWORD: ${{ secrets.CERTIFICATE_MACOS_P12_PASSWORD }} + + # - name: Package AppImage + # if: startsWith(runner.os, 'linux') + # run: | + # ./scripts/package/package-appimage.sh + + # - name: Package deb + # if: startsWith(runner.os, 'linux') + # run: | + # # The entire process is deferred to a shell file for consistency. + # ./scripts/package/package-deb.sh + + - name: Upload packages + uses: actions/upload-artifact@v4 + with: + name: builds-${{ matrix.os }}-py${{ matrix.python_version }} + path: dist/activitywatch-*.* + + release-notes: + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') # only on runs triggered from tag + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: 0 # fetch all branches and tags + + - uses: ActivityWatch/check-version-format-action@v2 + id: version + with: + prefix: "v" + + - name: Echo version + run: | + echo "${{ steps.version.outputs.full }} (stable: ${{ steps.version.outputs.is_stable }})" + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install deps + run: | + pip install requests + + - name: Generate release notes + run: | + LAST_RELEASE=`STABLE_ONLY=${{ steps.version.output.is_stable }} ./scripts/get_latest_release.sh` + ./scripts/build_changelog.py --range "$LAST_RELEASE...${{ steps.version.outputs.full }}" + + # TODO: Move rename build_changelog and move into there + - name: Rename + run: | + mv changelog.md release_notes.md + + - name: Upload release notes + uses: actions/upload-artifact@v4 + with: + name: release_notes + path: release_notes.md + + release: + needs: [build, release-notes] + if: startsWith(github.ref, 'refs/tags/v') # only run on tag + runs-on: ubuntu-latest + steps: + # Will download all artifacts to path + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: dist + + - name: Display structure of downloaded files + run: ls -R + working-directory: dist + + # detect if version tag is stable/beta + - uses: ActivityWatch/check-version-format-action@v2 + id: version + with: + prefix: "v" + + # create a release + - name: Release + uses: softprops/action-gh-release@v1 + with: + draft: true + files: dist/*/activitywatch-*.* + body_path: dist/release_notes/release_notes.md + prerelease: ${{ !(steps.version.outputs.is_stable == 'true') }} # must compare to true, since boolean outputs are actually just strings, and "false" is truthy since it's not empty: https://github.com/actions/runner/issues/1483#issuecomment-994986996 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e003ca684..f3e59585d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} env: - # Wether to build and include extras (like aw-notify and aw-watcher-input) + # Whether to build and include extras (like aw-notify and aw-watcher-input) AW_EXTRAS: true # sets the macOS version target, see: https://users.rust-lang.org/t/compile-rust-binary-for-older-versions-of-mac-osx/38695 MACOSX_DEPLOYMENT_TARGET: 10.9 @@ -26,9 +26,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-20.04, windows-latest, macOS-13] + os: [ubuntu-24.04, windows-latest, macOS-13, macos-latest] python_version: [3.9] - node_version: [20] + node_version: [22] skip_rust: [false] skip_webui: [false] experimental: [false] @@ -53,14 +53,14 @@ jobs: echo "RELEASE=${{ startsWith(github.ref_name, 'v') || github.ref_name == 'master' }}" >> $GITHUB_ENV - name: Set up Python - if: runner.os != 'macOS' + if: matrix.os != 'macOS-13' uses: actions/setup-python@v5 with: python-version: ${{ matrix.python_version }} # Setup Python version built for older macOS (https://github.com/actions/virtual-environments/issues/1256) - name: Set up Python for macOS - if: runner.os == 'macOS' + if: matrix.os == 'macOS-13' run: | curl https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macosx10.9.pkg -o "python.pkg" @@ -103,21 +103,21 @@ jobs: cache-name: node with: path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + key: ${{ matrix.os }}-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} restore-keys: | - ${{ runner.os }}-${{ env.cache-name }}- + ${{ matrix.os }}-${{ env.cache-name }}- - name: Cache cargo build uses: actions/cache@v4 - if: ${{ !matrix.skip_rust && (runner.os != 'macOS') }} # cache doesn't seem to behave nicely on macOS, see: https://github.com/ActivityWatch/aw-server-rust/issues/180 + # if: ${{ !matrix.skip_rust && (runner.os != 'macOS') }} # cache doesn't seem to behave nicely on macOS, see: https://github.com/ActivityWatch/aw-server-rust/issues/180 env: cache-name: cargo-build-target with: path: aw-server-rust/target # key needs to contain rustc_hash due to https://github.com/ActivityWatch/aw-server-rust/issues/180 - key: ${{ runner.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }} + key: ${{ matrix.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.cachekey }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | - ${{ runner.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.rustc_hash }}- + ${{ matrix.os }}-${{ env.cache-name }}-${{ steps.toolchain.outputs.rustc_hash }}- - name: Install APT dependencies if: runner.os == 'Linux' @@ -126,7 +126,8 @@ jobs: # Unsure which of these are actually necessary... sudo apt-get install -y \ appstream \ - qt5-default \ + qt5-qmake \ + qtbase5-dev \ qtwayland5 \ libqt5x11extras5 \ libfontconfig1 \ @@ -223,7 +224,7 @@ jobs: - name: Upload packages uses: actions/upload-artifact@v4 with: - name: builds-${{ runner.os }}-py${{ matrix.python_version }} + name: builds-${{ matrix.os }}-py${{ matrix.python_version }} path: dist/activitywatch-*.* release-notes: diff --git a/.gitmodules b/.gitmodules index 8e7d1bdaf..e5e7a8947 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,9 @@ [submodule "aw-watcher-input"] path = aw-watcher-input url = https://github.com/ActivityWatch/aw-watcher-input.git +[submodule "aw-tauri"] + path = aw-tauri + url = https://github.com/activitywatch/aw-tauri +[submodule "awatcher"] + path = awatcher + url = https://github.com/2e3s/awatcher diff --git a/Makefile b/Makefile index 67d8fdd27..c2c25d22e 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,32 @@ SHELL := /usr/bin/env bash -SUBMODULES := aw-core aw-client aw-qt aw-server aw-server-rust aw-watcher-afk aw-watcher-window +OS := $(shell uname -s) + +ifeq ($(TAURI_BUILD),true) + SUBMODULES := aw-core aw-client aw-server aw-server-rust aw-watcher-afk aw-watcher-window aw-tauri +else + SUBMODULES := aw-core aw-client aw-qt aw-server aw-server-rust aw-watcher-afk aw-watcher-window +endif # Exclude aw-server-rust if SKIP_SERVER_RUST is true ifeq ($(SKIP_SERVER_RUST),true) SUBMODULES := $(filter-out aw-server-rust,$(SUBMODULES)) endif + +# Build in release mode by default, unless RELEASE=false +ifeq ($(RELEASE), false) + targetdir := debug +else + targetdir := release +endif + + +#Include awatcher on linux +ifeq ($(OS),Linux) + SUBMODULES := $(SUBMODULES) awatcher +endif + # Include extras if AW_EXTRAS is true ifeq ($(AW_EXTRAS),true) SUBMODULES := $(SUBMODULES) aw-notify aw-watcher-input @@ -34,6 +54,10 @@ PACKAGEABLES := $(foreach dir,$(SUBMODULES),$(call has_target,$(dir),package)) LINTABLES := $(foreach dir,$(SUBMODULES),$(call has_target,$(dir),lint)) TYPECHECKABLES := $(foreach dir,$(SUBMODULES),$(call has_target,$(dir),typecheck)) +ifeq ($(TAURI_BUILD),true) + PACKAGEABLES := $(filter-out aw-server-rust aw-server, $(PACKAGEABLES)) +endif + # The `build` target # ------------------ # @@ -44,17 +68,13 @@ build: aw-core/.git # needed due to https://github.com/pypa/setuptools/issues/1963 # would ordinarily be specified in pyproject.toml, but is not respected due to https://github.com/pypa/setuptools/issues/1963 pip install 'setuptools>49.1.1' - @if [ "$(SKIP_SERVER_RUST)" = "false" ]; then \ - if (which cargo); then \ - echo 'Rust found!'; \ - else \ - echo 'ERROR: Rust not found, try running with SKIP_SERVER_RUST=true'; \ - exit 1; \ - fi \ - fi for module in $(SUBMODULES); do \ echo "Building $$module"; \ - make --directory=$$module build SKIP_WEBUI=$(SKIP_WEBUI) || { echo "Error in $$module build"; exit 2; }; \ + if [ "$$module" = "aw-server-rust" ] && [ "$(TAURI_BUILD)" = "true" ]; then \ + make --directory=$$module aw-sync SKIP_WEBUI=$(SKIP_WEBUI) || { echo "Error in $$module aw-sync"; exit 2; }; \ + else \ + make --directory=$$module build SKIP_WEBUI=$(SKIP_WEBUI) || { echo "Error in $$module build"; exit 2; }; \ + fi; \ done # The below is needed due to: https://github.com/ActivityWatch/activitywatch/issues/173 make --directory=aw-client build @@ -62,18 +82,6 @@ build: aw-core/.git # Needed to ensure that the server has the correct version set python -c "import aw_server; print(aw_server.__version__)" - -# Install -# ------- -# -# Installs things like desktop/menu shortcuts. -# Might in the future configure autostart on the system. -install: - make --directory=aw-qt install -# Installation is already happening in the `make build` step currently. -# We might want to change this. -# We should also add some option to install as user (pip3 install --user) - # Update # ------ # @@ -120,10 +128,6 @@ test-integration: # aw-server-python @echo "== Integration testing aw-server ==" @pytest ./scripts/tests/integration_tests.py ./aw-server/tests/ -v - # aw-server-rust - @echo "== Integration testing aw-server-rust ==" - @export PATH=aw-server-rust/target/release:aw-server-rust/target/debug:${PATH}; \ - pytest ./scripts/tests/integration_tests.py ./aw-server/tests/ -v %/.git: git submodule update --init --recursive @@ -146,8 +150,13 @@ aw-qt/media/logo/logo.icns: rm -R build/MyIcon.iconset mv build/MyIcon.icns aw-qt/media/logo/logo.icns +ifeq ($(TAURI_BUILD),true) +dist/ActivityWatch.app: + scripts/package/build_app_tauri.sh +else dist/ActivityWatch.app: aw-qt/media/logo/logo.icns pyinstaller --clean --noconfirm aw.spec +endif dist/ActivityWatch.dmg: dist/ActivityWatch.app # NOTE: This does not codesign the dmg, that is done in the CI config @@ -164,10 +173,15 @@ package: make --directory=$$dir package; \ cp -r $$dir/dist/$$dir dist/activitywatch; \ done +ifeq ($(TAURI_BUILD),true) + mkdir -p dist/activitywatch/aw-server-rust + cp aw-server-rust/target/$(targetdir)/aw-sync dist/activitywatch/aw-server-rust/aw-sync +else # Move aw-qt to the root of the dist folder mv dist/activitywatch/aw-qt aw-qt-tmp mv aw-qt-tmp/* dist/activitywatch rmdir aw-qt-tmp +endif # Remove problem-causing binaries rm -f dist/activitywatch/libdrm.so.2 # see: https://github.com/ActivityWatch/activitywatch/issues/161 rm -f dist/activitywatch/libharfbuzz.so.0 # see: https://github.com/ActivityWatch/activitywatch/issues/660#issuecomment-959889230 diff --git a/aw-core b/aw-core index 6a58ec59c..e13c33c6d 160000 --- a/aw-core +++ b/aw-core @@ -1 +1 @@ -Subproject commit 6a58ec59c16c57933fce7bad4453449168c83ebd +Subproject commit e13c33c6d7349ae6482c666e267c4d48c475bd79 diff --git a/aw-notify b/aw-notify index 092337a13..bcea3cd1a 160000 --- a/aw-notify +++ b/aw-notify @@ -1 +1 @@ -Subproject commit 092337a1354fdc3da96e08eb5ab87487bc731652 +Subproject commit bcea3cd1a7ffd1ffcb721b952dfa75d11c3bef91 diff --git a/aw-server-rust b/aw-server-rust index a0cdef90c..c6409796f 160000 --- a/aw-server-rust +++ b/aw-server-rust @@ -1 +1 @@ -Subproject commit a0cdef90cf86cd8d2cc89723f5751c1123ae7e2b +Subproject commit c6409796f3859c1c610339682d90e0a03659ccdd diff --git a/aw-tauri b/aw-tauri new file mode 160000 index 000000000..f2ed9e74b --- /dev/null +++ b/aw-tauri @@ -0,0 +1 @@ +Subproject commit f2ed9e74b8ab6726bb589c78758e03649e4942a2 diff --git a/aw-watcher-afk b/aw-watcher-afk index 2dd99ca13..403a331f6 160000 --- a/aw-watcher-afk +++ b/aw-watcher-afk @@ -1 +1 @@ -Subproject commit 2dd99ca13c8ef9b14f891a8ddcc74b123482951e +Subproject commit 403a331f6f626afe18094cf61aeed235b75e537c diff --git a/awatcher b/awatcher new file mode 160000 index 000000000..0cdf79f85 --- /dev/null +++ b/awatcher @@ -0,0 +1 @@ +Subproject commit 0cdf79f857a65d5f43329c46a7039a166d280d7e diff --git a/scripts/changelog_contributors.csv b/scripts/changelog_contributors.csv index 34efc5543..f268181cd 100644 --- a/scripts/changelog_contributors.csv +++ b/scripts/changelog_contributors.csv @@ -1,3 +1,4 @@ +Oxbrayo vukubrian@gmail.com 2e3s 2e3s19@gmail.com 750 37119951+750@users.noreply.github.com Alwinator 39517491+Alwinator@users.noreply.github.com @@ -25,7 +26,6 @@ aaayushsingh ayush-_-singh@live.com alclary 9044153+alclary@users.noreply.github.com alialamine ali@towbe.com alwinator accounts@alwinschuster.at -brayo-pip 62670517+brayo-pip@users.noreply.github.com chaoky levimanga@gmail.com chengyuhui chengyuhui1@gmail.com davidfraser davidfraser@users.noreply.github.com diff --git a/scripts/changelog_contributors_twitter.csv b/scripts/changelog_contributors_twitter.csv index bbc14c5a2..d0560c107 100644 --- a/scripts/changelog_contributors_twitter.csv +++ b/scripts/changelog_contributors_twitter.csv @@ -1,4 +1,4 @@ -brayo-pip subrupt +0xbrayo subrupt chaoky chaokyer erikbjare erikbjare iloveitaly mike_bianco diff --git a/scripts/package/README.txt b/scripts/package/README.txt new file mode 100644 index 000000000..1b934d2c6 --- /dev/null +++ b/scripts/package/README.txt @@ -0,0 +1,3 @@ +Run move-to-aw-modules.sh to copy all modules except aw-tauri to ~/aw-modules/. Aw-tauri (replaces aw-qt), will use this directory to discover new modules. You can add your own modules and scripts to this directory. The modules should start with the aw- prefix and should not have an extension i.e `.sh`. + +In the aw-tauri folder there are AppImage, RPM, and DEB binaries. Choose the appropriate one for your distro; if in doubt, the AppImage works on most Linux systems. If you decide on the AppImage, copy it to a permanent folder like ~/bin or /usr/local/bin, since autostart relies on the AppImage being in the same location each time. diff --git a/scripts/package/aw-tauri.iss b/scripts/package/aw-tauri.iss new file mode 100644 index 000000000..daad157b2 --- /dev/null +++ b/scripts/package/aw-tauri.iss @@ -0,0 +1,64 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +#define MyAppName "ActivityWatch Tauri" +#define MyAppVersion GetEnv('AW_VERSION') +#define MyAppPublisher "ActivityWatch Contributors" +#define MyAppURL "https://activitywatch.net/" +#define MyAppExeName "aw-tauri.exe" +#define RootDir "..\.." +#define DistDir "..\..\dist" + +#pragma verboselevel 9 + +[Setup] +; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. +; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) +; NOTE: the double {{ are used to escape the { character (needed for the AppId) +AppId={{983D0855-08C8-46BD-AEFB-3924581C6703} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppVerName={#MyAppName} {#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL="https://github.com/ActivityWatch/activitywatch/issues" +AppUpdatesURL="https://github.com/ActivityWatch/activitywatch/releases" +DefaultDirName={autopf}\{#MyAppName} +DefaultGroupName={#MyAppName} +DisableProgramGroupPage=yes +; Uncomment the following line to run in non administrative install mode (install for current user only.) +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=dialog +OutputDir={#DistDir} +OutputBaseFilename=activitywatch-setup +SetupIconFile="{#RootDir}\aw-tauri\src-tauri\icons\icon.ico" +UninstallDisplayName={#MyAppName} +UninstallDisplayIcon={app}\{#MyAppExeName} +Compression=lzma +SolidCompression=yes +WizardStyle=modern + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked +Name: "StartMenuEntry" ; Description: "Start ActivityWatch when Windows starts"; GroupDescription: "Windows Startup"; MinVersion: 4,4; + +[Files] +Source: "{#DistDir}\activitywatch\aw-tauri.exe"; DestDir: "{app}\aw-tauri"; Flags: ignoreversion +Source: "{#DistDir}\activitywatch\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon +Name: "{userstartup}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: StartMenuEntry; + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +; Removes the previously installed version before installing the new one +; NOTE: Doesn't work? And also discouraged by the docs +;[InstallDelete] +;Type: filesandordirs; Name: "{app}\" diff --git a/scripts/package/build_app_tauri.sh b/scripts/package/build_app_tauri.sh new file mode 100755 index 000000000..d2abf224b --- /dev/null +++ b/scripts/package/build_app_tauri.sh @@ -0,0 +1,145 @@ +#!/bin/bash +set -e + +# Configuration +APP_NAME="ActivityWatch" +BUNDLE_ID="net.activitywatch.ActivityWatch" +VERSION="0.1.0" +ICON_PATH="aw-tauri/src-tauri/icons/icon.icns" + +# Check if running on macOS +if [[ "$(uname)" != "Darwin" ]]; then + echo "This script is designed to run on macOS only." + exit 1 +fi + +# Check if dist/activitywatch exists +if [ ! -d "dist/activitywatch" ]; then + echo "Error: dist/activitywatch directory not found. Please build the project first." + exit 1 +fi + +# Check if aw-tauri binary exists +if [ ! -f "dist/activitywatch/aw-tauri" ]; then + echo "Error: aw-tauri binary not found in dist/activitywatch/" + exit 1 +fi + +# Clean previous build +echo "Cleaning previous builds..." +rm -rf "dist/${APP_NAME}.app" +mkdir -p "dist" + +# Create app bundle structure +echo "Creating app bundle structure..." +mkdir -p "dist/${APP_NAME}.app/Contents/"{MacOS,Resources} + +# Copy aw-tauri as the main executable +echo "Copying aw-tauri as main executable..." +cp "dist/activitywatch/aw-tauri" "dist/${APP_NAME}.app/Contents/MacOS/aw-tauri" +chmod +x "dist/${APP_NAME}.app/Contents/MacOS/aw-tauri" + +# Copy all other components to Resources in organized directories +echo "Copying all components to Resources..." +for component in dist/activitywatch/*/; do + if [ -d "$component" ]; then + component_name=$(basename "$component") + echo " Copying $component_name..." + mkdir -p "dist/${APP_NAME}.app/Contents/Resources/$component_name" + cp -r "$component"/* "dist/${APP_NAME}.app/Contents/Resources/$component_name/" + fi +done + +# Make all aw-* executables within Resources executable +echo "Setting executable permissions..." +find "dist/${APP_NAME}.app/Contents/Resources" -type f -name "aw-*" -exec chmod +x {} \; + +# Copy app icon +echo "Copying app icon..." +if [ -f "$ICON_PATH" ]; then + cp "$ICON_PATH" "dist/${APP_NAME}.app/Contents/Resources/icon.icns" +else + echo "Warning: Icon file not found at $ICON_PATH" +fi + +# Create Info.plist +echo "Creating Info.plist..." +cat > "dist/${APP_NAME}.app/Contents/Info.plist" << EOF + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + aw-tauri + CFBundleIconFile + icon.icns + CFBundleIdentifier + ${BUNDLE_ID} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${APP_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${VERSION} + CFBundleVersion + ${VERSION} + NSAppleEventsUsageDescription + ActivityWatch needs access to monitor application usage + NSHighResolutionCapable + + NSPrincipalClass + NSApplication + LSMinimumSystemVersion + 10.14 + + +EOF + +# Create PkgInfo file +echo "Creating PkgInfo..." +echo "APPL????" > "dist/${APP_NAME}.app/Contents/PkgInfo" + +# Code signing (if APPLE_PERSONALID is set) +if [ -n "$APPLE_PERSONALID" ]; then + echo "Signing app with identity: $APPLE_PERSONALID" + codesign --deep --force --sign "$APPLE_PERSONALID" "dist/${APP_NAME}.app" + echo "App signing complete." +else + echo "APPLE_PERSONALID environment variable not set. Skipping code signing." +fi + +echo "" +echo "✅ App bundle created successfully at: dist/${APP_NAME}.app" +echo "" +echo "App Bundle Structure:" +echo "├── Contents/" +echo "│ ├── MacOS/" +echo "│ │ └── aw-tauri (main executable)" +echo "│ ├── Resources/" +for dir in "dist/${APP_NAME}.app/Contents/Resources/"*/; do + if [ -d "$dir" ] && [[ $(basename "$dir") == aw-* ]]; then + component_name=$(basename "$dir") + echo "│ │ ├── $component_name/" + # Show the main executable in each component + main_exec=$(find "$dir" -maxdepth 1 -name "aw-*" -type f 2>/dev/null | head -1) + if [ -n "$main_exec" ]; then + exec_name=$(basename "$main_exec") + echo "│ │ │ ├── $exec_name (executable)" + fi + # Show other important files + other_files=$(find "$dir" -maxdepth 2 -name "*.jxa" -o -name "Python" -o -name "*.dylib" 2>/dev/null | wc -l | tr -d ' ') + if [ "$other_files" -gt 0 ]; then + echo "│ │ │ └── ... (+ dependencies & libraries)" + fi + fi +done +echo "│ │ └── icon.icns" +echo "│ ├── Info.plist" +echo "│ └── PkgInfo" +echo "" +echo "All executables are properly packaged and accessible by aw-tauri." +echo "To test the app, run: open dist/${APP_NAME}.app" diff --git a/scripts/package/move-to-aw-modules.sh b/scripts/package/move-to-aw-modules.sh new file mode 100644 index 000000000..9545edec2 --- /dev/null +++ b/scripts/package/move-to-aw-modules.sh @@ -0,0 +1,11 @@ +#!/usr/bin/bash + +EXCLUDES="--exclude=aw-tauri --exclude=aw-server-rust --exclude=awatcher --exclude=move-to-aw-modules.sh --exclude=README.txt" + +if [[ -n "$XDG_SESSION_TYPE" && "$XDG_SESSION_TYPE" == "wayland" ]]; then + rsync -a . ~/aw-modules/ $EXCLUDES + cp ./awatcher/aw-awatcher ~/aw-modules/ +else + rsync -a . ~/aw-modules/ $EXCLUDES +fi +cp aw-server-rust/aw-sync ~/aw-modules/ diff --git a/scripts/package/package-all.sh b/scripts/package/package-all.sh index 967c6a459..cb949a718 100755 --- a/scripts/package/package-all.sh +++ b/scripts/package/package-all.sh @@ -41,6 +41,11 @@ function get_arch() { platform=$(get_platform) version=$(get_version) arch=$(get_arch) + +if [[ $platform == "linux" && $TAURI_BUILD == "true" ]]; then + cp scripts/package/README.txt scripts/package/move-to-aw-modules.sh dist/activitywatch +fi + echo "Platform: $platform, arch: $arch, version: $version" function build_zip() { @@ -70,7 +75,11 @@ function build_setup() { # Windows installer version should not include 'v' prefix, see: https://github.com/microsoft/winget-pkgs/pull/17564 version_no_prefix="$(echo $version | sed -e 's/^v//')" - env AW_VERSION=$version_no_prefix "$innosetupdir/iscc.exe" scripts/package/activitywatch-setup.iss + if [[ $TAURI_BUILD == "true" ]]; then + env AW_VERSION=$version_no_prefix "$innosetupdir/iscc.exe" scripts/package/aw-tauri.iss + else + env AW_VERSION=$version_no_prefix "$innosetupdir/iscc.exe" scripts/package/activitywatch-setup.iss + fi mv dist/activitywatch-setup.exe dist/$filename echo "Setup built!" } @@ -85,4 +94,3 @@ echo "-------------------------------------" echo "Contents of ./dist" ls -l dist echo "-------------------------------------" -