Commit d58a64e9a5d32b511447943f20a84340b520872f

Carlos Martín Nieto 2014-06-30T20:55:32

clone: add a callback for repository creation Analogously to the remote creation callback, provide a way for the user of git_clone() to create the repository with whichever options they desire via callback.

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3938dcb..f2cb3d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,3 +25,7 @@ v0.21 + 1
 
   The remote_callbacks member has been preserved for convenience, although it
   is not used when a remote creation callback is supplied.
+
+* The git_clone_options struct now provides repository_cb and
+  repository_cb_payload to allow the user to create a repository with
+  custom options.
diff --git a/include/git2/clone.h b/include/git2/clone.h
index c07928a..b829c81 100644
--- a/include/git2/clone.h
+++ b/include/git2/clone.h
@@ -74,6 +74,26 @@ typedef int (*git_remote_create_cb)(
 	void *payload);
 
 /**
+ * The signature of a function matchin git_repository_init, with an
+ * aditional void * as callback payload.
+ *
+ * Callers of git_clone my provide a function matching this signature
+ * to override the repository creation and customization process
+ * during a clone operation.
+ *
+ * @param out the resulting repository
+ * @param path path in which to create the repository
+ * @param bare whether the repository is bare. This is the value from the clone options
+ * @param payload payload specified by the options
+ * @return 0, or a negative value to indicate error
+ */
+typedef int (*git_repository_create_cb)(
+	git_repository **out,
+	const char *path,
+	int bare,
+	void *payload);
+
+/**
  * Clone options structure
  *
  * Use the GIT_CLONE_OPTIONS_INIT to get the default settings, like this:
@@ -126,6 +146,19 @@ typedef struct git_clone_options {
 	git_signature *signature;
 
 	/**
+	 * A callback used to create the new repository into which to
+	 * clone. If NULL, the 'bare' field will be used to determine
+	 * whether to create a bare repository.
+	 */
+	git_repository_create_cb repository_cb;
+
+	/**
+	 * An opaque payload to pass to the git_repository creation callback.
+	 * This parameter is ignored unless repository_cb is non-NULL.
+	 */
+	void *repository_cb_payload;
+
+	/**
 	 * A callback used to create the git_remote, prior to its being
 	 * used to perform the clone operation. See the documentation for
 	 * git_remote_create_cb for details. This parameter may be NULL,
@@ -158,9 +191,9 @@ GIT_EXTERN(int) git_clone_init_options(
 /**
  * Clone a remote repository.
  *
- * This version handles the simple case. If you'd like to create the
- * repository or remote with non-default settings, you can create and
- * configure them and then use `git_clone_into()`.
+ * By default this creates its repository and initial remote to match
+ * git's defaults. You can use the options in the callback to
+ * customize how these are created.
  *
  * @param out pointer that will receive the resulting repository object
  * @param url the remote repository to clone
diff --git a/src/clone.c b/src/clone.c
index a4ed1a2..8894f97 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -229,6 +229,13 @@ cleanup:
 	return retcode;
 }
 
+static int default_repository_create(git_repository **out, const char *path, int bare, void *payload)
+{
+	GIT_UNUSED(payload);
+
+	return git_repository_init(out, path, bare);
+}
+
 static int default_remote_create(
 		git_remote **out,
 		git_repository *repo,
@@ -396,6 +403,7 @@ int git_clone(
 	git_remote *origin;
 	git_clone_options options = GIT_CLONE_OPTIONS_INIT;
 	uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES;
+	git_repository_create_cb repository_cb;
 
 	assert(out && url && local_path);
 
@@ -415,7 +423,12 @@ int git_clone(
 	if (git_path_exists(local_path))
 		rmdir_flags |= GIT_RMDIR_SKIP_ROOT;
 
-	if ((error = git_repository_init(&repo, local_path, options.bare)) < 0)
+	if (options.repository_cb)
+		repository_cb = options.repository_cb;
+	else
+		repository_cb = default_repository_create;
+
+	if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0)
 		return error;
 
 	if (!(error = create_and_configure_origin(&origin, repo, url, &options))) {