From c1e2cfeaff5c94197e90d5d930423fdd3763c886 Mon Sep 17 00:00:00 2001 From: Nicolas Mailhot Date: Dec 02 2018 16:01:58 +0000 Subject: First try at automated buildrequires and gometa multicall --- diff --git a/bin/go-rpm-integration b/bin/go-rpm-integration index 81827aa..d691c13 100755 --- a/bin/go-rpm-integration +++ b/bin/go-rpm-integration @@ -26,10 +26,11 @@ arguments are optional. -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 +-s read expanded and prepared Go sources in /src + should be populated in %prep -o output file lists to file, default value if not set: devel.file-list +-O create file list in add to the default installation set, can be specified several times @@ -57,16 +58,13 @@ arguments are optional. 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 +-b read binaries already produced in used by: install and check, ignored by: provides and requires -d a directory that should be ignored during processing, @@ -86,18 +84,98 @@ EOF_USAGE exit 1 } +multigoipath() { +cat >&2 << EOF_MULTIGOIPATH +Error: Attempt to install to multiple Go import paths. Aborting… + +The installation target of “$0 install” is a unique Go import +path tree. Some of the presets rpm passes to this command in the %install stage +rely on this unicity. + +If you need to install files to different Go import path trees you MUST invoque +this command once per target. + +Even though the import path value was originally intended to be implicit in Go, +it usually leaks in multiple project files (documentation, unit tests, non-Go +files and so on). + +Therefore you SHOULD always: + — determine the canonical import path name of the project you want to install, + — change every self-reference in the project files, to this canonical name, + removing alternative leftovers (usually done, in the %prep stage of rpm) + — and only then deploy the result to the canonical import path using + “$0 install -i ” + +You MAY use symbolic links to maintain compatibility with codebases that refer +to this project via alternative, non canonical names (due to past renamings +or forkings). That will have the same effect as the HTTP redirects some +project upstreams are fond of. It WILL break the same way on the explicit +self-references that may exist in the files of this project. + +Therefore, you SHOULD preferably patch those codebases to use the project +canonical import path, like you did for this codebase in %prep. + +If you can not patch away references to an alternative import path name in some +third-party codebases, but wish to avoid import path naming problems, you +SHOULD: + — prepare, in %prep, a separate copy of the project files, with every self + reference changed to the alternative name + — and only then deploy, from this separate copy, to the alternative name + “$0 install -i \ + -s ” + +This later pattern is not recommended as it helps entrenching naming confusion. +EOF_MULTIGOIPATH +exit 1 +} + +alreadyexists() { +cat >&2 << EOF_ALREADYEXISTS +Error: Attempt to overwrite an existing installation. Aborting… + +“$0 install” aims at deploying clean Go source project files in +the %install stage of rpm. + +You SHOULD have prepared the project files in the rpm %prep stage and resolved +any file conflict before calling “$0 install”. That means a +specific Go import path is usually deployed in a single call. + +If you wish to deploy the same import path using multiple +“$0 install” calls you MUST make sure they use consistent +versionning and exclusion arguments. Those arguments are recorded on disk to +allow reliable provides computation in later rpm stages. + +If used outside rpm, you MUST ensure some other way no conflicting installation +already exists. “$0 install” has no way to remove cleanly such +an installation. Installing blindly over another deployment would leave in +place, all the files, not present in the new installation, resulting in an +unreliable mix. +EOF_ALREADYEXISTS +exit 1 +} + action='' -version='' prefix='' checkin="workdir" sourcedir="${PWD}" -GO_BUILD_PATH="${GO_BUILD_BATH:-${PWD}/_build}" +bindir="${GO_BUILD_DIR:-${PWD}/_build}" +goldflags='' gopath=/usr/share/gocode filelist='devel.file-list' -goipathes=() -_last_goipath='' -declare -A attributes -declare -A golistflags +filelistroot="${PWD}" +goipath='' +declare -A metadata +flags_d=() +flags_t=() +flags_r=() +flags_e=() +declare -A imetadata +iflags_d=() +iflags_t=() +iflags_r=() +iflags_e=() +vinstall=install +vln=ln if [[ $# -eq 0 ]] ; then usage @@ -109,17 +187,19 @@ fi shift -if ! options=$(getopt -n $0 -o hi:yp:g:wb:d:t:r:e:s:o:v:a: \ +if ! options=$(getopt -n $0 -o hi:yp:g:wb:d:t:r:e:s:o:O:l:V:T:C:B:vaz: \ -l help,go-import-path: \ -l system-files,prefix:,go-path: \ - -l workdir-files,go-build-path: \ + -l workdir-files,bindir: \ -l ignore-directory: \ -l ignore-tree: \ -l ignore-regex: \ - -l include-extension:,output: \ - -l version:,attribute: \ - -- "$@") -then + -l include-extension: \ + -l sourcedir: \ + -l output:,output-root \ + -l version:,tag:,commit:,branch: \ + -l verbose: \ + -- "$@") ; then usage fi @@ -127,27 +207,34 @@ eval set -- "$options" 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##${_last_goipath}/}" - golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -d ${_dir%/.}" ; shift;; - -t|--ignore-tree) _tree="${_last_goipath}/${2##${_last_goipath}/}" - golistflags[$_last_goipath]="${golistflags[$_last_goipath]} -t ${_tree}" ; 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;; + -h|--help) usage ;; + -i|--go-import-path) if [[ ("${goipath}" != "") && \ + ("${goipath}" != "${2}") ]] ; then + multigoipath + else + goipath="${2}" + fi ; 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|--bindir) bindir="${2}" ; shift;; + -d|--ignore-directory) iflags_d+=( "${2}" ) ; shift;; + -t|--ignore-tree) iflags_t+=( "${2}" ) ; shift;; + -r|--ignore-regex) iflags_r+=( "${2}" ) ; shift;; + -e|--include-extension) iflags_e+=( "${2}" ) ; shift;; + -s|--sourcedir ) sourcedir="${2}" ; shift;; + -o|--output) filelist="${2}" ; shift;; + -O|--output-root) filelistroot="${2}" ; shift;; + -l|--ldflags) ldflags="${2}" ; shift;; + -V|--version) imetadata["version"]="${2}" ; shift;; + -T|--tag) imetadata["tag"]="${2}" ; shift;; + -C|--commit) imetadata["commit"]="${2}" ; shift;; + -B|--branch) imetadata["branch"]="${2}" ; shift;; + -v|--verbose) vinstall="install -v" + vln="ln -v" ;; + -a) ;; # ignored, only used by the rpm macro side + -z) shift;; # ignored, only used by the rpm macro side (--) shift; break ;; (-*) usage ;; (*) break ;; @@ -155,6 +242,87 @@ while [ $# -gt 0 ] ; do shift done +dedupearray() { +local -n arrayref="${1}" +if [[ "${#arrayref[@]}" != "0" ]] ; then + local temparray=( "${arrayref[@]}" ) + arrayref=() + while read -r -d $'\0' l ; do + arrayref+=( "${l}" ) + done < <(printf "%s\0" "${temparray[@]}" | sort -z -u) +fi +} + +fixuserflags() { +if [[ -z "${goipath}" ]] ; then + echo "No import path was specified using -i, exiting" + exit 1 +fi +flags_d=( "${flags_d[@]##${goipath}/}" ) +flags_d=( "${flags_d[@]%/.}" ) +dedupearray flags_d +flags_t=( "${flags_t[@]##${goipath}/}" ) +flags_t=( "${flags_t[@]%/.}" ) +dedupearray flags_t +dedupearray flags_r +dedupearray flags_e +} + +expandflags() { +[[ "${#flags_d[@]}" != "0" ]] && printf -- ' -d %s' "${flags_d[@]}" +[[ "${#flags_t[@]}" != "0" ]] && printf -- ' -t %s' "${flags_t[@]}" +[[ "${#flags_r[@]}" != "0" ]] && printf -- ' -r %s' "${flags_r[@]}" +[[ "${#flags_e[@]}" != "0" ]] && printf -- ' -e %s' "${flags_e[@]}" +} + +popmetadata() { +unset metadata +declare -g -A metadata +for k in "${!imetadata[@]}"; do + metadata["${k}"]=${imetadata[${k}]} +done +flags_d=( "${iflags_d[@]}" ) +flags_t=( "${iflags_t[@]}" ) +flags_r=( "${iflags_r[@]}" ) +flags_e=( "${iflags_e[@]}" ) +} + +savemetadata() { +medadatafile="${1}" +rm -f "${medadatafile}" +touch "${medadatafile}" +for m in version tag commit branch ; do + if [[ -n "${metadata[${m}]}" ]] ; then + echo "${m}:${metadata[${m}]}" >> "${medadatafile}" + fi +done +[[ "${#flags_d[@]}" != "0" ]] && printf 'excludedir:%s\n' "${flags_d[@]}" >> "${medadatafile}" +[[ "${#flags_t[@]}" != "0" ]] && printf 'excludetree:%s\n' "${flags_t[@]}" >> "${medadatafile}" +[[ "${#flags_r[@]}" != "0" ]] && printf 'excluderegex:%s\n' "${flags_r[@]}" >> "${medadatafile}" +} + +readmetadata() { +medadatafile="${1}" +popmetadata +for m in version tag commit branch ; do + v=$(grep "^${m}\:" "${medadatafile}" | head -1) + v="${v#${m}:}" + [[ -n "${v}" ]] && metadata["${m}"]="${v}" +done +while read -r -d $'\n' l ; do + flags_d+=( "${l#excludedir:}" ) +done < <(grep "^excludedir:" "${medadatafile}") +dedupearray flags_d +while read -r -d $'\n' l ; do + flags_t+=( "${l#excludetree:}" ) +done < <(grep "^excludetree:" "${medadatafile}") +dedupearray flags_t +while read -r -d $'\n' l ; do + flags_r+=( "${l#excluderegex:}" ) +done < <(grep "^excluderegex:" "${medadatafile}") +dedupearray flags_r +} + installfile() { local goipath="${1}" local file="${2}" @@ -175,19 +343,27 @@ if [[ ! -d "${destdir}" ]] ; then installfile "${goipath}" "${destdir#${prefix}}" fi if [[ (! -e $file) || (-d "${file}" && ! -L "${file}") ]] ; then - install -m 0755 -vd "${dest}" + ${vinstall} -m 0755 -d "${dest}" if [[ -d "${file}" && ! -L "${file}" ]] ; then - find "${file}" -maxdepth 1 -iname '*.md' -type f | while read docfile ; do - installfile "${goipath}" "${docfile}" - done + find "${file}" -maxdepth 1 -iname '*.md' -type f -print0 | \ + while read -r -d $'\0' docfile ; do + installfile "${goipath}" "${docfile}" + done fi local fllprefix="%dir" else if [[ -L "${file}" ]] ; then - ln -vs $(readlink "${file}") "${dest}" - touch -h -r "${file}" "${dest}" + ${vln} -s $(readlink "${file}") "${dest}" + touch -h -r "${file}" "${dest}" else - install -m 0644 -vp "${file}" "${dest}" + if [[ -e "${dest}" ]] ; then + checksum=$(sha256sum "${file}") + checksum="${checksum%% *}" + destchecksum=$(sha256sum "${dest}") + destchecksum="${destchecksum%% *}" + [[ "${checksum}" != "${destchecksum=}" ]] && alreadyexists + fi + ${vinstall} -m 0644 -p "${file}" "${dest}" fi [[ "${file}" == *.md ]] && local fllprefix="%doc" fi @@ -195,119 +371,96 @@ echo "${fllprefix:+${fllprefix} }\"${dest#${prefix}}\"" >> "${filelist}" } listfiles() { -goipath="${1}" -echo $(GOPATH="${GO_BUILD_PATH}" golist --to-install \ - --package-path ${goipath} \ - ${golistflags[${goipath}]}) +local goipath="${1}" +GOPATH="${sourcedir}" \ + golist --to-install --package-path ${goipath} $(expandflags) } 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 +local goipath="${1}" +GOPATH="${workroot}${GOPATH+:${GOPATH}}" \ + golist --provided --tests --package-path ${goipath} $(expandflags) |\ + while read -r -d $'\n' dir ; do + pushd "${workroot}/src/${dir}" >/dev/null + echo "${dir}" + GOPATH="${workroot}${GOPATH:+:${GOPATH}}:${gopath}" \ + PATH="${workbin:+${workbin}:}${PATH}" \ + go test ${GO_TEST_FLAGS} -ldflags "${LDFLAGS:+${LDFLAGS} }-extldflags '${GO_TEST_EXT_LD_FLAGS}'" + popd >/dev/null + done } -fullprovides(){ - namespace=${1} - prov=${2} - for index in "${!deco[@]}" ; do - echo "${namespace}(${prov})${deco[index]}${version:+ = ${version}}" - done +fullprovides() { +local fp="${1}(${2})" +echo "${fp}${metadata[version]:+ = ${metadata[version]}}" +for m in "${!metadata[@]}" ; do + if [[ "${m}" != "version" ]] ; then + echo "${fp}(${m}=${metadata[${m}]})${metadata[version]:+ = ${metadata[version]}}" + fi +done } provides() { -goipath="${1}" -lockfile="${2}" +local goipath="${1}" fullprovides golang-ipath "${goipath}" -for prov in $(\ - GOPATH="${prefix}${gopath}" \ - golist --provided \ - --package-path ${goipath} \ - $(cat "${lockfile}") \ - ${golistflags[$goipath]} \ - ); do - fullprovides golang "${prov}" -done +GOPATH="${prefix}${gopath}" \ + golist --provided --package-path "${goipath}" $(expandflags) |\ + while read -r -d $'\n' prov ; do + fullprovides golang "${prov}" + done } requires() { -goipath="${1}" -lockfile="${2}" -for req in $(\ - GOPATH="${prefix}${gopath}" \ - golist --imported \ - --package-path ${goipath} \ - --skip-self \ - $(cat "${lockfile}") \ - ${golistflags[$goipath]} \ - ); do - echo "golang($req)" -done +local goipath="${1}" +GOPATH="${prefix}${gopath}" \ + golist --imported --package-path "${goipath}" $(expandflags) --skip-self |\ + while read -r -d $'\n' req ; do + echo "golang($req)" + done } # Action-specific preparation case $action in - install) [[ ${#goipathes[@]} -eq 0 ]] && exit 0 + install) popmetadata + fixuserflags otherfiles=( $* ) - filelist="${PWD}/${filelist}" - install -m 0755 -vd "${prefix}${gopath}/src" - for goipath in ${goipathes[@]} ; do - echo "Installing: ${goipath}" - fakepath="${GO_BUILD_PATH}/src/${goipath}" - fakeroot=$(dirname ${fakepath}) - if [[ ! -d ${fakeroot} ]] ; then - install -m 0755 -vd "${fakeroot}" - else - symdir="${fakeroot}" - until [[ -h "${symdir}" || \ - "${symdir}" == "${GO_BUILD_PATH}/src" ]] ; do - symdir=$(dirname ${symdir}) - done - # The root exists but none of the parents is a symlink - # → someone goinstalled a Go subpackage before - # → the conflicting path can be removed without affecting - # project sources - [[ "${symdir}" == "${GO_BUILD_PATH}/src" ]] && rm -fr "${fakepath}" - fi - [[ ! -d ${fakepath} ]] && ln -fs "${sourcedir}" "${fakepath}" - pushd "${GO_BUILD_PATH}/src/${goipath}" >/dev/null - echo "${golistflags[$goipath]}" > .goflags - touch -r "${sourcedir}" .goipath .goflags - for file in .goipath .goflags \ - $(listfiles "${goipath}") ${otherfiles[@]} ; do - installfile "${goipath}" "${file}" - done - popd >/dev/null - done + filelist="${filelistroot}/${filelist}" + ${vinstall} -m 0755 -d "${prefix}${gopath}/src" + echo "Installing: ${goipath}" + pushd "${sourcedir}/src/${goipath}" >/dev/null + savemetadata .goipath + touch -r "${sourcedir}" .goipath + for file in $(listfiles "${goipath}") .goipath ${otherfiles[@]} ; do + installfile "${goipath}" "${file}" + done + rm .goipath + popd >/dev/null 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 - echo "Testing: ${goipath}" - checks "${goipath}" - done ;; - provides) deco=( "" ) - for key in "${!attributes[@]}"; do - [[ -n "${attributes[$key]}" ]] && deco+=( "($key=${attributes[$key]})" ) - done - while read lockfile ; do + check) popmetadata + fixuserflags + if [[ ${checkin} == "system" ]] ; then + workroot="${prefix}${gopath}" + unset workbin + else + workroot="${sourcedir}" + workbin="${bindir}" + fi + echo "Testing in: ${workroot}/src" + echo " PATH: ${workbin:+${workbin}:}${PATH}" + echo " GOPATH: ${workroot}${GOPATH:+:${GOPATH}}:${gopath}" + echo " command: go test ${GO_TEST_FLAGS} -ldflags \"${LDFLAGS:+${LDFLAGS} }-extldflags '${GO_TEST_EXT_LD_FLAGS}'\"" + echo " testing: ${goipath}" + checks "${goipath}" ;; + provides) while read lockfile ; do dir=$(dirname "${lockfile}") - provides "${dir#${prefix}${gopath}/src/}" "${lockfile%%\.goipath}.goflags" + goipath="${dir#${prefix}${gopath}/src/}" + readmetadata "${lockfile}" + provides "${goipath}" done ;; requires) while read lockfile ; do dir=$(dirname "${lockfile}") - requires "${dir#${prefix}${gopath}/src/}" "${lockfile%%\.goipath}.goflags" + goipath="${dir#${prefix}${gopath}/src/}" + readmetadata "${lockfile}" + requires "${goipath}" done ;; esac diff --git a/rpm/fileattrs/go.attr b/rpm/fileattrs/go.attr index 0901c4f..0560171 100644 --- a/rpm/fileattrs/go.attr +++ b/rpm/fileattrs/go.attr @@ -1,4 +1,4 @@ %__go_path ^%{gopath}/src/.+/.goipath$ %__go_flags path -%__go_provides go-rpm-integration provides %{?goipath:-i "%{goipath}"} --prefix "%{buildroot}" --go-path "%{gopath}" --version "%{?epoch:%{epoch}:}%{version}-%{release}" %{?commit:-a "(commit=%{commit})"} %{?branch:-a "(branch=%{branch})"} %{?tag:-a "(tag=%{tag})"} %{?goprovflags} -%__go_requires go-rpm-integration requires %{?goipath:-i "%{goipath}"} --prefix "%{buildroot}" --go-path "%{gopath}" %{?goreqflags} +%__go_provides go-rpm-integration provides --prefix "%{buildroot}" --go-path "%{gopath}" %{?goprovflags} +%__go_requires go-rpm-integration requires --prefix "%{buildroot}" --go-path "%{gopath}" %{?goreqflags} diff --git a/rpm/macros.d/macros.go-compilers-gcc b/rpm/macros.d/macros.go-compilers-gcc index 9aa5e7a..656803b 100644 --- a/rpm/macros.d/macros.go-compilers-gcc +++ b/rpm/macros.d/macros.go-compilers-gcc @@ -9,8 +9,11 @@ %gccgo_min_vers 5.0.0 # Define commands for building -%gobuild(o:) go build -compiler gccgo -gccgoflags "$RPM_OPT_FLAGS ${LDFLAGS:-} %__global_ldflags %{?__golang_extldflags}" -a -v -x %{?**}; +%gobuild(o:) %{expand: +%{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} \\ +go build -compiler gccgo -gccgoflags "$RPM_OPT_FLAGS ${LDFLAGS:-}%{?currentgoldflags} %__global_ldflags %{?__golang_extldflags}" -a -v -x %{?**}; +} # Define commands for testing -%gotestflags -compiler gccgo -gccgoflags "$RPM_OPT_FLAGS ${LDFLAGS:-} %__global_ldflags %{?__golang_extldflags}" +%gotestflags -compiler gccgo -gccgoflags "$RPM_OPT_FLAGS ${LDFLAGS:-}%{?currentgoldflags} %__global_ldflags %{?__golang_extldflags}" %gotest() go test %{gotestflags} %{?**}; diff --git a/rpm/macros.d/macros.go-compilers-golang b/rpm/macros.d/macros.go-compilers-golang index e4a856a..4edb1e5 100644 --- a/rpm/macros.d/macros.go-compilers-golang +++ b/rpm/macros.d/macros.go-compilers-golang @@ -11,13 +11,16 @@ # https://bugzilla.redhat.com/show_bug.cgi?id=995136#c12 %global _dwz_low_mem_die_limit 0 %ifnarch ppc64 - go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; + %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} \\ + go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; %else - go build -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; + %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} \\ + go build -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; %endif } +${workroot}${GOPATH:+:${GOPATH}} # Define commands for testing %gotestflags -buildmode pie -compiler gc %gotestextldflags %__global_ldflags %{?__golang_extldflags} -%gotest() go test %{gotestflags} -ldflags "${LDFLAGS:-} -extldflags '%{gotestextldflags}'" %{?**}; +%gotest() go test %{gotestflags} -ldflags "${LDFLAGS:-}%{?currentgoldflags} -extldflags '%{gotestextldflags}'" %{?**}; diff --git a/rpm/macros.d/macros.go-rpm b/rpm/macros.d/macros.go-rpm index c3dd87a..643db21 100644 --- a/rpm/macros.d/macros.go-rpm +++ b/rpm/macros.d/macros.go-rpm @@ -3,22 +3,22 @@ # This file is distributed under the terms of GNU GPL license version 3, or # any later version. # -# This file contains macros needed at %%build %%install and %%check +# This file contains macros needed at %build %install and %check # stage by Golang packages. -# The macros necessary at %%setup and srpm stage are in the sister file +# The macros necessary at %setup and srpm stage are in the sister file # macros.go-srpm # Default filtering policy # Complete or replace the following variables in your spec file if this policy # does not apply to your project - -# Flags to filter examples +# +# Specific example matching rule. # The average Go project example code is incomplete and obsolete. It will # fail to compile as-is, or even panic. It will poison the dependency # generator with bogus or legacy import path requirements. Even when it it # clean and up to date, it will require many third party components not needed # in production. Therefore: -# – never install Go project example code in %%{gopath}. Publish is as %%doc. +# – never install Go project example code in %{gopath}. Publish is as %doc. # — ask politely projects that publish example code in some other directory # than _examples to rename it. # – never rely on third party examples being available or working in another @@ -29,11 +29,11 @@ # Default flags to apply in all stages %godefaultflags %{goignoreflags_examples} -# Default flags to apply in Go install (%%goinstall) +# Default flags to apply in Go install (%goinstall) %goinstallflags %{godefaultflags} -# Default flags to apply in Go checks (%%gochecks) -%gochecksflags %{godefaultflags} +# Default flags to apply in Go checks (%gochecks) +%gocheckflags %{godefaultflags} # Default flags to apply in Go autoprovides %goprovflags %{godefaultflags} @@ -41,131 +41,315 @@ # Default flags to apply in Go autorequires %goreqflags %{godefaultflags} -# Create a local Go build root -# -# The -i allows working on another import path than the -# default %%{goipath} (can not be repeated). -# -# The -s argument allows building from another location than the -# current directory. -# -# The -b argument allows specifying the script build directory (by -# default "$PWD/_build"). -%gobuildroot(i:b:s:) %{expand: - %{?-i*:goipath="%{-i*}"} - %{?-b*:GO_BUILD_PATH="%{-b*}"} - %{?-s*:sourcedir="%{-s*}"} - goipath="${goipath:-%{goipath}}" - GO_BUILD_PATH="${GO_BUILD_PATH:-${PWD}/_build}" - %global gobuildpath "$GO_BUILD_PATH" - if [[ ! -e "%{gobuildpath}/src/${goipath}" ]] ; then - install -m 0755 -vd "$(dirname %{gobuildpath}/src/${goipath})" - ln -fs "${sourcedir:-$PWD}" "%{gobuildpath}/src/${goipath}" - fi - cd "%{gobuildpath}/src/${goipath}" - install -m 0755 -vd _bin - export PATH="${PWD}/_bin${PATH:+:${PATH}}" - export GOPATH="%{gobuildpath}:%{gopath}" - export LDFLAGS="${LDFLAGS:-}%{?commit: -X ${goipath}/version.commit=%{commit}}%{?tag: -X ${goipath}/version.tag=%{tag}}%{?version: -X ${goipath}/version=%{version}}" +# The default filelist name generated by %goinstall +%gofilelist devel.file-list + +# Sets environment variables suitable for a Go source archive. Optional arguments: +# -z read the zth block of definitions, for example +# %{goipath}, %{commit}… +# derived from the import path value if not specified +# -i use the specified import path value instead of the one +# found in %{goipath} +# -v be verbose +# -V Should only be specified when creating subpackages with +# distinct versions +# default: %{version}.%{release} +# -T default: %{tag} +# -C default: %{commit} +# -B default: %{branch} +%goenv(z:i:vV:T:C:B:) %{lua: +local rpmmacros = require "rpmmacros" +local verbose = (rpm.expand("%{-v}") ~= "") +local suffix = rpm.expand("%{?-z*}") +local ismain = (suffix == "") or (suffix == "0") +local goipath = rpm.expand("%{?-i*}") +if (goipath ~= "") and (suffix == "") then + local bettersuffix = rpmmacros.getbestsuffix("goipath",goipath) + if (bettersuffix ~= nil) then + suffix = bettersuffix + end +end +if (goipath == "") then + goipath = "%{goipath" .. suffix .. "}" +end +suffixes=rpmmacros.getsuffixes("goipath") +rpmmacros.safeset( "goworkdir", "%{_builddir}/%{extractdir" .. suffixes[#suffixes] .. "}", verbose) +rpmmacros.safeset( "gobuilddir", "%{goworkdir}/_build", verbose) +if ismain then + rpmmacros.zalias({"gosourcedir","gofilelist"}, verbose) +else + rpmmacros.safeset("gofilelist" .. suffix, rpm.expand("%gorpmname %{goipath" .. suffix .. "}") .. "-%{gofilelist}", verbose) +end +rpmmacros.safeset( "gosourcedir" .. suffix, "%{?extractdir" .. suffix .. ":%{_builddir}/%{extractdir" .. suffix .. "}}" .. + "%{!?extractdir" .. suffix .. ":%{goworkdir}}", verbose) +if ismain then + rpmmacros.zalias({"gosourcedir"}, verbose) +end +local ldflags = "" +local metadata = { + version = { flag = "V", id = "version" }, + tag = { flag = "T", }, + commit = { flag = "C", }, + branch = { flag = "B", }, +} +table.sort(metadata) +for m,_ in pairs(metadata) do + metadata[m]["id"] = metadata[m]["id"] or "version." .. m + metadata[m]["value"] = rpm.expand("%{?-" .. metadata[m]["flag"] .. "*}" .. + "%{!-" .. metadata[m]["flag"] .. ":" .. + "%{?" .. m .. suffix .. "}}") + if (m == "version") and (metadata["version"]["value"] == "0") then + metadata["version"]["value"] = '' + end + if (metadata[m]["value"] ~= '') then + ldflags = ldflags .. " -X " .. goipath .. "/" .. metadata[m]["id"] .. "=" .. metadata[m]["value"] + end +end +for _, v in ipairs({"goipath","gosourcedir","gofilelist","version","tag","commit","branch"}) do + if (rpm.expand("%{?" .. v .. suffix .. "}") ~= "") then + rpmmacros.explicitset( "current" .. v, "%{" .. v .. suffix .. "}", verbose) + else + rpmmacros.explicitunset("current" .. v, verbose) + end +end +rpmmacros.explicitset( "currentgoldflags", ldflags, verbose) } -# The default filelist name generated by %%goinstall -%gofilelist devel.file-list +# Create default Go directories. Arguments: +# -z read the zth block of definitions, for example +# %{goipath}, %{commit}… +# derived from the import path value if not specified +# -i use the specified import path value instead of the one +# found in %{goipath} +# can not be repeated +# -b use as build directory +# binaries will be produced in /bin +# expanded Go sources will be symlinked in /src +# -s symlink expanded Go sources from +# default: %{_builddir}/%{?extractdir} +# -k keep the vendor directory, do not delete it +# -v be verbose +%gomkdir(z:i:b:s:kv) %{expand: +%goenv %{?-z} %{?-i} %{?-v} +%define mybuilddir %{?-b*}%{!-b:%{gobuilddir}} +%define mygoipath %{?-i*}%{!-i:%{currentgoipath}} +%define mysourcedir %{?-s*}%{!-s:%{currentgosourcedir}} +%{!?-k:rm -fr "%{mysourcedir}/vendor"} +if [[ ! -e "%{mybuilddir}/bin" ]] ; then + install -m 0755 -vd "%{mybuilddir}/bin" + export GOPATH="%{mybuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}" +fi +if [[ ! -e "%{mybuilddir}/src/%{mygoipath}" ]] ; then + install -m 0755 -vd "$(dirname %{mybuilddir}/src/%{mygoipath})" + ln -fs "%{mysourcedir}" "%{mybuilddir}/src/%{mygoipath}" +fi +cd "%{mybuilddir}/src/%{mygoipath}" +} + +# Computes BuildRequires for a given import path. Optional argument: +# -i use the specified import path value +%gobuildrequires(i:) %{expand: ( +golist --imported --package-path %{?-i*}%{!-i:%{currentgoipath}} --skip-self +golist --imported --package-path %{?-i*}%{!-i:%{currentgoipath}} --skip-self --tests) | sort -u | xargs -I{} echo "golang({})" +} + +# Perform usual Go source preparation steps. Optional arguments: +# -z read the zth block of definitions, for example +# %{goipath}, %{commit}… +# derived from the import path value if not specified +# -a process all sources in one go, instead of using separate +# -z calls +# -i use the specified import path value instead of the one +# found in %{goipath} +# -b use as build directory +# binaries will be produced in /bin +# expanded Go sources will be symlinked in /src +# -s symlink expanded Go sources from +# default: %{_builddir}/%{?extractdir} +# -k keep the vendor directory, do not delete it +# -e use extracted archives, do not perform %setup-like +# operations +# -r resolve BuildRequires, but do not install them +# -v be verbose +%goprep(z:ai:b:s:kerv) %{lua: +local extract = (rpm.expand("%{-e}") == "") +local installdeps = (rpm.expand("%{-r}") == "") +local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") +local setupflags = rpm.expand("%{!-v:-q}") +local gomkdirflags = rpm.expand("%{?-i} %{?-b} %{?-s} %{-k} %{-v}") +local rpmmacros = require "rpmmacros" +local buildrequires = {} +local function process(suffix) + local zsuffix = "" + if (suffix ~= "") and (suffix ~= nil) then + zsuffix = "-z " .. suffix .. " " + end + if extract then + print(rpm.expand("%setup " .. setupflags .. " %{?forgesetupargs" .. suffix .. "}\\n")) + end + print( rpm.expand("%gomkdir " .. zsuffix .. gomkdirflags .. "\\n")) + print('GOBUILDREQUIRES=$((sort -u |grep -v "^$" || :) <<< "$(' .. rpm.expand("%gobuildrequires") .. ')\\n${GOBUILDREQUIRES}")\\n') +end +-- Main loop +if processall then + for _,s in pairs(rpmmacros.getsuffixes("goipath")) do + process(s) + end +else + process(rpm.expand("%{?-z*}")) +end +if installdeps then + print('[[ -n "${GOBUILDREQUIRES}" ]] && mock-install ${GOBUILDREQUIRES}\\n') + print('unset GOBUILDREQUIRES\\n') +end +} # Try to install Go package files in sensible locations, with strict directory # ownership and lockfile creation as required by Go autodeps. # -# %%goinstall will install files found in the current directory to the default -# spec import path (%%goipath}) or, if passed one or several -i -# arguments, will install to the specified import pathes. -# -# The -s argument allows installing from another location than the -# current directory. -# -# The -b argument allows specifying the script build directory (by -# default "$PWD/_build"). +# Simple arguments, that can not be repeated: +# -z read the zth block of definitions, for example +# %{goipath}, %{commit}… +# derived from the import path value if not specified +# -a process all sources in one go, instead of using separate +# -z calls +# -i use the specified import path value +# default: %{goipath} +# -b read binaries already produced in +# default: %{gobuilddir}/bin +# -s read expanded and prepared Go sources in /src +# should be populated in %prep +# default: %{gobuilddir} +# -o output installed file list in +# default: %{gofilelist} +# -O output in +# -l add those flags to LDFLAGS when building unit tests +# -v be verbose # -# %%goinstall will identify by itself Go language native files and directories -# that need installing. In case a project uses other kind of files, you can ask -# to install the corresponding file extensions using the -e flag one or several -# times. +# Inclusion arguments, that can be repeated: +# -e include files with the provided extension # -# Alternatively, you can pass directly the corresponding files as argument to -# %%goinstall. +# Exclusion arguments, that can be repeated, relative to the go import path root: +# -d exclude the files contained in +# not recursive (subdirectories are not excluded) +# -t exclude the files contained in +# recursive (subdirectories are excluded) +# -r exclude files matching , # -# %%goinstall accepts the following arguments to exclude elements from -# processing: -# -d a directory, relative to the import path root -# not recursive (subdirectories are not excluded) -# -t a subtree root, relative to the import path root -# recursive (subdirectories are excluded) -# -r a regexp, relative to the import path root -# -# %%goinstall will generate a file list that can be used in a %%files spec -# section. The default file list name matches the %%{goname} of the installed -# import path: %%{goname}-devel.file-list. You can override this using the -o -# argument with another filename (strongly recommended when processing multiple -# import pathes). -# -# When invoked several times with the same import pathit will append to -# existing file lists not create a new one. +# Optional versionning metadata, that can not be repeated: +# -V Should only be specified when creating subpackages with +# distinct versions +# default: %{version}.%{release} +# -T default: %{tag} +# -C default: %{commit} +# -B default: %{branch} # +# When invoked several times with the same import path goinstall will append to +# the existing file list if versionning and exclusion arguments are identical to +# previous calls, and error out otherwise. # When invoked several times with different file list names, it will attribute -# directories to the first file list that makes use of them only. -%goinstall(i:p:g:b:d:t:r:e:s:o:) %{expand:%{lua: -local maingoipath = rpm.expand("%{goipath}") -local othergoipath = rpm.expand("%{?-i*}") -local output = rpm.expand("%{?-o*}") -local sourcedir = rpm.expand("%{?-s*}") -local buildpath = rpm.expand("%{?-b*}") -local outputprefix = "" -if (sourcedir == "") then sourcedir = "${PWD}" end -if (buildpath == "") then buildpath = "${PWD}/_build" end -if (othergoipath ~= "") then - outputprefix = rpm.expand("%gorpmname " .. othergoipath) .. "-" - local i - local subdir - subdir, i = string.gsub(othergoipath, "^" .. maingoipath, "") - if (i == 1) then sourcedir = sourcedir .. subdir end +# directories to the first file list that makes use of them. +%goinstall(z:ai:b:s:o:O:ve:d:t:rV:T:C:B:p:g:) %{lua: +local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") +local rpmmacros = require "rpmmacros" +-- Main function +local function process(suffix) + local zsuffix = "" + if (suffix ~= "") and (suffix ~= nil) then + zsuffix = "-z " .. suffix .. " " + end + print(rpm.expand('%goenv ' .. zsuffix .. '%{?-i} %{?-v} %{?-V} %{?-T} %{?-C} %{?-B}\\n' .. + 'go-rpm-integration install %{!-i:-i "%{currentgoipath}" }' .. + '%{!-b:-b "%{gobuilddir}/bin" }' .. + '%{!-s:-s "%{gobuilddir}" }' .. + '%{!-o:-o "%{currentgofilelist}" }' .. + '%{!-O:-O "%{goworkdir}" }' .. + '%{!-V:-V "%{version}-%{release}" }' .. + '%{!-T:%{?currenttag: -T "%{?currenttag}" }}' .. + '%{!-C:%{?currentcommit: -C "%{?currentcommit}" }}' .. + '%{!-B:%{?currentbranch: -B "%{?currentbranch}" }}' .. + '%{!-p:-p "%{buildroot}" }' .. + '%{!-g:-g "%{gopath}" }' .. + '%{?goinstallflags} %{?**} \\n')) +end +-- Main loop +if processall then + for _,s in pairs(rpmmacros.getsuffixes("goipath")) do + process(s) + end +else + process(rpm.expand("%{-z*}")) end -if (othergoipath == "") then othergoipath = maingoipath end -if (output == "") then output = outputprefix .. rpm.expand("%{gofilelist}") end -local command = 'go-rpm-integration install' -command = command .. ' -i ' .. othergoipath -command = command .. ' %{?**}' -command = command .. ' -s ' .. sourcedir -command = command .. ' -b ' .. buildpath -command = command .. ' -o ' .. output -command = command .. ' %{!?-p*:-p %{buildroot}} %{!?-g*:-g %{gopath}}' -command = command .. ' %{?goinstallflags}' -print(command)}} +} # Run go test %{gotestflags} on all subdirectories except for those filtered out # THIS MACRO IS OPT-OUT. # -# %%gotest will process the default spec import path (%%goipath}) or, if passed -# one or several -i arguments, will process the specified import -# pathes. -# -# It targets by default files found in "$PWD/_build/src/%{goipath}". This -# directory will have been created during %build or %install if you used the -# other macros with their default flags. Use -b to override. -# -# Alternatively, use the -s switch to process files the package installed in -# %{gopath} (not recommended, as that requires deploying to other packages many -# test and testdata files with complex dependencies and uneven quality). -# -# It accepts the following arguments to exclude elements from -# processing: -# -d a directory, relative to the import path root -# not recursive (subdirectories are not excluded) -# -t a subtree root, relative to the import path root -# recursive (subdirectories are excluded) -# -r a regexp, relative to the import path root -%gochecks(i:sp:g:wb:d:t:r:) %{expand: -PATH="${PWD}/_bin${PATH:+:${PATH}}" \\ -%{?gotestflags:GO_TEST_FLAGS="%{gotestflags}"} \\ -%{?gotestextldflags:GO_TEST_EXT_LD_FLAGS="%{gotestextldflags}"} \\ -go-rpm-integration check %{!?-i*:-i %{goipath}} %{!?-p*:-p %{buildroot}} \\ - %{!?-g*:-g %{gopath}} %{!?-b*:-b "$PWD/_build"} %{?**} %{?gochecksflags} +# Simple arguments, that can not be repeated: +# -z read the zth block of definitions, for example +# %{goipath}, %{commit}… +# derived from the import path value if not specified +# -a process all sources in one go, instead of using separate +# -z calls +# -i use the specified import path value +# default: %{goipath} +# -b read binaries already produced in +# default: %{gobuilddir}/bin +# -s read expanded and prepared Go sources in /src +# should be populated in %prep +# default: %{gobuilddir} +# -v be verbose +# Exclusion arguments, that can be repeated, relative to the go import path root: +# -d exclude the files contained in +# not recursive (subdirectories are not excluded) +# -t exclude the files contained in +# recursive (subdirectories are excluded) +# -r exclude files matching , +%gocheck(z:ai:b:s:vd:t:rV:T:C:B:p:g:w) %{lua: +local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") +local rpmmacros = require "rpmmacros" +-- Main function +local function process(suffix) + local zsuffix = "" + if (suffix ~= "") and (suffix ~= nil) then + zsuffix = "-z " .. suffix .. " " + end + print(rpm.expand('%goenv ' .. zsuffix .. '%{?-i} %{?-v} %{?-V} %{?-T} %{?-C} %{?-B}\\n' .. + '%{?currentgoldflags:LDFLAGS="${LDFLAGS}%{?currentgoldflags}" }' .. + '%{?gotestflags:GO_TEST_FLAGS="%{gotestflags}" }' .. + '%{?gotestextldflags:GO_TEST_EXT_LD_FLAGS="%{gotestextldflags}" }' .. + 'go-rpm-integration check %{!-i:-i "%{currentgoipath}" }' .. + '%{!-b:-b "%{gobuilddir}/bin" }' .. + '%{!-s:-s "%{gobuilddir}" }' .. + '%{!-V:-V "%{version}-%{release}" }' .. + '%{!-T:%{?currenttag: -T "%{?currenttag}" }}' .. + '%{!-C:%{?currentcommit: -C "%{?currentcommit}" }}' .. + '%{!-B:%{?currentbranch: -B "%{?currentbranch}" }}' .. + '%{!-p:-p "%{buildroot}" }' .. + '%{!-g:-g "%{gopath}" }' .. + '%{?gocheckflags} %{?**} \\n')) +end +-- Main loop +if processall then + for _,s in pairs(rpmmacros.getsuffixes("goipath")) do + process(s) + end +else + process(rpm.expand("%{-z*}")) +end +} + +# Legacy compatibility macros. Do not use them. Should go away eventually +%gobuildroot %{expand: +%{warn:%%gobuildroot is obsolete, use %%goprep in %%prep instead!} +%goenv -z 0 +%gomkdir -k +ln -fs "%{gobuilddir}/bin" _bin +} + +%gochecksflags %{gocheckflags} + +%gochecks(z:ai:b:s:vd:t:rV:T:C:B:p:g:w) %{expand: +%{warn:%%gochecks is obsolete, use %%gocheck in %%check instead!} +%gocheck %{?**} } diff --git a/rpm/macros.d/macros.go-srpm b/rpm/macros.d/macros.go-srpm index 64e0e76..f676e63 100644 --- a/rpm/macros.d/macros.go-srpm +++ b/rpm/macros.d/macros.go-srpm @@ -77,11 +77,14 @@ print(result) # # The following spec variables SHOULD be set before calling the macro: # -# forgeurl the project url on the forge, strongly recommended, if it can not -# be deduced from goipath; alternatively, use -u +# forgeurl the project url on the forge, +# if it can not be deduced from goipath # Version if applicable, set it with Version: # tag if applicable # commit if applicable +# date if applicable (to override the mtime of the Source archive) +# +# Use -z for multiple calls to the macro # # The macro will attempt to compute and set the following variables if they are # not already set by the packager: @@ -99,72 +102,81 @@ print(result) # archiveext the source archive filename extensions, without leading dot # archiveurl the url that can be used to download the source archive, # without renaming +# topdir the source archive top directory (can be empty) +# extractdir the source directory created inside %{_builddir} after using +# %%forgesetup, %forgeautosetup or %{forgesetupargs} +# repo the repository name +# owner the repository owner (if used by another computed variable) +# shortcommit the commit hash clamping used by the forge, if any # scm the scm type, when packaging code snapshots: commits or tags +# distprefix the prefix that needs adding to dist to trace non-release packaging # -# If the macro is unable to parse your forgeurl value set at least archivename -# and archiveurl before calling it. -# -# Most of the computed variables are both overridable and optional. However, -# the macro WILL REDEFINE %{dist} when packaging a snapshot (commit or tag). -# The previous %{dist} value will be lost. Don’t call the macro if you don’t -# wish %{dist} to be changed. +# Most of the computed variables are both overridable and optional. # # Optional parameters: -# -u Ignore forgeurl even if it exists and use instead. Note -# that the macro will still end up setting as the forgeurl -# spec variable if it manages to parse it. +# -a process all sources in one go, instead of using separate -z calls +# -z suffix all the read and written variable names with +# for example read goipath, version… +# and generate goname, archiveurl… +# The macro assumes that null or nil suffix is used for the primary +# package source. # -s Silently ignore problems in forgeurl, use it if it can be parsed, # ignore it otherwise. -# -p Restore problem handling, override -s. # -v Be verbose and print every spec variable the macro sets. # -i Print some info about the state of spec variables the macro may use or # set at the end of the processing. -%gometa(u:spvi) %{expand:%{lua: -local forgeurl = rpm.expand("%{?-u*}") -if (forgeurl == "") then - forgeurl = rpm.expand("%{?forgeurl}") -end --- Be explicit about the spec variables we’re setting -local function explicitset(rpmvariable,value) - rpm.define(rpmvariable .. " " .. value) - if (rpm.expand("%{?-v}") ~= "") then - rpm.expand("%{echo:Setting %%{" .. rpmvariable .. "} = " .. value .. "\\n}") +%gometa(az:svi) %{lua: +print( "BuildRequires: go-rpm-macros\\n") +print(rpm.expand("ExclusiveArch: %{go_arches}\\n")) +local verbose = (rpm.expand("%{-v}") ~= "") +local informative = (rpm.expand("%{-i}") ~= "") +local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") +local forgeflags = rpm.expand("%{-s} %{-v} %{-i}") +local rpmmacros = require "rpmmacros" +-- Main function +local function process(suffix) + local zsuffix = "" + if (suffix ~= "") then + zsuffix = " -z " .. suffix end -end --- Never ever stomp on a spec variable the packager already set -local function safeset(rpmvariable,value) - if (rpm.expand("%{?" .. rpmvariable .. "}") == "") then - explicitset(rpmvariable,value) + local ismain = (suffix == "") or (suffix == "0") + if ismain then + rpmmacros.zalias({"forgeurl","goipath","goname","gourl","gosource"},verbose) + end + local spec = {} + for _, v in ipairs({'goipath','forgeurl'}) do + spec[v] = rpm.expand("%{?" .. v .. suffix .. "}") + end + -- All the Go packaging automation relies on goipath being set + if (spec["goipath"] == "") then + rpm.expand("%{error:Please set the Go import path in the %%{goipath" .. suffix .. "} variable before calling %%gometa" .. zsuffix .. "!}") + end + if (spec["forgeurl"] ~= "") then + rpmmacros.safeset("gourl" .. suffix, "%{forgeurl" .. suffix .. "}",verbose) + else + rpmmacros.safeset("gourl" .. suffix, "https://%{goipath" .. suffix .. "}",verbose) + rpmmacros.safeset("forgeurl" .. suffix, "%{gourl" .. suffix .. "}",verbose) + end + print(rpm.expand('%forgemeta ' .. forgeflags .. zsuffix .. '\\n')) + if (rpm.expand("%{?forgesource" .. suffix .. "}") ~= "") then + rpmmacros.safeset("gosource" .. suffix, "%{forgesource" .. suffix .. "}",verbose) + else + rpmmacros.safeset("gosource" .. suffix, "%{gourl" .. suffix .. "}/%{archivename" .. suffix .. "}.%{archiveext" .. suffix .. "}",verbose) + end + rpmmacros.safeset( "goname" .. suffix, "%gorpmname %{goipath" .. suffix .. "}",verbose) + rpmmacros.zalias({"forgeurl","goname","gourl","gosource"},verbose) + -- Final spec variable summary if the macro was called with -i + if informative then + rpm.expand("%{echo:Packaging variables read or set by %%gometa}") + rpmmacros.echovars({"goipath","goname","gourl","gosource"}, suffix) end end --- All the Go packaging automation relies on goipath being set -local goipath = rpm.expand("%{?goipath}") -if (goipath == "") then - rpm.expand("%{error:Please set the Go import path in the “goipath” variable before calling “gometa”!}") -end --- Compute and set spec variables -if (forgeurl ~= "") then - rpm.expand("%forgemeta %{?-v} %{?-i} %{?-s} %{?-p} -u " .. forgeurl .. "\\n") - safeset("gourl", forgeurl) -else - safeset("gourl", "https://" .. goipath) - rpm.expand("%forgemeta %{?-v} %{?-i} -s %{?-p} -u %{gourl}\\n") -end -if (rpm.expand("%{?forgesource}") ~= "") then - safeset("gosource", "%{forgesource}") +-- Main loop +if processall then + for _,s in pairs(rpmmacros.getsuffixes("goipath")) do + process(s) + end else - safeset("gosource", "%{gourl}/%{archivename}.%{archiveext}") + process(rpm.expand("%{-z*}")) end -safeset("goname", "%gorpmname %{goipath}") -rpm.define("gosetup %forgesetup") --- Final spec variable summary if the macro was called with -i -if (rpm.expand("%{?-i}") ~= "") then - rpm.expand("%{echo:Go-specific packaging variables}") - rpm.expand("%{echo: goipath: %{?goipath}}") - rpm.expand("%{echo: goname: %{?goname}}") - rpm.expand("%{echo: gourl: %{?gourl}}") - rpm.expand("%{echo: gosource: %{?gosource}}") -end} -BuildRequires: go-rpm-macros -ExclusiveArch: %{go_arches} }