#lang racket/base

(require racket/system racket/port racket/match racket/runtime-path)

(define-runtime-path THIS-GIT "../../../../.git")

(define (warn fmt . xs)
  (eprintf "Warning: ~a\a\n" (apply format fmt xs))
  (flush-output (current-error-port))
  (sleep 1)
  #f)

(define git
  (let* ([exe (or (find-executable-path "git")
                  (warn "no `git' executable => no release info"))]
         [try (λ (dir) (and dir (directory-exists? dir) dir))]
         [dir (and exe (or (ormap try (list (getenv "GIT_DIR") THIS-GIT))
                           (warn "no git dir found => no release info\n  (~a)"
                                 "set $GIT_DIR to a racket repo .git dir")))]
         [nowhere (open-output-nowhere)])
    (and dir (λ args (define o (open-output-string))
                     (parameterize ([current-directory dir]
                                    [current-output-port o]
                                    [current-error-port nowhere])
                       (and (apply system* exe "--no-pager" args)
                            (get-output-string o)))))))

(provide get-version-tag-info)
(define (get-version-tag-info version)
  (let/ec return
    (unless git (return #f))
    (define (bad . args) (apply warn args) (return #f))
    (define (try fmt)
      (let* ([tag (format fmt version)]
             [text (and (git "cat-file" "-e" tag)
                        (git "cat-file" "tag" tag))])
        (and text (cons tag text))))
    (let* ([text  (or (try "v~a") (try "old-v~a")
                      (bad "no git info for ~s (missing tag)" version))]
           [tag   (car text)]
           [text  (cdr text)]
           [check (λ (x) (or x (bad "malformed git info for ~s" tag)))]
           [sep   (check (regexp-match-positions #rx"\n\n" text))]
           [meta  (map (λ (h)
                         (let ([m (check (regexp-match-positions #rx" " h))])
                           (list (string->symbol (substring h 0 (caar m)))
                                 (substring h (cdar m)))))
                       (regexp-split #rx"\n" (substring text 0 (caar sep))))]
           [text  (substring text (cdar sep))])
      (match meta
        [`((object ,_) (type "commit") (tag ,_)
           (tagger ,(regexp #rx"^(.* <.*>) ([0-9]+) ([-+]?[0-9][0-9])00$"
                            (list _ tagger date ofs))))
         ;; ignore the time offset (it probably depends on where the tag
         ;; was made)
         (list tagger (seconds->date (string->number date)) text)]
        [_ (check #f)]))))
