summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/env.rs78
-rw-r--r--src/pipeline/mod.rs17
-rw-r--r--src/state/history/mod.rs15
3 files changed, 81 insertions, 29 deletions
diff --git a/src/env.rs b/src/env.rs
index 31671a3..f78b790 100644
--- a/src/env.rs
+++ b/src/env.rs
@@ -1,23 +1,85 @@
+use serde::Deserialize as _;
use std::os::unix::process::ExitStatusExt as _;
-pub struct Env {
+#[derive(serde::Serialize, serde::Deserialize)]
+pub enum Env {
+ V0(V0),
+}
+
+#[derive(serde::Serialize, serde::Deserialize)]
+pub struct V0 {
+ pipeline: Option<String>,
+ #[serde(
+ serialize_with = "serialize_status",
+ deserialize_with = "deserialize_status"
+ )]
latest_status: async_std::process::ExitStatus,
}
impl Env {
- pub fn new(code: i32) -> Self {
- Self {
- latest_status: async_std::process::ExitStatus::from_raw(
- code << 8,
- ),
+ pub fn new() -> Self {
+ Self::V0(V0 {
+ pipeline: None,
+ latest_status: std::process::ExitStatus::from_raw(0),
+ })
+ }
+
+ pub fn set_pipeline(&mut self, pipeline: String) {
+ match self {
+ Self::V0(env) => {
+ env.pipeline = Some(pipeline);
+ }
}
}
pub fn set_status(&mut self, status: async_std::process::ExitStatus) {
- self.latest_status = status;
+ match self {
+ Self::V0(env) => {
+ env.latest_status = status;
+ }
+ }
+ }
+
+ pub fn pipeline(&self) -> Option<&str> {
+ match self {
+ Self::V0(env) => env.pipeline.as_deref(),
+ }
}
pub fn latest_status(&self) -> &async_std::process::ExitStatus {
- &self.latest_status
+ match self {
+ Self::V0(env) => &env.latest_status,
+ }
}
+
+ pub fn as_bytes(&self) -> Vec<u8> {
+ bincode::serialize(self).unwrap()
+ }
+
+ pub fn from_bytes(bytes: &[u8]) -> Self {
+ bincode::deserialize(bytes).unwrap()
+ }
+}
+
+#[allow(clippy::trivially_copy_pass_by_ref)]
+fn serialize_status<S>(
+ status: &std::process::ExitStatus,
+ s: S,
+) -> Result<S::Ok, S::Error>
+where
+ S: serde::Serializer,
+{
+ let code: u16 = status.code().unwrap_or(0).try_into().unwrap();
+ let signal: u16 = status.signal().unwrap_or(0).try_into().unwrap();
+ s.serialize_u16((code << 8) | signal)
+}
+
+fn deserialize_status<'de, D>(
+ d: D,
+) -> Result<std::process::ExitStatus, D::Error>
+where
+ D: serde::Deserializer<'de>,
+{
+ let status = u16::deserialize(d)?;
+ Ok(std::process::ExitStatus::from_raw(i32::from(status)))
}
diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs
index 8fa0041..89381c6 100644
--- a/src/pipeline/mod.rs
+++ b/src/pipeline/mod.rs
@@ -10,8 +10,8 @@ mod command;
pub use command::{Child, Command};
pub async fn run() -> anyhow::Result<i32> {
- let (code, pipeline) = read_data().await?;
- let env = crate::env::Env::new(code);
+ let env = read_data().await?;
+ let pipeline = crate::parse::Pipeline::parse(env.pipeline().unwrap())?;
let (children, pg) = spawn_children(pipeline, &env)?;
let status = wait_children(children, pg).await;
if let Some(signal) = status.signal() {
@@ -20,18 +20,15 @@ pub async fn run() -> anyhow::Result<i32> {
Ok(status.code().unwrap())
}
-async fn read_data() -> anyhow::Result<(i32, crate::parse::Pipeline)> {
+async fn read_data() -> anyhow::Result<crate::env::Env> {
// Safety: this code is only called by crate::history::run_pipeline, which
// passes data through on fd 3, and which will not spawn this process
// unless the pipe was successfully opened on that fd
let mut fd3 = unsafe { async_std::fs::File::from_raw_fd(3) };
- let mut be_bytes = [0; 4];
- fd3.read_exact(&mut be_bytes).await?;
- let code = i32::from_be_bytes(be_bytes);
- let mut pipeline = String::new();
- fd3.read_to_string(&mut pipeline).await?;
- let ast = crate::parse::Pipeline::parse(&pipeline)?;
- Ok((code, ast))
+ let mut data = vec![];
+ fd3.read_to_end(&mut data).await?;
+ let env = crate::env::Env::from_bytes(&data);
+ Ok(env)
}
fn spawn_children(
diff --git a/src/state/history/mod.rs b/src/state/history/mod.rs
index 3573a1c..430eb28 100644
--- a/src/state/history/mod.rs
+++ b/src/state/history/mod.rs
@@ -104,7 +104,7 @@ impl History {
run_commands(
ast,
async_std::sync::Arc::clone(&entry),
- crate::env::Env::new(0),
+ crate::env::Env::new(),
input_r,
resize_r,
event_w,
@@ -541,8 +541,8 @@ fn run_commands(
};
for pipeline in ast.pipelines() {
- let (pipeline_status, done) =
- run_pipeline(pipeline, &pty, &env).await;
+ env.set_pipeline(pipeline.input_string().to_string());
+ let (pipeline_status, done) = run_pipeline(&pty, &env).await;
env.set_status(pipeline_status);
if done {
break;
@@ -556,7 +556,6 @@ fn run_commands(
}
async fn run_pipeline(
- pipeline: &crate::parse::Pipeline,
pty: &pty::Pty,
env: &crate::env::Env,
) -> (async_std::process::ExitStatus, bool) {
@@ -573,13 +572,7 @@ async fn run_pipeline(
nix::unistd::close(r).unwrap();
let mut w = unsafe { async_std::fs::File::from_raw_fd(w) };
- // TODO: actual serialization
- w.write_all(&env.latest_status().code().unwrap_or(1).to_be_bytes())
- .await
- .unwrap();
- w.write_all(pipeline.input_string().as_bytes())
- .await
- .unwrap();
+ w.write_all(&env.as_bytes()).await.unwrap();
drop(w);
let status = child.status_no_drop().await.unwrap();