use std::{
fs,
path::{Path, PathBuf},
};
use anyhow::{anyhow, Context, Error, Result};
use clap::ValueEnum;
use indexmap::IndexSet;
use path_absolutize::Absolutize;
use crate::{compose, config::Config};
#[derive(clap::Args, Debug)]
#[command(alias = "config", next_display_order = None)]
pub(crate) struct Args {
#[arg(long, value_enum, default_value_t = Format::Yaml)]
format: Format,
#[arg(short, long)]
quiet: bool,
#[arg(long)]
no_interpolate: bool,
#[arg(long)]
services: bool,
#[arg(long)]
volumes: bool,
#[arg(long)]
profiles: bool,
#[arg(long)]
images: bool,
#[arg(short, long)]
output: Option<PathBuf>,
}
#[derive(ValueEnum, Clone, Debug)]
enum Format {
Yaml,
Json,
}
pub(crate) fn run(args: Args, config: &Config) -> Result<()> {
let file = compose::parse(config, args.no_interpolate)?;
if !args.quiet {
if args.services {
for service in file.services.into_keys() {
println!("{service}");
}
} else if args.volumes {
for volume in file.volumes.into_keys() {
println!("{volume}");
}
} else if args.profiles {
for profile in file
.services
.into_values()
.flat_map(|service| service.profiles)
.collect::<IndexSet<_>>()
{
println!("{profile}");
}
} else if args.images {
for image in file
.services
.into_values()
.filter_map(|service| service.image)
{
println!("{image}");
}
} else {
let mut contents;
match args.format {
Format::Yaml => {
contents = serde_yaml::to_string(&file)?;
}
Format::Json => {
contents = serde_json::to_string_pretty(&file)?;
contents.push('\n');
}
}
if let Some(path) = args.output {
fs::write(&path, contents).with_context(|| match path.absolutize() {
Ok(path) => anyhow!(
"{} not found",
path.parent().unwrap_or_else(|| Path::new("/")).display()
),
Err(err) => Error::from(err),
})?;
} else {
print!("{contents}");
}
}
}
Ok(())
}