use std::error::Error;
use std::path::{Path, PathBuf};
use clap::{Parser, Subcommand};
use rusqlite::Connection;
use crate::actions::{
add, branch, clone, commit, diff, init, log, migration, remote, reset,
status, tree,
};
use crate::db::repo_db_path;
use crate::store::get_root_path;
use crate::types::remote_kind::RemoteKind;
#[derive(Parser, Debug)]
#[command(name = "sssync")]
#[command(author = "Anders Conbere<anders@conbere.org>")]
#[command(version = "0.1")]
#[command(about = "Keep big files in sync in S3", long_about = None)]
pub struct Cli {
#[command(subcommand)]
action: Action,
}
#[derive(Subcommand, Debug)]
pub enum Branch {
Add { name: String },
Switch { name: String },
List,
}
#[derive(Subcommand, Debug)]
pub enum Migration {
List,
Show { id: String },
}
#[derive(Subcommand, Debug)]
pub enum Remote {
Add {
name: String,
#[arg(long)]
#[arg(value_enum)]
kind: RemoteKind,
#[arg(long)]
location: String,
},
List,
Init {
name: String,
#[arg(long)]
force: bool,
},
Push { name: String },
FetchRemoteDB { name: String },
PushRemoteDB {
name: String,
#[arg(long)]
force: bool,
},
Remove { name: String },
Locate {
name: String,
#[arg(long)]
path: PathBuf,
},
}
#[derive(Subcommand, Debug)]
pub enum Action {
Remote {
#[command(subcommand)]
action: Remote,
},
Branch {
#[command(subcommand)]
action: Branch,
},
Migration {
#[command(subcommand)]
action: Migration,
},
Init {
path: PathBuf,
},
Add {
path: PathBuf,
},
Commit,
Clone {
url: String,
path: PathBuf,
},
Log,
Status,
Tree {
hash: String,
},
Diff {
hash: String,
},
Reset,
}
pub fn run() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
let pwd = Path::new(".").canonicalize()?;
if let Action::Init { path } = &cli.action {
init::init(path)?;
return Ok(());
}
if let Action::Clone { url, path } = &cli.action {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(clone::clone(url, path))?;
return Ok(());
}
let root_path = get_root_path(&pwd)
.ok_or(format!("not in a sssync'd directory: {}", pwd.display()))?;
let connection = Connection::open(repo_db_path(root_path))?;
match &cli.action {
Action::Remote { action } => match action {
Remote::Add {
name,
kind,
location,
} => {
println!("Adding remote: {}", name);
remote::add(&connection, name, kind, location)
}
Remote::List => remote::list(&connection),
Remote::Init { name, force } => {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(remote::init(
&connection,
root_path,
name,
*force,
))?;
Ok(())
}
Remote::Push { name } => {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(remote::push(&connection, root_path, name))?;
Ok(())
}
Remote::FetchRemoteDB { name } => {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(remote::fetch_remote_database(
&connection,
root_path,
name,
))?;
Ok(())
}
Remote::PushRemoteDB { name, force } => {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(remote::push_remote_database(
&connection,
root_path,
name,
*force,
))?;
Ok(())
}
Remote::Remove { name } => {
remote::remove(&connection, name)?;
Ok(())
}
Remote::Locate { name, path } => {
remote::locate(&connection, name, path)?;
Ok(())
}
},
Action::Branch { action } => match action {
Branch::Add { name } => branch::add(&connection, name, None),
Branch::Switch { name } => {
branch::switch(&connection, root_path, name)
}
Branch::List => branch::list(&connection),
},
Action::Migration { action } => match action {
Migration::List {} => {
migration::list(&connection)?;
Ok(())
}
Migration::Show { id } => migration::show(&connection, id),
},
Action::Commit => commit::commit(&connection, root_path),
Action::Clone { url, path } => {
println!("Action::Clone {} {}", url, path.display());
Ok(())
}
Action::Status => {
status::status(&connection, root_path)?;
Ok(())
}
Action::Init { path } => {
println!("Action::Init {}", path.display());
Ok(())
}
Action::Add { path } => {
let cp = path.canonicalize()?;
let rel_path = cp.strip_prefix(root_path)?;
add::add(&connection, root_path, rel_path)
}
Action::Log => log::log(&connection),
Action::Diff { hash } => diff::diff(&connection, hash),
Action::Reset => reset::reset(&connection, root_path),
Action::Tree { hash } => tree::tree(&connection, hash),
}
}