This adds a --json switch to status, which enables a json output format. This provides a standard output format that should be easily parsed by scripts using any of the large number of readily available json libraries. Signed-off-by: Julian Phillips <julian@xxxxxxxxxxxxxxxxx> --- On Sat, 10 Apr 2010, Eric Raymond wrote: > Julian Phillips <julian@xxxxxxxxxxxxxxxxx>: >> I didn't use "-" instead of " " as that seemed out of scope for a output >> formatting option. Though I don't personally have an objection to it, I >> also don't see a particularly strong need for it as with the -Z format >> there is no ambiguity. > > Good point. OK, the combinaation of -Z and a switch to list ignored > files should solve Emacs VC's problem. > > Having some sort of JSON dump might still not be a bad idea. Starter for 10 ... builtin/commit.c | 10 ++++ wt-status.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wt-status.h | 1 + 3 files changed, 143 insertions(+), 0 deletions(-) diff --git a/builtin/commit.c b/builtin/commit.c index c5ab683..f2b5cfa 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -91,6 +91,7 @@ static enum { STATUS_FORMAT_LONG, STATUS_FORMAT_SHORT, STATUS_FORMAT_PORCELAIN, + STATUS_FORMAT_JSON, } status_format = STATUS_FORMAT_LONG; static int opt_parse_m(const struct option *opt, const char *arg, int unset) @@ -422,6 +423,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(s, null_termination); break; + case STATUS_FORMAT_JSON: + wt_json_print(s); + break; case STATUS_FORMAT_LONG: wt_status_print(s); break; @@ -1025,6 +1029,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_SET_INT(0, "porcelain", &status_format, "show porcelain output format", STATUS_FORMAT_PORCELAIN), + OPT_SET_INT(0, "json", &status_format, + "show json output format", + STATUS_FORMAT_JSON), OPT_BOOLEAN('z', "null", &null_termination, "terminate entries with NUL"), { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, @@ -1068,6 +1075,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(&s, null_termination); break; + case STATUS_FORMAT_JSON: + wt_json_print(&s); + break; case STATUS_FORMAT_LONG: s.verbose = verbose; wt_status_print(&s); diff --git a/wt-status.c b/wt-status.c index 8ca59a2..ab934e7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -750,3 +750,135 @@ void wt_porcelain_print(struct wt_status *s, int null_termination) s->prefix = NULL; wt_shortstatus_print(s, null_termination); } + +static char *json_quote(char *s) +{ + struct strbuf buf = STRBUF_INIT; + + while (*s) { + switch (*s) { + case '"': + strbuf_addstr(&buf, "\\\""); + break; + case '\\': + strbuf_addstr(&buf, "\\\\"); + break; + case '\b': + strbuf_addstr(&buf, "\\b"); + break; + case '\f': + strbuf_addstr(&buf, "\\f"); + break; + case '\n': + strbuf_addstr(&buf, "\\n"); + break; + case '\r': + strbuf_addstr(&buf, "\\r"); + break; + case '\t': + strbuf_addstr(&buf, "\\t"); + break; + default: + /* All control characters must be encode, even if they + * don't have a specific escape character of their own */ + if (*s < 0x20) + strbuf_addf(&buf, "\\u%04x", *s); + else + strbuf_addch(&buf, *s); + break; + } + s++; + } + + return strbuf_detach(&buf, NULL); +} + +static void wt_json_unmerged(struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + char ours = '?', theirs = '?'; + char *name = json_quote(it->string); + + switch (d->stagemask) { + case 1: ours = 'D'; theirs = 'D'; break; /* both deleted */ + case 2: ours = 'A'; theirs = 'U'; break; /* added by us */ + case 3: ours = 'U'; theirs = 'D'; break; /* deleted by them */ + case 4: ours = 'U'; theirs = 'A'; break; /* added by them */ + case 5: ours = 'D'; theirs = 'U'; break; /* deleted by us */ + case 6: ours = 'A'; theirs = 'A'; break; /* both added */ + case 7: ours = 'U'; theirs = 'U'; break; /* both modified */ + } + + fprintf(stdout, "{"); + fprintf(stdout, "\"ours\" : \"%c\", ", ours); + fprintf(stdout, "\"theirs\" : \"%c\", ", theirs); + fprintf(stdout, "\"name\" : \"%s\"", name); + fprintf(stdout, "}"); + + free(name); +} + +static void wt_json_status(struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + char index = '-', worktree = '-'; + char *name = json_quote(it->string); + + if (d->index_status) + index = d->index_status; + if (d->worktree_status) + worktree = d->worktree_status; + + fprintf(stdout, "{"); + fprintf(stdout, "\"index\" : \"%c\", ", index); + fprintf(stdout, "\"worktree\" : \"%c\", ", worktree); + fprintf(stdout, "\"name\" : \"%s\"", name); + + if (d->head_path) { + free(name); + name = json_quote(d->head_path); + fprintf(stdout, ", \"orig_name\" : \"%s\"", name); + } + + fprintf(stdout, "}"); + + free(name); +} + +void wt_json_print(struct wt_status *s) +{ + int i; + fprintf(stdout, "["); + for (i = 0; i < s->change.nr; i++) { + struct wt_status_change_data *d; + struct string_list_item *it; + + if (i > 0) + fprintf(stdout, ",\n"); + it = &(s->change.items[i]); + d = it->util; + if (d->stagemask) + wt_json_unmerged(it, s); + else + wt_json_status(it, s); + } + if (s->change.nr > 0 && s->untracked.nr > 0) + fprintf(stdout, ",\n"); + for (i = 0; i < s->untracked.nr; i++) { + char *name = json_quote(s->untracked.items[i].string); + + if (i > 0) + fprintf(stdout, ",\n"); + + fprintf(stdout, "{"); + fprintf(stdout, "\"index\" : \"?\", "); + fprintf(stdout, "\"worktree\" : \"?\", "); + fprintf(stdout, "\"name\" : \"%s\"", name); + fprintf(stdout, "}"); + + free(name); + } + fprintf(stdout, "]\n"); +} diff --git a/wt-status.h b/wt-status.h index 9120673..effd3fd 100644 --- a/wt-status.h +++ b/wt-status.h @@ -61,5 +61,6 @@ void wt_status_collect(struct wt_status *s); void wt_shortstatus_print(struct wt_status *s, int null_termination); void wt_porcelain_print(struct wt_status *s, int null_termination); +void wt_json_print(struct wt_status *s); #endif /* STATUS_H */ -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html