git.scm 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2019, 2020 Ludovic Courtès <ludo@gnu.org>
  3. ;;;
  4. ;;; This file is part of GNU Guix.
  5. ;;;
  6. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  7. ;;; under the terms of the GNU General Public License as published by
  8. ;;; the Free Software Foundation; either version 3 of the License, or (at
  9. ;;; your option) any later version.
  10. ;;;
  11. ;;; GNU Guix is distributed in the hope that it will be useful, but
  12. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;; GNU General Public License for more details.
  15. ;;;
  16. ;;; You should have received a copy of the GNU General Public License
  17. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  18. (define-module (guix tests git)
  19. #:use-module (git)
  20. #:use-module ((guix git) #:select (with-repository))
  21. #:use-module (guix utils)
  22. #:use-module (guix build utils)
  23. #:use-module (ice-9 match)
  24. #:use-module (ice-9 control)
  25. #:export (git-command
  26. with-temporary-git-repository
  27. find-commit))
  28. (define git-command
  29. (make-parameter "git"))
  30. (define (populate-git-repository directory directives)
  31. "Initialize a new Git checkout and repository in DIRECTORY and apply
  32. DIRECTIVES. Each element of DIRECTIVES is an sexp like:
  33. (add \"foo.txt\" \"hi!\")
  34. Return DIRECTORY on success."
  35. ;; Note: As of version 0.2.0, Guile-Git lacks the necessary bindings to do
  36. ;; all this, so resort to the "git" command.
  37. (define (git command . args)
  38. ;; Make sure Git doesn't rely on the user's config.
  39. (call-with-temporary-directory
  40. (lambda (home)
  41. (call-with-output-file (string-append home "/.gitconfig")
  42. (lambda (port)
  43. (display "[user]
  44. email = charlie@example.org\n name = Charlie Guix\n"
  45. port)))
  46. (with-environment-variables
  47. `(("GIT_CONFIG_NOSYSTEM" "1")
  48. ("GIT_ATTR_NOSYSTEM" "1")
  49. ("HOME" ,home))
  50. (apply invoke (git-command) "-C" directory
  51. command args)))))
  52. (mkdir-p directory)
  53. (git "init")
  54. (let loop ((directives directives))
  55. (match directives
  56. (()
  57. directory)
  58. ((('add file contents) rest ...)
  59. (let ((file (string-append directory "/" file)))
  60. (mkdir-p (dirname file))
  61. (call-with-output-file file
  62. (lambda (port)
  63. (display (if (string? contents)
  64. contents
  65. (with-repository directory repository
  66. (contents repository)))
  67. port)))
  68. (git "add" file)
  69. (loop rest)))
  70. ((('remove file) rest ...)
  71. (git "rm" "-f" file)
  72. (loop rest))
  73. ((('commit text) rest ...)
  74. (git "commit" "-m" text)
  75. (loop rest))
  76. ((('commit text ('signer fingerprint)) rest ...)
  77. (git "commit" "-m" text (string-append "--gpg-sign=" fingerprint))
  78. (loop rest))
  79. ((('tag name) rest ...)
  80. (git "tag" name)
  81. (loop rest))
  82. ((('branch name) rest ...)
  83. (git "branch" name)
  84. (loop rest))
  85. ((('checkout branch) rest ...)
  86. (git "checkout" branch)
  87. (loop rest))
  88. ((('merge branch message) rest ...)
  89. (git "merge" branch "-m" message)
  90. (loop rest))
  91. ((('merge branch message ('signer fingerprint)) rest ...)
  92. (git "merge" branch "-m" message
  93. (string-append "--gpg-sign=" fingerprint))
  94. (loop rest)))))
  95. (define (call-with-temporary-git-repository directives proc)
  96. (call-with-temporary-directory
  97. (lambda (directory)
  98. (populate-git-repository directory directives)
  99. (proc directory))))
  100. (define-syntax-rule (with-temporary-git-repository directory
  101. directives exp ...)
  102. "Evaluate EXP in a context where DIRECTORY contains a checkout populated as
  103. per DIRECTIVES."
  104. (call-with-temporary-git-repository directives
  105. (lambda (directory)
  106. exp ...)))
  107. (define (find-commit repository message)
  108. "Return the commit in REPOSITORY whose message includes MESSAGE, a string."
  109. (let/ec return
  110. (fold-commits (lambda (commit _)
  111. (and (string-contains (commit-message commit)
  112. message)
  113. (return commit)))
  114. #f
  115. repository)
  116. (error "commit not found" message)))