aboutsummaryrefslogtreecommitdiff
path: root/lib/checkout.sh
blob: b906d99e099e8ff570dbd793d667c384690f8ff3 (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/bin/bash
# 
#   Copyright (C) 2013, 2014, 2015, 2016 Linaro, Inc
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
# 

#
# This does a checkout from a source code repository
#

# It's optional to use git-bzr-ng or git-svn to work on the remote sources,
# but we also want to work with the native source code control system.
usegit=no

# This is similar to make_all except it _just_ gathers sources trees and does
# nothing else.
checkout_all()
{
#    trace "$*"

    local packages="$*"

    notice "checkout_all called for packages: ${packages}"

    for i in ${packages}; do
	local package=$i
	if test x"$i" = x"libc"; then
	    package="${clibrary}"
	fi
	if test x"${package}" = x"stage1" -o x"${package}" = x"stage2"; then
	    package="gcc"
	fi

	local filespec="$(get_component_filespec ${package})"
	# don't skip mingw_only components so we get md5sums and/or
        # git revisions
	if test "$(component_is_tar ${package})" = no; then
 	    local checkout_ret=
	    checkout ${package}
	    checkout_ret=$?
	    if test ${checkout_ret} -gt 0; then
		error "Failed checkout out of ${package}."
		return 1
	    fi
	else
	    extract ${package}
	    if test $? -gt 0; then
		error "Couldn't extract tarball for ${package}"
		return 1
	    fi
	fi

    done

    notice "Checkout all took ${SECONDS} seconds"

    # Set this to no, since all the sources are now checked out
    supdate=no

    return 0
}

# merge changes from remote repo
update_checkout_branch()
{
    local component="$1"
    local srcdir=
    srcdir="$(get_component_srcdir ${component})" || return 1
    local branch=
    branch="$(get_component_branch ${component})" || return 1

    notice "Updating sources for ${component} in ${srcdir} on ${branch}"

    dryrun "git -C ${srcdir} merge --ff-only origin/${branch}"
    if test $? -gt 0; then
        error "Can't merge changes from ${branch}"
        return 1
    fi
}

# make sure the tag checkout is up to date
update_checkout_tag()
{
    local component="$1"
    local srcdir=
    srcdir="$(get_component_srcdir ${component})" || return 1
    local branch=
    branch="$(get_component_branch ${component})" || return 1

    local currev="$(git -C ${srcdir} rev-parse HEAD)"
    local tagrev="$(git -C ${srcdir} rev-parse ${branch})"
    if test x${currev} != x${tagrev}; then
	dryrun "git -C ${srcdir} stash && git -C ${srcdir} reset --hard ${branch}"
        if test $? -gt 0; then
	    error "Can't reset to ${branch}"
	    return 1
        fi
    fi
    return 0
}
# This gets the source tree from a remote host
# $1 - This should be a service:// qualified URL.  If you just
#       have a git identifier call get_URL first.
checkout()
{
#    trace "$*"

    local component="$1"

    # None of the following should be able to fail with the code as it is
    # written today (and failures are therefore untestable) but propagate
    # errors anyway, in case that situation changes.
    local url=
    url="$(get_component_url ${component})" || return 1
    local branch=
    branch="$(get_component_branch ${component})" || return 1
    local revision=
    revision="$(get_component_revision ${component})" || return 1
    local srcdir=
    srcdir="$(get_component_srcdir ${component})" || return 1
    local repo=
    repo="$(get_component_filespec ${component})" || return 1
    local protocol="$(echo ${url} | cut -d ':' -f 1)"
    local repodir="${url}/${repo}"
    local new_srcdir=false

    # gdbserver is already checked out in the GDB source tree.
    if test x"${component}" = x"gdbserver"; then
	local gdbrevision="$(get_component_revision gdb)"
        if [ x"${gdbrevision}" = x"" ]; then
            error "no gdb revision found"
            return 1
        fi
	set_component_revision gdbserver ${gdbrevision}
        return 0
    fi

    if ! validate_url "${repodir}"; then
	error "proper URL required"
	return 1
    fi

    case ${protocol} in
	git*|http*|ssh*)
	    if test ! -d ${srcdir}; then
		# By definition a git commit resides on a branch.  Therefore
		# specifying a branch AND a commit is redundant and potentially
		# contradictory.  For this reason we only consider the commit
		# if both are present.
		if test x"${revision}" != x""; then
		    notice "Checking out revision ${revision} for ${component} in ${srcdir}"
		    dryrun "${NEWWORKDIR} ${local_snapshots}/${repo} ${srcdir} ${revision}"
		    if test $? -gt 0; then
			error "Failed to create workdir for ${revision}"
			return 1
		    fi
	        else
		    notice "Checking out branch ${branch} for ${component} in ${srcdir}"
		    dryrun "${NEWWORKDIR} ${local_snapshots}/${repo} ${srcdir} ${branch}"
		    if test $? -gt 0; then
			error "Failed to create workdir for ${branch}"
			return 1
		    fi
		    # If the user mistakenly used ~revision instead of
		    # @revision, exit with an error, to avoid branch
		    # update failures on subsequent runs.
		    # ~revision can also point to a tag.
		    if test x"${dryrun}" != xyes; then
			if test $(git -C ${srcdir} reflog ${branch} | wc -l) -eq 0 -a \
			        $(git -C ${srcdir} tag -l ${branch} | wc -l) -eq 0; then
			    error "${branch} is not a branch or tag, use @{revision} to specify a revision"
			    return 1
			fi
		    fi
		fi
		new_srcdir=true
	    elif test x"${supdate}" = xyes; then
		# if we're building a particular revision, then make sure it
		# is checked out.
                if test x"${revision}" != x""; then
		    notice "Building explicit revision for ${component}."
		    # No need to pull.  A commit is a single moment in time
		    # and doesn't change.
		    dryrun "git -C ${srcdir} checkout ${revision}"
		    if test $? -gt 0; then
			error "Can't checkout ${revision}"
			return 1
		    fi
		elif git -C ${srcdir} rev-parse -q --verify refs/tags/${branch}; then
		    notice "Found tag ${branch}, updating in case tag has moved."
		    update_checkout_tag "${component}"
		    if test $? -gt 0; then
			error "Error during update_checkout_tag."
			return 1
		    fi
		else
		    # Some packages allow the build to modify the source
		    # directory and that might screw up abe's state so we
		    # restore a pristine branch.
		    if test x"${branch}" = x; then
			error "No branch name specified!"
			return 1
		    fi
		    update_checkout_branch ${component}
		    if test $? -gt 0; then
			error "Error during update_checkout_branch."
			return 1
		    fi
		fi
		new_srcdir=true
	    fi

	    if test x"${dryrun}" != xyes; then
		local newrev="$(git -C ${srcdir} log --format=format:%H -n 1)"
	    else
		local newrev="unknown/dryrun"
	    fi
	    set_component_revision ${component} ${newrev}
	    ;;
	*)
	    error "proper URL required"
	    return 1
	    ;;
    esac

    if $new_srcdir; then
	case "${component}" in
	    gcc)
		# Touch GCC's auto-generated files to avoid non-deterministic
		# build behavior.
		dryrun "(cd ${srcdir} && ./contrib/gcc_update --touch)"
		# LAST_UPDATED and gcc/REVISION are used when sending
		# results summaries
		# Report svn revision, if present
		local svnrev="$(git -C ${srcdir} log -n 1 | grep git-svn-id: | awk '{print $2;}' | cut -d@ -f2)"
		local revstring="${newrev}"
		[ x"${svnrev}" != x ] && revstring="${svnrev}"
		dryrun "echo $(TZ=UTC date) '(revision' ${revstring}')' | tee ${srcdir}/LAST_UPDATED"
		dryrun "echo \[${branch} revision ${revstring}\] | tee ${srcdir}/gcc/REVISION"

		if test x"${gcc_patch_file}" != x""; then
		    dryrun "git -C ${srcdir} apply --check ${gcc_patch_file}"
		    if test $? != 0; then
			error "Patch ${gcc_patch_file} does not apply."
			return 1
		    fi
		    git -C ${srcdir} apply ${gcc_patch_file}
		fi
		;;
	    *)
		# Avoid rebuilding of auto-generated C files. Rather than
		# try to determine which are auto-generated, touch all of them.
		# If a C file is not autogenerated, it does no harm to update
		# its timestamp.
		dryrun "cd ${srcdir} && git ls-files -z '*.c' | xargs -0 touch"
	esac
    fi

    # Show the most recent commit, useful when debugging (to check
    # that what we are building actually contains what we expect).
    dryrun "git --no-pager -C ${srcdir} show -s"

    return 0
}