#!/usr/bin/env bash set -euo pipefail # Regenerates CREDITS from the license text of every Go module linked into the # silo binary. The module set is what `go list -deps` reports for the main # package, so test-only and tool dependencies stay out: CREDITS documents what # a shipped binary actually contains. check-gen runs this and fails on a diff, # which keeps CREDITS from drifting when go.mod changes. script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" repo_dir="$(cd "${script_dir}/.." && pwd)" cd "${repo_dir}" out_file="${1:-${repo_dir}/CREDITS}" tmp_file="${out_file}.tmp" trap 'rm -f "${tmp_file}"' EXIT rule_dash='----------------------------------------------------------------' rule_equal='================================================================' # These modules repackage Go standard library code and publish no license # file; their source files carry the Go Authors' BSD-style header pointing at # the Go project license, so that text is reproduced for them. stdlib_derived='github.com/minio/colorjson github.com/minio/csvparser github.com/minio/filepath' is_stdlib_derived() { case " ${stdlib_derived} " in *" $1 "*) return 0 ;; *) return 1 ;; esac } # Command substitution strips trailing newlines; printf adds exactly one back, # so every entry ends the same way regardless of how the license file ends. emit_text() { printf '%s\n' "$(cat "$1")" } # The module cache must hold every dependency before .Dir can resolve. go mod download # The Go project license text is taken from the pinned golang.org/x/sys module # rather than GOROOT: Homebrew's Go does not ship GOROOT/LICENSE, and the # module copy is version-locked by go.mod, so the output cannot vary with the # machine's toolchain packaging. go_license="$(go list -m -f '{{.Dir}}' golang.org/x/sys)/LICENSE" if [ ! -f "${go_license}" ]; then echo "Missing Go license text: ${go_license}" >&2 exit 1 fi { printf '%s\n' \ 'Silo bundles third-party software under the licenses reproduced below.' \ 'Generated by buildscripts/gen-credits.sh (make credits) from the Go' \ 'modules linked into the silo binary. Do not edit by hand.' \ '' \ "${rule_equal}" \ '' printf '%s\n%s\n%s\n' 'Go (the standard library)' 'https://golang.org/' "${rule_dash}" emit_text "${go_license}" printf '\n%s\n\n' "${rule_equal}" # The dependency closure is GOOS/GOARCH-specific: platform-only modules # (darwin's go-m1cpu, windows' wmi, ...) enter and leave it with the host. # Pin the primary shipped target and the release build tags so regenerating # CREDITS produces identical output on every machine, including CI. GOOS=linux GOARCH=amd64 go list -deps -tags kqueue \ -f '{{if and (not .Standard) .Module}}{{.Module.Path}}{{end}}' . \ | LC_ALL=C sort -u \ | grep -vx 'github.com/minio/minio' \ | xargs go list -m -f '{{.Path}}|{{with .Replace}}{{.Path}}{{end}}|{{.Dir}}' \ | while IFS='|' read -r path replacement dir; do if [ -z "${dir}" ] || [ ! -d "${dir}" ]; then echo "Module cache directory missing for ${path}" >&2 exit 1 fi name="${path}" url="https://${path}" # A same-path replace only pins a version; the annotation is for # dependencies actually served from a different repository. if [ -n "${replacement}" ] && [ "${replacement}" != "${path}" ]; then name="${path} (replaced by ${replacement})" url="https://${replacement}" fi printf '%s\n%s\n%s\n' "${name}" "${url}" "${rule_dash}" if is_stdlib_derived "${path}"; then printf '%s\n%s\n\n' \ 'This module repackages Go standard library code and publishes no' \ 'license file; the Go project license below applies per its file headers.' emit_text "${go_license}" else license_file='' for candidate in LICENSE LICENSE.txt LICENSE.md COPYING COPYING.txt LICENCE UNLICENSE; do if [ -f "${dir}/${candidate}" ]; then license_file="${dir}/${candidate}" break fi done if [ -z "${license_file}" ]; then echo "No license file found for ${path} in ${dir}" >&2 exit 1 fi emit_text "${license_file}" fi # Apache License 2.0 section 4(d) requires redistributing the NOTICE # file contents alongside the licensed work. for notice in NOTICE NOTICE.txt; do if [ -f "${dir}/${notice}" ]; then printf '\n%s\n\n' 'Bundled NOTICE file:' emit_text "${dir}/${notice}" break fi done printf '\n%s\n\n' "${rule_equal}" done } > "${tmp_file}" mv "${tmp_file}" "${out_file}"