author | Junio C Hamano <gitster@pobox.com> | |
Wed, 17 Nov 2010 22:59:27 +0000 (14:59 -0800) | ||
committer | Junio C Hamano <gitster@pobox.com> | |
Wed, 17 Nov 2010 22:59:27 +0000 (14:59 -0800) |
* ks/no-textconv-symlink:
blame,cat-file --textconv: Don't assume mode is ``S_IFREF | 0664''
blame,cat-file: Demonstrate --textconv is wrongly running converter on symlinks
blame,cat-file: Prepare --textconv tests for correctly-failing conversion program
blame,cat-file --textconv: Don't assume mode is ``S_IFREF | 0664''
blame,cat-file: Demonstrate --textconv is wrongly running converter on symlinks
blame,cat-file: Prepare --textconv tests for correctly-failing conversion program
diff --git a/builtin.h b/builtin.h
index f2a25a084736e573f560672fabc9c6214997f437..8dd4569b3c06654826c298b6b52dcf2ac17481bb 100644 (file)
--- a/builtin.h
+++ b/builtin.h
extern int check_pager_config(const char *cmd);
-extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
diff --git a/builtin/blame.c b/builtin/blame.c
index 101535448f2b0405c280387b63f7ce82fb7dd350..f5fccc1f6767d7386e37f7273c560d0d4491ee91 100644 (file)
--- a/builtin/blame.c
+++ b/builtin/blame.c
struct commit *commit;
mmfile_t file;
unsigned char blob_sha1[20];
+ unsigned mode;
char path[FLEX_ARRAY];
};
* Return 1 if the conversion succeeds, 0 otherwise.
*/
int textconv_object(const char *path,
+ unsigned mode,
const unsigned char *sha1,
char **buf,
unsigned long *buf_size)
struct userdiff_driver *textconv;
df = alloc_filespec(path);
- fill_filespec(df, sha1, S_IFREG | 0664);
+ fill_filespec(df, sha1, mode);
textconv = get_textconv(df);
if (!textconv) {
free_filespec(df);
num_read_blob++;
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
+ textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
;
else
file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
* for an origin is also used to pass the blame for the entire file to
* the parent to detect the case where a child's blob is identical to
* that of its parent's.
+ *
+ * This also fills origin->mode for corresponding tree path.
*/
-static int fill_blob_sha1(struct origin *origin)
+static int fill_blob_sha1_and_mode(struct origin *origin)
{
- unsigned mode;
if (!is_null_sha1(origin->blob_sha1))
return 0;
if (get_tree_entry(origin->commit->object.sha1,
origin->path,
- origin->blob_sha1, &mode))
+ origin->blob_sha1, &origin->mode))
goto error_out;
if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
goto error_out;
return 0;
error_out:
hashclr(origin->blob_sha1);
+ origin->mode = S_IFINVALID;
return -1;
}
/*
* If the origin was newly created (i.e. get_origin
* would call make_origin if none is found in the
- * scoreboard), it does not know the blob_sha1,
+ * scoreboard), it does not know the blob_sha1/mode,
* so copy it. Otherwise porigin was in the
- * scoreboard and already knows blob_sha1.
+ * scoreboard and already knows blob_sha1/mode.
*/
- if (porigin->refcnt == 1)
+ if (porigin->refcnt == 1) {
hashcpy(porigin->blob_sha1, cached->blob_sha1);
+ porigin->mode = cached->mode;
+ }
return porigin;
}
/* otherwise it was not very useful; free it */
/* The path is the same as parent */
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, origin->blob_sha1);
+ porigin->mode = origin->mode;
} else {
/*
* Since origin->path is a pathspec, if the parent
case 'M':
porigin = get_origin(sb, parent, origin->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
+ porigin->mode = p->one->mode;
break;
case 'A':
case 'T':
cached = make_origin(porigin->commit, porigin->path);
hashcpy(cached->blob_sha1, porigin->blob_sha1);
+ cached->mode = porigin->mode;
parent->util = cached;
}
return porigin;
!strcmp(p->two->path, origin->path)) {
porigin = get_origin(sb, parent, p->one->path);
hashcpy(porigin->blob_sha1, p->one->sha1);
+ porigin->mode = p->one->mode;
break;
}
}
norigin = get_origin(sb, parent, p->one->path);
hashcpy(norigin->blob_sha1, p->one->sha1);
+ norigin->mode = p->one->mode;
fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
if (!file_p.ptr)
continue;
switch (st.st_mode & S_IFMT) {
case S_IFREG:
if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
- textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
+ textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
buf.len = buf_len;
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
die_errno("cannot open or read '%s'", read_from);
}
else {
o = get_origin(&sb, sb.final, path);
- if (fill_blob_sha1(o))
+ if (fill_blob_sha1_and_mode(o))
die("no such path %s in %s", path, final_commit_name);
if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
- textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
+ textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
&sb.final_buf_size))
;
else
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 76ec3fec9279f38520fa4b5b525ce2c03cc9cbb0..94632dbdb400f9a2986d10f06dd16119ce1b4e54 100644 (file)
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);
- if (!textconv_object(obj_context.path, sha1, &buf, &size))
+ if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
die("git cat-file --textconv: unable to run textconv on %s",
obj_name);
break;
diff --git a/sha1_name.c b/sha1_name.c
index 484081de82928108a23a714a76ea88693e56bdd1..3e856b80369c289a3d9399d60ec3be22bbbc6788 100644 (file)
--- a/sha1_name.c
+++ b/sha1_name.c
struct cache_entry *ce;
int pos;
if (namelen > 2 && name[1] == '/')
+ /* don't need mode for commit */
return get_sha1_oneline(name + 2, sha1);
if (namelen < 3 ||
name[2] != ':' ||
break;
if (ce_stage(ce) == stage) {
hashcpy(sha1, ce->sha1);
+ oc->mode = ce->ce_mode;
return 0;
}
pos++;
index 9ad96d4d32390081ba97c336d80b2294cf69dc44..dbf623bce5598860800fa463c26ec8145d6e2400 100755 (executable)
cat >helper <<'EOF'
#!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
EOF
chmod +x helper
test_expect_success 'setup ' '
- echo test 1 >one.bin &&
- echo test number 2 >two.bin &&
+ echo "bin: test 1" >one.bin &&
+ echo "bin: test number 2" >two.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -s one.bin symlink.bin
+ fi &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
- echo test 1 version 2 >one.bin &&
- echo test number 2 version 2 >>two.bin &&
+ echo "bin: test 1 version 2" >one.bin &&
+ echo "bin: test number 2 version 2" >>two.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -sf two.bin symlink.bin
+ fi &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
cat >expected <<EOF
-(Number2 2010-01-01 20:00:00 +0000 1) test 1 version 2
+(Number2 2010-01-01 20:00:00 +0000 1) bin: test 1 version 2
EOF
test_expect_success 'no filter specified' '
'
test_expect_success 'make a new commit' '
- echo "test number 2 version 3" >>two.bin &&
+ echo "bin: test number 2 version 3" >>two.bin &&
GIT_AUTHOR_NAME=Number3 git commit -a -m Third --date="2010-01-01 22:00:00"
'
test_cmp expected result
'
+cat >expected <<EOF
+(Number2 2010-01-01 20:00:00 +0000 1) two.bin
+EOF
+
+test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
+ git blame --no-textconv symlink.bin >blame &&
+ find_blame <blame >result &&
+ test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
+ git blame --textconv symlink.bin >blame &&
+ find_blame <blame >result &&
+ test_cmp expected result
+'
+
+# cp two.bin three.bin and make small tweak
+# (this will direct blame -C -C three.bin to consider two.bin and symlink.bin)
+test_expect_success SYMLINKS 'make another new commit' '
+ cat >three.bin <<\EOF &&
+bin: test number 2
+bin: test number 2 version 2
+bin: test number 2 version 3
+bin: test number 3
+EOF
+ git add three.bin &&
+ GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
+'
+
+test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
+ git blame -C -C three.bin >blame &&
+ find_blame <blame >result &&
+ cat >expected <<\EOF &&
+(Number1 2010-01-01 18:00:00 +0000 1) converted: test number 2
+(Number2 2010-01-01 20:00:00 +0000 2) converted: test number 2 version 2
+(Number3 2010-01-01 22:00:00 +0000 3) converted: test number 2 version 3
+(Number4 2010-01-01 23:00:00 +0000 4) converted: test number 3
+EOF
+ test_cmp expected result
+'
+
test_done
index 38ac05e4a0b62e9105a400b4583d5504b42b3e7d..78a0085e648b8fa6773b47e86959853cf29ccdf9 100755 (executable)
cat >helper <<'EOF'
#!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
EOF
chmod +x helper
test_expect_success 'setup ' '
- echo test >one.bin &&
+ echo "bin: test" >one.bin &&
+ if test_have_prereq SYMLINKS; then
+ ln -s one.bin symlink.bin
+ fi &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
- echo test version 2 >one.bin &&
+ echo "bin: test version 2" >one.bin &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
'
cat >expected <<EOF
-test version 2
+bin: test version 2
EOF
test_expect_success 'cat-file without --textconv' '
'
cat >expected <<EOF
-test
+bin: test
EOF
test_expect_success 'cat-file without --textconv on previous commit' '
git cat-file --textconv HEAD^:one.bin >result &&
test_cmp expected result
'
+
+test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
+ git cat-file blob :symlink.bin >result &&
+ printf "%s" "one.bin" >expected
+ test_cmp expected result
+'
+
+
+test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
+ ! git cat-file --textconv :symlink.bin 2>result &&
+ cat >expected <<\EOF &&
+fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
+EOF
+ test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
+ ! git cat-file --textconv HEAD:symlink.bin 2>result &&
+ cat >expected <<EOF &&
+fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
+EOF
+ test_cmp expected result
+'
+
test_done