init: Introduce Service type
A future commit will use it to define services in toml format.
This commit is contained in:
+9
-55
@@ -9,6 +9,7 @@ use libredox::flag::{O_RDONLY, O_WRONLY};
|
||||
use crate::script::Command;
|
||||
|
||||
mod script;
|
||||
mod service;
|
||||
|
||||
fn switch_stdio(stdio: &str) -> Result<()> {
|
||||
let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?;
|
||||
@@ -101,64 +102,17 @@ fn run_command(cmd: Command, config: &mut InitConfig) {
|
||||
eprintln!("init: failed to switch stdio to '{}': {}", stdio, err);
|
||||
}
|
||||
}
|
||||
Command::Nowait(cmd) => {
|
||||
if config.skip_cmd.contains(&cmd.cmd) {
|
||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
||||
Command::Service(service) => {
|
||||
if config.skip_cmd.contains(&service.cmd) {
|
||||
eprintln!(
|
||||
"init: skipping '{} {}'",
|
||||
service.cmd,
|
||||
service.args.join(" ")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut command = cmd.into_command(&config.envs);
|
||||
|
||||
match command.spawn() {
|
||||
Ok(_child) => {}
|
||||
Err(err) => eprintln!("init: failed to execute '{:?}': {}", command, err),
|
||||
}
|
||||
}
|
||||
Command::Notify(cmd) => {
|
||||
if config.skip_cmd.contains(&cmd.cmd) {
|
||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
||||
return;
|
||||
}
|
||||
|
||||
let command = cmd.into_command(&config.envs);
|
||||
|
||||
daemon::Daemon::spawn(command);
|
||||
}
|
||||
Command::Scheme(scheme, cmd) => {
|
||||
if config.skip_cmd.contains(&cmd.cmd) {
|
||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
||||
return;
|
||||
}
|
||||
|
||||
let command = cmd.into_command(&config.envs);
|
||||
|
||||
daemon::SchemeDaemon::spawn(command, &scheme);
|
||||
}
|
||||
Command::Regular(cmd) => {
|
||||
if config.skip_cmd.contains(&cmd.cmd) {
|
||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
||||
return;
|
||||
}
|
||||
|
||||
let mut command = cmd.into_command(&config.envs);
|
||||
|
||||
let mut child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to execute {:?}: {}", command, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match child.wait() {
|
||||
Ok(exit_status) => {
|
||||
if !exit_status.success() {
|
||||
eprintln!("{command:?} failed with {exit_status}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to wait for {:?}: {}", command, err)
|
||||
}
|
||||
}
|
||||
service.spawn(&config.envs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-22
@@ -1,7 +1,8 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::OsString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs, io, iter, process};
|
||||
use std::{env, fs, io, iter};
|
||||
|
||||
use crate::service::{Service, ServiceType};
|
||||
|
||||
fn subst_env<'a>(arg: &str) -> String {
|
||||
if arg.starts_with('$') {
|
||||
@@ -39,10 +40,7 @@ impl Script {
|
||||
#[derive(Debug)]
|
||||
pub enum Command {
|
||||
// Service
|
||||
Nowait(Process),
|
||||
Notify(Process),
|
||||
Scheme(String, Process),
|
||||
Regular(Process),
|
||||
Service(Service),
|
||||
|
||||
// Modify env
|
||||
Stdio(String),
|
||||
@@ -79,18 +77,50 @@ impl Command {
|
||||
};
|
||||
Ok(Command::Stdio(stdio))
|
||||
}
|
||||
"nowait" => Ok(Command::Nowait(Process::parse(args)?)),
|
||||
"notify" => Ok(Command::Notify(Process::parse(args)?)),
|
||||
"notify" => {
|
||||
let process = Process::parse(args)?;
|
||||
|
||||
Ok(Command::Service(Service {
|
||||
cmd: process.cmd,
|
||||
args: process.args,
|
||||
envs: process.envs,
|
||||
type_: ServiceType::Notify,
|
||||
}))
|
||||
}
|
||||
"scheme" => {
|
||||
let Some(scheme) = args.next() else {
|
||||
return Err("init: failed to run scheme: no argument".to_owned());
|
||||
};
|
||||
|
||||
Ok(Command::Scheme(scheme, Process::parse(args)?))
|
||||
let process = Process::parse(args)?;
|
||||
|
||||
Ok(Command::Service(Service {
|
||||
cmd: process.cmd,
|
||||
args: process.args,
|
||||
envs: process.envs,
|
||||
type_: ServiceType::Scheme(scheme),
|
||||
}))
|
||||
}
|
||||
"nowait" => {
|
||||
let process = Process::parse(args)?;
|
||||
|
||||
Ok(Command::Service(Service {
|
||||
cmd: process.cmd,
|
||||
args: process.args,
|
||||
envs: process.envs,
|
||||
type_: ServiceType::OneshotAsync,
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
let process = Process::parse(iter::once(cmd).chain(args))?;
|
||||
|
||||
Ok(Command::Service(Service {
|
||||
cmd: process.cmd,
|
||||
args: process.args,
|
||||
envs: process.envs,
|
||||
type_: ServiceType::Oneshot,
|
||||
}))
|
||||
}
|
||||
_ => Ok(Command::Regular(Process::parse(
|
||||
iter::once(cmd).chain(args),
|
||||
)?)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,14 +129,14 @@ impl Command {
|
||||
pub struct Process {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
pub envs: Vec<(String, String)>,
|
||||
pub envs: BTreeMap<String, String>,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
fn parse(parts: impl Iterator<Item = String>) -> Result<Process, String> {
|
||||
let mut cmd = None;
|
||||
let mut args = vec![];
|
||||
let mut envs = vec![];
|
||||
let mut envs = BTreeMap::new();
|
||||
|
||||
for arg in parts {
|
||||
if cmd.is_none() {
|
||||
@@ -117,7 +147,7 @@ impl Process {
|
||||
subst_env(value)
|
||||
};
|
||||
if !value.is_empty() {
|
||||
envs.push((env.to_owned(), value));
|
||||
envs.insert(env.to_owned(), value);
|
||||
}
|
||||
} else {
|
||||
cmd = Some(arg);
|
||||
@@ -133,11 +163,4 @@ impl Process {
|
||||
Err("no command given".to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_command(self, base_envs: &BTreeMap<String, OsString>) -> process::Command {
|
||||
let mut command = process::Command::new(self.cmd);
|
||||
command.args(self.args);
|
||||
command.env_clear().envs(base_envs).envs(self.envs);
|
||||
command
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Service {
|
||||
pub cmd: String,
|
||||
pub args: Vec<String>,
|
||||
pub envs: BTreeMap<String, String>,
|
||||
pub type_: ServiceType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum ServiceType {
|
||||
#[default]
|
||||
Notify,
|
||||
Scheme(String),
|
||||
Oneshot,
|
||||
OneshotAsync,
|
||||
}
|
||||
|
||||
impl Service {
|
||||
pub fn spawn(self, base_envs: &BTreeMap<String, OsString>) {
|
||||
let mut command = Command::new(self.cmd);
|
||||
command.args(self.args);
|
||||
command.env_clear().envs(base_envs).envs(self.envs);
|
||||
|
||||
match self.type_ {
|
||||
ServiceType::Notify => {
|
||||
daemon::Daemon::spawn(command);
|
||||
}
|
||||
ServiceType::Scheme(scheme) => {
|
||||
daemon::SchemeDaemon::spawn(command, &scheme);
|
||||
}
|
||||
ServiceType::Oneshot => {
|
||||
let mut child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to execute {:?}: {}", command, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match child.wait() {
|
||||
Ok(exit_status) => {
|
||||
if !exit_status.success() {
|
||||
eprintln!("{command:?} failed with {exit_status}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to wait for {:?}: {}", command, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
ServiceType::OneshotAsync => match command.spawn() {
|
||||
Ok(_child) => {}
|
||||
Err(err) => eprintln!("init: failed to execute '{:?}': {}", command, err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ impl SchemeSync for ZeroScheme {
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
|
||||
Reference in New Issue
Block a user