blob: 3148d12d7245d6bd080317e3c7d5de49e457f4c5 [file] [log] [blame]
#!/bin/sh
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# NOTE: Parts of this file (Makefile.am) are automatically transcluded verbatim
# into Makefile.in. Though the build system (GNU Autotools) automatically adds
# its own license boilerplate to the generated Makefile.in, that boilerplate
# does not apply to the transcluded portions of Makefile.am which are licensed
# to you by the ASF under the Apache License, Version 2.0, as described above.
#
#
# generate-license-files.sh
# -------------------------
#
# Automatically iterates through the provided runtime dependencies of the Maven
# project in the current directory, creating new LICENSE and NOTICE files which
# contain all the license information of bundled dependencies, as well as any
# required notices.
#
# This script is expected to be invoked as part of the build process of the
# various guacamole-client subprojects.
#
# USAGE:
#
# path/to/generate-license-files.sh DEPENDENCY_LIST OUTPUT_DIRECTORY
#
# where DEPENDENCY_LIST is the list of Maven dependencies to consider when
# generating LICENSE and NOTICE (as produced by "mvn dependency:list") and
# OUTPUT_DIRECTORY is the directory in which the LICENSE and NOTICE files
# should be written.
#
# Structure of license information
# --------------------------------
#
# The LICENSE and NOTICE files of the guacamole-client project are used as the
# basis for the generated LICENSE and NOTICE files. It is expected that the
# guacamole-client LICENSE will may contain license information for
# subcomponents that had to be copied verbatim into the source tree, with that
# information following a human-readable preamble that begins with a solid line
# of "=" characters. This line of "=" characters MUST BE INCLUDED when such
# dependencies are present, as it is specifically searched for by this script
# when determining what parts of the main LICENSE file should be copied over.
#
# License information for the bundled runtime dependencies of all subprojects
# is included in the subdirectories of the "doc/licenses/" directory of the
# main guacamole-client source tree. Each subdirectory is associated with a
# single, logical dependency, with the Maven coordinatees of that dependency
# listed in the "maven-coordinates.txt" file within that subdirectory. There
# may be multiple coordinates associated with a dependency, in which case each
# relevant set of coordinates should be listed on its own line.
#
# For dependencies that are not associated with Maven coordinates, the licenses
# of those dependencies should instead be documented within subdirectories of
# the "src/licenses/bundled/" directory of the relevant subproject.
#
# Regardless of whether a dependency is documented within the top-level
# guacamole-client project (Maven dependencies) or within the relevant
# subproject (non-Maven dependencies), the subdirectory for each dependency
# must contain a "README" file describing the dependency, the version used, the
# copyright holder(s), and the license. Examples of the formatting expected for
# these README files can be found within the existing dependency license
# directories.
#
# Files that contain the word "notice", regardless of case, are considered by
# this script to be the notice file mentioned within the Apache License, and
# will be copied verbatim into the generated NOTICE file.
#
# Files that that are not recognized as any other type of file are considered
# by this script to be the license and will be included verbatim within the
# generated LICENSE if they are less than 50 lines.
#
##
## The filename of the file containing whether any errors have been logged. The
## contents of this file will be set to "1" if at least one error occurred. A
## file is used here instead of a simple environment variable to allow error()
## to be called from within pipelines and still be detectable.
##
HAS_ERRORS="`mktemp`"
trap 'rm -f "$HAS_ERRORS"' EXIT
##
## The maximum size of a license that may be included verbatim within the
## generated LICENSE file. Larger licenses will only be included separately.
##
LICENSE_COPY_LIMIT=50
##
## The directory containing this script and all license information. This
## should be "doc/licenses/" within the guacamole-client source tree.
##
LICENSES_DIR="`dirname "$0"`"
##
## The base directory of the guacamole-client source tree.
##
BASEDIR="$LICENSES_DIR/../.."
##
## The file containing all relevant runtime dependencies, as generated by
## "mvn dependency:list".
##
DEPENDENCY_LIST="$1"
##
## The output directory in which the generated LICENSE, NOTICE, etc. files
## should be placed.
##
OUTPUT_DIR="$2"
##
## Lists the license information directories (subdirectories of the
## "doc/licenses/" directory in the main guacamole-client source tree) that
## apply to the list of runtime dependencies provided via STDIN. If any runtime
## dependencies are not described by license information included in the
## guacamole-client source tree, a error is printed to STDERR.
##
## The license information directories for dependencies that are not pulled in
## by Maven (subdirectories of the "src/licenses/bundled/" directory within the
## current project) will also be included, if any.
##
list_dependency_license_info() {
# List the license directories of all runtime dependencies, as dictated by
# the "maven-coordinates.txt" files included within those directores
grep -o '[^: ]*:[^: ]*:[^: ]*:[^: ]*' | while read DEPENDENCY; do
if ! grep -l "$DEPENDENCY[[:space:]]*$" "$LICENSES_DIR"/*/maven-coordinates.txt; then
error "License information missing for $DEPENDENCY"
fi
done | sort -u | while read LICENSE_INFO_COORDS_FILE; do
dirname "$LICENSE_INFO_COORDS_FILE"
done
# Include license directories for all dependencies not pulled in by Maven
if [ -d ./src/licenses/bundled/ ]; then
find src/licenses/bundled/ -mindepth 1 -maxdepth 1 -type d
fi
}
##
## Sorts the given list of license information directories by the name of the
## dependency, as determined by the header line within that dependency's
## README. The list of directories is read from STDIN, and the sorted result is
## written to STDOUT. Each directory must be on its own line.
##
sort_dependency_license_info() {
while read LICENSE_INFO; do
if [ ! -e "$LICENSE_INFO/README" ]; then
error "Missing license README in $LICENSE_INFO"
continue
fi
NAME="`grep . < "$LICENSE_INFO/README" | head -n1`"
printf "%s\t%s\n" "$NAME" "$LICENSE_INFO"
done | sort -f | cut -f2
}
##
## Prints the given informational message to STDERR.
##
## @param ...
## The message to print.
##
info() {
echo "$@" >&2
}
##
## Prints the given error message to STDERR, updating HAS_ERRORS
## appropriately.
##
## @param ...
## The message to print.
##
error() {
echo "ERROR: $@" >&2
echo "1" > "$HAS_ERRORS"
}
##
## Prints the first line from STDIN. If more than one line is provided,
## those lines are omitted, and an error exit code is returned.
##
## @return
## Zero (success) if no more than one line was provided on STDIN,
## non-zero (failure) otherwise.
##
single_result() {
read RESULT && echo "$RESULT"
! read DUMMY
}
##
## Searches the given directory for a license file, prints the path to the
## license file found. If multiple files are found, only the first file is
## printed, and an error is logged to STDERR.
##
## @param DIR
## The directory to search.
##
license_file() {
DIR="$1"
find "$DIR" -mindepth 1 \
-a \! -iname "*notice*" \
-a \! -name "maven-coordinates.txt" \
-a \! -name "README" \
| if ! single_result; then
error "Multiple license files found within $DIR"
fi
}
##
## Searches the given directory for a notice file, prints the path to the
## notice file found. If multiple files are found, only the first file is
## printed, and a error is logged to STDERR.
##
## @param DIR
## The directory to search.
##
notice_file() {
DIR="$1"
find "$DIR" -iname "*notice*" \
| if ! single_result; then
error "Multiple notice files found within $DIR"
fi
}
##
## Prints the contents of the given file, excluding any blank lines at the
## beginning and end of the file.
##
## @param FILENAME
## The file to print.
##
trim_file() {
FILENAME="$1"
# Find line number of first and last non-blank lines
FIRST_LINE="`awk '/[^\t ]/ {print NR; exit}' "$FILENAME"`"
LAST_LINE="`awk '/[^\t ]/ {last=NR} END {print last}' "$FILENAME"`"
# Print the contents of the file between those lines, inclusive
awk "NR==$FIRST_LINE,NR==$LAST_LINE" "$FILENAME"
}
# Verify that an output directory was provided
if [ -z "$DEPENDENCY_LIST" -o -z "$OUTPUT_DIR" ]; then
error "USAGE: $0 DEPENDENCY_LIST OUTPUT_DIRECTORY"
exit 1
fi
# Verify input file actually exists
if [ ! -r "$DEPENDENCY_LIST" ]; then
error "$DEPENDENCY_LIST cannot be read."
exit 1
fi
#
# Autogenerate base LICENSE and NOTICE
#
info "Processing runtime dependencies to produce LICENSE and NOTICE. Output will be within \"$OUTPUT_DIR\"."
mkdir -p "$OUTPUT_DIR"
# Copy overall license up to but not including its subcomponent preamble (the
# section that starts after a line made up entirely of "=" characters)
awk 'NR==1 {flag=1}; /^[=]{10,}$/ {flag=0}; flag;' "$BASEDIR/LICENSE" > "$OUTPUT_DIR/LICENSE"
# Copy base NOTICE verbatim
cp "$BASEDIR/NOTICE" "$OUTPUT_DIR/"
#
# Autogenerate LICENSE and NOTICE information from dependencies
#
PREAMBLE_ADDED=0
list_dependency_license_info < "$DEPENDENCY_LIST" | sort_dependency_license_info | \
while read LICENSE_INFO_DIR; do
# Add subcomponent license preamble if not already added
if [ "$PREAMBLE_ADDED" = 0 ]; then
cat >> "$OUTPUT_DIR/LICENSE" <<EOF
==============================================================================
APACHE GUACAMOLE SUBCOMPONENTS
Apache Guacamole includes a number of subcomponents with separate copyright
notices and license terms. Your use of these subcomponents is subject to the
terms and conditions of the following licenses.
EOF
PREAMBLE_ADDED=1
fi
# Locate LICENSE and NOTICE files
LICENSE_FILE="`license_file "$LICENSE_INFO_DIR"`"
NOTICE_FILE="`notice_file "$LICENSE_INFO_DIR"`"
# Extract component name from README
COMPONENT_NAME="`trim_file "$LICENSE_INFO_DIR/README" | head -n1 | grep -o '^[^(]*[^([:space:]]'`"
# Add license information to LICENSE
printf '\n\n' >> "$OUTPUT_DIR/LICENSE"
trim_file "$LICENSE_INFO_DIR/README" >> "$OUTPUT_DIR/LICENSE"
# Append verbatim copy of license if small enough
if [ -n "$LICENSE_FILE" ]; then
if [ "`wc -l < "$LICENSE_FILE"`" -le "$LICENSE_COPY_LIMIT" ]; then
echo >> "$OUTPUT_DIR/LICENSE"
trim_file "$LICENSE_FILE" >> "$OUTPUT_DIR/LICENSE"
fi
fi
# Copy NOTICE, if provided
if [ -n "$NOTICE_FILE" ]; then
printf '\n======== NOTICE for "%s" ========\n\n' "$COMPONENT_NAME" >> "$OUTPUT_DIR/NOTICE"
trim_file "$NOTICE_FILE" >> "$OUTPUT_DIR/NOTICE"
fi
# Include verbatim copy of license information
mkdir -p "$OUTPUT_DIR/bundled/"
cp -Lr "$LICENSE_INFO_DIR" "$OUTPUT_DIR/bundled/"
# Add README describing nature of the "bundled/" directory
cat > "$OUTPUT_DIR/bundled/README" <<EOF
Apache Guacamole includes a number of subcomponents with separate copyright
notices and license terms. Your use of these subcomponents is subject to the
terms and conditions of their respective licenses, included within this
directory for reference.
EOF
done
# Do not double-bundle the information contained in the README files (it's
# already in LICENSE), nor internal mappings like maven-coordinates.txt
for EXCLUDED_FILE in README maven-coordinates.txt; do
rm -f "$OUTPUT_DIR/bundled"/*/"$EXCLUDED_FILE"
done
# Fail if any errors occurred
[ "`cat "$HAS_ERRORS"`" != "1" ] && info "Dependency licenses processed successfully."