Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ endif
ifeq ($(SKIP_SERVER_RUST),true)
SUBMODULES := $(filter-out aw-server-rust,$(SUBMODULES))
endif
# Exclude aw-server (Python) when using aw-server-rust only
ifeq ($(SKIP_SERVER_PYTHON),true)
SUBMODULES := $(filter-out aw-server,$(SUBMODULES))
endif
# Odoo-specific Windows build: replaces aw-qt with aw-systray-odoo
ifeq ($(ODOO_WINDOWS_BUILD),true)
SUBMODULES := $(filter-out aw-qt,$(SUBMODULES))
endif
# Include extras if AW_EXTRAS is true
ifeq ($(AW_EXTRAS),true)
SUBMODULES := $(SUBMODULES) aw-notify aw-watcher-input
Expand Down Expand Up @@ -79,7 +87,9 @@ build: aw-core/.git
make --directory=aw-client build
make --directory=aw-core build
# Needed to ensure that the server has the correct version set
ifneq ($(SKIP_SERVER_PYTHON),true)
python -c "import aw_server; print(aw_server.__version__)"
endif


# Install
Expand Down Expand Up @@ -186,6 +196,9 @@ package:
rm -rf dist
mkdir -p dist/activitywatch
for dir in $(PACKAGEABLES); do \
if [[ "$(ODOO_WINDOWS_BUILD)" == "true" ]] && [[ "$$dir" == "aw-watcher-afk" || "$$dir" == "aw-watcher-window" ]]; then \
continue; \
fi; \
make --directory=$$dir package; \
cp -r $$dir/dist/$$dir dist/activitywatch; \
done
Expand All @@ -194,10 +207,11 @@ 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
ifeq ($(ODOO_WINDOWS_BUILD),true)
@echo "ODOO_WINDOWS_BUILD: Building aw-systray-odoo.exe via PyInstaller..."
$(PYTHON) -m PyInstaller --clean --noconfirm odoo-setup/aw-systray-odoo.spec
cp dist/aw-systray-odoo.exe dist/activitywatch/aw-systray-odoo.exe
endif
endif
# Remove problem-causing binaries
rm -f dist/activitywatch/libdrm.so.2 # see: https://github.com/ActivityWatch/activitywatch/issues/161
Expand Down
2 changes: 1 addition & 1 deletion aw-server-rust
65 changes: 44 additions & 21 deletions aw.spec
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,16 @@ restx_path = Path(os.path.dirname(flask_restx.__file__))

aws_location = Path("aw-server")
aw_server_rust_location = Path("aw-server-rust")
aw_server_rust_bin = aw_server_rust_location / "target/package/aw-server-rust"
aw_sync_bin = aw_server_rust_location / "target/package/aw-sync"

# Properly find windows executables
_cargo_target = os.environ.get("CARGO_BUILD_TARGET", "")
if _cargo_target:
aw_server_rust_bin = aw_server_rust_location / "target" / _cargo_target / "release" / "aw-server.exe"
aw_sync_bin = aw_server_rust_location / "target" / _cargo_target / "release" / "aw-sync.exe"
else:
aw_server_rust_bin = aw_server_rust_location / "target/package/aw-server-rust"
aw_sync_bin = aw_server_rust_location / "target/package/aw-sync"

aw_qt_location = Path("aw-qt")
awa_location = Path("aw-watcher-afk")
aww_location = Path("aw-watcher-window")
Expand All @@ -101,16 +109,25 @@ if not aw_server_rust_bin.exists():
skip_rust = True
print("Skipping Rust build because aw-server-rust binary not found.")

skip_aw_server_python = os.environ.get("SKIP_SERVER_PYTHON", "false").lower() == "true"
if skip_aw_server_python:
print("Skipping aw-server (Python) packaging, using aw-server-rust only.")

aw_qt_a = build_analysis(
"aw-qt",
aw_qt_location,
binaries=[(aw_server_rust_bin, "."), (aw_sync_bin, ".")] if not skip_rust else [],
datas=[
(aw_qt_location / "resources/aw-qt.desktop", "aw_qt/resources"),
(aw_qt_location / "media", "aw_qt/media"),
],
)
skip_aw_qt = os.environ.get("ODOO_WINDOWS_BUILD", "false").lower() == "true"
if skip_aw_qt:
print("Skipping aw-qt packaging, using aw-systray-odoo instead.")


if not skip_aw_qt:
aw_qt_a = build_analysis(
"aw-qt",
aw_qt_location,
binaries=[(aw_server_rust_bin, "."), (aw_sync_bin, ".")] if not skip_rust else [],
datas=[
(aw_qt_location / "resources/aw-qt.desktop", "aw_qt/resources"),
(aw_qt_location / "media", "aw_qt/media"),
],
)
aw_server_a = build_analysis(
"aw-server",
aws_location,
Expand Down Expand Up @@ -182,20 +199,23 @@ aw_notify_a = None if skip_aw_notify else build_analysis(
# MERGE takes a bit weird arguments, it wants tuples which consists of
# the analysis paired with the script name and the bin name
merge_args = [
(aw_server_a, "aw-server", "aw-server"),
(aw_qt_a, "aw-qt", "aw-qt"),
(aw_watcher_afk_a, "aw-watcher-afk", "aw-watcher-afk"),
(aw_watcher_window_a, "aw-watcher-window", "aw-watcher-window"),
(aw_watcher_input_a, "aw-watcher-input", "aw-watcher-input"),
]
if not skip_aw_server_python:
merge_args.insert(0, (aw_server_a, "aw-server", "aw-server"))
if not skip_aw_qt:
merge_args.append((aw_qt_a, "aw-qt", "aw-qt"))
if aw_notify_a is not None:
merge_args.append((aw_notify_a, "aw-notify", "aw-notify"))

MERGE(*merge_args)


# aw-server
aws_coll = build_collect(aw_server_a, "aw-server")
if not skip_aw_server_python:
aws_coll = build_collect(aw_server_a, "aw-server")

# aw-watcher-window
aww_coll = build_collect(aw_watcher_window_a, "aw-watcher-window")
Expand All @@ -204,11 +224,12 @@ aww_coll = build_collect(aw_watcher_window_a, "aw-watcher-window")
awa_coll = build_collect(aw_watcher_afk_a, "aw-watcher-afk")

# aw-qt
awq_coll = build_collect(
aw_qt_a,
"aw-qt",
console=False if platform.system() == "Windows" else True,
)
if not skip_aw_qt:
awq_coll = build_collect(
aw_qt_a,
"aw-qt",
console=False if platform.system() == "Windows" else True,
)

# aw-watcher-input
awi_coll = build_collect(aw_watcher_input_a, "aw-watcher-input")
Expand All @@ -218,12 +239,14 @@ aw_notify_coll = build_collect(aw_notify_a, "aw-notify") if aw_notify_a is not N

if platform.system() == "Darwin":
bundle_args = [
awq_coll,
aws_coll,
aww_coll,
awa_coll,
awi_coll,
]
if not skip_aw_server_python:
bundle_args.insert(1, aws_coll)
if not skip_aw_qt:
bundle_args.insert(0, awq_coll)
if aw_notify_coll is not None:
bundle_args.append(aw_notify_coll)

Expand Down
74 changes: 74 additions & 0 deletions odoo-setup/Dockerfile_windows
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
FROM debian:trixie

ENV DEBIAN_FRONTEND=noninteractive
ENV LC_ALL=C.UTF-8

RUN dpkg --add-architecture i386

ARG USID=1000 GRID=1000
RUN groupadd -g $GRID odoo \
&& useradd --create-home -u $USID -g odoo -G audio,video odoo \
&& mkdir -p /run/user/$USID \
&& chmod 700 /run/user/$USID

RUN apt-get update \
&& apt-get install -y curl unzip 7zip xvfb mingw-w64 rustup make build-essential git zip \
python3 python3-pip python3-venv python3-poetry \
&& rm -rf /var/lib/apt/lists/*

RUN mkdir -pm755 /etc/apt/keyrings \
&& curl -sSL https://dl.winehq.org/wine-builds/winehq.key -o /etc/apt/keyrings/winehq-archive.key \
&& curl -sSL https://dl.winehq.org/wine-builds/debian/dists/trixie/winehq-trixie.sources -o /etc/apt/sources.list.d/winehq.sources \
&& apt-get update \
&& apt-get install --install-recommends -y winehq-stable \
&& rm -rf /var/lib/apt/lists/*

USER odoo

ENV NVM_DIR=/home/odoo/.nvm
ENV NODE_VERSION=22.22.1
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash && \
bash -c "source $NVM_DIR/nvm.sh && \
nvm install $NODE_VERSION && \
nvm alias default $NODE_VERSION && \
nvm use default"

ENV PATH="$NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH"

RUN rustup toolchain install nightly \
&& rustup default nightly \
&& rustup target add x86_64-pc-windows-gnu

RUN python3 -m venv /home/odoo/awvenv
ENV PATH="/home/odoo/awvenv/bin:$PATH"
ENV VIRTUAL_ENV=/home/odoo/awvenv

ENV XDG_RUNTIME_DIR=/run/user/$USID

ENV WINEPREFIX=/home/odoo/.wine
ENV WINEARCH=win64
# Ignoring debug and fixme's message when running wine
ENV WINEDEBUG=-all

ENV CARGO_BUILD_TARGET=x86_64-pc-windows-gnu

RUN wineboot --init && wineserver -w

RUN curl -fsSL https://www.python.org/ftp/python/3.14.4/python-3.14.4-amd64.exe -o /tmp/python-installer.exe \
&& chmod u+x /tmp/python-installer.exe

RUN xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" \
sh -c "wine /tmp/python-installer.exe /quiet Include_doc=0 InstallAllUsers=1 PrependPath=1 \
&& (while pgrep -u $(id -u) -x wineserver > /dev/null 2>&1; do sleep 1; done) \
&& wineserver -w"

RUN PYTHON_EXE="/home/odoo/.wine/drive_c/Program Files/Python314/python.exe" \
&& PIP_EXE="/home/odoo/.wine/drive_c/Program Files/Python314/Scripts/pip.exe" \
&& xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" \
sh -c "wine '$PIP_EXE' install pystray pillow pywin32 pyinstaller"

RUN curl -fsSL https://github.com/jrsoftware/issrc/releases/download/is-6_7_1/innosetup-6.7.1.exe -o /tmp/innosetup.exe \
&& chmod u+x /tmp/innosetup.exe \
&& xvfb-run --auto-servernum wine /tmp/innosetup.exe /VERYSILENT /SUPPRESSMSGBOXES /NORESTART \
&& (while pgrep -u $(id -u) -x wineserver > /dev/null 2>&1; do sleep 1; done) \
&& wineserver -w
57 changes: 57 additions & 0 deletions odoo-setup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ActivityWatch Odoo Package Build

Build script for Odoo version of ActivityWatch packages for Linux (Debian/Ubuntu) and Windows.

## Requirements

- Docker
- `realpath` (coreutils)
- Sufficient disk space (~2GB for Docker images + build artifacts)

## Usage

```bash
./buildpackage.sh <distro> [package_name]
```

### Arguments

| Argument | Description | Default |
|---|---|---|
| `distro` | Target platform (`noble`, `jammy`, `windows`) | `noble` |
| `package_name` | Output package name | `activitywatch-odoo-<distro>` |

### Examples

```bash
# Build Ubuntu 24.04 package
./buildpackage.sh noble

# Build Ubuntu 22.04 package
./buildpackage.sh jammy

# Build Windows installer
./buildpackage.sh windows

# Custom package name
./buildpackage.sh jammy activitywatch-custom
```

## Outputs

After a successful build, artifacts are available in `odoo-setup/dist/`:

| Platform | Output |
|---|---|
| Linux | `activitywatch-odoo-<distro>.deb` |
| Windows | `activitywatch-odoo-YYYY-MM-DD-windows-x86_64-setup.exe` + `.zip` |

## Troubleshooting

### Docker permission errors

Ensure your user is in the `docker` group:

```bash
sudo usermod -aG docker $USER
```
Loading