summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-09-11 16:38:33 -0700
committerRussell Belfer <rb@github.com>2013-09-17 09:31:45 -0700
commit4b11f25a4fbb6952284e037a70e2d61fde841ab6 (patch)
tree41929ce26c3c41183b3fc221927afb67444eadf2 /src
parent40cb40fab93281c808255d980bbe81a18a4d9e9a (diff)
downloadlibgit2-4b11f25a4fbb6952284e037a70e2d61fde841ab6.tar.gz
Add ident filter
This adds the ident filter (that knows how to replace $Id$) and tweaks the filter APIs and code so that git_filter_source objects actually have the updated OID of the object being filtered when it is a known value.
Diffstat (limited to 'src')
-rw-r--r--src/blob.c8
-rw-r--r--src/checkout.c2
-rw-r--r--src/crlf.c7
-rw-r--r--src/diff.c2
-rw-r--r--src/diff_file.c2
-rw-r--r--src/filter.c31
-rw-r--r--src/filter.h3
-rw-r--r--src/ident.c128
-rw-r--r--src/repository.c3
9 files changed, 170 insertions, 16 deletions
diff --git a/src/blob.c b/src/blob.c
index e6bba033a..97fd6f70d 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -195,7 +195,7 @@ int git_blob__create_from_paths(
if (try_load_filters)
/* Load the filters for writing this file to the ODB */
error = git_filter_list_load(
- &fl, repo, hint_path, GIT_FILTER_TO_ODB);
+ &fl, repo, NULL, hint_path, GIT_FILTER_TO_ODB);
if (error < 0)
/* well, that didn't work */;
@@ -331,19 +331,19 @@ int git_blob_is_binary(git_blob *blob)
int git_blob_filtered_content(
git_buffer *out,
git_blob *blob,
- const char *as_path,
+ const char *path,
int check_for_binary_data)
{
int error = 0;
git_filter_list *fl = NULL;
- assert(blob && as_path && out);
+ assert(blob && path && out);
if (check_for_binary_data && git_blob_is_binary(blob))
return 0;
if (!(error = git_filter_list_load(
- &fl, git_blob_owner(blob), as_path, GIT_FILTER_TO_WORKTREE))) {
+ &fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE))) {
error = git_filter_list_apply_to_blob(out, fl, blob);
diff --git a/src/checkout.c b/src/checkout.c
index 1def58b0a..7e79c9b5e 100644
--- a/src/checkout.c
+++ b/src/checkout.c
@@ -718,7 +718,7 @@ static int blob_content_to_file(
if (!opts->disable_filters && !git_blob_is_binary(blob))
error = git_filter_list_load(
- &fl, git_blob_owner(blob), path, GIT_FILTER_TO_WORKTREE);
+ &fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE);
if (!error)
error = git_filter_list_apply_to_blob(&out, fl, blob);
diff --git a/src/crlf.c b/src/crlf.c
index 99c154f70..f61a870da 100644
--- a/src/crlf.c
+++ b/src/crlf.c
@@ -324,11 +324,6 @@ static void crlf_cleanup(
git__free(payload);
}
-static void crlf_shutdown(git_filter *self)
-{
- git__free(self);
-}
-
git_filter *git_crlf_filter_new(void)
{
struct crlf_filter *f = git__calloc(1, sizeof(struct crlf_filter));
@@ -336,7 +331,7 @@ git_filter *git_crlf_filter_new(void)
f->f.version = GIT_FILTER_VERSION;
f->f.attributes = "crlf eol text";
f->f.initialize = NULL;
- f->f.shutdown = crlf_shutdown;
+ f->f.shutdown = git_filter_free;
f->f.check = crlf_check;
f->f.apply = crlf_apply;
f->f.cleanup = crlf_cleanup;
diff --git a/src/diff.c b/src/diff.c
index b1cde36bc..4d9ace183 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -570,7 +570,7 @@ int git_diff__oid_for_file(
} else {
git_filter_list *fl = NULL;
- result = git_filter_list_load(&fl, repo, path, GIT_FILTER_TO_ODB);
+ result = git_filter_list_load(&fl, repo, NULL, path, GIT_FILTER_TO_ODB);
if (!result) {
int fd = git_futils_open_ro(full_path.ptr);
if (fd < 0)
diff --git a/src/diff_file.c b/src/diff_file.c
index e0e244b65..d02787c75 100644
--- a/src/diff_file.c
+++ b/src/diff_file.c
@@ -311,7 +311,7 @@ static int diff_file_content_load_workdir_file(
goto cleanup;
if ((error = git_filter_list_load(
- &fl, fc->repo, fc->file->path, GIT_FILTER_TO_ODB)) < 0)
+ &fl, fc->repo, NULL, fc->file->path, GIT_FILTER_TO_ODB)) < 0)
goto cleanup;
/* if there are no filters, try to mmap the file */
diff --git a/src/filter.c b/src/filter.c
index 79ccac0cf..f20611471 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -103,7 +103,23 @@ static int filter_registry_initialize(void)
git__on_shutdown(filter_registry_shutdown);
- return git_filter_register(GIT_FILTER_CRLF, git_crlf_filter_new(), 0);
+ /* try to register both default filters */
+ {
+ git_filter *crlf = git_crlf_filter_new();
+ git_filter *ident = git_ident_filter_new();
+
+ if (crlf && git_filter_register(
+ GIT_FILTER_CRLF, crlf, GIT_FILTER_CRLF_PRIORITY) < 0)
+ crlf = NULL;
+ if (ident && git_filter_register(
+ GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0)
+ ident = NULL;
+
+ if (!crlf || !ident)
+ return -1;
+ }
+
+ return 0;
cleanup:
git_vector_free(&reg->filters);
@@ -132,7 +148,7 @@ static int filter_def_scan_attrs(
if (scan > start) {
(*nattr)++;
- if (has_eq || *scan == '-' || *scan == '+' || *scan == '!')
+ if (has_eq || *start == '-' || *start == '+' || *start == '!')
(*nmatch)++;
if (has_eq)
@@ -312,6 +328,11 @@ git_filter *git_filter_lookup(const char *name)
return fdef->filter;
}
+void git_filter_free(git_filter *filter)
+{
+ git__free(filter);
+}
+
git_repository *git_filter_source_repo(const git_filter_source *src)
{
return src->repo;
@@ -410,6 +431,7 @@ int git_filter_list_new(
int git_filter_list_load(
git_filter_list **filters,
git_repository *repo,
+ git_blob *blob, /* can be NULL */
const char *path,
git_filter_mode_t mode)
{
@@ -426,6 +448,8 @@ int git_filter_list_load(
src.repo = repo;
src.path = path;
src.mode = mode;
+ if (blob)
+ git_oid_cpy(&src.oid, git_blob_id(blob));
git_vector_foreach(&git__filter_registry->filters, idx, fdef) {
const char **values = NULL;
@@ -630,5 +654,8 @@ int git_filter_list_apply_to_blob(
(char *)git_blob_rawcontent(blob), git_blob_rawsize(blob), 0
};
+ if (filters)
+ git_oid_cpy(&filters->source.oid, git_blob_id(blob));
+
return git_filter_list_apply_to_data(out, filters, &in);
}
diff --git a/src/filter.h b/src/filter.h
index 1bde1e306..d0ace0f9a 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -19,10 +19,13 @@ typedef enum {
GIT_CRLF_AUTO,
} git_crlf_t;
+extern void git_filter_free(git_filter *filter);
+
/*
* Available filters
*/
extern git_filter *git_crlf_filter_new(void);
+extern git_filter *git_ident_filter_new(void);
#endif
diff --git a/src/ident.c b/src/ident.c
new file mode 100644
index 000000000..aedb973f9
--- /dev/null
+++ b/src/ident.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "git2/sys/filter.h"
+#include "filter.h"
+#include "buffer.h"
+
+int ident_find_id(
+ const char **id_start, const char **id_end, const char *start, size_t len)
+{
+ const char *found;
+
+ while (len > 0 && (found = memchr(start, '$', len)) != NULL) {
+ size_t remaining = len - (size_t)(found - start);
+ if (remaining < 3)
+ return GIT_ENOTFOUND;
+ if (found[1] == 'I' && found[2] == 'd')
+ break;
+ start = found + 1;
+ len = remaining - 1;
+ }
+
+ if (len < 3)
+ return GIT_ENOTFOUND;
+ *id_start = found;
+
+ if ((found = memchr(found + 3, '$', len - 3)) == NULL)
+ return GIT_ENOTFOUND;
+
+ *id_end = found + 1;
+ return 0;
+}
+
+static int ident_insert_id(
+ git_buffer *to, const git_buffer *from, const git_filter_source *src)
+{
+ char oid[GIT_OID_HEXSZ+1];
+ const char *id_start, *id_end, *from_end = from->ptr + from->size;
+ size_t need_size;
+ git_buf to_buf = GIT_BUF_FROM_BUFFER(to);
+
+ /* replace $Id$ with blob id */
+
+ if (!git_filter_source_id(src))
+ return GIT_ENOTFOUND;
+
+ git_oid_tostr(oid, sizeof(oid), git_filter_source_id(src));
+
+ if (ident_find_id(&id_start, &id_end, from->ptr, from->size) < 0)
+ return GIT_ENOTFOUND;
+
+ need_size = (size_t)(id_start - from->ptr) +
+ 5 /* "$Id: " */ + GIT_OID_HEXSZ + 1 /* "$" */ +
+ (size_t)(from_end - id_end);
+
+ if (git_buf_grow(&to_buf, need_size) < 0)
+ return -1;
+
+ git_buf_set(&to_buf, from->ptr, (size_t)(id_start - from->ptr));
+ git_buf_put(&to_buf, "$Id: ", 5);
+ git_buf_put(&to_buf, oid, GIT_OID_HEXSZ);
+ git_buf_putc(&to_buf, '$');
+ git_buf_put(&to_buf, id_end, (size_t)(from_end - id_end));
+
+ if (git_buf_oom(&to_buf))
+ return -1;
+
+ git_buffer_from_buf(to, &to_buf);
+ return 0;
+}
+
+static int ident_remove_id(
+ git_buffer *to, const git_buffer *from)
+{
+ const char *id_start, *id_end, *from_end = from->ptr + from->size;
+ size_t need_size;
+ git_buf to_buf = GIT_BUF_FROM_BUFFER(to);
+
+ if (ident_find_id(&id_start, &id_end, from->ptr, from->size) < 0)
+ return GIT_ENOTFOUND;
+
+ need_size = (size_t)(id_start - from->ptr) +
+ 4 /* "$Id$" */ + (size_t)(from_end - id_end);
+
+ if (git_buf_grow(&to_buf, need_size) < 0)
+ return -1;
+
+ git_buf_set(&to_buf, from->ptr, (size_t)(id_start - from->ptr));
+ git_buf_put(&to_buf, "$Id$", 4);
+ git_buf_put(&to_buf, id_end, (size_t)(from_end - id_end));
+
+ if (git_buf_oom(&to_buf))
+ return -1;
+
+ git_buffer_from_buf(to, &to_buf);
+ return 0;
+}
+
+static int ident_apply(
+ git_filter *self,
+ void **payload,
+ git_buffer *to,
+ const git_buffer *from,
+ const git_filter_source *src)
+{
+ GIT_UNUSED(self); GIT_UNUSED(payload);
+
+ if (git_filter_source_mode(src) == GIT_FILTER_SMUDGE)
+ return ident_insert_id(to, from, src);
+ else
+ return ident_remove_id(to, from);
+}
+
+git_filter *git_ident_filter_new(void)
+{
+ git_filter *f = git__calloc(1, sizeof(git_filter));
+
+ f->version = GIT_FILTER_VERSION;
+ f->attributes = "+ident"; /* apply to files with ident attribute set */
+ f->shutdown = git_filter_free;
+ f->apply = ident_apply;
+
+ return f;
+}
diff --git a/src/repository.c b/src/repository.c
index 94700e4e3..76e8228b7 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -1671,7 +1671,8 @@ int git_repository_hashfile(
/* passing empty string for "as_path" indicated --no-filters */
if (strlen(as_path) > 0) {
- error = git_filter_list_load(&fl, repo, as_path, GIT_FILTER_TO_ODB);
+ error = git_filter_list_load(
+ &fl, repo, NULL, as_path, GIT_FILTER_TO_ODB);
if (error < 0)
return error;
} else {