doc: Mention value /var to localstatedir option.
[jackhill/guix/guix.git] / guix / git-download.scm
CommitLineData
9b5b5c17 1;;; GNU Guix --- Functional package management for GNU
81c3dc32 2;;; Copyright © 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
6554be68 3;;; Copyright © 2017 Mathieu Lirzin <mthl@gnu.org>
f135b4ae 4;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
9b5b5c17
LC
5;;;
6;;; This file is part of GNU Guix.
7;;;
8;;; GNU Guix is free software; you can redistribute it and/or modify it
9;;; under the terms of the GNU General Public License as published by
10;;; the Free Software Foundation; either version 3 of the License, or (at
11;;; your option) any later version.
12;;;
13;;; GNU Guix is distributed in the hope that it will be useful, but
14;;; WITHOUT ANY WARRANTY; without even the implied warranty of
15;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;;; GNU General Public License for more details.
17;;;
18;;; You should have received a copy of the GNU General Public License
19;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
20
21(define-module (guix git-download)
6119ebf1 22 #:use-module (guix gexp)
e87f0591 23 #:use-module (guix store)
6119ebf1 24 #:use-module (guix monads)
9b5b5c17 25 #:use-module (guix records)
9b5b5c17 26 #:use-module (guix packages)
37ce440d 27 #:use-module (guix modules)
0d5a559f 28 #:autoload (guix build-system gnu) (standard-packages)
aed0a594 29 #:use-module (git)
9b5b5c17 30 #:use-module (ice-9 match)
f135b4ae 31 #:use-module (ice-9 vlist)
6554be68 32 #:use-module (srfi srfi-1)
9b5b5c17
LC
33 #:export (git-reference
34 git-reference?
35 git-reference-url
36 git-reference-commit
6750877f 37 git-reference-recursive?
9b5b5c17 38
ee17a9e0
DC
39 git-fetch
40 git-version
6554be68
ML
41 git-file-name
42 git-predicate))
9b5b5c17
LC
43
44;;; Commentary:
45;;;
46;;; An <origin> method that fetches a specific commit from a Git repository.
47;;; The repository URL and commit hash are specified with a <git-reference>
48;;; object.
49;;;
50;;; Code:
51
52(define-record-type* <git-reference>
53 git-reference make-git-reference
54 git-reference?
6750877f
LC
55 (url git-reference-url)
56 (commit git-reference-commit)
57 (recursive? git-reference-recursive? ; whether to recurse into sub-modules
58 (default #f)))
9b5b5c17 59
6119ebf1
LC
60(define (git-package)
61 "Return the default Git package."
62 (let ((distro (resolve-interface '(gnu packages version-control))))
3b5829bb 63 (module-ref distro 'git-minimal)))
6119ebf1 64
f220a838 65(define* (git-fetch ref hash-algo hash
9b5b5c17 66 #:optional name
f220a838 67 #:key (system (%current-system)) (guile (default-guile))
6119ebf1 68 (git (git-package)))
f220a838
LC
69 "Return a fixed-output derivation that fetches REF, a <git-reference>
70object. The output is expected to have recursive hash HASH of type
71HASH-ALGO (a symbol). Use NAME as the file name, or a generic name if #f."
6750877f
LC
72 (define inputs
73 ;; When doing 'git clone --recursive', we need sed, grep, etc. to be
74 ;; available so that 'git submodule' works.
75 (if (git-reference-recursive? ref)
0d5a559f 76 (standard-packages)
608d3dca
LC
77
78 ;; The 'swh-download' procedure requires tar and gzip.
79 `(("gzip" ,(module-ref (resolve-interface '(gnu packages compression))
80 'gzip))
81 ("tar" ,(module-ref (resolve-interface '(gnu packages base))
82 'tar)))))
6750877f 83
37ce440d
LC
84 (define zlib
85 (module-ref (resolve-interface '(gnu packages compression)) 'zlib))
86
608d3dca 87 (define guile-json
81c3dc32 88 (module-ref (resolve-interface '(gnu packages guile)) 'guile-json-3))
608d3dca
LC
89
90 (define gnutls
91 (module-ref (resolve-interface '(gnu packages tls)) 'gnutls))
92
37ce440d
LC
93 (define config.scm
94 (scheme-file "config.scm"
95 #~(begin
96 (define-module (guix config)
97 #:export (%libz))
98
99 (define %libz
100 #+(file-append zlib "/lib/libz")))))
101
102 (define modules
103 (cons `((guix config) => ,config.scm)
104 (delete '(guix config)
105 (source-module-closure '((guix build git)
106 (guix build utils)
608d3dca
LC
107 (guix build download-nar)
108 (guix swh))))))
37ce440d 109
6119ebf1 110 (define build
37ce440d 111 (with-imported-modules modules
608d3dca
LC
112 (with-extensions (list guile-json gnutls) ;for (guix swh)
113 #~(begin
114 (use-modules (guix build git)
115 (guix build utils)
116 (guix build download-nar)
117 (guix swh)
118 (ice-9 match))
119
120 (define recursive?
121 (call-with-input-string (getenv "git recursive?") read))
122
123 ;; The 'git submodule' commands expects Coreutils, sed,
124 ;; grep, etc. to be in $PATH.
125 (set-path-environment-variable "PATH" '("bin")
126 (match '#+inputs
127 (((names dirs outputs ...) ...)
128 dirs)))
129
130 (setvbuf (current-output-port) 'line)
131 (setvbuf (current-error-port) 'line)
132
133 (or (git-fetch (getenv "git url") (getenv "git commit")
134 #$output
135 #:recursive? recursive?
136 #:git-command (string-append #+git "/bin/git"))
137 (download-nar #$output)
138
139 ;; As a last resort, attempt to download from Software Heritage.
140 ;; XXX: Currently recursive checkouts are not supported.
141 (and (not recursive?)
b8815c5e
LC
142 (begin
143 (format (current-error-port)
144 "Trying to download from Software Heritage...~%")
145 (swh-download (getenv "git url") (getenv "git commit")
146 #$output))))))))
6750877f 147
f220a838 148 (mlet %store-monad ((guile (package->derivation guile system)))
6119ebf1 149 (gexp->derivation (or name "git-checkout") build
c0b2d08b
LC
150
151 ;; Use environment variables and a fixed script name so
152 ;; there's only one script in store for all the
153 ;; downloads.
154 #:script-name "git-download"
155 #:env-vars
156 `(("git url" . ,(git-reference-url ref))
157 ("git commit" . ,(git-reference-commit ref))
158 ("git recursive?" . ,(object->string
159 (git-reference-recursive? ref))))
67c2db17
LC
160 #:leaked-env-vars '("http_proxy" "https_proxy"
161 "LC_ALL" "LC_MESSAGES" "LANG"
162 "COLUMNS")
c0b2d08b 163
6119ebf1 164 #:system system
6b44a097 165 #:local-build? #t ;don't offload repo cloning
6119ebf1
LC
166 #:hash-algo hash-algo
167 #:hash hash
168 #:recursive? #t
5c6a30c5 169 #:guile-for-build guile)))
9b5b5c17 170
ee17a9e0
DC
171(define (git-version version revision commit)
172 "Return the version string for packages using git-download."
173 (string-append version "-" revision "." (string-take commit 7)))
174
175(define (git-file-name name version)
176 "Return the file-name for packages using git-download."
177 (string-append name "-" version "-checkout"))
178
f135b4ae
CB
179\f
180;;;
181;;; 'git-predicate'.
182;;;
183
aed0a594
LC
184(define (git-file-list directory)
185 "Return the list of files checked in in the Git repository at DIRECTORY.
186The result is similar to that of the 'git ls-files' command, except that it
187also includes directories, not just regular files. The returned file names
188are relative to DIRECTORY, which is not necessarily the root of the checkout."
280fc835
MB
189 (let* (;; 'repository-working-directory' always returns a trailing "/",
190 ;; so add one here to ease the comparisons below.
191 (directory (string-append (canonicalize-path directory) "/"))
aed0a594 192 (dot-git (repository-discover directory))
aed0a594 193 (repository (repository-open dot-git))
5d9fe431 194 (workdir (repository-working-directory repository))
aed0a594
LC
195 (head (repository-head repository))
196 (oid (reference-target head))
197 (commit (commit-lookup repository oid))
198 (tree (commit-tree commit))
199 (files (tree-list tree)))
200 (repository-close! repository)
280fc835 201 (if (string=? workdir directory)
aed0a594 202 files
280fc835 203 (let ((relative (string-drop directory (string-length workdir))))
aed0a594
LC
204 (filter-map (lambda (file)
205 (and (string-prefix? relative file)
206 (string-drop file (string-length relative))))
207 files)))))
f135b4ae 208
6554be68
ML
209(define (git-predicate directory)
210 "Return a predicate that returns true if a file is part of the Git checkout
13512e1b
LC
211living at DIRECTORY. If DIRECTORY does not lie within a Git checkout, and
212upon Git errors, return #f instead of a predicate.
6554be68
ML
213
214The returned predicate takes two arguments FILE and STAT where FILE is an
215absolute file name and STAT is the result of 'lstat'."
13512e1b
LC
216 (catch 'git-error
217 (lambda ()
218 (let* ((files (git-file-list directory))
219 (inodes (fold (lambda (file result)
220 (let ((stat
221 (lstat (string-append directory "/"
222 file))))
223 (vhash-consv (stat:ino stat) (stat:dev stat)
224 result)))
225 vlist-null
226 files)))
227 (lambda (file stat)
228 ;; Comparing file names is always tricky business so we rely on inode
229 ;; numbers instead.
230 (match (vhash-assv (stat:ino stat) inodes)
231 ((_ . dev) (= dev (stat:dev stat)))
232 (#f #f)))))
233 (const #f)))
6554be68 234
9b5b5c17 235;;; git-download.scm ends here