Merge branch 'cp/textconv-cat-file'

* cp/textconv-cat-file:
  git-cat-file.txt: Document --textconv
  t/t8007: test textconv support for cat-file
  textconv: support for cat_file
  sha1_name: add get_sha1_with_context()
This commit is contained in:
Junio C Hamano 2010-06-27 12:07:55 -07:00
Родитель 6aa206413a 9f77fe0224
Коммит cf4403a010
7 изменённых файлов: 155 добавлений и 15 удалений

Просмотреть файл

@ -9,14 +9,15 @@ git-cat-file - Provide content or type and size information for repository objec
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git cat-file' (-t | -s | -e | -p | <type>) <object> 'git cat-file' (-t | -s | -e | -p | <type> | --textconv ) <object>
'git cat-file' (--batch | --batch-check) < <list-of-objects> 'git cat-file' (--batch | --batch-check) < <list-of-objects>
DESCRIPTION DESCRIPTION
----------- -----------
In its first form, the command provides the content or the type of an object in In its first form, the command provides the content or the type of an object in
the repository. The type is required unless '-t' or '-p' is used to find the the repository. The type is required unless '-t' or '-p' is used to find the
object type, or '-s' is used to find the object size. object type, or '-s' is used to find the object size, or '--textconv' is used
(which implies type "blob").
In the second form, a list of objects (separated by linefeeds) is provided on In the second form, a list of objects (separated by linefeeds) is provided on
stdin, and the SHA1, type, and size of each object is printed on stdout. stdin, and the SHA1, type, and size of each object is printed on stdout.
@ -51,6 +52,11 @@ OPTIONS
or to ask for a "blob" with <object> being a tag object that or to ask for a "blob" with <object> being a tag object that
points at it. points at it.
--textconv::
Show the content as transformed by a textconv filter. In this case,
<object> has be of the form <treeish>:<path>, or :<path> in order
to apply the filter to the content recorded in the index at <path>.
--batch:: --batch::
Print the SHA1, type, size, and contents of each object provided on Print the SHA1, type, size, and contents of each object provided on
stdin. May not be combined with any other options or arguments. stdin. May not be combined with any other options or arguments.

Просмотреть файл

@ -37,6 +37,8 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
extern int check_pager_config(const char *cmd); 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 cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_add(int argc, const char **argv, const char *prefix);
extern int cmd_annotate(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_apply(int argc, const char **argv, const char *prefix); extern int cmd_apply(int argc, const char **argv, const char *prefix);

Просмотреть файл

@ -91,10 +91,10 @@ struct origin {
* if the textconv driver exists. * if the textconv driver exists.
* Return 1 if the conversion succeeds, 0 otherwise. * Return 1 if the conversion succeeds, 0 otherwise.
*/ */
static int textconv_object(const char *path, int textconv_object(const char *path,
const unsigned char *sha1, const unsigned char *sha1,
char **buf, char **buf,
unsigned long *buf_size) unsigned long *buf_size)
{ {
struct diff_filespec *df; struct diff_filespec *df;
struct userdiff_driver *textconv; struct userdiff_driver *textconv;

Просмотреть файл

@ -9,6 +9,8 @@
#include "tree.h" #include "tree.h"
#include "builtin.h" #include "builtin.h"
#include "parse-options.h" #include "parse-options.h"
#include "diff.h"
#include "userdiff.h"
#define BATCH 1 #define BATCH 1
#define BATCH_CHECK 2 #define BATCH_CHECK 2
@ -84,10 +86,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{ {
unsigned char sha1[20]; unsigned char sha1[20];
enum object_type type; enum object_type type;
void *buf; char *buf;
unsigned long size; unsigned long size;
struct object_context obj_context;
if (get_sha1(obj_name, sha1)) if (get_sha1_with_context(obj_name, sha1, &obj_context))
die("Not a valid object name %s", obj_name); die("Not a valid object name %s", obj_name);
buf = NULL; buf = NULL;
@ -134,6 +137,17 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
/* otherwise just spit out the data */ /* otherwise just spit out the data */
break; break;
case 'c':
if (!obj_context.path[0])
die("git cat-file --textconv %s: <object> must be <sha1:path>",
obj_name);
if (!textconv_object(obj_context.path, sha1, &buf, &size))
die("git cat-file --textconv: unable to run textconv on %s",
obj_name);
break;
case 0: case 0:
buf = read_object_with_reference(sha1, exp_type, &size, NULL); buf = read_object_with_reference(sha1, exp_type, &size, NULL);
break; break;
@ -203,11 +217,25 @@ static int batch_objects(int print_contents)
} }
static const char * const cat_file_usage[] = { static const char * const cat_file_usage[] = {
"git cat-file (-t|-s|-e|-p|<type>) <object>", "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
"git cat-file (--batch|--batch-check) < <list_of_objects>", "git cat-file (--batch|--batch-check) < <list_of_objects>",
NULL NULL
}; };
static int git_cat_file_config(const char *var, const char *value, void *cb)
{
switch (userdiff_config(var, value)) {
case 0:
break;
case -1:
return -1;
default:
return 0;
}
return git_default_config(var, value, cb);
}
int cmd_cat_file(int argc, const char **argv, const char *prefix) int cmd_cat_file(int argc, const char **argv, const char *prefix)
{ {
int opt = 0, batch = 0; int opt = 0, batch = 0;
@ -220,6 +248,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_SET_INT('e', NULL, &opt, OPT_SET_INT('e', NULL, &opt,
"exit with zero when there's no error", 'e'), "exit with zero when there's no error", 'e'),
OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'), OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
OPT_SET_INT(0, "textconv", &opt,
"for blob objects, run textconv on object's content", 'c'),
OPT_SET_INT(0, "batch", &batch, OPT_SET_INT(0, "batch", &batch,
"show info and content of objects fed from the standard input", "show info and content of objects fed from the standard input",
BATCH), BATCH),
@ -229,7 +259,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
OPT_END() OPT_END()
}; };
git_config(git_default_config, NULL); git_config(git_cat_file_config, NULL);
if (argc != 3 && argc != 2) if (argc != 3 && argc != 2)
usage_with_options(cat_file_usage, options); usage_with_options(cat_file_usage, options);

11
cache.h
Просмотреть файл

@ -750,12 +750,23 @@ static inline unsigned int hexval(unsigned char c)
#define MINIMUM_ABBREV 4 #define MINIMUM_ABBREV 4
#define DEFAULT_ABBREV 7 #define DEFAULT_ABBREV 7
struct object_context {
unsigned char tree[20];
char path[PATH_MAX];
unsigned mode;
};
extern int get_sha1(const char *str, unsigned char *sha1); extern int get_sha1(const char *str, unsigned char *sha1);
extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix); extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode) static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
{ {
return get_sha1_with_mode_1(str, sha1, mode, 1, NULL); return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
} }
extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int gently, const char *prefix);
static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
{
return get_sha1_with_context_1(str, sha1, orc, 1, NULL);
}
extern int get_sha1_hex(const char *hex, unsigned char *sha1); extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
extern int read_ref(const char *filename, unsigned char *sha1); extern int read_ref(const char *filename, unsigned char *sha1);

Просмотреть файл

@ -939,8 +939,8 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
*/ */
int get_sha1(const char *name, unsigned char *sha1) int get_sha1(const char *name, unsigned char *sha1)
{ {
unsigned unused; struct object_context unused;
return get_sha1_with_mode(name, sha1, &unused); return get_sha1_with_context(name, sha1, &unused);
} }
/* Must be called only when object_name:filename doesn't exist. */ /* Must be called only when object_name:filename doesn't exist. */
@ -1037,12 +1037,24 @@ static void diagnose_invalid_index_path(int stage,
int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int gently, const char *prefix) int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int gently, const char *prefix)
{
struct object_context oc;
int ret;
ret = get_sha1_with_context_1(name, sha1, &oc, gently, prefix);
*mode = oc.mode;
return ret;
}
int get_sha1_with_context_1(const char *name, unsigned char *sha1,
struct object_context *oc,
int gently, const char *prefix)
{ {
int ret, bracket_depth; int ret, bracket_depth;
int namelen = strlen(name); int namelen = strlen(name);
const char *cp; const char *cp;
*mode = S_IFINVALID; memset(oc, 0, sizeof(*oc));
oc->mode = S_IFINVALID;
ret = get_sha1_1(name, namelen, sha1); ret = get_sha1_1(name, namelen, sha1);
if (!ret) if (!ret)
return ret; return ret;
@ -1065,6 +1077,11 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
cp = name + 3; cp = name + 3;
} }
namelen = namelen - (cp - name); namelen = namelen - (cp - name);
strncpy(oc->path, cp,
sizeof(oc->path));
oc->path[sizeof(oc->path)-1] = '\0';
if (!active_cache) if (!active_cache)
read_cache(); read_cache();
pos = cache_name_pos(cp, namelen); pos = cache_name_pos(cp, namelen);
@ -1077,7 +1094,6 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
break; break;
if (ce_stage(ce) == stage) { if (ce_stage(ce) == stage) {
hashcpy(sha1, ce->sha1); hashcpy(sha1, ce->sha1);
*mode = ce->ce_mode;
return 0; return 0;
} }
pos++; pos++;
@ -1104,12 +1120,17 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
} }
if (!get_sha1_1(name, cp-name, tree_sha1)) { if (!get_sha1_1(name, cp-name, tree_sha1)) {
const char *filename = cp+1; const char *filename = cp+1;
ret = get_tree_entry(tree_sha1, filename, sha1, mode); ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
if (!gently) { if (!gently) {
diagnose_invalid_sha1_path(prefix, filename, diagnose_invalid_sha1_path(prefix, filename,
tree_sha1, object_name); tree_sha1, object_name);
free(object_name); free(object_name);
} }
hashcpy(oc->tree, tree_sha1);
strncpy(oc->path, filename,
sizeof(oc->path));
oc->path[sizeof(oc->path)-1] = '\0';
return ret; return ret;
} else { } else {
if (!gently) if (!gently)

70
t/t8007-cat-file-textconv.sh Executable file
Просмотреть файл

@ -0,0 +1,70 @@
#!/bin/sh
test_description='git cat-file textconv support'
. ./test-lib.sh
cat >helper <<'EOF'
#!/bin/sh
sed 's/^/converted: /' "$@"
EOF
chmod +x helper
test_expect_success 'setup ' '
echo test >one.bin &&
git add . &&
GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
echo test version 2 >one.bin &&
GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
'
cat >expected <<EOF
fatal: git cat-file --textconv: unable to run textconv on :one.bin
EOF
test_expect_success 'no filter specified' '
git cat-file --textconv :one.bin 2>result
test_cmp expected result
'
test_expect_success 'setup textconv filters' '
echo "*.bin diff=test" >.gitattributes &&
git config diff.test.textconv ./helper &&
git config diff.test.cachetextconv false
'
cat >expected <<EOF
test version 2
EOF
test_expect_success 'cat-file without --textconv' '
git cat-file blob :one.bin >result &&
test_cmp expected result
'
cat >expected <<EOF
test
EOF
test_expect_success 'cat-file without --textconv on previous commit' '
git cat-file -p HEAD^:one.bin >result &&
test_cmp expected result
'
cat >expected <<EOF
converted: test version 2
EOF
test_expect_success 'cat-file --textconv on last commit' '
git cat-file --textconv :one.bin >result &&
test_cmp expected result
'
cat >expected <<EOF
converted: test
EOF
test_expect_success 'cat-file --textconv on previous commit' '
git cat-file --textconv HEAD^:one.bin >result &&
test_cmp expected result
'
test_done