Skip to content

Commit

Permalink
Merge branch 'lt/apply' into next
Browse files Browse the repository at this point in the history
* lt/apply:
  apply --whitespace fixes and enhancements.
  The war on trailing whitespace
  svnimport: Convert the svn:ignore property
  svnimport: Convert executable flag
  svnimport: Mention -r in usage summary
  Make git diff-generation use a simpler spawn-like interface
  • Loading branch information
Junio C Hamano committed Feb 27, 2006
2 parents ef55636 + b5767dd commit 0a26233
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 80 deletions.
14 changes: 10 additions & 4 deletions Documentation/git-svnimport.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ git-svnimport - Import a SVN repository into git
SYNOPSIS
--------
'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
[ -s start_chg ] [ -m ] [ -M regex ]
<SVN_repository_URL> [ <path> ]
[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
[ -I <ignorefile_name> ] <SVN_repository_URL> [ <path> ]


DESCRIPTION
Expand Down Expand Up @@ -65,6 +65,12 @@ When importing incrementally, you might need to edit the .git/svn2git file.
Prepend 'rX: ' to commit messages, where X is the imported
subversion revision.

-I <ignorefile_name>::
Import the svn:ignore directory property to files with this
name in each directory. (The Subversion and GIT ignore
syntaxes are similar enough that using the Subversion patterns
directly with "-I .gitignore" will almost always just work.)

-m::
Attempt to detect merges based on the commit message. This option
will enable default regexes that try to capture the name source
Expand Down
80 changes: 72 additions & 8 deletions apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ static int line_termination = '\n';
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] <patch>...";

static enum whitespace_eol {
nowarn,
warn_on_whitespace,
error_on_whitespace,
strip_and_apply,
} new_whitespace = nowarn;
static int whitespace_error = 0;
static const char *patch_input_file = NULL;

/*
* For "diff-stat" like behaviour, we keep track of the biggest change
* we've seen, and the longest filename. That allows us to do simple
Expand Down Expand Up @@ -815,6 +824,20 @@ static int parse_fragment(char *line, unsigned long size, struct patch *patch, s
oldlines--;
break;
case '+':
/*
* We know len is at least two, since we have a '+' and
* we checked that the last character was a '\n' above.
* That is, an addition of an empty line would check
* the '+' here. Sneaky...
*/
if ((new_whitespace != nowarn) &&
isspace(line[len-2])) {
fprintf(stderr, "Added whitespace\n");
fprintf(stderr, "%s:%d:%.*s\n",
patch_input_file,
linenr, len-2, line+1);
whitespace_error = 1;
}
added++;
newlines--;
break;
Expand Down Expand Up @@ -1092,6 +1115,27 @@ struct buffer_desc {
unsigned long alloc;
};

static int apply_line(char *output, const char *patch, int plen)
{
/* plen is number of bytes to be copied from patch,
* starting at patch+1 (patch[0] is '+'). Typically
* patch[plen] is '\n'.
*/
int add_nl_to_tail = 0;
if ((new_whitespace == strip_and_apply) &&
1 < plen && isspace(patch[plen-1])) {
if (patch[plen] == '\n')
add_nl_to_tail = 1;
plen--;
while (0 < plen && isspace(patch[plen]))
plen--;
}
memcpy(output, patch + 1, plen);
if (add_nl_to_tail)
output[plen++] = '\n';
return plen;
}

static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
{
char *buf = desc->buffer;
Expand Down Expand Up @@ -1127,10 +1171,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
break;
/* Fall-through for ' ' */
case '+':
if (*patch != '+' || !no_add) {
memcpy(new + newsize, patch + 1, plen);
newsize += plen;
}
if (*patch != '+' || !no_add)
newsize += apply_line(new + newsize, patch,
plen);
break;
case '@': case '\\':
/* Ignore it, we already handled it */
Expand Down Expand Up @@ -1699,14 +1742,15 @@ static int use_patch(struct patch *p)
return 1;
}

static int apply_patch(int fd)
static int apply_patch(int fd, const char *filename)
{
int newfd;
unsigned long offset, size;
char *buffer = read_patch_file(fd, &size);
struct patch *list = NULL, **listp = &list;
int skipped_patch = 0;

patch_input_file = filename;
if (!buffer)
return -1;
offset = 0;
Expand All @@ -1733,6 +1777,9 @@ static int apply_patch(int fd)
}

newfd = -1;
if (whitespace_error && (new_whitespace == error_on_whitespace))
apply = 0;

write_index = check_index && apply;
if (write_index)
newfd = hold_index_file_for_update(&cache_file, get_index_file());
Expand Down Expand Up @@ -1779,7 +1826,7 @@ int main(int argc, char **argv)
int fd;

if (!strcmp(arg, "-")) {
apply_patch(0);
apply_patch(0, "<stdin>");
read_stdin = 0;
continue;
}
Expand Down Expand Up @@ -1839,6 +1886,21 @@ int main(int argc, char **argv)
line_termination = 0;
continue;
}
if (!strncmp(arg, "--whitespace=", 13)) {
if (!strcmp(arg+13, "warn")) {
new_whitespace = warn_on_whitespace;
continue;
}
if (!strcmp(arg+13, "error")) {
new_whitespace = error_on_whitespace;
continue;
}
if (!strcmp(arg+13, "strip")) {
new_whitespace = strip_and_apply;
continue;
}
die("unrecognixed whitespace option '%s'", arg+13);
}

if (check_index && prefix_length < 0) {
prefix = setup_git_directory();
Expand All @@ -1852,10 +1914,12 @@ int main(int argc, char **argv)
if (fd < 0)
usage(apply_usage);
read_stdin = 0;
apply_patch(fd);
apply_patch(fd, arg);
close(fd);
}
if (read_stdin)
apply_patch(0);
apply_patch(0, "<stdin>");
if (whitespace_error && new_whitespace == error_on_whitespace)
return 1;
return 0;
}
138 changes: 80 additions & 58 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,12 @@ static void emit_rewrite_diff(const char *name_a,
copy_file('+', temp[1].name);
}

static void builtin_diff(const char *name_a,
static const char *builtin_diff(const char *name_a,
const char *name_b,
struct diff_tempfile *temp,
const char *xfrm_msg,
int complete_rewrite)
int complete_rewrite,
const char **args)
{
int i, next_at, cmd_size;
const char *const diff_cmd = "diff -L%s -L%s";
Expand Down Expand Up @@ -242,19 +243,24 @@ static void builtin_diff(const char *name_a,
}
if (xfrm_msg && xfrm_msg[0])
puts(xfrm_msg);
/*
* we do not run diff between different kind
* of objects.
*/
if (strncmp(temp[0].mode, temp[1].mode, 3))
/* we do not run diff between different kind
* of objects.
*/
exit(0);
return NULL;
if (complete_rewrite) {
fflush(NULL);
emit_rewrite_diff(name_a, name_b, temp);
exit(0);
return NULL;
}
}
fflush(NULL);
execlp("/bin/sh","sh", "-c", cmd, NULL);

/* This is disgusting */
*args++ = "sh";
*args++ = "-c";
*args++ = cmd;
*args = NULL;
return "/bin/sh";
}

struct diff_filespec *alloc_filespec(const char *path)
Expand Down Expand Up @@ -559,6 +565,40 @@ static void remove_tempfile_on_signal(int signo)
raise(signo);
}

static int spawn_prog(const char *pgm, const char **arg)
{
pid_t pid;
int status;

fflush(NULL);
pid = fork();
if (pid < 0)
die("unable to fork");
if (!pid) {
execvp(pgm, (char *const*) arg);
exit(255);
}

while (waitpid(pid, &status, 0) < 0) {
if (errno == EINTR)
continue;
return -1;
}

/* Earlier we did not check the exit status because
* diff exits non-zero if files are different, and
* we are not interested in knowing that. It was a
* mistake which made it harder to quit a diff-*
* session that uses the git-apply-patch-script as
* the GIT_EXTERNAL_DIFF. A custom GIT_EXTERNAL_DIFF
* should also exit non-zero only when it wants to
* abort the entire diff-* session.
*/
if (WIFEXITED(status) && !WEXITSTATUS(status))
return 0;
return -1;
}

/* An external diff command takes:
*
* diff-cmd name infile1 infile1-sha1 infile1-mode \
Expand All @@ -573,9 +613,9 @@ static void run_external_diff(const char *pgm,
const char *xfrm_msg,
int complete_rewrite)
{
const char *spawn_arg[10];
struct diff_tempfile *temp = diff_temp;
pid_t pid;
int status;
int retval;
static int atexit_asked = 0;
const char *othername;

Expand All @@ -592,59 +632,41 @@ static void run_external_diff(const char *pgm,
signal(SIGINT, remove_tempfile_on_signal);
}

fflush(NULL);
pid = fork();
if (pid < 0)
die("unable to fork");
if (!pid) {
if (pgm) {
if (one && two) {
const char *exec_arg[10];
const char **arg = &exec_arg[0];
*arg++ = pgm;
*arg++ = name;
*arg++ = temp[0].name;
*arg++ = temp[0].hex;
*arg++ = temp[0].mode;
*arg++ = temp[1].name;
*arg++ = temp[1].hex;
*arg++ = temp[1].mode;
if (other) {
*arg++ = other;
*arg++ = xfrm_msg;
}
*arg = NULL;
execvp(pgm, (char *const*) exec_arg);
if (pgm) {
const char **arg = &spawn_arg[0];
if (one && two) {
*arg++ = pgm;
*arg++ = name;
*arg++ = temp[0].name;
*arg++ = temp[0].hex;
*arg++ = temp[0].mode;
*arg++ = temp[1].name;
*arg++ = temp[1].hex;
*arg++ = temp[1].mode;
if (other) {
*arg++ = other;
*arg++ = xfrm_msg;
}
else
execlp(pgm, pgm, name, NULL);
} else {
*arg++ = pgm;
*arg++ = name;
}
/*
* otherwise we use the built-in one.
*/
if (one && two)
builtin_diff(name, othername, temp, xfrm_msg,
complete_rewrite);
else
*arg = NULL;
} else {
if (one && two) {
pgm = builtin_diff(name, othername, temp, xfrm_msg, complete_rewrite, spawn_arg);
} else
printf("* Unmerged path %s\n", name);
exit(0);
}
if (waitpid(pid, &status, 0) < 0 ||
!WIFEXITED(status) || WEXITSTATUS(status)) {
/* Earlier we did not check the exit status because
* diff exits non-zero if files are different, and
* we are not interested in knowing that. It was a
* mistake which made it harder to quit a diff-*
* session that uses the git-apply-patch-script as
* the GIT_EXTERNAL_DIFF. A custom GIT_EXTERNAL_DIFF
* should also exit non-zero only when it wants to
* abort the entire diff-* session.
*/
remove_tempfile();

retval = 0;
if (pgm)
retval = spawn_prog(pgm, spawn_arg);
remove_tempfile();
if (retval) {
fprintf(stderr, "external diff died, stopping at %s.\n", name);
exit(1);
}
remove_tempfile();
}

static void diff_fill_sha1_info(struct diff_filespec *one)
Expand Down
Loading

0 comments on commit 0a26233

Please sign in to comment.