blob: cb2eec72e904ed57a6a87d85263227a17da97008 [file] [log] [blame]
# Copyright 2018 Fairphone B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# repo forall -c environment:
# pwd is the project's working directory. If the current client is a
# mirror client, then pwd is the Git repository.
#
# REPO_PROJECT is set to the unique name of the project.
#
# REPO_PATH is the path relative the root of the client.
#
# REPO_REMOTE is the name of the remote system from the manifest.
#
# REPO_LREV is the name of the revision from the manifest, translated to a
# local tracking branch. If you need to pass the manifest revision to a
# locally executed git command, use REPO_LREV.
#
# REPO_RREV is the name of the revision from the manifest, exactly as
# written in the manifest.
#
# REPO_COUNT is the total number of projects being iterated.
#
# REPO_I is the current (1-based) iteration count. Can be used in
# conjunction with REPO_COUNT to add a simple progress indicator to your
# command.
#
# REPO__* are any extra environment variables, specified by the
# "annotation" element under any project element. This can be useful for
# differentiating trees based on user-specific criteria, or simply
# annotating tree details.#
#
#
# Globals:
# SHELL_LIBS
set -e
# Includes:
. ${SHELL_LIBS}/utils.sh
# Environment variables:
VERBOSE="${VERBOSE:-}"
DEBUG="${DEBUG:-}"
DRY_RUN="${DRY_RUN:-}" #'--dry-run'. If set, run ssh/git commands without modify remote.
FAIRPHONE_REMOTE_URL="review.fairphone.software"
FAIRPHONE_REMOTE_PORT="29418"
# Check if a reference exists on project remote.
#
# Globals:
# REPO_REMOTE
# Arguments:
# ref The reference to check.
# Returns:
# 0 if found, otherwise the exit code for 'git ls-remote'
_remote_ref_exists()
{
local ref="$1"
local result=0
git ls-remote --exit-code ${REPO_REMOTE} ${ref} > /dev/null 2>&1 \
|| result=$?
case $result in
0)
;;
2)
log_e "${ref} does not exist on remote '${REPO_REMOTE}'"
;;
128)
log_e "${REPO_REMOTE} is not a valid remote"
;;
*)
log_e "[$result]: Unable to 'git ls-remote ${REPO_REMOTE} ${ref}'"
;;
esac
return "${result}"
}
# Check if a reference exists.
#
# Globals:
# None
# Arguments:
# ref The explicit reference path to check.
# Returns:
# Exit code of 'git show-ref'
_local_ref_exists()
{
local ref="$1"
local result=0
git show-ref --quiet --verify ${ref} || result=$?
return "${result}"
}
# Fetch a reference from a remote.
#
# If we have a shallow copy of the project, remove this condition.
#
# Globals:
# REPO_PROJECT
# REPO_REMOTE
# VERBOSE
# Arguments:
# ref_spec Specifies which refs to fetch and which local refs to update.
# Returns:
# None
_git_fetch()
{
local ref_spec="$1"
# Update shallow copies if needed
local unshallow=
if [ -f .git/shallow ] ; then
log_i "Removing shallow clone for ${REPO_PROJECT}"
unshallow="--unshallow"
fi
local result=0
git fetch --no-tags ${unshallow} ${VERBOSE} "${REPO_REMOTE}" \
"${ref_spec}" || result=$?
case $result in
0)
;;
*)
log_e "[$result]: Error fetching ${ref_spec} from ${REPO_REMOTE}."
;;
esac
}
# Push a reference to the remote 'fairphone'.
#
# Globals:
# DRY_RUN
# Arguments:
# ref_spec Specify what destination ref to update with what source object.
# Returns:
# None
_git_push()
{
local ref_spec="$1"
local result=0
git push ${DRY_RUN} fairphone "${ref_spec}" || result=$?
case $result in
0)
;;
128)
remote_url="$(git config --get remote.fairphone.url)"
log_e "${remote_url} is not a valid remote."
;;
*)
log_e "[$result]: Error pushing ${ref_spec} to fairphone."
;;
esac
}
# Run a gerrit command on the fairphone gerrit server.
#
# Globals:
# FAIRPHONE_REMOTE_PORT
# FAIRPHONE_REMOTE_URL
# Arguments:
# cmd The gerrit command
# Returns:
# Result of the gerrit command
_ssh_gerrit()
{
local result=0
ssh -p "${FAIRPHONE_REMOTE_PORT}" "${FAIRPHONE_REMOTE_URL}" gerrit $@ \
|| result=$?
case $result in
0)
;;
*)
log_e "[$result]: Error running 'ssh gerrit $@'"
;;
esac
return "${result}"
}
# Add remote 'fairphone' to project if missing.
#
# Globals:
# FAIRPHONE_REMOTE_PORT
# FAIRPHONE_REMOTE_URL
# REPO_PROJECT
# Arguments:
# None
# Returns:
# None
add_fairphone_remote()
{
if [ -z "$(git config --get remote.fairphone.url)" ] ; then
log_i "Adding remote 'fairphone' to ${REPO_PROJECT}"
local gerrit="ssh://${FAIRPHONE_REMOTE_URL}:${FAIRPHONE_REMOTE_PORT}"
git remote add fairphone "${gerrit}/${REPO_PROJECT}"
fi
}
# Add missing project to remote 'fairphone' if missing.
#
# Globals:
# FAIRPHONE_REMOTE_URL
# REPO_PROJECT
# DRY_RUN
# Arguments:
# None
# Returns:
# None
add_project_to_fairphone_remote()
{
# Does project exist on remote?
[ -n "$(_ssh_gerrit ls-projects -r ^${REPO_PROJECT}$)" ] && return
if [ -z "${DRY_RUN}" ] ; then
local result=0
_ssh_gerrit create-project "${REPO_PROJECT}" -p Marshmallow \
|| result=$?
if [ $result -eq 0 ] ; then
log_i " ${REPO_PROJECT} added to ${FAIRPHONE_REMOTE_URL}"
fi
else
# No dry-run options exists for 'gerrit create-project'
log_i "ssh gerrit create-project ${REPO_PROJECT} -p Marshmallow"
fi
}
# Fetch and save a reference from a remote.
#
# If we have a shallow copy, remove this condition.
#
# Globals:
# REPO_REMOTE
# Arguments:
# from_ref The explicit ref path of the ref to fetch.
# to_ref The explicit ref path of where to save the ref.
# Returns:
# None
fetch_remote_ref()
{
local from_ref=$1
local to_ref=$2
local result=0
_remote_ref_exists "${from_ref}" || result=$?
if [ $result -eq 0 ] ; then
_git_fetch "${from_ref}:${to_ref}"
fi
}
# Fetch a branch from a remote.
#
# Globals:
# REPO_REMOTE
# Arguments:
# branch
# Returns:
# None
fetch_remote_branch()
{
local branch="$1"
[ -n "${branch}" ] || log_e "Missing branch to fetch"
local from_branch="refs/heads/${branch}"
local to_branch="refs/remotes/${REPO_REMOTE}/${branch}"
fetch_remote_ref "${from_branch}" "${to_branch}"
}
# Fetch a tag from a remote.
#
# Globals:
# None
# Arguments:
# tag
# Returns:
# None
fetch_remote_tag()
{
local tag="$1"
[ -n "${tag}" ] || log_e "Missing tag to fetch"
fetch_remote_ref "refs/tags/${tag}" "refs/tags/${tag}"
}
# Globals:
# REPO_RREV
# Arguments:
# None
# Returns:
# None
remove_shallow_clone()
{
# Update shallow copies if needed
if [ -f .git/shallow ] ; then
_git_fetch "${REPO_RREV}:${REPO_RREV}"
fi
}
# Push a reference to the remote 'fairphone'.
#
# If the branch exists both locally and on remote, we default to pushing the
# local branch.
#
# Globals:
# REPO_REMOTE
# Arguments:
# branch_src Name of the local or remote branch to push.
# branch_target Name of the target branch to push to.
# Returns:
# None
push_branch_to_fairphone()
{
local branch_src="$1"
local branch_target="$2"
[ -n "${branch_src}" ] || log_e 'Missing branch parameter'
[ -n "${branch_target}" ] || log_e 'Missing target branch parameter'
local from_ref=
local to_ref="refs/heads/${branch_target}"
local result=0
_local_ref_exists "refs/heads/${branch_src}" || result=$?
if [ $result -eq 0 ] ; then
from_ref="refs/heads/${branch_src}"
else
result=0
_local_ref_exists "refs/remotes/${REPO_REMOTE}/${branch_src}" \
|| result=$?
if [ $result -eq 0 ] ; then
from_ref="refs/remotes/${REPO_REMOTE}/${branch_src}"
else
log_e "Unable to find local branch '${branch_src}' to push."
fi
fi
if [ -n "${from_ref}" ] ; then
_git_push "${from_ref}:${to_ref}"
fi
}
# Push a tag to the remote 'fairphone'.
#
# Globals:
# None
# Arguments:
# Tag Name of the tag to push.
# Returns:
# None
push_tag_to_fairphone()
{
local tag="refs/tags/$1"
[ -n "${tag}" ] || log_e 'Missing tag parameter'
local result=0
_local_ref_exists "${tag}" || result $?
if [ $result -eq 0 ] ; then
_git_push "${tag}:${tag}"
fi
}
[ -n "${DEBUG}" ] && set -x || true