1#!/usr/bin/env bash
2
3set -ex
4
5
6# MANUAL ADJUSTMENTS
7
8# This variable will be used for testing if the target directory contains all the necessary licenses.
9# The name of every 'lib/*' directory (except 'resources'), 'lib/resources/libraries/*' file
10#   (except '*-license') and proper OS-specific licenses are added automatically.
11REQUIRED_LICENSES=(
12    libllvm-disas
13    llvm
14    nunit3
15    renode
16    RobotoMono-Regular
17    socket-cpp
18    tcg
19    tlib
20)
21
22# Licenses for these directories and files won't be required.
23REQUIRED_LICENSES_EXCLUDE=(
24    # CCTask is only used during building.
25    cctask
26
27    # There is 'IronPython-license' for 'IronPython.dll'. That's enough.
28    IronPython.Modules.dll
29    IronPython.StdLib.dll
30
31    # License is named 'libopenlibm-license' and is only required on Linux.
32    libopenlibm-Linux.a
33
34    # There is 'Sprache-license' for 'Sprache.dll'.
35    Sprache.xml
36)
37
38# Custom names for the 'license*' files. It should be an associative array but macOSs use bash3...
39CUSTOM_TARGET_NAME_KEYS=(
40    lib/bc-csharp/crypto/License.html
41    LICENSE
42)
43CUSTOM_TARGET_NAME_VALUES=(
44    bc-csharp
45    renode
46)
47
48# Use target names without the '-license' suffix, e.g., 'renode' instead of 'LICENSE'. The OSs order
49#   has to be synced with the 'get_os_specific_licenses' function.
50OS_SPECIFIC_LICENSES=(
51    "libopenlibm"  # Linux
52    "macos_run.command"  # macOS
53    "mingw winpthreads"  # Windows
54)
55
56
57# HELPERS
58
59function exit_invalid_args {
60    exit_with_error \
61      "Invalid arguments: $@" \
62      "" \
63      "Usage: $(basename $0) <DESTINATION_DIR> <linux/macos/windows>"
64}
65
66function exit_with_error {
67    set +x
68    echo "ERROR: License copying failed!"
69    echo
70    for message in "$@"; do
71        echo $message
72    done
73    exit 1
74}
75
76function get_custom_target_name {
77    path=$1
78    i=0
79    for key in ${CUSTOM_TARGET_NAME_KEYS[@]}; do
80        if [ "$key" = "$path" ]; then
81            echo "${CUSTOM_TARGET_NAME_VALUES[$i]}"
82            return
83        fi
84        let i++
85    done
86}
87
88function get_os_specific_licenses {
89    if [ "$OS" = linux ]; then
90        index=0
91    elif [ "$OS" = macos ]; then
92        index=1
93    elif [ "$OS" = windows ]; then
94        index=2
95    fi
96    echo "${OS_SPECIFIC_LICENSES[$index]}"
97}
98
99
100# CHECK ARGUMENTS
101
102if [ $# -ne 2 ]; then
103    exit_invalid_args $@
104fi
105
106BASE="$(dirname $0)/../.."
107TARGET="$1"
108OS="$2"
109
110if [ "$OS" != linux ] && [ "$OS" != macos ] && [ "$OS" != windows ]; then
111    exit_invalid_args $@
112fi
113
114_resources_dir="lib/resources/libraries"
115if ! [ -d $BASE/$_resources_dir ]; then
116    exit_with_error "No such directory: '$BASE/$_resources_dir'. Fetch 'renode-resources' first."
117fi
118
119
120# COPY LICENSES
121
122function is_license_skipped {
123    # Extract the license name core if the argument is a full path.
124    filename=${1##*/}
125    name_core=${filename%-licen*}
126
127    # The extra spaces are necessary to only have exact matches.
128    if [[ " ${OS_SPECIFIC_LICENSES[@]} " =~ " $name_core " ]]; then
129        if [[ " $(get_os_specific_licenses) " =~ " $name_core " ]]; then
130            return 1  # Don't skip.
131        else
132            return 0  # Skip.
133        fi
134    else
135        return 1  # Don't skip.
136    fi
137}
138
139# Copy licenses which include the library name. LicenCe is a correct spelling as well (BrE).
140for license in $(find $BASE -type f -iname "*-licen[cs]e"); do
141    if ! is_license_skipped $license; then
142        cp $license $TARGET/
143    fi
144done
145
146# Copy other licenses as '<parent-directory-name>-license' (see CUSTOM_TARGET_NAME* for exceptions).
147# The pattern isn't a simple '-iname "licen[cs]e*"' to prevent matching many potential non-license
148#   files, e.g., "license-script.sh".
149for license in $(find $BASE -type f \( -iname "licen[cs]e" -or -iname "licen[cs]e.*" \)); do
150    base_relative_path=${license#$BASE/}
151    custom_name="$(get_custom_target_name $base_relative_path)"
152    if [ -n "$custom_name" ]; then
153        name="$custom_name"
154    else
155        full_dirname=${license%/*}
156        parent_dirname=${full_dirname##*/}
157        name=$parent_dirname
158    fi
159
160    if ! is_license_skipped $name; then
161        cp $license $TARGET/$name-license
162    fi
163done
164
165set +x
166
167
168# LIST TARGET DIRECTORY
169
170LICENSE_COUNT=$(ls $TARGET/*-license | wc -w)
171echo
172echo "The target directory for licenses ($TARGET) contains $LICENSE_COUNT license files:"
173ls $TARGET
174echo
175
176
177# TEST
178
179# There should be a license for every directory from 'lib' except 'resources' and for every file
180#   from 'lib/resources/libraries' except the '*-license' files.
181for name in $(ls $BASE/lib) $(ls $BASE/lib/resources/libraries/); do
182    if [ "$name" != "resources" ] && ! [[ "$name" =~ "-license" ]]; then
183        REQUIRED_LICENSES+=( $name )
184    fi
185done
186
187# Don't use double quotes for the '$(get_os_specific_licenses)'. The value can contain multiple
188#   names separated with spaces which should be checked separately.
189for name in ${REQUIRED_LICENSES[@]} $(get_os_specific_licenses); do
190    # Check if the license isn't excluded.
191    if [[ " ${REQUIRED_LICENSES_EXCLUDE[@]} " =~ " $name " ]]; then
192        continue
193    fi
194
195    # Strip possible '.a' and '.dll' extensions and add the '-license' suffix.
196    license=${name%.a}
197    license=${license%.dll}
198    license="$license-license"
199    if ! [ -f "$TARGET/$license" ]; then
200        exit_with_error "Required file not found: '$license'. Provide it or exclude '$name'."
201    fi
202done
203