diff --git a/README.md b/README.md index f166d87..e91a389 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ behavior: - `git-status` uses Git's porcelain status and returns structured status items. - `git-log -l` / `git-log --list` returns `(commit subject)` items. +- `git-tag -l` / `git-tag --list` returns tag names; with `-n` it returns `(tag subject)` items and `-n` supports multiple content lines. - `git-diff` renders HTML by default; `--output=-` selects stdout and `--output=string` returns a string. - `git-show` renders a commit and its diff as HTML by default. `-l` / diff --git a/main.rkt b/main.rkt index 4f80283..ce629ac 100644 --- a/main.rkt +++ b/main.rkt @@ -256,9 +256,71 @@ ; goal : List, create, delete or verify tags. ; pre : The supplied arguments are valid for git tag. ; post : Git tag has completed successfully or an exception has been raised. -; result : #t after a successful tag command. +; result : A list of tag names with --list/-l, a list of (tag annotation) +; items when -n is combined with --list/-l, otherwise #t. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(def-cmd git-tag cmd-git-tag 'tag) +(def-cmd git-tag cmd-git-tag 'tag + (λ (args info) + (let* ((split-id (format "git-cli-tag-split-~a-~a" + (random 1000000000) + (random 1000000000))) + (record-id (format "git-cli-tag-record-~a-~a" + (random 1000000000) + (random 1000000000))) + (scheme-format #f) + (tag-lines #f)) + (for-each + (λ (e) + (let* ((o (format "~a" e)) + (m (regexp-match #px"^[-]n([0-9]+)?$" o))) + (when (or (string=? o "--list") + (string=? o "-l")) + (set! scheme-format #t)) + (when m + (set! tag-lines + (if (cadr m) + (string->number (cadr m)) + 1))))) + args) + + (hash-set! info 'scheme-format scheme-format) + (hash-set! info 'tag-lines tag-lines) + (hash-set! info 'tag-split-id split-id) + (hash-set! info 'tag-record-id record-id) + + (map + (λ (e) + (let* ((o (format "~a" e)) + (m (regexp-match #px"^[-]n([0-9]+)?$" o))) + (if (and scheme-format m) + (format "--format=%(refname:strip=2)~a~a~a" + split-id + (if (> tag-lines 1) + (format "%(contents:lines=~a)" tag-lines) + "%(contents:subject)") + record-id) + e))) + args))) + + (λ (cmd exit-code result output out info) + (if (hash-ref info 'scheme-format #f) + (if (and (= exit-code 0) result) + (let ((tag-lines (hash-ref info 'tag-lines #f))) + (if tag-lines + (let* ((split-id (hash-ref info 'tag-split-id)) + (record-id (hash-ref info 'tag-record-id)) + (text (string-join out "\n")) + (records (string-split text record-id #:trim? #f))) + (map + (λ (record) + (string-split (string-trim record) split-id #:trim? #f)) + (filter (λ (record) + (not (string=? (string-trim record) ""))) + records))) + out)) + (std-process-git-result cmd exit-code result output out info)) + (std-process-git-result cmd exit-code result output out info))) + ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : Display the Git commit log or return it as a Racket list. diff --git a/scribblings/git.scrbl b/scribblings/git.scrbl index bdbeaf3..8982684 100644 --- a/scribblings/git.scrbl +++ b/scribblings/git.scrbl @@ -108,17 +108,43 @@ Runs @tt{git switch} with the supplied arguments. Runs @tt{git clone} with the supplied arguments. } -@defproc[(git-tag [argument any/c] ...) boolean?]{ +@defproc[(git-tag [argument any/c] ...) (or/c boolean? list?)]{ Runs @tt{git tag} with the supplied arguments. It can list, create, delete, or verify tags according to the options supported by Git. -@racketblock[ -(git-tag) -(git-tag "v0.3.16") -(git-tag '-d "old-tag") -] -} +When @tt{-l} or @tt{--list} is supplied, the matching tag names are returned +as a Racket list. Git's sorting options are passed through unchanged, so the +returned list keeps Git's order. +@racketblock[ +(git-tag '-l) +(git-tag '--list "--sort=version:refname") +(git-tag '--list "--sort=-creatordate") +] + +When @tt{-n} or @tt{-n1} is combined with @tt{-l} or @tt{--list}, each result +item contains the tag name and the subject reported by Git. + +@racketblock[ +(git-tag '-l '-n) + +'(("v0.3.16" "Release 0.3.16") + ("v0.3.17" "Release 0.3.17")) +] + +With @tt{-n} and a number greater than one, git-cli asks Git for that +many content lines using @tt{%(contents:lines=)}. The returned message +is kept as one string, including embedded newlines. + +For structured tag output git-cli asks Git for an explicit format using +@tt{%(refname:strip=2)} and either @tt{%(contents:subject)} or +@tt{%(contents:lines=)}. Generated field and record delimiters are used +to split the result safely. + +Other forms keep the normal command behavior and return @racket[#t] when Git +exits successfully. Git errors are handled by the standard git-cli result +processor. +} @defproc[(git-rev-list [argument any/c] ...) boolean?]{ Runs @tt{git rev-list} with the supplied arguments and displays Git's normal output. It returns @racket[#t] when Git exits successfully.