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
@@ -92,56 +92,83 @@ in pkgs.runCommand (name + "-coverage-report")
92
92
}
93
93
94
94
function findModules() {
95
- local searchDir=$2
95
+ local -n result=$1
96
+ local -n searchDirs=$2
96
97
local pattern=$3
97
98
98
- pushd $searchDir
99
- mapfile -d $'\0' $1 < <(find ./ -type f \
100
- -wholename "$pattern" -not -name "Paths*" \
101
- -exec basename {} \; \
102
- | sed "s/\.mix$//" \
103
- | tr "\n" "\0")
104
- 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
105
110
}
106
111
107
- local mixDirs=${ toBashArray mixDirs }
108
-
109
112
mkdir -p $out/nix-support
110
- mkdir -p $out/share/hpc/vanilla/mix/${ name }
113
+ mkdir -p $out/share/hpc/vanilla/mix/
111
114
mkdir -p $out/share/hpc/vanilla/tix/${ name }
112
115
mkdir -p $out/share/hpc/vanilla/html/${ name }
113
116
114
- # 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
115
121
for dir in "'' ${mixDirs[@]}"; do
116
122
if [ -d "$dir" ]; then
117
123
cp -R "$dir"/* $out/share/hpc/vanilla/mix/${ name }
118
124
fi
119
125
done
120
126
121
- local srcDirs=${ toBashArray srcDirs }
122
- local allMixModules=()
123
- local pkgMixModules=()
124
-
125
- # The behaviour of stack coverage reports is to provide tix files
126
- # that include coverage information for every local package, but
127
- # to provide HTML reports that only include coverage info for the
128
- # current package. We emulate the same behaviour here. If the user
129
- # includes all local packages in the mix libraries argument, they
130
- # will get a coverage report very similar to stack.
131
-
132
- # All mix modules
133
- findModules allMixModules "$out/share/hpc/vanilla/mix/${ name } " "*.mix"
134
- # Only mix modules corresponding to this package
135
- findModules pkgMixModules "$out/share/hpc/vanilla/mix/${ name } " "*${ name } */*.mix"
136
-
137
- # 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
+
138
165
local tixFiles=()
139
166
${ lib . concatStringsSep "\n " ( builtins . map ( check : ''
140
167
if [ -d "${ check } /share/hpc/vanilla/tix" ]; then
141
168
pushd ${ check } /share/hpc/vanilla/tix
142
169
143
170
tixFile="$(find . -iwholename "*.tix" -type f -print -quit)"
144
- local newTixFile=$out/share/hpc/vanilla/tix/${ name } /"$tixFile"
171
+ local newTixFile=$out/share/hpc/vanilla/tix/${ check . name } /"$(basename $ tixFile) "
145
172
146
173
mkdir -p "$(dirname $newTixFile)"
147
174
# Copy over the tix file verbatim
@@ -150,24 +177,25 @@ in pkgs.runCommand (name + "-coverage-report")
150
177
# Add the tix file to our list
151
178
tixFiles+=("$newTixFile")
152
179
153
- # Create a coverage report for *just that test*
154
- 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"
155
183
156
184
popd
157
185
fi
158
186
'' ) checks )
159
187
}
160
188
161
- # Sum tix files to create a tix file with all relevant tix
162
- # information and markup a HTML report from this info.
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.
163
191
local sumTixFile="$out/share/hpc/vanilla/tix/${ name } /${ name } .tix"
164
192
local markupOutDir="$out/share/hpc/vanilla/html/${ name } "
165
193
166
- # Sum all of our tix file, including modules from any local package
167
- sumTix allMixModules tixFiles "$sumTixFile"
194
+ # Sum all of our tix files
195
+ sumTix mixModules tixFiles "$sumTixFile"
168
196
169
- # Markup a HTML report, included modules from only this package
170
- markup srcDirs mixDirs pkgMixModules "$markupOutDir" "$sumTixFile"
197
+ # Markup a HTML report
198
+ markup srcDirs mixDirs mixModules "$markupOutDir" "$sumTixFile"
171
199
172
200
# Provide a HTML zipfile and Hydra links
173
201
( cd "$markupOutDir" ; zip -r $out/share/hpc/vanilla/${ name } -html.zip . )
0 commit comments