Skip to content

Commit

Permalink
Merge branch 'sb/format-patch-patchname'
Browse files Browse the repository at this point in the history
* sb/format-patch-patchname:
  format_sanitized_subject: Don't trim past initial length of strbuf
  log-tree: fix patch filename computation in "git format-patch"
  format-patch: --numbered-files and --stdout aren't mutually exclusive
  format-patch: --attach/inline uses filename instead of SHA1
  format-patch: move get_patch_filename() into log-tree
  format-patch: pass a commit to reopen_stdout()
  format-patch: construct patch filename in one function
  pretty.c: add %f format specifier to format_commit_message()
  • Loading branch information
Junio C Hamano committed Apr 6, 2009
2 parents a6e5ef7 + 871d21d commit 87d2062
Show file tree
Hide file tree
Showing 17 changed files with 381 additions and 129 deletions.
1 change: 1 addition & 0 deletions Documentation/pretty-formats.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ The placeholders are:
- '%d': ref names, like the --decorate option of linkgit:git-log[1]
- '%e': encoding
- '%s': subject
- '%f': sanitized subject line, suitable for a filename
- '%b': body
- '%Cred': switch color to red
- '%Cgreen': switch color to green
Expand Down
131 changes: 43 additions & 88 deletions builtin-log.c
Original file line number Diff line number Diff line change
Expand Up @@ -417,13 +417,6 @@ int cmd_log(int argc, const char **argv, const char *prefix)
}

/* format-patch */
#define FORMAT_PATCH_NAME_MAX 64

static int istitlechar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '.' || c == '_';
}

static const char *fmt_patch_suffix = ".patch";
static int numbered = 0;
Expand Down Expand Up @@ -523,92 +516,33 @@ static int git_format_config(const char *var, const char *value, void *cb)
return git_log_config(var, value, cb);
}


static const char *get_oneline_for_filename(struct commit *commit,
int keep_subject)
{
static char filename[PATH_MAX];
char *sol;
int len = 0;
int suffix_len = strlen(fmt_patch_suffix) + 1;

sol = strstr(commit->buffer, "\n\n");
if (!sol)
filename[0] = '\0';
else {
int j, space = 0;

sol += 2;
/* strip [PATCH] or [PATCH blabla] */
if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
char *eos = strchr(sol + 6, ']');
if (eos) {
while (isspace(*eos))
eos++;
sol = eos;
}
}

for (j = 0;
j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
len < sizeof(filename) - suffix_len &&
sol[j] && sol[j] != '\n';
j++) {
if (istitlechar(sol[j])) {
if (space) {
filename[len++] = '-';
space = 0;
}
filename[len++] = sol[j];
if (sol[j] == '.')
while (sol[j + 1] == '.')
j++;
} else
space = 1;
}
while (filename[len - 1] == '.'
|| filename[len - 1] == '-')
len--;
filename[len] = '\0';
}
return filename;
}

static FILE *realstdout = NULL;
static const char *output_directory = NULL;
static int outdir_offset;

static int reopen_stdout(const char *oneline, int nr, struct rev_info *rev)
static int reopen_stdout(struct commit *commit, struct rev_info *rev)
{
char filename[PATH_MAX];
int len = 0;
struct strbuf filename = STRBUF_INIT;
int suffix_len = strlen(fmt_patch_suffix) + 1;

if (output_directory) {
len = snprintf(filename, sizeof(filename), "%s",
output_directory);
if (len >=
sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)
strbuf_addstr(&filename, output_directory);
if (filename.len >=
PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
return error("name of output directory is too long");
if (filename[len - 1] != '/')
filename[len++] = '/';
if (filename.buf[filename.len - 1] != '/')
strbuf_addch(&filename, '/');
}

if (!oneline)
len += sprintf(filename + len, "%d", nr);
else {
len += sprintf(filename + len, "%04d-", nr);
len += snprintf(filename + len, sizeof(filename) - len - 1
- suffix_len, "%s", oneline);
strcpy(filename + len, fmt_patch_suffix);
}
get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);

if (!DIFF_OPT_TST(&rev->diffopt, QUIET))
fprintf(realstdout, "%s\n", filename + outdir_offset);
fprintf(realstdout, "%s\n", filename.buf + outdir_offset);

if (freopen(filename, "w", stdout) == NULL)
return error("Cannot open patch file %s",filename);
if (freopen(filename.buf, "w", stdout) == NULL)
return error("Cannot open patch file %s", filename.buf);

strbuf_release(&filename);
return 0;
}

Expand Down Expand Up @@ -678,7 +612,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
int nr, struct commit **list, struct commit *head)
{
const char *committer;
char *head_sha1;
const char *subject_start = NULL;
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
const char *msg;
Expand All @@ -689,20 +622,40 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
const char *encoding = "utf-8";
struct diff_options opts;
int need_8bit_cte = 0;
struct commit *commit = NULL;

if (rev->commit_format != CMIT_FMT_EMAIL)
die("Cover letter needs email format");

if (!use_stdout && reopen_stdout(numbered_files ?
NULL : "cover-letter", 0, rev))
committer = git_committer_info(0);

if (!numbered_files) {
/*
* We fake a commit for the cover letter so we get the filename
* desired.
*/
commit = xcalloc(1, sizeof(*commit));
commit->buffer = xmalloc(400);
snprintf(commit->buffer, 400,
"tree 0000000000000000000000000000000000000000\n"
"parent %s\n"
"author %s\n"
"committer %s\n\n"
"cover letter\n",
sha1_to_hex(head->object.sha1), committer, committer);
}

if (!use_stdout && reopen_stdout(commit, rev))
return;

head_sha1 = sha1_to_hex(head->object.sha1);
if (commit) {

log_write_email_headers(rev, head_sha1, &subject_start, &extra_headers,
&need_8bit_cte);
free(commit->buffer);
free(commit);
}

committer = git_committer_info(0);
log_write_email_headers(rev, head, &subject_start, &extra_headers,
&need_8bit_cte);

msg = body;
pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,
Expand Down Expand Up @@ -1067,6 +1020,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
const char *msgid = clean_message_id(in_reply_to);
string_list_append(msgid, rev.ref_message_ids);
}
rev.numbered_files = numbered_files;
rev.patch_suffix = fmt_patch_suffix;
if (cover_letter) {
if (thread)
gen_message_id(&rev, "cover");
Expand Down Expand Up @@ -1115,9 +1070,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
gen_message_id(&rev, sha1_to_hex(commit->object.sha1));
}
if (!use_stdout && reopen_stdout(numbered_files ? NULL :
get_oneline_for_filename(commit, keep_subject),
rev.nr, &rev))

if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
&rev))
die("Failed to create output files");
shown = log_tree_commit(&rev, commit);
free(commit->buffer);
Expand Down
35 changes: 28 additions & 7 deletions log-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,31 @@ static int has_non_ascii(const char *s)
return 0;
}

void log_write_email_headers(struct rev_info *opt, const char *name,
void get_patch_filename(struct commit *commit, int nr, const char *suffix,
struct strbuf *buf)
{
int suffix_len = strlen(suffix) + 1;
int start_len = buf->len;

strbuf_addf(buf, commit ? "%04d-" : "%d", nr);
if (commit) {
int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len;

format_commit_message(commit, "%f", buf, DATE_NORMAL);
if (max_len < buf->len)
strbuf_setlen(buf, max_len);
strbuf_addstr(buf, suffix);
}
}

void log_write_email_headers(struct rev_info *opt, struct commit *commit,
const char **subject_p,
const char **extra_headers_p,
int *need_8bit_cte_p)
{
const char *subject = NULL;
const char *extra_headers = opt->extra_headers;
const char *name = sha1_to_hex(commit->object.sha1);

*need_8bit_cte_p = 0; /* unknown */
if (opt->total > 0) {
Expand Down Expand Up @@ -224,6 +242,7 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
if (opt->mime_boundary) {
static char subject_buffer[1024];
static char buffer[1024];
struct strbuf filename = STRBUF_INIT;
*need_8bit_cte_p = -1; /* NEVER */
snprintf(subject_buffer, sizeof(subject_buffer) - 1,
"%s"
Expand All @@ -242,18 +261,21 @@ void log_write_email_headers(struct rev_info *opt, const char *name,
mime_boundary_leader, opt->mime_boundary);
extra_headers = subject_buffer;

get_patch_filename(opt->numbered_files ? NULL : commit, opt->nr,
opt->patch_suffix, &filename);
snprintf(buffer, sizeof(buffer) - 1,
"\n--%s%s\n"
"Content-Type: text/x-patch;"
" name=\"%s.diff\"\n"
" name=\"%s\"\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Disposition: %s;"
" filename=\"%s.diff\"\n\n",
" filename=\"%s\"\n\n",
mime_boundary_leader, opt->mime_boundary,
name,
filename.buf,
opt->no_inline ? "attachment" : "inline",
name);
filename.buf);
opt->diffopt.stat_sep = buffer;
strbuf_release(&filename);
}
*subject_p = subject;
*extra_headers_p = extra_headers;
Expand Down Expand Up @@ -333,8 +355,7 @@ void show_log(struct rev_info *opt)
*/

if (opt->commit_format == CMIT_FMT_EMAIL) {
log_write_email_headers(opt, sha1_to_hex(commit->object.sha1),
&subject, &extra_headers,
log_write_email_headers(opt, commit, &subject, &extra_headers,
&need_8bit_cte);
} else if (opt->commit_format != CMIT_FMT_USERFORMAT) {
fputs(diff_get_color_opt(&opt->diffopt, DIFF_COMMIT), stdout);
Expand Down
6 changes: 5 additions & 1 deletion log-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ int log_tree_commit(struct rev_info *, struct commit *);
int log_tree_opt_parse(struct rev_info *, const char **, int);
void show_log(struct rev_info *opt);
void show_decorations(struct rev_info *opt, struct commit *commit);
void log_write_email_headers(struct rev_info *opt, const char *name,
void log_write_email_headers(struct rev_info *opt, struct commit *commit,
const char **subject_p,
const char **extra_headers_p,
int *need_8bit_cte_p);
void load_ref_decorations(void);

#define FORMAT_PATCH_NAME_MAX 64
void get_patch_filename(struct commit *commit, int nr, const char *suffix,
struct strbuf *buf);

#endif
37 changes: 37 additions & 0 deletions pretty.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,40 @@ static void parse_commit_header(struct format_commit_context *context)
context->commit_header_parsed = 1;
}

static int istitlechar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '.' || c == '_';
}

static void format_sanitized_subject(struct strbuf *sb, const char *msg)
{
size_t trimlen;
size_t start_len = sb->len;
int space = 2;

for (; *msg && *msg != '\n'; msg++) {
if (istitlechar(*msg)) {
if (space == 1)
strbuf_addch(sb, '-');
space = 0;
strbuf_addch(sb, *msg);
if (*msg == '.')
while (*(msg+1) == '.')
msg++;
} else
space |= 1;
}

/* trim any trailing '.' or '-' characters */
trimlen = 0;
while (sb->len - trimlen > start_len &&
(sb->buf[sb->len - 1 - trimlen] == '.'
|| sb->buf[sb->len - 1 - trimlen] == '-'))
trimlen++;
strbuf_remove(sb, sb->len - trimlen, trimlen);
}

const char *format_subject(struct strbuf *sb, const char *msg,
const char *line_separator)
{
Expand Down Expand Up @@ -683,6 +717,9 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder,
case 's': /* subject */
format_subject(sb, msg + c->subject_off, " ");
return 1;
case 'f': /* sanitized subject */
format_sanitized_subject(sb, msg + c->subject_off);
return 1;
case 'b': /* body */
strbuf_addstr(sb, msg + c->body_off);
return 1;
Expand Down
2 changes: 2 additions & 0 deletions revision.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ struct rev_info {
struct log_info *loginfo;
int nr, total;
const char *mime_boundary;
const char *patch_suffix;
int numbered_files;
char *message_id;
struct string_list *ref_message_ids;
const char *add_signoff;
Expand Down
3 changes: 2 additions & 1 deletion t/t4013-diff-various.sh
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,12 @@ format-patch --stdout initial..master
format-patch --stdout --no-numbered initial..master
format-patch --stdout --numbered initial..master
format-patch --attach --stdout initial..side
format-patch --attach --stdout --suffix=.diff initial..side
format-patch --attach --stdout initial..master^
format-patch --attach --stdout initial..master
format-patch --inline --stdout initial..side
format-patch --inline --stdout initial..master^
format-patch --inline --stdout initial..master
format-patch --inline --stdout --numbered-files initial..master
format-patch --inline --stdout initial..master
format-patch --inline --stdout --subject-prefix=TESTCASE initial..master
config format.subjectprefix DIFFERENT_PREFIX
Expand Down
Loading

0 comments on commit 87d2062

Please sign in to comment.