#!/bin/bash -e # Copyright (c) 2018 Nicolas Mailhot , # Jan Chaloupka # This file is distributed under the terms of GNU GPL license version 3, or # any later version. usage() { cat >&2 << EOF_USAGE Usage: $0 [ [-h] ] [ [-i ] ] [ [-y] ] [ [-p ] [-g ] ] [ [-w] ] [ [-b ] ] [ [-d ] [-t ] [-r ] ] [ [-e ] [-s ] [-o ] ] [ [-v ] ] [ [-a ] ] 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 is a mandatory argument -e add files ending in to the default installation set, can be specified several times -s install files from the specified source directory, not from the current directory -o output file lists to file, default value if not set: devel.file-list add to the default installation set, can be specified several times “check”-specific arguments: -i 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 : tag the provides with -a : 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 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 : an optionnal prefix path such as %{buildroot} -g : the root of the Go source tree default value if not set: /usr/share/gocode -b 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 a directory that should be ignored during processing, relative to the import path root, non recursive, can be specified several times -t 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 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