summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/db/interface.rs110
-rw-r--r--src/db/mod.rs2
-rw-r--r--src/main.rs3
4 files changed, 115 insertions, 1 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9b15937..1a0b7ab 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ handlebars = "3"
filters = "0.4.0"
indoc = "1"
diesel = { version = "1.4", features = ["postgres"] }
+which = "4"
url = { version = "2", features = ["serde"] }
tokio = { version = "0.2", features = ["full"] }
diff --git a/src/db/interface.rs b/src/db/interface.rs
new file mode 100644
index 0000000..65a46ad
--- /dev/null
+++ b/src/db/interface.rs
@@ -0,0 +1,110 @@
+use std::path::PathBuf;
+
+use clap_v3 as clap;
+use clap::ArgMatches;
+use anyhow::anyhow;
+use anyhow::Context;
+use anyhow::Error;
+use anyhow::Result;
+
+use crate::config::Configuration;
+use crate::db::DbConnectionConfig;
+
+pub fn interface(db_connection_config: DbConnectionConfig, matches: &ArgMatches, config: &Configuration) -> Result<()> {
+ match matches.subcommand() {
+ ("cli", Some(matches)) => cli(db_connection_config, matches, config),
+ (other, _) => return Err(anyhow!("Unknown subcommand: {}", other)),
+ }
+}
+
+fn cli(db_connection_config: DbConnectionConfig, matches: &ArgMatches, config: &Configuration) -> Result<()> {
+ use std::process::Command;
+
+ trait PgCliCommand {
+ fn run_for_uri(&self, dbcc: DbConnectionConfig) -> Result<()>;
+ }
+
+ struct Psql(PathBuf);
+ impl PgCliCommand for Psql {
+ fn run_for_uri(&self, dbcc: DbConnectionConfig) -> Result<()> {
+ Command::new(&self.0)
+ .arg(format!("--dbname={}", dbcc.database_name()))
+ .arg(format!("--host={}", dbcc.database_host()))
+ .arg(format!("--port={}", dbcc.database_port()))
+ .arg(format!("--username={}", dbcc.database_user()))
+ .stdin(std::process::Stdio::inherit())
+ .stdout(std::process::Stdio::inherit())
+ .stderr(std::process::Stdio::inherit())
+ .output()
+ .map_err(Error::from)
+ .and_then(|out| {
+ if out.status.success() {
+ info!("pgcli exited successfully");
+ Ok(())
+ } else {
+ Err(anyhow!("gpcli did not exit successfully"))
+ .with_context(|| {
+ match String::from_utf8(out.stderr) {
+ Ok(log) => anyhow!("{}", log),
+ Err(e) => anyhow!("Cannot parse log into valid UTF-8: {}", e),
+ }
+ })
+ .map_err(Error::from)
+ }
+ })
+ }
+ }
+
+ struct PgCli(PathBuf);
+ impl PgCliCommand for PgCli {
+ fn run_for_uri(&self, dbcc: DbConnectionConfig) -> Result<()> {
+ Command::new(&self.0)
+ .arg("--host")
+ .arg(dbcc.database_host())
+ .arg("--port")
+ .arg(dbcc.database_port())
+ .arg("--username")
+ .arg(dbcc.database_user())
+ .arg(dbcc.database_name())
+ .stdin(std::process::Stdio::inherit())
+ .stdout(std::process::Stdio::inherit())
+ .stderr(std::process::Stdio::inherit())
+ .output()
+ .map_err(Error::from)
+ .and_then(|out| {
+ if out.status.success() {
+ info!("pgcli exited successfully");
+ Ok(())
+ } else {
+ Err(anyhow!("gpcli did not exit successfully"))
+ .with_context(|| {
+ match String::from_utf8(out.stderr) {
+ Ok(log) => anyhow!("{}", log),
+ Err(e) => anyhow!("Cannot parse log into valid UTF-8: {}", e),
+ }
+ })
+ .map_err(Error::from)
+ }
+ })
+
+ }
+ }
+
+
+ matches.value_of("tool")
+ .map(|s| vec![s])
+ .unwrap_or_else(|| vec!["psql", "pgcli"])
+ .into_iter()
+ .filter_map(|s| which::which(&s).ok().map(|path| (path, s)))
+ .map(|(path, s)| {
+ match s {
+ "psql" => Ok(Box::new(Psql(path)) as Box<dyn PgCliCommand>),
+ "pgcli" => Ok(Box::new(PgCli(path)) as Box<dyn PgCliCommand>),
+ prog => Err(anyhow!("Unsupported pg CLI program: {}", prog)),
+ }
+ })
+ .next()
+ .transpose()?
+ .ok_or_else(|| anyhow!("No Program found"))?
+ .run_for_uri(db_connection_config)
+}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 95074cb..322d168 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -4,3 +4,5 @@ pub use connection::*;
mod cli;
pub use cli::*;
+mod interface;
+pub use interface::*;
diff --git a/src/main.rs b/src/main.rs
index 9e30044..8030a41 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -55,7 +55,6 @@ async fn main() -> Result<()> {
let repo_path = PathBuf::from(config.repository());
let max_packages = count_pkg_files(&repo_path, ProgressBar::new_spinner());
let mut progressbars = ProgressBars::setup();
- let db = db::establish_connection(&config, &cli)?;
let repo = {
let bar = progressbars.repo_loading();
@@ -65,7 +64,9 @@ async fn main() -> Result<()> {
repo
};
+ let db_connection_config = crate::db::parse_db_connection_config(&config, &cli);
match cli.subcommand() {
+ ("db", Some(matches)) => db::interface(db_connection_config, matches, &config)?,
("build", Some(matches)) => {
let bar_tree_building = progressbars.tree_building();
bar_tree_building.set_length(max_packages);