root/build-tools/repo-utils.sh

238 lines
5.7 KiB
Bash

#!/bin/bash
#
# Copyright (c) 2020 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
#
# A collection of utilities relating to 'repo'
#
#
# Echo to stderr
# echo_stderr [any text you want]
#
echo_stderr ()
{
echo "$@" >&2
}
#
# Get the root dir of a repo managed repository
# repo_root [<dir_path>]
#
repo_root () {
local query_dir="${1:-${PWD}}"
local work_dir
if [ ! -d "${query_dir}" ]; then
echo_stderr "not a valid directory: ${query_dir}"
return 1
fi
if [ "${query_dir:0:1}" != "/" ]; then
query_dir=$(readlink -f ${query_dir})
if [ $? -ne 0 ]; then
return 1
fi
fi
work_dir="${query_dir}"
while true; do
if [ -d "$work_dir/.repo/manifests" ]; then
echo $work_dir
return 0
fi
if [ "${work_dir}" == "/" ]; then
break
fi
work_dir="$(dirname "${work_dir}")"
done
echo_stderr "directory is not controlled by repo: ${query_dir}"
return 1
}
#
# Get the active manifest file of a repo managed repository
# repo_manifest [<dir_path>]
#
repo_manifest () {
local query_dir="${1:-${PWD}}"
local root_dir=""
local repo_manifest=""
root_dir="$(repo_root "${query_dir}")"
if [ $? -ne 0 ]; then
return 1
fi
repo_manifest="${root_dir}/.repo/manifest.xml"
# Depending on repo version, ${repo_manifest} is either a symlink to
# the real manifest, or a wrapper manifest that includes the real manifest
if [ -L "${repo_manifest}" ]; then
readlink -f "${repo_manifest}"
else
grep "<include " ${repo_manifest} | head -n 1 | sed "s#^.*name=\"\([^\"]*\)\".*#${root_dir}/.repo/manifests/\1#"
fi
}
#
# Get a list of repo remotes.
# repo_manifest
#
# Current directory must be withing the repo.
repo_remote_list () {
repo forall -c 'echo $REPO_REMOTE' | sort --unique
}
repo_is_remote () {
local query_remote=$1
local remote
for remote in $(repo_remote_list); do
if [ "$query_remote" == "$remote" ]; then
return 0
fi
done
return 1
}
#
# Get a list of repo projects.
# Optionally restrict the list to projects from listed remotes.
# repo_manifest [remote_1 remote_2 ...]
#
# Current directory must be withing the repo.
repo_project_list () {
local remote_list=( $@ )
if [ ${#remote_list[@]} -eq 0 ]; then
repo forall -c 'echo $REPO_PROJECT' | sort --unique
else
for remote in ${remote_list[@]}; do
repo forall -c \
'if [ "$REPO_REMOTE" == "'${remote}'" ]; then echo $REPO_PROJECT; fi' \
| sort --unique
done
fi
}
repo_is_project () {
local query_project=$1
local project
for project in $(repo_project_list); do
if [ "$query_project" == "$project" ]; then
return 0
fi
done
return 1
}
#
# manifest_set_revision <old_manifest> <new_manifest> <revision> <lock_down> <project-list>
#
# old_manifest = Path to original manifest.
# new_manifest = Path to modified manifest. It will not overwrite an
# existing file.
# revision = A branch, tag ,or sha. Branch and SHA can be used
# directly, but repo requires that a tag be in the form
# "refs/tags/<tag-name>".
# lock_down = 0 or 1. If 1, set a revision on all other non-listed
# projects to equal the SHA of the current git head.
# project-list = A space seperated list of projects. Listed projects
# will have their revision set to the provided revision
# value.
#
manifest_set_revision () {
local old_manifest="${1}"
local new_manifest="${2}"
local revision="${3}"
local lock_down="${4}"
shift 4
local projects="${@}"
local repo_root_dir=""
local line=""
local FOUND=0
local path=""
local project=""
local rev=""
repo_root_dir=$(repo_root)
if [ $? -ne 0 ]; then
echo_stderr "Current directory is not managed by repo."
return 1
fi
if [ ! -f "${old_manifest}" ]; then
echo_stderr "Old manifest file is missing '${old_manifest}'."
return 1
fi
if [ -f "${new_manifest}" ]; then
echo_stderr "New manifest file already present '${new_manifest}'."
return 1
fi
mkdir -p "$(dirname "${new_manifest}")"
if [ $? -ne 0 ]; then
echo_stderr "Failed to create directory '$(dirname "${new_manifest}")'"
return 1
fi
while IFS= read -r line; do
echo "${line}" | grep -q '<project'
if [ $? -ne 0 ]; then
# Line does not define a project, do not modify
echo "${line}"
continue
fi
# check if project name is selected
FOUND=0
for project in ${projects}; do
echo "${line}" | grep -q 'name="'${project}'"'
if [ $? -eq 0 ]; then
FOUND=1
break
fi
done
rev=${revision}
if [ $FOUND -eq 0 ]; then
# A non-selected project
if [ ${lock_down} -eq 0 ]; then
echo "${line}"
continue
fi
path="${repo_root_dir}/$(echo "${line}" | sed 's#.*path="\([^"]*\)".*#\1#')"
rev=$(cd "${path}"; git rev-parse HEAD)
fi
# Need to set revision on selected project
if echo "${line}" | grep -q 'revision='; then
echo "${line}" | sed "s#revision=\"[^\"]*\"#revision=\"${rev}\"#"
else
# No prior revision
# Set revision prior to name
echo "${line}" | sed "s#name=#revision=\"${rev}\" name=#"
fi
done < "${old_manifest}" > "${new_manifest}"
return 0
}