ghcup-hs/HACKING.md
2021-01-02 16:07:41 +08:00

3.2 KiB
Raw Permalink Blame History

HACKING

Design decisions

Using Excepts as a beefed up ExceptT

This is an open variant, similar to plucky or oops and allows us to combine different error types. Maybe it is too much and it's a little bit unergonomic at times. If it really hurts maintenance, it will be removed. It was more of an experiment.

No use of filepath or directory

Filepath and directory have two fundamental problems: 1. they use String as filepath (see AFPP as to why this is wrong) and 2. they try very hard to be cross-platform at the expense of low-level correctness. Instead, we use the hpath libraries for file and filepath related stuff, which also gives us stronger filepath types.

No use of haskell-TLS

I consider haskell-TLS an interesting experiment, but not a battle-tested and peer-reviewed crypto implementation. There is little to no research about what the intricacies of using haskell for low-level crypto are and how vulnerable such binaries are. Instead, we use either curl the binary (for FreeBSD and mac) or http-io-streams, which works with OpenSSL bindings.

Optics instead of lens

They're a little safer (less Monoid weirdness with view) and have better error messages. Consider the following wit lens

> view (_Just . to (++ "abc")) Nothing
""

vs optics

> view (_Just % to (++ "abc")) Nothing

<interactive>:2:1: error:
    • An_AffineFold cannot be used as A_Getter
    • In the expression: view (_Just % to (++ "abc")) Nothing
      In an equation for it: it = view (_Just % to (++ "abc")) Nothing

Strict and StrictData on by default

Kazu Yamamoto explained it in his PR very well. I like to agree with him. The instances where we need non-strict behavior, we annotate it.

Code style and formatting

  1. Brittany
  2. mtl-style preferred
  3. no overly pointfree style

Code structure

Main functionality is in GHCup module. Utility functions are organised tree-ish in GHCup.Utils and GHCup.Utils.*.

Anything dealing with ghcup specific directories is in GHCup.Utils.Dirs.

Download information on where to fetch bindists from is in the appropriate yaml files: ghcup-<yaml-ver>.yaml.

Common Tasks

Adding a new GHC version

  1. open the latest ghcup-<yaml-ver>.yaml
  2. find the latest ghc version (in yaml tree e.g. ghcupDownloads -> GHC -> 8.10.3)
  3. copy-paste it
  4. adjust the version, tags, changelog, source url
  5. adjust the various bindist urls (make sure to also change the yaml anchors)
  6. run cabal run exe:ghcup-gen -- check-tarballs -f ghcup-<yaml-ver>.yaml -u 'ghc-8\.10\.4'

Major refactors

  1. First major refactor included adding cross support. This added GHCTargetVersion, which includes the target in addition to the version. Most of the Version parameters to functions had to be replaced with that and ensured the logic is consistent for cross and non-cross installs.