;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; CLI for sr.ht ;;; ;;; Copyright (c) 2019, Evan Hanson ;;; ;;; See LICENSE for details. ;;; (declare (module (topham cli))) (import (chicken condition) (chicken keyword) (chicken io) (chicken pretty-print) (chicken process-context) (chicken string) (openssl) (topham) (topham builds) (topham meta) (topham paste) (medea) (optimism getopt-long) (simple-exceptions) (only (srfi 1) any)) (import-syntax (matchable)) (define common-options '((--access-token . token) ((-o --output) . format) ((-h --help)))) (define output-format (make-parameter "s" string->symbol)) (define (alist-ref* keys . args) (any (lambda (key) (apply alist-ref key args)) keys)) (define (error-message e) (let ((m (message e)) (a (arguments e))) (if (null? a) m (conc m ": " (string-intersperse (map conc a) ", "))))) (define (print-json . args) (apply write-json args) (print)) (define (string->id x) (let ((id (string->number x))) (if (and (integer? id) (positive? id)) id (error "Invalid ID" x)))) (define (crud? x) (and (pair? x) (pair? (car x)) (keyword? (caar x)))) (define (output x) (let ((printer (case (output-format) ((s) pretty-print) ((j json) print-json)))) (cond ((crud? x) (printer (cdr x))) ((string? x) (print (string-chomp x))) (else (printer x))))) (define (input x) (if (equal? x "-") (read-string) (with-input-from-file x read-string))) (define (get-profile) (retrieve (profile))) (define (get-audit-log) (retrieve (audit-log))) (define (get-ssh-keys) (retrieve (ssh-keys))) (define (get-pgp-keys) (retrieve (pgp-keys))) (define ((key-creator type function) args) (define opts (parse-command-line args '(((-f --filename) . input)))) (define file (alist-ref* '(-f --filename) opts eq? "-")) (match (assq '-- opts) ((_) (create (apply function (list type (input file))))) ((_ . _) (usage (current-error-port)) (exit 1)))) (define ((key-deleter function) id) (delete (function (string->id id)))) (define (create-job args) (define opts (parse-command-line args '(((-m --manifest) . input) ((-f --filename) . input) ((-n --note) . message)))) (define manifest (alist-ref* '(-m --manifest -f --filename) opts eq? "-")) (define note (alist-ref* '(-n --note) opts)) (match (assq '-- opts) ((_) (let ((args* (append (list manifest: (input manifest)) (if (not note) (list) (list note: note))))) (create (apply job args*)))) ((_ . _) (usage (current-error-port)) (exit 1)))) (define (get-manifest id) (retrieve (manifest (string->id id)))) (define (get-job id) (retrieve (job (string->id id)))) (define (create-paste args) (define opts (parse-command-line args '(((-c --contents) . input) ((-f --filename) . input) ((-n --name) . name) ((-v --visibility) . level)))) (define contents (alist-ref* '(-c --contents -f --filename) opts eq? "-")) (define filename (alist-ref* '(-n --name) opts eq? 'null)) (define visibility (alist-ref* '(-v --visibility) opts eq? "unlisted")) (match (assq '-- opts) ((_) (let ((args* (list contents: (input contents) filename: filename visibility: visibility))) (create (apply paste args*)))) ((_ . _) (usage (current-error-port)) (exit 1)))) (define (create-paste* args) (let ((paste (create-paste args))) (conc "https://paste." (service-domain) "/blob/" (alist-ref 'blob_id (vector-ref (alist-ref 'files paste) 0))))) (define (get-paste sha) (retrieve (paste sha))) (define (get-pastes) (retrieve (pastes))) (define (get-blob sha) (and-let* ((blob (retrieve (blob sha)))) (alist-ref 'contents blob))) (define (usage #!optional (port (current-output-port))) (parameterize ((current-output-port port)) (print "Usage: " (program-name) " [options ...] command ...") (print) (print "Options:") (print " --access-token Set API token (SRHT_ACCESS_TOKEN)") (print " -o, --output Set output format {s|j|json} (s)") (print " -h, --help Show this message") (print) (print "Commands:") (print) (print " get profile Fetch user details") (print " get audit-log Fetch audit log") (print " get ssh-keys List SSH keys") (print " get pgp-keys List PGP keys") (print " create ssh-key Create SSH key") (print " -f, --filename filename (stdin)") (print " create pgp-key Create PGP key") (print " -f, --filename filename (stdin)") (print " delete ssh-key Delete SSH key") (print " delete pgp-key Delete PGP key") (print) (print " get job Fetch job details") (print " get manifest Fetch job manifest") (print " create job Create job") (print " -m, --manifest manifest (stdin)") (print " -n, --note description (null)") (print) (print " get pastes List pastes") (print " get paste Fetch paste details") (print " get blob Fetch blob contents") (print " create paste Create paste") (print " paste Create paste and print URL") (print " -c, --contents source (stdin)") (print " -n, --name name (null)") (print " -v, --visibility visibility (unlisted)") (print))) (define (handle-global-options! opts) (and-let* ((help (alist-ref* '(-h --help) opts))) (usage) (exit 0)) (and-let* ((format (alist-ref* '(-o --output) opts))) (output-format format) (unless (member (output-format) '(s j json)) (error "Invalid output format" format))) (and-let* ((token (alist-ref '--access-token opts))) (access-token token))) (define (main args) (let ((opts (parse-command-line args common-options))) (handle-global-options! opts) (match (assq '-- opts) ((_ "get" "profile") (output (get-profile))) ((_ "get" (or "audit" "audit-log" "audit-logs")) (output (get-audit-log))) ((_ "get" (or "ssh-key" "ssh-keys")) (output (get-ssh-keys))) ((_ "create" "ssh-key" . args*) (output ((key-creator ssh-key: ssh-key) args*))) ((_ "delete" "ssh-key" id) (output ((key-deleter ssh-key) id))) ((_ "get" (or "pgp-key" "gpg-key" "pgp-keys" "gpg-keys")) (output (get-pgp-keys))) ((_ "create" (or "pgp-key" "gpg-key") . args*) (output ((key-creator pgp-key: pgp-key) args*))) ((_ "delete" (or "pgp-key" "gpg-key") id) (output ((key-deleter pgp-key) id))) ((_ "get" "job" id) (output (get-job id))) ((_ "create" "job" . args*) (output (create-job args*))) ((_ "get" "manifest" id) (output (get-manifest id))) ((_ "get" (or "paste" "pastes")) (output (get-pastes))) ((_ "get" "paste" sha) (output (get-paste sha))) ((_ "get" "blob" sha) (output (get-blob sha))) ((_ "create" "paste" . args*) (output (create-paste args*))) ((_ "paste" . args*) (output (create-paste* args*))) ((_ . _) (usage (current-error-port)) (exit 1))))) (cond-expand (compiling (with-exception-handler (lambda (e) (print "Error: " (error-message e)) (exit 1)) (lambda () (main (command-line-arguments))))) (else))