Skip to content

Commit cb4be8c

Browse files
author
Joe Grund
committed
Truncate recordings when running in test + record mode
Signed-off-by: Joe Grund <[email protected]>
1 parent 790b5d0 commit cb4be8c

File tree

3 files changed

+57
-39
lines changed

3 files changed

+57
-39
lines changed

commandeer-cli/src/main.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::path::PathBuf;
55

66
#[derive(Parser)]
77
#[command(name = "commandeer")]
8-
#[command(about = "A CLI test binary substitute with record and replay modes")]
8+
/// A CLI test binary substitute with record and replay modes
99
struct Cli {
1010
#[command(subcommand)]
1111
command: Commands,
@@ -14,14 +14,19 @@ struct Cli {
1414
#[derive(Subcommand)]
1515
enum Commands {
1616
Record {
17+
/// Path to save recordings.
1718
#[arg(long, default_value = "recordings.json")]
1819
file: PathBuf,
20+
/// Whether to truncate the file before recording.
21+
#[arg(long)]
22+
truncate: bool,
1923
#[arg(long)]
2024
command: String,
2125
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
2226
args: Vec<String>,
2327
},
2428
Replay {
29+
/// Path to the recordings.
2530
#[arg(long, default_value = "recordings.json")]
2631
file: PathBuf,
2732
#[arg(long)]
@@ -31,8 +36,13 @@ enum Commands {
3136
},
3237
}
3338

34-
async fn record_mode(file_path: PathBuf, command: String, args: Vec<String>) -> Result<()> {
35-
let invocation = record_command(file_path, command, args).await?;
39+
async fn record_mode(
40+
truncate: bool,
41+
file_path: PathBuf,
42+
command: String,
43+
args: Vec<String>,
44+
) -> Result<()> {
45+
let invocation = record_command(truncate, file_path, command, args).await?;
3646

3747
output_invocation(&invocation);
3848

@@ -66,8 +76,9 @@ async fn main() -> Result<()> {
6676
file,
6777
command,
6878
args,
79+
truncate,
6980
} => {
70-
record_mode(file, command, args).await?;
81+
record_mode(truncate, file, command, args).await?;
7182
}
7283
Commands::Replay {
7384
file,

commandeer-test/src/lib.rs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ use serde::{Deserialize, Serialize};
44
use std::{
55
collections::HashMap,
66
env, fmt,
7-
fs::{self, DirBuilder},
7+
fs::{self},
88
path::{Path, PathBuf},
99
};
1010
use tempfile::TempDir;
11-
use tokio::process::Command;
11+
use tokio::{
12+
fs::{DirBuilder, try_exists},
13+
io::AsyncReadExt as _,
14+
process::Command,
15+
};
1216

1317
pub use commandeer_macros::commandeer;
1418

@@ -49,19 +53,17 @@ impl RecordedCommands {
4953
}
5054

5155
pub async fn load_recordings(file_path: &PathBuf) -> Result<RecordedCommands> {
52-
if !file_path.exists() {
53-
tokio::fs::create_dir_all(
54-
file_path.parent().ok_or_else(|| {
55-
anyhow!("Couldn't get parent of recording {}", file_path.display())
56-
})?,
57-
)
56+
let mut f = tokio::fs::File::options();
57+
58+
let mut contents = String::new();
59+
f.create(true)
60+
.write(true)
61+
.read(true)
62+
.open(file_path)
63+
.await?
64+
.read_to_string(&mut contents)
5865
.await?;
5966

60-
return Ok(RecordedCommands::default());
61-
}
62-
63-
let contents = tokio::fs::read_to_string(file_path).await?;
64-
6567
if contents.trim().is_empty() {
6668
return Ok(RecordedCommands::default());
6769
}
@@ -80,11 +82,29 @@ pub async fn save_recordings(file_path: &PathBuf, recordings: &RecordedCommands)
8082
}
8183

8284
pub async fn record_command(
85+
truncate: bool,
8386
file_path: PathBuf,
8487
command: String,
8588
args: Vec<String>,
8689
) -> Result<CommandInvocation> {
87-
let mut recordings = load_recordings(&file_path).await?;
90+
let recording_dir = file_path
91+
.parent()
92+
.ok_or_else(|| anyhow!("Couldn't get parent of recording {}", file_path.display()))?;
93+
94+
DirBuilder::new()
95+
.recursive(true)
96+
.create(recording_dir)
97+
.await?;
98+
99+
let mut recordings = if truncate {
100+
if try_exists(&file_path).await? {
101+
tokio::fs::remove_file(&file_path).await?;
102+
}
103+
104+
RecordedCommands::default()
105+
} else {
106+
load_recordings(&file_path).await?
107+
};
88108

89109
let output = Command::new(&command).args(&args).output().await?;
90110

@@ -121,7 +141,7 @@ pub fn exit_with_code(code: i32) -> ! {
121141
std::process::exit(code);
122142
}
123143

124-
#[derive(Debug, Clone, Copy)]
144+
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
125145
pub enum Mode {
126146
Record,
127147
Replay,
@@ -150,7 +170,7 @@ impl Commandeer {
150170
std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get crate directory."),
151171
);
152172

153-
DirBuilder::new()
173+
std::fs::DirBuilder::new()
154174
.recursive(true)
155175
.create(&dir)
156176
.expect("Failed to create testcmds dir");
@@ -186,11 +206,16 @@ impl Commandeer {
186206

187207
let wrapper = format!(
188208
r#"#!/usr/bin/env bash
189-
exec env PATH="{}" {} {} --file {} --command {command_name} "$@"
209+
exec env PATH="{}" {} {}{}--file {} --command {command_name} "$@"
190210
"#,
191211
self.original_path,
192212
self.mock_runner.path().display(),
193213
self.mode,
214+
if self.mode == Mode::Record {
215+
" --truncate "
216+
} else {
217+
" "
218+
},
194219
self.fixture.display(),
195220
);
196221

commandeer-test/testcmds/cmds_test_flag_args.json

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,6 @@
11
{
22
"commands": {
33
"git:--version": [
4-
{
5-
"binary_name": "git",
6-
"args": [
7-
"--version"
8-
],
9-
"stdout": "git version 2.51.0\n",
10-
"stderr": "",
11-
"exit_code": 0
12-
},
13-
{
14-
"binary_name": "git",
15-
"args": [
16-
"--version"
17-
],
18-
"stdout": "git version 2.51.0\n",
19-
"stderr": "",
20-
"exit_code": 0
21-
},
224
{
235
"binary_name": "git",
246
"args": [

0 commit comments

Comments
 (0)