Skip to content

Commit 0bd547a

Browse files
committed
attr: introduce GIT_ATTR_CHECK_INCLUDE_COMMIT
Introduce `GIT_ATTR_CHECK_INCLUDE_COMMIT`, which like 4fd5748 allows attribute information to be read from files in the repository. 4fd5748 always reads the information from HEAD, while `GIT_ATTR_CHECK_INCLUDE_COMMIT` allows users to provide the commit to read the attributes from.
1 parent 093d579 commit 0bd547a

File tree

5 files changed

+71
-17
lines changed

5 files changed

+71
-17
lines changed

include/git2/attr.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,13 @@ GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
130130
*
131131
* Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes
132132
* from a `.gitattributes` file in the repository at the HEAD revision.
133+
*
134+
* Passing the `GIT_ATTR_CHECK_INCLUDE_COMMIT` flag will use attributes
135+
* from a `.gitattributes` file in a specific commit.
133136
*/
134137
#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
135138
#define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3)
139+
#define GIT_ATTR_CHECK_INCLUDE_COMMIT (1 << 4)
136140

137141
/**
138142
* An options structure for querying attributes.
@@ -142,6 +146,12 @@ typedef struct {
142146

143147
/** A combination of GIT_ATTR_CHECK flags */
144148
unsigned int flags;
149+
150+
/**
151+
* The commit to load attributes from, when
152+
* `GIT_ATTR_CHECK_INCLUDE_COMMIT` is specified.
153+
*/
154+
git_oid *commit_id;
145155
} git_attr_options;
146156

147157
#define GIT_ATTR_OPTIONS_VERSION 1

src/attr.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,9 @@ static int attr_setup(
381381
git_attr_options *opts)
382382
{
383383
git_buf system = GIT_BUF_INIT, info = GIT_BUF_INIT;
384-
git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE };
385-
git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE };
384+
git_attr_file_source index_source = { GIT_ATTR_FILE_SOURCE_INDEX, NULL, GIT_ATTR_FILE, NULL };
385+
git_attr_file_source head_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL };
386+
git_attr_file_source commit_source = { GIT_ATTR_FILE_SOURCE_COMMIT, NULL, GIT_ATTR_FILE, NULL };
386387
git_index *idx = NULL;
387388
const char *workdir;
388389
int error = 0;
@@ -430,6 +431,13 @@ static int attr_setup(
430431
(error = preload_attr_source(repo, attr_session, &head_source)) < 0)
431432
goto out;
432433

434+
if ((opts && (opts->flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0)) {
435+
commit_source.commit_id = opts->commit_id;
436+
437+
if ((error = preload_attr_source(repo, attr_session, &commit_source)) < 0)
438+
goto out;
439+
}
440+
433441
if (attr_session)
434442
attr_session->init_setup = 1;
435443

@@ -480,7 +488,7 @@ int git_attr_add_macro(
480488
typedef struct {
481489
git_repository *repo;
482490
git_attr_session *attr_session;
483-
uint32_t flags;
491+
git_attr_options *opts;
484492
const char *workdir;
485493
git_index *index;
486494
git_vector *files;
@@ -513,7 +521,8 @@ static int attr_decide_sources(
513521
break;
514522
}
515523

516-
if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0)
524+
if ((flags & GIT_ATTR_CHECK_INCLUDE_HEAD) != 0 ||
525+
(flags & GIT_ATTR_CHECK_INCLUDE_COMMIT) != 0)
517526
srcs[count++] = GIT_ATTR_FILE_SOURCE_COMMIT;
518527

519528
return count;
@@ -563,13 +572,19 @@ static int push_one_attr(void *ref, const char *path)
563572
int error = 0, n_src, i;
564573
bool allow_macros;
565574

566-
n_src = attr_decide_sources(
567-
info->flags, info->workdir != NULL, info->index != NULL, src);
575+
n_src = attr_decide_sources(info->opts ? info->opts->flags : 0,
576+
info->workdir != NULL,
577+
info->index != NULL,
578+
src);
579+
568580
allow_macros = info->workdir ? !strcmp(info->workdir, path) : false;
569581

570582
for (i = 0; !error && i < n_src; ++i) {
571583
git_attr_file_source source = { src[i], path, GIT_ATTR_FILE };
572584

585+
if (src[i] == GIT_ATTR_FILE_SOURCE_COMMIT && info->opts)
586+
source.commit_id = info->opts->commit_id;
587+
573588
error = push_attr_source(info->repo, info->attr_session, info->files,
574589
&source, allow_macros);
575590
}
@@ -631,7 +646,7 @@ static int collect_attr_files(
631646

632647
info.repo = repo;
633648
info.attr_session = attr_session;
634-
info.flags = opts ? opts->flags : 0;
649+
info.opts = opts;
635650
info.workdir = workdir;
636651
if (git_repository_index__weakptr(&info.index, repo) < 0)
637652
git_error_clear(); /* no error even if there is no index */

src/attr_file.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ int git_attr_file__load(
113113
bool allow_macros)
114114
{
115115
int error = 0;
116+
git_commit *commit = NULL;
116117
git_tree *tree = NULL;
117118
git_tree_entry *tree_entry = NULL;
118119
git_blob *blob = NULL;
@@ -163,8 +164,14 @@ int git_attr_file__load(
163164
break;
164165
}
165166
case GIT_ATTR_FILE_SOURCE_COMMIT: {
166-
if ((error = git_repository_head_tree(&tree, repo)) < 0)
167-
goto cleanup;
167+
if (source->commit_id) {
168+
if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0 ||
169+
(error = git_commit_tree(&tree, commit)) < 0)
170+
goto cleanup;
171+
} else {
172+
if ((error = git_repository_head_tree(&tree, repo)) < 0)
173+
goto cleanup;
174+
}
168175

169176
if ((error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0) {
170177
/*
@@ -239,6 +246,7 @@ int git_attr_file__load(
239246
git_blob_free(blob);
240247
git_tree_entry_free(tree_entry);
241248
git_tree_free(tree);
249+
git_commit_free(commit);
242250
git_buf_dispose(&content);
243251

244252
return error;
@@ -247,7 +255,8 @@ int git_attr_file__load(
247255
int git_attr_file__out_of_date(
248256
git_repository *repo,
249257
git_attr_session *attr_session,
250-
git_attr_file *file)
258+
git_attr_file *file,
259+
git_attr_file_source *source)
251260
{
252261
if (!file)
253262
return 1;
@@ -280,13 +289,26 @@ int git_attr_file__out_of_date(
280289
}
281290

282291
case GIT_ATTR_FILE_SOURCE_COMMIT: {
283-
git_tree *tree;
292+
git_tree *tree = NULL;
284293
int error;
285294

286-
if ((error = git_repository_head_tree(&tree, repo)) < 0)
295+
if (source->commit_id) {
296+
git_commit *commit = NULL;
297+
298+
if ((error = git_commit_lookup(&commit, repo, source->commit_id)) < 0)
299+
return error;
300+
301+
error = git_commit_tree(&tree, commit);
302+
303+
git_commit_free(commit);
304+
} else {
305+
error = git_repository_head_tree(&tree, repo);
306+
}
307+
308+
if (error < 0)
287309
return error;
288310

289-
error = git_oid__cmp(&file->cache_data.oid, git_tree_id(tree));
311+
error = (git_oid__cmp(&file->cache_data.oid, git_tree_id(tree)) != 0);
290312

291313
git_tree_free(tree);
292314
return error;

src/attr_file.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ typedef struct {
5555
*/
5656
const char *base;
5757
const char *filename;
58+
59+
/*
60+
* The commit ID when the given source type is a commit (or NULL
61+
* for the repository's HEAD commit.)
62+
*/
63+
git_oid *commit_id;
5864
} git_attr_file_source;
5965

6066
extern const char *git_attr__true;
@@ -171,7 +177,7 @@ int git_attr_file__load_standalone(
171177
git_attr_file **out, const char *path);
172178

173179
int git_attr_file__out_of_date(
174-
git_repository *repo, git_attr_session *session, git_attr_file *file);
180+
git_repository *repo, git_attr_session *session, git_attr_file *file, git_attr_file_source *source);
175181

176182
int git_attr_file__parse_buffer(
177183
git_repository *repo, git_attr_file *attrs, const char *data, bool allow_macros);

src/attrcache.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,17 @@ int git_attr_cache__get(
224224
return error;
225225

226226
/* load file if we don't have one or if existing one is out of date */
227-
if (!file || (error = git_attr_file__out_of_date(repo, attr_session, file)) > 0)
227+
if (!file ||
228+
(error = git_attr_file__out_of_date(repo, attr_session, file, source)) > 0)
228229
error = git_attr_file__load(&updated, repo, attr_session,
229230
entry, source, parser,
230231
allow_macros);
231232

232233
/* if we loaded the file, insert into and/or update cache */
233234
if (updated) {
234-
if ((error = attr_cache_upsert(cache, updated)) < 0)
235+
if ((error = attr_cache_upsert(cache, updated)) < 0) {
235236
git_attr_file__free(updated);
236-
else {
237+
} else {
237238
git_attr_file__free(file); /* offset incref from lookup */
238239
file = updated;
239240
}

0 commit comments

Comments
 (0)