mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 11:48:13 +01:00
Include env in written header
This commit is contained in:
@@ -72,10 +72,7 @@ Map of captured environment variables. Object (String -> String).
|
|||||||
Example env:
|
Example env:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"env": {
|
"env": { "SHELL": "/bin/bash", "TERM": "xterm-256color" }
|
||||||
"SHELL": "/bin/bash",
|
|
||||||
"TERM": "xterm-256color"
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> Official asciinema recorder captures only `SHELL` and `TERM` by default. All
|
> Official asciinema recorder captures only `SHELL` and `TERM` by default. All
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pub mod asciicast;
|
pub mod asciicast;
|
||||||
pub mod raw;
|
pub mod raw;
|
||||||
use std::io;
|
use std::{collections::HashMap, io};
|
||||||
|
|
||||||
pub trait Writer {
|
pub trait Writer {
|
||||||
fn header(&mut self, header: &Header) -> io::Result<()>;
|
fn header(&mut self, header: &Header) -> io::Result<()>;
|
||||||
@@ -15,4 +15,5 @@ pub struct Header {
|
|||||||
pub idle_time_limit: Option<f32>,
|
pub idle_time_limit: Option<f32>,
|
||||||
pub command: Option<String>,
|
pub command: Option<String>,
|
||||||
pub title: Option<String>,
|
pub title: Option<String>,
|
||||||
|
pub env: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
@@ -19,6 +20,7 @@ pub struct Header {
|
|||||||
idle_time_limit: Option<f32>,
|
idle_time_limit: Option<f32>,
|
||||||
command: Option<String>,
|
command: Option<String>,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
|
env: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
@@ -180,6 +182,10 @@ impl serde::Serialize for Header {
|
|||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.env.is_empty() {
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
let mut map = serializer.serialize_map(Some(len))?;
|
let mut map = serializer.serialize_map(Some(len))?;
|
||||||
map.serialize_entry("version", &2)?;
|
map.serialize_entry("version", &2)?;
|
||||||
map.serialize_entry("width", &self.width)?;
|
map.serialize_entry("width", &self.width)?;
|
||||||
@@ -198,6 +204,10 @@ impl serde::Serialize for Header {
|
|||||||
map.serialize_entry("title", &title)?;
|
map.serialize_entry("title", &title)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.env.is_empty() {
|
||||||
|
map.serialize_entry("env", &self.env)?;
|
||||||
|
}
|
||||||
|
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,6 +235,7 @@ impl From<&Header> for super::Header {
|
|||||||
idle_time_limit: header.idle_time_limit,
|
idle_time_limit: header.idle_time_limit,
|
||||||
command: header.command.clone(),
|
command: header.command.clone(),
|
||||||
title: header.title.clone(),
|
title: header.title.clone(),
|
||||||
|
env: header.env.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,6 +249,7 @@ impl From<&super::Header> for Header {
|
|||||||
idle_time_limit: header.idle_time_limit,
|
idle_time_limit: header.idle_time_limit,
|
||||||
command: header.command.clone(),
|
command: header.command.clone(),
|
||||||
title: header.title.clone(),
|
title: header.title.clone(),
|
||||||
|
env: header.env.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,6 +257,7 @@ impl From<&super::Header> for Header {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Event, EventCode, Header, Writer};
|
use super::{Event, EventCode, Header, Writer};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
@@ -287,6 +300,7 @@ mod tests {
|
|||||||
idle_time_limit: None,
|
idle_time_limit: None,
|
||||||
command: None,
|
command: None,
|
||||||
title: None,
|
title: None,
|
||||||
|
env: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
fw.write_header(&header).unwrap();
|
fw.write_header(&header).unwrap();
|
||||||
@@ -310,9 +324,18 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let asciicast = String::from_utf8(data).unwrap();
|
let lines = parse(data);
|
||||||
|
|
||||||
assert_eq!(asciicast, "{\"version\":2,\"width\":80,\"height\":24,\"timestamp\":1}\n[1.0,\"o\",\"hello\\r\\n\"]\n[2.0,\"o\",\"world\"]\n");
|
assert_eq!(lines[0]["version"], 2);
|
||||||
|
assert_eq!(lines[0]["width"], 80);
|
||||||
|
assert_eq!(lines[0]["height"], 24);
|
||||||
|
assert_eq!(lines[0]["timestamp"], 1);
|
||||||
|
assert_eq!(lines[1][0], 1.0);
|
||||||
|
assert_eq!(lines[1][1], "o");
|
||||||
|
assert_eq!(lines[1][2], "hello\r\n");
|
||||||
|
assert_eq!(lines[2][0], 2.0);
|
||||||
|
assert_eq!(lines[2][1], "o");
|
||||||
|
assert_eq!(lines[2][2], "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -320,6 +343,10 @@ mod tests {
|
|||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let mut fw = Writer::new(io::Cursor::new(&mut data), 0.0);
|
let mut fw = Writer::new(io::Cursor::new(&mut data), 0.0);
|
||||||
|
|
||||||
|
let mut env = HashMap::new();
|
||||||
|
env.insert("SHELL".to_owned(), "/usr/bin/fish".to_owned());
|
||||||
|
env.insert("TERM".to_owned(), "xterm256-color".to_owned());
|
||||||
|
|
||||||
let header = Header {
|
let header = Header {
|
||||||
width: 80,
|
width: 80,
|
||||||
height: 24,
|
height: 24,
|
||||||
@@ -327,15 +354,32 @@ mod tests {
|
|||||||
idle_time_limit: Some(1.5),
|
idle_time_limit: Some(1.5),
|
||||||
command: Some("/bin/bash".to_owned()),
|
command: Some("/bin/bash".to_owned()),
|
||||||
title: Some("Demo".to_owned()),
|
title: Some("Demo".to_owned()),
|
||||||
|
env,
|
||||||
};
|
};
|
||||||
|
|
||||||
fw.write_header(&header).unwrap();
|
fw.write_header(&header).unwrap();
|
||||||
|
|
||||||
let asciicast = String::from_utf8(data).unwrap();
|
let lines = parse(data);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(lines[0]["version"], 2);
|
||||||
asciicast,
|
assert_eq!(lines[0]["width"], 80);
|
||||||
"{\"version\":2,\"width\":80,\"height\":24,\"timestamp\":1,\"idle_time_limit\":1.5,\"command\":\"/bin/bash\",\"title\":\"Demo\"}\n"
|
assert_eq!(lines[0]["height"], 24);
|
||||||
);
|
assert_eq!(lines[0]["timestamp"], 1);
|
||||||
|
assert_eq!(lines[0]["idle_time_limit"], 1.5);
|
||||||
|
assert_eq!(lines[0]["command"], "/bin/bash");
|
||||||
|
assert_eq!(lines[0]["title"], "Demo");
|
||||||
|
assert_eq!(lines[0]["env"].as_object().unwrap().len(), 2);
|
||||||
|
assert_eq!(lines[0]["env"]["SHELL"], "/usr/bin/fish");
|
||||||
|
assert_eq!(lines[0]["env"]["TERM"], "xterm256-color");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(json: Vec<u8>) -> Vec<serde_json::Value> {
|
||||||
|
String::from_utf8(json)
|
||||||
|
.unwrap()
|
||||||
|
.split('\n')
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(serde_json::from_str::<serde_json::Value>)
|
||||||
|
.collect::<serde_json::Result<Vec<_>>>()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ mod recorder;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use format::{asciicast, raw};
|
use format::{asciicast, raw};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path;
|
use std::path;
|
||||||
@@ -149,6 +150,12 @@ fn main() -> Result<()> {
|
|||||||
Box::new(writer)
|
Box::new(writer)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let env_allow_list = env.split(',').collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
let env = std::env::vars()
|
||||||
|
.filter(|(k, _v)| env_allow_list.contains(&k.as_str()))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
let mut recorder = recorder::Recorder::new(
|
let mut recorder = recorder::Recorder::new(
|
||||||
writer,
|
writer,
|
||||||
append,
|
append,
|
||||||
@@ -156,6 +163,7 @@ fn main() -> Result<()> {
|
|||||||
idle_time_limit,
|
idle_time_limit,
|
||||||
command.clone(),
|
command.clone(),
|
||||||
title.clone(),
|
title.clone(),
|
||||||
|
env,
|
||||||
);
|
);
|
||||||
|
|
||||||
let command = command
|
let command = command
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::format;
|
use crate::format;
|
||||||
use crate::pty;
|
use crate::pty;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
@@ -11,6 +12,7 @@ pub struct Recorder {
|
|||||||
idle_time_limit: Option<f32>,
|
idle_time_limit: Option<f32>,
|
||||||
command: Option<String>,
|
command: Option<String>,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
|
env: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Recorder {
|
impl Recorder {
|
||||||
@@ -21,6 +23,7 @@ impl Recorder {
|
|||||||
idle_time_limit: Option<f32>,
|
idle_time_limit: Option<f32>,
|
||||||
command: Option<String>,
|
command: Option<String>,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
|
env: HashMap<String, String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Recorder {
|
Recorder {
|
||||||
writer,
|
writer,
|
||||||
@@ -30,6 +33,7 @@ impl Recorder {
|
|||||||
idle_time_limit,
|
idle_time_limit,
|
||||||
command,
|
command,
|
||||||
title,
|
title,
|
||||||
|
env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +59,7 @@ impl pty::Recorder for Recorder {
|
|||||||
idle_time_limit: self.idle_time_limit,
|
idle_time_limit: self.idle_time_limit,
|
||||||
command: self.command.clone(),
|
command: self.command.clone(),
|
||||||
title: self.title.clone(),
|
title: self.title.clone(),
|
||||||
|
env: self.env.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.writer.header(&header)
|
self.writer.header(&header)
|
||||||
|
|||||||
Reference in New Issue
Block a user