extern crate postgres;
extern crate postgres_array;
extern crate git2;
extern crate iron;
extern crate router;
extern crate logger;
extern crate env_logger;
extern crate rand;
extern crate sha1;
extern crate flate2;
extern crate toml;
extern crate simple_error;
#[macro_use]
extern crate clap;
#[macro_use]
extern crate lazy_static;
mod core;
mod server;
mod client;
mod updater;
use std::process::exit;
use std::sync::{Mutex};
use core::GitSqlConfig;
use client::GitSqlClient;
use server::GitSqlServer;
use updater::RepositoryUpdater;
use git2::Repository;
use clap::App;
use iron::prelude::*;
use logger::Logger;
lazy_static! {
static ref DB_CONFIG: Mutex<GitSqlConfig> = {
Mutex::new(GitSqlConfig::empty())
};
}
pub fn load_client_by_repo_name(_repo: String) -> Option<GitSqlClient> {
let config = DB_CONFIG.lock().unwrap().clone();
config.get_repo_db_url(&_repo).map(|x| GitSqlClient::new(x).unwrap())
}
fn set_db_config(cfg: &GitSqlConfig) {
let mut global = DB_CONFIG.lock().unwrap();
*global = cfg.clone();
}
fn main() {
env_logger::init().expect("Failed to configure logger.");
let yaml = load_yaml!("cli.yaml");
let args = App::from_yaml(yaml).get_matches();
let conf : GitSqlConfig;
let mut repo_name : String = "".into();
let mut maybe_client : Option<GitSqlClient> = None;
if let Some(cfg_path) = args.value_of("config") {
conf = GitSqlConfig::load(cfg_path).unwrap();
} else {
println!("[ERROR] Please specify a Git SQL configuration file (-c mycfg.toml)");
exit(1);
}
set_db_config(&conf);
if let Some(the_repo_name) = args.value_of("repository") {
maybe_client = load_client_by_repo_name(the_repo_name.into());
repo_name = the_repo_name.into();
if maybe_client.is_none() {
println!("[ERROR] Repository '{}' is not configured.", repo_name);
exit(1);
}
}
if let Some(_) = args.subcommand_matches("list-refs") {
if maybe_client.is_none() {
println!("[ERROR] Please specify a repository to operate on (-r myrepo)");
exit(1);
}
let client = maybe_client.unwrap();
for (name, target) in client.list_refs().unwrap() {
println!("{} = {}", name, target);
}
} else if let Some(_) = args.subcommand_matches("update") {
if maybe_client.is_none() {
println!("[ERROR] Please specify a repository to operate on (-r myrepo)");
exit(1);
}
let client = maybe_client.unwrap();
let maybe_repo_path = conf.get_repo_cfg_str(&repo_name, "local-path");
if maybe_repo_path.is_none() {
println!("[ERROR] Please configure the local-path for the repository.");
exit(1);
}
let repo = Repository::open(maybe_repo_path.unwrap()).unwrap();
let mut updater = RepositoryUpdater::new(&client).unwrap();
updater.process_objects(&repo).expect("Failed to load object list.");
updater.update_objects(&repo).expect("Failed to update objects.");
updater.update_refs(&repo).expect("Failed to update references");
} else if let Some(cmd) = args.subcommand_matches("init") {
if maybe_client.is_none() {
println!("[ERROR] Please specify a repository to operate on (-r myrepo)");
exit(1);
}
let client = maybe_client.unwrap();
let sql_file_content = String::from(include_str!(concat!(env!("OUT_DIR"), "/git.rs.sql")));
let mut used_file_content = String::new();
if cmd.is_present("no-python") {
let mut inside_python_section = false;
for line in sql_file_content.lines() {
if line.contains("<PYTHON ONLY>") {
inside_python_section = true;
} else if line.contains("</PYTHON ONLY>") {
inside_python_section = false;
continue;
}
if !inside_python_section {
used_file_content.push_str(line);
used_file_content.push('\n');
}
}
} else {
used_file_content.push_str(sql_file_content.as_str());
}
client.run_sql(&used_file_content).unwrap();
println!("Completed.");
} else if let Some(_) = args.subcommand_matches("serve") {
let maybe_server_cfg = conf.get_server_cfg();
if maybe_server_cfg.is_none() {
println!("[ERROR] Missing 'server' configuration section.");
exit(1);
}
let server_cfg = maybe_server_cfg.unwrap();
let bind_spec = &server_cfg["bind"];
if !bind_spec.is_str() {
println!("[ERROR] Missing 'bind' option in 'server' configuration section.");
exit(1);
}
let server = GitSqlServer::new(load_client_by_repo_name);
let router = server.router();
let mut chain = Chain::new(router);
chain.link_before(server);
let (logger_before, logger_after) = Logger::new(None);
chain.link_before(logger_before);
chain.link_after(logger_after);
println!("Serving Git SQL on {}", bind_spec.as_str().unwrap());
Iron::new(chain).http(bind_spec.as_str().unwrap()).unwrap();
} else {
println!("{}", args.usage());
exit(1);
}
}