The patches for 3.2.6.
[rsync-patches.git] / json-version.diff
1 This patch changes a repeated `--version` (`-V`) to output the
2 version, capabilities, etc. in json format.
3
4 To use this patch, run these commands for a successful build:
5
6     patch -p1 <patches/json-version.diff
7     ./configure                               (optional if already run)
8     make
9
10 based-on: db5bfe67a5d022f9ad25340db6bc2cca2cbbdb65
11 diff --git a/options.c b/options.c
12 --- a/options.c
13 +++ b/options.c
14 @@ -1926,7 +1926,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
15                 saw_stderr_opt = 1;
16  
17         if (version_opt_cnt) {
18 -               print_rsync_version(FINFO);
19 +               print_rsync_version(FINFO, version_opt_cnt > 1);
20                 exit_cleanup(0);
21         }
22  
23 diff --git a/usage.c b/usage.c
24 --- a/usage.c
25 +++ b/usage.c
26 @@ -22,6 +22,7 @@
27  #include "latest-year.h"
28  #include "git-version.h"
29  #include "default-cvsignore.h"
30 +#include "itypes.h"
31  
32  extern struct name_num_obj valid_checksums;
33  extern struct name_num_obj valid_compressions;
34 @@ -34,10 +35,10 @@ static char *istring(const char *fmt, int val)
35         return str;
36  }
37  
38 -static void print_info_flags(enum logcode f)
39 +static void print_info_flags(enum logcode f, BOOL as_json)
40  {
41         STRUCT_STAT *dumstat;
42 -       char line_buf[75];
43 +       char line_buf[75], *quot = as_json ? "\"" : "";
44         int line_len, j;
45         char *info_flags[] = {
46  
47 @@ -161,10 +162,12 @@ static void print_info_flags(enum logcode f)
48  
49                 NULL
50         };
51 +       if (as_json)
52 +               as_json = 1; /* We use 1 == first attribute, 2 == need closing array */
53  
54         for (line_len = 0, j = 0; ; j++) {
55                 char *str = info_flags[j], *next_nfo = str ? info_flags[j+1] : NULL;
56 -               int str_len = str && *str != '*' ? strlen(str) : 1000;
57 +               int str_len = str && *str != '*' ? strlen(str) + (as_json ? 2 : 0) : 1000;
58                 int need_comma = next_nfo && *next_nfo != '*' ? 1 : 0;
59                 if (line_len && line_len + 1 + str_len + need_comma >= (int)sizeof line_buf) {
60                         rprintf(f, "   %s\n", line_buf);
61 @@ -173,37 +176,88 @@ static void print_info_flags(enum logcode f)
62                 if (!str)
63                         break;
64                 if (*str == '*') {
65 -                       rprintf(f, "%s:\n", str+1);
66 +                       if (as_json) {
67 +                               if (as_json == 2)
68 +                                       printf("  ],\n");
69 +                               else
70 +                                       as_json = 2;
71 +                               printf("  \"%c%s\": [\n", toLower(str+1), str+2);
72 +                       } else
73 +                               rprintf(f, "%s:\n", str+1);
74                         continue;
75                 }
76 -               line_len += snprintf(line_buf+line_len, sizeof line_buf - line_len, " %s%s", str, need_comma ? "," : "");
77 +               line_len += snprintf(line_buf+line_len, sizeof line_buf - line_len,
78 +                                    " %s%s%s%s", quot, str, quot, need_comma ? "," : "");
79         }
80 +       if (as_json == 2)
81 +               printf("  ],\n");
82  }
83  
84 -void print_rsync_version(enum logcode f)
85 +void output_json_list(const char *name, char *tmpbuf)
86 +{
87 +       char *comma = ",";
88 +       char *tok = strtok(tmpbuf, " ");
89 +       char *next_tok = tok ? strtok(NULL, " ") : NULL;
90 +
91 +       printf("  \"%s\": [\n   ", name);
92 +
93 +       while (tok) {
94 +               printf(" \"%s\"%s", tok, comma + (next_tok ? 0 : 1));
95 +               if ((tok = next_tok) != NULL)
96 +                       next_tok = strtok(NULL, " ");
97 +       }
98 +       printf("\n  ],\n");
99 +}
100 +
101 +void print_rsync_version(enum logcode f, BOOL as_json)
102  {
103         char tmpbuf[256], *subprotocol = "";
104  
105  #if SUBPROTOCOL_VERSION != 0
106         subprotocol = istring(".PR%d", SUBPROTOCOL_VERSION);
107  #endif
108 -       rprintf(f, "%s  version %s  protocol version %d%s\n",
109 -               RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol);
110  
111 -       rprintf(f, "Copyright (C) 1996-" LATEST_YEAR " by Andrew Tridgell, Wayne Davison, and others.\n");
112 -       rprintf(f, "Web site: https://rsync.samba.org/\n");
113 +       if (as_json) {
114 +               printf("{\n  \"program\": \"%s\",\n  \"version\": \"%s\",\n  \"protocol\": \"%d%s\",\n",
115 +                       RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol);
116 +       } else {
117 +               rprintf(f, "%s  version %s  protocol version %d%s\n",
118 +                       RSYNC_NAME, rsync_version(), PROTOCOL_VERSION, subprotocol);
119 +       }
120  
121 -       print_info_flags(f);
122 +#define vinfo(name, pre, msg, suf) \
123 +       if (as_json) \
124 +               printf("  \"%s\": \"%s\",\n", name, msg); \
125 +       else \
126 +               rprintf(f, "%s%s%s", pre ? pre : name, msg, suf);
127 +
128 +       vinfo("copyright", "Copyright ", "(C) 1996-" LATEST_YEAR " by Andrew Tridgell, Wayne Davison, and others.", "\n");
129 +       vinfo("url", "Web site: ", "https://rsync.samba.org/", "\n");
130 +
131 +       print_info_flags(f, as_json);
132  
133         init_checksum_choices();
134  
135 -       rprintf(f, "Checksum list:\n");
136 -       get_default_nno_list(&valid_checksums, tmpbuf, sizeof tmpbuf, '(');
137 -       rprintf(f, "    %s\n", tmpbuf);
138 +       get_default_nno_list(&valid_checksums, tmpbuf, sizeof tmpbuf, as_json ? '\0' : '(');
139 +       if (as_json)
140 +               output_json_list("checksum_list", tmpbuf);
141 +       else {
142 +               rprintf(f, "Checksum list:\n");
143 +               rprintf(f, "    %s\n", tmpbuf);
144 +       }
145  
146 -       rprintf(f, "Compress list:\n");
147 -       get_default_nno_list(&valid_compressions, tmpbuf, sizeof tmpbuf, '(');
148 -       rprintf(f, "    %s\n", tmpbuf);
149 +       get_default_nno_list(&valid_compressions, tmpbuf, sizeof tmpbuf, as_json ? '\0' : '(');
150 +       if (as_json)
151 +               output_json_list("compress_list", tmpbuf);
152 +       else {
153 +               rprintf(f, "Compress list:\n");
154 +               rprintf(f, "    %s\n", tmpbuf);
155 +       }
156 +
157 +       if (as_json) {
158 +               printf("  \"caveat\": \"rsync comes with ABSOLUTELY NO WARRANTY\"\n}\n");
159 +               return;
160 +       }
161  
162  #ifdef MAINTAINER_MODE
163         rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
164 @@ -226,7 +280,7 @@ void print_rsync_version(enum logcode f)
165  
166  void usage(enum logcode F)
167  {
168 -  print_rsync_version(F);
169 +  print_rsync_version(F, 0);
170  
171    rprintf(F,"\n");
172    rprintf(F,"rsync is a file transfer program capable of efficient remote update\n");
173 @@ -253,7 +307,7 @@ void usage(enum logcode F)
174  
175  void daemon_usage(enum logcode F)
176  {
177 -  print_rsync_version(F);
178 +  print_rsync_version(F, 0);
179  
180    rprintf(F,"\n");
181    rprintf(F,"Usage: rsync --daemon [OPTION]...\n");