feat(pack): add install subcommand; clean up servo-shell stub comment

weft-pack:
- install <dir>: validates the package (runs check), resolves the user
  app store root (WEFT_APP_STORE > ~/.local/share/weft/apps), copies
  the package directory to <root>/<app_id>/. Fails if the destination
  already exists.
- resolve_install_root(): replaces the unused _resolve_store_roots;
  returns a single writable root rather than a search list.
- copy_dir(): recursive directory copy using std::fs only; no new deps.
- Updated usage text to include all three subcommands.

weft-servo-shell: removed stale implementation-note comment from
embed_servo stub.
This commit is contained in:
Marco Allegretti 2026-03-11 09:45:31 +01:00
parent ab38b96a7f
commit 265868bf67
2 changed files with 53 additions and 30 deletions

View file

@ -43,10 +43,15 @@ fn main() -> anyhow::Result<()> {
let manifest = load_manifest(Path::new(dir))?;
print_info(&manifest);
}
Some("install") => {
let dir = args.get(2).context("usage: weft-pack install <dir>")?;
install_package(Path::new(dir))?;
}
_ => {
eprintln!("usage:");
eprintln!(" weft-pack check <dir> validate a package directory");
eprintln!(" weft-pack info <dir> print package metadata");
eprintln!(" weft-pack check <dir> validate a package directory");
eprintln!(" weft-pack info <dir> print package metadata");
eprintln!(" weft-pack install <dir> install package to app store");
std::process::exit(1);
}
}
@ -140,22 +145,57 @@ fn is_valid_app_id(id: &str) -> bool {
})
}
fn _resolve_store_roots() -> Vec<PathBuf> {
fn resolve_install_root() -> anyhow::Result<PathBuf> {
if let Ok(explicit) = std::env::var("WEFT_APP_STORE") {
return vec![PathBuf::from(explicit)];
return Ok(PathBuf::from(explicit));
}
let mut roots = Vec::new();
if let Ok(home) = std::env::var("HOME") {
roots.push(
PathBuf::from(home)
.join(".local")
.join("share")
.join("weft")
.join("apps"),
return Ok(PathBuf::from(home)
.join(".local")
.join("share")
.join("weft")
.join("apps"));
}
anyhow::bail!("cannot determine install root: HOME and WEFT_APP_STORE are both unset")
}
fn install_package(dir: &Path) -> anyhow::Result<()> {
check_package(dir)?;
let manifest = load_manifest(dir)?;
let app_id = &manifest.package.id;
let store_root = resolve_install_root()?;
let dest = store_root.join(app_id);
if dest.exists() {
anyhow::bail!(
"package '{}' is already installed at {}; remove it first",
app_id,
dest.display()
);
}
roots.push(PathBuf::from("/usr/share/weft/apps"));
roots
copy_dir(dir, &dest)
.with_context(|| format!("copy {} -> {}", dir.display(), dest.display()))?;
println!("installed {} -> {}", app_id, dest.display());
Ok(())
}
fn copy_dir(src: &Path, dst: &Path) -> anyhow::Result<()> {
std::fs::create_dir_all(dst)?;
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let src_path = entry.path();
let dst_path = dst.join(entry.file_name());
if src_path.is_dir() {
copy_dir(&src_path, &dst_path)?;
} else {
std::fs::copy(&src_path, &dst_path)
.with_context(|| format!("copy {}", src_path.display()))?;
}
}
Ok(())
}
#[cfg(test)]

View file

@ -43,23 +43,6 @@ fn system_ui_html_path() -> anyhow::Result<PathBuf> {
}
fn embed_servo(_wayland_display: &str, _html_path: &std::path::Path) -> anyhow::Result<()> {
// Wave 4 skeleton entry point.
//
// Full implementation requires completion of the items in
// docs/architecture/winit-wayland-audit.md before production readiness,
// and the following integration work:
//
// 1. Add servo git dependency (not on crates.io; requires building Servo)
// 2. Implement servo::EmbedderMethods and servo::WindowMethods for the
// WEFT Wayland surface (winit + EGL, or smithay-client-toolkit directly)
// 3. Call servo::Servo::new() with the window and embedder
// 4. Load the system UI via servo::ServoUrl::parse(html_path)
// 5. Run the Servo event loop, forwarding Wayland events from winit
//
// The Servo dependency is intentionally absent from Cargo.toml at this stage.
// It requires a git dependency on github.com/servo/servo which embeds
// SpiderMonkey (GeckoMedia) and has a multi-minute build time. It is added
// when the embedder contract is ready.
anyhow::bail!(
"Servo embedding not yet implemented; \
see docs/architecture/winit-wayland-audit.md for gap assessment"