diff options
author | Junio C Hamano <gitster@pobox.com> | 2012-05-29 13:09:13 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2012-05-29 13:09:13 -0700 |
commit | 261ec7d02ae25ba1f5532645fa6fd790515bfa70 (patch) | |
tree | 7c9c68dd5cbef0aff748eaa40a0c88de0d970f4f | |
parent | 12d7d150743acebe9684100e98979f2d0188114e (diff) | |
parent | 59f9b8a9a95cbcf4f6a5123cac04dc5073a8d0cc (diff) | |
download | git-261ec7d02ae25ba1f5532645fa6fd790515bfa70.tar.gz |
Merge branch 'jk/ident-gecos-strbuf'
Fixes quite a lot of brokenness when ident information needs to be taken
from the system and cleans up the code.
By Jeff King
* jk/ident-gecos-strbuf: (22 commits)
format-patch: do not use bogus email addresses in message ids
ident: reject bogus email addresses with IDENT_STRICT
ident: rename IDENT_ERROR_ON_NO_NAME to IDENT_STRICT
format-patch: use GIT_COMMITTER_EMAIL in message ids
ident: let callers omit name with fmt_indent
ident: refactor NO_DATE flag in fmt_ident
ident: reword empty ident error message
format-patch: refactor get_patch_filename
ident: trim whitespace from default name/email
ident: use a dynamic strbuf in fmt_ident
ident: use full dns names to generate email addresses
ident: report passwd errors with a more friendly message
drop length limitations on gecos-derived names and emails
ident: don't write fallback username into git_default_name
fmt_ident: drop IDENT_WARN_ON_NO_NAME code
format-patch: use default email for generating message ids
ident: trim trailing newline from /etc/mailname
move git_default_* variables to ident.c
move identity config parsing to ident.c
fmt-merge-msg: don't use static buffer in record_person
...
-rw-r--r-- | Documentation/git-commit-tree.txt | 9 | ||||
-rw-r--r-- | Documentation/git-var.txt | 9 | ||||
-rw-r--r-- | builtin/commit.c | 3 | ||||
-rw-r--r-- | builtin/fmt-merge-msg.c | 8 | ||||
-rw-r--r-- | builtin/log.c | 46 | ||||
-rw-r--r-- | builtin/merge.c | 4 | ||||
-rw-r--r-- | builtin/tag.c | 2 | ||||
-rw-r--r-- | builtin/var.c | 4 | ||||
-rw-r--r-- | cache.h | 13 | ||||
-rw-r--r-- | commit.c | 4 | ||||
-rw-r--r-- | config.c | 24 | ||||
-rw-r--r-- | environment.c | 3 | ||||
-rw-r--r-- | git-compat-util.h | 3 | ||||
-rw-r--r-- | gpg-interface.c | 2 | ||||
-rw-r--r-- | http-push.c | 2 | ||||
-rw-r--r-- | ident.c | 243 | ||||
-rw-r--r-- | log-tree.c | 19 | ||||
-rw-r--r-- | log-tree.h | 4 | ||||
-rw-r--r-- | wrapper.c | 12 |
19 files changed, 176 insertions, 238 deletions
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index cfb9906bb5..eb8ee9999e 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -88,15 +88,6 @@ for one to be entered and terminated with ^D. include::date-formats.txt[] -Diagnostics ------------ -You don't exist. Go away!:: - The passwd(5) gecos field couldn't be read -Your parents must have hated you!:: - The passwd(5) gecos field is longer than a giant static buffer. -Your sysadmin must hate you!:: - The passwd(5) name field is longer than a giant static buffer. - Discussion ---------- diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt index 988a3234f4..67edf58689 100644 --- a/Documentation/git-var.txt +++ b/Documentation/git-var.txt @@ -59,15 +59,6 @@ ifdef::git-default-pager[] The build you are using chose '{git-default-pager}' as the default. endif::git-default-pager[] -Diagnostics ------------ -You don't exist. Go away!:: - The passwd(5) gecos field couldn't be read -Your parents must have hated you!:: - The passwd(5) gecos field is longer than a giant static buffer. -Your sysadmin must hate you!:: - The passwd(5) name field is longer than a giant static buffer. - SEE ALSO -------- linkgit:git-commit-tree[1] diff --git a/builtin/commit.c b/builtin/commit.c index a2ec73d738..f43eaafb3b 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -526,8 +526,7 @@ static void determine_author_info(struct strbuf *author_ident) if (force_date) date = force_date; - strbuf_addstr(author_ident, fmt_ident(name, email, date, - IDENT_ERROR_ON_NO_NAME)); + strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT)); if (!split_ident_line(&author, author_ident->buf, author_ident->len)) { export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0); export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0); diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index d42015d867..bf93b043b7 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -230,7 +230,7 @@ static void add_branch_desc(struct strbuf *out, const char *name) static void record_person(int which, struct string_list *people, struct commit *commit) { - char name_buf[MAX_GITNAME], *name, *name_end; + char *name_buf, *name, *name_end; struct string_list_item *elem; const char *field = (which == 'a') ? "\nauthor " : "\ncommitter "; @@ -243,10 +243,9 @@ static void record_person(int which, struct string_list *people, name_end--; while (isspace(*name_end) && name <= name_end) name_end--; - if (name_end < name || name + MAX_GITNAME <= name_end) + if (name_end < name) return; - memcpy(name_buf, name, name_end - name + 1); - name_buf[name_end - name + 1] = '\0'; + name_buf = xmemdupz(name, name_end - name + 1); elem = string_list_lookup(people, name_buf); if (!elem) { @@ -254,6 +253,7 @@ static void record_person(int which, struct string_list *people, elem->util = (void *)0; } elem->util = (void*)(util_as_integral(elem) + 1); + free(name_buf); } static int cmp_string_list_util_as_integral(const void *a_, const void *b_) diff --git a/builtin/log.c b/builtin/log.c index 690caa7830..906dca475a 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -663,7 +663,8 @@ static FILE *realstdout = NULL; static const char *output_directory = NULL; static int outdir_offset; -static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet) +static int reopen_stdout(struct commit *commit, const char *subject, + struct rev_info *rev, int quiet) { struct strbuf filename = STRBUF_INIT; int suffix_len = strlen(fmt_patch_suffix) + 1; @@ -677,7 +678,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet) strbuf_addch(&filename, '/'); } - get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename); + get_patch_filename(commit, subject, rev->nr, fmt_patch_suffix, &filename); if (!quiet) fprintf(realstdout, "%s\n", filename.buf + outdir_offset); @@ -737,15 +738,10 @@ static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const cha static void gen_message_id(struct rev_info *info, char *base) { - const char *committer = git_committer_info(IDENT_WARN_ON_NO_NAME); - const char *email_start = strrchr(committer, '<'); - const char *email_end = strrchr(committer, '>'); struct strbuf buf = STRBUF_INIT; - if (!email_start || !email_end || email_start > email_end - 1) - die(_("Could not extract email from committer identity.")); - strbuf_addf(&buf, "%s.%lu.git.%.*s", base, + strbuf_addf(&buf, "%s.%lu.git.%s", base, (unsigned long) time(NULL), - (int)(email_end - email_start - 1), email_start + 1); + git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT)); info->message_id = strbuf_detach(&buf, NULL); } @@ -784,7 +780,6 @@ 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; struct pretty_print_context pp = {0}; if (rev->commit_format != CMIT_FMT_EMAIL) @@ -792,31 +787,10 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, 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, quiet)) + if (!use_stdout && + reopen_stdout(NULL, numbered_files ? NULL : "cover-letter", rev, quiet)) return; - if (commit) { - - free(commit->buffer); - free(commit); - } - log_write_email_headers(rev, head, &pp.subject, &pp.after_subject, &need_8bit_cte); @@ -1173,7 +1147,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (do_signoff) { const char *committer; const char *endpos; - committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); + committer = git_committer_info(IDENT_STRICT); endpos = strchr(committer, '>'); if (!endpos) die(_("bogus committer info %s"), committer); @@ -1411,8 +1385,8 @@ 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 : commit, - &rev, quiet)) + if (!use_stdout && + reopen_stdout(numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); free(commit->buffer); diff --git a/builtin/merge.c b/builtin/merge.c index 470fc57c5d..dd50a0c57b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -1447,7 +1447,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) refresh_cache(REFRESH_QUIET); if (allow_trivial && !fast_forward_only) { /* See if it is really trivial. */ - git_committer_info(IDENT_ERROR_ON_NO_NAME); + git_committer_info(IDENT_STRICT); printf(_("Trying really trivial in-index merge...\n")); if (!read_tree_trivial(common->item->object.sha1, head_commit->object.sha1, @@ -1490,7 +1490,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) die(_("Not possible to fast-forward, aborting.")); /* We are going to make a new commit. */ - git_committer_info(IDENT_ERROR_ON_NO_NAME); + git_committer_info(IDENT_STRICT); /* * At this point, we need a real merge. No matter what strategy diff --git a/builtin/tag.c b/builtin/tag.c index 4fb6bd7b3d..7b1be85e48 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -332,7 +332,7 @@ static void create_tag(const unsigned char *object, const char *tag, sha1_to_hex(object), typename(type), tag, - git_committer_info(IDENT_ERROR_ON_NO_NAME)); + git_committer_info(IDENT_STRICT)); if (header_len > sizeof(header_buf) - 1) die(_("tag header too big.")); diff --git a/builtin/var.c b/builtin/var.c index 99d068a532..aedbb53a2d 100644 --- a/builtin/var.c +++ b/builtin/var.c @@ -11,7 +11,7 @@ static const char *editor(int flag) { const char *pgm = git_editor(); - if (!pgm && flag & IDENT_ERROR_ON_NO_NAME) + if (!pgm && flag & IDENT_STRICT) die("Terminal is dumb, but EDITOR unset"); return pgm; @@ -55,7 +55,7 @@ static const char *read_var(const char *var) val = NULL; for (ptr = git_vars; ptr->read; ptr++) { if (strcmp(var, ptr->name) == 0) { - val = ptr->read(IDENT_ERROR_ON_NO_NAME); + val = ptr->read(IDENT_STRICT); break; } } @@ -887,15 +887,19 @@ unsigned long approxidate_careful(const char *, int *); unsigned long approxidate_relative(const char *date, const struct timeval *now); enum date_mode parse_date_format(const char *format); -#define IDENT_WARN_ON_NO_NAME 1 -#define IDENT_ERROR_ON_NO_NAME 2 -#define IDENT_NO_DATE 4 +#define IDENT_STRICT 1 +#define IDENT_NO_DATE 2 +#define IDENT_NO_NAME 4 extern const char *git_author_info(int); extern const char *git_committer_info(int); extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int); extern const char *fmt_name(const char *name, const char *email); +extern const char *ident_default_name(void); +extern const char *ident_default_email(void); +extern const char *ident_default_date(void); extern const char *git_editor(void); extern const char *git_pager(int stdout_is_tty); +extern int git_ident_config(const char *, const char *, void *); struct ident_split { const char *name_begin; @@ -1139,9 +1143,6 @@ struct config_include_data { #define CONFIG_INCLUDE_INIT { 0 } extern int git_config_include(const char *name, const char *value, void *data); -#define MAX_GITNAME (1000) -extern char git_default_email[MAX_GITNAME]; -extern char git_default_name[MAX_GITNAME]; #define IDENT_NAME_GIVEN 01 #define IDENT_MAIL_GIVEN 02 #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN) @@ -1154,9 +1154,9 @@ int commit_tree_extended(const struct strbuf *msg, unsigned char *tree, /* Person/date information */ if (!author) - author = git_author_info(IDENT_ERROR_ON_NO_NAME); + author = git_author_info(IDENT_STRICT); strbuf_addf(&buffer, "author %s\n", author); - strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_ERROR_ON_NO_NAME)); + strbuf_addf(&buffer, "committer %s\n", git_committer_info(IDENT_STRICT)); if (!encoding_is_utf8) strbuf_addf(&buffer, "encoding %s\n", git_commit_encoding); @@ -762,28 +762,6 @@ static int git_default_core_config(const char *var, const char *value) return 0; } -static int git_default_user_config(const char *var, const char *value) -{ - if (!strcmp(var, "user.name")) { - if (!value) - return config_error_nonbool(var); - strlcpy(git_default_name, value, sizeof(git_default_name)); - user_ident_explicitly_given |= IDENT_NAME_GIVEN; - return 0; - } - - if (!strcmp(var, "user.email")) { - if (!value) - return config_error_nonbool(var); - strlcpy(git_default_email, value, sizeof(git_default_email)); - user_ident_explicitly_given |= IDENT_MAIL_GIVEN; - return 0; - } - - /* Add other config variables here and to Documentation/config.txt. */ - return 0; -} - static int git_default_i18n_config(const char *var, const char *value) { if (!strcmp(var, "i18n.commitencoding")) @@ -870,7 +848,7 @@ int git_default_config(const char *var, const char *value, void *dummy) return git_default_core_config(var, value); if (!prefixcmp(var, "user.")) - return git_default_user_config(var, value); + return git_ident_config(var, value, dummy); if (!prefixcmp(var, "i18n.")) return git_default_i18n_config(var, value); diff --git a/environment.c b/environment.c index d7e6c65763..669e498f5a 100644 --- a/environment.c +++ b/environment.c @@ -11,9 +11,6 @@ #include "refs.h" #include "fmt-merge-msg.h" -char git_default_email[MAX_GITNAME]; -char git_default_name[MAX_GITNAME]; -int user_ident_explicitly_given; int trust_executable_bit = 1; int trust_ctime = 1; int has_symlinks = 1; diff --git a/git-compat-util.h b/git-compat-util.h index ed11ad8119..5bd9ad7d2a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -595,4 +595,7 @@ int rmdir_or_warn(const char *path); */ int remove_or_warn(unsigned int mode, const char *path); +/* Get the passwd entry for the UID of the current process. */ +struct passwd *xgetpwuid_self(void); + #endif diff --git a/gpg-interface.c b/gpg-interface.c index 09ab64aa24..0863c61800 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -30,7 +30,7 @@ const char *get_signing_key(void) { if (configured_signing_key) return configured_signing_key; - return git_committer_info(IDENT_ERROR_ON_NO_NAME|IDENT_NO_DATE); + return git_committer_info(IDENT_STRICT|IDENT_NO_DATE); } /* diff --git a/http-push.c b/http-push.c index 1df7ab5670..a832ca77a3 100644 --- a/http-push.c +++ b/http-push.c @@ -904,7 +904,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout) ep = strchr(ep + 1, '/'); } - escaped = xml_entities(git_default_email); + escaped = xml_entities(ident_default_email()); strbuf_addf(&out_buffer.buf, LOCK_REQUEST, escaped); free(escaped); @@ -7,7 +7,10 @@ */ #include "cache.h" +static struct strbuf git_default_name = STRBUF_INIT; +static struct strbuf git_default_email = STRBUF_INIT; static char git_default_date[50]; +int user_ident_explicitly_given; #ifdef NO_GECOS_IN_PWENT #define get_gecos(ignored) "&" @@ -15,42 +18,27 @@ static char git_default_date[50]; #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos) #endif -static void copy_gecos(const struct passwd *w, char *name, size_t sz) +static void copy_gecos(const struct passwd *w, struct strbuf *name) { - char *src, *dst; - size_t len, nlen; - - nlen = strlen(w->pw_name); + char *src; /* Traditionally GECOS field had office phone numbers etc, separated * with commas. Also & stands for capitalized form of the login name. */ - for (len = 0, dst = name, src = get_gecos(w); len < sz; src++) { + for (src = get_gecos(w); *src && *src != ','; src++) { int ch = *src; - if (ch != '&') { - *dst++ = ch; - if (ch == 0 || ch == ',') - break; - len++; - continue; - } - if (len + nlen < sz) { + if (ch != '&') + strbuf_addch(name, ch); + else { /* Sorry, Mr. McDonald... */ - *dst++ = toupper(*w->pw_name); - memcpy(dst, w->pw_name + 1, nlen - 1); - dst += nlen - 1; - len += nlen; + strbuf_addch(name, toupper(*w->pw_name)); + strbuf_addstr(name, w->pw_name + 1); } } - if (len < sz) - name[len] = 0; - else - die("Your parents must have hated you!"); - } -static int add_mailname_host(char *buf, size_t len) +static int add_mailname_host(struct strbuf *buf) { FILE *mailname; @@ -61,7 +49,7 @@ static int add_mailname_host(char *buf, size_t len) strerror(errno)); return -1; } - if (!fgets(buf, len, mailname)) { + if (strbuf_getline(buf, mailname, '\n') == EOF) { if (ferror(mailname)) warning("cannot read /etc/mailname: %s", strerror(errno)); @@ -73,94 +61,67 @@ static int add_mailname_host(char *buf, size_t len) return 0; } -static void add_domainname(char *buf, size_t len) +static void add_domainname(struct strbuf *out) { + char buf[1024]; struct hostent *he; - size_t namelen; - const char *domainname; - if (gethostname(buf, len)) { + if (gethostname(buf, sizeof(buf))) { warning("cannot get host name: %s", strerror(errno)); - strlcpy(buf, "(none)", len); + strbuf_addstr(out, "(none)"); return; } - namelen = strlen(buf); - if (memchr(buf, '.', namelen)) - return; - - he = gethostbyname(buf); - buf[namelen++] = '.'; - buf += namelen; - len -= namelen; - if (he && (domainname = strchr(he->h_name, '.'))) - strlcpy(buf, domainname + 1, len); + if (strchr(buf, '.')) + strbuf_addstr(out, buf); + else if ((he = gethostbyname(buf)) && strchr(he->h_name, '.')) + strbuf_addstr(out, he->h_name); else - strlcpy(buf, "(none)", len); + strbuf_addf(out, "%s.(none)", buf); } -static void copy_email(const struct passwd *pw) +static void copy_email(const struct passwd *pw, struct strbuf *email) { /* * Make up a fake email address * (name + '@' + hostname [+ '.' + domainname]) */ - size_t len = strlen(pw->pw_name); - if (len > sizeof(git_default_email)/2) - die("Your sysadmin must hate you!"); - memcpy(git_default_email, pw->pw_name, len); - git_default_email[len++] = '@'; - - if (!add_mailname_host(git_default_email + len, - sizeof(git_default_email) - len)) + strbuf_addstr(email, pw->pw_name); + strbuf_addch(email, '@'); + + if (!add_mailname_host(email)) return; /* read from "/etc/mailname" (Debian) */ - add_domainname(git_default_email + len, - sizeof(git_default_email) - len); + add_domainname(email); } -static void setup_ident(const char **name, const char **emailp) +const char *ident_default_name(void) { - struct passwd *pw = NULL; - - /* Get the name ("gecos") */ - if (!*name && !git_default_name[0]) { - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - copy_gecos(pw, git_default_name, sizeof(git_default_name)); + if (!git_default_name.len) { + copy_gecos(xgetpwuid_self(), &git_default_name); + strbuf_trim(&git_default_name); } - if (!*name) - *name = git_default_name; + return git_default_name.buf; +} - if (!*emailp && !git_default_email[0]) { +const char *ident_default_email(void) +{ + if (!git_default_email.len) { const char *email = getenv("EMAIL"); if (email && email[0]) { - strlcpy(git_default_email, email, - sizeof(git_default_email)); + strbuf_addstr(&git_default_email, email); user_ident_explicitly_given |= IDENT_MAIL_GIVEN; - } else { - if (!pw) - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - copy_email(pw); - } + } else + copy_email(xgetpwuid_self(), &git_default_email); + strbuf_trim(&git_default_email); } - if (!*emailp) - *emailp = git_default_email; - - /* And set the default date */ - if (!git_default_date[0]) - datestamp(git_default_date, sizeof(git_default_date)); + return git_default_email.buf; } -static int add_raw(char *buf, size_t size, int offset, const char *str) +const char *ident_default_date(void) { - size_t len = strlen(str); - if (offset + len > size) - return size; - memcpy(buf + offset, str, len); - return offset + len; + if (!git_default_date[0]) + datestamp(git_default_date, sizeof(git_default_date)); + return git_default_date; } static int crud(unsigned char c) @@ -181,7 +142,7 @@ static int crud(unsigned char c) * Copy over a string to the destination, but avoid special * characters ('\n', '<' and '>') and remove crud at the end */ -static int copy(char *buf, size_t size, int offset, const char *src) +static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src) { size_t i, len; unsigned char c; @@ -205,19 +166,19 @@ static int copy(char *buf, size_t size, int offset, const char *src) /* * Copy the rest to the buffer, but avoid the special * characters '\n' '<' and '>' that act as delimiters on - * an identification line + * an identification line. We can only remove crud, never add it, + * so 'len' is our maximum. */ + strbuf_grow(sb, len); for (i = 0; i < len; i++) { c = *src++; switch (c) { case '\n': case '<': case '>': continue; } - if (offset >= size) - return size; - buf[offset++] = c; + sb->buf[sb->len++] = c; } - return offset; + sb->buf[sb->len] = '\0'; } /* @@ -304,57 +265,62 @@ static const char *env_hint = const char *fmt_ident(const char *name, const char *email, const char *date_str, int flag) { - static char buffer[1000]; + static struct strbuf ident = STRBUF_INIT; char date[50]; - int i; - int error_on_no_name = (flag & IDENT_ERROR_ON_NO_NAME); - int warn_on_no_name = (flag & IDENT_WARN_ON_NO_NAME); - int name_addr_only = (flag & IDENT_NO_DATE); + int strict = (flag & IDENT_STRICT); + int want_date = !(flag & IDENT_NO_DATE); + int want_name = !(flag & IDENT_NO_NAME); - setup_ident(&name, &email); + if (want_name && !name) + name = ident_default_name(); + if (!email) + email = ident_default_email(); - if (!*name) { + if (want_name && !*name) { struct passwd *pw; - if ((warn_on_no_name || error_on_no_name) && - name == git_default_name && env_hint) { - fputs(env_hint, stderr); - env_hint = NULL; /* warn only once */ + if (strict) { + if (name == git_default_name.buf) + fputs(env_hint, stderr); + die("empty ident name (for <%s>) not allowed", email); } - if (error_on_no_name) - die("empty ident %s <%s> not allowed", name, email); - pw = getpwuid(getuid()); - if (!pw) - die("You don't exist. Go away!"); - strlcpy(git_default_name, pw->pw_name, - sizeof(git_default_name)); - name = git_default_name; + pw = xgetpwuid_self(); + name = pw->pw_name; + } + + if (strict && email == git_default_email.buf && + strstr(email, "(none)")) { + fputs(env_hint, stderr); + die("unable to auto-detect email address (got '%s')", email); } - strcpy(date, git_default_date); - if (!name_addr_only && date_str && date_str[0]) { - if (parse_date(date_str, date, sizeof(date)) < 0) - die("invalid date format: %s", date_str); + if (want_date) { + if (date_str && date_str[0]) { + if (parse_date(date_str, date, sizeof(date)) < 0) + die("invalid date format: %s", date_str); + } + else + strcpy(date, ident_default_date()); } - i = copy(buffer, sizeof(buffer), 0, name); - i = add_raw(buffer, sizeof(buffer), i, " <"); - i = copy(buffer, sizeof(buffer), i, email); - if (!name_addr_only) { - i = add_raw(buffer, sizeof(buffer), i, "> "); - i = copy(buffer, sizeof(buffer), i, date); - } else { - i = add_raw(buffer, sizeof(buffer), i, ">"); + strbuf_reset(&ident); + if (want_name) { + strbuf_addstr_without_crud(&ident, name); + strbuf_addstr(&ident, " <"); } - if (i >= sizeof(buffer)) - die("Impossibly long personal identifier"); - buffer[i] = 0; - return buffer; + strbuf_addstr_without_crud(&ident, email); + if (want_name) + strbuf_addch(&ident, '>'); + if (want_date) { + strbuf_addch(&ident, ' '); + strbuf_addstr_without_crud(&ident, date); + } + return ident.buf; } const char *fmt_name(const char *name, const char *email) { - return fmt_ident(name, email, NULL, IDENT_ERROR_ON_NO_NAME | IDENT_NO_DATE); + return fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE); } const char *git_author_info(int flag) @@ -385,3 +351,26 @@ int user_ident_sufficiently_given(void) return (user_ident_explicitly_given == IDENT_ALL_GIVEN); #endif } + +int git_ident_config(const char *var, const char *value, void *data) +{ + if (!strcmp(var, "user.name")) { + if (!value) + return config_error_nonbool(var); + strbuf_reset(&git_default_name); + strbuf_addstr(&git_default_name, value); + user_ident_explicitly_given |= IDENT_NAME_GIVEN; + return 0; + } + + if (!strcmp(var, "user.email")) { + if (!value) + return config_error_nonbool(var); + strbuf_reset(&git_default_email); + strbuf_addstr(&git_default_email, value); + user_ident_explicitly_given |= IDENT_MAIL_GIVEN; + return 0; + } + + return 0; +} diff --git a/log-tree.c b/log-tree.c index 376d973176..c894930c18 100644 --- a/log-tree.c +++ b/log-tree.c @@ -299,19 +299,22 @@ static unsigned int digits_in_number(unsigned int number) return result; } -void get_patch_filename(struct commit *commit, int nr, const char *suffix, - struct strbuf *buf) +void get_patch_filename(struct commit *commit, const char *subject, 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) { + strbuf_addf(buf, commit || subject ? "%04d-" : "%d", nr); + if (commit || subject) { int max_len = start_len + FORMAT_PATCH_NAME_MAX - suffix_len; struct pretty_print_context ctx = {0}; - ctx.date_mode = DATE_NORMAL; - format_commit_message(commit, "%f", buf, &ctx); + if (subject) + strbuf_addstr(buf, subject); + else if (commit) + format_commit_message(commit, "%f", buf, &ctx); + if (max_len < buf->len) strbuf_setlen(buf, max_len); strbuf_addstr(buf, suffix); @@ -384,8 +387,8 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, mime_boundary_leader, opt->mime_boundary); extra_headers = subject_buffer; - get_patch_filename(opt->numbered_files ? NULL : commit, opt->nr, - opt->patch_suffix, &filename); + get_patch_filename(opt->numbered_files ? NULL : commit, NULL, + opt->nr, opt->patch_suffix, &filename); snprintf(buffer, sizeof(buffer) - 1, "\n--%s%s\n" "Content-Type: text/x-patch;" diff --git a/log-tree.h b/log-tree.h index 5c4cf7cac3..f5ac238bba 100644 --- a/log-tree.h +++ b/log-tree.h @@ -21,7 +21,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, void load_ref_decorations(int flags); #define FORMAT_PATCH_NAME_MAX 64 -void get_patch_filename(struct commit *commit, int nr, const char *suffix, - struct strbuf *buf); +void get_patch_filename(struct commit *commit, const char *subject, int nr, + const char *suffix, struct strbuf *buf); #endif @@ -402,3 +402,15 @@ int remove_or_warn(unsigned int mode, const char *file) { return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file); } + +struct passwd *xgetpwuid_self(void) +{ + struct passwd *pw; + + errno = 0; + pw = getpwuid(getuid()); + if (!pw) + die(_("unable to look up current user in the passwd file: %s"), + errno ? strerror(errno) : _("no such user")); + return pw; +} |