From abb179bb495536a0e093d386d6b9dadaddce6ed6 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Wed, 21 Oct 2026 00:44:33 +0800 Subject: [PATCH] Build Makepad's catalog apps in the checkout, shared by every home The six "source": "makepad" catalog apps (browser, files, finance, route, image, pdf) built into /build/makepad, so every new home (each test or demo profile) compiled all six again, minutes each on a busy Mac, and kept its own 1.5-2 GB copy. They now build in the checkout's own target dir, target/makepad ($CARGO_TARGET_DIR/makepad when set), beside the native apps, which every home already shared. Co-Authored-By: Claude Opus 5.5 --- crates/shell/src/clients.rs | 29 ++++++++++++++++++++++++++- crates/shell/src/octosense/catalog.rs | 21 ++++++++++++------- crates/shell/src/sandbox/tests.rs | 8 +++++--- desktop/README.md | 2 +- desktop/README.zh-CN.md | 2 +- 5 files changed, 49 insertions(+), 13 deletions(-) diff --git a/crates/shell/src/clients.rs b/crates/shell/src/clients.rs index c0d6d9ec..c9def6a8 100644 --- a/crates/shell/src/clients.rs +++ b/crates/shell/src/clients.rs @@ -1098,6 +1098,12 @@ fn env_target_dir(dir: &Path) -> Option { std::env::var_os("CARGO_TARGET_DIR").filter(|v| !v.is_empty()).map(|v| dir.join(v)) } +/// The target dir of the workspace at `root`, where its native apps build: +/// `CARGO_TARGET_DIR` as cargo reads it there, else `/target`. +pub(crate) fn workspace_target_dir(root: &Path) -> PathBuf { + env_target_dir(root).unwrap_or_else(|| root.join("target")) +} + /// The launch of `app` (the release-only law: a hosted app is always a /// release build). /// @@ -1131,7 +1137,7 @@ pub fn launch_plan(app: &AppDef, root: Option<&Path>, extra_args: &[String]) -> // The desktop package lives in the workspace (`desktop/`): build // from the workspace itself, where its lock and target dir are. let root = &workspace_root(root); - let target = env_target_dir(root).unwrap_or_else(|| root.join("target")); + let target = workspace_target_dir(root); (root.to_path_buf(), root.join("Cargo.toml"), package.to_string(), bin.to_string(), target, true, Some(PROCESS_APPS)) } _ => { @@ -1809,6 +1815,27 @@ mod tests { assert_eq!(build.dir, Path::new("/cargo/checkouts/makepad-d00a/ad8f372"), "cargo runs in its checkout"); } + /// Makepad's apps build in the checkout's own target dir, beside the + /// native apps, never in the OctoSense home: a test or demo profile + /// opens them already built, where one under the home built all six + /// again, minutes each (20 Oct 2026). + #[test] + fn makepad_launches_share_the_checkouts_build_with_every_home() { + let apps = crate::octosense::catalog::parse_catalog( + br#"[{"id":"files","label":"Files","source":"makepad","package":"makepad-files","bin":"files"}]"#, + Path::new("/catalog"), + Some(Path::new("/checkout/.sources/makepad")), + ) + .unwrap(); + let root = repo_root().expect("the tests run in a checkout"); + let build = launch_plan(&apps[0], Some(&root), &[]).unwrap().build.unwrap(); + let native = AppDef::app("terminal", "Terminal", "makepad-terminal", "", "terminal", LaunchPolicy::AlwaysNew); + let native = launch_plan(&native, Some(&root), &[]).unwrap().build.unwrap(); + assert_eq!(build.target_dir, native.target_dir.join("makepad"), "beside the native apps' builds"); + assert!(!build.target_dir.starts_with(crate::octosense::paths::home()), "{}", build.target_dir.display()); + assert!(build.args.windows(2).any(|p| p[0] == "--target-dir" && Path::new(&p[1]) == build.target_dir), "{:?}", build.args); + } + #[test] fn installed_catalog_refreshes_without_shadowing_native_apps() { let app = |id: &str, label: &str| AppDef::app(id, label, "", "", "card", LaunchPolicy::OrFocus); diff --git a/crates/shell/src/octosense/catalog.rs b/crates/shell/src/octosense/catalog.rs index 0509dca8..11cad47c 100644 --- a/crates/shell/src/octosense/catalog.rs +++ b/crates/shell/src/octosense/catalog.rs @@ -74,13 +74,7 @@ pub fn parse_catalog( let Some(root) = makepad_root else { return Ok(None); }; - target_dir = Some( - super::paths::home() - .join("build") - .join(name) - .to_string_lossy() - .into_owned(), - ); + target_dir = Some(makepad_target_dir().to_string_lossy().into_owned()); ( Some(root.join("Cargo.toml").to_string_lossy().into_owned()), required("package")?, @@ -139,6 +133,19 @@ pub fn parse_catalog( Ok(out) } +/// Where the catalog's Makepad rows build: `makepad/` in the checkout's own +/// target dir, beside the native apps (`CARGO_TARGET_DIR` when set). Every +/// OctoSense home run from the checkout, a test or demo profile too, shares +/// that one build; under the home, each new profile built all six apps +/// again, minutes each. With no checkout to find, the home's +/// `build/makepad`. +fn makepad_target_dir() -> PathBuf { + match super::paths::project_root() { + Some(project) => crate::clients::workspace_target_dir(&crate::clients::workspace_root(&project)).join("makepad"), + None => super::paths::home().join("build").join("makepad"), + } +} + fn catalog_path() -> Result, String> { let args: Vec<_> = std::env::args().collect(); if let Some(i) = args.iter().position(|a| a == "--apps") { diff --git a/crates/shell/src/sandbox/tests.rs b/crates/shell/src/sandbox/tests.rs index 5699d019..c0496962 100644 --- a/crates/shell/src/sandbox/tests.rs +++ b/crates/shell/src/sandbox/tests.rs @@ -634,9 +634,11 @@ fn the_allow_list_never_admits_a_secret_shaped_name() { #[test] fn a_program_inside_the_octosense_home_stays_readable() { - // The desktop builds process apps into `/build`: the - // private deny must not take the app's own program away (the Terminal - // crashed at start, unable to read its own bundle). + // A process app's program can sit inside the OctoSense home (the + // desktop built Makepad's catalog apps into `/build` + // until they moved to the checkout's target dir): the private deny must + // not take the app's own program away (the Terminal crashed at start, + // unable to read its own bundle). let root = Path::new("/nonexistent/home"); let mut p = home_rw_with_octosense_home(root); let build = root.join(".octosense/build/makepad"); diff --git a/desktop/README.md b/desktop/README.md index d1dbad99..6ccde5c2 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -319,7 +319,7 @@ Catalog lookup: `--apps ` if given, else `~/.octosense/apps.json` if it ex ] ``` -- `"source": "makepad"` resolves through Cargo to the same Makepad checkout as the host (`.sources/makepad`); such builds go to `~/.octosense/build/makepad`. +- `"source": "makepad"` resolves through Cargo to the same Makepad checkout as the host (`.sources/makepad`); such builds go to the checkout's `target/makepad` (`$CARGO_TARGET_DIR/makepad` when set), beside the native apps, and every OctoSense home run from that checkout shares them. Older shells built them into `~/.octosense/build/makepad`; that folder is no longer used and can be deleted. - Step-by-step guides (Chinese): [open a hosted app](docs/open-apps.md), including the fix for an empty catalog when `cargo metadata --offline` fails, and [open the full Makepad catalog](docs/add-all-makepad-apps.md). - Relative paths resolve from the catalog's directory. Arguments are passed literally, without a shell. - `policy`: `"new"` opens another instance; `"focus"` (default) focuses a running one. diff --git a/desktop/README.zh-CN.md b/desktop/README.zh-CN.md index d982110f..2fa25196 100644 --- a/desktop/README.zh-CN.md +++ b/desktop/README.zh-CN.md @@ -304,7 +304,7 @@ OCTOSENSE_HUB_CATALOG=legacy \ ] ``` -- `"source": "makepad"` 通过 Cargo 解析到与宿主相同的 Makepad 检出(`.sources/makepad`);这类构建输出到 `~/.octosense/build/makepad`。 +- `"source": "makepad"` 通过 Cargo 解析到与宿主相同的 Makepad 检出(`.sources/makepad`);这类构建输出到该检出的 `target/makepad`(设置了 `CARGO_TARGET_DIR` 时为 `$CARGO_TARGET_DIR/makepad`),与原生应用的构建放在一起,从该检出运行的每个 OctoSense 主目录都共用它们。旧版 Shell 把它们构建到 `~/.octosense/build/makepad`;该目录已不再使用,可以删除。 - 分步指南:[打开托管应用](docs/open-apps.md)(包括 `cargo metadata --offline` 失败导致目录为空时的修复方法),以及[打开完整的 Makepad 目录](docs/add-all-makepad-apps.md)。 - 相对路径相对于目录文件所在目录解析。参数按原样传递,不经过 shell。 - `policy`:`"new"` 打开新实例;`"focus"`(默认)聚焦已运行的实例。