Skip to content

Commit 5ca17e7

Browse files
authored
Add bash script to print the used GHC packages
including their version and license and copyright information, erroring if the license if ever not BSD-3-Clause or BSD-2-Clause. Install the GHC package info into 'inst' in CI builds.
1 parent d33c3cb commit 5ca17e7

File tree

4 files changed

+221
-21
lines changed

4 files changed

+221
-21
lines changed

.github/workflows/build-and-test-macos.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ jobs:
8787
CORES=$(sysctl -n hw.ncpu)
8888
echo "Cores: ${CORES}"
8989
90+
# Generate package info
91+
export BSC_BUILD_PKGINFO=1
92+
9093
make -j ${CORES} GHCJOBS=2 GHCRTSFLAGS='+RTS -M4500M -A128m -RTS' install-src
9194
tar czf inst.tar.gz inst
9295
- name: CCache stats

.github/workflows/build-and-test-ubuntu.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ jobs:
6666
CORES=$(nproc)
6767
echo "Cores: ${CORES}"
6868
69+
# Generate package info
70+
export BSC_BUILD_PKGINFO=1
71+
6972
make -j ${CORES} GHCJOBS=2 GHCRTSFLAGS='+RTS -M5G -A128m -RTS' install-src
7073
tar czf inst.tar.gz inst
7174
- name: CCache stats

src/comp/Makefile

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export NOUPDATEBUILDVERSION
3939
PREFIX?=$(TOP)/inst
4040
BINDIR=$(PREFIX)/bin
4141

42+
# Where package information is installed
43+
LICDIR=$(PREFIX)/LICENSES
44+
4245
# Top-level of where intermediate GHC files are stored
4346
BUILDDIR=$(TOP)/build/comp
4447

@@ -125,26 +128,25 @@ endif
125128
GHCPROFAUTO = -fprof-auto
126129

127130
PACKAGES = \
128-
-package base \
129-
-package containers \
130-
-package array \
131-
-package mtl \
132-
-package unix \
133-
-package regex-compat \
134-
-package bytestring \
135-
-package directory \
136-
-package process \
137-
-package filepath \
138-
-package time \
139-
-package old-time \
140-
-package old-locale \
141-
-package split \
142-
-package syb \
143-
-package integer-gmp \
144-
-package text \
145-
-package deepseq \
146-
-package strict-concurrency \
147-
$(GHCEXTRAPKGS)
131+
base \
132+
containers \
133+
array \
134+
mtl \
135+
unix \
136+
regex-compat \
137+
bytestring \
138+
directory \
139+
process \
140+
filepath \
141+
time \
142+
old-time \
143+
old-locale \
144+
split \
145+
syb \
146+
integer-gmp \
147+
text \
148+
deepseq \
149+
strict-concurrency \
148150

149151
# GHC can compile either a single file (use GHCCOMPILEFLAGS) or
150152
# in make mode where it follows dependencies (use GHCMAKEFLAGS).
@@ -184,7 +186,7 @@ GHCFLAGS = \
184186
-fno-warn-orphans \
185187
-fno-warn-name-shadowing \
186188
-fno-warn-unused-matches \
187-
$(PACKAGES) \
189+
$(addprefix -package ,$(PACKAGES)) \
188190
$(GHCINCLUDES) \
189191
$(GHCTMP) \
190192

@@ -353,6 +355,23 @@ bluetcl: bluetcl.hs bluetcl_Main.hsc $(SOURCES)
353355
-x c bluetcl_Main.hsc
354356
$(POSTBUILDCOMMAND)
355357

358+
# -----
359+
# GHC package info
360+
361+
# If BSC_BUILD_PKGINFO is non-empty,
362+
# generate and install a LICENCES/LICENSE.ghc_pkgs file
363+
364+
ifeq ($(BSC_BUILD_PKGINFO),)
365+
PKGINFO=
366+
else
367+
PKGINFO=$(LICDIR)/LICENSE.ghc_pkgs
368+
369+
.PHONY: $(PKGINFO)
370+
$(PKGINFO):
371+
mkdir -p -m 755 $(LICDIR)
372+
./make-ghc-pkg-info.sh $(PACKAGES) > $(PKGINFO)
373+
endif
374+
356375
# -----
357376
# Install targets
358377

@@ -375,18 +394,22 @@ $(BINDIR)/%: wrapper.sh $(BINDIR)/core/%
375394
.PHONY: install-bsc
376395
install-bsc: $(addprefix $(BINDIR)/,$(BSCEXES))
377396
install-bsc: $(addprefix $(BINDIR)/core/,$(BSCEXES))
397+
install-bsc: $(PKGINFO)
378398

379399
.PHONY: install-bluetcl
380400
install-bluetcl: $(addprefix $(BINDIR)/,$(TCLEXES))
381401
install-bluetcl: $(addprefix $(BINDIR)/core/,$(TCLEXES))
402+
install-bluetcl: $(PKGINFO)
382403

383404
.PHONY: install-utils
384405
install-utils: $(addprefix $(BINDIR)/,$(UTILEXES))
385406
install-utils: $(addprefix $(BINDIR)/core/,$(UTILEXES))
407+
install-utils: $(PKGINFO)
386408

387409
.PHONY: install-showrules
388410
install-showrules: $(addprefix $(BINDIR)/,$(SHOWRULESEXES))
389411
install-showrules: $(addprefix $(BINDIR)/core/,$(SHOWRULESEXES))
412+
install-showrules: $(PKGINFO)
390413

391414
# ----
392415
# Other targets

src/comp/make-ghc-pkg-info.sh

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#! /usr/bin/env bash
2+
set -euo pipefail
3+
4+
PACKAGES=$@
5+
6+
# ===========================================================================
7+
8+
# Implement associative arrays, in case the shell is not bash 4+
9+
10+
## ainit STEM
11+
## Declare an empty associative array named STEM.
12+
ainit () {
13+
eval "__aa__${1}=' '"
14+
}
15+
16+
## akeys STEM
17+
## List the keys in the associatve array named STEM.
18+
akeys () {
19+
eval "echo \"\$__aa__${1}\""
20+
}
21+
22+
## aget STEM KEY VAR
23+
## Set VAR to the value of KEY in the associative array named STEM.
24+
## If KEY is not present, unset VAR.
25+
aget () {
26+
eval "unset $3
27+
case \$__aa__${1} in
28+
*\" $2 \"*) $3=\$__aa__${1}__$2;;
29+
esac"
30+
}
31+
32+
## aset STEM KEY VALUE
33+
## Set KEY to VALUE in the associative array named STEM.
34+
aset () {
35+
eval "__aa__${1}__${2}=\$3
36+
case \$__aa__${1} in
37+
*\" $2 \"*) :;;
38+
*) __aa__${1}=\"\${__aa__${1}}$2 \";;
39+
esac"
40+
}
41+
42+
## aunset STEM KEY
43+
## Remove KEY from the associative array named STEM.
44+
aunset () {
45+
eval "unset __aa__${1}__${2}
46+
case \$__aa__${1} in
47+
*\" $2 \"*) __aa__${1}=\"\${__aa__${1}%% $2 *} \${__aa__${1}#* $2 }\";;
48+
esac"
49+
}
50+
51+
# ===========================================================================
52+
53+
ainit arr_id
54+
ainit arr_ver
55+
ainit arr_lic
56+
ainit arr_copyr
57+
ainit arr_deps
58+
59+
# Horizontal delimiter between packages in the output
60+
#
61+
DELIM='-------------------------'
62+
63+
# Regex for removing the hash from names like
64+
# syb-0.7.2.4-FBa2dfZrzzu7owkvhCx23j
65+
#
66+
STRIP_HASH_REGEX='^([-[:lower:]]+[[:digit:]]+.[[:digit:]][.[:digit:]]*)-[[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]+$'
67+
68+
# Function to add a package to the database and follow its dependencies
69+
#
70+
add_pkg() {
71+
local PKG_ID
72+
local PKG_NAME
73+
local PKG_VER
74+
local PKG_LIC
75+
local PKG_COPYR
76+
local PKG_DEPS
77+
78+
#echo "Looking up $1"
79+
80+
PKG_ID=`ghc-pkg field $1 id --simple-output`
81+
82+
if [[ ${PKG_ID} =~ ${STRIP_HASH_REGEX} ]] ; then
83+
#echo "stripping ${PKG_ID} => ${BASH_REMATCH[1]}"
84+
PKG_NAME=${BASH_REMATCH[1]}
85+
else
86+
PKG_NAME=${PKG_ID}
87+
fi
88+
89+
PKG_NAME=`echo "${PKG_NAME}" | tr .- _`
90+
91+
aget arr_id "${PKG_NAME}" i_id
92+
if [ -z ${i_id+x} ] ; then
93+
PKG_VER=`ghc-pkg field $1 version --simple-output`
94+
PKG_LIC=`ghc-pkg field $1 license --simple-output`
95+
PKG_COPYR=`ghc-pkg field $1 copyright --simple-output`
96+
PKG_DEPS=`ghc-pkg field $1 depends --simple-output`
97+
98+
if [ "${PKG_LIC}" != "BSD-3-Clause" ] ; then
99+
if [ "${PKG_LIC}" != "BSD-2-Clause" ] ; then
100+
echo "Unexpected license for ${PKG_ID}: ${PKG_LIC}"
101+
exit 1
102+
fi
103+
fi
104+
105+
aset arr_id ${PKG_NAME} "${PKG_ID}"
106+
aset arr_ver ${PKG_NAME} "${PKG_VER}"
107+
aset arr_lic ${PKG_NAME} "${PKG_LIC}"
108+
aset arr_copyr ${PKG_NAME} "${PKG_COPYR}"
109+
aset arr_deps ${PKG_NAME} "${PKG_DEPS}"
110+
111+
for dep in ${PKG_DEPS}
112+
do
113+
#echo "Following dep: $dep"
114+
if [[ ${dep} =~ ${STRIP_HASH_REGEX} ]] ; then
115+
#echo "stripping ${dep} => ${BASH_REMATCH[1]}"
116+
dep=${BASH_REMATCH[1]}
117+
fi
118+
add_pkg "${dep}"
119+
done
120+
fi
121+
}
122+
123+
# Add the packages from the command line (and their dependencies)
124+
for i in ${PACKAGES}
125+
do
126+
add_pkg "$i"
127+
done
128+
129+
# Generate the output, starting with a delimiter
130+
echo $DELIM
131+
132+
# For each package in the database
133+
keys=$(akeys arr_id)
134+
sorted_keys=`echo ${keys} | tr ' ' '\012' | sort | tr '\012' ' '`
135+
for i in ${sorted_keys}
136+
do
137+
aget arr_id $i i_id
138+
aget arr_ver $i i_ver
139+
aget arr_lic $i i_lic
140+
aget arr_copyr $i i_copyr
141+
142+
# Because the package name was mangled to make the assoc array key
143+
# re-construct it from the ID
144+
145+
if [[ ${i_id} =~ ${STRIP_HASH_REGEX} ]] ; then
146+
pkg=${BASH_REMATCH[1]}
147+
else
148+
pkg=${i_id}
149+
fi
150+
151+
# And then strip the version number
152+
153+
STRIP_VER_REGEX="^([-[:lower:]]+)-${i_ver}"
154+
if [[ $pkg =~ ${STRIP_VER_REGEX} ]] ; then
155+
pkg=${BASH_REMATCH[1]}
156+
fi
157+
158+
echo
159+
echo "package: $pkg"
160+
#echo "id: ${i_id}"
161+
echo "version: ${i_ver}"
162+
echo "license: ${i_lic}"
163+
if [[ -n "${i_copyr}" ]]; then
164+
echo "copyright: ${i_copyr}"
165+
fi
166+
echo
167+
echo $DELIM
168+
done
169+
170+
# Done
171+
exit 0

0 commit comments

Comments
 (0)