|
|
63f006a |
#!/bin/bash
|
|
|
63f006a |
|
|
|
63f006a |
usage() {
|
|
|
63f006a |
cat >&2 << EOF_USAGE
|
|
|
63f006a |
Usage: $0 -g <go import path> [-p <prefix>] [-G <go path>] [-v <version string>] [-a <attributes>]
|
|
|
63f006a |
<go import path> the Go import path of the target package
|
|
|
63f006a |
<prefix>: an eventual prefix path such as %{buildroot}
|
|
|
63f006a |
<go path>: the root of the Go source tree
|
|
|
63f006a |
<version string>: tag the provides with the <version string>
|
|
|
63f006a |
<attributes>: attributes to add to the provides, for example
|
|
|
63f006a |
(commit=XXXX)(branch=YYYY) or
|
|
|
63f006a |
(vermod=alpha1)
|
|
|
63f006a |
|
|
|
63f006a |
Example:
|
|
|
63f006a |
echo filename | $0 -g golang.org/x/net -G /usr/share/gocode -v 2.5-0.1
|
|
|
63f006a |
echo filename | $0 -g golang.org/x/net -a '(commit=XXXX)(branch=YYYY)'
|
|
|
63f006a |
echo filename | $0 -g golang.org/x/net -a '(vermod=alpha1)'
|
|
|
63f006a |
EOF_USAGE
|
|
|
63f006a |
exit 1
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
if ! options=$(getopt -n $0 -o hg:p:G:v:a: -l help,goipath:,prefix:,gopath:,version:,attr:,attribute:,attributes: -- "$@")
|
|
|
63f006a |
then
|
|
|
63f006a |
# something went wrong, getopt will put out an error message for us
|
|
|
63f006a |
exit 2
|
|
|
63f006a |
fi
|
|
|
63f006a |
|
|
|
63f006a |
eval set -- "$options"
|
|
|
63f006a |
|
|
|
63f006a |
# Convert paths within gopath to version-constrained provides
|
|
|
63f006a |
# Never call it before checking the path belongs to the package import path
|
|
|
63f006a |
provides() {
|
|
|
63f006a |
local ppath="$1"
|
|
|
63f006a |
# Check for a vendor root, when not processing a symlink
|
|
|
63f006a |
if ! ( [[ -L "${ppath}" ]] || ( notvendored "${ppath}" ) ) ; then
|
|
|
63f006a |
local vroot="$(realpath -sm "${ppath}")/"
|
|
|
63f006a |
vroot="${vroot%/vendor/*}/vendor"
|
|
|
63f006a |
if [[ "${vroot}" != "${ppath}" ]] ; then
|
|
|
63f006a |
# Check if a parent with files exists within the vendor root
|
|
|
63f006a |
local tip="${ppath}"
|
|
|
63f006a |
local vipath=/dev/null
|
|
|
63f006a |
until [[ "${tip}" == "${vroot}" || "${ppath}" == "${vipath}/"* ]] ; do
|
|
|
63f006a |
[[ -n $(find "$tip" -maxdepth 1 -type f) ]] && vipath="$tip"
|
|
|
63f006a |
tip=$(dirname "$tip")
|
|
|
63f006a |
done
|
|
|
63f006a |
# If we didn't find a parent with files other than the path itself, it is
|
|
|
63f006a |
# the vendored import path root!
|
|
|
63f006a |
if [[ "$vipath" == "$ppath" ]] ; then
|
|
|
63f006a |
echo "bundled(golang(${ppath##*/vendor/}))"
|
|
|
63f006a |
fi
|
|
|
63f006a |
fi
|
|
|
63f006a |
else
|
|
|
63f006a |
local package="${ppath#${root}/src/}"
|
|
|
63f006a |
for index in "${!deco[@]}" ; do
|
|
|
63f006a |
echo "golang(${package})${deco[index]}${version}"
|
|
|
63f006a |
done
|
|
|
63f006a |
fi
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
# Resolve a symlink target in presence of a build root
|
|
|
63f006a |
resolvelink() {
|
|
|
63f006a |
local lt=$(realpath -m "$1")
|
|
|
63f006a |
echo "${prefix}${lt#${prefix}}"
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
# Resolve a symlink to its ultimate target in presence of a build root
|
|
|
63f006a |
ultimateresolvelink() {
|
|
|
63f006a |
local lt="$1"
|
|
|
63f006a |
until [[ ! -L ${lt} ]] ; do
|
|
|
63f006a |
lt=$(resolvelink "${lt}")
|
|
|
63f006a |
done
|
|
|
63f006a |
echo "${lt}"
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
# Test if a path is a directory within the package import path.
|
|
|
63f006a |
isgoipathdir() {
|
|
|
63f006a |
local lt="$1"
|
|
|
63f006a |
if [[ -d ${lt} ]] && [[ "${lt}"/ == "${root}/src/${goipath}"/* ]] ; then
|
|
|
63f006a |
true
|
|
|
63f006a |
else
|
|
|
63f006a |
false
|
|
|
63f006a |
fi
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
# Test if a path is vendored
|
|
|
63f006a |
notvendored() {
|
|
|
63f006a |
local p=$(realpath -sm "$1")
|
|
|
63f006a |
local vr="${p}/"
|
|
|
63f006a |
vr="${vr%/vendor/*}"
|
|
|
63f006a |
if [[ "${vr}" != "${p}/" ]] ; then
|
|
|
63f006a |
false
|
|
|
63f006a |
else
|
|
|
63f006a |
true
|
|
|
63f006a |
fi
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
# A symlink can point to a whole directory tree, but go.attr will only
|
|
|
63f006a |
# trigger on the root symlink.
|
|
|
63f006a |
# Therefore, check the symlink points within the processed import path, then
|
|
|
63f006a |
# walk all the target tree to generate symlink provides
|
|
|
63f006a |
#
|
|
|
63f006a |
# To process nested symlinks the function needs to be provided a working path
|
|
|
63f006a |
# to the symlink tip within the build root as second argument.
|
|
|
63f006a |
processlink() {
|
|
|
63f006a |
local link="$1"
|
|
|
63f006a |
local linktarget=$(ultimateresolvelink "$2")
|
|
|
63f006a |
if ( isgoipathdir "${linktarget}" ) && ( notvendored "${linktarget}" ) ; then
|
|
|
63f006a |
find "${linktarget}" -type d -print | while read subdir ; do
|
|
|
63f006a |
provides "${link}${subdir#${linktarget}}"
|
|
|
63f006a |
done
|
|
|
63f006a |
find "${linktarget}" -type l -print | while read sublink ; do
|
|
|
63f006a |
processlink "${link}${sublink#${linktarget}}" "${sublink}"
|
|
|
63f006a |
done
|
|
|
63f006a |
fi
|
|
|
63f006a |
}
|
|
|
63f006a |
|
|
|
63f006a |
version=''
|
|
|
63f006a |
prefix=''
|
|
|
63f006a |
gopath=/usr/share/gocode
|
|
|
63f006a |
declare -A attributes
|
|
|
63f006a |
|
|
|
63f006a |
while [ $# -gt 0 ] ; do
|
|
|
63f006a |
case $1 in
|
|
|
63f006a |
-h|--help) usage ;;
|
|
|
63f006a |
-g|--goipath) goipath="$2" ; shift;;
|
|
|
63f006a |
-p|--prefix) prefix=$(realpath -sm "$2") ; shift;;
|
|
|
63f006a |
-G|--gopath) gopath="$2" ; shift;;
|
|
|
63f006a |
-v|--version) version=" = $2" ; shift;;
|
|
|
63f006a |
-a|--attr|--attribute|--attributes)
|
|
|
63f006a |
IFS=')' read -r -a newattrs <<< "$2"
|
|
|
63f006a |
for index in "${!newattrs[@]}" ; do
|
|
|
63f006a |
newattrs[index]=${newattrs[index]#\(}
|
|
|
63f006a |
attributes[${newattrs[index]%%=*}]=${newattrs[index]#*=}
|
|
|
63f006a |
done ; shift;;
|
|
|
63f006a |
(--) shift; break;;
|
|
|
63f006a |
(-*) echo "$0: error - unrecognized option $1" >&2; exit 3;;
|
|
|
63f006a |
(*) break;;
|
|
|
63f006a |
esac
|
|
|
63f006a |
shift
|
|
|
63f006a |
done
|
|
|
63f006a |
|
|
|
63f006a |
# Detection of the package import path root is necessary to insure we do not
|
|
|
63f006a |
# generate useless provides such as golang(github).
|
|
|
63f006a |
#
|
|
|
63f006a |
# When go dep stabilizes and can be generalized import path root detection may
|
|
|
63f006a |
# be automated by searching for the first level of go dep lock files.
|
|
|
63f006a |
#
|
|
|
63f006a |
# However the requirement to set %{goipath} may remain to make sure we avoid
|
|
|
63f006a |
# processing directories created without applying the sanity checks documented
|
|
|
63f006a |
# in Fedora Packaging Guidelines.
|
|
|
63f006a |
[[ -z ${goipath} ]] && exit 0
|
|
|
63f006a |
|
|
|
63f006a |
root="${prefix}${gopath}"
|
|
|
63f006a |
|
|
|
63f006a |
deco=( "" )
|
|
|
63f006a |
# Some filtering may be needed in the future
|
|
|
63f006a |
for key in "${!attributes[@]}"; do
|
|
|
63f006a |
[ -n "${attributes[$key]}" ] && deco+=( "($key=${attributes[$key]})" )
|
|
|
63f006a |
done
|
|
|
63f006a |
|
|
|
63f006a |
# go.attr ensures that every time a package declares owning a directory or
|
|
|
63f006a |
# symlink under %{gopath}/src, the directory or symlink name will be piped to
|
|
|
63f006a |
# this script to compute the package Go provides.
|
|
|
63f006a |
#
|
|
|
63f006a |
# For legacy reason the script is supposed to be able to handle multiple
|
|
|
63f006a |
# inputs, even though modern rpm invokes it separately for each directory.
|
|
|
63f006a |
#
|
|
|
63f006a |
# As native Go tooling is focused on leaf developer needs (“what I need from
|
|
|
63f006a |
# others to build my code”, not “what I provide to help others build their
|
|
|
63f006a |
# code”) Go auto-provides do not invoke any Go binary and just record all the
|
|
|
63f006a |
# directories created under the import path root. This is actually faster and
|
|
|
63f006a |
# more reliable, since Go project seem to import pretty much any import path
|
|
|
63f006a |
# subdirectory, even if it contains assets without any .go file.
|
|
|
63f006a |
while read dir ; do
|
|
|
63f006a |
if [[ -L $dir ]] ; then
|
|
|
63f006a |
processlink "$dir" "$dir"
|
|
|
63f006a |
else
|
|
|
63f006a |
# If go.attr triggered on a normal directory just make sure it is under the
|
|
|
63f006a |
# package import path, then provide it
|
|
|
63f006a |
if [[ -d $dir ]] ; then
|
|
|
63f006a |
dir=$(realpath -sm "$dir")
|
|
|
63f006a |
[[ "${dir}"/ == "${root}/src/${goipath}"/* ]] && provides "$dir"
|
|
|
63f006a |
fi
|
|
|
63f006a |
fi
|
|
|
63f006a |
done | sort | uniq | grep -v '/\([._]\)\?\(internal\|vendor\)\([/)]\)'
|