Skip to content

Commit 5058cf2

Browse files
committed
fix: sync block execution failed due to Runtime mutably borrowed more than once (#2225)
1 parent ed3c9c4 commit 5058cf2

File tree

8 files changed

+54
-40
lines changed

8 files changed

+54
-40
lines changed

.github/workflows/draft.yml

+13-4
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,24 @@ jobs:
203203
runs-on: ubuntu-latest
204204
needs: [build-unix, build-windows, build-musl, build-snap]
205205
steps:
206-
- uses: actions/download-artifact@v4
207-
with:
208-
merge-multiple: true
209-
210206
- run: |
211207
echo 'NIGHTLY_BODY<<EOF' >> $GITHUB_ENV
212208
echo "From commit: ${GITHUB_SHA:0:8}" >> $GITHUB_ENV
213209
echo "Generated on: $(date -u +"%Y-%m-%d %H:%M") UTC" >> $GITHUB_ENV
214210
echo "EOF" >> $GITHUB_ENV
215211
212+
- uses: actions/checkout@v4
213+
214+
- uses: actions/download-artifact@v4
215+
with:
216+
merge-multiple: true
217+
218+
- name: Update the tag
219+
run: |
220+
git config user.name "github-actions[bot]"
221+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
222+
git tag --force nightly && git push --force origin tag nightly
223+
216224
- name: Nightly
217225
uses: softprops/action-gh-release@v1
218226
with:
@@ -223,3 +231,4 @@ jobs:
223231
yazi-*.snap
224232
name: Nightly Build
225233
body: ${{ env.NIGHTLY_BODY }}
234+
target_commitish: ${{ github.sha }}

yazi-fm/src/app/commands/accept_payload.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use mlua::IntoLua;
22
use tracing::error;
33
use yazi_dds::{LOCAL, Payload, REMOTE};
4-
use yazi_plugin::{LUA, RtRef};
4+
use yazi_plugin::{LUA, RtRefMut};
55
use yazi_shared::event::CmdCow;
66

77
use crate::{app::App, lives::Lives};
@@ -27,11 +27,11 @@ impl App {
2727
_ = Lives::scope(&self.cx, || {
2828
let body = payload.body.into_lua(&LUA)?;
2929
for (id, cb) in handlers {
30-
LUA.named_registry_value::<RtRef>("rt")?.push(&id);
30+
LUA.named_registry_value::<RtRefMut>("rt")?.push(&id);
3131
if let Err(e) = cb.call::<()>(body.clone()) {
3232
error!("Failed to run `{kind}` event handler in your `{id}` plugin: {e}");
3333
}
34-
LUA.named_registry_value::<RtRef>("rt")?.pop();
34+
LUA.named_registry_value::<RtRefMut>("rt")?.pop();
3535
}
3636
Ok(())
3737
});

yazi-fm/src/app/commands/plugin.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::fmt::Display;
22

33
use mlua::ObjectLike;
44
use scopeguard::defer;
5-
use tracing::warn;
5+
use tracing::{error, warn};
66
use yazi_dds::Sendable;
7-
use yazi_plugin::{LUA, RtRef, loader::LOADER};
7+
use yazi_plugin::{LUA, RtRefMut, loader::LOADER};
88
use yazi_proxy::{AppProxy, options::{PluginMode, PluginOpt}};
99

1010
use crate::{app::App, lives::Lives};
@@ -50,26 +50,28 @@ impl App {
5050
return self.cx.tasks.plugin_micro(opt);
5151
}
5252

53-
match LUA.named_registry_value::<RtRef>("rt") {
53+
match LUA.named_registry_value::<RtRefMut>("rt") {
5454
Ok(mut r) => r.push(&opt.id),
5555
Err(e) => return warn!("{e}"),
5656
}
57-
defer! { _ = LUA.named_registry_value::<RtRef>("rt").map(|mut r| r.pop()) }
57+
defer! { _ = LUA.named_registry_value::<RtRefMut>("rt").map(|mut r| r.pop()) }
5858

5959
let plugin = match LOADER.load_with(&LUA, &opt.id, chunk) {
6060
Ok(plugin) => plugin,
6161
Err(e) => return warn!("{e}"),
6262
};
6363
drop(loader);
6464

65-
_ = Lives::scope(&self.cx, || {
65+
let result = Lives::scope(&self.cx, || {
6666
if let Some(cb) = opt.cb {
6767
cb(&LUA, plugin)
6868
} else {
6969
let job = LUA.create_table_from([("args", Sendable::args_to_table(&LUA, opt.args)?)])?;
70-
7170
plugin.call_method("entry", job)
7271
}
7372
});
73+
if let Err(e) = result {
74+
error!("Sync plugin `{}` failed: {e}", opt.id);
75+
}
7476
}
7577
}

yazi-plugin/src/isolate/seek.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use yazi_shared::event::Cmd;
55

66
use crate::{bindings::Cast, elements::Rect, file::File};
77

8-
pub fn seek_sync(cmd: &Cmd, file: yazi_fs::File, units: i16) {
8+
pub fn seek_sync(cmd: &'static Cmd, file: yazi_fs::File, units: i16) {
99
let cb: PluginCallback = Box::new(move |lua, plugin| {
1010
let job = lua.create_table_from([
1111
("file", File::cast(lua, file)?.into_lua(lua)?),

yazi-plugin/src/loader/require.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use mlua::{ExternalResult, Function, IntoLua, Lua, MetaMethod, MultiValue, ObjectLike, Table, Value};
44

55
use super::LOADER;
6-
use crate::RtRef;
6+
use crate::RtRefMut;
77

88
pub(super) struct Require;
99

@@ -15,9 +15,9 @@ impl Require {
1515
let s = &id.to_str()?;
1616
futures::executor::block_on(LOADER.ensure(s)).into_lua_err()?;
1717

18-
lua.named_registry_value::<RtRef>("rt")?.push(s);
18+
lua.named_registry_value::<RtRefMut>("rt")?.push(s);
1919
let mod_ = LOADER.load(lua, s);
20-
lua.named_registry_value::<RtRef>("rt")?.pop();
20+
lua.named_registry_value::<RtRefMut>("rt")?.pop();
2121

2222
Self::create_mt(lua, s, mod_?, true)
2323
})?,
@@ -31,9 +31,9 @@ impl Require {
3131
let s = &id.to_str()?;
3232
LOADER.ensure(s).await.into_lua_err()?;
3333

34-
lua.named_registry_value::<RtRef>("rt")?.push(s);
34+
lua.named_registry_value::<RtRefMut>("rt")?.push(s);
3535
let mod_ = LOADER.load(&lua, s);
36-
lua.named_registry_value::<RtRef>("rt")?.pop();
36+
lua.named_registry_value::<RtRefMut>("rt")?.pop();
3737

3838
Self::create_mt(&lua, s, mod_?, false)
3939
})?,
@@ -73,19 +73,19 @@ impl Require {
7373
if sync {
7474
lua.create_function(move |lua, args: MultiValue| {
7575
let (mod_, args) = Self::split_mod_and_args(lua, &id, args)?;
76-
lua.named_registry_value::<RtRef>("rt")?.push(&id);
76+
lua.named_registry_value::<RtRefMut>("rt")?.push(&id);
7777
let result = mod_.call_function::<MultiValue>(&f, args);
78-
lua.named_registry_value::<RtRef>("rt")?.pop();
78+
lua.named_registry_value::<RtRefMut>("rt")?.pop();
7979
result
8080
})
8181
} else {
8282
lua.create_async_function(move |lua, args: MultiValue| {
8383
let (id, f) = (id.clone(), f.clone());
8484
async move {
8585
let (mod_, args) = Self::split_mod_and_args(&lua, &id, args)?;
86-
lua.named_registry_value::<RtRef>("rt")?.push(&id);
86+
lua.named_registry_value::<RtRefMut>("rt")?.push(&id);
8787
let result = mod_.call_async_function::<MultiValue>(&f, args).await;
88-
lua.named_registry_value::<RtRef>("rt")?.pop();
88+
lua.named_registry_value::<RtRefMut>("rt")?.pop();
8989
result
9090
}
9191
})

yazi-plugin/src/runtime.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@ use std::collections::{HashMap, VecDeque};
22

33
use mlua::{Function, UserData};
44

5-
#[derive(Default)]
5+
#[derive(Debug, Default)]
66
pub struct Runtime {
77
frames: VecDeque<RuntimeFrame>,
88
blocks: HashMap<String, Vec<Function>>,
99
}
1010

11+
#[derive(Debug)]
1112
struct RuntimeFrame {
1213
id: String,
1314
calls: usize,
1415
}
1516

16-
pub type RtRef = mlua::UserDataRefMut<Runtime>;
17+
pub type RtRef = mlua::UserDataRef<Runtime>;
18+
pub type RtRefMut = mlua::UserDataRefMut<Runtime>;
1719

1820
impl Runtime {
1921
pub fn new(id: &str) -> Self {
@@ -31,6 +33,8 @@ impl Runtime {
3133

3234
pub fn current(&self) -> Option<&str> { self.frames.back().map(|f| f.id.as_str()) }
3335

36+
pub fn current_owned(&self) -> Option<String> { self.current().map(ToOwned::to_owned) }
37+
3438
pub fn next_block(&mut self) -> Option<usize> {
3539
self.frames.back_mut().map(|f| {
3640
f.calls += 1;

yazi-plugin/src/utils/sync.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,31 @@ use yazi_proxy::{AppProxy, options::{PluginCallback, PluginOpt}};
66
use yazi_shared::event::Data;
77

88
use super::Utils;
9-
use crate::{bindings::{MpscRx, MpscTx, MpscUnboundedRx, MpscUnboundedTx, OneshotRx, OneshotTx}, loader::LOADER, runtime::RtRef};
9+
use crate::{RtRefMut, bindings::{MpscRx, MpscTx, MpscUnboundedRx, MpscUnboundedTx, OneshotRx, OneshotTx}, loader::LOADER, runtime::RtRef};
1010

1111
impl Utils {
1212
pub(super) fn sync(lua: &Lua, isolate: bool) -> mlua::Result<Function> {
1313
if isolate {
1414
lua.create_function(|lua, ()| {
15-
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.next_block() else {
15+
let Some(block) = lua.named_registry_value::<RtRefMut>("rt")?.next_block() else {
1616
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
1717
};
1818

1919
lua.create_async_function(move |lua, args: MultiValue| async move {
20-
if let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current() {
21-
Sendable::list_to_values(&lua, Self::retrieve(cur, block, args).await?)
22-
} else {
23-
Err("block spawned by `ya.sync()` must be called in a plugin").into_lua_err()
24-
}
20+
let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current_owned() else {
21+
return Err("block spawned by `ya.sync()` must be called in a plugin").into_lua_err();
22+
};
23+
Sendable::list_to_values(&lua, Self::retrieve(cur, block, args).await?)
2524
})
2625
})
2726
} else {
2827
lua.create_function(|lua, f: Function| {
29-
let mut rt = lua.named_registry_value::<RtRef>("rt")?;
28+
let mut rt = lua.named_registry_value::<RtRefMut>("rt")?;
3029
if !rt.put_block(f.clone()) {
3130
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
3231
}
3332

34-
let cur = rt.current().unwrap().to_owned();
33+
let cur = rt.current_owned().unwrap();
3534
lua.create_function(move |lua, mut args: MultiValue| {
3635
args.push_front(Value::Table(LOADER.try_load(lua, &cur)?));
3736
f.call::<MultiValue>(args)
@@ -78,14 +77,14 @@ impl Utils {
7877
lua.create_async_function(|_lua, _futs: MultiValue| async move { Ok(()) })
7978
}
8079

81-
async fn retrieve(id: &str, calls: usize, args: MultiValue) -> mlua::Result<Vec<Data>> {
80+
async fn retrieve(id: String, calls: usize, args: MultiValue) -> mlua::Result<Vec<Data>> {
8281
let args = Sendable::values_to_list(args)?;
8382
let (tx, rx) = oneshot::channel::<Vec<Data>>();
8483

8584
let callback: PluginCallback = {
86-
let id = id.to_owned();
85+
let id_ = id.clone();
8786
Box::new(move |lua, plugin| {
88-
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&id, calls) else {
87+
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&id_, calls) else {
8988
return Err("sync block not found".into_lua_err());
9089
};
9190

@@ -99,7 +98,7 @@ impl Utils {
9998
})
10099
};
101100

102-
AppProxy::plugin(PluginOpt::new_callback(id, callback));
101+
AppProxy::plugin(PluginOpt::new_callback(id.clone(), callback));
103102

104103
rx.await
105104
.map_err(|_| format!("Failed to execute sync block-{calls} in `{id}` plugin").into_lua_err())

yazi-proxy/src/options/plugin.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ impl Debug for PluginOpt {
4949
}
5050

5151
impl PluginOpt {
52-
pub fn new_callback(id: &str, cb: PluginCallback) -> Self {
53-
Self { id: id.to_owned().into(), mode: PluginMode::Sync, cb: Some(cb), ..Default::default() }
52+
pub fn new_callback(id: impl Into<Cow<'static, str>>, cb: PluginCallback) -> Self {
53+
Self { id: id.into(), mode: PluginMode::Sync, cb: Some(cb), ..Default::default() }
5454
}
5555
}
5656

0 commit comments

Comments
 (0)