1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
/*
* libgit2 "init" example - shows how to initialize a new repo (also includes how to do an initial commit)
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#![deny(warnings)]
use clap::Parser;
use git2::{Error, Repository, RepositoryInitMode, RepositoryInitOptions};
use std::path::{Path, PathBuf};
#[derive(Parser)]
struct Args {
#[structopt(name = "directory")]
arg_directory: String,
#[structopt(name = "quiet", short, long)]
/// don't print information to stdout
flag_quiet: bool,
#[structopt(name = "bare", long)]
/// initialize a new bare repository
flag_bare: bool,
#[structopt(name = "dir", long = "template")]
/// use <dir> as an initialization template
flag_template: Option<String>,
#[structopt(name = "separate-git-dir", long)]
/// use <dir> as the .git directory
flag_separate_git_dir: Option<String>,
#[structopt(name = "initial-commit", long)]
/// create an initial empty commit
flag_initial_commit: bool,
#[structopt(name = "perms", long = "shared")]
/// permissions to create the repository with
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 you specified a separate git directory, then initialize
// the repository at that path and use the second path as the
// working directory of the repository (with a git-link file)
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)?
};
// Print a message to stdout like "git init" does
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(())
}
/// Unlike regular "git init", this example shows how to create an initial empty
/// commit in the repository. This is the helper function that does that.
fn create_initial_commit(repo: &Repository) -> Result<(), Error> {
// First use the config to initialize a commit signature for the user.
let sig = repo.signature()?;
// Now let's create an empty tree for this commit
let tree_id = {
let mut index = repo.index()?;
// Outside of this example, you could call index.add_path()
// here to put actual files into the index. For our purposes, we'll
// leave it empty for now.
index.write_tree()?
};
let tree = repo.find_tree(tree_id)?;
// Ready to create the initial commit.
//
// Normally creating a commit would involve looking up the current HEAD
// commit and making that be the parent of the initial commit, but here this
// is the first commit so there will be no parent.
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::parse();
match run(&args) {
Ok(()) => {}
Err(e) => println!("error: {}", e),
}
}
|