Skip to content

Commit 9b3b163

Browse files
authored
feat(core): simplify scope definition for sidecars (#3574)
1 parent 91ec876 commit 9b3b163

File tree

9 files changed

+137
-37
lines changed

9 files changed

+137
-37
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch
3+
---
4+
5+
The `cmd` field is no longer required on the shell scope for sidecars.

core/tauri-utils/src/config.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ impl Allowlist for WindowAllowlistConfig {
877877
}
878878

879879
/// A command allowed to be executed by the webview API.
880-
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
880+
#[derive(Debug, PartialEq, Clone, Serialize)]
881881
#[cfg_attr(feature = "schema", derive(JsonSchema))]
882882
pub struct ShellAllowedCommand {
883883
/// The name for this allowed shell command configuration.
@@ -903,6 +903,39 @@ pub struct ShellAllowedCommand {
903903
pub sidecar: bool,
904904
}
905905

906+
impl<'de> Deserialize<'de> for ShellAllowedCommand {
907+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
908+
where
909+
D: Deserializer<'de>,
910+
{
911+
#[derive(Deserialize)]
912+
struct InnerShellAllowedCommand {
913+
name: String,
914+
#[serde(rename = "cmd")]
915+
command: Option<PathBuf>,
916+
#[serde(default)]
917+
args: ShellAllowedArgs,
918+
#[serde(default)]
919+
sidecar: bool,
920+
}
921+
922+
let config = InnerShellAllowedCommand::deserialize(deserializer)?;
923+
924+
if !config.sidecar && config.command.is_none() {
925+
return Err(DeError::custom(
926+
"The shell scope `command` value is required.",
927+
));
928+
}
929+
930+
Ok(ShellAllowedCommand {
931+
name: config.name,
932+
command: config.command.unwrap_or_default(),
933+
args: config.args,
934+
sidecar: config.sidecar,
935+
})
936+
}
937+
}
938+
906939
/// A set of command arguments allowed to be executed by the webview API.
907940
///
908941
/// A value of `true` will allow any arguments to be passed to the command. `false` will disable all

core/tauri/src/endpoints/shell.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl Cmd {
9797
let program = PathBuf::from(program);
9898
let program_as_string = program.display().to_string();
9999
let program_no_ext_as_string = program.with_extension("").display().to_string();
100-
let is_configured = context
100+
let configured_sidecar = context
101101
.config
102102
.tauri
103103
.bundle
@@ -106,15 +106,15 @@ impl Cmd {
106106
.map(|bins| {
107107
bins
108108
.iter()
109-
.any(|b| b == &program_as_string || b == &program_no_ext_as_string)
109+
.find(|b| b == &&program_as_string || b == &&program_no_ext_as_string)
110110
})
111111
.unwrap_or_default();
112-
if is_configured {
112+
if let Some(sidecar) = configured_sidecar {
113113
context
114114
.window
115115
.state::<Scopes>()
116116
.shell
117-
.prepare(&program.to_string_lossy(), args, true)
117+
.prepare_sidecar(&program.to_string_lossy(), sidecar, args)
118118
.map_err(crate::error::into_anyhow)?
119119
} else {
120120
return Err(crate::Error::SidecarNotAllowed(program).into_anyhow());
@@ -128,7 +128,7 @@ impl Cmd {
128128
.window
129129
.state::<Scopes>()
130130
.shell
131-
.prepare(&program, args, false)
131+
.prepare(&program, args)
132132
{
133133
Ok(cmd) => cmd,
134134
Err(e) => {

core/tauri/src/scope/shell.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,37 @@ impl Scope {
197197
Self(scope)
198198
}
199199

200+
/// Validates argument inputs and creates a Tauri sidecar [`Command`].
201+
#[cfg(shell_sidecar)]
202+
pub fn prepare_sidecar(
203+
&self,
204+
command_name: &str,
205+
command_script: &str,
206+
args: ExecuteArgs,
207+
) -> Result<Command, ScopeError> {
208+
self._prepare(command_name, args, Some(command_script))
209+
}
210+
211+
/// Validates argument inputs and creates a Tauri [`Command`].
212+
#[cfg(shell_execute)]
213+
pub fn prepare(&self, command_name: &str, args: ExecuteArgs) -> Result<Command, ScopeError> {
214+
self._prepare(command_name, args, None)
215+
}
216+
200217
/// Validates argument inputs and creates a Tauri [`Command`].
201218
#[cfg(any(shell_execute, shell_sidecar))]
202-
pub fn prepare(
219+
pub fn _prepare(
203220
&self,
204221
command_name: &str,
205222
args: ExecuteArgs,
206-
sidecar: bool,
223+
sidecar: Option<&str>,
207224
) -> Result<Command, ScopeError> {
208225
let command = match self.0.scopes.get(command_name) {
209226
Some(command) => command,
210227
None => return Err(ScopeError::NotFound(command_name.into())),
211228
};
212229

213-
if command.sidecar != sidecar {
230+
if command.sidecar != sidecar.is_some() {
214231
return Err(ScopeError::BadSidecarFlag);
215232
}
216233

@@ -250,7 +267,17 @@ impl Scope {
250267
(Some(_), _) => Err(ScopeError::InvalidInput(command_name.into())),
251268
}?;
252269

253-
let command_s = command.command.to_string_lossy();
270+
let command_s = sidecar
271+
.map(|s| {
272+
std::path::PathBuf::from(s)
273+
.components()
274+
.last()
275+
.unwrap()
276+
.as_os_str()
277+
.to_string_lossy()
278+
.into_owned()
279+
})
280+
.unwrap_or_else(|| command.command.to_string_lossy().into_owned());
254281
let command = if command.sidecar {
255282
Command::new_sidecar(command_s).map_err(ScopeError::Sidecar)?
256283
} else {

examples/sidecar/index.html

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,49 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8" />
5-
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Sidecar</title>
8-
</head>
93

10-
<body>
11-
<div></div>
12-
<script>
13-
const div = document.querySelector('div')
14-
window.__TAURI__.event.listen('message', (event) => {
15-
const p = document.createElement('p')
16-
p.innerText = event.payload
17-
div.appendChild(p)
18-
})
19-
</script>
20-
</body>
4+
<head>
5+
<meta charset="UTF-8" />
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8+
<title>Sidecar</title>
9+
<style>
10+
.container {
11+
display: flex;
12+
}
13+
.container > div {
14+
flex: 1;
15+
}
16+
</style>
17+
</head>
18+
19+
<body>
20+
<div class="container">
21+
<div id="backend"></div>
22+
<div id="frontend"></div>
23+
</div>
24+
<script>
25+
function addMessage(div, message) {
26+
const p = document.createElement('p')
27+
p.innerText = message
28+
div.appendChild(p)
29+
}
30+
31+
const backendDiv = document.getElementById('backend')
32+
window.__TAURI__.event.listen('message', (event) => {
33+
addMessage(backendDiv, event.payload)
34+
})
35+
36+
const frontendDiv = document.getElementById('frontend')
37+
const { Command } = window.__TAURI__.shell
38+
const command = Command.sidecar('binaries/app')
39+
command.on('close', data => {
40+
addMessage(frontendDiv, `command finished with code ${data.code} and signal ${data.signal}`)
41+
})
42+
command.on('error', error => addMessage(frontendDiv, `command error: "${error}"`))
43+
command.stdout.on('data', line => addMessage(frontendDiv, `command stdout: "${line}"`))
44+
command.stderr.on('data', line => addMessage(frontendDiv, `command stderr: "${line}"`))
45+
command.spawn()
46+
</script>
47+
</body>
48+
2149
</html>

examples/sidecar/src-tauri/Cargo.lock

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/sidecar/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ tauri-build = { path = "../../../core/tauri-build", features = ["codegen"] }
1111
[dependencies]
1212
serde_json = "1.0"
1313
serde = { version = "1.0", features = [ "derive" ] }
14-
tauri = { path = "../../../core/tauri", features = ["shell-execute"] }
14+
tauri = { path = "../../../core/tauri", features = ["shell-sidecar"] }
1515

1616
[features]
1717
default = [ "custom-protocol" ]

examples/sidecar/src-tauri/tauri.conf.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@
3838
"allowlist": {
3939
"all": false,
4040
"shell": {
41-
"execute": true
41+
"sidecar": true,
42+
"scope": [
43+
{
44+
"name": "binaries/app",
45+
"sidecar": true
46+
}
47+
]
4248
}
4349
},
4450
"windows": [

tooling/api/src/shell.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
*
4343
* - `name`: the unique identifier of the command, passed to the [[Command.constructor | Command constructor]].
4444
* If it's a sidecar, this must be the value defined on `tauri.conf.json > tauri > bundle > externalBin`.
45-
* - `cmd`: the program that is executed on this configuration. If it's a sidecar, it must be the same as `name`.
45+
* - `cmd`: the program that is executed on this configuration. If it's a sidecar, this value is ignored.
4646
* - `sidecar`: whether the object configures a sidecar or a system program.
4747
* - `args`: the arguments that can be passed to the program. By default no arguments are allowed.
4848
* - `true` means that any argument list is allowed.

0 commit comments

Comments
 (0)