|
Packit |
fec9a0 |
#!/bin/bash
|
|
Packit |
fec9a0 |
# Copyright (c) 2018 Nicolas Mailhot <nim@fedoraproject.org>
|
|
Packit |
fec9a0 |
# This file is distributed under the terms of GNU GPL license version 3, or
|
|
Packit |
fec9a0 |
# any later version.
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
usage() {
|
|
Packit |
fec9a0 |
cat >&2 << EOF_USAGE
|
|
Packit |
fec9a0 |
Usage: $0 <action> [ [-h] ]
|
|
Packit |
fec9a0 |
[ [-p <prefix>] [-g <go path>] ]
|
|
Packit |
fec9a0 |
[ [-v <version>] ] [ [-a <attribute>] ]
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
<action> should be one of: provides, requires
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
Most actions accept the same set of arguments, and will silently ignore those
|
|
Packit |
fec9a0 |
that do not apply to a specific action. Unless specified otherwise, all
|
|
Packit |
fec9a0 |
arguments are optional.
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
“provides”-specific arguments:
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
-v <version string>: tag the provides with <version string>
|
|
Packit |
fec9a0 |
-a <attribute>: an attribute to add to the provides, for example
|
|
Packit |
fec9a0 |
-a "(commit=XXXX)"
|
|
Packit |
fec9a0 |
-a "(branch=YYYY)"
|
|
Packit |
fec9a0 |
-a "(tag=rx.y.z-alpha1)"
|
|
Packit |
fec9a0 |
can be specified several times
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
“requires”-specific arguments:
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
-v <version string>: tag symbolink link target requires with <version string>
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
Common arguments:
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
-h print this help
|
|
Packit |
fec9a0 |
-p <prefix>: an optionnal prefix path such as %{buildroot}
|
|
Packit |
fec9a0 |
-g <go path>: the root of the Go source tree
|
|
Packit |
fec9a0 |
default value if not set: /usr/share/gocode
|
|
Packit |
fec9a0 |
EOF_USAGE
|
|
Packit |
fec9a0 |
exit 1
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
action=''
|
|
Packit |
fec9a0 |
version=''
|
|
Packit |
fec9a0 |
prefix=''
|
|
Packit |
fec9a0 |
gopath=/usr/share/gocode
|
|
Packit |
fec9a0 |
declare -A attributes
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
if [[ $# -eq 0 ]] ; then
|
|
Packit |
fec9a0 |
usage
|
|
Packit |
fec9a0 |
else case $1 in
|
|
Packit |
fec9a0 |
provides|requires) action=$1 ;;
|
|
Packit |
fec9a0 |
*) usage ;;
|
|
Packit |
fec9a0 |
esac
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
shift
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
if ! options=$(getopt -n $0 -o hp:gv:a: \
|
|
Packit |
fec9a0 |
-l help,prefix:,go-path: \
|
|
Packit |
fec9a0 |
-l version:,attribute: \
|
|
Packit |
fec9a0 |
-- "$@")
|
|
Packit |
fec9a0 |
then
|
|
Packit |
fec9a0 |
usage
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
eval set -- "$options"
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
while [ $# -gt 0 ] ; do
|
|
Packit |
fec9a0 |
case $1 in
|
|
Packit |
fec9a0 |
-h|--help) usage ;;
|
|
Packit |
fec9a0 |
-p|--prefix) prefix=$(realpath -sm "$2") ; shift;;
|
|
Packit |
fec9a0 |
-g|--go-path) gopath="$2" ; shift;;
|
|
Packit |
fec9a0 |
-v|--version) version="$2" ; shift;;
|
|
Packit |
fec9a0 |
-a|--attribute) IFS=')' read -r -a newattrs <<< "$2"
|
|
Packit |
fec9a0 |
for index in "${!newattrs[@]}" ; do
|
|
Packit |
fec9a0 |
newattrs[index]=${newattrs[index]#\(}
|
|
Packit |
fec9a0 |
attributes[${newattrs[index]%%=*}]=${newattrs[index]#*=}
|
|
Packit |
fec9a0 |
done ; shift;;
|
|
Packit |
fec9a0 |
(--) shift; break;;
|
|
Packit |
fec9a0 |
(-*) usage ;;
|
|
Packit |
fec9a0 |
(*) break;;
|
|
Packit |
fec9a0 |
esac
|
|
Packit |
fec9a0 |
shift
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
deco=( "" )
|
|
Packit |
fec9a0 |
for key in "${!attributes[@]}"; do
|
|
Packit |
fec9a0 |
[ -n "${attributes[$key]}" ] && deco+=( "($key=${attributes[$key]})" )
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# Convert paths within gopath to version-constrained provides
|
|
Packit |
fec9a0 |
provides() {
|
|
Packit |
fec9a0 |
local package="${1#${prefix}${gopath}/src/}"
|
|
Packit |
fec9a0 |
for index in "${!deco[@]}" ; do
|
|
Packit |
fec9a0 |
echo "golang(${package})${deco[index]}${version:+ = ${version}}"
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# Convert paths within gopath to version-constrained requires
|
|
Packit |
fec9a0 |
requires() {
|
|
Packit |
fec9a0 |
local package="${1#${prefix}${gopath}/src/}"
|
|
Packit |
fec9a0 |
echo "golang(${package})${version:+ = ${version}}"
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# Resolve a symlink target in presence of a build root
|
|
Packit |
fec9a0 |
resolvelink() {
|
|
Packit |
fec9a0 |
local lt=$(realpath -m "$1")
|
|
Packit |
fec9a0 |
echo "${prefix}${lt#${prefix}}"
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# Resolve a symlink to its ultimate target in presence of a build root
|
|
Packit |
fec9a0 |
ultimateresolvelink() {
|
|
Packit |
fec9a0 |
local lt="$1"
|
|
Packit |
fec9a0 |
until [[ ! -L ${lt} ]] ; do
|
|
Packit |
fec9a0 |
lt=$(resolvelink "${lt}")
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
echo "${lt}"
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# Test if a path is a directory within the target gopath
|
|
Packit |
fec9a0 |
isgopathdir() {
|
|
Packit |
fec9a0 |
local lt="$1"
|
|
Packit |
fec9a0 |
if [[ -d ${lt} ]] && [[ "${lt}"/ == "${prefix}${gopath}"/src/* ]] ; then
|
|
Packit |
fec9a0 |
true
|
|
Packit |
fec9a0 |
else
|
|
Packit |
fec9a0 |
false
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# A symlink can point to a whole directory tree, but go.attr will only
|
|
Packit |
fec9a0 |
# trigger on the root symlink.
|
|
Packit |
fec9a0 |
# Therefore, check the symlink points within the processed import path, then
|
|
Packit |
fec9a0 |
# walk all the target tree to generate symlink provides/requires
|
|
Packit |
fec9a0 |
#
|
|
Packit |
fec9a0 |
# To process nested symlinks the function needs to be provided a working path
|
|
Packit |
fec9a0 |
# to the symlink tip within the build root as second argument.
|
|
Packit |
fec9a0 |
processlink() {
|
|
Packit |
fec9a0 |
local link="$1"
|
|
Packit |
fec9a0 |
local nexttarget=$(resolvelink "$2")
|
|
Packit |
fec9a0 |
local linktarget=$(ultimateresolvelink "${nexttarget}")
|
|
Packit |
fec9a0 |
if isgopathdir "${linktarget}" ; then
|
|
Packit |
fec9a0 |
case ${action} in
|
|
Packit |
fec9a0 |
provides) find "${linktarget}" -type d -print | while read subdir ; do
|
|
Packit |
fec9a0 |
provides "${link}${subdir#${linktarget}}"
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
find "${linktarget}" -type l -print | while read sublink ; do
|
|
Packit |
fec9a0 |
processlink "${link}${sublink#${linktarget}}" "${sublink}"
|
|
Packit |
fec9a0 |
done ;;
|
|
Packit |
fec9a0 |
requires) # Requires is not recursive — it relies on providers requiring their own needs
|
|
Packit |
fec9a0 |
find "${nexttarget}" -type d -print | while read subdir ; do
|
|
Packit |
fec9a0 |
requires "${subdir}"
|
|
Packit |
fec9a0 |
done
|
|
Packit |
fec9a0 |
find "${nexttarget}" -type l -print | while read sublink ; do
|
|
Packit |
fec9a0 |
if isgopathdir $(ultimateresolvelink "${sublink}") ; then
|
|
Packit |
fec9a0 |
# The owner of the link will declare the correct requires
|
|
Packit |
fec9a0 |
requires "${sublink}"
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
done ;;
|
|
Packit |
fec9a0 |
esac
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
}
|
|
Packit |
fec9a0 |
|
|
Packit |
fec9a0 |
# go.attr ensures that every time a package declares owning a symlink under
|
|
Packit |
fec9a0 |
# %{gopath}/src, symlink name will be piped to this script to compute the
|
|
Packit |
fec9a0 |
# package Go provides/requires.
|
|
Packit |
fec9a0 |
#
|
|
Packit |
fec9a0 |
# For legacy reason the script is supposed to be able to handle multiple
|
|
Packit |
fec9a0 |
# inputs, even though modern rpm invokes it separately for each directory.
|
|
Packit |
fec9a0 |
while read dir ; do
|
|
Packit |
fec9a0 |
if [[ -L $dir ]] ; then
|
|
Packit |
fec9a0 |
processlink "$dir" "$dir"
|
|
Packit |
fec9a0 |
fi
|
|
Packit |
fec9a0 |
done | sort -u | grep -v '/\([._]\)\?\(internal\|testdata\|vendor\)\([/)]\)'
|