summaryrefslogtreecommitdiff
path: root/eclass/scm-git.eclass
blob: c027085b64455407e1c0801ee1af2e3a1b5b4a77 (plain)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# Copyright 2008 David Leverton <dleverton@exherbo.org>
# Distributed under the terms of the GNU General Public License v2
# Based in part upon git.exlib, which is:
#    Copyright 2008 Fernando J. Pereda
#    Based upon 'git.eclass' which is:
#       Copyright 1999-2007 Gentoo Foundation

if [[ -z ${SCM_TYPE} ]]; then
	SCM_TYPE=git
	inherit scm
fi

scm-git_do_dependencies() {
	local git='>=dev-vcs/git-1.6.0'
	if [[ $(scm_get_var REPOSITORY) == https://* ]]; then
		echo "${git}$(scm_usedeps curl) net-misc/curl$(scm_usedeps ssl)"
	elif [[ $(scm_get_var REPOSITORY) == http://* || $(scm_get_var REPOSITORY) == ftp://* ]]; then
		echo "${git}$(scm_usedeps curl)"
	elif [[ $(scm_get_var REPOSITORY) == rsync://* ]]; then
		echo "${git} net-misc/rsync"
	elif [[ $(scm_get_var REPOSITORY) == ssh://* ]] ||
			[[ $(scm_get_var REPOSITORY) != *://* && $(scm_get_var REPOSITORY) == *:* ]]; then
		echo "${git} net-misc/openssh"
	else
		echo "${git}"
	fi

	if [[ -n $(scm_get_var TAG) ]]; then
		local keys
		scm_get_array GIT_TAG_SIGNING_KEYS keys
		[[ ${#keys[@]} -gt 0 ]] && echo app-crypt/gnupg
	fi
}

scm-git_do_check_vars() {
	[[ -n $(scm_get_var TAG) && -n $(scm_get_var REVISION) ]] \
		&& die "for git, $(scm_var_name TAG) must not be set at the same time as $(scm_var_name REVISION)"
	[[ -z $(scm_get_var BRANCH) && -z $(scm_get_var REVISION) &&
			-z $(scm_get_var TAG) ]] && scm_set_var BRANCH master
	local rev=$(scm_get_var REVISION)
	[[ -n ${rev} ]] && [[ ${rev} == *[^0123456789abcdef]* || ${#rev} -ne 40 ]] \
		&& die "for git, $(scm_var_name REVISION) must be a 40-character lowercase hexadecimal SHA-1 sum"
	[[ -n $(scm_get_var SUBPATH) ]] && die "for git, $(scm_var_name SUBPATH) must not be set"

	scm_modify_var REPOSITORY scm_trim_slashes -scheme -trailing
}

scm-git_git() {
	local echo=echo
	if [[ ${1} == -q ]]; then
		shift
		echo=:
	fi

	local need_git_dir=yes global=( )
	while [[ ${#} -gt 0 && ${1} == -* ]]; do
		global+=( "${1}" )
		[[ ${1} == --git-dir=* ]] && need_git_dir=
		shift
	done
	[[ ${1} != clone && -n ${need_git_dir} ]] && global+=( --git-dir="$(scm_get_var CHECKOUT_TO)" )

	${echo} git "${global[@]}" "${@}"
	GIT_PAGER=cat git "${global[@]}" "${@}" || scm_die_unless_nonfatal "git ${1} failed"
}

scm-git_do_appraise() {
	local dir=$(scm_get_var CHECKOUT_TO)

	if ! scm_nonfatal scm-git_git -q rev-parse 2>/dev/null; then
		echo "${dir} is not a git checkout"
		return 3
	fi

	if [[ -n $(scm_get_var REVISION) ]]; then
		if [[ -z $(scm_nonfatal scm-git_git -q cat-file -t $(scm_get_var REVISION) 2>/dev/null) ]]; then
			echo "$(scm_get_var REVISION) is not present in ${dir}"
			return 1
		elif [[ $(scm-git_git -q cat-file -t $(scm_get_var REVISION)) == commit ]]; then
			if [[ -n $(scm_get_var BRANCH) ]] && ! scm-git_git -q rev-list "refs/heads/$(scm_get_var BRANCH)" \
					| grep -Fx $(scm_get_var REVISION) >/dev/null; then
				echo "revision $(scm_get_var REVISION) is not part of branch $(scm_get_var BRANCH) of ${dir}"
				return 1
			fi
			return 2
		else
			die "$(scm_get_var REVISION) is not a commit in ${dir}"
		fi
	fi

	local origin=$(scm-git_git -q config remote.origin.url)
	[[ -n ${origin} ]] || die "could not determine origin URL for ${dir}"
	if [[ ${origin} != $(scm_get_var REPOSITORY) ]]; then
		echo "${dir} is a clone of ${origin}, but wanted $(scm_get_var REPOSITORY)"
		return 1
	fi

	if [[ -n $(scm_get_var TAG) ]]; then
		if [[ -n $(scm-git_git -q for-each-ref "refs/tags/$(scm_get_var TAG)") ]]; then
			if [[ -n $(scm_get_var BRANCH) ]] && ! scm-git_git -q rev-list "refs/heads/$(scm_get_var BRANCH)" \
					| grep -Fx $(scm-git_git -q rev-parse "refs/tags/$(scm_get_var TAG)") >/dev/null; then
				echo "tag $(scm_get_var TAG) is not part of branch $(scm_get_var BRANCH) of ${dir}"
				return 1
			fi

			local keys
			scm_get_array GIT_TAG_SIGNING_KEYS keys
			if [[ ${#keys[@]} -gt 0 ]]; then
				local gpghome=$(mktemp -d -p "${T}" gpg-XXXXXX)
				[[ -n ${gpghome} ]] || die "mktemp failed"

				cat >"${gpghome}/gpg" <<-EOF
					#! /usr/bin/env bash
					$(HOME=${gpghome} declare -p HOME)
					$(gpg=$(type -P gpg); declare -p gpg)
					errors=\$("\${gpg}" --keyserver-options no-auto-key-retrieve "\${@}" 2>&1 >/dev/null) && exit
					status=\${?}
					echo "\${errors}" >&2
					exit \${status}
				EOF
				[[ ${?} -eq 0 ]] || die "create gpg wrapper failed"
				chmod +x "${gpghome}/gpg" || die "chmod +x gpg wrapper failed"

				PATH=${gpghome}:${PATH} gpg --import "${keys[@]}" || die "gpg --import ${keys[*]} failed"
				PATH=${gpghome}:${PATH} scm-git_git -q verify-tag "$(scm_get_var TAG)" >/dev/null
			fi

			return 2
		else
			echo "${dir} does not contain the tag $(scm_get_var TAG)"
			return 1
		fi
	fi

	if [[ -n $(scm_get_var BRANCH) && -z $(scm-git_git -q for-each-ref "refs/heads/$(scm_get_var BRANCH)") ]]; then
		echo "${dir} does not contain the branch $(scm_get_var BRANCH)"
		return 1
	fi

	return 0
}

scm-git_do_checkout() {
	scm-git_git clone --bare "$(scm_get_var REPOSITORY)" "$(scm_get_var CHECKOUT_TO)"
	scm-git_git config remote.origin.url "$(scm_get_var REPOSITORY)"
	scm-git_git gc --auto
}

scm-git_do_update() {
	local old_origin=$(scm-git_git -q config remote.origin.url)
	[[ -n ${old_origin} ]] || die "could not determine origin URL for $(scm_get_var CHECKOUT_TO)"
	if [[ ${old_origin} != $(scm_get_var REPOSITORY) ]]; then
		scm-git_git config remote.origin.url "$(scm_get_var REPOSITORY)"
		eval "$(scm-git_git -q for-each-ref --shell --format "scm-git_git update-ref -d %(refname)" refs/{heads,tags}/\*)"
	fi

	local branch=$(scm_get_var BRANCH)
	scm-git_git fetch -f -u origin "refs/heads/${branch:-*}:refs/heads/${branch:-*}"
	scm-git_git gc --auto
	[[ -n ${branch} ]] && scm_set_array FETCHED_BRANCHES "${branch}"
}

scm-git_do_revision() {
	scm-git_git -q rev-parse $(
		if [[ -n $(scm_get_var TAG) ]]; then
			echo refs/tags/$(scm_get_var TAG)
		elif [[ -n $(scm_get_var REVISION) ]]; then
			scm_get_var REVISION
		else
			echo refs/heads/$(scm_get_var BRANCH)
		fi)
}

scm-git_do_unpack() {
	scm-git_git clone -s -n "$(scm_get_var CHECKOUT_TO)" "$(scm_get_var UNPACK_TO)"
	scm-git_git --git-dir="$(scm_get_var UNPACK_TO)"/.git --work-tree="$(scm_get_var UNPACK_TO)" checkout -f $(
		if [[ -n $(scm_get_var TAG) ]]; then
			echo refs/tags/$(scm_get_var TAG)
		elif [[ -n $(scm_get_var REVISION) ]]; then
			scm_get_var REVISION
		else
			[[ -n $(scm-git_git -q --git-dir="$(scm_get_var UNPACK_TO)"/.git for-each-ref "refs/heads/$(scm_get_var BRANCH)") ]] \
				|| echo -b $(scm_get_var BRANCH) refs/remotes/origin/$(scm_get_var BRANCH)
		fi) --
}