#!/bin/bash -e
# Copyright (c) 2018 Nicolas Mailhot <nim@fedoraproject.org>,
# Jan Chaloupka <jchaloup@redhat.com>
# This file is distributed under the terms of GNU GPL license version 3, or
# any later version.
usage() {
cat >&2 << EOF_USAGE
Usage: $0 <action> [ [-h] ]
[ [-i <go import path> ] ]
[ [-y] ] [ [-p <prefix>] [-g <go path>] ]
[ [-w] ] [ [-b <go build path>] ]
[ [-d <directory>] [-t <tree root>] [-r <regex>] ]
[ [-e <extension>] [-s <sourcedir>] [-o <file>] <file> ]
[ [-v <version>] ] [ [-a <attribute>] ]
<action> should be one of: install, check, provides, requires
Most actions accept the same set of arguments, and will silently ignore those
that do not apply to a specific action. Unless specified otherwise, all
arguments are optional.
“install”-specific arguments:
-i <go import path> is a mandatory argument
-e <extension> add files ending in <extension> to the default
installation set,
can be specified several times
-s <sourcedir> install files from the specified source directory, not
from the current directory
-o <file> output file lists to file,
default value if not set: devel.file-list
<file> add <file> to the default installation set,
can be specified several times
“check”-specific arguments:
-i <go import path> is a mandatory argument
-y check the files installed in the system Go path, not the
files in the current work directory,
this option is usually used with -p and -g,
-w check the files in the current work directory, not the
files installed in the system Go path,
this option is usually used with -b,
this is the default check mode if neither -y nor -w are
specified
“provides”-specific arguments:
-v <version string>: tag the provides with <version string>
-a <attribute>: an attribute to add to the provides, for example
-a "(commit=XXXX)"
-a "(branch=YYYY)"
-a "(tag=rx.y.z-alpha1)"
can be specified several times
Common arguments:
-i <go import path> a Go import path of the target package,
can be specified several times,
mandatory for: install and check,
ignored by: provides and requires
-h print this help
-p <prefix>: an optionnal prefix path such as %{buildroot}
-g <go path>: the root of the Go source tree
default value if not set: /usr/share/gocode
-b <go build path> sets the GO_BUILD_PATH work directory,
it will be created if not already existing,
default value if not set: \$PWD/_build
used by: install and check,
ignored by: provides and requires
-d <directory> a directory that should be ignored during processing,
relative to the import path root,
non recursive,
can be specified several times
-t <tree root> the root of a directory tree that should be ignored during
processing,
relative to the import path root,
recursive,
can be specified several times
-r <regex> a regex matching elements that should be ignored during
processing,
relative to the import path root,
can be specified several times
EOF_USAGE
exit 1
}
action=''
version=''
prefix=''
checkin="workdir"
sourcedir="${PWD}"
GO_BUILD_PATH="${GO_BUILD_BATH:-${PWD}/_build}"
gopath=/usr/share/gocode
filelist='devel.file-list'
goipathes=()
declare -A attributes
declare -A golistflags
if [[ $# -eq 0 ]] ; then
usage
else case $1 in
install|check|provides|requires) action=$1 ;;
*) usage ;;
esac
fi
shift
if ! options=$(getopt -n $0 -o hi:yp:g:wb:d:t:r:e:o:v:a: \
-l help,go-import-path: \
-l system-files,prefix:,go-path: \
-l workdir-files,go-build-path: \
-l ignore-directory: \
-l ignore-tree: \
-l ignore-regex: \
-l include-extension:,output: \
-l version:,attribute: \
-- "$@")
then
usage
fi
eval set -- "$options"
_last_goipath=''
while [ $# -gt 0 ] ; do
case $1 in
-h|--help) usage ;;
-i|--go-import-path) goipathes+=( "$2" ); _last_goipath="${2}" ; shift;;
-y|--system-files) checkin="system" ;;
-p|--prefix) prefix=$(realpath -sm "$2") ; shift;;
-g|--go-path) gopath="$2" ; shift;;
-w|--workdir-files) checkin="workdir" ;;
-b|--go-build-path) GO_BUILD_PATH="$2" ; shift;;
-d|--ignore-directory) dir="${_last_goipath}/$2"; golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -d ${dir%/.}" ; shift;;
-t|--ignore-tree) golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -t ${_last_goipath}/$2" ; shift;;
-r|--ignore-regex) golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -r $2" ; shift;;
-e|--include-extension) golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -e $2" ; shift;;
-s|--source-dir) sourcedir="$2" ; shift;;
-o|--output) filelist="$2" ; shift;;
-v|--version) version="$2" ; shift;;
-a|--attribute) IFS=')' read -r -a newattrs <<< "$2"
for index in "${!newattrs[@]}" ; do
newattrs[index]=${newattrs[index]#\(}
attributes[${newattrs[index]%%=*}]=${newattrs[index]#*=}
done ; shift;;
(--) shift; break ;;
(-*) usage ;;
(*) break ;;
esac
shift
done
installfile() {
goipath="${1}"
file="${2}"
file="${file#./}"
[[ -d "${file}" && ! -L "${file}" ]] && srcdir="${file}" || srcdir=$(dirname "${file}")
destdir="${prefix}${gopath}/src/${goipath}/${srcdir}"
destdir="${destdir%/.}"
dir="${destdir}"
dirs=()
while [[ ! -e "${dir}" ]] ; do
dirs=("$dir" "${dirs[@]}")
dir=$(dirname "${dir}")
done
for dir in "${dirs[@]}" ; do
install -m 0755 -vd "${dir}"
if $(echo "${dir}" | grep -q "^${prefix}${gopath}/src/${goipath}") ; then
touch -r ".${dir#${prefix}${gopath}/src/${goipath}}" "${dir}"
fi
echo "%dir \"${dir#${prefix}}\"" >> ${filelist}
done
if [[ -L "$file" ]] ; then
ln -s $(readlink "${file}") "${destdir}/$(basename ${file})"
touch -h -r "${file}" "${destdir}/$(basename ${file})"
fi
[[ -f "$file" && ! -L "$file" ]] && install -m 0644 -vp "${file}" "${destdir}/"
[[ -f "$file" || -L "$file" ]] && echo "\"${gopath}/src/${goipath}/${file}\"" >> "${filelist}" || :
}
listfiles() {
goipath="${1}"
for file in $(\
GOPATH="${GO_BUILD_PATH}" \
golist --to-install \
--package-path ${goipath} \
${golistflags[${goipath}]}
); do
# The import path root does not end in /
file="${file##${GO_BUILD_PATH}/src/${goipath}}"
echo "${file##/}"
done
}
checks() {
goipath="${1}"
for dir in $(\
GOPATH="${workroot}${GOPATH+:${GOPATH}}" \
golist --provided --tests \
--package-path ${goipath} \
${golistflags[$goipath]} \
) ; do
pushd "${workroot}/src/${dir}" >/dev/null
echo "Testing \"${workroot}/src/${dir}\""
(set -x ; GOPATH="${GO_BUILD_PATH}:${GOPATH:+${GOPATH}:}${gopath}" \
go test ${GO_TEST_FLAGS} \
-ldflags "${LDFLAGS:+${LDFLAGS} }-extldflags '${GO_TEST_EXT_LD_FLAGS}'")
popd >/dev/null
done
}
provides() {
goipath="${1}"
for prov in $(\
GOPATH="${prefix}${gopath}" \
golist --provided \
--package-path ${goipath} \
${golistflags[$goipath]} \
); do
for index in "${!deco[@]}" ; do
echo "golang($prov)${deco[index]}${version:+ = ${version}}"
done
done
}
requires() {
goipath="${1}"
for req in $(\
GOPATH="${prefix}${gopath}" \
golist --imported \
--package-path ${goipath} \
--skip-self \
${golistflags[$goipath]} \
); do
echo "golang($req)"
done
}
# Action-specific preparation
case $action in
install) [[ ${#goipathes[@]} -eq 0 ]] && exit 0
otherfiles=( $* )
install -m 0755 -vd "${prefix}${gopath}/src"
[[ ! -e .goipath ]] && touch .goipath
for goipath in ${goipathes[@]} ; do
if [[ ! -e "${GO_BUILD_PATH}/src/${goipath}" ]] ; then
install -m 0755 -vd "$(dirname ${GO_BUILD_PATH}/src/${goipath})"
ln -fs "${sourcedir}" "${GO_BUILD_PATH}/src/${goipath}"
fi
pushd "${GO_BUILD_PATH}/src/${goipath}" >/dev/null
[[ ! -e .goipath ]] && touch .goipath
golistfiles=$(listfiles "${goipath}")
for file in ${golistfiles[@]} ${otherfiles[@]} .goipath ; do
installfile "${goipath}" "${file}"
done
popd >/dev/null
done
sort -u -o "${filelist}" "${filelist}" ;;
check) [[ ${#goipathes[@]} -eq 0 ]] && exit 0
[[ ${checkin} == "system" ]] && workroot="${prefix}${gopath}" \
|| workroot="${GO_BUILD_PATH}"
for goipath in ${goipathes[@]} ; do
checks "${goipath}"
done ;;
provides) deco=( "" )
for key in "${!attributes[@]}"; do
[[ -n "${attributes[$key]}" ]] && deco+=( "($key=${attributes[$key]})" )
done
while read lockfile ; do
dir=$(dirname "${lockfile}")
provides "${dir#${prefix}${gopath}/src/}"
done ;;
requires) while read lockfile ; do
dir=$(dirname "${lockfile}")
requires "${dir#${prefix}${gopath}/src/}"
done ;;
esac