Merge branch 'js/commit-format'
authorJunio C Hamano <junkio@cox.net>
Fri, 2 Mar 2007 08:37:12 +0000 (00:37 -0800)
committerJunio C Hamano <junkio@cox.net>
Fri, 2 Mar 2007 08:37:12 +0000 (00:37 -0800)
* js/commit-format:
show_date(): rename the "relative" parameter to "mode"
Actually make print_wrapped_text() useful
pretty-formats: add 'format:<string>'

1  2 
cache.h
commit.c
commit.h
diff --combined cache.h
index b84e3decfcd38a349243dc8e3a88e1b5151ced6c,75418c0a4c7e6c2a0696f7abc5d328904842e48a..8018b2cd3b20533ea03ce503bc88b8bd0155432e
+++ b/cache.h
@@@ -106,16 -106,6 +106,16 @@@ static inline unsigned int create_ce_mo
                return htonl(S_IFLNK);
        return htonl(S_IFREG | ce_permissions(mode));
  }
 +static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
 +{
 +      extern int trust_executable_bit;
 +      if (!trust_executable_bit && S_ISREG(mode)) {
 +              if (ce && S_ISREG(ntohl(ce->ce_mode)))
 +                      return ce->ce_mode;
 +              return create_ce_mode(0666);
 +      }
 +      return create_ce_mode(mode);
 +}
  #define canon_mode(mode) \
        (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
        S_ISLNK(mode) ? S_IFLNK : S_IFDIR)
@@@ -127,19 -117,6 +127,19 @@@ extern unsigned int active_nr, active_a
  extern struct cache_tree *active_cache_tree;
  extern int cache_errno;
  
 +enum object_type {
 +      OBJ_BAD = -1,
 +      OBJ_NONE = 0,
 +      OBJ_COMMIT = 1,
 +      OBJ_TREE = 2,
 +      OBJ_BLOB = 3,
 +      OBJ_TAG = 4,
 +      /* 5 for future expansion */
 +      OBJ_OFS_DELTA = 6,
 +      OBJ_REF_DELTA = 7,
 +      OBJ_MAX,
 +};
 +
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
@@@ -190,7 -167,7 +190,7 @@@ extern int ce_same_name(struct cache_en
  extern int ce_match_stat(struct cache_entry *ce, struct stat *st, int);
  extern int ce_modified(struct cache_entry *ce, struct stat *st, int);
  extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 -extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
 +extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
  extern int read_pipe(int fd, char** return_buf, unsigned long* return_size);
  extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
@@@ -224,7 -201,6 +224,7 @@@ extern const char *apply_default_whites
  extern int zlib_compression_level;
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
 +extern int auto_crlf;
  
  #define GIT_REPO_VERSION 0
  extern int repository_format_version;
@@@ -276,12 -252,12 +276,12 @@@ int safe_create_leading_directories(cha
  char *enter_repo(char *path, int strict);
  
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
 -extern int sha1_object_info(const unsigned char *, char *, unsigned long *);
 -extern void * unpack_sha1_file(void *map, unsigned long mapsize, char *type, unsigned long *size);
 -extern void * read_sha1_file(const unsigned char *sha1, char *type, unsigned long *size);
 +extern int sha1_object_info(const unsigned char *, unsigned long *);
 +extern void * unpack_sha1_file(void *map, unsigned long mapsize, enum object_type *type, unsigned long *size);
 +extern void * read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size);
  extern int hash_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *sha1);
  extern int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 -extern int pretend_sha1_file(void *, unsigned long, const char *, unsigned char *);
 +extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
@@@ -298,6 -274,18 +298,6 @@@ extern int legacy_loose_object(unsigne
  extern int has_pack_file(const unsigned char *sha1);
  extern int has_pack_index(const unsigned char *sha1);
  
 -enum object_type {
 -      OBJ_NONE = 0,
 -      OBJ_COMMIT = 1,
 -      OBJ_TREE = 2,
 -      OBJ_BLOB = 3,
 -      OBJ_TAG = 4,
 -      /* 5 for future expansion */
 -      OBJ_OFS_DELTA = 6,
 -      OBJ_REF_DELTA = 7,
 -      OBJ_BAD,
 -};
 -
  extern signed char hexval_table[256];
  static inline unsigned int hexval(unsigned int c)
  {
@@@ -327,7 -315,8 +327,8 @@@ extern void *read_object_with_reference
                                        unsigned long *size,
                                        unsigned char *sha1_ret);
  
- const char *show_date(unsigned long time, int timezone, int relative);
+ enum date_mode { DATE_NORMAL = 0, DATE_RELATIVE, DATE_SHORT };
+ const char *show_date(unsigned long time, int timezone, enum date_mode mode);
  const char *show_rfc2822_date(unsigned long time, int timezone);
  int parse_date(const char *date, char *buf, int bufsize);
  void datestamp(char *buf, int bufsize);
@@@ -423,9 -412,9 +424,9 @@@ extern struct packed_git *add_packed_gi
  extern int num_packed_objects(const struct packed_git *p);
  extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
  extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
 -extern void *unpack_entry(struct packed_git *, unsigned long, char *, unsigned long *);
 +extern void *unpack_entry(struct packed_git *, unsigned long, enum object_type *, unsigned long *);
  extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
 -extern void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
 +extern const char *packed_object_info_detail(struct packed_git *, unsigned long, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
@@@ -480,8 -469,4 +481,8 @@@ extern int nfvasprintf(char **str, cons
  extern void trace_printf(const char *format, ...);
  extern void trace_argv_printf(const char **argv, int count, const char *format, ...);
  
 +/* convert.c */
 +extern int convert_to_git(const char *path, char **bufp, unsigned long *sizep);
 +extern int convert_to_working_tree(const char *path, char **bufp, unsigned long *sizep);
 +
  #endif /* CACHE_H */
diff --combined commit.c
index da515a49738c3c8e3065da08e468a93bf976f1e4,f78ce262f6cd141b9b4b8ba1c73fc37ecc07d6f4..555252734298540ffc5678ac5d80888fd23dd4e5
+++ b/commit.c
@@@ -3,6 -3,7 +3,7 @@@
  #include "commit.h"
  #include "pkt-line.h"
  #include "utf8.h"
+ #include "interpolate.h"
  
  int save_commit_buffer = 1;
  
@@@ -36,8 -37,11 +37,11 @@@ struct cmt_fmt_map 
        { "full",       5,      CMIT_FMT_FULL },
        { "fuller",     5,      CMIT_FMT_FULLER },
        { "oneline",    1,      CMIT_FMT_ONELINE },
+       { "format:",    7,      CMIT_FMT_USERFORMAT},
  };
  
+ static char *user_format;
  enum cmit_fmt get_commit_format(const char *arg)
  {
        int i;
                return CMIT_FMT_DEFAULT;
        if (*arg == '=')
                arg++;
+       if (!prefixcmp(arg, "format:")) {
+               if (user_format)
+                       free(user_format);
+               user_format = xstrdup(arg + 7);
+               return CMIT_FMT_USERFORMAT;
+       }
        for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
                if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
                    !strncmp(arg, cmt_fmts[i].n, strlen(arg)))
@@@ -342,18 -352,18 +352,18 @@@ int parse_commit_buffer(struct commit *
  
  int parse_commit(struct commit *item)
  {
 -      char type[20];
 +      enum object_type type;
        void *buffer;
        unsigned long size;
        int ret;
  
        if (item->object.parsed)
                return 0;
 -      buffer = read_sha1_file(item->object.sha1, type, &size);
 +      buffer = read_sha1_file(item->object.sha1, &type, &size);
        if (!buffer)
                return error("Could not read %s",
                             sha1_to_hex(item->object.sha1));
 -      if (strcmp(type, commit_type)) {
 +      if (type != OBJ_COMMIT) {
                free(buffer);
                return error("Object %s not a commit",
                             sha1_to_hex(item->object.sha1));
@@@ -710,6 -720,188 +720,188 @@@ static char *logmsg_reencode(const stru
        return out;
  }
  
+ static char *xstrndup(const char *text, int len)
+ {
+       char *result = xmalloc(len + 1);
+       memcpy(result, text, len);
+       result[len] = '\0';
+       return result;
+ }
+ static void fill_person(struct interp *table, const char *msg, int len)
+ {
+       int start, end, tz = 0;
+       unsigned long date;
+       char *ep;
+       /* parse name */
+       for (end = 0; end < len && msg[end] != '<'; end++)
+               ; /* do nothing */
+       start = end + 1;
+       while (end > 0 && isspace(msg[end - 1]))
+               end--;
+       table[0].value = xstrndup(msg, end);
+       if (start >= len)
+               return;
+       /* parse email */
+       for (end = start + 1; end < len && msg[end] != '>'; end++)
+               ; /* do nothing */
+       if (end >= len)
+               return;
+       table[1].value = xstrndup(msg + start, end - start);
+       /* parse date */
+       for (start = end + 1; start < len && isspace(msg[start]); start++)
+               ; /* do nothing */
+       if (start >= len)
+               return;
+       date = strtoul(msg + start, &ep, 10);
+       if (msg + start == ep)
+               return;
+       table[5].value = xstrndup(msg + start, ep - msg + start);
+       /* parse tz */
+       for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
+               ; /* do nothing */
+       if (start + 1 < len) {
+               tz = strtoul(msg + start + 1, NULL, 10);
+               if (msg[start] == '-')
+                       tz = -tz;
+       }
+       interp_set_entry(table, 2, show_date(date, tz, 0));
+       interp_set_entry(table, 3, show_rfc2822_date(date, tz));
+       interp_set_entry(table, 4, show_date(date, tz, 1));
+ }
+ static long format_commit_message(const struct commit *commit,
+               const char *msg, char *buf, unsigned long space)
+ {
+       struct interp table[] = {
+               { "%H" },       /* commit hash */
+               { "%h" },       /* abbreviated commit hash */
+               { "%T" },       /* tree hash */
+               { "%t" },       /* abbreviated tree hash */
+               { "%P" },       /* parent hashes */
+               { "%p" },       /* abbreviated parent hashes */
+               { "%an" },      /* author name */
+               { "%ae" },      /* author email */
+               { "%ad" },      /* author date */
+               { "%aD" },      /* author date, RFC2822 style */
+               { "%ar" },      /* author date, relative */
+               { "%at" },      /* author date, UNIX timestamp */
+               { "%cn" },      /* committer name */
+               { "%ce" },      /* committer email */
+               { "%cd" },      /* committer date */
+               { "%cD" },      /* committer date, RFC2822 style */
+               { "%cr" },      /* committer date, relative */
+               { "%ct" },      /* committer date, UNIX timestamp */
+               { "%e" },       /* encoding */
+               { "%s" },       /* subject */
+               { "%b" },       /* body */
+               { "%Cred" },    /* red */
+               { "%Cgreen" },  /* green */
+               { "%Cblue" },   /* blue */
+               { "%Creset" },  /* reset color */
+               { "%n" }        /* newline */
+       };
+       enum interp_index {
+               IHASH = 0, IHASH_ABBREV,
+               ITREE, ITREE_ABBREV,
+               IPARENTS, IPARENTS_ABBREV,
+               IAUTHOR_NAME, IAUTHOR_EMAIL,
+               IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
+               IAUTHOR_TIMESTAMP,
+               ICOMMITTER_NAME, ICOMMITTER_EMAIL,
+               ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
+               ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
+               IENCODING,
+               ISUBJECT,
+               IBODY,
+               IRED, IGREEN, IBLUE, IRESET_COLOR,
+               INEWLINE
+       };
+       struct commit_list *p;
+       char parents[1024];
+       int i;
+       enum { HEADER, SUBJECT, BODY } state;
+       if (INEWLINE + 1 != ARRAY_SIZE(table))
+               die("invalid interp table!");
+       /* these are independent of the commit */
+       interp_set_entry(table, IRED, "\033[31m");
+       interp_set_entry(table, IGREEN, "\033[32m");
+       interp_set_entry(table, IBLUE, "\033[34m");
+       interp_set_entry(table, IRESET_COLOR, "\033[m");
+       interp_set_entry(table, INEWLINE, "\n");
+       /* these depend on the commit */
+       if (!commit->object.parsed)
+               parse_object(commit->object.sha1);
+       interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
+       interp_set_entry(table, IHASH_ABBREV,
+                       find_unique_abbrev(commit->object.sha1,
+                               DEFAULT_ABBREV));
+       interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
+       interp_set_entry(table, ITREE_ABBREV,
+                       find_unique_abbrev(commit->tree->object.sha1,
+                               DEFAULT_ABBREV));
+       for (i = 0, p = commit->parents;
+                       p && i < sizeof(parents) - 1;
+                       p = p->next)
+               i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
+                       sha1_to_hex(p->item->object.sha1));
+       interp_set_entry(table, IPARENTS, parents);
+       for (i = 0, p = commit->parents;
+                       p && i < sizeof(parents) - 1;
+                       p = p->next)
+               i += snprintf(parents + i, sizeof(parents) - i - 1, "%s ",
+                       find_unique_abbrev(p->item->object.sha1,
+                               DEFAULT_ABBREV));
+       interp_set_entry(table, IPARENTS_ABBREV, parents);
+       for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
+               int eol;
+               for (eol = i; msg[eol] && msg[eol] != '\n'; eol++)
+                       ; /* do nothing */
+               if (state == SUBJECT) {
+                       table[ISUBJECT].value = xstrndup(msg + i, eol - i);
+                       i = eol;
+               }
+               if (i == eol) {
+                       state++;
+                       /* strip empty lines */
+                       while (msg[eol + 1] == '\n')
+                               eol++;
+               } else if (!prefixcmp(msg + i, "author "))
+                       fill_person(table + IAUTHOR_NAME,
+                                       msg + i + 7, eol - i - 7);
+               else if (!prefixcmp(msg + i, "committer "))
+                       fill_person(table + ICOMMITTER_NAME,
+                                       msg + i + 10, eol - i - 10);
+               else if (!prefixcmp(msg + i, "encoding "))
+                       table[IENCODING].value = xstrndup(msg + i, eol - i);
+               i = eol;
+       }
+       if (msg[i])
+               table[IBODY].value = xstrdup(msg + i);
+       for (i = 0; i < ARRAY_SIZE(table); i++)
+               if (!table[i].value)
+                       interp_set_entry(table, i, "<unknown>");
+       interpolate(buf, space, user_format, table, ARRAY_SIZE(table));
+       interp_clear_table(table, ARRAY_SIZE(table));
+       return strlen(buf);
+ }
  unsigned long pretty_print_commit(enum cmit_fmt fmt,
                                  const struct commit *commit,
                                  unsigned long len,
        char *reencoded;
        char *encoding;
  
+       if (fmt == CMIT_FMT_USERFORMAT)
+               return format_commit_message(commit, msg, buf, space);
        encoding = (git_log_output_encoding
                    ? git_log_output_encoding
                    : git_commit_encoding);
@@@ -1187,17 -1382,14 +1382,17 @@@ struct commit_list *get_merge_bases(str
        return result;
  }
  
 -int in_merge_bases(struct commit *rev1, struct commit *rev2)
 +int in_merge_bases(struct commit *commit, struct commit **reference, int num)
  {
        struct commit_list *bases, *b;
        int ret = 0;
  
 -      bases = get_merge_bases(rev1, rev2, 1);
 +      if (num == 1)
 +              bases = get_merge_bases(commit, *reference, 1);
 +      else
 +              die("not yet");
        for (b = bases; b; b = b->next) {
 -              if (!hashcmp(rev1->object.sha1, b->item->object.sha1)) {
 +              if (!hashcmp(commit->object.sha1, b->item->object.sha1)) {
                        ret = 1;
                        break;
                }
diff --combined commit.h
index c73744463ca55ce0df3623dffbb994bd4a86d76e,8feeb2c7ba52a1dde0bddf532e576540dfb513c5..83507a07e4cbaab81f130891a64b78539d1beede
+++ b/commit.h
@@@ -47,6 -47,7 +47,7 @@@ enum cmit_fmt 
        CMIT_FMT_FULLER,
        CMIT_FMT_ONELINE,
        CMIT_FMT_EMAIL,
+       CMIT_FMT_USERFORMAT,
  
        CMIT_FMT_UNSPECIFIED,
  };
@@@ -114,5 -115,5 +115,5 @@@ extern int is_repository_shallow(void)
  extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
  
 -int in_merge_bases(struct commit *rev1, struct commit *rev2);
 +int in_merge_bases(struct commit *, struct commit **, int);
  #endif /* COMMIT_H */