Blame examples/init.c

Packit Service 20376f
/*
Packit Service 20376f
 * libgit2 "init" example - shows how to initialize a new repo
Packit Service 20376f
 *
Packit Service 20376f
 * Written by the libgit2 contributors
Packit Service 20376f
 *
Packit Service 20376f
 * To the extent possible under law, the author(s) have dedicated all copyright
Packit Service 20376f
 * and related and neighboring rights to this software to the public domain
Packit Service 20376f
 * worldwide. This software is distributed without any warranty.
Packit Service 20376f
 *
Packit Service 20376f
 * You should have received a copy of the CC0 Public Domain Dedication along
Packit Service 20376f
 * with this software. If not, see
Packit Service 20376f
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include "common.h"
Packit Service 20376f
Packit Service 20376f
/**
Packit Service 20376f
 * This is a sample program that is similar to "git init".  See the
Packit Service 20376f
 * documentation for that (try "git help init") to understand what this
Packit Service 20376f
 * program is emulating.
Packit Service 20376f
 *
Packit Service 20376f
 * This demonstrates using the libgit2 APIs to initialize a new repository.
Packit Service 20376f
 *
Packit Service 20376f
 * This also contains a special additional option that regular "git init"
Packit Service 20376f
 * does not support which is "--initial-commit" to make a first empty commit.
Packit Service 20376f
 * That is demonstrated in the "create_initial_commit" helper function.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
/** Forward declarations of helpers */
Packit Service 20376f
struct opts {
Packit Service 20376f
	int no_options;
Packit Service 20376f
	int quiet;
Packit Service 20376f
	int bare;
Packit Service 20376f
	int initial_commit;
Packit Service 20376f
	uint32_t shared;
Packit Service 20376f
	const char *template;
Packit Service 20376f
	const char *gitdir;
Packit Service 20376f
	const char *dir;
Packit Service 20376f
};
Packit Service 20376f
static void create_initial_commit(git_repository *repo);
Packit Service 20376f
static void parse_opts(struct opts *o, int argc, char *argv[]);
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
int main(int argc, char *argv[])
Packit Service 20376f
{
Packit Service 20376f
	git_repository *repo = NULL;
Packit Service 20376f
	struct opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
Packit Service 20376f
Packit Service 20376f
	git_libgit2_init();
Packit Service 20376f
Packit Service 20376f
	parse_opts(&o, argc, argv);
Packit Service 20376f
Packit Service 20376f
	/* Initialize repository. */
Packit Service 20376f
Packit Service 20376f
	if (o.no_options) {
Packit Service 20376f
		/**
Packit Service 20376f
		 * No options were specified, so let's demonstrate the default
Packit Service 20376f
		 * simple case of git_repository_init() API usage...
Packit Service 20376f
		 */
Packit Service 20376f
		check_lg2(git_repository_init(&repo, o.dir, 0),
Packit Service 20376f
			"Could not initialize repository", NULL);
Packit Service 20376f
	}
Packit Service 20376f
	else {
Packit Service 20376f
		/**
Packit Service 20376f
		 * Some command line options were specified, so we'll use the
Packit Service 20376f
		 * extended init API to handle them
Packit Service 20376f
		 */
Packit Service 20376f
		git_repository_init_options initopts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
Packit Service 20376f
		initopts.flags = GIT_REPOSITORY_INIT_MKPATH;
Packit Service 20376f
Packit Service 20376f
		if (o.bare)
Packit Service 20376f
			initopts.flags |= GIT_REPOSITORY_INIT_BARE;
Packit Service 20376f
Packit Service 20376f
		if (o.template) {
Packit Service 20376f
			initopts.flags |= GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
Packit Service 20376f
			initopts.template_path = o.template;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (o.gitdir) {
Packit Service 20376f
			/**
Packit Service 20376f
			 * If you specified a separate git directory, then initialize
Packit Service 20376f
			 * the repository at that path and use the second path as the
Packit Service 20376f
			 * working directory of the repository (with a git-link file)
Packit Service 20376f
			 */
Packit Service 20376f
			initopts.workdir_path = o.dir;
Packit Service 20376f
			o.dir = o.gitdir;
Packit Service 20376f
		}
Packit Service 20376f
Packit Service 20376f
		if (o.shared != 0)
Packit Service 20376f
			initopts.mode = o.shared;
Packit Service 20376f
Packit Service 20376f
		check_lg2(git_repository_init_ext(&repo, o.dir, &initopts),
Packit Service 20376f
				"Could not initialize repository", NULL);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/** Print a message to stdout like "git init" does. */
Packit Service 20376f
Packit Service 20376f
	if (!o.quiet) {
Packit Service 20376f
		if (o.bare || o.gitdir)
Packit Service 20376f
			o.dir = git_repository_path(repo);
Packit Service 20376f
		else
Packit Service 20376f
			o.dir = git_repository_workdir(repo);
Packit Service 20376f
Packit Service 20376f
		printf("Initialized empty Git repository in %s\n", o.dir);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	/**
Packit Service 20376f
	 * As an extension to the basic "git init" command, this example
Packit Service 20376f
	 * gives the option to create an empty initial commit.  This is
Packit Service 20376f
	 * mostly to demonstrate what it takes to do that, but also some
Packit Service 20376f
	 * people like to have that empty base commit in their repo.
Packit Service 20376f
	 */
Packit Service 20376f
	if (o.initial_commit) {
Packit Service 20376f
		create_initial_commit(repo);
Packit Service 20376f
		printf("Created empty initial commit\n");
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	git_repository_free(repo);
Packit Service 20376f
	git_libgit2_shutdown();
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/**
Packit Service 20376f
 * Unlike regular "git init", this example shows how to create an initial
Packit Service 20376f
 * empty commit in the repository.  This is the helper function that does
Packit Service 20376f
 * that.
Packit Service 20376f
 */
Packit Service 20376f
static void create_initial_commit(git_repository *repo)
Packit Service 20376f
{
Packit Service 20376f
	git_signature *sig;
Packit Service 20376f
	git_index *index;
Packit Service 20376f
	git_oid tree_id, commit_id;
Packit Service 20376f
	git_tree *tree;
Packit Service 20376f
Packit Service 20376f
	/** First use the config to initialize a commit signature for the user. */
Packit Service 20376f
Packit Service 20376f
	if (git_signature_default(&sig, repo) < 0)
Packit Service 20376f
		fatal("Unable to create a commit signature.",
Packit Service 20376f
		      "Perhaps 'user.name' and 'user.email' are not set");
Packit Service 20376f
Packit Service 20376f
	/* Now let's create an empty tree for this commit */
Packit Service 20376f
Packit Service 20376f
	if (git_repository_index(&index, repo) < 0)
Packit Service 20376f
		fatal("Could not open repository index", NULL);
Packit Service 20376f
Packit Service 20376f
	/**
Packit Service 20376f
	 * Outside of this example, you could call git_index_add_bypath()
Packit Service 20376f
	 * here to put actual files into the index.  For our purposes, we'll
Packit Service 20376f
	 * leave it empty for now.
Packit Service 20376f
	 */
Packit Service 20376f
Packit Service 20376f
	if (git_index_write_tree(&tree_id, index) < 0)
Packit Service 20376f
		fatal("Unable to write initial tree from index", NULL);
Packit Service 20376f
Packit Service 20376f
	git_index_free(index);
Packit Service 20376f
Packit Service 20376f
	if (git_tree_lookup(&tree, repo, &tree_id) < 0)
Packit Service 20376f
		fatal("Could not look up initial tree", NULL);
Packit Service 20376f
Packit Service 20376f
	/**
Packit Service 20376f
	 * Ready to create the initial commit.
Packit Service 20376f
	 *
Packit Service 20376f
	 * Normally creating a commit would involve looking up the current
Packit Service 20376f
	 * HEAD commit and making that be the parent of the initial commit,
Packit Service 20376f
	 * but here this is the first commit so there will be no parent.
Packit Service 20376f
	 */
Packit Service 20376f
Packit Service 20376f
	if (git_commit_create_v(
Packit Service 20376f
			&commit_id, repo, "HEAD", sig, sig,
Packit Service 20376f
			NULL, "Initial commit", tree, 0) < 0)
Packit Service 20376f
		fatal("Could not create the initial commit", NULL);
Packit Service 20376f
Packit Service 20376f
	/** Clean up so we don't leak memory. */
Packit Service 20376f
Packit Service 20376f
	git_tree_free(tree);
Packit Service 20376f
	git_signature_free(sig);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void usage(const char *error, const char *arg)
Packit Service 20376f
{
Packit Service 20376f
	fprintf(stderr, "error: %s '%s'\n", error, arg);
Packit Service 20376f
	fprintf(stderr,
Packit Service 20376f
			"usage: init [-q | --quiet] [--bare] [--template=<dir>]\n"
Packit Service 20376f
			"            [--shared[=perms]] [--initial-commit]\n"
Packit Service 20376f
			"            [--separate-git-dir] <directory>\n");
Packit Service 20376f
	exit(1);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/** Parse the tail of the --shared= argument. */
Packit Service 20376f
static uint32_t parse_shared(const char *shared)
Packit Service 20376f
{
Packit Service 20376f
	if (!strcmp(shared, "false") || !strcmp(shared, "umask"))
Packit Service 20376f
		return GIT_REPOSITORY_INIT_SHARED_UMASK;
Packit Service 20376f
Packit Service 20376f
	else if (!strcmp(shared, "true") || !strcmp(shared, "group"))
Packit Service 20376f
		return GIT_REPOSITORY_INIT_SHARED_GROUP;
Packit Service 20376f
Packit Service 20376f
	else if (!strcmp(shared, "all") || !strcmp(shared, "world") ||
Packit Service 20376f
			 !strcmp(shared, "everybody"))
Packit Service 20376f
		return GIT_REPOSITORY_INIT_SHARED_ALL;
Packit Service 20376f
Packit Service 20376f
	else if (shared[0] == '0') {
Packit Service 20376f
		long val;
Packit Service 20376f
		char *end = NULL;
Packit Service 20376f
		val = strtol(shared + 1, &end, 8);
Packit Service 20376f
		if (end == shared + 1 || *end != 0)
Packit Service 20376f
			usage("invalid octal value for --shared", shared);
Packit Service 20376f
		return (uint32_t)val;
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	else
Packit Service 20376f
		usage("unknown value for --shared", shared);
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void parse_opts(struct opts *o, int argc, char *argv[])
Packit Service 20376f
{
Packit Service 20376f
	struct args_info args = ARGS_INFO_INIT;
Packit Service 20376f
	const char *sharedarg;
Packit Service 20376f
Packit Service 20376f
	/** Process arguments. */
Packit Service 20376f
Packit Service 20376f
	for (args.pos = 1; args.pos < argc; ++args.pos) {
Packit Service 20376f
		char *a = argv[args.pos];
Packit Service 20376f
Packit Service 20376f
		if (a[0] == '-')
Packit Service 20376f
			o->no_options = 0;
Packit Service 20376f
Packit Service 20376f
		if (a[0] != '-') {
Packit Service 20376f
			if (o->dir != NULL)
Packit Service 20376f
				usage("extra argument", a);
Packit Service 20376f
			o->dir = a;
Packit Service 20376f
		}
Packit Service 20376f
		else if (!strcmp(a, "-q") || !strcmp(a, "--quiet"))
Packit Service 20376f
			o->quiet = 1;
Packit Service 20376f
		else if (!strcmp(a, "--bare"))
Packit Service 20376f
			o->bare = 1;
Packit Service 20376f
		else if (!strcmp(a, "--shared"))
Packit Service 20376f
			o->shared = GIT_REPOSITORY_INIT_SHARED_GROUP;
Packit Service 20376f
		else if (!strcmp(a, "--initial-commit"))
Packit Service 20376f
			o->initial_commit = 1;
Packit Service 20376f
		else if (match_str_arg(&sharedarg, &args, "--shared"))
Packit Service 20376f
			o->shared = parse_shared(sharedarg);
Packit Service 20376f
		else if (!match_str_arg(&o->template, &args, "--template") ||
Packit Service 20376f
		         !match_str_arg(&o->gitdir, &args, "--separate-git-dir"))
Packit Service 20376f
			usage("unknown option", a);
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (!o->dir)
Packit Service 20376f
		usage("must specify directory to init", NULL);
Packit Service 20376f
}