1
+ # The following collects coverage information from a set of given "checks" and
2
+ # provides a coverage report showing how those "checks" cover a set of given
3
+ # "mixLibraries".
1
4
{ stdenv , lib , haskellLib , pkgs } :
2
5
3
- # Name of the coverage report, which should be unique
6
+ # Name of the coverage report, which should be unique.
4
7
{ name
5
- # Library to check coverage of
6
- , library
7
- # List of check derivations that generate coverage
8
- , checks
9
- # List of other libraries to include in the coverage report. The
10
- # default value if just the derivation provided as the `library`
11
- # argument. Use a larger list of libraries if you would like the tests
12
- # of one local package to generate coverage for another.
13
- , mixLibraries ? [ library ]
14
- # hack for project-less projects
15
- , ghc ? library . project . pkg-set . config . ghc . package
8
+ # List of check derivations that generate coverage.
9
+ , checks ? [ ]
10
+ # List of libraries to include in the coverage report. If one of the above
11
+ # checks generates coverage for a particular library, coverage will only
12
+ # be included if that library is in this list.
13
+ , mixLibraries ? [ ]
14
+ # Hack for project-less projects.
15
+ , ghc ? if mixLibraries == [ ] then null else ( lib . head mixLibraries ) . project . pkg-set . config . ghc . package
16
16
} :
17
17
18
18
let
26
26
in pkgs . runCommand ( name + "-coverage-report" )
27
27
( { nativeBuildInputs = [ ( ghc . buildGHC or ghc ) pkgs . buildPackages . zip ] ;
28
28
passthru = {
29
- inherit name library checks ;
29
+ inherit name checks mixLibraries ;
30
30
} ;
31
31
# HPC will fail if the Haskell file contains non-ASCII characters,
32
32
# unless our locale is set correctly. This has been fixed, but we
@@ -70,71 +70,105 @@ in pkgs.runCommand (name + "-coverage-report")
70
70
local -n tixFs=$2
71
71
local outFile="$3"
72
72
73
- local hpcSumCmd=("hpc" "sum" "--union" "--output=$outFile")
73
+ if (( "'' ${#tixFs[@]}" > 0 )); then
74
+ local hpcSumCmd=("hpc" "sum" "--union" "--output=$outFile")
74
75
75
- for module in "'' ${includedModules[@]}"; do
76
- hpcSumCmd+=("--include=$module")
77
- done
76
+ for module in "'' ${includedModules[@]}"; do
77
+ hpcSumCmd+=("--include=$module")
78
+ done
78
79
79
- for tixFile in "'' ${tixFs[@]}"; do
80
- hpcSumCmd+=("$tixFile")
81
- done
80
+ for tixFile in "'' ${tixFs[@]}"; do
81
+ hpcSumCmd+=("$tixFile")
82
+ done
82
83
83
- echo "'' ${hpcSumCmd[@]}"
84
- eval "'' ${hpcSumCmd[@]}"
84
+ echo "'' ${hpcSumCmd[@]}"
85
+ eval "'' ${hpcSumCmd[@]}"
86
+ else
87
+ # If there are no tix files we output an empty tix file so that we can
88
+ # markup an empty HTML coverage report. This is preferable to failing to
89
+ # output a HTML report.
90
+ echo 'Tix []' > $outFile
91
+ fi
85
92
}
86
93
87
94
function findModules() {
88
- local searchDir=$2
95
+ local -n result=$1
96
+ local -n searchDirs=$2
89
97
local pattern=$3
90
98
91
- pushd $searchDir
92
- mapfile -d $'\0' $1 < <(find ./ -type f \
93
- -wholename "$pattern" -not -name "Paths*" \
94
- -exec basename {} \; \
95
- | sed "s/\.mix$//" \
96
- | tr "\n" "\0")
97
- popd
99
+ for dir in "'' ${searchDirs[@]}"; do
100
+ pushd $dir
101
+ local temp=()
102
+ mapfile -d $'\0' temp < <(find ./ -type f \
103
+ -wholename "$pattern" -not -name "Paths*" \
104
+ -exec basename {} \; \
105
+ | sed "s/\.mix$//" \
106
+ | tr "\n" "\0")
107
+ result+=("'' ${temp[@]}")
108
+ popd
109
+ done
98
110
}
99
111
100
- local mixDirs=${ toBashArray mixDirs }
101
-
102
112
mkdir -p $out/nix-support
103
- mkdir -p $out/share/hpc/vanilla/mix/${ name }
113
+ mkdir -p $out/share/hpc/vanilla/mix/
104
114
mkdir -p $out/share/hpc/vanilla/tix/${ name }
105
115
mkdir -p $out/share/hpc/vanilla/html/${ name }
106
116
107
- # Copy over mix files verbatim
117
+ local srcDirs=${ toBashArray srcDirs }
118
+ local mixDirs=${ toBashArray mixDirs }
119
+
120
+ # Copy out mix files used for this report
108
121
for dir in "'' ${mixDirs[@]}"; do
109
122
if [ -d "$dir" ]; then
110
123
cp -R "$dir"/* $out/share/hpc/vanilla/mix/${ name }
111
124
fi
112
125
done
113
126
114
- local srcDirs=${ toBashArray srcDirs }
115
- local allMixModules=()
116
- local pkgMixModules=()
117
-
118
- # The behaviour of stack coverage reports is to provide tix files
119
- # that include coverage information for every local package, but
120
- # to provide HTML reports that only include coverage info for the
121
- # current package. We emulate the same behaviour here. If the user
122
- # includes all local packages in the mix libraries argument, they
123
- # will get a coverage report very similar to stack.
124
-
125
- # All mix modules
126
- findModules allMixModules "$out/share/hpc/vanilla/mix/${ name } " "*.mix"
127
- # Only mix modules corresponding to this package
128
- findModules pkgMixModules "$out/share/hpc/vanilla/mix/${ name } " "*${ name } */*.mix"
129
-
130
- # For each test
127
+ local mixModules=()
128
+ # Mix modules for all packages in "mixLibraries"
129
+ findModules mixModules mixDirs "*.mix"
130
+
131
+ # We need to make a distinction between library "exposed-modules" and
132
+ # "other-modules" used in test suites:
133
+ # - "exposed-modules" are addressed as "$library-$version-$hash/module"
134
+ # - "other-modules" are addressed as "module"
135
+ #
136
+ # This complicates the code required to find the mix modules. For a given mix directory:
137
+ #
138
+ # mix
139
+ # └── ntp-client-0.0.1
140
+ # └── ntp-client-0.0.1-gYjRsBHUCaHX7ENcjHnw5
141
+ # ├── Network.NTP.Client.mix
142
+ # ├── Network.NTP.Client.Packet.mix
143
+ # └── Network.NTP.Client.Query.mix
144
+ #
145
+ # Iff ntp-client uses "other-modules" in a test suite, both:
146
+ # - "mix/ntp-client-0.0.1", and
147
+ # - "mix/ntp-client-0.0.1/ntp-client-0.0.1-gYjRsBHUCaHX7ENcjHnw5"
148
+ # need to be provided to hpc as search directories.
149
+ #
150
+ # I'd prefer to just exclude "other-modules", but I can't think of an easy
151
+ # way to do that in bash.
152
+ #
153
+ # Here we expand the search dirs and modify the mix dirs accordingly:
154
+ for dir in "'' ${mixDirs[@]}"; do
155
+ local otherModulesSearchDirs=()
156
+ # Simply consider any directory with a mix file as a search directory.
157
+ mapfile -d $'\0' otherModulesSearchDirs < <(find $dir -type f \
158
+ -wholename "*.mix" \
159
+ -exec dirname {} \; \
160
+ | uniq \
161
+ | tr "\n" "\0")
162
+ mixDirs+=("'' ${otherModulesSearchDirs[@]}")
163
+ done
164
+
131
165
local tixFiles=()
132
166
${ lib . concatStringsSep "\n " ( builtins . map ( check : ''
133
167
if [ -d "${ check } /share/hpc/vanilla/tix" ]; then
134
168
pushd ${ check } /share/hpc/vanilla/tix
135
169
136
170
tixFile="$(find . -iwholename "*.tix" -type f -print -quit)"
137
- local newTixFile=$out/share/hpc/vanilla/tix/${ name } /"$tixFile"
171
+ local newTixFile=$out/share/hpc/vanilla/tix/${ check . name } /"$(basename $ tixFile) "
138
172
139
173
mkdir -p "$(dirname $newTixFile)"
140
174
# Copy over the tix file verbatim
@@ -143,29 +177,28 @@ in pkgs.runCommand (name + "-coverage-report")
143
177
# Add the tix file to our list
144
178
tixFiles+=("$newTixFile")
145
179
146
- # Create a coverage report for *just that test*
147
- markup srcDirs mixDirs pkgMixModules "$out/share/hpc/vanilla/html/${ name } /${ check . exeName } /" "$newTixFile"
180
+ # Create a coverage report for *just that check* affecting any of the
181
+ # "mixLibraries"
182
+ markup srcDirs mixDirs mixModules "$out/share/hpc/vanilla/html/${ check . name } /" "$newTixFile"
148
183
149
184
popd
150
185
fi
151
186
'' ) checks )
152
187
}
153
188
154
- # Sum tix files to create a tix file with all relevant tix
155
- # information and markup a HTML report from this info.
156
- if (( "'' ${#tixFiles[@]}" > 0 )); then
157
- local sumTixFile="$out/share/hpc/vanilla/tix/${ name } /${ name } .tix"
158
- local markupOutDir="$out/share/hpc/vanilla/html/${ name } "
189
+ # Sum tix files to create a tix file with tix information from all tests in
190
+ # the package and markup a HTML report from this info.
191
+ local sumTixFile="$out/share/hpc/vanilla/tix/${ name } /${ name } .tix"
192
+ local markupOutDir="$out/share/hpc/vanilla/html/${ name } "
159
193
160
- # Sum all of our tix file, including modules from any local package
161
- sumTix allMixModules tixFiles "$sumTixFile"
194
+ # Sum all of our tix files
195
+ sumTix mixModules tixFiles "$sumTixFile"
162
196
163
- # Markup a HTML report, included modules from only this package
164
- markup srcDirs mixDirs pkgMixModules "$markupOutDir" "$sumTixFile"
197
+ # Markup a HTML report
198
+ markup srcDirs mixDirs mixModules "$markupOutDir" "$sumTixFile"
165
199
166
- # Provide a HTML zipfile and Hydra links
167
- ( cd "$markupOutDir" ; zip -r $out/share/hpc/vanilla/${ name } -html.zip . )
168
- echo "report coverage $markupOutDir/hpc_index.html" >> $out/nix-support/hydra-build-products
169
- echo "file zip $out/share/hpc/vanilla/${ name } -html.zip" >> $out/nix-support/hydra-build-products
170
- fi
200
+ # Provide a HTML zipfile and Hydra links
201
+ ( cd "$markupOutDir" ; zip -r $out/share/hpc/vanilla/${ name } -html.zip . )
202
+ echo "report coverage $markupOutDir/hpc_index.html" >> $out/nix-support/hydra-build-products
203
+ echo "file zip $out/share/hpc/vanilla/${ name } -html.zip" >> $out/nix-support/hydra-build-products
171
204
''
0 commit comments