feat(cli): add recursive migra config search

... in parent directories
This commit is contained in:
Dmitriy Pleshevskiy 2021-02-01 23:51:23 +03:00
parent cc6899d416
commit 942edd0f8b
3 changed files with 39 additions and 17 deletions

View File

@ -1,38 +1,60 @@
use migra_core::path::PathBuilder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fs; use std::fs;
use std::path::Path; use std::io;
use std::path::{Path, PathBuf};
const MIGRA_TOML_FILENAME: &str = "Migra.toml"; const MIGRA_TOML_FILENAME: &str = "Migra.toml";
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub(crate) struct Config { pub(crate) struct Config {
pub directory: String, #[serde(skip)]
pub root: PathBuf,
pub directory: PathBuf,
pub database: DatabaseConfig, pub database: DatabaseConfig,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub(crate) struct DatabaseConfig { pub(crate) struct DatabaseConfig {
pub connection: String pub connection: String,
} }
impl Default for Config { impl Default for Config {
fn default() -> Config { fn default() -> Config {
Config { Config {
directory: String::from("database"), root: PathBuf::new(),
directory: PathBuf::from("database"),
database: DatabaseConfig { database: DatabaseConfig {
connection: String::new(), connection: String::new(),
} },
} }
} }
} }
impl Config { impl Config {
pub fn read() -> Config { pub fn read() -> io::Result<Config> {
fs::read_to_string(MIGRA_TOML_FILENAME) let current_dir = std::env::current_dir()?;
.ok()
.and_then(|content| toml::from_str(&content).ok()) let mut read_dir = Some(current_dir.as_path());
.unwrap_or_default()
loop {
if let Some(dir) = read_dir {
let migra_file_path = PathBuilder::from(dir).append(MIGRA_TOML_FILENAME).build();
if !migra_file_path.exists() {
read_dir = dir.parent();
continue;
}
let content = fs::read_to_string(migra_file_path)?;
let mut config: Config = toml::from_str(&content).expect("Cannot parse Migra.toml");
config.root = PathBuf::from(dir);
return Ok(config);
} else {
return Err(io::Error::from(io::ErrorKind::NotFound));
}
}
} }
pub fn initialize() -> Result<(), Box<dyn std::error::Error>> { pub fn initialize() -> Result<(), Box<dyn std::error::Error>> {

View File

@ -4,7 +4,7 @@ mod config;
mod opts; mod opts;
use config::Config; use config::Config;
use opts::{StructOpt, AppOpt, ApplyOpt}; use opts::{AppOpt, ApplyOpt, StructOpt};
use std::fs; use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
@ -13,13 +13,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
match opt { match opt {
AppOpt::Init => { AppOpt::Init => {
Config::initialize()?; Config::initialize()?;
}, }
AppOpt::Apply(ApplyOpt { file_name }) => { AppOpt::Apply(ApplyOpt { file_name }) => {
let config = Config::read(); let config = Config::read()?;
let mut client = migra_core::database::connect(&config.database.connection)?; let mut client = migra_core::database::connect(&config.database.connection)?;
let file_path = migra_core::path::PathBuilder::new(config.directory) let file_path = migra_core::path::PathBuilder::from(config.root)
.append(config.directory)
.append(file_name) .append(file_name)
.default_extension("sql") .default_extension("sql")
.build(); .build();

View File

@ -6,9 +6,8 @@ pub(crate) enum AppOpt {
Apply(ApplyOpt), Apply(ApplyOpt),
} }
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
pub(crate) struct ApplyOpt { pub(crate) struct ApplyOpt {
#[structopt(parse(from_str))] #[structopt(parse(from_str))]
pub file_name: String pub file_name: String,
} }