Skip to content

Commit 1439b9f

Browse files
committed
filter: introduce GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT
Provide a mechanism to filter using attribute data from a specific commit (making use of `GIT_ATTR_CHECK_INCLUDE_COMMIT`).
1 parent 0bd547a commit 1439b9f

File tree

12 files changed

+104
-5
lines changed

12 files changed

+104
-5
lines changed

include/git2/blob.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ typedef enum {
114114
* in the HEAD commit.
115115
*/
116116
GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD = (1 << 2),
117+
118+
/**
119+
* When set, filters will be loaded from a `.gitattributes` file
120+
* in the specified commit.
121+
*/
122+
GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT = (1 << 3),
117123
} git_blob_filter_flag_t;
118124

119125
/**
@@ -128,6 +134,12 @@ typedef struct {
128134

129135
/** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
130136
uint32_t flags;
137+
138+
/**
139+
* The commit to load attributes from, when
140+
* `GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
141+
*/
142+
git_oid *commit_id;
131143
} git_blob_filter_options;
132144

133145
#define GIT_BLOB_FILTER_OPTIONS_VERSION 1

include/git2/filter.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ typedef enum {
4949

5050
/** Load attributes from `.gitattributes` in the root of HEAD */
5151
GIT_FILTER_ATTRIBUTES_FROM_HEAD = (1u << 2),
52+
53+
/**
54+
* Load attributes from `.gitattributes` in a given commit.
55+
* This can only be specified in a `git_filter_options`.
56+
*/
57+
GIT_FILTER_ATTRIBUTES_FROM_COMMIT = (1u << 3),
5258
} git_filter_flag_t;
5359

5460
/**
@@ -59,6 +65,12 @@ typedef struct {
5965

6066
/** See `git_filter_flag_t` above */
6167
uint32_t flags;
68+
69+
/**
70+
* The commit to load attributes from, when
71+
* `GIT_FILTER_ATTRIBUTES_FROM_COMMIT` is specified.
72+
*/
73+
git_oid *commit_id;
6274
} git_filter_options;
6375

6476
#define GIT_FILTER_OPTIONS_VERSION 1

src/blob.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ int git_blob_filter(
421421
int error = 0;
422422
git_filter_list *fl = NULL;
423423
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
424-
git_filter_flag_t flags = GIT_FILTER_DEFAULT;
424+
git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT;
425425

426426
GIT_ASSERT_ARG(blob);
427427
GIT_ASSERT_ARG(path);
@@ -441,14 +441,19 @@ int git_blob_filter(
441441
return 0;
442442

443443
if ((opts.flags & GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES) != 0)
444-
flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
444+
filter_opts.flags |= GIT_FILTER_NO_SYSTEM_ATTRIBUTES;
445445

446446
if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
447-
flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
447+
filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_HEAD;
448448

449-
if (!(error = git_filter_list_load(
449+
if ((opts.flags & GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
450+
filter_opts.flags |= GIT_FILTER_ATTRIBUTES_FROM_COMMIT;
451+
filter_opts.commit_id = opts.commit_id;
452+
}
453+
454+
if (!(error = git_filter_list_load_ext(
450455
&fl, git_blob_owner(blob), blob, path,
451-
GIT_FILTER_TO_WORKTREE, flags))) {
456+
GIT_FILTER_TO_WORKTREE, &filter_opts))) {
452457

453458
error = git_filter_list_apply_to_blob(out, fl, blob);
454459

src/filter.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,11 @@ static int filter_list_check_attributes(
443443
if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0)
444444
attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD;
445445

446+
if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) {
447+
attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_COMMIT;
448+
attr_opts.commit_id = src->options.commit_id;
449+
}
450+
446451
error = git_attr_get_many_with_session(
447452
strs, repo, filter_session->attr_session, &attr_opts, src->path, fdef->nattrs, fdef->attrs);
448453

tests/filter/bare.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,63 @@ void test_filter_bare__sanitizes(void)
132132
git_blob_free(blob);
133133
}
134134

135+
void test_filter_bare__from_specific_commit_one(void)
136+
{
137+
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
138+
git_blob *blob;
139+
git_buf buf = { 0 };
140+
git_oid commit_id;
141+
142+
cl_git_pass(git_oid_fromstr(&commit_id, "b8986fec0f7bde90f78ac72706e782d82f24f2f0"));
143+
144+
opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
145+
opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
146+
opts.commit_id = &commit_id;
147+
148+
cl_git_pass(git_revparse_single(
149+
(git_object **)&blob, g_repo, "055c872")); /* ident */
150+
151+
cl_assert_equal_s("$Id$\n", git_blob_rawcontent(blob));
152+
153+
cl_git_pass(git_blob_filter(&buf, blob, "ident.bin", &opts));
154+
cl_assert_equal_s("$Id$\n", buf.ptr);
155+
156+
cl_git_pass(git_blob_filter(&buf, blob, "ident.identlf", &opts));
157+
cl_assert_equal_s("$Id: 055c8729cdcc372500a08db659c045e16c4409fb $\n", buf.ptr);
158+
159+
git_buf_dispose(&buf);
160+
git_blob_free(blob);
161+
}
162+
163+
void test_filter_bare__from_specific_commit_with_no_attributes_file(void)
164+
{
165+
git_blob_filter_options opts = GIT_BLOB_FILTER_OPTIONS_INIT;
166+
git_blob *blob;
167+
git_buf buf = { 0 };
168+
git_oid commit_id;
169+
170+
cl_git_pass(git_oid_fromstr(&commit_id, "5afb6a14a864e30787857dd92af837e8cdd2cb1b"));
171+
172+
opts.flags |= GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES;
173+
opts.flags |= GIT_BLOB_FILTER_ATTRIBUTES_FROM_COMMIT;
174+
opts.commit_id = &commit_id;
175+
176+
cl_git_pass(git_revparse_single(
177+
(git_object **)&blob, g_repo, "799770d")); /* all-lf */
178+
179+
cl_assert_equal_s(ALL_LF_TEXT_RAW, git_blob_rawcontent(blob));
180+
181+
cl_git_pass(git_blob_filter(&buf, blob, "file.bin", &opts));
182+
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
183+
184+
/* we never convert CRLF -> LF on platforms that have LF */
185+
cl_git_pass(git_blob_filter(&buf, blob, "file.lf", &opts));
186+
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
187+
188+
/* we never convert CRLF -> LF on platforms that have LF */
189+
cl_git_pass(git_blob_filter(&buf, blob, "file.crlf", &opts));
190+
cl_assert_equal_s(ALL_LF_TEXT_RAW, buf.ptr);
191+
192+
git_buf_dispose(&buf);
193+
git_blob_free(blob);
194+
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

tests/resources/crlf.git/objects/b8/986fec0f7bde90f78ac72706e782d82f24f2f0

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
x��M
2+
�0�]�s%3�Dt���$�b�6�F��Q�����2Mc�nSWU`�6*��C��ĽG�w��,�|S��,��\�����#��Y��8t�);q��ȳ��
3+
���5��V�G��-���~��ۥ2=�`��ֲ���ml�?1�3� cn��H�]a�j�@�U

0 commit comments

Comments
 (0)