...
1#!/usr/bin/env bash
2# Copyright 2015 The Kubernetes Authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# Update the LICENSES directory.
17# Generates a table of Go dependencies and their licenses.
18#
19# Usage:
20# $0 [--create-missing] [/path/to/licenses]
21#
22# --create-missing will write the files that only exist upstream, locally.
23# This option is mostly used for testing as we cannot check-in any of the
24# additionally created files into the vendor auto-generated tree.
25#
26# Run every time a license file is added/modified within /vendor to
27# update /LICENSES
28
29set -o errexit
30set -o nounset
31set -o pipefail
32
33KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
34source "${KUBE_ROOT}/hack/lib/init.sh"
35
36export LANG=C
37export LC_ALL=C
38
39###############################################################################
40# Process package content
41#
42# @param package The incoming package name
43# @param type The type of content (LICENSE, COPYRIGHT or COPYING)
44#
45process_content () {
46 local package=$1
47 local type=$2
48
49 local package_root
50 local ensure_pattern
51 local dir_root
52 local find_maxdepth
53 local find_names
54 local -a local_files=()
55
56 # Necessary to expand {}
57 case ${type} in
58 LICENSE) find_names=(-iname 'licen[sc]e*')
59 find_maxdepth=1
60 # Sadly inconsistent in the wild, but mostly license files
61 # containing copyrights, but no readme/notice files containing
62 # licenses (except to "see license file")
63 ensure_pattern="license|copyright"
64 ;;
65 # We search READMEs for copyrights and this includes notice files as well
66 # Look in as many places as we find files matching
67 COPYRIGHT) find_names=(-iname 'notice*' -o -iname 'readme*')
68 find_maxdepth=3
69 ensure_pattern="copyright"
70 ;;
71 COPYING) find_names=(-iname 'copying*')
72 find_maxdepth=1
73 ensure_pattern="license|copyright"
74 ;;
75 esac
76
77 # Start search at package root
78 case ${package} in
79 github.com/*|golang.org/*|bitbucket.org/*|gonum.org/*)
80 package_root=$(echo "${package}" |awk -F/ '{ print $1"/"$2"/"$3 }')
81 ;;
82 go4.org/*)
83 package_root=$(echo "${package}" |awk -F/ '{ print $1 }')
84 ;;
85 gopkg.in/*)
86 # Root of gopkg.in package always ends with '.v(number)' and my contain
87 # more than two path elements. For example:
88 # - gopkg.in/yaml.v2
89 # - gopkg.in/inf.v0
90 # - gopkg.in/square/go-jose.v2
91 package_root=$(echo "${package}" |grep -oh '.*\.v[0-9]')
92 ;;
93 */*)
94 package_root=$(echo "${package}" |awk -F/ '{ print $1"/"$2 }')
95 ;;
96 *)
97 package_root="${package}"
98 ;;
99 esac
100
101 # Find files - only root and package level
102 local_files=()
103 IFS=" " read -r -a local_files <<< "$(
104 for dir_root in ${package} ${package_root}; do
105 [[ -d ${DEPS_DIR}/${dir_root} ]] || continue
106
107 # One (set) of these is fine
108 find "${DEPS_DIR}/${dir_root}" \
109 -xdev -follow -maxdepth ${find_maxdepth} \
110 -type f "${find_names[@]}"
111 done | sort -u)"
112
113 local index
114 local f
115 index="${package}-${type}"
116 if [[ -z "${CONTENT[${index}]-}" ]]; then
117 for f in "${local_files[@]-}"; do
118 if [[ -z "$f" ]]; then
119 # Set the default value and then check it to prevent
120 # accessing potentially empty array
121 continue
122 fi
123 # Find some copyright info in any file and break
124 if grep -E -i -wq "${ensure_pattern}" "${f}"; then
125 CONTENT[${index}]="${f}"
126 break
127 fi
128 done
129 fi
130}
131
132
133#############################################################################
134# MAIN
135#############################################################################
136
137# use modules, and use module info rather than the vendor dir for computing dependencies
138kube::golang::setup_env
139export GOWORK=off
140export GOFLAGS=-mod=mod
141
142# Check bash version
143if (( BASH_VERSINFO[0] < 4 )); then
144 echo
145 echo "ERROR: Bash v4+ required."
146 # Extra help for OSX
147 if [[ "$(uname -s)" == "Darwin" ]]; then
148 echo
149 echo "Ensure you are up to date on the following packages:"
150 echo "$ brew install md5sha1sum bash jq"
151 fi
152 echo
153 exit 9
154fi
155
156# This variable can be injected, as in the verify script.
157LICENSE_ROOT="${LICENSE_ROOT:-${KUBE_ROOT}}"
158cd "${LICENSE_ROOT}"
159
160kube::util::ensure-temp-dir
161
162# Save the genreated LICENSE file for each package temporarily
163TMP_LICENSE_FILE="${KUBE_TEMP}/LICENSES.$$"
164
165# The directory to save all the LICENSE files
166LICENSES_DIR="${LICENSES_DIR:-${LICENSE_ROOT}/LICENSES}"
167mkdir -p "${LICENSES_DIR}"
168
169# The tmp directory to save all the LICENSE files, will move to LICENSES_DIR
170TMP_LICENSES_DIR="${KUBE_TEMP}/LICENSES.DIR.$$"
171mkdir -p "${TMP_LICENSES_DIR}"
172
173DEPS_DIR="vendor"
174declare -Ag CONTENT
175
176# Put the K8S LICENSE on top
177if [ -f "${LICENSE_ROOT}/LICENSE" ]; then
178 (
179 echo "================================================================================"
180 echo "= Kubernetes licensed under: ="
181 echo
182 cat "${LICENSE_ROOT}/LICENSE"
183 echo
184 echo "= LICENSE $(kube::util::md5 "${LICENSE_ROOT}/LICENSE")"
185 echo "================================================================================"
186 ) > "${TMP_LICENSE_FILE}"
187 mv "${TMP_LICENSE_FILE}" "${TMP_LICENSES_DIR}/LICENSE"
188fi
189
190# Capture all module dependencies
191modules=$(go list -m -json all | jq -r .Path | sort -f)
192# Loop through every vendored package
193for PACKAGE in ${modules}; do
194 if [[ -e "staging/src/${PACKAGE}" ]]; then
195 echo "${PACKAGE} is a staging package, skipping" >&2
196 continue
197 fi
198 if [[ ! -e "${DEPS_DIR}/${PACKAGE}" ]]; then
199 echo "${PACKAGE} doesn't exist in ${DEPS_DIR}, skipping" >&2
200 continue
201 fi
202
203 # if there are no files vendored under this package...
204 if [[ -z "$(find "${DEPS_DIR}/${PACKAGE}" -mindepth 1 -maxdepth 1 -type f)" ]]; then
205 # and we have at least the same number of submodules as subdirectories...
206 if [[ "$(find "${DEPS_DIR}/${PACKAGE}/" -mindepth 1 -maxdepth 1 -type d | wc -l)" -le "$(echo "${modules}" | grep -cE "^${PACKAGE}/")" ]]; then
207 echo "Only submodules of ${PACKAGE} are vendored, skipping" >&2
208 continue
209 fi
210 fi
211
212 echo "${PACKAGE}"
213
214 process_content "${PACKAGE}" LICENSE
215 process_content "${PACKAGE}" COPYRIGHT
216 process_content "${PACKAGE}" COPYING
217
218 # copy content and throw error message
219 {
220 echo "= ${DEPS_DIR}/${PACKAGE} licensed under: ="
221 echo
222
223 file=""
224 if [[ -n "${CONTENT[${PACKAGE}-LICENSE]-}" ]]; then
225 file="${CONTENT[${PACKAGE}-LICENSE]-}"
226 elif [[ -n "${CONTENT[${PACKAGE}-COPYRIGHT]-}" ]]; then
227 file="${CONTENT[${PACKAGE}-COPYRIGHT]-}"
228 elif [[ -n "${CONTENT[${PACKAGE}-COPYING]-}" ]]; then
229 file="${CONTENT[${PACKAGE}-COPYING]-}"
230 fi
231 if [[ -z "${file}" ]]; then
232 cat >&2 << __EOF__
233No license could be found for ${PACKAGE} - aborting.
234
235Options:
2361. Check if the upstream repository has a newer version with LICENSE, COPYRIGHT and/or
237 COPYING files.
2382. Contact the author of the package to ensure there is a LICENSE, COPYRIGHT and/or
239 COPYING file present.
2403. Do not use this package in Kubernetes.
241__EOF__
242 exit 9
243 fi
244
245 cat "${file}"
246 echo
247 echo "= ${file} $(kube::util::md5 "${file}")"
248 } >> "${TMP_LICENSE_FILE}"
249
250 dest_dir="${TMP_LICENSES_DIR}/vendor/${PACKAGE}"
251 mkdir -p "${dest_dir}"
252 mv "${TMP_LICENSE_FILE}" "${dest_dir}/LICENSE"
253done
254
255# copy licenses for forked code from vendor and third_party directories
256(cd "${KUBE_ROOT}" && \
257 find vendor third_party -iname 'licen[sc]e*' -o -iname 'notice*' -o -iname 'copying*' | \
258 grep -E 'third_party|forked' | \
259 xargs tar -czf - | tar -C "${TMP_LICENSES_DIR}" -xzf -)
260
261# Leave things like OWNERS alone.
262rm -f "${LICENSES_DIR}/LICENSE"
263rm -rf "${LICENSES_DIR}/vendor"
264rm -rf "${LICENSES_DIR}/third_party"
265mv "${TMP_LICENSES_DIR}"/* "${LICENSES_DIR}"
View as plain text