diff --git a/crates/engine/src/doc_list_paths_tests.rs b/crates/engine/src/doc_list_paths_tests.rs index f69941919..0d73d0736 100644 --- a/crates/engine/src/doc_list_paths_tests.rs +++ b/crates/engine/src/doc_list_paths_tests.rs @@ -63,3 +63,20 @@ fn a_plugin_gets_library_names_but_not_their_links() { assert!(out.contains("Kit"), "{out}"); assert!(!out.contains("per-file-secret") && !out.contains("\\\"path\\\""), "{out}"); } + +#[test] +fn a_plugin_gets_a_fixed_message_for_library_update_failures() { + const LINK: &str = "/home/someone/private/kits/kit.figcraft"; + let mut s = Session::new(); + s.doc_mut().unwrap().libraries_mut().enabled.push(figcraft_doc::LibraryLink { + id: "lib".into(), + name: "Kit".into(), + path: LINK.into(), + version: 3, + }); + let tail = "(call $set_output (i32.const 40000) (call $reply_read (i32.const 40000) (i32.const 20000))) (return (i32.const 0))"; + install(&mut s, manifest("org.test.upd", "read", &[]), &script(&[("library.updates", json!({}))], OnRefusal::Fail, tail)); + let out = ex(&mut s, "plugin.run", json!({"id": "org.test.upd"}))["output"].to_string(); + assert!(out.contains("could not be read"), "{out}"); + assert!(!out.contains("someone") && !out.contains("private"), "{out}"); +} diff --git a/crates/engine/src/extensions/plugins.rs b/crates/engine/src/extensions/plugins.rs index 78044ee71..7677a9b7d 100644 --- a/crates/engine/src/extensions/plugins.rs +++ b/crates/engine/src/extensions/plugins.rs @@ -264,16 +264,20 @@ impl figcraft_plugin::Host for EngineHost<'_> { r.map(|mut v| { // A plugin gets the open files' and libraries' names, not where they are on disk or // the share links (with their tokens) that reach them (#1117). - if matches!(command, "doc.list" | "library.list") { - // `doc.list` is a list; `library.list` keeps its list under `libraries`. - let list = if command == "library.list" { v.get_mut("libraries") } else { Some(&mut v) }; + if matches!(command, "doc.list" | "library.list" | "library.updates") { + // `doc.list` is a list; `library.list` keeps its list under `libraries`, and + // `library.updates` its failures under `errors`. + let list = match command { + "library.list" => v.get_mut("libraries"), + "library.updates" => v.get_mut("errors"), + _ => Some(&mut v), + }; for e in list.and_then(Value::as_array_mut).into_iter().flatten().filter_map(Value::as_object_mut) { - // An error may quote the path too. - if let Some(Value::String(path)) = e.remove("path") - && !path.is_empty() - && let Some(Value::String(err)) = e.get_mut("error") - { - *err = err.replace(&path, "the library"); + e.remove("path"); + // A failure's text may quote the path, a token or another form of it: the + // plugin gets a fixed message. + if let Some(err) = e.get_mut("error").filter(|v| v.is_string()) { + *err = json!("the library could not be read"); } } }