-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathupstream-git.lisp
133 lines (115 loc) · 5.09 KB
/
upstream-git.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
;;;; upstream-git.lisp
(in-package #:quicklisp-controller)
(defclass git-source (vcs-source)
((tarball-target
:initarg :tarball-target
:accessor tarball-target
:initform "master"))
(:default-initargs
:command "git"
:checkout-subcommand "clone"
:checkout-subcommand-arguments '("--recursive")
:update-subcommand "pull"))
(defclass tagged-git-source (tagged-mixin git-source)
((tag-data :reader tarball-target)))
(defclass branched-git-source (tagged-mixin git-source)
((tag-data :reader branch-name :reader tarball-target)))
(defclass git-at-commit-source (tagged-git-source)
((tag-data :reader commit :reader tarball-target)))
(defmethod checkout-subcommand-arguments ((source branched-git-source))
(append (call-next-method) (list "--branch" (branch-name source))))
(defmethod vcs-update ((source tagged-git-source) checkout-directory)
(with-posix-cwd checkout-directory
(run "git" "fetch")
(run "git" "checkout" (tag-data source))))
(defmethod vcs-update :after ((source git-source) checkout-directory)
(with-posix-cwd checkout-directory
(run "git" "submodule" "update" "--init" "--recursive")))
(defmethod cached-checkout-directory :around ((source git-source))
;; Older gits have problems with checking out to a directory with
;; a trailing slash, so trim it.
(string-right-trim "/" (namestring (call-next-method))))
(defun commit-id (source)
(let ((checkout (ensure-source-cache source)))
(with-posix-cwd checkout
(with-run-output (stream ("git" "rev-parse" "HEAD"))
(read-line stream)))))
(defmethod source-cache-timestamp ((source git-source))
(let ((unix-time-offset (load-time-value (encode-universal-time 0 0 0 1 1 1970 0))))
(let ((checkout (ensure-source-cache source)))
(with-posix-cwd checkout
(with-run-output (stream ("git" "show" "-s" "--format=%ct"))
(let ((unix-time-string (read-line stream)))
(+ (parse-integer unix-time-string) unix-time-offset)))))))
(defmethod tag-data :around ((source branched-git-source))
(let ((tag (call-next-method))
(commit (commit-id source)))
(format nil "~A-~A"
tag
(subseq commit 0 8))))
(defgeneric target-ref (source)
(:documentation "The ref to use when archiving.")
(:method ((source git-source))
"HEAD")
(:method ((source branched-git-source))
(format nil "refs/heads/~A" (tarball-target source)))
(:method ((source tagged-git-source))
(format nil "refs/tags/~A" (tarball-target source)))
(:method ((source git-at-commit-source))
(format nil "~A" (commit source))))
(defstruct (submodule (:type vector))
name
path
sha1)
(defun git-submodules (git-path)
(loop for line in
(run-output-lines "git" "-C" (truename git-path) "submodule"
"--quiet"
"foreach"
"--recursive"
"echo $name $sha1 $displaypath")
for (name sha1 path) = (split-spaces line)
collect (make-submodule :name (encode-string-for-filesystem name)
:path path
:sha1 sha1)))
(defun full-git-archive (git-path target-ref prefix output-file)
"Create a tarball archive in OUTPUT-FILE of the full contents of the
git checkout GIT-PATH, including submodules. The repo is archived at
TARGET-REF, e.g. 'HEAD'. "
(run "git" "-C" (truename git-path)
"submodule" "update" "--init" "--recursive")
(let ((submodules (git-submodules git-path)))
(in-temporary-directory prefix
(let* ((temp-base *default-pathname-defaults*))
(with-posix-cwd git-path
(run "git" "archive"
:format "tar"
:prefix (format nil "~A/" prefix)
"-o" (make-pathname :name (string-right-trim "/" prefix)
:type "tar"
:defaults temp-base)
target-ref)
(dolist (submodule submodules)
(with-posix-cwd (submodule-path submodule)
(let ((output (make-pathname :name (submodule-name submodule)
:type "tar"
:defaults temp-base)))
(run "git" "archive"
:format "tar"
"-o" output
:prefix (format nil "~A/~A/"
prefix (submodule-path submodule))
(submodule-sha1 submodule))))))
;; Back in the temp directory
(dolist (tarball (directory "*.tar"))
(run "tar" "xf" tarball))
(let ((combined "combined.tar")
(combined-tgz "combined.tar.gz"))
(run "tar" "cf" combined prefix)
(run "gzip" "-vn9" "-S" ".gz" combined)
(rename-file combined-tgz output-file))
output-file))))
(defmethod make-release-tarball ((source git-source) output-file)
(let ((prefix (release-tarball-prefix source))
(checkout (ensure-source-cache source)))
(full-git-archive checkout (target-ref source) prefix output-file)))