Skip to content
Open
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
2 changes: 1 addition & 1 deletion aw-qt
2 changes: 1 addition & 1 deletion aw-tauri
89 changes: 37 additions & 52 deletions scripts/patch_research_edition_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ def _python_profile_patches(path: str) -> List[Patch]:
# names are independent of the installer's: without this the two editions
# overwrite each other's login item / Startup shortcut / autostart .desktop even
# though every other identity is already split.
#
# aw-qt#133 made those names profile-aware (`aw-qt-research.desktop`,
# `net.activitywatch.aw-qt-research`, `ActivityWatch (research)`). The research
# edition *is* profile=research, so the suffix alone collides with a standard
# build launched as `--profile research`. Override the written identities to
# edition-specific names; leave DESKTOP_FILENAME / LAUNCH_AGENT_LABEL as the
# shipped-resource / base strings.

AUTOSTART_PATCHES_QT: List[Patch] = [
Patch(
Expand All @@ -558,16 +565,18 @@ def _python_profile_patches(path: str) -> List[Patch]:
),
Patch(
"aw-qt/aw_qt/autostart.py",
" return _linux_autostart_dir() / DESKTOP_FILENAME\n",
' return _linux_autostart_dir() / f"{stem}{_profile_suffix()}{extension}"\n',
f' return _linux_autostart_dir() / "{LINUX_DESKTOP_FILENAME}"\n',
"Linux autostart entry filename (DESKTOP_FILENAME still names the "
"shipped resource we copy from)",
"shipped resource we copy from; do not use aw-qt-research.desktop — "
"that is the standard build's named-profile entry)",
),
Patch(
"aw-qt/aw_qt/autostart.py",
'LAUNCH_AGENT_LABEL = "net.activitywatch.aw-qt"\n',
f'LAUNCH_AGENT_LABEL = "{LAUNCH_AGENT_LABEL}"\n',
"macOS LaunchAgent label and plist filename",
' return f"{LAUNCH_AGENT_LABEL}{_profile_suffix()}"\n',
f' return "{BUNDLE_ID}"\n',
"macOS LaunchAgent label (bundle id, not net.activitywatch.aw-qt-research, "
"which is the standard build's named-profile label)",
),
Patch(
"aw-qt/aw_qt/autostart.py",
Expand All @@ -579,13 +588,10 @@ def _python_profile_patches(path: str) -> List[Patch]:


# --- first-run autostart identity (Tauri) --------------------------------------
# tauri_plugin_autostart derives its OS entry name from productName by default.
# Standard and research Tauri builds share productName="aw-tauri", so their
# autostart entries (Windows registry Run key, Linux ~/.config/autostart/ file)
# overwrite each other. Give the research build a distinct name by switching to
# the Builder API and setting app_name when BUILD_PROFILE is not the default.
# macOS uses different OS mechanisms (AppleScript vs LaunchAgent) so it doesn't
# collide, but the macos_launcher selection is included for completeness.
# aw-tauri#253 already gives named profiles a distinct plugin app name
# (`aw-tauri-research`). The research edition *is* profile=research, so that
# name collides with a standard build launched as `--profile research`. Override
# with an edition-specific `aw-tauri-{BUILD_PROFILE}-edition` identity.
#
# This patch applies after PROFILE_PATCHES_TAURI, so BUILD_PROFILE and
# DEFAULT_PROFILE are both defined in the compiled profile module by the time
Expand All @@ -594,47 +600,26 @@ def _python_profile_patches(path: str) -> List[Patch]:
AUTOSTART_PATCHES_TAURI: List[Patch] = [
Patch(
"aw-tauri/src-tauri/src/lib.rs",
" .plugin(tauri_plugin_autostart::init(\n"
" // AppleScript login items silently drop extra arguments; LaunchAgent\n"
" // writes a plist with ProgramArguments so --profile survives relogin.\n"
" if profile::is_default(&cli_args.profile) {\n"
" MacosLauncher::AppleScript\n"
" } else {\n"
" MacosLauncher::LaunchAgent\n"
" },\n"
" if profile::is_default(&cli_args.profile) {\n"
" Some(vec![])\n"
" } else {\n"
" Some(vec![\"--profile\", cli_args.profile.as_str()])\n"
" },\n"
" ))\n",
" .plugin({\n"
" // AppleScript login items silently drop extra arguments; LaunchAgent\n"
" // writes a plist with ProgramArguments so --profile survives relogin.\n"
" // Non-default BUILD_PROFILE means a research-edition binary: give it a\n"
" // distinct autostart entry name so editions don't overwrite each other.\n"
" let is_default_profile = profile::is_default(&cli_args.profile);\n"
" let args: Vec<&str> = if is_default_profile {\n"
" vec![]\n"
" } else {\n"
" vec![\"--profile\", cli_args.profile.as_str()]\n"
" };\n"
" #[allow(unused_mut)]\n"
" let mut b = tauri_plugin_autostart::Builder::new().args(args);\n"
" if profile::BUILD_PROFILE != profile::DEFAULT_PROFILE {\n"
" b = b.app_name(format!(\"aw-tauri-{}\", profile::BUILD_PROFILE));\n"
" if let Some(app_name) = profile::autostart_app_name(&cli_args.profile) {\n"
" builder = builder\n"
" .app_name(app_name)\n"
" .args([\"--profile\", cli_args.profile.as_str()]);\n"
" }\n",
" if let Some(app_name) = profile::autostart_app_name(&cli_args.profile) {\n"
" builder = builder\n"
" .app_name(app_name)\n"
" .args([\"--profile\", cli_args.profile.as_str()]);\n"
" }\n"
" #[cfg(target_os = \"macos\")]\n"
" {\n"
" b = b.macos_launcher(if is_default_profile {\n"
" MacosLauncher::AppleScript\n"
" } else {\n"
" MacosLauncher::LaunchAgent\n"
" });\n"
" }\n"
" b.build()\n"
" })\n",
"tauri autostart: Builder with distinct app_name for research edition",
" // Non-default BUILD_PROFILE is a research-edition binary: do not\n"
" // reuse the named-profile identity (`aw-tauri-research`), which a\n"
" // standard `--profile research` login item already owns.\n"
" if profile::BUILD_PROFILE != profile::DEFAULT_PROFILE {\n"
" builder = builder.app_name(format!(\n"
" \"aw-tauri-{}-edition\",\n"
" profile::BUILD_PROFILE\n"
" ));\n"
" }\n",
"tauri autostart: edition-specific app_name so research != named profile",
),
]

Expand Down
40 changes: 23 additions & 17 deletions scripts/tests/test_patch_research_edition_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,21 +436,26 @@ def test_first_run_autostart_identity_is_distinct_on_every_platform(tmp_path: Pa

# Linux: the written filename changes; the *shipped resource* name does not
# (the patched build still reads resources/aw-qt.desktop out of the bundle).
# Must not be aw-qt-research.desktop — that is the standard named-profile entry.
assert f'_linux_autostart_dir() / "{patcher.LINUX_DESKTOP_FILENAME}"' in after
assert "aw-qt-research.desktop" not in after
assert 'DESKTOP_FILENAME = "aw-qt.desktop"' in after
# macOS: LAUNCH_AGENT_FILENAME is derived, so the plist follows the label.
assert f'LAUNCH_AGENT_LABEL = "{patcher.LAUNCH_AGENT_LABEL}"' in after
assert 'LAUNCH_AGENT_LABEL = "net.activitywatch.aw-qt"\n' not in after
# macOS: plist path follows _macos_launch_agent_label(), which would otherwise
# become net.activitywatch.aw-qt-research and collide with --profile research.
assert f'return "{patcher.BUNDLE_ID}"' in after
assert 'return f"{LAUNCH_AGENT_LABEL}{_profile_suffix()}"' not in after
assert f'return "{patcher.LAUNCH_AGENT_LABEL}"' not in after
# Windows: both the Run value name and the Startup .lnk derive from APP_NAME.
# Named-profile suffixing then yields "ActivityWatch Research (research)".
assert f'APP_NAME = "{patcher.BUNDLE_NAME}"' in after
assert 'APP_NAME = "ActivityWatch"\n' not in after

# Guard the derivations the assertions above rely on: if upstream stops
# deriving these, the research build silently keeps a colliding name.
# Guard the runtime identity sources: if upstream stops suffixing these, the
# research overrides above would be patching dead code.
for derived in (
'LAUNCH_AGENT_FILENAME = f"{LAUNCH_AGENT_LABEL}.plist"',
"WINDOWS_RUN_VALUE_NAME = APP_NAME",
'WINDOWS_STARTUP_SHORTCUT_NAME = f"{APP_NAME}.lnk"',
'return _linux_autostart_dir() / f"{stem}{_profile_suffix()}{extension}"',
'return f"{LAUNCH_AGENT_LABEL}{_profile_suffix()}"',
'return APP_NAME if not suffix else f"{APP_NAME} ({_profile()})"',
):
assert derived in before, f"upstream no longer derives: {derived}"

Expand Down Expand Up @@ -487,23 +492,24 @@ def test_tauri_autostart_uses_distinct_app_name_for_research_build(tmp_path: Pat
)
assert f'pub const BUILD_PROFILE: &str = "{patcher.RESEARCH_PROFILE}";' in after_profile

# --- half 2: AUTOSTART_PATCHES_TAURI replaces init() with Builder + app_name ---
# --- half 2: AUTOSTART_PATCHES_TAURI overrides named-profile app_name ---
lib_rs_rel = "aw-tauri/src-tauri/src/lib.rs"
lib_rs_src = _repo_root() / lib_rs_rel
if not lib_rs_src.is_file():
pytest.skip(f"{lib_rs_rel} not present")
before_lib = lib_rs_src.read_text(encoding="utf-8")
# Standard source uses init(), not Builder
assert "tauri_plugin_autostart::init(" in before_lib
assert "tauri_plugin_autostart::Builder::new()" not in before_lib
# Standard source already uses Builder + named-profile identities.
assert "tauri_plugin_autostart::Builder::new()" in before_lib
assert "profile::autostart_app_name" in before_lib
assert "BUILD_PROFILE" not in before_lib
after_lib = _patch_real_file(
tmp_path,
lib_rs_rel,
patcher.AUTOSTART_PATCHES_TAURI,
)
# Research build uses Builder with conditional app_name
assert "tauri_plugin_autostart::Builder::new().args(args)" in after_lib
# Research build keeps named-profile wiring, then overrides the OS identity
# so it does not collide with a standard `--profile research` login item.
assert "profile::autostart_app_name" in after_lib
assert "profile::BUILD_PROFILE != profile::DEFAULT_PROFILE" in after_lib
assert 'b.app_name(format!("aw-tauri-{}", profile::BUILD_PROFILE))' in after_lib
# Standard autostart call is gone
assert "tauri_plugin_autostart::init(" not in after_lib
assert '"aw-tauri-{}-edition"' in after_lib
assert 'format!("aw-tauri-{}", profile::BUILD_PROFILE)' not in after_lib