ghcup-talk/GHCup.md
2024-06-01 22:07:00 +08:00

421 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

% GHCup
% Julian Ospald
% June 07, 2024
# Introduction
## What is GHCup?
![](what.jpg)
## State of 2019
::: incremental
* stack is the only "Haskell Installer"
* no unified alternative for cabal users
* distro packages, nix, manual installs, ...
* 🤮
:::
## How it started
::: incremental
* 🤹 small team at work (Capital Match), using different platforms
- originally used stack
- cabal distro packages constantly out of date
* 🦾 first version was 165 LOC
- Posix shell
* ![](linux.png){#id .class height=32px} only supported linux and mac
* ![](rust.png){#id .class height=32px} inspired by **rustup**
:::
## GHCup today
[Haskell Survey 2022](https://taylor.fausak.me/2022/11/18/haskell-survey-results/#s2q1):
![](survey.png)
. . .
- over **17k** LOC Haskell
- supports all platforms: Linux, Windows, macOS, FreeBSD
## GHCup and haskell.org
The default installer:
![](downloads.png)
. . .
* provides infrastructure (home page, downloads)
## GHCup and the Haskell Foundation
::: incremental
* affiliation: [https://haskell.foundation/affiliates/](https://haskell.foundation/affiliates/)
* pays for CI
* pays consultants to assist the project
:::
# Philosophy
## What is a good installer?
::: incremental
* it installs (just that)
- everywhere
* intuitive interface
- `ghcup install ghc`
* good documentation
- but you shouldn't have to read it
* get out of the way
- has no self-fulfilling purpose
:::
## Goals and principles
::: incremental
- ☮️ unification
- unix principles
- 🛠️ do one thing and do it well
- ⚗️ pipes, compose stdout and stdin (re-usable)
- 🎁 good re-distribution
- 🛣️ user experience
:::
## What is GHCup (simplified)?
```sh
curl -s -L 'https://downloads.haskell.org/~ghc/9.6.5/ghc-9.6.5-x86_64-fedora33-linux.tar.xz' |
tar -xJ -C /tmp &&
cd /tmp/ghc-9.6.5-x86_64-unknown-linux/ &&
./configure --prefix="$HOME/.local" &&
make install &&
rm -rf /tmp/ghc-9.6.5-x86_64-unknown-linux/
```
## What is GHCup really?
* [https://hasufell.github.io/posts/2023-11-14-ghcup-is-not-an-installer.html](https://hasufell.github.io/posts/2023-11-14-ghcup-is-not-an-installer.html)
::: incremental
* ![](open-box.png){#id .class width=32 height=32px} installer
* ![](debian.png){#id .class width=32 height=32px} distribution channel
* ![](feedback.png){#id .class width=32 height=32px} feedback channel
* ![](qa.png){#id .class width=32 height=32px} testing/QA gateway
* ![](user.png){#id .class width=32 height=32px} provider of sane defaults (e.g. "recommended" GHC version)
* ![](chain-saw.png){#id .class width=32 height=32px} glue for holistic toolchain experience
- VSCode, stack, cabal-install integration
* ![](ghaction.png){#id .class width=32 height=32px} CI provisioning (e.g. github actions)
:::
# Relationships
## Upstream (dependencies)
- supported tools
- GHC
- Cabal
- HLS
- Stack
. . .
- decisions that affect us
- release frequency
- upstream CI
- platform support
- binary distributions (the `.tar.gz`/`.zip`)
## Downstream (dependents)
- ![](haskell_logo.png){#id .class height=32px} Haskell developers
- beginners, advanced, students, companies
- ![](person.png){#id .class width=32 height=32px} end users (e.g. compiling pandoc from source)
- ![](ghaction.png){#id .class width=32 height=32px} GitHub CI
- GitHub images, Haskell repos
- 🪞 mirrors
- [sjtug](https://mirror.sjtu.edu.cn/docs/ghcup)
- 🧰 tools
- [vscode-haskell](https://github.com/haskell/vscode-haskell), [Haskell playground](https://play.haskell.org/), [nvim-lsp-installer](https://github.com/williamboman/nvim-lsp-installer)
# The installer in detail
## How does it work?
* **Architectural components**
- ![](sh-file.png){#id .class height=32px} bootstrap scripts
- ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- ![](config-file.png){#id .class height=32px} ghcup-metadata
. . .
* **Logical components**
- ![](terminal.png){#id .class height=32px} cli interface
- ![](file.png){#id .class height=32px} file layout / installation destination
- ![](tar.png){#id .class height=32px} bindist selection
- ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- ![](config.svg){#id .class height=32px} configuration
## Basic CLI (context)
* **Architectural components**
- [ ] ![](sh-file.png){#id .class height=32px} bootstrap scripts
- [x] ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- [ ] ![](config-file.png){#id .class height=32px} ghcup-metadata
* **Logical components**
- [x] ![](terminal.png){#id .class height=32px} cli interface
- [ ] ![](file.png){#id .class height=32px} file layout / installation destination
- [ ] ![](tar.png){#id .class height=32px} bindist selection
- [ ] ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- [ ] ![](config.svg){#id .class height=32px} configuration
## Basic CLI
::: incremental
* show all available tools / versions
```sh
ghcup list
```
* install a tool
```sh
ghcup install ghc latest
```
* make a tool version the default
```sh
ghcup set ghc latest
```
* remove a tool version
```sh
ghcup rm ghc 9.10.1
```
:::
## File layout (context)
* **Architectural components**
- [ ] ![](sh-file.png){#id .class height=32px} bootstrap scripts
- [x] ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- [ ] ![](config-file.png){#id .class height=32px} ghcup-metadata
* **Logical components**
- [ ] ![](terminal.png){#id .class height=32px} cli interface
- [x] ![](file.png){#id .class height=32px} file layout / installation destination
- [ ] ![](tar.png){#id .class height=32px} bindist selection
- [ ] ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- [ ] ![](config.svg){#id .class height=32px} configuration
## File layout
::: incremental
* root dir
```sh
$ ls ~/.ghcup
📁bin 📁ghc 📁hls
📁cache 📁db 📁logs 📁tmp 🗑trash 📄config.yaml 📄env
```
* GHC and HLS are installed into sub-directories
```sh
$ ls ~/.ghcup/ghc
📁8.10.7 📁9.0.2 📁9.2.8
```
* bin directory is mostly symbolic links (compare with [update-alternatives](https://man7.org/linux/man-pages/man1/update-alternatives.1.html))
```sh
$ ls ~/.ghcup/bin
📄ghcup
🔗cabal 📄cabal-3.10.3.0
🔗ghc 🔗ghc-8.10 🔗ghc-8.10.7 🔗ghc-9.0 🔗ghc-9.0.2 🔗ghc-9.2 🔗ghc-9.2.8
```
:::
## Bindist selection (context)
* **Architectural components**
- [ ] ![](sh-file.png){#id .class height=32px} bootstrap scripts
- [x] ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- [x] ![](config-file.png){#id .class height=32px} ghcup-metadata
* **Logical components**
- [ ] ![](terminal.png){#id .class height=32px} cli interface
- [ ] ![](file.png){#id .class height=32px} file layout / installation destination
- [x] ![](tar.png){#id .class height=32px} bindist selection
- [ ] ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- [ ] ![](config.svg){#id .class height=32px} configuration
## Bindist selection (sysinfo)
**Gather system information:**
::: incremental
* module `GHCup.Platform`
* `System.Info.arch` and `System.Info.os` (compile-time strings)
* distro detection mostly via `/etc/os-release`
- specified by [freedesktop.org](https://www.freedesktop.org/software/systemd/man/latest/os-release.html)
- using [os-release](https://hackage.haskell.org/package/os-release) package for parsing
:::
## Bindist selection (mapping)
**Map binaries to systems:**
::: incremental
- binary compatibility (platform, distro, distro version)
- finite set of binaries
- statically linked GHC?
- static mapping in [ghcup-metadata YAML files](https://github.com/haskell/ghcup-metadata/blob/develop/ghcup-0.0.8.yaml)
- Tool -> Version -> Architecture -> Platform/Distro -> binary URL
- mapping based on binary compatibility
- [https://gitlab.haskell.org/ghc/ghc/-/wikis/platforms/linux](https://gitlab.haskell.org/ghc/ghc/-/wikis/platforms/linux)
- alternative dynamic logic (utilizing `ldconfig -p` output)
- for stack compatibility
- updated on every release
- "channels"
:::
## Installation flow
![](install-flow.svg){#id .class height=500px}
## TUI interface (context)
* **Architectural components**
- [ ] ![](sh-file.png){#id .class height=32px} bootstrap scripts
- [x] ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- [ ] ![](config-file.png){#id .class height=32px} ghcup-metadata
* **Logical components**
- [ ] ![](terminal.png){#id .class height=32px} cli interface
- [ ] ![](file.png){#id .class height=32px} file layout / installation destination
- [ ] ![](tar.png){#id .class height=32px} bindist selection
- [x] ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- [ ] ![](config.svg){#id .class height=32px} configuration
## TUI interface
![](matrix.png){#id .class height=550px}
## Configuration (context)
* **Architectural components**
- [X] ![](sh-file.png){#id .class height=32px} bootstrap scripts
- [x] ![](exe-file.png){#id .class height=32px} ghcup binary (compiled)
- [x] ![](config-file.png){#id .class height=32px} ghcup-metadata
* **Logical components**
- [ ] ![](terminal.png){#id .class height=32px} cli interface
- [ ] ![](file.png){#id .class height=32px} file layout / installation destination
- [ ] ![](tar.png){#id .class height=32px} bindist selection
- [ ] ![](brick-final-clearbg.png){#id .class height=32px} tui interface
- [x] ![](config.svg){#id .class height=32px} configuration
## Configuration
::: incremental
* Types of configuration:
- environment variables
- cli switches / TUI options
- config file (`~/.ghcup/config.yaml`)
* e.g.
- env: `GHCUP_INSTALL_BASE_PREFIX` (default `$HOME`)
- cli: `ghcup install ghc -u <url> <version>`
- config: `url-source` (selecting and mixing "channels")
- file/http/https URI
- `GHCupURL`
- `StackSetupURL`
:::
## Phew
![](headache.png){#id .class height=550px}
# Distribution
## What is distribution?
* QA gate between "upstream" and "downstream"
* trust relationship (with upstream and downstream)
* release selection and defaults
* binary distribution
## What happens on e.g. a GHC release
- testing and inspection of bindists
- manual
- automated at [github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata/blob/develop/.github/workflows/bindists.yaml)
- fixing bindists
- building additional bindists (e.g. FreeBSD)
. . .
- forks at [github.com/stable-haskell](https://github.com/stable-haskell)
- builds cabal, stack and HLS binaries
- GHC TBD
## The "recommended" versions (defaults)
* community adoption (both industry and "open source")
* stack LTS
* HLS support
* known issues and regressions
* GHC HQs opinion and support window
* must be consistent across platforms
# Contributing
## How to contribute
::: incremental
- loose project structure (BDFL)
- discuss early
- repositories
- [github.com/haskell/ghcup-hs](https://github.com/haskell/ghcup-hs): documentation, bootstrap-scripts, ghcup exe
- [github.com/haskell/ghcup-metadata](https://github.com/haskell/ghcup-metadata): bindist mapping (YAML), bindist testing
- build with cabal/stack
- communication
- [#haskell-ghcup](https://kiwiirc.com/nextclient/irc.libera.chat/?nick=Guest%7C?##haskell-ghcup) on libera IRC
- [#ghcup:matrix.org](https://matrix.to/#/#ghcup:matrix.org) (bridged with IRC)
- [github issues](https://github.com/haskell/ghcup-hs/issues)
- [haskell discourse](https://discourse.haskell.org/) (interacting with the community)
:::
## Getting started
Head over to [https://github.com/haskell/ghcup-hs/issues/1074](https://github.com/haskell/ghcup-hs/issues/1074) (`zurihac` labeled issue).
## Advanced topics
- bootstrap scripts
- windows and MSYS2
- security
- HLS/GHC interaction
- reproducibility
- stack integration
- bindist work (curation)
- isolated installs
- mirrors