Commit 83862c83 by lhchavez

commit-graph: Add a way to write commit-graph files

This change adds the git_commit_graph_writer_* functions to allow to
write and create `commit-graph` files from `.idx`/`.pack` files or
`git_revwalk`s.

Part of: #5757
parent f08cae10
......@@ -40,6 +40,136 @@ GIT_EXTERN(int) git_commit_graph_open(git_commit_graph **cgraph_out, const char
*/
GIT_EXTERN(void) git_commit_graph_free(git_commit_graph *cgraph);
GIT_END_DECL
/**
* Create a new writer for `commit-graph` files.
*
* @param out Location to store the writer pointer.
* @param objects_info_dir The `objects/info` directory.
* The `commit-graph` file will be written in this directory.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_graph_writer_new(
git_commit_graph_writer **out,
const char *objects_info_dir);
/**
* Free the commit-graph writer and its resources.
*
* @param w The writer to free. If NULL no action is taken.
*/
GIT_EXTERN(void) git_commit_graph_writer_free(git_commit_graph_writer *w);
/**
* Add an `.idx` file (associated to a packfile) to the writer.
*
* @param w The writer.
* @param repo The repository that owns the `.idx` file.
* @param idx_path The path of an `.idx` file.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_graph_writer_add_index_file(
git_commit_graph_writer *w,
git_repository *repo,
const char *idx_path);
/**
* Add a revwalk to the writer. This will add all the commits from the revwalk
* to the commit-graph.
*
* @param w The writer.
* @param walk The git_revwalk.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_graph_writer_add_revwalk(
git_commit_graph_writer *w,
git_revwalk *walk);
/**
* The strategy to use when adding a new set of commits to a pre-existing
* commit-graph chain.
*/
typedef enum {
/**
* Do not split commit-graph files. The other split strategy-related option
* fields are ignored.
*/
GIT_COMMIT_GRAPH_SPLIT_STRATEGY_SINGLE_FILE = 0,
} git_commit_graph_split_strategy_t;
/**
* Options structure for
* `git_commit_graph_writer_commit`/`git_commit_graph_writer_dump`.
*
* Initialize with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`. Alternatively, you
* can use `git_commit_graph_writer_options_init`.
*/
typedef struct {
unsigned int version;
/**
* The strategy to use when adding new commits to a pre-existing commit-graph
* chain.
*/
git_commit_graph_split_strategy_t split_strategy;
/**
* The number of commits in level N is less than X times the number of
* commits in level N + 1.
*/
float size_multiple;
/**
* The number of commits in level N + 1 is more than C commits.
*/
size_t max_commits;
} git_commit_graph_writer_options;
#define GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION 1
#define GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT \
{ \
GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION, \
GIT_COMMIT_GRAPH_SPLIT_STRATEGY_SINGLE_FILE, 2.0f, 64000 \
}
/**
* Initialize git_commit_graph_writer_options structure
*
* Initializes a `git_commit_graph_writer_options` with default values. Equivalent to
* creating an instance with `GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT`.
*
* @param opts The `git_commit_graph_writer_options` struct to initialize.
* @param version The struct version; pass `GIT_COMMIT_GRAPH_WRITER_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure.
*/
GIT_EXTERN(int) git_commit_graph_writer_options_init(
git_commit_graph_writer_options *opts,
unsigned int version);
/**
* Write a `commit-graph` file to a file.
*
* @param w The writer
* @param opts Pointer to git_commit_graph_writer_options struct.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_graph_writer_commit(
git_commit_graph_writer *w,
git_commit_graph_writer_options *opts);
/**
* Dump the contents of the `commit-graph` to an in-memory buffer.
*
* @param buffer Buffer where to store the contents of the `commit-graph`.
* @param w The writer.
* @param opts Pointer to git_commit_graph_writer_options struct.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_commit_graph_writer_dump(
git_buf *buffer,
git_commit_graph_writer *w,
git_commit_graph_writer_options *opts);
/** @} */
GIT_END_DECL
#endif
......@@ -96,6 +96,9 @@ typedef struct git_odb_stream git_odb_stream;
/** A stream to write a packfile to the ODB */
typedef struct git_odb_writepack git_odb_writepack;
/** a writer for commit-graph files. */
typedef struct git_commit_graph_writer git_commit_graph_writer;
/** An open refs database handle. */
typedef struct git_refdb git_refdb;
......
......@@ -14,6 +14,7 @@
#include "git2/sys/commit_graph.h"
#include "map.h"
#include "vector.h"
/**
* A commit-graph file.
......@@ -119,6 +120,20 @@ int git_commit_graph_get_file(git_commit_graph_file **file_out, git_commit_graph
void git_commit_graph_refresh(git_commit_graph *cgraph);
/*
* A writer for `commit-graph` files.
*/
struct git_commit_graph_writer {
/*
* The path of the `objects/info` directory where the `commit-graph` will be
* stored.
*/
git_buf objects_info_dir;
/* The list of packed commits. */
git_vector commits;
};
/*
* Returns whether the git_commit_graph_file needs to be reloaded since the
* contents of the commit-graph file have changed on disk.
*/
......
#include "clar_libgit2.h"
#include <git2.h>
#include <git2/sys/commit_graph.h>
#include "commit_graph.h"
#include "futils.h"
void test_graph_commit_graph__parse(void)
{
......@@ -88,3 +90,36 @@ void test_graph_commit_graph__parse_octopus_merge(void)
git_repository_free(repo);
git_buf_dispose(&commit_graph_path);
}
void test_graph_commit_graph__writer(void)
{
git_repository *repo;
git_commit_graph_writer *w = NULL;
git_revwalk *walk;
git_commit_graph_writer_options opts = GIT_COMMIT_GRAPH_WRITER_OPTIONS_INIT;
git_buf cgraph = GIT_BUF_INIT, expected_cgraph = GIT_BUF_INIT, path = GIT_BUF_INIT;
cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git")));
cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/info"));
cl_git_pass(git_commit_graph_writer_new(&w, git_buf_cstr(&path)));
/* This is equivalent to `git commit-graph write --reachable`. */
cl_git_pass(git_revwalk_new(&walk, repo));
cl_git_pass(git_revwalk_push_glob(walk, "refs/*"));
cl_git_pass(git_commit_graph_writer_add_revwalk(w, walk));
git_revwalk_free(walk);
cl_git_pass(git_commit_graph_writer_dump(&cgraph, w, &opts));
cl_git_pass(git_buf_joinpath(&path, git_repository_path(repo), "objects/info/commit-graph"));
cl_git_pass(git_futils_readbuffer(&expected_cgraph, git_buf_cstr(&path)));
cl_assert_equal_i(git_buf_len(&cgraph), git_buf_len(&expected_cgraph));
cl_assert_equal_i(memcmp(git_buf_cstr(&cgraph), git_buf_cstr(&expected_cgraph), git_buf_len(&cgraph)), 0);
git_buf_dispose(&cgraph);
git_buf_dispose(&expected_cgraph);
git_buf_dispose(&path);
git_commit_graph_writer_free(w);
git_repository_free(repo);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment