summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock31
-rw-r--r--Cargo.toml2
-rw-r--r--src/env.rs78
-rw-r--r--src/pipeline/mod.rs17
-rw-r--r--src/state/history/mod.rs15
5 files changed, 114 insertions, 29 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 776304a..90cc3c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -155,6 +155,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -493,6 +502,7 @@ version = "0.1.0"
dependencies = [
"anyhow",
"async-std",
+ "bincode",
"blocking",
"futures-lite",
"futures-util",
@@ -503,6 +513,7 @@ dependencies = [
"pest",
"pest_derive",
"pty-process",
+ "serde",
"signal-hook",
"signal-hook-async-std",
"terminal_size",
@@ -652,6 +663,26 @@ dependencies = [
]
[[package]]
+name = "serde"
+version = "1.0.133"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.133"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index e5b7df8..e02cb53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,6 +8,7 @@ license = "MIT"
[dependencies]
anyhow = "1.0.52"
async-std = { version = "1.10.0", features = ["unstable"] }
+bincode = "1.3.3"
blocking = "1.1.0"
futures-lite = "1.12.0"
futures-util = "0.3.19"
@@ -18,6 +19,7 @@ once_cell = "1.9.0"
pest = "2.1.3"
pest_derive = "2.1.0"
pty-process = { version = "0.2.0", features = ["async"] }
+serde = { version = "1.0.133", features = ["derive"] }
signal-hook = "0.3.13"
signal-hook-async-std = "0.2.1"
terminal_size = "0.1.17"
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();