Skip to content

Commit

Permalink
Add flag --make-parents (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
veehaitch authored Sep 22, 2024
1 parent bafab8f commit 8e54063
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 12 deletions.
9 changes: 9 additions & 0 deletions .github/codecov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
github_checks:
annotations: false
coverage:
status:
project: off
patch: off
# Fix path of Nix sandbox
fixes:
- "/build/source::"
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ Options:
-i, --input <FILE> If no input file is given, read from stdin.
-o, --output <FILE> If no output file is given, write to stdout.
-p, --pattern <PATTERN> Regex pattern to replace. Must at least provide a named group 'id'. By default matches ${id}. [default: \$\{(?P<id>[^\$\{\}/]+)\}]
-c, --copy-if-no-creds Copy input to output if $CREDENTIALS_DIRECTORY is not set
-c, --copy-if-no-creds Copy input to output if $CREDENTIALS_DIRECTORY is not set.
-m, --make-parents Make parent directories of the output file as needed.
-h, --help Print help
-V, --version Print version
```
11 changes: 6 additions & 5 deletions nixos/tests/nixos-test-systemd-credsubst.nix
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ nixosTest {
};
};

specialisation."passthru".configuration = {
specialisation."passthru-parents".configuration = {
systemd.services.systemd-credsubst-test.serviceConfig = {
ExecStartPre = lib.mkForce [ "${systemd-credsubst}/bin/systemd-credsubst -c -i ${appsettings} -o appsettings.json" ];
ExecStart = lib.mkForce "${pkgsStatic.busybox}/bin/tail -f -n +1 some/dir/appsettings.json";
ExecStartPre = lib.mkForce [ "${systemd-credsubst}/bin/systemd-credsubst -c -i ${appsettings} -m -o some/dir/appsettings.json" ];
LoadCredential = lib.mkForce [ ];
};
};
Expand All @@ -64,10 +65,10 @@ nixosTest {
out = machine.succeed("cat /run/systemd-credsubst-test/workdir/appsettings.json")
assert out == '{"license":"prometheus","name":"Wurzelpfropf Banking"}', f"appsettings.json has unexpected content '{out}'"
with subtest("passthru works"):
machine.succeed("${nodes.machine.system.build.toplevel}/specialisation/passthru/bin/switch-to-configuration test")
with subtest("passthru and make parents works"):
machine.succeed("${nodes.machine.system.build.toplevel}/specialisation/passthru-parents/bin/switch-to-configuration test")
machine.wait_for_unit("systemd-credsubst-test.service");
out = machine.succeed("cat /run/systemd-credsubst-test/workdir/appsettings.json")
out = machine.succeed("cat /run/systemd-credsubst-test/workdir/some/dir/appsettings.json")
assert out == '{"license":"''${license}","name":"Wurzelpfropf Banking"}', f"appsettings.json has unexpected content '{out}'"
'';
}
27 changes: 21 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,15 @@ struct Cli {
#[arg(
short,
long,
help = "Copy input to output if $CREDENTIALS_DIRECTORY is not set"
help = "Copy input to output if $CREDENTIALS_DIRECTORY is not set."
)]
copy_if_no_creds: bool,
#[arg(
short,
long,
help = "Make parent directories of the output file as needed."
)]
make_parents: bool,
}

fn validate_path_exists(path: &str) -> Result<PathBuf, String> {
Expand Down Expand Up @@ -95,10 +101,17 @@ fn input_reader(input: Option<&PathBuf>) -> Result<Box<dyn Read>> {
Ok(reader)
}

fn output_writer(output: Option<&PathBuf>) -> Result<Box<dyn Write>> {
fn output_writer(output: Option<&PathBuf>, make_parents: bool) -> Result<Box<dyn Write>> {
let writer: Box<dyn Write> = match output {
None => Box::new(io::stdout()) as Box<dyn Write>,
Some(filename) => {
if make_parents {
let parent_dir = &filename.parent().unwrap_or(Path::new("/"));
fs::create_dir_all(parent_dir).context(format!(
"Failed to create parent directories of '{}'",
filename.display()
))?;
}
let f = File::create(filename).context(format!(
"Failed to open '{}' for writing",
filename.display()
Expand All @@ -109,9 +122,9 @@ fn output_writer(output: Option<&PathBuf>) -> Result<Box<dyn Write>> {
Ok(writer)
}

fn passthru(input: Option<&PathBuf>, output: Option<&PathBuf>) -> Result<()> {
fn passthru(input: Option<&PathBuf>, output: Option<&PathBuf>, make_parents: bool) -> Result<()> {
let mut reader = input_reader(input)?;
let mut writer = output_writer(output)?;
let mut writer = output_writer(output, make_parents)?;

io::copy(&mut reader, &mut writer)?;

Expand Down Expand Up @@ -141,6 +154,7 @@ fn substitute(
output: Option<&PathBuf>,
creds_dir: &str,
pattern: &Regex,
make_parents: bool,
) -> Result<()> {
// Read input as string
let mut reader = input_reader(input)?;
Expand Down Expand Up @@ -174,7 +188,7 @@ fn substitute(
)?;

// Write the modified contents
let mut writer = output_writer(output)?;
let mut writer = output_writer(output, make_parents)?;
writer.write_all(modified.as_bytes())?;

Ok(())
Expand All @@ -197,10 +211,11 @@ fn main() -> Result<ExitCode> {
cli.output.as_ref(),
&creds_dir?,
&cli.pattern,
cli.make_parents,
)?,
Err(err) => {
if cli.copy_if_no_creds {
passthru(cli.input.as_ref(), cli.output.as_ref())?;
passthru(cli.input.as_ref(), cli.output.as_ref(), cli.make_parents)?;
} else {
return Err(err);
}
Expand Down
58 changes: 58 additions & 0 deletions tests/credsubst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,61 @@ fn copy_if_no_creds() -> Result<()> {

Ok(())
}

#[test]
fn make_parents() -> Result<()> {
let credentials_dir = tempfile::tempdir()?;
let mut file = File::create(credentials_dir.path().join("yaxi-license"))?;
file.write_all(b"hunter1\n\n")?;

let out_dir = tempfile::tempdir()?;
let output_filename = out_dir.path().join("wur/zel/pfropf");

Command::cargo_bin(crate_name!())?
.env("CREDENTIALS_DIRECTORY", credentials_dir.path())
.arg("--output")
.arg(&output_filename)
.arg("--make-parents")
.write_stdin(indoc! {r#"
{
"wurzel": "pfropf",
"license": "${yaxi-license}",
"wuff": "c://msdog",
"password": "secret-password:${/with-special-chars}"
}
"#})
.assert();

assert_eq!(
std::fs::read_to_string(output_filename)?,
indoc! {r#"
{
"wurzel": "pfropf",
"license": "hunter1",
"wuff": "c://msdog",
"password": "secret-password:${/with-special-chars}"
}
"#}
);

Ok(())
}

#[test]
fn fails_no_make_parents() -> Result<()> {
Command::cargo_bin(crate_name!())?
.arg("--output")
.arg("/does/not/exist")
.arg("--copy-if-no-creds")
.write_stdin("wurzelpfropf")
.assert()
.stdout("")
.stderr(indoc! {r#"
Error: Failed to open '/does/not/exist' for writing
Caused by:
No such file or directory (os error 2)
"#});

Ok(())
}

0 comments on commit 8e54063

Please sign in to comment.