inferior: Add home-page and location package accessors.
[jackhill/guix/guix.git] / guix / git.scm
CommitLineData
6b7b3ca9
MO
1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com>
95bd9f65 3;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
6b7b3ca9
MO
4;;;
5;;; This file is part of GNU Guix.
6;;;
7;;; GNU Guix is free software; you can redistribute it and/or modify it
8;;; under the terms of the GNU General Public License as published by
9;;; the Free Software Foundation; either version 3 of the License, or (at
10;;; your option) any later version.
11;;;
12;;; GNU Guix is distributed in the hope that it will be useful, but
13;;; WITHOUT ANY WARRANTY; without even the implied warranty of
14;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;;; GNU General Public License for more details.
16;;;
17;;; You should have received a copy of the GNU General Public License
18;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19
20(define-module (guix git)
21 #:use-module (git)
22 #:use-module (git object)
23 #:use-module (guix base32)
24 #:use-module (guix hash)
0ad5f809 25 #:use-module ((guix build utils) #:select (mkdir-p))
6b7b3ca9
MO
26 #:use-module (guix store)
27 #:use-module (guix utils)
28 #:use-module (rnrs bytevectors)
29 #:use-module (ice-9 match)
30 #:use-module (srfi srfi-1)
91881986 31 #:use-module (srfi srfi-11)
95bd9f65
LC
32 #:use-module (srfi srfi-34)
33 #:use-module (srfi srfi-35)
6b7b3ca9 34 #:export (%repository-cache-directory
91881986 35 update-cached-checkout
6b7b3ca9
MO
36 latest-repository-commit))
37
38(define %repository-cache-directory
39 (make-parameter "/var/cache/guix/checkouts"))
40
41(define-syntax-rule (with-libgit2 thunk ...)
b02469d2
MO
42 (begin
43 ;; XXX: The right thing to do would be to call (libgit2-shutdown) here,
44 ;; but pointer finalizers used in guile-git may be called after shutdown,
45 ;; resulting in a segfault. Hence, let's skip shutdown call for now.
46 (libgit2-init!)
47 thunk ...))
6b7b3ca9
MO
48
49(define* (url-cache-directory url
50 #:optional (cache-directory
51 (%repository-cache-directory)))
52 "Return the directory associated to URL in %repository-cache-directory."
53 (string-append
54 cache-directory "/"
55 (bytevector->base32-string (sha256 (string->utf8 url)))))
56
57(define (clone* url directory)
58 "Clone git repository at URL into DIRECTORY. Upon failure,
59make sure no empty directory is left behind."
60 (with-throw-handler #t
61 (lambda ()
62 (mkdir-p directory)
195f0d05
LC
63
64 ;; Note: Explicitly pass options to work around the invalid default
65 ;; value in Guile-Git: <https://bugs.gnu.org/29238>.
b1488c76
LC
66 (if (module-defined? (resolve-interface '(git))
67 'clone-init-options)
68 (clone url directory (clone-init-options))
69 (clone url directory)))
6b7b3ca9
MO
70 (lambda _
71 (false-if-exception (rmdir directory)))))
72
6b7b3ca9
MO
73(define (url+commit->name url sha1)
74 "Return the string \"<REPO-NAME>-<SHA1:7>\" where REPO-NAME is the name of
75the git repository, extracted from URL and SHA1:7 the seven first digits
76of SHA1 string."
77 (string-append
78 (string-replace-substring
79 (last (string-split url #\/)) ".git" "")
80 "-" (string-take sha1 7)))
81
6b7b3ca9 82(define (switch-to-ref repository ref)
91881986
LC
83 "Switch to REPOSITORY's branch, commit or tag specified by REF. Return the
84OID (roughly the commit hash) corresponding to REF."
95bd9f65
LC
85 (define obj
86 (match ref
87 (('branch . branch)
88 (let ((oid (reference-target
89 (branch-lookup repository branch BRANCH-REMOTE))))
90 (object-lookup repository oid)))
91 (('commit . commit)
92 (let ((len (string-length commit)))
93 ;; 'object-lookup-prefix' appeared in Guile-Git in Mar. 2018, so we
94 ;; can't be sure it's available. Furthermore, 'string->oid' used to
95 ;; read out-of-bounds when passed a string shorter than 40 chars,
96 ;; which is why we delay calls to it below.
97 (if (< len 40)
98 (if (module-defined? (resolve-interface '(git object))
99 'object-lookup-prefix)
100 (object-lookup-prefix repository (string->oid commit) len)
101 (raise (condition
102 (&message
103 (message "long Git object ID is required")))))
104 (object-lookup repository (string->oid commit)))))
105 (('tag . tag)
106 (let ((oid (reference-name->oid repository
107 (string-append "refs/tags/" tag))))
108 (object-lookup repository oid)))))
109
91881986
LC
110 (reset repository obj RESET_HARD)
111 (object-id obj))
112
113(define* (update-cached-checkout url
114 #:key
115 (ref '(branch . "origin/master"))
116 (cache-directory
ffc3fcad
OP
117 (url-cache-directory
118 url (%repository-cache-directory))))
91881986
LC
119 "Update the cached checkout of URL to REF in CACHE-DIRECTORY. Return two
120values: the cache directory name, and the SHA1 commit (a string) corresponding
121to REF.
122
123REF is pair whose key is [branch | commit | tag] and value the associated
124data, respectively [<branch name> | <sha1> | <tag name>]."
125 (with-libgit2
ffc3fcad 126 (let* ((cache-exists? (openable-repository? cache-directory))
91881986 127 (repository (if cache-exists?
ffc3fcad
OP
128 (repository-open cache-directory)
129 (clone* url cache-directory))))
91881986
LC
130 ;; Only fetch remote if it has not been cloned just before.
131 (when cache-exists?
132 (remote-fetch (remote-lookup repository "origin")))
133 (let ((oid (switch-to-ref repository ref)))
134
135 ;; Reclaim file descriptors and memory mappings associated with
136 ;; REPOSITORY as soon as possible.
137 (when (module-defined? (resolve-interface '(git repository))
138 'repository-close!)
139 (repository-close! repository))
140
ffc3fcad 141 (values cache-directory (oid->string oid))))))
6b7b3ca9
MO
142
143(define* (latest-repository-commit store url
144 #:key
145 (cache-directory
146 (%repository-cache-directory))
147 (ref '(branch . "origin/master")))
148 "Return two values: the content of the git repository at URL copied into a
149store directory and the sha1 of the top level commit in this directory. The
150reference to be checkout, once the repository is fetched, is specified by REF.
151REF is pair whose key is [branch | commit | tag] and value the associated
152data, respectively [<branch name> | <sha1> | <tag name>].
153
154Git repositories are kept in the cache directory specified by
155%repository-cache-directory parameter."
91881986
LC
156 (define (dot-git? file stat)
157 (and (string=? (basename file) ".git")
158 (eq? 'directory (stat:type stat))))
dfca2418 159
ffc3fcad
OP
160 (let*-values
161 (((checkout commit)
162 (update-cached-checkout url
163 #:ref ref
164 #:cache-directory
165 (url-cache-directory url cache-directory)))
166 ((name)
167 (url+commit->name url commit)))
91881986
LC
168 (values (add-to-store store name #t "sha256" checkout
169 #:select? (negate dot-git?))
170 commit)))