commit: move empty message checks to libgit

Move the functions that check for empty messages from bulitin/commit.c to sequencer.c so they can be shared with other commands. The functions are refactored to take an explicit cleanup mode and template filename passed by the caller. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Nov 10, 2017 at 11:09 UTC d0aaa46fd3e53801346a4cadebf398f05d79780b
3 files changed +91 -80
builtin/commit.c
+19 -80
@@ -128,12 +128,7 @@ static char *sign_commit;
128 * if editor is used, and only the whitespaces if the message
129 * is specified explicitly.
130 */
131 -static enum {
132 - CLEANUP_SPACE,
133 - CLEANUP_NONE,
134 - CLEANUP_SCISSORS,
135 - CLEANUP_ALL
136 -} cleanup_mode;
131 +static enum commit_msg_cleanup_mode cleanup_mode;
132 static const char *cleanup_arg;
133
134 static enum commit_whence whence;
@@ -673,7 +668,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
668 struct strbuf sb = STRBUF_INIT;
669 const char *hook_arg1 = NULL;
670 const char *hook_arg2 = NULL;
676 - int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
671 + int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
672 int old_display_comment_prefix;
673
674 /* This checks and barfs if author is badly specified */
@@ -812,7 +807,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
807 struct ident_split ci, ai;
808
809 if (whence != FROM_COMMIT) {
815 - if (cleanup_mode == CLEANUP_SCISSORS)
810 + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
811 wt_status_add_cut_line(s->fp);
812 status_printf_ln(s, GIT_COLOR_NORMAL,
813 whence == FROM_MERGE
@@ -832,14 +827,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
827 }
828
829 fprintf(s->fp, "\n");
835 - if (cleanup_mode == CLEANUP_ALL)
830 + if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
831 status_printf(s, GIT_COLOR_NORMAL,
832 _("Please enter the commit message for your changes."
833 " Lines starting\nwith '%c' will be ignored, and an empty"
834 " message aborts the commit.\n"), comment_line_char);
840 - else if (cleanup_mode == CLEANUP_SCISSORS && whence == FROM_COMMIT)
835 + else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
836 + whence == FROM_COMMIT)
837 wt_status_add_cut_line(s->fp);
842 - else /* CLEANUP_SPACE, that is. */
838 + else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
839 status_printf(s, GIT_COLOR_NORMAL,
840 _("Please enter the commit message for your changes."
841 " Lines starting\n"
@@ -984,65 +980,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
980 return 1;
981 }
982
987 -static int rest_is_empty(struct strbuf *sb, int start)
988 -{
989 - int i, eol;
990 - const char *nl;
991 -
992 - /* Check if the rest is just whitespace and Signed-off-by's. */
993 - for (i = start; i < sb->len; i++) {
994 - nl = memchr(sb->buf + i, '\n', sb->len - i);
995 - if (nl)
996 - eol = nl - sb->buf;
997 - else
998 - eol = sb->len;
999 -
1000 - if (strlen(sign_off_header) <= eol - i &&
1001 - starts_with(sb->buf + i, sign_off_header)) {
1002 - i = eol;
1003 - continue;
1004 - }
1005 - while (i < eol)
1006 - if (!isspace(sb->buf[i++]))
1007 - return 0;
1008 - }
1009 -
1010 - return 1;
1011 -}
1012 -
1013 -/*
1014 - * Find out if the message in the strbuf contains only whitespace and
1015 - * Signed-off-by lines.
1016 - */
1017 -static int message_is_empty(struct strbuf *sb)
1018 -{
1019 - if (cleanup_mode == CLEANUP_NONE && sb->len)
1020 - return 0;
1021 - return rest_is_empty(sb, 0);
1022 -}
1023 -
1024 -/*
1025 - * See if the user edited the message in the editor or left what
1026 - * was in the template intact
1027 - */
1028 -static int template_untouched(struct strbuf *sb)
1029 -{
1030 - struct strbuf tmpl = STRBUF_INIT;
1031 - const char *start;
1032 -
1033 - if (cleanup_mode == CLEANUP_NONE && sb->len)
1034 - return 0;
1035 -
1036 - if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
1037 - return 0;
1038 -
1039 - strbuf_stripspace(&tmpl, cleanup_mode == CLEANUP_ALL);
1040 - if (!skip_prefix(sb->buf, tmpl.buf, &start))
1041 - start = sb->buf;
1042 - strbuf_release(&tmpl);
1043 - return rest_is_empty(sb, start - sb->buf);
1044 -}
1045 -
983 static const char *find_author_by_nickname(const char *name)
984 {
985 struct rev_info revs;
@@ -1214,15 +1151,17 @@ static int parse_and_validate_options(int argc, const char *argv[],
1151 if (argc == 0 && (also || (only && !amend && !allow_empty)))
1152 die(_("No paths with --include/--only does not make sense."));
1153 if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
1217 - cleanup_mode = use_editor ? CLEANUP_ALL : CLEANUP_SPACE;
1154 + cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_ALL :
1155 + COMMIT_MSG_CLEANUP_SPACE;
1156 else if (!strcmp(cleanup_arg, "verbatim"))
1219 - cleanup_mode = CLEANUP_NONE;
1157 + cleanup_mode = COMMIT_MSG_CLEANUP_NONE;
1158 else if (!strcmp(cleanup_arg, "whitespace"))
1221 - cleanup_mode = CLEANUP_SPACE;
1159 + cleanup_mode = COMMIT_MSG_CLEANUP_SPACE;
1160 else if (!strcmp(cleanup_arg, "strip"))
1223 - cleanup_mode = CLEANUP_ALL;
1161 + cleanup_mode = COMMIT_MSG_CLEANUP_ALL;
1162 else if (!strcmp(cleanup_arg, "scissors"))
1225 - cleanup_mode = use_editor ? CLEANUP_SCISSORS : CLEANUP_SPACE;
1163 + cleanup_mode = use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
1164 + COMMIT_MSG_CLEANUP_SPACE;
1165 else
1166 die(_("Invalid cleanup mode %s"), cleanup_arg);
1167
@@ -1749,17 +1688,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
1688 }
1689
1690 if (verbose || /* Truncate the message just before the diff, if any. */
1752 - cleanup_mode == CLEANUP_SCISSORS)
1691 + cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
1692 strbuf_setlen(&sb, wt_status_locate_end(sb.buf, sb.len));
1754 - if (cleanup_mode != CLEANUP_NONE)
1755 - strbuf_stripspace(&sb, cleanup_mode == CLEANUP_ALL);
1693 + if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
1694 + strbuf_stripspace(&sb, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
1695
1757 - if (message_is_empty(&sb) && !allow_empty_message) {
1696 + if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
1697 rollback_index_files();
1698 fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
1699 exit(1);
1700 }
1762 - if (template_untouched(&sb) && !allow_empty_message) {
1701 + if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
1702 rollback_index_files();
1703 fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
1704 exit(1);
sequencer.c
+61
@@ -691,6 +691,67 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
691 return run_command(&cmd);
692 }
693
694 +static int rest_is_empty(const struct strbuf *sb, int start)
695 +{
696 + int i, eol;
697 + const char *nl;
698 +
699 + /* Check if the rest is just whitespace and Signed-off-by's. */
700 + for (i = start; i < sb->len; i++) {
701 + nl = memchr(sb->buf + i, '\n', sb->len - i);
702 + if (nl)
703 + eol = nl - sb->buf;
704 + else
705 + eol = sb->len;
706 +
707 + if (strlen(sign_off_header) <= eol - i &&
708 + starts_with(sb->buf + i, sign_off_header)) {
709 + i = eol;
710 + continue;
711 + }
712 + while (i < eol)
713 + if (!isspace(sb->buf[i++]))
714 + return 0;
715 + }
716 +
717 + return 1;
718 +}
719 +
720 +/*
721 + * Find out if the message in the strbuf contains only whitespace and
722 + * Signed-off-by lines.
723 + */
724 +int message_is_empty(const struct strbuf *sb,
725 + enum commit_msg_cleanup_mode cleanup_mode)
726 +{
727 + if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
728 + return 0;
729 + return rest_is_empty(sb, 0);
730 +}
731 +
732 +/*
733 + * See if the user edited the message in the editor or left what
734 + * was in the template intact
735 + */
736 +int template_untouched(const struct strbuf *sb, const char *template_file,
737 + enum commit_msg_cleanup_mode cleanup_mode)
738 +{
739 + struct strbuf tmpl = STRBUF_INIT;
740 + const char *start;
741 +
742 + if (cleanup_mode == COMMIT_MSG_CLEANUP_NONE && sb->len)
743 + return 0;
744 +
745 + if (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)
746 + return 0;
747 +
748 + strbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
749 + if (!skip_prefix(sb->buf, tmpl.buf, &start))
750 + start = sb->buf;
751 + strbuf_release(&tmpl);
752 + return rest_is_empty(sb, start - sb->buf);
753 +}
754 +
755 static int is_original_commit_empty(struct commit *commit)
756 {
757 const struct object_id *ptree_oid;
sequencer.h
+11
@@ -58,4 +58,15 @@ extern const char sign_off_header[];
58 void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
59 void append_conflicts_hint(struct strbuf *msgbuf);
60
61 +enum commit_msg_cleanup_mode {
62 + COMMIT_MSG_CLEANUP_SPACE,
63 + COMMIT_MSG_CLEANUP_NONE,
64 + COMMIT_MSG_CLEANUP_SCISSORS,
65 + COMMIT_MSG_CLEANUP_ALL
66 +};
67 +
68 +int message_is_empty(const struct strbuf *sb,
69 + enum commit_msg_cleanup_mode cleanup_mode);
70 +int template_untouched(const struct strbuf *sb, const char *template_file,
71 + enum commit_msg_cleanup_mode cleanup_mode);
72 #endif