mirror of
https://git.proxmox.com/git/libgit2
synced 2025-06-20 04:07:26 +00:00
Checkout: obey core.symlinks.
This commit is contained in:
parent
3e026f1b45
commit
8651c10f1e
@ -13,6 +13,7 @@
|
|||||||
#include "git2/tree.h"
|
#include "git2/tree.h"
|
||||||
#include "git2/commit.h"
|
#include "git2/commit.h"
|
||||||
#include "git2/blob.h"
|
#include "git2/blob.h"
|
||||||
|
#include "git2/config.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
@ -29,22 +30,26 @@ typedef struct tree_walk_data
|
|||||||
git_indexer_stats *stats;
|
git_indexer_stats *stats;
|
||||||
git_repository *repo;
|
git_repository *repo;
|
||||||
git_odb *odb;
|
git_odb *odb;
|
||||||
|
bool do_symlinks;
|
||||||
} tree_walk_data;
|
} tree_walk_data;
|
||||||
|
|
||||||
|
|
||||||
static int blob_contents_to_link(git_repository *repo, git_buf *fnbuf,
|
static int blob_contents_to_link(tree_walk_data *data, git_buf *fnbuf,
|
||||||
const git_oid *id)
|
const git_oid *id)
|
||||||
{
|
{
|
||||||
int retcode = GIT_ERROR;
|
int retcode = GIT_ERROR;
|
||||||
git_blob *blob;
|
git_blob *blob;
|
||||||
|
|
||||||
/* Get the link target */
|
/* Get the link target */
|
||||||
if (!(retcode = git_blob_lookup(&blob, repo, id))) {
|
if (!(retcode = git_blob_lookup(&blob, data->repo, id))) {
|
||||||
git_buf linktarget = GIT_BUF_INIT;
|
git_buf linktarget = GIT_BUF_INIT;
|
||||||
if (!(retcode = git_blob__getbuf(&linktarget, blob))) {
|
if (!(retcode = git_blob__getbuf(&linktarget, blob))) {
|
||||||
/* Create the link */
|
/* Create the link */
|
||||||
retcode = p_symlink(git_buf_cstr(&linktarget),
|
const char *new = git_buf_cstr(&linktarget),
|
||||||
git_buf_cstr(fnbuf));
|
*old = git_buf_cstr(fnbuf);
|
||||||
|
retcode = data->do_symlinks
|
||||||
|
? p_symlink(new, old)
|
||||||
|
: git_futils_fake_symlink(new, old);
|
||||||
}
|
}
|
||||||
git_buf_free(&linktarget);
|
git_buf_free(&linktarget);
|
||||||
git_blob_free(blob);
|
git_blob_free(blob);
|
||||||
@ -77,7 +82,7 @@ static int blob_contents_to_file(git_repository *repo, git_buf *fnbuf,
|
|||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int checkout_walker(const char *path, git_tree_entry *entry, void *payload)
|
static int checkout_walker(const char *path, const git_tree_entry *entry, void *payload)
|
||||||
{
|
{
|
||||||
int retcode = 0;
|
int retcode = 0;
|
||||||
tree_walk_data *data = (tree_walk_data*)payload;
|
tree_walk_data *data = (tree_walk_data*)payload;
|
||||||
@ -99,7 +104,7 @@ static int checkout_walker(const char *path, git_tree_entry *entry, void *payloa
|
|||||||
path,
|
path,
|
||||||
git_tree_entry_name(entry));
|
git_tree_entry_name(entry));
|
||||||
if (S_ISLNK(attr)) {
|
if (S_ISLNK(attr)) {
|
||||||
retcode = blob_contents_to_link(data->repo, &fnbuf,
|
retcode = blob_contents_to_link(data, &fnbuf,
|
||||||
git_tree_entry_id(entry));
|
git_tree_entry_id(entry));
|
||||||
} else {
|
} else {
|
||||||
retcode = blob_contents_to_file(data->repo, &fnbuf,
|
retcode = blob_contents_to_file(data->repo, &fnbuf,
|
||||||
@ -125,6 +130,7 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
|
|||||||
git_indexer_stats dummy_stats;
|
git_indexer_stats dummy_stats;
|
||||||
git_tree *tree;
|
git_tree *tree;
|
||||||
tree_walk_data payload;
|
tree_walk_data payload;
|
||||||
|
git_config *cfg;
|
||||||
|
|
||||||
assert(repo);
|
assert(repo);
|
||||||
if (!stats) stats = &dummy_stats;
|
if (!stats) stats = &dummy_stats;
|
||||||
@ -134,6 +140,15 @@ int git_checkout_force(git_repository *repo, git_indexer_stats *stats)
|
|||||||
return GIT_ERROR;
|
return GIT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine if symlinks should be handled */
|
||||||
|
if (!git_repository_config(&cfg, repo)) {
|
||||||
|
int temp = true;
|
||||||
|
if (!git_config_get_bool(&temp, cfg, "core.symlinks")) {
|
||||||
|
payload.do_symlinks = !!temp;
|
||||||
|
}
|
||||||
|
git_config_free(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
stats->total = stats->processed = 0;
|
stats->total = stats->processed = 0;
|
||||||
payload.stats = stats;
|
payload.stats = stats;
|
||||||
payload.repo = repo;
|
payload.repo = repo;
|
||||||
|
@ -230,7 +230,7 @@ static int find_and_add_filter(git_vector *filters, git_repository *repo, const
|
|||||||
static int crlf_apply_to_workdir(git_filter *self, git_buf *dest, const git_buf *source)
|
static int crlf_apply_to_workdir(git_filter *self, git_buf *dest, const git_buf *source)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path)
|
int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const char *path)
|
||||||
|
@ -480,3 +480,14 @@ int git_futils_find_global_file(git_buf *path, const char *filename)
|
|||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int git_futils_fake_symlink(const char *old, const char *new)
|
||||||
|
{
|
||||||
|
int retcode = GIT_ERROR;
|
||||||
|
int fd = git_futils_creat_withpath(new, 0755, 0644);
|
||||||
|
if (fd >= 0) {
|
||||||
|
retcode = p_write(fd, old, strlen(old));
|
||||||
|
p_close(fd);
|
||||||
|
}
|
||||||
|
return retcode;
|
||||||
|
}
|
||||||
|
@ -179,4 +179,14 @@ extern int git_futils_find_global_file(git_buf *path, const char *filename);
|
|||||||
*/
|
*/
|
||||||
extern int git_futils_find_system_file(git_buf *path, const char *filename);
|
extern int git_futils_find_system_file(git_buf *path, const char *filename);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a "fake" symlink (text file containing the target path).
|
||||||
|
*
|
||||||
|
* @param new symlink file to be created
|
||||||
|
* @param old original symlink target
|
||||||
|
* @return 0 on success, -1 on error
|
||||||
|
*/
|
||||||
|
extern int git_futils_fake_symlink(const char *new, const char *old);
|
||||||
|
|
||||||
#endif /* INCLUDE_fileops_h__ */
|
#endif /* INCLUDE_fileops_h__ */
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../posix.h"
|
#include "../posix.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "utf-conv.h"
|
#include "utf-conv.h"
|
||||||
|
#include "repository.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -219,8 +220,10 @@ int p_readlink(const char *link, char *target, size_t target_len)
|
|||||||
|
|
||||||
int p_symlink(const char *old, const char *new)
|
int p_symlink(const char *old, const char *new)
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* Real symlinks on NTFS require admin privileges. Until this changes,
|
||||||
return -1;
|
* libgit2 just creates a text file with the link target in the contents.
|
||||||
|
*/
|
||||||
|
return git_futils_fake_symlink(old, new);
|
||||||
}
|
}
|
||||||
|
|
||||||
int p_open(const char *path, int flags, ...)
|
int p_open(const char *path, int flags, ...)
|
||||||
|
@ -12,7 +12,10 @@ static git_repository *g_repo;
|
|||||||
|
|
||||||
void test_checkout_checkout__initialize(void)
|
void test_checkout_checkout__initialize(void)
|
||||||
{
|
{
|
||||||
|
const char *attributes = "*.txt text eol=cr\n";
|
||||||
|
|
||||||
g_repo = cl_git_sandbox_init("testrepo");
|
g_repo = cl_git_sandbox_init("testrepo");
|
||||||
|
cl_git_mkfile("./testrepo/.gitattributes", attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_checkout_checkout__cleanup(void)
|
void test_checkout_checkout__cleanup(void)
|
||||||
@ -26,7 +29,7 @@ static void test_file_contents(const char *path, const char *expectedcontents)
|
|||||||
int fd;
|
int fd;
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
fd = p_open(path, O_RDONLY);
|
fd = p_open(path, O_RDONLY);
|
||||||
cl_assert(fd);
|
cl_assert(fd >= 0);
|
||||||
cl_assert_equal_i(p_read(fd, buffer, 1024), strlen(expectedcontents));
|
cl_assert_equal_i(p_read(fd, buffer, 1024), strlen(expectedcontents));
|
||||||
cl_assert_equal_s(expectedcontents, buffer);
|
cl_assert_equal_s(expectedcontents, buffer);
|
||||||
cl_git_pass(p_close(fd));
|
cl_git_pass(p_close(fd));
|
||||||
@ -67,15 +70,34 @@ void test_checkout_checkout__stats(void)
|
|||||||
/* TODO */
|
/* TODO */
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_checkout_checkout__links(void)
|
void test_checkout_checkout__symlinks(void)
|
||||||
{
|
{
|
||||||
char link_data[1024];
|
git_config *cfg;
|
||||||
size_t link_size = 1024;
|
|
||||||
|
|
||||||
|
cl_git_pass(git_repository_config(&cfg, g_repo));
|
||||||
|
|
||||||
|
/* First try with symlinks forced on */
|
||||||
|
cl_git_pass(git_config_set_bool(cfg, "core.symlinks", true));
|
||||||
cl_git_pass(git_checkout_force(g_repo, NULL));
|
cl_git_pass(git_checkout_force(g_repo, NULL));
|
||||||
link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size);
|
|
||||||
cl_assert_equal_i(link_size, strlen("new.txt"));
|
#ifdef GIT_WIN32
|
||||||
link_data[link_size] = '\0';
|
test_file_contents("./testrepo/link_to_new.txt", "new.txt");
|
||||||
cl_assert_equal_s(link_data, "new.txt");
|
#else
|
||||||
test_file_contents("./testrepo/link_to_new.txt", "my new file\n");
|
{
|
||||||
|
char link_data[1024];
|
||||||
|
size_t link_size = 1024;
|
||||||
|
|
||||||
|
link_size = p_readlink("./testrepo/link_to_new.txt", link_data, link_size);
|
||||||
|
link_data[link_size] = '\0';
|
||||||
|
cl_assert_equal_i(link_size, strlen("new.txt"));
|
||||||
|
cl_assert_equal_s(link_data, "new.txt");
|
||||||
|
test_file_contents("./testrepo/link_to_new.txt", "my new file\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Now with symlinks forced off */
|
||||||
|
cl_git_pass(git_config_set_bool(cfg, "core.symlinks", false));
|
||||||
|
cl_git_pass(git_checkout_force(g_repo, NULL));
|
||||||
|
|
||||||
|
test_file_contents("./testrepo/link_to_new.txt", "new.txt");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user