Author: Tom Sydney Kerckhove <syd@cs-syd.eu>
Committer: Tom Sydney Kerckhove <NorfairKing@users.noreply.github.com>
Check a repository against one rule hopinion reads every module of every cabal component and reports what the rules have to say about it. One rule ships, HsNoCustomShowRead from haskell-style.md, so that the machinery is exercised by something real rather than by a demonstration. The shape it is built on: A rule says there is something to fix or there is not. There is no third answer, because a checker whose silence can mean "I could not tell" is a checker whose silence means nothing. A module that did not parse is a failure of the run rather than a module with nothing wrong in it, and a module whose source is a preprocessor's input is counted as unread. A rule is a value in a registry rather than an instance of a class: no generic code is polymorphic in a check type, so a record of functions is the right encoding. Adding a rule is a module and a line in a list, plus a directory of resources that becomes a golden test per file with no test code to write. Errors are types with renderers, not prose in a Left. RuleSetError says which of the three ways a list of rules fails to be a set, ReportError tells bytes that are not JSON from JSON that is not a report, DiscoveryError says what stopped a repository from being read, and Failure is what a report carries when the tool could not tell. Rendering happens once per error, at the boundary, so the wording lives in one place and a caller matches on what happened rather than on a sentence. Paths are path and path-io throughout. Nothing in the library takes a FilePath: a cabal file's main-is becomes a Path Rel File where it is read, the repository root arrives from the command line as a SomeBase Dir because which of the two it is is all a parser can know, and the working directory turns it absolute at the one place that does IO. ParseInput lost a field to this: it carried the module's path twice, once as a name for GHC's messages and once as a RelPath, and only the second was ever a path. There is no set of the shipped rules here. Building one can fail, and for a hand-written list it can only fail on something a test asserts rather than something a run could hit, so a value carrying that failure would hand every caller a branch it cannot act on. RuleSpec asserts the invariant instead, and asserts that the set the rest of the suite runs with is the rules that ship, so a broken list cannot show up as a suite passing over no rules. Nothing here is built for a rule that does not exist yet. One level, no fact store, no cross-process split, and nothing reads what the compiler wrote down, because one module-level rule needs none of them. The build is what holds that line: -Wunused-packages, -Wunused-top-binds and weeder run as errors, and they are what removed the last of the machinery this rule turned out not to need. It cannot be adopted yet, and the rule it ships is the reason: haskell-style.md allows a written Show for data that is secret, and there is no way to say so. Suppressions come next, with the rule that makes them unavoidable.
| Time to Start | Worker time | Duration | Time to finish | Idle | |
| Config | 2m51s | 1s | 1s | 2m52s | 2m51s |
| Eval | 2m58s | 15s | 15s | 3m14s | 6s |
| Build | 3m13s | 0s | 0s | 3m13s | 0s |
| Suite | 2m51s | 17s | 23s | 3m14s | 2m57s |