terragrate 0.4.0

Simplifies migrating terraform state based on migration files
Documentation
#[macro_use]
extern crate clap;

use anyhow::Result;

use terragrate::command::Commands;
use terragrate::config;
use terragrate::migration::Migration;
use terragrate::state::State;

fn read_state(file: &str) -> Result<State> {
    match file {
        "-" => State::from_stdin(),
        _ => State::from_file(file),
    }
}

fn print_state(state: &State) {
    for line in state.elements.iter() {
        println!("{}", line)
    }
}

fn print_diff(state: &State, result: &State) {
    let diff = state.diff(&result);
    for line in diff.iter() {
        println!("{}", line);
    }
}

fn print_commands(result: &Commands) {
    for line in result.elements.iter() {
        println!("{}", line);
    }
}

fn main() -> Result<()> {
    let cfg = config::config();
    let matches = clap_app!(terragrate =>
                            (version: &*cfg.package.version)
                            (author: &*cfg.package.authors.join(","))
                            (about: &*cfg.package.description)
                            (@setting ArgRequiredElseHelp)
                            (@setting ColoredHelp)
                            (@arg STATE: -s --state <STATE_FILE> +takes_value "State file to migrate")
                            (@arg MIGRATION: -m --migration <MIGRATION_FILE> +takes_value "Migration file to use for the migration")
                            (@subcommand initial_state =>
                             (about: "Prints the initial state")
                            )
                            (@subcommand end_state =>
                             (about: "Prints the end state after the migration")
                            )
                            (@subcommand diff =>
                             (about: "Show the difference between the existing state and the end state")
                            )
                            (@subcommand tf =>
                             (about: "Prints the terraform commands to execute the given migration")
                            )
                            (after_help: "When STATE_FILE is '-', read standard input.")
    )
    .get_matches();

    let state = read_state(matches.value_of("STATE").expect("unreachable"))?;
    let migration = Migration::from_file(matches.value_of("MIGRATION").expect("unreachable"))?;
    let (result, commands) = migration.apply(&state);

    if matches.subcommand_matches("initial_state").is_some() {
        print_state(&state);
    }

    if matches.subcommand_matches("end_state").is_some() {
        print_state(&result);
    }

    if matches.subcommand_matches("diff").is_some() {
        print_diff(&state, &result);
    }

    if matches.subcommand_matches("tf").is_some() {
        print_commands(&commands);
    }

    Ok(())
}