]> pd.if.org Git - zpackage/commitdiff
rework zpm-note
authorNathan Wagner <nw@hydaspes.if.org>
Sun, 9 Dec 2018 15:11:08 +0000 (15:11 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Sun, 9 Dec 2018 15:17:51 +0000 (15:17 +0000)
zpm-note now takes a range of note ids with -n, and both delete and ack
will work on that range.  The show output can take a -j option to output
json, and the date of the note was added to the list output.

Makefile
doc/zpm-note.8 [new file with mode: 0644]
lib/notes.c
schema/main.sql
zpm-note.c
zpm.h

index 85a5d13dcce9ba837bc686260b5e0d4ebf53026f..dd84d52f9e0153ceb48ff6b6fb30703ceb2f50c0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -34,7 +34,7 @@ ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
        zpm-pkg zpm-add zpm-pkgfile zpm-gc zpm-repo zpm-update zpm-confgit
-MANPAGES=doc/zpm.8 $(addprefix doc/zpm-, list.8 contents.8 hash.8 quote.8 pathmod.8 )
+MANPAGES=doc/zpm.8 $(addprefix doc/zpm-, list.8 contents.8 hash.8 quote.8 pathmod.8 note.8)
 COMPILED=$(ZPKGBIN)
 PROGRAMS=$(SCRIPTS) $(COMPILED)
 
diff --git a/doc/zpm-note.8 b/doc/zpm-note.8
new file mode 100644 (file)
index 0000000..29650db
--- /dev/null
@@ -0,0 +1,86 @@
+.TH zpm-note 8 2018-12-09 "ZPM 0.4"
+.SH NAME
+zpm-note \- manage zpm admin notes
+.SH SYNOPSIS
+.B zpm note
+[
+.BI -f " pkgfile"
+]
+[
+.B -ljseDAa
+]
+.RI [ package ...]
+.RB [ :
+.IR glob ...\fR]
+.SH DESCRIPTION
+\fBzpm-note\fR lists, shows, creates, or deletes admin notes.
+.SH OPTIONS
+.TP
+\-f
+specify the package file to find packages in
+.TP
+.BI \-n " range"
+specify the range of notes to be operated on in show, list, ack, and delete
+modes.  The \fIrange\fR can be in the form of
+\fIstart\fB-\fIend\fR,
+\fB-\fIend\fR,
+\fIstart\fB-\fR, or
+\fin\fR, where \fIn\fR is a single note, and the other forms
+specify an inclusive range, if either the start or the end is not
+given in a range, it is taken to be unbounded.
+.TP
+\-a
+include acknowledged notes in the range
+\-u
+suppress unacknowledged notes, i.e. just select acknowledged notes
+in the range.  Implies \-a.
+.TP
+\-l
+list a range of notes.  The output will be constrained to fit on one
+line.  Only as many characters from the first line of the note as will fit
+will be printed.
+.TP
+\-s
+show a range of notes in full format
+.TP
+\-j
+use json output if in show (-s) mode
+.TP
+\-D
+delete a range of notes
+.TP
+\-A
+acknowledge a range of notes
+.TP
+\-e
+when adding a note, print the resulting note to stdout as if the new note were
+to be listed with -l.  By default, only the new note number is printed to
+stdout.
+.TP
+\-m \fimessage\fR
+specify the note message
+.TP
+\-a
+operate on all notes in the range.  by default, only un-acknowledged notes
+are operated on.
+.TP
+-F \fIfile\fR
+Take the note message from the given file.  If the file is "-", the
+message is taken from standard input.
+.SH EXAMPLES
+.TP
+zpm note -m 'foo'
+create a new note named foo
+.TP
+zpm note -l -n 1-10
+list unacknowledged notes from 1-10
+.SH EXIT STATUS
+0 on success non zero on failure
+.SH FILES
+/var/lib/zpm/local.db
+.SH ENVIRONMENT
+ZPMDB
+.SH AUTHOR
+Nathan Wagner
+.SH SEE ALSO
+zpm(8)
index b337fd446756a320330519e6f6bfaa7a3a48eea1..b29cbc79f5438ad83a78c8c3952853a7aa0c73a9 100644 (file)
@@ -69,7 +69,7 @@ int64_t zpm_note(struct zpm *zpm, struct zpm_note *n, unsigned int flags) {
                        n->path = colstring(st, 4);
                        n->file = colstring(st, 5);
                        n->ack = sqlite3_column_int(st, 6);
-                       n->ts = sqlite3_column_int(st, 1);
+                       n->ts = colstring(st, 1);
                        n->id = sqlite3_column_int64(st, 0);
                        id = n->id;
                        break;
@@ -87,7 +87,8 @@ void zpm_note_free(struct zpm_note *n) {
        free(n->pkgid);
        free(n->path);
        free(n->file);
-       n->note = n->pkgid = n->path = n->file = 0;
+       free(n->ts);
+       n->note = n->ts = n->pkgid = n->path = n->file = 0;
 }
 
 int zpm_notes_available(struct zpm *zpm, int flags) {
index c9c79a26e0f338920d9bfcf0894066a2ef23cc47..b0675509e1a6884e8b2ba6560a91350111bed3fd 100644 (file)
@@ -372,7 +372,7 @@ create table zpmlog (
 
 create table notes (
        id      integer primary key, -- rowid alias
-       ts      text default (strftime('%Y-%m-%d %H:%M:%f', 'now')),
+       ts      text default (strftime('%Y-%m-%dT%H:%M:%f', 'now')),
        note    text not null,
        pkgid   text, -- package
        path    text, -- file path involved
index 927f30a45b8443ed6c93f92a25ae2061fdef35c7..c94e37b480295cb65f5e06227dfcc171d3424a1c 100644 (file)
@@ -3,6 +3,7 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 #include <ctype.h>
 #include <unistd.h>
 
@@ -12,8 +13,76 @@ void usage(void) {
        fprintf(stderr, "zpm-note [-I] [-s <status> ...] [-S <status>] [package]\n");
 }
 
+void show_note(struct zpm_note *n) {
+       printf("Note %" PRId64 " %s\n", n->id, n->ts);
+       if (n->pkgid) {
+               printf("Package: %s\n", n->pkgid);
+       }
+       if (n->file) {
+               printf("Hash: %s\n", n->file);
+       }
+
+       printf("%s\n", n->note);
+}
+
+void jstring(char *field, char *value, int indent, int final) {
+       while (indent--) {
+               putchar('\t');
+       }
+       printf("\"%s\": ", field);
+       if (value) {
+               printf("\"%s\": ", value);
+       } else {
+               printf("null");
+       }
+       if (!final) {
+               printf(",");
+       }
+       putchar('\n');
+}
+
+void show_json(struct zpm_note *n) {
+       size_t len = 0;
+
+       if (n->pkgid) {
+               len = strcspn(n->note, "\n\r");
+       }
+
+       printf("{\n\t\"id\": %" PRId64 ",\n", n->id);
+       jstring("package", n->pkgid, 1, 0);
+       jstring("hash", n->file, 1, 0);
+
+       if (len) {
+               printf("\t\"subject\": \"%.*s\",\n", (int)len, n->note);
+       } else {
+               printf("\t\"subject\": null,\n");
+       }
+       jstring("note", n->note, 1, 1);
+       printf("}\n");
+}
+
 void print_note(struct zpm_note *n) {
-       printf("%" PRId64 " %s %s\n", n->id, n->pkgid ? n->pkgid : "-", n->note);
+       size_t len;
+       size_t space = 66;
+       uint64_t id = n->id;
+
+       if (n->pkgid) {
+               space -= strlen(n->pkgid);
+       } else {
+               space -= 1;
+       }
+
+       do {
+               space--;
+       } while (id /= 10);
+
+       len = strcspn(n->note, "\n\r");
+       if (len > space) {
+               len = space;
+       }
+
+       printf("%" PRId64 " %.10s %s %.*s\n", n->id, n->ts,
+               n->pkgid ? n->pkgid : "-", (int)len, n->note);
 }
 
 int main(int ac, char **av){
@@ -21,6 +90,8 @@ int main(int ac, char **av){
        struct zpm pkg;
        char *dbfile;
        int fail, echo = 0;
+       int64_t start = 0, end = INT64_MAX;
+       char *range = 0;
 
        int select = 1;
 
@@ -28,6 +99,7 @@ int main(int ac, char **av){
        n.pkgid = 0;
        n.hash = 0;
        n.path = 0;
+       n.ts = 0;
 
        dbfile = getenv("ZPMDB");
        if (!dbfile) {
@@ -40,7 +112,6 @@ int main(int ac, char **av){
         * -n note id
         * -D delete
         * -H hash
-        * -a all
         * -m note message, otherwise EDITOR/vi to edit a text file
         * -e echo note after creating
         * zpm note -p pkgid -P path -H hash -m 'foo'
@@ -48,20 +119,25 @@ int main(int ac, char **av){
         * zpm note -D <n>
         * zpm note -A <n>
         */
-       int list = 0, delete = 0, ack = 0;
-       while ((opt = getopt(ac, av, "f:p:P:H:m:n:lDAae")) != -1) {
+       int list = 0, delete = 0, ack = 0, show = 0, json = 0;
+       char *notefrom = 0;
+       while ((opt = getopt(ac, av, "f:p:P:H:m:n:lDAauesjF:")) != -1) {
                switch (opt) {
                        case 'f': dbfile = optarg; break;
                        case 'p': n.pkgid = optarg; break;
                        case 'P': n.path = optarg; break;
                        case 'H': n.hash = optarg; break;
                        case 'm': n.note = optarg; break;
-                       case 'n': n.id = strtoll(optarg, NULL, 10); break;
+                       case 'F': notefrom = optarg; break;
+                       case 'n': range = optarg; break;
                        case 'l': list = 1; break;
+                       case 'j': json = 1; break;
+                       case 's': show = 1; break;
                        case 'e': echo = 1; break;
                        case 'D': delete = 1; break;
                        case 'A': ack = 1; break;
-                       case 'a': select = 3; break;
+                       case 'a': select |= 2; break;
+                       case 'u': select |= 6; break;
 
                        default:
                                  usage();
@@ -69,6 +145,29 @@ int main(int ac, char **av){
                                  break;
                }
        }
+/* 0x1 = next note,
+ * 0x2 = include acked
+ * 0x4 = suppress unack, implies 0x2
+ */
+
+       if (range) {
+               if (*range == '-') {
+                       start = 0;
+                       end = strtoll(range+1, NULL, 10);
+               } else if (isdigit(*range)) {
+                       char *next;
+                       start = strtoll(range, &next, 10);
+                       if (next && *next == '-') {
+                               end = -1;
+                               next++;
+                               if (isdigit(*next)) {
+                                       end = strtoll(next, NULL, 10);
+                               }
+                       } else {
+                               end = start;
+                       }
+               }
+       }
 
        if (!dbfile) {
                fprintf(stderr, "must specify db\n");
@@ -77,15 +176,55 @@ int main(int ac, char **av){
 
        /* given a package name, get the packages */
        /* no package name, get all */
+       char *filenote = 0;
+       if (notefrom) {
+               size_t in = 0;
+               ssize_t cread = 0;
+               FILE *input;
+
+               if (strcmp(notefrom, "-")) {
+                       input = fopen(notefrom, "r");
+               } else {
+                       input = stdin;
+               }
+               if (!input) {
+                       perror("can't read input file");
+                       exit(EXIT_FAILURE);
+               }
+               cread = getdelim(&filenote, &in, 0, input);
+               if (cread == -1) {
+                       perror("error reading file");
+                       exit(EXIT_FAILURE);
+               }
+               n.note = filenote;
+       }
 
        if (zpm_open(&pkg, dbfile)) {
-               if (list) {
+               if (list || show || delete || ack) {
+                       n.id = start ? start - 1 : start;
                        while (zpm_note(&pkg, &n, select)) {
-                               print_note(&n);
+                               if (n.id > end) {
+                                       break;
+                               }
+                               if (delete) {
+                                       zpm_note_del(&pkg, n.id);
+                               } else if (ack) {
+                                       zpm_note_ack(&pkg, n.id);
+                               } else if (show) {
+                                       if (json) {
+                                               show_json(&n);
+                                       } else {
+                                               show_note(&n);
+                                       }
+                               } else {
+                                       print_note(&n);
+                               }
                                zpm_note_free(&n);
                        }
+                       zpm_note_free(&n);
                } else if (n.note) {
                        n.id = zpm_note_add(&pkg, n.pkgid, n.path, n.hash, "%s", n.note);
+                       zpm_note(&pkg, &n, 2);
                        if (n.id) {
                                if (echo) {
                                        print_note(&n);
@@ -96,15 +235,12 @@ int main(int ac, char **av){
                                fprintf(stderr, "unable to create note\n");
                                pkg.error = 1;
                        }
-               } else if (delete) {
-                       zpm_note_del(&pkg, n.id);
-               } else if (ack) {
-                       zpm_note_ack(&pkg, n.id);
                }
        } else {
                fprintf(stderr, "unable to open %s\n", dbfile);
        }
        fail = pkg.error;
        zpm_close(&pkg);
+       free(filenote);
        return fail ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/zpm.h b/zpm.h
index 9be5f60aaffbf17c1e334b11a2896db6107417d6..ea9cd6c96ec406073662475e9086a5648b0b72de 100644 (file)
--- a/zpm.h
+++ b/zpm.h
@@ -201,7 +201,7 @@ struct zpm *zpm_clearmem(struct zpm *zpm);
 
 struct zpm_note {
        int64_t id;
-       time_t ts; /* or timespec */
+       char *ts; /* applications can parse it if they need to */
        char *note;
        char *pkgid;
        char *path;