Handle shebang more thoroughly in scripts plugin (#160)
* feat(scripts): allow whitespace after shebang `#!` characters * feat(scripts): allow shebang line to have its own args * fix(scripts): improve unwraps and extra allocations; use SHELL env variable
This commit is contained in:
parent
92766af95f
commit
1fa817f12f
1 changed files with 39 additions and 5 deletions
|
|
@ -6,6 +6,7 @@ use pop_launcher::*;
|
||||||
|
|
||||||
use flume::Sender;
|
use flume::Sender;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
use regex::Regex;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
@ -54,11 +55,42 @@ impl App {
|
||||||
|
|
||||||
async fn activate(&mut self, id: u32) {
|
async fn activate(&mut self, id: u32) {
|
||||||
if let Some(script) = self.scripts.get(id as usize) {
|
if let Some(script) = self.scripts.get(id as usize) {
|
||||||
let interpreter = script.interpreter.as_deref().unwrap_or("sh");
|
let mut shell: String = Default::default();
|
||||||
|
let mut args: Vec<&OsStr> = Vec::new();
|
||||||
|
|
||||||
|
let program = script
|
||||||
|
.interpreter
|
||||||
|
.as_deref()
|
||||||
|
.and_then(|interpreter| {
|
||||||
|
// split the shebang into parts, e.g. ["/bin/bash"], or a more complex ["/usr/bin/env", "bash"]
|
||||||
|
let mut parts = interpreter.split_ascii_whitespace();
|
||||||
|
|
||||||
|
// first part must be the command to run, e.g. "/usr/bin/env"
|
||||||
|
let command = parts.next()?;
|
||||||
|
|
||||||
|
for arg in parts {
|
||||||
|
args.push(arg.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(command)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
if let Ok(string) = std::env::var("SHELL") {
|
||||||
|
shell = string;
|
||||||
|
return Some(&shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.unwrap_or("sh");
|
||||||
|
|
||||||
|
// add the script file itself as a final arg for the interpreter
|
||||||
|
args.push(script.path.as_ref());
|
||||||
|
|
||||||
send(&mut self.out, PluginResponse::Close).await;
|
send(&mut self.out, PluginResponse::Close).await;
|
||||||
|
|
||||||
let _ = Command::new(interpreter)
|
let _ = Command::new(program)
|
||||||
.arg(script.path.as_os_str())
|
.args(args)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::null())
|
.stdout(Stdio::null())
|
||||||
.stderr(Stdio::null())
|
.stderr(Stdio::null())
|
||||||
|
|
@ -156,6 +188,8 @@ async fn load_from(path: &Path, paths: &mut VecDeque<PathBuf>, tx: Sender<Script
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
let shebang_re = Regex::new(r"^!\s*").unwrap();
|
||||||
|
|
||||||
let mut file = match tokio::fs::File::open(&path).await {
|
let mut file = match tokio::fs::File::open(&path).await {
|
||||||
Ok(file) => tokio::io::BufReader::new(file).lines(),
|
Ok(file) => tokio::io::BufReader::new(file).lines(),
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
|
|
@ -180,8 +214,8 @@ async fn load_from(path: &Path, paths: &mut VecDeque<PathBuf>, tx: Sender<Script
|
||||||
|
|
||||||
if first {
|
if first {
|
||||||
first = false;
|
first = false;
|
||||||
if let Some(interpreter) = line.strip_prefix('!') {
|
if shebang_re.is_match(line) {
|
||||||
info.interpreter = Some(interpreter.to_owned());
|
info.interpreter = Some(shebang_re.replace(line, "").to_string());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue