From: Pang Yan Han <pangyanhan@gmail.com>
To: git@vger.kernel.org
Cc: Bertrand BENOIT <projettwk@users.sourceforge.net>,
Ramkumar Ramachandra <artagnon@gmail.com>,
Thomas Rast <trast@student.ethz.ch>,
Junio C Hamano <gitster@pobox.com>,
Pang Yan Han <pangyanhan@gmail.com>
Subject: [PATCH] grep: resolve symlinks for --no-index and untracked symlinks for --untracked
Date: Sat, 14 Jan 2012 15:10:50 +0800 [thread overview]
Message-ID: <1326525050-8011-1-git-send-email-pangyanhan@gmail.com> (raw)
For a tracked symbolic link, git tracks where the symbolic link points to
and as such, git grep does not search for patterns in where the symbolic link
points to.
However, git grep with --no-index is supposed to work similarly to GNU grep by
pretending that the current directory is not a git repository and hence resolve
symbolic links.
When used with the --untracked option, untracked symbolic links should also
be resolved.
Teach git grep to resolve symbolic links for --no-index and untracked symbolic
links for --untracked.
---
builtin/grep.c | 49 +++++++++++++++++++++++++++++++++++--------------
t/t7810-grep.sh | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 14 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 9ce064a..c7883c3 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -29,9 +29,12 @@ static int use_threads = 1;
#define THREADS 8
static pthread_t threads[THREADS];
+#define UNTRACKED 0
+#define TRACKED 1
+
static void *load_sha1(const unsigned char *sha1, unsigned long *size,
const char *name);
-static void *load_file(const char *filename, size_t *sz);
+static void *load_file(const char *filename, size_t *sz, int tracked);
enum work_type {WORK_SHA1, WORK_FILE};
@@ -50,6 +53,11 @@ struct work_item {
void *identifier;
char done;
struct strbuf out;
+ /* indicates whether file is tracked by git.
+ * with --no-index, resolve all symlinks.
+ * with --untracked, resolve only untracked symlinks.
+ */
+ int tracked;
};
/* In the range [todo_done, todo_start) in 'todo' we have work_items
@@ -113,7 +121,7 @@ static pthread_cond_t cond_result;
static int skip_first_line;
-static void add_work(enum work_type type, char *name, void *id)
+static void add_work(enum work_type type, char *name, void *id, int tracked)
{
grep_lock();
@@ -125,6 +133,7 @@ static void add_work(enum work_type type, char *name, void *id)
todo[todo_end].name = name;
todo[todo_end].identifier = id;
todo[todo_end].done = 0;
+ todo[todo_end].tracked = tracked;
strbuf_reset(&todo[todo_end].out);
todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
@@ -157,13 +166,13 @@ static void grep_sha1_async(struct grep_opt *opt, char *name,
unsigned char *s;
s = xmalloc(20);
memcpy(s, sha1, 20);
- add_work(WORK_SHA1, name, s);
+ add_work(WORK_SHA1, name, s, TRACKED);
}
static void grep_file_async(struct grep_opt *opt, char *name,
- const char *filename)
+ const char *filename, int tracked)
{
- add_work(WORK_FILE, name, xstrdup(filename));
+ add_work(WORK_FILE, name, xstrdup(filename), tracked);
}
static void work_done(struct work_item *w)
@@ -226,7 +235,7 @@ static void *run(void *arg)
}
} else if (w->type == WORK_FILE) {
size_t sz;
- void* data = load_file(w->identifier, &sz);
+ void* data = load_file(w->identifier, &sz, w->tracked);
if (data) {
hit |= grep_buffer(opt, w->name, data, sz);
free(data);
@@ -429,7 +438,7 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
}
}
-static void *load_file(const char *filename, size_t *sz)
+static void *load_file(const char *filename, size_t *sz, int tracked)
{
struct stat st;
char *data;
@@ -441,6 +450,12 @@ static void *load_file(const char *filename, size_t *sz)
error(_("'%s': %s"), filename, strerror(errno));
return NULL;
}
+ /* Resolve symlink if file is not tracked */
+ if (S_ISLNK(st.st_mode) && !tracked) {
+ memset(&st, 0, sizeof(st));
+ if (stat(filename, &st) < 0)
+ goto err_ret;
+ }
if (!S_ISREG(st.st_mode))
return NULL;
*sz = xsize_t(st.st_size);
@@ -459,7 +474,8 @@ static void *load_file(const char *filename, size_t *sz)
return data;
}
-static int grep_file(struct grep_opt *opt, const char *filename)
+static int grep_file(struct grep_opt *opt, const char *filename,
+ int tracked)
{
struct strbuf buf = STRBUF_INIT;
char *name;
@@ -472,14 +488,14 @@ static int grep_file(struct grep_opt *opt, const char *filename)
#ifndef NO_PTHREADS
if (use_threads) {
- grep_file_async(opt, name, filename);
+ grep_file_async(opt, name, filename, tracked);
return 0;
} else
#endif
{
int hit;
size_t sz;
- void *data = load_file(filename, &sz);
+ void *data = load_file(filename, &sz, tracked);
if (!data)
hit = 0;
else
@@ -541,7 +557,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int
hit |= grep_sha1(opt, ce->sha1, ce->name, 0);
}
else
- hit |= grep_file(opt, ce->name);
+ hit |= grep_file(opt, ce->name, TRACKED);
if (ce_stage(ce)) {
do {
nr++;
@@ -658,7 +674,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
}
static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
- int exc_std)
+ int exc_std, int use_index)
{
struct dir_struct dir;
int i, hit = 0;
@@ -668,12 +684,17 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
setup_standard_excludes(&dir);
fill_directory(&dir, pathspec->raw);
+ if (use_index)
+ read_cache();
for (i = 0; i < dir.nr; i++) {
const char *name = dir.entries[i]->name;
int namelen = strlen(name);
if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
continue;
- hit |= grep_file(opt, dir.entries[i]->name);
+ if (use_index && cache_name_exists(name, namelen, ignore_case))
+ hit |= grep_file(opt, dir.entries[i]->name, TRACKED);
+ else
+ hit |= grep_file(opt, dir.entries[i]->name, UNTRACKED);
if (hit && opt->status_only)
break;
}
@@ -1083,7 +1104,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
if (list.nr)
die(_("--no-index or --untracked cannot be used with revs."));
- hit = grep_directory(&opt, &pathspec, use_exclude);
+ hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
} else if (0 <= opt_exclude) {
die(_("--[no-]exclude-standard cannot be used for tracked contents."));
} else if (!list.nr) {
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 7ba5b16..fe41095 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -647,6 +647,41 @@ test_expect_success 'inside git repository but with --no-index' '
)
'
+test_expect_success '--no-index greps contents of targets of symlinks' '
+ mkdir -p repo/sub &&
+ echo hello >repo/file &&
+ echo hello there >repo/sub/file1 &&
+ (cd repo/sub && ln -s ../file link1 && ln -s ../file link2 &&
+ git init && git add link1 && git commit -m "first" &&
+ test_must_fail git grep "hello" &&
+ cat >../expected <<-EOF &&
+ file1:hello there
+ link1:hello
+ link2:hello
+ EOF
+ git grep --no-index "hello" >../actual &&
+ test_cmp ../expected ../actual
+ ) &&
+ rm -rf repo
+'
+
+test_expect_success '--untracked greps targets of untracked symlinks' '
+ mkdir -p repo/sub &&
+ echo hello >repo/file &&
+ echo hello there > repo/sub/file1 &&
+ (cd repo/sub && ln -s ../file link1 && ln -s ../file link2 &&
+ git init && git add link1 && git commit -m "first" &&
+ test_must_fail git grep "hello" &&
+ cat >../expected <<-EOF &&
+ file1:hello there
+ link2:hello
+ EOF
+ git grep --untracked "hello" >../actual &&
+ test_cmp ../expected ../actual
+ ) &&
+ rm -rf repo
+'
+
test_expect_success 'setup double-dash tests' '
cat >double-dash <<EOF &&
--
--
1.7.9.rc0.24.ga4351
next reply other threads:[~2012-01-14 7:11 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-14 7:10 Pang Yan Han [this message]
-- strict thread matches above, loose matches on Subject: below --
2012-01-14 7:14 [PATCH] grep: resolve symlinks for --no-index and untracked symlinks for --untracked Pang Yan Han
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1326525050-8011-1-git-send-email-pangyanhan@gmail.com \
--to=pangyanhan@gmail.com \
--cc=artagnon@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=projettwk@users.sourceforge.net \
--cc=trast@student.ethz.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).