Merge branch 'jc/refactor-diff-stdin' into maint

"git diff", "git status" and anything that internally uses the
comparison machinery was utterly broken when the difference
involved a file with "-" as its name.  This was due to the way "git
diff --no-index" was incorrectly bolted on to the system, making
any comparison that involves a file "-" at the root level
incorrectly read from the standard input.

* jc/refactor-diff-stdin:
  diff-index.c: "git diff" has no need to read blob from the standard input
  diff-index.c: unify handling of command line paths
  diff-index.c: do not pretend paths are pathspecs
This commit is contained in:
Junio C Hamano
2012-07-22 13:01:22 -07:00
4 changed files with 67 additions and 50 deletions

View File

@ -32,6 +32,13 @@ static int read_directory(const char *path, struct string_list *list)
return 0;
}
/*
* This should be "(standard input)" or something, but it will
* probably expose many more breakages in the way no-index code
* is bolted onto the diff callchain.
*/
static const char file_from_standard_input[] = "-";
static int get_mode(const char *path, int *mode)
{
struct stat st;
@ -42,7 +49,7 @@ static int get_mode(const char *path, int *mode)
else if (!strcasecmp(path, "nul"))
*mode = 0;
#endif
else if (!strcmp(path, "-"))
else if (path == file_from_standard_input)
*mode = create_ce_mode(0666);
else if (lstat(path, &st))
return error("Could not access '%s'", path);
@ -51,6 +58,36 @@ static int get_mode(const char *path, int *mode)
return 0;
}
static int populate_from_stdin(struct diff_filespec *s)
{
struct strbuf buf = STRBUF_INIT;
size_t size = 0;
if (strbuf_read(&buf, 0, 0) < 0)
return error("error while reading from stdin %s",
strerror(errno));
s->should_munmap = 0;
s->data = strbuf_detach(&buf, &size);
s->size = size;
s->should_free = 1;
s->is_stdin = 1;
return 0;
}
static struct diff_filespec *noindex_filespec(const char *name, int mode)
{
struct diff_filespec *s;
if (!name)
name = "/dev/null";
s = alloc_filespec(name);
fill_filespec(s, null_sha1, mode);
if (name == file_from_standard_input)
populate_from_stdin(s);
return s;
}
static int queue_diff(struct diff_options *o,
const char *name1, const char *name2)
{
@ -137,15 +174,8 @@ static int queue_diff(struct diff_options *o,
tmp_c = name1; name1 = name2; name2 = tmp_c;
}
if (!name1)
name1 = "/dev/null";
if (!name2)
name2 = "/dev/null";
d1 = alloc_filespec(name1);
d2 = alloc_filespec(name2);
fill_filespec(d1, null_sha1, mode1);
fill_filespec(d2, null_sha1, mode2);
d1 = noindex_filespec(name1, mode1);
d2 = noindex_filespec(name2, mode2);
diff_queue(&diff_queued_diff, d1, d2);
return 0;
}
@ -155,9 +185,10 @@ void diff_no_index(struct rev_info *revs,
int argc, const char **argv,
int nongit, const char *prefix)
{
int i;
int i, prefixlen;
int no_index = 0;
unsigned options = 0;
const char *paths[2];
/* Were we asked to do --no-index explicitly? */
for (i = 1; i < argc; i++) {
@ -207,26 +238,19 @@ void diff_no_index(struct rev_info *revs,
}
}
if (prefix) {
int len = strlen(prefix);
const char *paths[3];
memset(paths, 0, sizeof(paths));
for (i = 0; i < 2; i++) {
const char *p = argv[argc - 2 + i];
prefixlen = prefix ? strlen(prefix) : 0;
for (i = 0; i < 2; i++) {
const char *p = argv[argc - 2 + i];
if (!strcmp(p, "-"))
/*
* stdin should be spelled as '-'; if you have
* path that is '-', spell it as ./-.
* stdin should be spelled as "-"; if you have
* path that is "-", spell it as "./-".
*/
p = (strcmp(p, "-")
? xstrdup(prefix_filename(prefix, len, p))
: p);
paths[i] = p;
}
diff_tree_setup_paths(paths, &revs->diffopt);
p = file_from_standard_input;
else if (prefixlen)
p = xstrdup(prefix_filename(prefix, prefixlen, p));
paths[i] = p;
}
else
diff_tree_setup_paths(argv + argc - 2, &revs->diffopt);
revs->diffopt.skip_stat_unmatch = 1;
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
@ -240,8 +264,7 @@ void diff_no_index(struct rev_info *revs,
setup_diff_pager(&revs->diffopt);
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],
revs->diffopt.pathspec.raw[1]))
if (queue_diff(&revs->diffopt, paths[0], paths[1]))
exit(1);
diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
diffcore_std(&revs->diffopt);