#!/bin/sh
exec ${GUILE-guile} -e "(ttn-do show-pubstats)" -s $0 "$@" # -*- scheme -*-
!#
;;; show-pubstats

;; Copyright (C) 2001, 2003, 2004, 2005, 2008, 2009, 2010 Thien-Thi Nguyen
;;
;; This file is part of ttn-do, released under the terms of the
;; GNU General Public License as published by the Free Software
;; Foundation; either version 3, or (at your option) any later
;; version.  There is NO WARRANTY.  See file COPYING for details.

;;; Commentary:

;; Usage: show-pubstats [--details]
;;
;; Display information stashed away during "ttn-do publish" runs.
;; Option `--details' means also display information on the files
;; transferred, highest count first.
;;
;; Env var TTN_PGTABLE_DEFS must be set.

;;; Code:

(define-module (ttn-do show-pubstats)
  #:export (main fln make-D)
  #:use-module ((ttn-do zzz banalities)
                #:select (check-hv
                          qop<-args))
  #:use-module ((database postgres)
                #:select (pg-exec
                          pg-ntuples
                          pg-make-print-options
                          pg-print))
  #:use-module ((database postgres-qcons)
                #:select (sql-command<-trees
                          parse+make-SELECT-tree))
  #:use-module ((database postgres-resx)
                #:select (object<-result))
  #:use-module ((ttn-do zzz personally)
                #:select (FE fs fso))
  #:use-module ((ttn-do zzz various-db)
                #:select (personal-pgtable-manager)))

(define (v00 result . objectifier)
  (object<-result result (if (pair? objectifier)
                             (car objectifier)
                             identity)))

(define >>
  (let ((po (pg-make-print-options '(no-header (field-sep . " -- ")))))
    (lambda (result)                    ; rv
      (pg-print result po))))

(define (fln s . args)
  (apply fso s args)
  (newline))

(define (make-D)
  (let ((db "gnuvola")
        (tables '(ok bad files)))
    (define (make-manager table)
      (or (personal-pgtable-manager db (fs "upd~A" table))
          (error "could not make table managers")))
    (let ((managers (map cons tables (map make-manager tables))))
      (define (D table cmd . rest)
        (if (eq? #t table)
            (FE tables (lambda (table)
                         (apply D table cmd rest)))
            (apply ((assq-ref managers table) cmd) rest)))
      ;; rv
      D)))

(define (spew! details? D)

  (define (qdb:count table . etc)
    (v00 (apply D table #:select '((integer #f (count *))) etc)
         string->number))

  (let ((n-ok  (qdb:count 'ok))
        (n-bad (qdb:count 'bad)))
    (fln "~A update attempts, last attempt: ~A"
         (+ n-ok n-bad)
         (v00 (pg-exec (D 'ok #:k #:connection)
                       (let* ((ult '(#:order-by ((> time)) #:limit 1))
                              (from (lambda (table)
                                      `(#t (time) #:from (,table) ,@ult))))
                         (sql-command<-trees
                          (apply parse+make-SELECT-tree
                                 #:union (map from '(updok updbad))
                                 ult))))))
    (fln "~A errors" n-bad)
    (and details? (>> (D 'bad
                         #:select '((integer #f (count cause))
                                    cause)
                         #:group-by '(cause))))
    (let ((latest (v00 (D 'ok #:select '((#f #f (max time)))))))
      (fln "~A times files transferred, last update: ~A" n-ok latest)
      (>> (D 'files #:select '(move file) #:where `(= ,latest time)))))
  (cond (details?
         (fln "- last five updates (number of files -- time):")
         (>> (D 'files
                #:select '((integer #f (count file))
                           time)
                #:group-by '(time)
                #:order-by '((> time))
                #:limit 5))))
  (fln "~A files updated, ~A deleted, ~A unique"
       (qdb:count 'files #:where '(= move "u"))
       (qdb:count 'files #:where '(= move "d"))
       (pg-ntuples (D 'files #:select 'file #:group-by '(file))))
  (and details?
       (>> (D 'files
              #:select '((text #f (|| " " (count file)))
                         file)
              #:group-by '(file)
              #:having '((> (count file) 42))
              #:order-by '((> (count file))))))
  (fln "summaries (min -- max -- sum -- avg):")
  (FE '(wrote read rate speedup)
      (lambda (col)
        (let ((name (symbol->string col)))
          (fso "~A:~A" col (make-string (- 8 (string-length name)) #\space)))
        (>> (D 'ok #:select
               `((real #f (min ,col))
                 (real #f (max ,col))
                 (real #f (sum ,col))
                 (real #f (avg ,col)))))))
  (D #t #:finish))

(define (main/qop qop)
  (spew! (qop 'details) (make-D)))

(define (main args)
  (check-hv args '((package . "ttn-do")
                   (version . "1.3")
                   (help . commentary)))
  (main/qop (qop<-args args '((details)))))

;;; show-pubstats ends here