#![deny(warnings)]
use git2::{Error, Repository, RepositoryInitMode, RepositoryInitOptions};
use std::path::{Path, PathBuf};
use structopt::StructOpt;
#[derive(StructOpt)]
struct Args {
#[structopt(name = "directory")]
arg_directory: String,
#[structopt(name = "quiet", short, long)]
flag_quiet: bool,
#[structopt(name = "bare", long)]
flag_bare: bool,
#[structopt(name = "dir", long = "template")]
flag_template: Option<String>,
#[structopt(name = "separate-git-dir", long)]
flag_separate_git_dir: Option<String>,
#[structopt(name = "initial-commit", long)]
flag_initial_commit: bool,
#[structopt(name = "perms", long = "shared")]
flag_shared: Option<String>,
}
fn run(args: &Args) -> Result<(), Error> {
let mut path = PathBuf::from(&args.arg_directory);
let repo = if !args.flag_bare
&& args.flag_template.is_none()
&& args.flag_shared.is_none()
&& args.flag_separate_git_dir.is_none()
{
Repository::init(&path)?
} else {
let mut opts = RepositoryInitOptions::new();
opts.bare(args.flag_bare);
if let Some(ref s) = args.flag_template {
opts.template_path(Path::new(s));
}
if let Some(ref s) = args.flag_separate_git_dir {
opts.workdir_path(&path);
path = PathBuf::from(s);
}
if let Some(ref s) = args.flag_shared {
opts.mode(parse_shared(s)?);
}
Repository::init_opts(&path, &opts)?
};
if !args.flag_quiet {
if args.flag_bare || args.flag_separate_git_dir.is_some() {
path = repo.path().to_path_buf();
} else {
path = repo.workdir().unwrap().to_path_buf();
}
println!("Initialized empty Git repository in {}", path.display());
}
if args.flag_initial_commit {
create_initial_commit(&repo)?;
println!("Created empty initial commit");
}
Ok(())
}
fn create_initial_commit(repo: &Repository) -> Result<(), Error> {
let sig = repo.signature()?;
let tree_id = {
let mut index = repo.index()?;
index.write_tree()?
};
let tree = repo.find_tree(tree_id)?;
repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;
Ok(())
}
fn parse_shared(shared: &str) -> Result<RepositoryInitMode, Error> {
match shared {
"false" | "umask" => Ok(git2::RepositoryInitMode::SHARED_UMASK),
"true" | "group" => Ok(git2::RepositoryInitMode::SHARED_GROUP),
"all" | "world" => Ok(git2::RepositoryInitMode::SHARED_ALL),
_ => {
if shared.starts_with('0') {
match u32::from_str_radix(&shared[1..], 8).ok() {
Some(n) => Ok(RepositoryInitMode::from_bits_truncate(n)),
None => Err(Error::from_str("invalid octal value for --shared")),
}
} else {
Err(Error::from_str("unknown value for --shared"))
}
}
}
}
fn main() {
let args = Args::from_args();
match run(&args) {
Ok(()) => {}
Err(e) => println!("error: {}", e),
}
}