#![feature(old_orphan_check)]
#![deny(warnings)]
extern crate git2;
extern crate docopt;
extern crate "rustc-serialize" as rustc_serialize;
use docopt::Docopt;
use git2::{Repository, RepositoryInitOptions, RepositoryInitMode, Error};
use std::num::FromStrRadix;
#[derive(RustcDecodable)]
struct Args {
arg_directory: String,
flag_quiet: bool,
flag_bare: bool,
flag_template: Option<String>,
flag_separate_git_dir: Option<String>,
flag_initial_commit: bool,
flag_shared: Option<String>,
}
fn run(args: &Args) -> Result<(), Error> {
let mut path = Path::new(&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() {
try!(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 = Path::new(s);
}
if let Some(ref s) = args.flag_shared {
opts.mode(try!(parse_shared(s.as_slice())));
}
try!(Repository::init_opts(&path, &opts))
};
if !args.flag_quiet {
if args.flag_bare || args.flag_separate_git_dir.is_some() {
path = repo.path();
} else {
path = repo.workdir().unwrap();
}
println!("Initialized empty Git repository in {}", path.display());
}
if args.flag_initial_commit {
try!(create_initial_commit(&repo));
println!("Created empty initial commit");
}
Ok(())
}
fn create_initial_commit(repo: &Repository) -> Result<(), Error> {
let sig = try!(repo.signature());
let tree_id = {
let mut index = try!(repo.index());
try!(index.write_tree())
};
let tree = try!(repo.find_tree(tree_id));
try!(repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[]));
Ok(())
}
fn parse_shared(shared: &str) -> Result<RepositoryInitMode, Error> {
match shared {
"false" | "umask" => Ok(git2::REPOSITORY_INIT_SHARED_UMASK),
"true" | "group" => Ok(git2::REPOSITORY_INIT_SHARED_GROUP),
"all" | "world" => Ok(git2::REPOSITORY_INIT_SHARED_ALL),
_ => {
if shared.starts_with("0") {
match FromStrRadix::from_str_radix(shared.slice_from(1), 8) {
Some(n) => {
return 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() {
const USAGE: &'static str = "
usage: init [options] <directory>
Options:
-q, --quiet don't print information to stdout
--bare initialize a new bare repository
--template <dir> use <dir> as an initialization template
--separate-git-dir <dir> use <dir> as the .git directory
--initial-commit create an initial empty commit
--shared <perms> permissions to create the repository with
";
let args = Docopt::new(USAGE).and_then(|d| d.decode())
.unwrap_or_else(|e| e.exit());
match run(&args) {
Ok(()) => {}
Err(e) => println!("error: {}", e),
}
}