Revert "Diverse commando's toegevoegd. Ik weet nog niet of ik ze allemaal ga houden"

This reverts commit 003f3713f0.
This commit is contained in:
2026-08-13 09:17:46 +02:00
parent 003f3713f0
commit 9741b1cf51
9 changed files with 130 additions and 829 deletions
+36 -41
View File
@@ -1,54 +1,49 @@
# git-cli
# git
A small command-line-like Git module for Racket. It invokes the installed
`git` executable and exposes commands both through `git` and through direct
procedures.
A small command-line-like Git module for Racket, implemented directly on top of the `libgit2` package.
```racket
(require git-cli)
(require git)
(git 'help)
(git 'help 'grep)
(git 'status)
(git 'fetch '--prune)
(git 'switch "main")
(git 'diff)
(git 'diff '--cached)
(git 'add "main.rkt" "info.rkt")
(git 'restore '--staged "scratch.rkt")
(git 'reset 'HEAD "--" "main.rkt")
(git 'grep '-i '-n "todo")
(git 'commit "Implement raco support")
(git 'tag "v0.2")
(git 'branch-current)
(git 'switch "main")
(git-status)
(git-current-branch)
(git-branches)
(git-remotes)
;; Display-oriented variant:
(dgit 'status)
```
`git-status` returns the index and working-tree status separately:
`git` is an ordinary procedure; command names are symbols. `dgit` performs the
same operation, displays a compact human-readable result, and returns that result.
`(git 'help)` opens the locally installed Scribble documentation. A command can
be supplied to jump directly to its section, for example `(git 'help 'restore)`
or `(git 'help 'grep)`.
For `grep`, the natural `(git 'grep '-i "pattern")` spelling is supported even
though Racket's reader represents `-i` as the complex number `0-1i`; in grep
option position that value is interpreted as Git's `-i` flag.
The same operations are available as normal procedures such as `git-status`, `git-add`, `git-commit`, `git-tag`, `git-current-branch`, `git-switch`, and `git-checkout`.
## Help
Open the locally installed Scribble documentation through Racket's
documentation cross-reference index:
```racket
'((modified unchanged "staged.rkt")
(unchanged modified "working-tree.rkt")
(untracked untracked "new.rkt"))
(git 'help)
(git 'help 'grep)
(git 'help 'restore)
```
The module also provides a few direct workflows:
```racket
(git-save "Implement status parser" "main.rkt" "scribblings/git.scrbl")
(git-save-all "Finish release")
(git-start-branch "feature")
(git-sync)
(git-release 'patch)
```
`git-sync` requires a clean working tree and performs pull followed by push.
`git-release` increments `info.rkt`, commits it, and creates a tag; it does not
push automatically.
Git is searched on `PATH`. If it cannot be found, `git-cli` asks for the path
to `git` or `git.exe` and stores it in its simple-ini configuration.
```racket
(set-git-config! 'display-output #t)
(set-git-config! 'display-command #f)
(set-git-config! 'tag-prefix "v")
```
Remote names, upstream branches, pull strategy, credentials and SSH keys remain
normal Git configuration.
+1 -1
View File
@@ -2,7 +2,7 @@
(define collection "git-cli")
(define pkg-desc "Command-line-like Git operations for Racket, interface to the git cli command")
(define version "0.3.12")
(define version "0.3.11")
(define pkg-authors '("Hans Dijkema"))
(define license 'MIT)
+44 -490
View File
@@ -16,37 +16,9 @@
git-commit
git-pull
git-push
git-fetch
git-branch
git-clone
git-log
git-rev-list
git-diff
git-grep
git-help
git-switch
git-restore
git-show
git-tag
git-stash
git-remote
git-init
git-current-branch
git-branches
git-remotes
git-tags
git-stashes
git-save
git-save-all
git-sync
git-start-branch
git-release
git-version
git-new-version
git-exe
set-git-exe!
git-config
set-git-config!
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -59,12 +31,10 @@
;; Command invocation using 'git'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Invoke a supported Git command through the command table.
; pre : command is a registered Git command symbol.
; post : The selected command has processed all supplied arguments.
; result : The command-specific result.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Invoke a supported Git command through the command table.
;; pre: command is a registered Git command symbol.
;; post: The selected command has processed all supplied arguments.
;; result: The command-specific result.
(define (git command . args)
((hash-ref git-commands command
@@ -76,23 +46,11 @@
;; Supporting functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Read one line of input after displaying a prompt.
; pre : p can be displayed.
; post : The prompt has been flushed before input is read.
; result : The line entered by the user or an EOF object.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-prompt p)
(display p)
(flush-output)
(read-line))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Add --porcelain to a Git argument list when it is absent.
; pre : args is a list and an optional transformation accepts a list.
; post : Existing porcelain options have not been duplicated.
; result : The transformed Git argument list.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (add-porcelain args info . f)
(let ((m (has-git-arg? args #px"^[-][-]porcelain([=](.*))?"))
(g (if (null? f) (λ (x) x) (car f)))
@@ -101,12 +59,6 @@
(g args)
(g (cons '--porcelain args)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Convert one porcelain status character to a semantic symbol.
; pre : status is one Git porcelain v1 status character.
; post : Unknown status characters have raised an exception.
; result : The corresponding semantic status symbol.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (status->symbol status)
(cond
((string=? status " ") 'unchanged)
@@ -121,12 +73,6 @@
((string=? status "!") 'ignored)
(else (error 'git-status "Unexpected status: ~a" status))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Recognize Git output that reports there is nothing to commit.
; pre : out is a list of output lines.
; post : The output has only been inspected.
; result : #t when a known nothing-to-commit message occurs, otherwise #f.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (nothing-to-commit? out)
(ormap (λ (line)
(let ((line* (string-downcase line)))
@@ -134,37 +80,10 @@
(string-contains? line* "no changes added to commit"))))
out))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Select the standard-output lines from ordered process output.
; pre : output contains (source line) items returned by run-git.
; post : The order of the selected lines has been preserved.
; result : A list of standard-output lines.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (stdout-lines output)
(map cadr
(filter (lambda (entry) (eq? (car entry) 'stdout)) output)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Process a Git command whose useful result is a list of lines.
; pre : exit-code and output belong to the completed Git command.
; post : A non-zero exit code has raised a Git exception.
; result : The standard-output lines when Git exits with status zero.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (process-lines-result cmd exit-code result output out info)
(if (= exit-code 0)
(stdout-lines output)
(git-error cmd (format "Exitcode <> 0: ~a" exit-code) out)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Command definition macro
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Define, register and connect a public Git command procedure.
; pre : The preprocessor and result processor use the proxy interfaces.
; post : cmd-sym is registered in the generic git command table.
; result : Definitions for the public and internal command procedures.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-syntax def-cmd
(syntax-rules ()
((_ cmd cmd* cmd-sym)
@@ -172,10 +91,8 @@
((_ cmd cmd* cmd-sym pre-code)
(def-cmd cmd cmd* cmd-sym pre-code std-process-git-result))
((_ cmd cmd* cmd-sym pre-code process-result)
(def-cmd cmd cmd* cmd-sym cmd-sym pre-code process-result))
((_ cmd cmd* cmd-sym git-cmd pre-code process-result)
(begin
(def-git-cmd-proxy cmd* git-cmd
(def-git-cmd-proxy cmd* cmd-sym
pre-code
process-result)
(define (cmd . args) (cmd* args))
@@ -187,12 +104,10 @@
;; Typical git commands
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Return the complete Git index and worktree status for every file.
; pre : The current directory is inside a Git working tree.
; post : Git status has been invoked with --porcelain.
; result : A list of (index-status worktree-status file) items.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Return the complete Git index and worktree status for every reported file.
;; pre: The current directory is inside a Git working tree.
;; post: Git status has been invoked with --porcelain.
;; result: A list containing (index-status worktree-status file) for every file.
(def-cmd git-status cmd-git-status 'status
add-porcelain
(λ (cmd exit-code result output out info)
@@ -204,26 +119,23 @@
(list (status->symbol (substring line 0 1))
(status->symbol (substring line 1 2))
(substring line 3))))
(stdout-lines output))
(map cadr
(filter (λ (entry) (eq? (car entry) 'stdout)) output)))
(git-error 'status "Exitcode <> 0" (cons (format "~a\n" exit-code) output))
))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Add file contents to the Git index.
; pre : The supplied arguments are valid for git add.
; post : Git add has completed successfully or an exception has been raised.
; result : #t after a successful Git command.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Add file contents to the Git index.
;; pre: The supplied arguments are valid for git add.
;; post: Git add has completed successfully or an exception has been raised.
;; result: #t after a successful Git command.
(def-cmd git-add cmd-git-add 'add)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Create a Git commit.
; pre : A commit message is supplied or can be requested from the user.
; post : A commit exists, nothing needed committing, or an exception was raised.
; result : #t after a commit or when the repository has nothing to commit.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Create a Git commit.
;; pre: A commit message is supplied or can be requested from the user.
;; post: The commit was created, nothing needed committing, or an exception was raised.
;; result: #t after a commit or when the repository has nothing to commit.
(def-cmd git-commit cmd-git-commit 'commit
(λ (args info)
(with-handlers ([exn:fail? (λ (e)
@@ -242,68 +154,30 @@
(std-process-git-result cmd exit-code result output out info))))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Push local changes to a remote repository.
; pre : The supplied arguments are valid for git push.
; post : Git push has completed successfully or an exception has been raised.
; result : #t after a successful push.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Push local changes to a remote repository.
;; pre: The supplied arguments are valid for git push.
;; post: Git push has completed successfully or an exception has been raised.
;; result: #t after a successful push.
(def-cmd git-push cmd-git-push 'push add-porcelain)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Fetch and integrate changes from a remote repository.
; pre : The supplied arguments are valid for git pull.
; post : Git pull has completed successfully or an exception has been raised.
; result : #t after a successful pull.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Fetch and integrate changes from a remote repository.
;; pre: The supplied arguments are valid for git pull.
;; post: Git pull has completed successfully or an exception has been raised.
;; result: #t after a successful pull.
(def-cmd git-pull cmd-git-pull 'pull)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Download refs and objects from a remote repository.
; pre : The supplied arguments are valid for git fetch.
; post : Git fetch has completed successfully or an exception has been raised.
; result : #t after a successful fetch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-fetch cmd-git-fetch 'fetch)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : List, create or delete branches.
; pre : The supplied arguments are valid for git branch.
; post : Git branch has completed successfully or an exception has been raised.
; result : #t after a successful branch command.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-branch cmd-git-branch 'branch)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Clone a repository into a new directory.
; pre : The supplied arguments are valid for git clone.
; post : The clone exists or an exception has been raised.
; result : #t after a successful clone.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-clone cmd-git-clone 'clone)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Display the Git commit log.
; pre : The supplied arguments are valid for git log.
; post : Git log has completed successfully or an exception has been raised.
; result : #t after successfully displaying the log.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Display the Git commit log.
;; pre: The supplied arguments are valid for git log.
;; post: Git log has completed successfully or an exception has been raised.
;; result: #t after successfully displaying the log.
(def-cmd git-log cmd-git-log 'log)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : List commit objects reachable from supplied revisions.
; pre : The supplied arguments are valid for git rev-list.
; post : Git rev-list has completed successfully or an exception was raised.
; result : #t after successfully displaying the result.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-rev-list cmd-git-rev-list 'rev-list)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Render a Git diff in the browser.
; pre : The supplied arguments are valid for git diff.
; post : A successful non-empty diff has been rendered as HTML.
; result : #t for a rendered diff, otherwise #f.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-diff cmd-git-diff 'diff
(λ (args info) args)
(λ (cmd exit-code result output out info)
@@ -318,12 +192,10 @@
#t)
#f)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Search tracked files for a pattern.
; pre : The supplied arguments are valid for git grep.
; post : Git grep has completed; exit code one is treated as no matches.
; result : A list containing file, line number, match count and matched text.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Search tracked files for a pattern.
;; pre: The supplied arguments are valid for git grep.
;; post: Git grep has completed; exit code one is treated as no matches.
;; result: A list containing file, line number, match count and matched text.
(def-cmd git-grep cmd-git-grep 'grep
(λ (args info)
(let ((matches #f)
@@ -372,357 +244,39 @@
#f))))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Display help for Git or a Git command.
; pre : The supplied arguments are valid for git help.
; post : Git help has completed successfully or an exception has been raised.
; result : #t after successfully displaying help.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-help cmd-git-help 'help)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Switch branches or restore working-tree files.
; pre : The supplied arguments are valid for git switch.
; post : Git switch has completed successfully or an exception was raised.
; result : #t after a successful switch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-switch cmd-git-switch 'switch)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Restore working-tree or index files.
; pre : The supplied arguments are valid for git restore.
; post : Git restore has completed successfully or an exception was raised.
; result : #t after a successful restore.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-restore cmd-git-restore 'restore)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Display one or more Git objects.
; pre : The supplied arguments are valid for git show.
; post : Git show has completed successfully or an exception was raised.
; result : #t after successfully displaying the objects.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-show cmd-git-show 'show)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : List, create, verify or delete tags.
; pre : The supplied arguments are valid for git tag.
; post : Git tag has completed successfully or an exception was raised.
; result : #t after a successful tag command.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-tag cmd-git-tag 'tag)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Store or restore uncommitted changes.
; pre : The supplied arguments are valid for git stash.
; post : Git stash has completed successfully or an exception was raised.
; result : #t after a successful stash command.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-stash cmd-git-stash 'stash)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Manage the repositories whose branches are tracked.
; pre : The supplied arguments are valid for git remote.
; post : Git remote has completed successfully or an exception was raised.
; result : #t after a successful remote command.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-remote cmd-git-remote 'remote)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Create an empty Git repository or reinitialize an existing one.
; pre : The supplied arguments are valid for git init.
; post : Git init has completed successfully or an exception was raised.
; result : #t after a successful initialization.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-init cmd-git-init 'init)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Git information
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Obtain the name of the currently checked-out branch.
; pre : No arguments are supplied and the current directory is a repository.
; post : The repository has only been inspected.
; result : The branch name, or #f when HEAD is detached.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-current-branch cmd-git-current-branch 'current-branch 'branch
(lambda (args info)
(unless (null? args)
(error 'git-current-branch "No arguments expected"))
(list '--show-current))
(lambda (cmd exit-code result output out info)
(let ((lines (process-lines-result cmd exit-code result output out info)))
(if (null? lines) #f (car lines)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Obtain the local branch names.
; pre : No arguments are supplied and the current directory is a repository.
; post : The repository has only been inspected.
; result : A list of local branch names.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-branches cmd-git-branches 'branches 'branch
(lambda (args info)
(unless (null? args)
(error 'git-branches "No arguments expected"))
(list "--format=%(refname:short)"))
process-lines-result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Obtain the configured remote names.
; pre : No arguments are supplied and the current directory is a repository.
; post : The repository has only been inspected.
; result : A list of remote names.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-remotes cmd-git-remotes 'remotes 'remote
(lambda (args info)
(unless (null? args)
(error 'git-remotes "No arguments expected"))
args)
process-lines-result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Obtain the repository tag names.
; pre : No arguments are supplied and the current directory is a repository.
; post : The repository has only been inspected.
; result : A list of tag names.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-tags cmd-git-tags 'tags 'tag
(lambda (args info)
(unless (null? args)
(error 'git-tags "No arguments expected"))
(list '--list))
process-lines-result)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Convert one formatted stash line to a semantic list item.
; pre : line was produced by git stash list with the configured format.
; post : The line has only been inspected.
; result : A list containing the stash reference and description.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (stash-line->result line)
(let ((m (regexp-match #px"^([^\t]+)\t(.*)$" line)))
(if m
(list (cadr m) (caddr m))
(list line ""))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Obtain stash references and descriptions.
; pre : No arguments are supplied and the current directory is a repository.
; post : The repository has only been inspected.
; result : A list of (reference description) items.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def-cmd git-stashes cmd-git-stashes 'stashes 'stash
(lambda (args info)
(unless (null? args)
(error 'git-stashes "No arguments expected"))
(list 'list "--format=%gd%x09%s"))
(lambda (cmd exit-code result output out info)
(map stash-line->result
(process-lines-result cmd exit-code result output out info))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Easy workflows
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Add selected paths and commit them with one message.
; pre : message is non-empty and at least one path is supplied.
; post : The paths have been staged and committed, or an exception was raised.
; result : #t after a successful save.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-save message . files)
(when (string=? (string-trim (format "~a" message)) "")
(error 'git-save "A commit message is mandatory"))
(when (null? files)
(error 'git-save "At least one file is mandatory"))
(apply git-add files)
(git-commit '-m message))
(hash-set! git-commands 'save
(lambda (args) (apply git-save args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Stage every change and commit it with one message.
; pre : message is non-empty.
; post : All changes have been staged and committed, or an exception was raised.
; result : #t after a successful save.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-save-all message)
(when (string=? (string-trim (format "~a" message)) "")
(error 'git-save-all "A commit message is mandatory"))
(git-add '-A)
(git-commit '-m message))
(hash-set! git-commands 'save-all
(lambda (args) (apply git-save-all args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Pull and then push a clean working tree.
; pre : Either no arguments or a remote and branch are supplied.
; post : Pull and push completed, or an exception was raised.
; result : #t after a successful synchronization.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-sync . args)
(unless (or (null? args) (= (length args) 2))
(error 'git-sync "Expected no arguments or a remote and branch"))
(unless (null? (git-status))
(error 'git-sync "The working tree must be clean"))
(apply git-pull args)
(apply git-push args))
(hash-set! git-commands 'sync
(lambda (args) (apply git-sync args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Create and switch to a new branch.
; pre : A name and at most one optional start point are supplied.
; post : The new branch is checked out, or an exception was raised.
; result : #t after successfully creating the branch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-start-branch name . start-point)
(when (> (length start-point) 1)
(error 'git-start-branch "Expected a name and optionally one start point"))
(apply git-switch (append (list '-c name) start-point)))
(hash-set! git-commands 'start-branch
(lambda (args) (apply git-start-branch args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Format a three-part version list as dotted text.
; pre : version contains major, minor and patch numbers.
; post : version has only been inspected.
; result : The dotted version string.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (version->string version)
(string-join (map number->string version) "."))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Increment, commit and tag a clean package release.
; pre : kind is a supported version kind and the working tree is clean.
; post : info.rkt is committed and the release tag exists, or an exception occurred.
; result : The created tag name.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-release kind)
(unless (null? (git-status))
(error 'git-release "The working tree must be clean"))
(let* ((version (git-new-version kind))
(version-text (version->string version))
(tag (string-append (git-config 'tag-prefix) version-text)))
(git-add "info.rkt")
(git-commit '-m (format "Version ~a" version-text))
(git-tag tag)
tag))
(hash-set! git-commands 'release
(lambda (args) (apply git-release args)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Racket module versioning
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Return the package version from info.rkt.
; pre : No arguments are required.
; post : info.rkt has only been inspected.
; result : A list containing major, minor and patch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-version . args)
(cmd-git-version args))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Implement the registered version command.
; pre : args is empty.
; post : info.rkt has only been inspected.
; result : A list containing major, minor and patch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cmd-git-version args)
(unless (null? args)
(error 'git-version "No arguments expected"))
(info-version "."))
(hash-set! git-commands 'version cmd-git-version)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Increment the package version in info.rkt.
; pre : kind is 'maj, 'major, 'min, 'minor or 'patch.
; post : The version definition in info.rkt has been updated.
; result : The new version as a list containing major, minor and patch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Increment the package version in info.rkt.
;; pre: kind is 'maj, 'major, 'min, 'minor or 'patch.
;; post: The version definition in info.rkt has been updated.
;; result: The new version as a list containing major, minor and patch.
(define (git-new-version . args)
(cmd-git-new-version args))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Implement the registered new-version command.
; pre : args contains a supported version kind.
; post : The version definition in info.rkt has been updated.
; result : The new version as a list containing major, minor and patch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cmd-git-new-version args)
(unless (= (length args) 1)
(error 'git-new-version "Expected 'maj, 'major, 'min, 'minor or 'patch"))
(when(null? args)
(error "git-new-version expects 'maj, 'major, 'min, 'minor or 'patch"))
(let ((kind (car args)))
(git-next-version kind ".")
(git-version)))
(hash-set! git-commands 'new-version cmd-git-new-version)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Return the default value for a public configuration key.
; pre : key is a supported public configuration key.
; post : Configuration has not been changed.
; result : The default value for key.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-config-default key)
(case key
((display-output) #t)
((display-command) #f)
((tag-prefix) "v")
(else (error 'git-config "Unknown configuration key: ~a" key))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Validate a value for a public configuration key.
; pre : key is a supported public configuration key.
; post : An invalid value has raised an exception.
; result : The validated value.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (validate-git-config key value)
(case key
((display-output display-command)
(unless (boolean? value)
(error 'set-git-config! "~a must be a boolean" key)))
((tag-prefix)
(unless (string? value)
(error 'set-git-config! "tag-prefix must be a string")))
(else (error 'set-git-config! "Unknown configuration key: ~a" key)))
value)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Read a public git-cli configuration value.
; pre : key is display-output, display-command or tag-prefix.
; post : Configuration has not been changed.
; result : The configured value or its default.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-config key)
(cfg-get (if (eq? key 'tag-prefix) 'release 'git)
key
(git-config-default key)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Store a public git-cli configuration value.
; pre : key and value form a supported configuration setting.
; post : The setting has been persisted.
; result : The stored value.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (set-git-config! key value)
(cfg-set! (if (eq? key 'tag-prefix) 'release 'git)
key
(validate-git-config key value))
value)
+1 -12
View File
@@ -43,24 +43,13 @@
;; Provided functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Store one git-cli configuration value.
; pre : section and key identify a simple-ini setting.
; post : value has been persisted.
; result : The result returned by simple-ini.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cfg-set! section key value)
(critical
(check-ini)
(send ini set! section key value)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Read one git-cli configuration value.
; pre : section and key identify a simple-ini setting.
; post : Configuration has not been changed.
; result : The stored value or default-value.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (cfg-get section key default-value)
(critical
(check-ini)
(send ini get section key default-value)))
+1 -6
View File
@@ -11,12 +11,6 @@
(define (make-js . args)
(string-join args "\n"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Render a Git diff in a temporary HTML file.
; pre : diff is a unified Git diff string.
; post : The generated HTML file has been opened in the default browser.
; result : void.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (diff->html diff)
(let ((highlight-css "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css")
(diff2html-min-css "https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css")
@@ -58,3 +52,4 @@
(send-url/file tmp-file)))))
+9 -24
View File
@@ -11,12 +11,7 @@
std-process-git-result
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Determine whether a Git option occurs in an argument list.
; pre : args is a list and opt is a symbol, string or regular expression.
; post : args has only been inspected.
; result : The match result, or #f when the option is absent.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (has-git-arg? args opt)
(let ((cmp (cond ((symbol? opt) (λ (x) (eq? x opt)))
((string? opt) (λ (x) (string=? (format "~a" x) opt)))
@@ -33,12 +28,6 @@
(f args)
(error 'has-git-arg? "args must be a list of arguments")))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Check that mandatory Git options and their arguments are present.
; pre : flags contains (option argument-count error-message) items.
; post : Missing options have raised an exception.
; result : args when every mandatory option is present.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (check-git-args cmd args flags)
(for-each
(λ (opt)
@@ -62,12 +51,10 @@
args)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Process the standard result of a Git command.
; pre : exit-code and out belong to the completed Git command.
; post : Successful output has been displayed or a Git exception has been raised.
; result : #t when exit-code is zero.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Process the standard result of a Git command.
;; pre: exit-code and out belong to the completed Git command.
;; post: Successful output has been displayed or a Git exception has been raised.
;; result: #t when exit-code is zero.
(define (std-process-git-result cmd exit-code result output out info)
(if (= exit-code 0)
(begin
@@ -78,12 +65,10 @@
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Define the internal proxy for a Git command.
; pre : pre-code and process-result accept the command proxy arguments.
; post : The proxy invokes Git without standard input and processes its result.
; result : A procedure named f accepting a list of Git arguments.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; goal: Define the internal proxy for a Git command.
;; pre: pre-code and process-result accept the command proxy arguments.
;; post: The proxy invokes Git without standard input and processes its result.
;; result: A procedure named f accepting a list of Git arguments.
(define-syntax def-git-cmd-proxy
(syntax-rules ()
((_ f cmd pre-code process-result)
+1 -38
View File
@@ -47,12 +47,6 @@
;; Provided functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Find the configured Git executable.
; pre : Git is on PATH or a valid executable can be selected interactively.
; post : The executable path has been cached.
; result : The path to git or git.exe.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define/contract (git-exe)
(-> (or/c path? #f))
(if (eq? cached-git-exe #f)
@@ -70,12 +64,6 @@
the-git-exe)
cached-git-exe))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Configure the Git executable.
; pre : exe-path names an executable path.
; post : The path has been stored and cached.
; result : void.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define/contract (set-git-exe! exe-path)
(-> path? void?)
(void
@@ -83,17 +71,9 @@
(cfg-set! 'git 'exe exe-path)
(set! cached-git-exe exe-path))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Run Git without allowing interactive terminal prompts.
; pre : args contains the Git command and its arguments.
; post : Standard output and error have been read completely.
; result : The exit code and ordered (source line) output items.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (run-git args)
(putenv "GIT_TERMINAL_PROMPT" "0")
(when (cfg-get 'git 'display-command #f)
(displayln
(string-join (cons "git" (map (lambda (arg) (format "~a" arg)) args)) " ")))
(let-values (((process stdout stdin stderr)
(apply subprocess
#f
@@ -143,12 +123,6 @@
(define (is-error? e)
(not (is-output? e)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Separate normal Git output from error output.
; pre : output contains (source line) items returned by run-git.
; post : output has only been inspected.
; result : Whether no error occurred and either normal or error lines.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-out cmd output)
(let* ((out (map (λ (e) (cadr e)) (filter (λ (e) (is-output? e)) output)))
(err (map (λ (e) (cadr e)) (filter (λ (e) (is-error? e)) output)))
@@ -156,11 +130,6 @@
)
(values r (if (eq? r #t) out err))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Log and raise a Git exception.
; pre : cmd, msg* and outp describe a failed Git command.
; post : The message has been logged and an exception has been raised.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-syntax git-error
(syntax-rules ()
((_ cmd msg* outp)
@@ -184,12 +153,6 @@
(define re-a #px"~+")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Log Git output and optionally display it.
; pre : out is a string or a list of displayable lines.
; post : Non-empty output has been logged.
; result : void.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-displ out)
(let ((str (if (string? out) out (string-join out "\n"))))
(unless (string=? (string-trim str) "")
-18
View File
@@ -9,12 +9,6 @@
git-next-version
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Read a package version from info.rkt.
; pre : dir contains a readable info.rkt.
; post : info.rkt has only been inspected.
; result : A list containing major, minor and patch.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (info-version dir)
(let* ((l (get-info/full dir))
(re #px"([0-9]+)[.]([0-9]+)([.]([0-9]+))?")
@@ -29,12 +23,6 @@
(cadddr (cdr m)))))
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Store a package version in info.rkt.
; pre : dir contains info.rkt and version parts are numbers.
; post : The version definition has been replaced.
; result : #t after writing the file.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (set-info-version! dir maj min patch)
(define (write-version fh)
@@ -66,12 +54,6 @@
#t)))))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; goal : Increment a package version.
; pre : kind is maj, major, min, minor or patch.
; post : The version definition in info.rkt has been updated.
; result : #t after writing the new version.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (git-next-version kind . dir*)
(let ((dir (if (null? dir*)
"."
+15 -177
View File
@@ -1,8 +1,8 @@
#lang scribble/manual
@(require (for-label racket/base
racket/contract
"../main.rkt"))
@;git-cli))
@title[#:tag "top"]{git-cli}
@author{Hans Dijkema}
@@ -10,42 +10,30 @@
@defmodule[git-cli]
The @racketmodname[git-cli] module provides a command-line-like Git interface
implemented by invoking the @tt{git} executable. Git never reads credentials or
other answers from standard input.
@section{Command interface}
implemented by invoking the @tt{git} executable. Commands never read from
standard input.
@defform[(git command argument ...)]{
Runs a registered command. Every command is also available as a normal
procedure. For example, @racket[(git 'fetch '--prune)] and
@racket[(git-fetch '--prune)] are equivalent.
Registered command symbols are @racket['status], @racket['add],
@racket['commit], @racket['push], @racket['pull], @racket['fetch],
@racket['branch], @racket['clone], @racket['log], @racket['rev-list],
@racket['diff], @racket['grep], @racket['help], @racket['switch],
@racket['restore], @racket['show], @racket['tag], @racket['stash],
@racket['remote], @racket['init], @racket['current-branch],
@racket['branches], @racket['remotes], @racket['tags], @racket['stashes],
@racket['save], @racket['save-all], @racket['sync],
@racket['start-branch], @racket['release], @racket['version], and
Runs a supported Git @racket[command]. The arguments are passed to the Git
command. Supported commands include @racket['status], @racket['add],
@racket['commit], @racket['push], @racket['pull], @racket['branch],
@racket['clone], @racket['log], @racket['rev-list], @racket['diff],
@racket['grep], @racket['help], @racket['version], and
@racket['new-version].
}
@section{Basic commands}
@defproc[(git-status [argument any/c] ...) list?]{
Runs @tt{git status --porcelain} with the supplied arguments.
Each result item has the form
@racket[(index-status worktree-status file)]. The first status describes the
index: the change already staged for the next commit. The second describes the
working tree relative to the index: the change that is not staged yet.
@racket[(index-status worktree-status file)]. The index status describes the
change staged for the next commit. The worktree status describes the change in
the working tree relative to the index.
Both statuses are one of @racket['unchanged], @racket['modified],
@racket['type-changed], @racket['added], @racket['deleted], @racket['renamed],
@racket['copied], @racket['unmerged], @racket['untracked], or
@racket['ignored]. Git reports an untracked file as @tt{??}, so both statuses
@racket['ignored]. For an untracked file, Git reports @tt{??}, so both statuses
are @racket['untracked].
@racketblock[
@@ -74,171 +62,21 @@ status zero; otherwise an exception is raised.
@defproc[(git-pull [argument any/c] ...) boolean?]{
Fetches and integrates changes. Normal progress written by Git to standard
error is accepted when Git exits successfully.
}
@defproc[(git-fetch [argument any/c] ...) boolean?]{
Downloads refs and objects without integrating them into the current branch.
}
@defproc[(git-branch [argument any/c] ...) boolean?]{
Passes the arguments to @tt{git branch}. Use @racket[git-branches] when a list
of local branch names is required.
}
@defproc[(git-clone [argument any/c] ...) boolean?]{
Clones a repository. Normal progress on standard error is accepted when Git
exits successfully.
error is treated as output when Git exits successfully.
}
@defproc[(git-log [argument any/c] ...) boolean?]{
Displays the commit log.
Displays Git log output and returns @racket[#t] when Git exits successfully.
}
@defproc[(git-rev-list [argument any/c] ...) boolean?]{
Lists commit objects reachable from the supplied revisions.
}
@defproc[(git-diff [argument any/c] ...) boolean?]{
Renders the Git diff as HTML and opens it in the default browser. Returns
@racket[#t] when a diff was rendered and @racket[#f] otherwise.
}
@defproc[(git-grep [argument any/c] ...) (or/c list? #f)]{
@defproc[(git-grep [argument any/c] ...) list?]{
Searches tracked files. Each result contains the file, optional line number,
optional match count, and matched text. Exit status one means that no matches
were found and returns an empty list.
}
@defproc[(git-help [argument any/c] ...) boolean?]{
Displays help for Git or a supplied Git command.
}
@defproc[(git-switch [argument any/c] ...) boolean?]{
Switches branches. @racket[(git-switch '-c "feature")] creates and checks out a
new branch.
}
@defproc[(git-restore [argument any/c] ...) boolean?]{
Restores working-tree or index files. For example,
@racket[(git-restore '--staged "main.rkt")] removes a file from the index
without discarding its working-tree changes.
}
@defproc[(git-show [argument any/c] ...) boolean?]{
Displays one or more Git objects.
}
@defproc[(git-tag [argument any/c] ...) boolean?]{
Lists, creates, verifies or deletes tags. Use @racket[git-tags] when a list of
tag names is required.
}
@defproc[(git-stash [argument any/c] ...) boolean?]{
Stores or restores uncommitted work, for example
@racket[(git-stash 'push '-m "Temporary work")] and @racket[(git-stash 'pop)].
}
@defproc[(git-remote [argument any/c] ...) boolean?]{
Lists or manages remotes. Use @racket[git-remotes] when a list of remote names
is required.
}
@defproc[(git-init [argument any/c] ...) boolean?]{
Creates an empty repository or reinitializes an existing repository.
}
@section{Repository information}
@defproc[(git-current-branch) (or/c string? #f)]{
Returns the current local branch name, or @racket[#f] for a detached HEAD.
}
@defproc[(git-branches) (listof string?)]{
Returns the local branch names.
}
@defproc[(git-remotes) (listof string?)]{
Returns the configured remote names.
}
@defproc[(git-tags) (listof string?)]{
Returns the repository tag names.
}
@defproc[(git-stashes) list?]{
Returns stash information as @racket[(reference description)] items.
}
@section{Easy workflows}
@defproc[(git-save [message string?] [file any/c] ...) boolean?]{
Stages only the supplied files and commits them with @racket[message]. At least
one file is required.
}
@defproc[(git-save-all [message string?]) boolean?]{
Runs @tt{git add -A} and commits every change with @racket[message].
}
@defproc[(git-start-branch [name any/c] [start-point any/c #f]) boolean?]{
Creates and switches to a branch with @tt{git switch -c}. When
@racket[start-point] is supplied, the branch starts there.
}
@defproc[(git-sync [argument any/c] ...) boolean?]{
Requires a clean working tree, then pulls and pushes. Supply either no
arguments, so Git uses the configured upstream, or both a remote and branch.
The pull behavior remains controlled by Git configuration such as
@tt{pull.rebase}.
}
@defproc[(git-release [kind symbol?]) string?]{
Requires a clean working tree, increments the package version in
@filepath{info.rkt}, commits it as @tt{Version <version>}, creates a tag, and
returns the tag name. The release is not pushed automatically.
}
@section{Package version}
@defproc[(git-version) list?]{
Returns the version from @filepath{info.rkt} as a list containing major, minor
and patch.
}
@defproc[(git-new-version [kind symbol?]) list?]{
Updates the version in @filepath{info.rkt}. The kind is @racket['major],
@racket['minor], or @racket['patch], with @racket['maj] and @racket['min] as
abbreviations. The result is the new version as a list of three integers.
}
@section{Configuration}
@defproc[(git-exe) (or/c path? #f)]{
Returns the configured Git executable. Git is first searched on @tt{PATH}. If
it is absent, the executable is requested interactively and stored in the
@tt{git-cli} simple-ini file.
}
@defproc[(set-git-exe! [exe-path path?]) void?]{
Stores and caches the path to Git.
}
@defproc[(git-config [key symbol?]) any/c]{
Returns one of the public settings:
@itemlist[
@item{@racket['display-output], default @racket[#t], controls normal Git output.}
@item{@racket['display-command], default @racket[#f], displays the command before execution.}
@item{@racket['tag-prefix], default @racket["v"], controls tags made by @racket[git-release].}
]}
The display settings are stored in section @tt{git}; the tag prefix is stored
in section @tt{release}. Git settings such as remotes, upstream branches,
@tt{pull.rebase}, credentials and SSH keys remain Git's own configuration.
}
@defproc[(set-git-config! [key symbol?] [value any/c]) any/c]{
Validates and stores a public setting, then returns @racket[value]. The display
settings require booleans and @racket['tag-prefix] requires a string.
}