mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 18:38:58 +00:00
checkout: introduce git_checkout_perfdata
Checkout can now provide performance data about the number of (some) syscalls performed using an optional callback.
This commit is contained in:
parent
93b4a50de1
commit
1d50b3649d
@ -206,6 +206,12 @@ typedef enum {
|
|||||||
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu
|
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu
|
||||||
} git_checkout_notify_t;
|
} git_checkout_notify_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t mkdir_calls;
|
||||||
|
size_t stat_calls;
|
||||||
|
size_t chmod_calls;
|
||||||
|
} git_checkout_perfdata;
|
||||||
|
|
||||||
/** Checkout notification callback function */
|
/** Checkout notification callback function */
|
||||||
typedef int (*git_checkout_notify_cb)(
|
typedef int (*git_checkout_notify_cb)(
|
||||||
git_checkout_notify_t why,
|
git_checkout_notify_t why,
|
||||||
@ -222,6 +228,11 @@ typedef void (*git_checkout_progress_cb)(
|
|||||||
size_t total_steps,
|
size_t total_steps,
|
||||||
void *payload);
|
void *payload);
|
||||||
|
|
||||||
|
/** Checkout perfdata notification function */
|
||||||
|
typedef void (*git_checkout_perfdata_cb)(
|
||||||
|
const git_checkout_perfdata *perfdata,
|
||||||
|
void *payload);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checkout options structure
|
* Checkout options structure
|
||||||
*
|
*
|
||||||
@ -261,6 +272,10 @@ typedef struct git_checkout_options {
|
|||||||
const char *ancestor_label; /**< the name of the common ancestor side of conflicts */
|
const char *ancestor_label; /**< the name of the common ancestor side of conflicts */
|
||||||
const char *our_label; /**< the name of the "our" side of conflicts */
|
const char *our_label; /**< the name of the "our" side of conflicts */
|
||||||
const char *their_label; /**< the name of the "their" side of conflicts */
|
const char *their_label; /**< the name of the "their" side of conflicts */
|
||||||
|
|
||||||
|
/** Optional callback to notify the consumer of performance data. */
|
||||||
|
git_checkout_perfdata_cb perfdata_cb;
|
||||||
|
void *perfdata_payload;
|
||||||
} git_checkout_options;
|
} git_checkout_options;
|
||||||
|
|
||||||
#define GIT_CHECKOUT_OPTIONS_VERSION 1
|
#define GIT_CHECKOUT_OPTIONS_VERSION 1
|
||||||
|
111
src/checkout.c
111
src/checkout.c
@ -67,6 +67,7 @@ typedef struct {
|
|||||||
bool reload_submodules;
|
bool reload_submodules;
|
||||||
size_t total_steps;
|
size_t total_steps;
|
||||||
size_t completed_steps;
|
size_t completed_steps;
|
||||||
|
git_checkout_perfdata perfdata;
|
||||||
} checkout_data;
|
} checkout_data;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -1289,50 +1290,86 @@ fail:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int checkout_mkdir(
|
||||||
|
checkout_data *data,
|
||||||
|
const char *path,
|
||||||
|
const char *base,
|
||||||
|
mode_t mode,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
struct git_futils_mkdir_perfdata mkdir_perfdata = {0};
|
||||||
|
|
||||||
|
int error = git_futils_mkdir_withperf(
|
||||||
|
path, base, mode, flags, &mkdir_perfdata);
|
||||||
|
|
||||||
|
data->perfdata.mkdir_calls += mkdir_perfdata.mkdir_calls;
|
||||||
|
data->perfdata.stat_calls += mkdir_perfdata.stat_calls;
|
||||||
|
data->perfdata.chmod_calls += mkdir_perfdata.chmod_calls;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mkpath2file(
|
||||||
|
checkout_data *data, const char *path, unsigned int mode)
|
||||||
|
{
|
||||||
|
return checkout_mkdir(
|
||||||
|
data, path, git_repository_workdir(data->repo), mode,
|
||||||
|
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
static int buffer_to_file(
|
static int buffer_to_file(
|
||||||
|
checkout_data *data,
|
||||||
struct stat *st,
|
struct stat *st,
|
||||||
git_buf *buf,
|
git_buf *buf,
|
||||||
const char *path,
|
const char *path,
|
||||||
mode_t dir_mode,
|
|
||||||
int file_open_flags,
|
|
||||||
mode_t file_mode)
|
mode_t file_mode)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
|
if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if ((error = git_futils_writebuffer(
|
if ((error = git_futils_writebuffer(
|
||||||
buf, path, file_open_flags, file_mode)) < 0)
|
buf, path, data->opts.file_open_flags, file_mode)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (st != NULL && (error = p_stat(path, st)) < 0)
|
if (st) {
|
||||||
giterr_set(GITERR_OS, "Error statting '%s'", path);
|
data->perfdata.stat_calls++;
|
||||||
|
|
||||||
else if (GIT_PERMS_IS_EXEC(file_mode) &&
|
if ((error = p_stat(path, st)) < 0) {
|
||||||
(error = p_chmod(path, file_mode)) < 0)
|
giterr_set(GITERR_OS, "Error statting '%s'", path);
|
||||||
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GIT_PERMS_IS_EXEC(file_mode)) {
|
||||||
|
data->perfdata.chmod_calls++;
|
||||||
|
|
||||||
|
if ((error = p_chmod(path, file_mode)) < 0)
|
||||||
|
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
|
||||||
|
}
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int blob_content_to_file(
|
static int blob_content_to_file(
|
||||||
|
checkout_data *data,
|
||||||
struct stat *st,
|
struct stat *st,
|
||||||
git_blob *blob,
|
git_blob *blob,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char * hint_path,
|
const char * hint_path,
|
||||||
mode_t entry_filemode,
|
mode_t entry_filemode)
|
||||||
git_checkout_options *opts)
|
|
||||||
{
|
{
|
||||||
int error = 0;
|
mode_t file_mode = data->opts.file_mode ?
|
||||||
mode_t file_mode = opts->file_mode ? opts->file_mode : entry_filemode;
|
data->opts.file_mode : entry_filemode;
|
||||||
git_buf out = GIT_BUF_INIT;
|
git_buf out = GIT_BUF_INIT;
|
||||||
git_filter_list *fl = NULL;
|
git_filter_list *fl = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
if (hint_path == NULL)
|
if (hint_path == NULL)
|
||||||
hint_path = path;
|
hint_path = path;
|
||||||
|
|
||||||
if (!opts->disable_filters)
|
if (!data->opts.disable_filters)
|
||||||
error = git_filter_list_load(
|
error = git_filter_list_load(
|
||||||
&fl, git_blob_owner(blob), blob, hint_path,
|
&fl, git_blob_owner(blob), blob, hint_path,
|
||||||
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
|
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
|
||||||
@ -1343,9 +1380,7 @@ static int blob_content_to_file(
|
|||||||
git_filter_list_free(fl);
|
git_filter_list_free(fl);
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = buffer_to_file(
|
error = buffer_to_file(data, st, &out, path, file_mode);
|
||||||
st, &out, path, opts->dir_mode, opts->file_open_flags, file_mode);
|
|
||||||
|
|
||||||
st->st_mode = entry_filemode;
|
st->st_mode = entry_filemode;
|
||||||
|
|
||||||
git_buf_free(&out);
|
git_buf_free(&out);
|
||||||
@ -1355,22 +1390,21 @@ static int blob_content_to_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int blob_content_to_link(
|
static int blob_content_to_link(
|
||||||
|
checkout_data *data,
|
||||||
struct stat *st,
|
struct stat *st,
|
||||||
git_blob *blob,
|
git_blob *blob,
|
||||||
const char *path,
|
const char *path)
|
||||||
mode_t dir_mode,
|
|
||||||
int can_symlink)
|
|
||||||
{
|
{
|
||||||
git_buf linktarget = GIT_BUF_INIT;
|
git_buf linktarget = GIT_BUF_INIT;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
|
if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
|
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (can_symlink) {
|
if (data->can_symlink) {
|
||||||
if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
|
if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
|
||||||
giterr_set(GITERR_OS, "Could not create symlink %s\n", path);
|
giterr_set(GITERR_OS, "Could not create symlink %s\n", path);
|
||||||
} else {
|
} else {
|
||||||
@ -1378,6 +1412,8 @@ static int blob_content_to_link(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
data->perfdata.stat_calls++;
|
||||||
|
|
||||||
if ((error = p_lstat(path, st)) < 0)
|
if ((error = p_lstat(path, st)) < 0)
|
||||||
giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
|
giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
|
||||||
|
|
||||||
@ -1421,6 +1457,7 @@ static int checkout_submodule_update_index(
|
|||||||
if (git_buf_puts(&data->path, file->path) < 0)
|
if (git_buf_puts(&data->path, file->path) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
data->perfdata.stat_calls++;
|
||||||
if (p_stat(git_buf_cstr(&data->path), &st) < 0) {
|
if (p_stat(git_buf_cstr(&data->path), &st) < 0) {
|
||||||
giterr_set(
|
giterr_set(
|
||||||
GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
|
GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
|
||||||
@ -1442,7 +1479,8 @@ static int checkout_submodule(
|
|||||||
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
|
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((error = git_futils_mkdir(
|
if ((error = checkout_mkdir(
|
||||||
|
data,
|
||||||
file->path, data->opts.target_directory,
|
file->path, data->opts.target_directory,
|
||||||
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
|
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
|
||||||
return error;
|
return error;
|
||||||
@ -1481,10 +1519,13 @@ static void report_progress(
|
|||||||
data->opts.progress_payload);
|
data->opts.progress_payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
|
static int checkout_safe_for_update_only(
|
||||||
|
checkout_data *data, const char *path, mode_t expected_mode)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
data->perfdata.stat_calls++;
|
||||||
|
|
||||||
if (p_lstat(path, &st) < 0) {
|
if (p_lstat(path, &st) < 0) {
|
||||||
/* if doesn't exist, then no error and no update */
|
/* if doesn't exist, then no error and no update */
|
||||||
if (errno == ENOENT || errno == ENOTDIR)
|
if (errno == ENOENT || errno == ENOTDIR)
|
||||||
@ -1517,11 +1558,9 @@ static int checkout_write_content(
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (S_ISLNK(mode))
|
if (S_ISLNK(mode))
|
||||||
error = blob_content_to_link(
|
error = blob_content_to_link(data, st, blob, full_path);
|
||||||
st, blob, full_path, data->opts.dir_mode, data->can_symlink);
|
|
||||||
else
|
else
|
||||||
error = blob_content_to_file(
|
error = blob_content_to_file(data, st, blob, full_path, hint_path, mode);
|
||||||
st, blob, full_path, hint_path, mode, &data->opts);
|
|
||||||
|
|
||||||
git_blob_free(blob);
|
git_blob_free(blob);
|
||||||
|
|
||||||
@ -1552,7 +1591,7 @@ static int checkout_blob(
|
|||||||
|
|
||||||
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
|
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
|
||||||
int rval = checkout_safe_for_update_only(
|
int rval = checkout_safe_for_update_only(
|
||||||
git_buf_cstr(&data->path), file->mode);
|
data, git_buf_cstr(&data->path), file->mode);
|
||||||
if (rval <= 0)
|
if (rval <= 0)
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
@ -1807,7 +1846,7 @@ static int checkout_write_entry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
|
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
|
||||||
(error = checkout_safe_for_update_only(git_buf_cstr(&data->path), side->mode)) <= 0)
|
(error = checkout_safe_for_update_only(data, git_buf_cstr(&data->path), side->mode)) <= 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return checkout_write_content(data,
|
return checkout_write_content(data,
|
||||||
@ -1906,7 +1945,7 @@ static int checkout_write_merge(
|
|||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
|
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
|
||||||
(error = checkout_safe_for_update_only(git_buf_cstr(&path_workdir), result.mode)) <= 0)
|
(error = checkout_safe_for_update_only(data, git_buf_cstr(&path_workdir), result.mode)) <= 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!data->opts.disable_filters) {
|
if (!data->opts.disable_filters) {
|
||||||
@ -1922,7 +1961,7 @@ static int checkout_write_merge(
|
|||||||
out_data.size = result.len;
|
out_data.size = result.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((error = git_futils_mkpath2file(path_workdir.ptr, 0755)) < 0 ||
|
if ((error = mkpath2file(data, path_workdir.ptr, data->opts.dir_mode)) < 0 ||
|
||||||
(error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
|
(error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
|
||||||
(error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
|
(error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
|
||||||
(error = git_filebuf_commit(&output)) < 0)
|
(error = git_filebuf_commit(&output)) < 0)
|
||||||
@ -2157,8 +2196,9 @@ static int checkout_data_init(
|
|||||||
if (!data->opts.target_directory)
|
if (!data->opts.target_directory)
|
||||||
data->opts.target_directory = git_repository_workdir(repo);
|
data->opts.target_directory = git_repository_workdir(repo);
|
||||||
else if (!git_path_isdir(data->opts.target_directory) &&
|
else if (!git_path_isdir(data->opts.target_directory) &&
|
||||||
(error = git_futils_mkdir(data->opts.target_directory, NULL,
|
(error = checkout_mkdir(data,
|
||||||
GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
|
data->opts.target_directory, NULL,
|
||||||
|
GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* refresh config and index content unless NO_REFRESH is given */
|
/* refresh config and index content unless NO_REFRESH is given */
|
||||||
@ -2371,6 +2411,9 @@ int git_checkout_iterator(
|
|||||||
|
|
||||||
assert(data.completed_steps == data.total_steps);
|
assert(data.completed_steps == data.total_steps);
|
||||||
|
|
||||||
|
if (data.opts.perfdata_cb)
|
||||||
|
data.opts.perfdata_cb(&data.perfdata, data.opts.perfdata_payload);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (!error && data.index != NULL &&
|
if (!error && data.index != NULL &&
|
||||||
(data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
|
(data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
|
||||||
|
@ -279,11 +279,12 @@ void git_futils_mmap_free(git_map *out)
|
|||||||
p_munmap(out);
|
p_munmap(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_futils_mkdir(
|
int git_futils_mkdir_withperf(
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *base,
|
const char *base,
|
||||||
mode_t mode,
|
mode_t mode,
|
||||||
uint32_t flags)
|
uint32_t flags,
|
||||||
|
struct git_futils_mkdir_perfdata *perfdata)
|
||||||
{
|
{
|
||||||
int error = -1;
|
int error = -1;
|
||||||
git_buf make_path = GIT_BUF_INIT;
|
git_buf make_path = GIT_BUF_INIT;
|
||||||
@ -352,15 +353,20 @@ int git_futils_mkdir(
|
|||||||
st.st_mode = 0;
|
st.st_mode = 0;
|
||||||
|
|
||||||
/* make directory */
|
/* make directory */
|
||||||
|
perfdata->mkdir_calls++;
|
||||||
|
|
||||||
if (p_mkdir(make_path.ptr, mode) < 0) {
|
if (p_mkdir(make_path.ptr, mode) < 0) {
|
||||||
int tmp_errno = giterr_system_last();
|
int tmp_errno = giterr_system_last();
|
||||||
|
|
||||||
/* ignore error if not at end or if directory already exists */
|
/* ignore error if not at end or if directory already exists */
|
||||||
if (lastch == '\0' &&
|
if (lastch == '\0') {
|
||||||
(p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) {
|
perfdata->stat_calls++;
|
||||||
giterr_system_set(tmp_errno);
|
|
||||||
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
|
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||||
goto done;
|
giterr_system_set(tmp_errno);
|
||||||
|
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* with exclusive create, existing dir is an error */
|
/* with exclusive create, existing dir is an error */
|
||||||
@ -374,11 +380,15 @@ int git_futils_mkdir(
|
|||||||
/* chmod if requested and necessary */
|
/* chmod if requested and necessary */
|
||||||
if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 ||
|
if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 ||
|
||||||
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
|
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
|
||||||
st.st_mode != mode &&
|
st.st_mode != mode) {
|
||||||
(error = p_chmod(make_path.ptr, mode)) < 0 &&
|
|
||||||
lastch == '\0') {
|
perfdata->chmod_calls++;
|
||||||
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr);
|
|
||||||
goto done;
|
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
|
||||||
|
lastch == '\0') {
|
||||||
|
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,10 +396,13 @@ int git_futils_mkdir(
|
|||||||
|
|
||||||
/* check that full path really is a directory if requested & needed */
|
/* check that full path really is a directory if requested & needed */
|
||||||
if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
|
if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
|
||||||
lastch != '\0' &&
|
lastch != '\0') {
|
||||||
(p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) {
|
perfdata->stat_calls++;
|
||||||
giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr);
|
|
||||||
error = GIT_ENOTFOUND;
|
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||||
|
giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr);
|
||||||
|
error = GIT_ENOTFOUND;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
@ -397,6 +410,16 @@ done:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_futils_mkdir(
|
||||||
|
const char *path,
|
||||||
|
const char *base,
|
||||||
|
mode_t mode,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct git_futils_mkdir_perfdata perfdata = {0};
|
||||||
|
return git_futils_mkdir_withperf(path, base, mode, flags, &perfdata);
|
||||||
|
}
|
||||||
|
|
||||||
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
||||||
{
|
{
|
||||||
return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);
|
return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);
|
||||||
|
@ -84,6 +84,13 @@ typedef enum {
|
|||||||
GIT_MKDIR_VERIFY_DIR = 64,
|
GIT_MKDIR_VERIFY_DIR = 64,
|
||||||
} git_futils_mkdir_flags;
|
} git_futils_mkdir_flags;
|
||||||
|
|
||||||
|
struct git_futils_mkdir_perfdata
|
||||||
|
{
|
||||||
|
size_t stat_calls;
|
||||||
|
size_t mkdir_calls;
|
||||||
|
size_t chmod_calls;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a directory or entire path.
|
* Create a directory or entire path.
|
||||||
*
|
*
|
||||||
@ -95,8 +102,15 @@ typedef enum {
|
|||||||
* @param base Root for relative path. These directories will never be made.
|
* @param base Root for relative path. These directories will never be made.
|
||||||
* @param mode The mode to use for created directories.
|
* @param mode The mode to use for created directories.
|
||||||
* @param flags Combination of the mkdir flags above.
|
* @param flags Combination of the mkdir flags above.
|
||||||
|
* @param perfdata Performance data, use `git_futils_mkdir` if you don't want this data.
|
||||||
* @return 0 on success, else error code
|
* @return 0 on success, else error code
|
||||||
*/
|
*/
|
||||||
|
extern int git_futils_mkdir_withperf(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
|
||||||
|
* without performance data.
|
||||||
|
*/
|
||||||
extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags);
|
extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1101,3 +1101,32 @@ void test_checkout_tree__case_changing_rename(void)
|
|||||||
git_commit_free(dir_commit);
|
git_commit_free(dir_commit);
|
||||||
git_commit_free(master_commit);
|
git_commit_free(master_commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void perfdata_cb(const git_checkout_perfdata *in, void *payload)
|
||||||
|
{
|
||||||
|
memcpy(payload, in, sizeof(git_checkout_perfdata));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_checkout_tree__can_collect_perfdata(void)
|
||||||
|
{
|
||||||
|
git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
|
||||||
|
git_oid oid;
|
||||||
|
git_object *obj = NULL;
|
||||||
|
git_checkout_perfdata perfdata = {0};
|
||||||
|
|
||||||
|
opts.perfdata_cb = perfdata_cb;
|
||||||
|
opts.perfdata_payload = &perfdata;
|
||||||
|
|
||||||
|
assert_on_branch(g_repo, "master");
|
||||||
|
opts.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||||
|
|
||||||
|
cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir"));
|
||||||
|
cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY));
|
||||||
|
|
||||||
|
cl_git_pass(git_checkout_tree(g_repo, obj, &opts));
|
||||||
|
|
||||||
|
cl_assert(perfdata.mkdir_calls > 0);
|
||||||
|
cl_assert(perfdata.stat_calls > 0);
|
||||||
|
|
||||||
|
git_object_free(obj);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user