Unverified Commit 853ba203 by Edward Thomson Committed by GitHub

Merge pull request #6073 from libgit2/ethomson/attr_lookups

parents a6f6a9f4 091bd738
...@@ -762,13 +762,15 @@ GIT_EXTERN(int) git_repository_mergehead_foreach( ...@@ -762,13 +762,15 @@ GIT_EXTERN(int) git_repository_mergehead_foreach(
* *
* @param out Output value of calculated SHA * @param out Output value of calculated SHA
* @param repo Repository pointer * @param repo Repository pointer
* @param path Path to file on disk whose contents should be hashed. If the * @param path Path to file on disk whose contents should be hashed. This
* repository is not NULL, this can be a relative path. * may be an absolute path or a relative path, in which case it
* will be treated as a path within the working directory.
* @param type The object type to hash as (e.g. GIT_OBJECT_BLOB) * @param type The object type to hash as (e.g. GIT_OBJECT_BLOB)
* @param as_path The path to use to look up filtering rules. If this is * @param as_path The path to use to look up filtering rules. If this is
* NULL, then the `path` parameter will be used instead. If * an empty string then no filters will be applied when
* this is passed as the empty string, then no filters will be * calculating the hash. If this is `NULL` and the `path`
* applied when calculating the hash. * parameter is a file within the repository's working
* directory, then the `path` will be used.
* @return 0 on success, or an error code * @return 0 on success, or an error code
*/ */
GIT_EXTERN(int) git_repository_hashfile( GIT_EXTERN(int) git_repository_hashfile(
......
...@@ -629,6 +629,8 @@ static int collect_attr_files( ...@@ -629,6 +629,8 @@ static int collect_attr_files(
const char *workdir = git_repository_workdir(repo); const char *workdir = git_repository_workdir(repo);
attr_walk_up_info info = { NULL }; attr_walk_up_info info = { NULL };
GIT_ASSERT(!git_path_is_absolute(path));
if ((error = attr_setup(repo, attr_session, opts)) < 0) if ((error = attr_setup(repo, attr_session, opts)) < 0)
return error; return error;
......
...@@ -277,21 +277,20 @@ int git_blob_create_from_disk( ...@@ -277,21 +277,20 @@ int git_blob_create_from_disk(
{ {
int error; int error;
git_buf full_path = GIT_BUF_INIT; git_buf full_path = GIT_BUF_INIT;
const char *workdir, *hintpath; const char *workdir, *hintpath = NULL;
if ((error = git_path_prettify(&full_path, path, NULL)) < 0) { if ((error = git_path_prettify(&full_path, path, NULL)) < 0) {
git_buf_dispose(&full_path); git_buf_dispose(&full_path);
return error; return error;
} }
hintpath = git_buf_cstr(&full_path);
workdir = git_repository_workdir(repo); workdir = git_repository_workdir(repo);
if (workdir && !git__prefixcmp(hintpath, workdir)) if (workdir && !git__prefixcmp(full_path.ptr, workdir))
hintpath += strlen(workdir); hintpath = full_path.ptr + strlen(workdir);
error = git_blob__create_from_paths( error = git_blob__create_from_paths(
id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true); id, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, !!hintpath);
git_buf_dispose(&full_path); git_buf_dispose(&full_path);
return error; return error;
......
...@@ -1520,8 +1520,7 @@ static int blob_content_to_file( ...@@ -1520,8 +1520,7 @@ static int blob_content_to_file(
int fd; int fd;
int error = 0; int error = 0;
if (hint_path == NULL) GIT_ASSERT(hint_path != NULL);
hint_path = path;
if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0) if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
return error; return error;
...@@ -1789,7 +1788,7 @@ static int checkout_blob( ...@@ -1789,7 +1788,7 @@ static int checkout_blob(
} }
error = checkout_write_content( error = checkout_write_content(
data, &file->id, fullpath->ptr, NULL, file->mode, &st); data, &file->id, fullpath->ptr, file->path, file->mode, &st);
/* update the index unless prevented */ /* update the index unless prevented */
if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
...@@ -1975,7 +1974,7 @@ static int checkout_write_entry( ...@@ -1975,7 +1974,7 @@ static int checkout_write_entry(
checkout_conflictdata *conflict, checkout_conflictdata *conflict,
const git_index_entry *side) const git_index_entry *side)
{ {
const char *hint_path = NULL, *suffix; const char *hint_path, *suffix;
git_buf *fullpath; git_buf *fullpath;
struct stat st; struct stat st;
int error; int error;
...@@ -1998,10 +1997,10 @@ static int checkout_write_entry( ...@@ -1998,10 +1997,10 @@ static int checkout_write_entry(
if (checkout_path_suffixed(fullpath, suffix) < 0) if (checkout_path_suffixed(fullpath, suffix) < 0)
return -1; return -1;
hint_path = side->path;
} }
hint_path = side->path;
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 && if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
(error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0) (error = checkout_safe_for_update_only(data, fullpath->ptr, side->mode)) <= 0)
return error; return error;
...@@ -2118,7 +2117,7 @@ static int checkout_write_merge( ...@@ -2118,7 +2117,7 @@ static int checkout_write_merge(
filter_session.temp_buf = &data->tmp; filter_session.temp_buf = &data->tmp;
if ((error = git_filter_list__load( if ((error = git_filter_list__load(
&fl, data->repo, NULL, git_buf_cstr(&path_workdir), &fl, data->repo, NULL, result.path,
GIT_FILTER_TO_WORKTREE, &filter_session)) < 0 || GIT_FILTER_TO_WORKTREE, &filter_session)) < 0 ||
(error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0) (error = git_filter_list__convert_buf(&out_data, fl, &in_data)) < 0)
goto done; goto done;
......
...@@ -2840,34 +2840,36 @@ int git_repository_hashfile( ...@@ -2840,34 +2840,36 @@ int git_repository_hashfile(
git_file fd = -1; git_file fd = -1;
uint64_t len; uint64_t len;
git_buf full_path = GIT_BUF_INIT; git_buf full_path = GIT_BUF_INIT;
const char *workdir = git_repository_workdir(repo);
/* as_path can be NULL */ /* as_path can be NULL */
GIT_ASSERT_ARG(out); GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(path); GIT_ASSERT_ARG(path);
GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(repo);
/* At some point, it would be nice if repo could be NULL to just if ((error = git_path_join_unrooted(&full_path, path, workdir, NULL)) < 0 ||
* apply filter rules defined in system and global files, but for
* now that is not possible because git_filters_load() needs it.
*/
if ((error = git_path_join_unrooted(
&full_path, path, git_repository_workdir(repo), NULL)) < 0 ||
(error = git_path_validate_workdir_buf(repo, &full_path)) < 0) (error = git_path_validate_workdir_buf(repo, &full_path)) < 0)
return error; return error;
if (!as_path) /*
as_path = path; * NULL as_path means that we should derive it from the
* given path.
*/
if (!as_path) {
if (workdir && !git__prefixcmp(full_path.ptr, workdir))
as_path = full_path.ptr + strlen(workdir);
else
as_path = "";
}
/* passing empty string for "as_path" indicated --no-filters */ /* passing empty string for "as_path" indicated --no-filters */
if (strlen(as_path) > 0) { if (strlen(as_path) > 0) {
error = git_filter_list_load( error = git_filter_list_load(
&fl, repo, NULL, as_path, &fl, repo, NULL, as_path,
GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT);
if (error < 0) if (error < 0)
return error; return error;
} else {
error = 0;
} }
/* at this point, error is a count of the number of loaded filters */ /* at this point, error is a count of the number of loaded filters */
......
...@@ -648,6 +648,8 @@ int p_getcwd(char *buffer_out, size_t size) ...@@ -648,6 +648,8 @@ int p_getcwd(char *buffer_out, size_t size)
if (!cwd) if (!cwd)
return -1; return -1;
git_win32_path_remove_namespace(cwd, wcslen(cwd));
/* Convert the working directory back to UTF-8 */ /* Convert the working directory back to UTF-8 */
if (git__utf16_to_8(buffer_out, size, cwd) < 0) { if (git__utf16_to_8(buffer_out, size, cwd) < 0) {
DWORD code = GetLastError(); DWORD code = GetLastError();
...@@ -660,6 +662,7 @@ int p_getcwd(char *buffer_out, size_t size) ...@@ -660,6 +662,7 @@ int p_getcwd(char *buffer_out, size_t size)
return -1; return -1;
} }
git_path_mkposix(buffer_out);
return 0; return 0;
} }
......
...@@ -10,6 +10,7 @@ void test_repo_hashfile__initialize(void) ...@@ -10,6 +10,7 @@ void test_repo_hashfile__initialize(void)
void test_repo_hashfile__cleanup(void) void test_repo_hashfile__cleanup(void)
{ {
cl_fixture_cleanup("absolute");
cl_git_sandbox_cleanup(); cl_git_sandbox_cleanup();
_repo = NULL; _repo = NULL;
} }
...@@ -38,10 +39,18 @@ void test_repo_hashfile__simple(void) ...@@ -38,10 +39,18 @@ void test_repo_hashfile__simple(void)
git_buf_dispose(&full); git_buf_dispose(&full);
} }
void test_repo_hashfile__filtered(void) void test_repo_hashfile__filtered_in_workdir(void)
{ {
git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT;
char cwd[GIT_PATH_MAX];
git_oid a, b; git_oid a, b;
cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX));
cl_must_pass(p_mkdir("absolute", 0777));
cl_git_pass(git_buf_joinpath(&root, cwd, "status"));
cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt"));
cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin"));
cl_repo_set_bool(_repo, "core.autocrlf", true); cl_repo_set_bool(_repo, "core.autocrlf", true);
cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n"); cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n");
...@@ -55,21 +64,41 @@ void test_repo_hashfile__filtered(void) ...@@ -55,21 +64,41 @@ void test_repo_hashfile__filtered(void)
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, NULL)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, NULL));
cl_assert(git_oid_cmp(&a, &b)); cl_assert(git_oid_cmp(&a, &b));
/* not equal hashes because of filtering when specified by absolute path */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL));
cl_assert(git_oid_cmp(&a, &b));
/* equal hashes because filter is binary */ /* equal hashes because filter is binary */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, NULL)); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b); cl_assert_equal_oid(&a, &b);
/* equal hashes because filter is binary when specified by absolute path */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
/* equal hashes when 'as_file' points to binary filtering */ /* equal hashes when 'as_file' points to binary filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "foo.bin")); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "foo.bin"));
cl_assert_equal_oid(&a, &b); cl_assert_equal_oid(&a, &b);
/* equal hashes when 'as_file' points to binary filtering (absolute path) */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "foo.bin"));
cl_assert_equal_oid(&a, &b);
/* not equal hashes when 'as_file' points to text filtering */ /* not equal hashes when 'as_file' points to text filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "foo.txt")); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "foo.txt"));
cl_assert(git_oid_cmp(&a, &b)); cl_assert(git_oid_cmp(&a, &b));
/* not equal hashes when 'as_file' points to text filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "foo.txt"));
cl_assert(git_oid_cmp(&a, &b));
/* equal hashes when 'as_file' is empty and turns off filtering */ /* equal hashes when 'as_file' is empty and turns off filtering */
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB)); cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, "")); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_BLOB, ""));
...@@ -79,7 +108,65 @@ void test_repo_hashfile__filtered(void) ...@@ -79,7 +108,65 @@ void test_repo_hashfile__filtered(void)
cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, "")); cl_git_pass(git_repository_hashfile(&b, _repo, "testfile.bin", GIT_OBJECT_BLOB, ""));
cl_assert_equal_oid(&a, &b); cl_assert_equal_oid(&a, &b);
cl_git_pass(git_odb_hashfile(&a, "status/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, ""));
cl_assert_equal_oid(&a, &b);
cl_git_pass(git_odb_hashfile(&a, "status/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, ""));
cl_assert_equal_oid(&a, &b);
/* some hash type failures */ /* some hash type failures */
cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0)); cl_git_fail(git_odb_hashfile(&a, "status/testfile.txt", 0));
cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_ANY, NULL)); cl_git_fail(git_repository_hashfile(&b, _repo, "testfile.txt", GIT_OBJECT_ANY, NULL));
git_buf_dispose(&txt);
git_buf_dispose(&bin);
git_buf_dispose(&root);
}
void test_repo_hashfile__filtered_outside_workdir(void)
{
git_buf root = GIT_BUF_INIT, txt = GIT_BUF_INIT, bin = GIT_BUF_INIT;
char cwd[GIT_PATH_MAX];
git_oid a, b;
cl_must_pass(p_getcwd(cwd, GIT_PATH_MAX));
cl_must_pass(p_mkdir("absolute", 0777));
cl_git_pass(git_buf_joinpath(&root, cwd, "absolute"));
cl_git_pass(git_buf_joinpath(&txt, root.ptr, "testfile.txt"));
cl_git_pass(git_buf_joinpath(&bin, root.ptr, "testfile.bin"));
cl_repo_set_bool(_repo, "core.autocrlf", true);
cl_git_append2file("status/.gitattributes", "*.txt text\n*.bin binary\n\n");
/* create some sample content with CRLF in it */
cl_git_mkfile("absolute/testfile.txt", "content\r\n");
cl_git_mkfile("absolute/testfile.bin", "other\r\nstuff\r\n");
/* not equal hashes because of filtering */
cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, "testfile.txt"));
cl_assert(git_oid_cmp(&a, &b));
/* equal hashes because filter is binary */
cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, "testfile.bin"));
cl_assert_equal_oid(&a, &b);
/*
* equal hashes because no filtering occurs for absolute paths outside the working
* directory unless as_path is specified
*/
cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.txt", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, txt.ptr, GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
cl_git_pass(git_odb_hashfile(&a, "absolute/testfile.bin", GIT_OBJECT_BLOB));
cl_git_pass(git_repository_hashfile(&b, _repo, bin.ptr, GIT_OBJECT_BLOB, NULL));
cl_assert_equal_oid(&a, &b);
git_buf_dispose(&txt);
git_buf_dispose(&bin);
git_buf_dispose(&root);
} }
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