fanta-cli 0.1.0

A cli for Fanta, the rust web framework.
use std::process::Command;
use std::fs::{create_dir, File};
use std::io::prelude::*;
use chrono::Utc;
use utils::*;

use context_template;
use controller_template;
use main_template;
use mod_template;
use model_template;
use service_template;
use util_template;

static TIMESTAMP_FORMAT: &str = "%Y-%m-%d-%H%M%S";

pub fn migrate() {
  Command::new("diesel")
    .arg("migration")
    .arg("run")
    .output()
    .expect("failed to run migrations");

  Command::new("sh")
    .arg("-c")
    .arg("diesel print-schema > src/schema.rs")
    .output()
    .expect("failed to create schema");
}

pub fn create_component(name: &str) {
  create_dir(format!("src/{}s", &name.to_snek_case()))
    .expect("failed to create component directory");

  Command::new("mkdir")
    .arg("-p")
    .arg("src/models")
    .output()
    .expect("failed to create models directory");

  Command::new("sh")
    .arg("-c")
    .arg(format!("echo 'pub mod {}s;\n' >> src/models/mod.rs", name.to_snek_case()))
    .output()
    .expect("failed to create models directory");

  let mut controller_file = File::create(format!("src/{}s/{}_controller.rs", &name.to_snek_case(), &name.to_snek_case()))
    .expect("Could not create controller");
  controller_file.write_all(controller_template::create(name, "Ctx").as_bytes())
    .expect("Could not write controller to file");

  let mut service_file = File::create(format!("src/{}s/{}_service.rs", &name.to_snek_case(), &name.to_snek_case()))
    .expect("Could not create service");
  service_file.write_all(service_template::create(name).as_bytes())
    .expect("Could not write service to file");

  let mut mod_file = File::create(format!("src/{}s/mod.rs", &name.to_snek_case()))
    .expect("Could not create mod file");
  mod_file.write_all(mod_template::create(name, "Ctx").as_bytes())
    .expect("Could not write mod to file");

  let mut model_file = File::create(format!("src/models/{}s.rs", name.to_snek_case()))
    .expect("Could not create model file");
  model_file.write_all(model_template::create(name).as_bytes())
    .expect("Could not write model file");

  let migration_folder = format!("migrations/{}_create_{}", Utc::now().format(TIMESTAMP_FORMAT), name.to_snek_case());
  create_dir(&migration_folder)
    .expect("failed to create migration folder");

  let mut up_file = File::create(format!("{}/up.sql", migration_folder))
    .expect("Could not create up migration file");
  up_file.write_all(format!("CREATE TABLE {}s (
  id SERIAL PRIMARY KEY,
  some_field TEXT
);
", name.to_snek_case()).as_bytes())
    .expect("Could not create up migration file");

  let mut down_file = File::create(format!("{}/down.sql", migration_folder))
    .expect("Could not create up migration file");
  down_file.write_all(format!("DROP TABLE {}s
", name.to_snek_case()).as_bytes())
    .expect("Could not create up migration file");

  let message = templatify! { "Almost there! Your new component isn't linked up to a route, so just add something like the following to your App:

mod "; &name.to_snek_case() ;"s;

...

use "; &name.to_snek_case() ;"s::{init as "; &name.to_snek_case() ;"_routes};

...

lazy_static! {
  static ref APP: App<Ctx> = {
    let mut _app = App::<Ctx>::create(generate_context);

    ....

    _app.use_sub_app(\"/"; &name.to_snek_case() ;"s\", &"; &name.to_snek_case() ;"_routes());
  }
}
" };

  println!("{}", message);
}

pub fn init(name: &str) {
  Command::new("mkdir")
    .arg(name)
    .output()
    .expect("failed to create project directory");

  Command::new("cargo")
    .arg("init")
    .arg("--bin")
    .current_dir(name)
    .output()
    .expect("failed to initialize rust");


  let dependencies = "'diesel = { version = \"1.0.0-rc1\", features = [\"postgres\", \"uuid\"] }
dotenv = \"0.9.0\"
fanta = \"0.1.5\"
lazy_static = \"0.2\"
serde = \"1.0.24\"
serde_json = \"1.0.8\"
serde_derive = \"1.0.24\"
time = \"0.1.38\"
tokio-proto = \"0.1\"
tokio-service = \"0.1\"
env_logger = { version = \"0.3.4\", default-features = false }
'";

  Command::new("sh")
    .arg("-c")
    .arg(format!("echo {} >> Cargo.toml", dependencies))
    .current_dir(name)
    .output()
    .expect("failed to add dependencies");

  let database_file = format!("DATABASE_URL=postgres://postgres@localhost/{}", name);
  Command::new("sh")
    .arg("-c")
    .arg(format!("echo {} > .env", database_file))
    .current_dir(name)
    .output()
    .expect("failed to create databse file");

  Command::new("diesel")
    .arg("setup")
    .current_dir(name)
    .output()
    .expect("failed to setup diesel");

  let mut main_file = File::create(format!("{}/src/main.rs", name))
    .expect("Could not create main file");
  main_file.write_all(main_template::create().as_bytes())
    .expect("Could not write main file");

  Command::new("mkdir")
    .arg(format!("{}/src/models", name))
    .output()
    .expect("failed to create models directory");

  let mut models_mod_file = File::create(format!("{}/src/models/mod.rs", name))
    .expect("Could not create models/mod file");
  models_mod_file.write_all("// Models
".as_bytes())
    .expect("Could not write models/mod file");

  let mut context_file = File::create(format!("{}/src/context.rs", name))
    .expect("Could not create context file");
  context_file.write_all(context_template::create().as_bytes())
    .expect("Could not write context file");

  let mut context_file = File::create(format!("{}/src/util.rs", name))
    .expect("Could not create util file");
  context_file.write_all(util_template::create().as_bytes())
    .expect("Could not write util file");
}