]> pd.if.org Git - zpackage/blob - zpm-note.c
c94e37b480295cb65f5e06227dfcc171d3424a1c
[zpackage] / zpm-note.c
1 #define _POSIX_C_SOURCE 200809L
2
3 #include <inttypes.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <ctype.h>
8 #include <unistd.h>
9
10 #include "zpm.h"
11
12 void usage(void) {
13         fprintf(stderr, "zpm-note [-I] [-s <status> ...] [-S <status>] [package]\n");
14 }
15
16 void show_note(struct zpm_note *n) {
17         printf("Note %" PRId64 " %s\n", n->id, n->ts);
18         if (n->pkgid) {
19                 printf("Package: %s\n", n->pkgid);
20         }
21         if (n->file) {
22                 printf("Hash: %s\n", n->file);
23         }
24
25         printf("%s\n", n->note);
26 }
27
28 void jstring(char *field, char *value, int indent, int final) {
29         while (indent--) {
30                 putchar('\t');
31         }
32         printf("\"%s\": ", field);
33         if (value) {
34                 printf("\"%s\": ", value);
35         } else {
36                 printf("null");
37         }
38         if (!final) {
39                 printf(",");
40         }
41         putchar('\n');
42 }
43
44 void show_json(struct zpm_note *n) {
45         size_t len = 0;
46
47         if (n->pkgid) {
48                 len = strcspn(n->note, "\n\r");
49         }
50
51         printf("{\n\t\"id\": %" PRId64 ",\n", n->id);
52         jstring("package", n->pkgid, 1, 0);
53         jstring("hash", n->file, 1, 0);
54
55         if (len) {
56                 printf("\t\"subject\": \"%.*s\",\n", (int)len, n->note);
57         } else {
58                 printf("\t\"subject\": null,\n");
59         }
60         jstring("note", n->note, 1, 1);
61         printf("}\n");
62 }
63
64 void print_note(struct zpm_note *n) {
65         size_t len;
66         size_t space = 66;
67         uint64_t id = n->id;
68
69         if (n->pkgid) {
70                 space -= strlen(n->pkgid);
71         } else {
72                 space -= 1;
73         }
74
75         do {
76                 space--;
77         } while (id /= 10);
78
79         len = strcspn(n->note, "\n\r");
80         if (len > space) {
81                 len = space;
82         }
83
84         printf("%" PRId64 " %.10s %s %.*s\n", n->id, n->ts,
85                 n->pkgid ? n->pkgid : "-", (int)len, n->note);
86 }
87
88 int main(int ac, char **av){
89         int opt;
90         struct zpm pkg;
91         char *dbfile;
92         int fail, echo = 0;
93         int64_t start = 0, end = INT64_MAX;
94         char *range = 0;
95
96         int select = 1;
97
98         struct zpm_note n = { 0 };
99         n.pkgid = 0;
100         n.hash = 0;
101         n.path = 0;
102         n.ts = 0;
103
104         dbfile = getenv("ZPMDB");
105         if (!dbfile) {
106                 dbfile = "/var/lib/zpm/local.db";
107         }
108
109         /* -l list
110          * -p packageid
111          * -A ack
112          * -n note id
113          * -D delete
114          * -H hash
115          * -m note message, otherwise EDITOR/vi to edit a text file
116          * -e echo note after creating
117          * zpm note -p pkgid -P path -H hash -m 'foo'
118          * zpm note -l
119          * zpm note -D <n>
120          * zpm note -A <n>
121          */
122         int list = 0, delete = 0, ack = 0, show = 0, json = 0;
123         char *notefrom = 0;
124         while ((opt = getopt(ac, av, "f:p:P:H:m:n:lDAauesjF:")) != -1) {
125                 switch (opt) {
126                         case 'f': dbfile = optarg; break;
127                         case 'p': n.pkgid = optarg; break;
128                         case 'P': n.path = optarg; break;
129                         case 'H': n.hash = optarg; break;
130                         case 'm': n.note = optarg; break;
131                         case 'F': notefrom = optarg; break;
132                         case 'n': range = optarg; break;
133                         case 'l': list = 1; break;
134                         case 'j': json = 1; break;
135                         case 's': show = 1; break;
136                         case 'e': echo = 1; break;
137                         case 'D': delete = 1; break;
138                         case 'A': ack = 1; break;
139                         case 'a': select |= 2; break;
140                         case 'u': select |= 6; break;
141
142                         default:
143                                   usage();
144                                   exit(EXIT_FAILURE);
145                                   break;
146                 }
147         }
148 /* 0x1 = next note,
149  * 0x2 = include acked
150  * 0x4 = suppress unack, implies 0x2
151  */
152
153         if (range) {
154                 if (*range == '-') {
155                         start = 0;
156                         end = strtoll(range+1, NULL, 10);
157                 } else if (isdigit(*range)) {
158                         char *next;
159                         start = strtoll(range, &next, 10);
160                         if (next && *next == '-') {
161                                 end = -1;
162                                 next++;
163                                 if (isdigit(*next)) {
164                                         end = strtoll(next, NULL, 10);
165                                 }
166                         } else {
167                                 end = start;
168                         }
169                 }
170         }
171
172         if (!dbfile) {
173                 fprintf(stderr, "must specify db\n");
174                 return 1;
175         }
176
177         /* given a package name, get the packages */
178         /* no package name, get all */
179         char *filenote = 0;
180         if (notefrom) {
181                 size_t in = 0;
182                 ssize_t cread = 0;
183                 FILE *input;
184
185                 if (strcmp(notefrom, "-")) {
186                         input = fopen(notefrom, "r");
187                 } else {
188                         input = stdin;
189                 }
190                 if (!input) {
191                         perror("can't read input file");
192                         exit(EXIT_FAILURE);
193                 }
194                 cread = getdelim(&filenote, &in, 0, input);
195                 if (cread == -1) {
196                         perror("error reading file");
197                         exit(EXIT_FAILURE);
198                 }
199                 n.note = filenote;
200         }
201
202         if (zpm_open(&pkg, dbfile)) {
203                 if (list || show || delete || ack) {
204                         n.id = start ? start - 1 : start;
205                         while (zpm_note(&pkg, &n, select)) {
206                                 if (n.id > end) {
207                                         break;
208                                 }
209                                 if (delete) {
210                                         zpm_note_del(&pkg, n.id);
211                                 } else if (ack) {
212                                         zpm_note_ack(&pkg, n.id);
213                                 } else if (show) {
214                                         if (json) {
215                                                 show_json(&n);
216                                         } else {
217                                                 show_note(&n);
218                                         }
219                                 } else {
220                                         print_note(&n);
221                                 }
222                                 zpm_note_free(&n);
223                         }
224                         zpm_note_free(&n);
225                 } else if (n.note) {
226                         n.id = zpm_note_add(&pkg, n.pkgid, n.path, n.hash, "%s", n.note);
227                         zpm_note(&pkg, &n, 2);
228                         if (n.id) {
229                                 if (echo) {
230                                         print_note(&n);
231                                 } else {
232                                         printf("%" PRId64 "\n", n.id);
233                                 }
234                         } else {
235                                 fprintf(stderr, "unable to create note\n");
236                                 pkg.error = 1;
237                         }
238                 }
239         } else {
240                 fprintf(stderr, "unable to open %s\n", dbfile);
241         }
242         fail = pkg.error;
243         zpm_close(&pkg);
244         free(filenote);
245         return fail ? EXIT_FAILURE : EXIT_SUCCESS;
246 }