diff --git a/.devcontainer/.gitignore b/.devcontainer/.gitignore new file mode 100644 index 000000000000..13512e2ed4e8 --- /dev/null +++ b/.devcontainer/.gitignore @@ -0,0 +1,25 @@ +* + +!/assets/ +!/backups/ +!/bind-mounts/ +!/conf/ +!/conf/etc/ +!/conf/etc/stack/ +!/ghc-*/ +!/scripts/ +!/scripts/usr/ +!/scripts/usr/local/ +!/scripts/usr/local/bin/ + +!/conf/etc/stack/config.yaml +!/ghc-*/devcontainer.json +!/scripts/usr/local/bin/*.sh + +!/devcontainer.json +!/GHC.Dockerfile +!/LICENSE +!/README.md + +!.gitignore +!.keep diff --git a/.devcontainer/GHC.Dockerfile b/.devcontainer/GHC.Dockerfile new file mode 100644 index 000000000000..f1bcfd062a2d --- /dev/null +++ b/.devcontainer/GHC.Dockerfile @@ -0,0 +1,112 @@ +ARG BUILD_ON_IMAGE=glcr.b-data.ch/ghc/ghc-musl +ARG GHC_VERSION=latest +ARG HLS_VERSION +ARG STACK_VERSION + +ARG HLS_GHC_VERSION=${HLS_VERSION:+$GHC_VERSION} +ARG HLS_SFX=/${HLS_GHC_VERSION:-all}/hls:${HLS_VERSION:-none} + +ARG STACK_VERSION_OVERRIDE=${STACK_VERSION:-none} + +FROM ${BUILD_ON_IMAGE}:${GHC_VERSION} as files + +RUN mkdir /files + +COPY conf /files +COPY scripts /files + +## Ensure file modes are correct +RUN find /files -type d -exec chmod 755 {} \; \ + && find /files -type f -exec chmod 644 {} \; \ + && find /files/usr/local/bin -type f -exec chmod 755 {} \; + +FROM glcr.b-data.ch/commercialhaskell/ssi:${STACK_VERSION_OVERRIDE} as ssi + +FROM ${BUILD_ON_IMAGE}${HLS_SFX} as hls + +FROM glcr.b-data.ch/ndmitchell/hlsi:latest as hlsi + +FROM docker.io/koalaman/shellcheck:stable as sci + +FROM ${BUILD_ON_IMAGE}:${GHC_VERSION} + +COPY --from=files /files / + +RUN sysArch="$(uname -m)" \ + ## Ensure that common CA certificates + ## and OpenSSL libraries are up to date + && apk upgrade --no-cache ca-certificates openssl-dev \ + ## Install pip + && apk add --no-cache py3-pip \ + ## Install terminal multiplexers + && apk add --no-cache screen tmux \ + ## Install yamllint + && apk add --no-cache yamllint \ + ## Install hadolint + && case "$sysArch" in \ + x86_64) tarArch="x86_64" ;; \ + aarch64) tarArch="arm64" ;; \ + *) echo "error: Architecture $sysArch unsupported"; exit 1 ;; \ + esac \ + && apiResponse="$(curl -sSL \ + https://api.github.com/repos/hadolint/hadolint/releases/latest)" \ + && downloadUrl="$(echo "$apiResponse" | grep -e \ + "browser_download_url.*Linux-$tarArch\"" | cut -d : -f 2,3 | tr -d \")" \ + && echo "$downloadUrl" | xargs curl -sSLo /usr/local/bin/hadolint \ + && chmod 755 /usr/local/bin/hadolint + +## Update environment +ARG USE_ZSH_FOR_ROOT +ARG SET_LANG +ARG SET_TZ + +ENV TZ=${SET_TZ:-$TZ} \ + LANG=${SET_LANG:-$LANG} + + ## Change root's shell to ZSH +RUN if [ -n "$USE_ZSH_FOR_ROOT" ]; then \ + apk add --no-cache zsh shadow; \ + fix-chsh.sh; \ + chsh -s /bin/zsh; \ + fi \ + ## Update timezone if needed + && if [ "$TZ" != "" ]; then \ + apk add --no-cache tzdata; \ + echo "Setting TZ to $TZ"; \ + ln -snf "/usr/share/zoneinfo/$TZ" /etc/localtime \ + && echo "$TZ" > /etc/timezone; \ + fi \ + ## Add/Update locale if needed + && if [ "$LANG" != "C.UTF-8" ]; then \ + if [ -n "$LANG" ]; then \ + apk add --no-cache musl-locales musl-locales-lang; \ + fi; \ + sed -i "s/LANG=C.UTF-8/LANG=$LANG/" /etc/profile.d/*locale.sh; \ + sed -i "s/LANG:-C.UTF-8/LANG:-$LANG/" /etc/profile.d/*locale.sh; \ + sed -i "s/LC_COLLATE=C/LC_COLLATE=$LANG/" /etc/profile.d/*locale.sh; \ + sed -i "s/LC_COLLATE:-C/LC_COLLATE:-$LANG/" /etc/profile.d/*locale.sh; \ + fi + +## Copy binaries as late as possible to avoid cache busting +## Install Stack +COPY --from=ssi /usr/local /usr/local +## Install HLS +COPY --from=hls /usr/local /usr/local +## Install HLint +COPY --from=hlsi /usr/local /usr/local +## Install ShellCheck +COPY --from=sci --chown=root:root /bin/shellcheck /usr/local/bin + +ARG HLS_VERSION +ARG STACK_VERSION + +ARG STACK_VERSION_OVERRIDE=${STACK_VERSION} + +ENV HLS_VERSION=${HLS_VERSION} \ + STACK_VERSION=${STACK_VERSION_OVERRIDE:-$STACK_VERSION} + +RUN if [ "${GHC_VERSION%.*}" = "9.2" ]; then \ + if [ -f /usr/local/bin/stack ]; then \ + mv -f /usr/local/bin/stack /usr/bin/; \ + fi \ + fi diff --git a/.devcontainer/LICENSE b/.devcontainer/LICENSE new file mode 100644 index 000000000000..3398aad4fa62 --- /dev/null +++ b/.devcontainer/LICENSE @@ -0,0 +1,35 @@ +Copyright (c) 2023 Olivier Benz + +The code in this directory is not part of Pandoc (the software) and, with the +exceptions noted below, is distributed under the terms of the MIT License: + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +This directory also contains code with other copyrights. The affected files, +their copyrights and license statements are listed below. + +-------------------------------------------------------------------------------- +scripts/fix-chsh.sh +Copyright (c) Microsoft Corporation. All rights reserved. + +Licensed under the MIT License. See +https://github.com/devcontainers/features/blob/main/LICENSE for +license information. + +-------------------------------------------------------------------------------- diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000000..c79208173086 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,9 @@ +# Dev Containers + +For further information, see [Pandoc's Dev Containers wiki page](https://github.com/jgm/pandoc/wiki/Dev-Containers). + +## License + +The code in this directory is not part of pandoc (the software) and, with the +exceptions noted in [LICENSE](LICENSE), is distributed under the terms of the +MIT License. diff --git a/.devcontainer/backups/.keep b/.devcontainer/backups/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/.devcontainer/bind-mounts/.keep b/.devcontainer/bind-mounts/.keep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/.devcontainer/conf/etc/stack/config.yaml b/.devcontainer/conf/etc/stack/config.yaml new file mode 100644 index 000000000000..37c999c3d6e1 --- /dev/null +++ b/.devcontainer/conf/etc/stack/config.yaml @@ -0,0 +1,4 @@ +# Use only the GHC available on the PATH +system-ghc: true +# Do not automatically install GHC when necessary +install-ghc: false diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..fcca9d01b4e8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,68 @@ +{ + "name": "Default (for use with Stack)", + "build": { + "dockerfile": "GHC.Dockerfile", + "args": { + "GHC_VERSION": "9.4.5", + "HLS_VERSION": "2.1.0.0", + "STACK_VERSION": "2.11.1", + "USE_ZSH_FOR_ROOT": "unset-to-use-ash", + "SET_LANG": "C.UTF-8", + "SET_TZ": "" + } + }, + + "onCreateCommand": "onCreateCommand.sh", + "postCreateCommand": "cabal update", + + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true, + "upgradePackages": false, + "username": "vscode", + "userUid": "automatic", + "userGid": "automatic" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "eamodio.gitlens@11.7.0", + "editorconfig.editorconfig", + "exiasr.hadolint", + "GitHub.vscode-pull-request-github", + "haskell.haskell", + "mhutchie.git-graph", + "ms-vscode.makefile-tools", + "mutantdino.resourcemonitor", + "timonwong.shellcheck" + ], + "settings": { + "gitlens.showWelcomeOnInstall": false, + "gitlens.showWhatsNewAfterUpgrades": false, + "haskell.manageHLS": "PATH", + "resmon.show.battery": false, + "resmon.show.cpufreq": false + } + } + }, + + // Set 'remoteUser' to 'root' to connect as root instead. + "remoteUser": "vscode", + "mounts": [ + "source=pandoc-default-home-vscode,target=/home/vscode,type=volume" + // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-default-home-vscode,target=/home/vscode,type=bind" + ], + + // "remoteUser": "root", + // "mounts": [ + // "source=pandoc-default-root,target=/root,type=volume" + // // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-default-root,target=/root,type=bind" + // ], + + // Pip: Install packages to the user site + "remoteEnv": { + "PIP_USER": "1" + } +} diff --git a/.devcontainer/ghc-9.2/devcontainer.json b/.devcontainer/ghc-9.2/devcontainer.json new file mode 100644 index 000000000000..06492b1812c6 --- /dev/null +++ b/.devcontainer/ghc-9.2/devcontainer.json @@ -0,0 +1,69 @@ +{ + "name": "GHC 9.2 (recommended)", + "build": { + "dockerfile": "../GHC.Dockerfile", + "context": "..", + "args": { + "GHC_VERSION": "9.2", + "HLS_VERSION": "2.2.0.0", + "STACK_VERSION": "2.9.3.1", + "USE_ZSH_FOR_ROOT": "unset-to-use-ash", + "SET_LANG": "C.UTF-8", + "SET_TZ": "" + } + }, + + "onCreateCommand": "onCreateCommand.sh", + "postCreateCommand": "cabal update", + + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true, + "upgradePackages": false, + "username": "vscode", + "userUid": "automatic", + "userGid": "automatic" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "eamodio.gitlens@11.7.0", + "editorconfig.editorconfig", + "exiasr.hadolint", + "GitHub.vscode-pull-request-github", + "haskell.haskell", + "mhutchie.git-graph", + "ms-vscode.makefile-tools", + "mutantdino.resourcemonitor", + "timonwong.shellcheck" + ], + "settings": { + "gitlens.showWelcomeOnInstall": false, + "gitlens.showWhatsNewAfterUpgrades": false, + "haskell.manageHLS": "PATH", + "resmon.show.battery": false, + "resmon.show.cpufreq": false + } + } + }, + + // Set 'remoteUser' to 'root' to connect as root instead. + "remoteUser": "vscode", + "mounts": [ + "source=pandoc-ghc-9.2-home-vscode,target=/home/vscode,type=volume" + // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.2-home-vscode,target=/home/vscode,type=bind" + ], + + // "remoteUser": "root", + // "mounts": [ + // "source=pandoc-ghc-9.2-root,target=/root,type=volume" + // // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.2-root,target=/root,type=bind" + // ], + + // Pip: Install packages to the user site + "remoteEnv": { + "PIP_USER": "1" + } +} diff --git a/.devcontainer/ghc-9.4/devcontainer.json b/.devcontainer/ghc-9.4/devcontainer.json new file mode 100644 index 000000000000..a28a70d3955d --- /dev/null +++ b/.devcontainer/ghc-9.4/devcontainer.json @@ -0,0 +1,68 @@ +{ + "name": "GHC 9.4", + "build": { + "dockerfile": "../GHC.Dockerfile", + "context": "..", + "args": { + "GHC_VERSION": "9.4", + "HLS_VERSION": "2.2.0.0", + "USE_ZSH_FOR_ROOT": "unset-to-use-ash", + "SET_LANG": "C.UTF-8", + "SET_TZ": "" + } + }, + + "onCreateCommand": "onCreateCommand.sh", + "postCreateCommand": "cabal update", + + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true, + "upgradePackages": false, + "username": "vscode", + "userUid": "automatic", + "userGid": "automatic" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "eamodio.gitlens@11.7.0", + "editorconfig.editorconfig", + "exiasr.hadolint", + "GitHub.vscode-pull-request-github", + "haskell.haskell", + "mhutchie.git-graph", + "ms-vscode.makefile-tools", + "mutantdino.resourcemonitor", + "timonwong.shellcheck" + ], + "settings": { + "gitlens.showWelcomeOnInstall": false, + "gitlens.showWhatsNewAfterUpgrades": false, + "haskell.manageHLS": "PATH", + "resmon.show.battery": false, + "resmon.show.cpufreq": false + } + } + }, + + // Set 'remoteUser' to 'root' to connect as root instead. + "remoteUser": "vscode", + "mounts": [ + "source=pandoc-ghc-9.4-home-vscode,target=/home/vscode,type=volume" + // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.4-home-vscode,target=/home/vscode,type=bind" + ], + + // "remoteUser": "root", + // "mounts": [ + // "source=pandoc-ghc-9.4-root,target=/root,type=volume" + // // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.4-root,target=/root,type=bind" + // ], + + // Pip: Install packages to the user site + "remoteEnv": { + "PIP_USER": "1" + } +} diff --git a/.devcontainer/ghc-9.6/devcontainer.json b/.devcontainer/ghc-9.6/devcontainer.json new file mode 100644 index 000000000000..4e651ae71cbc --- /dev/null +++ b/.devcontainer/ghc-9.6/devcontainer.json @@ -0,0 +1,68 @@ +{ + "name": "GHC 9.6 (latest)", + "build": { + "dockerfile": "../GHC.Dockerfile", + "context": "..", + "args": { + "GHC_VERSION": "9.6", + "HLS_VERSION": "2.2.0.0", + "USE_ZSH_FOR_ROOT": "unset-to-use-ash", + "SET_LANG": "C.UTF-8", + "SET_TZ": "" + } + }, + + "onCreateCommand": "onCreateCommand.sh", + "postCreateCommand": "cabal update", + + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true, + "upgradePackages": false, + "username": "vscode", + "userUid": "automatic", + "userGid": "automatic" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "eamodio.gitlens@11.7.0", + "editorconfig.editorconfig", + "exiasr.hadolint", + "GitHub.vscode-pull-request-github", + "haskell.haskell", + "mhutchie.git-graph", + "ms-vscode.makefile-tools", + "mutantdino.resourcemonitor", + "timonwong.shellcheck" + ], + "settings": { + "gitlens.showWelcomeOnInstall": false, + "gitlens.showWhatsNewAfterUpgrades": false, + "haskell.manageHLS": "PATH", + "resmon.show.battery": false, + "resmon.show.cpufreq": false + } + } + }, + + // Set 'remoteUser' to 'root' to connect as root instead. + "remoteUser": "vscode", + "mounts": [ + "source=pandoc-ghc-9.6-home-vscode,target=/home/vscode,type=volume" + // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.6-home-vscode,target=/home/vscode,type=bind" + ], + + // "remoteUser": "root", + // "mounts": [ + // "source=pandoc-ghc-9.6-root,target=/root,type=volume" + // // "source=${localWorkspaceFolder}/.devcontainer/bind-mounts/pandoc-ghc-9.6-root,target=/root,type=bind" + // ], + + // Pip: Install packages to the user site + "remoteEnv": { + "PIP_USER": "1" + } +} diff --git a/.devcontainer/scripts/usr/local/bin/fix-chsh.sh b/.devcontainer/scripts/usr/local/bin/fix-chsh.sh new file mode 100755 index 000000000000..84ab89f1cd6b --- /dev/null +++ b/.devcontainer/scripts/usr/local/bin/fix-chsh.sh @@ -0,0 +1,18 @@ +#!/bin/bash +#------------------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://github.com/devcontainers/features/blob/main/LICENSE for license information. +#------------------------------------------------------------------------------------------------------------------------- +# +# Docs: https://github.com/devcontainers/features/tree/main/src/common-utils +# Maintainer: The Dev Container spec maintainers + +set -e + +# Fixing chsh always asking for a password on alpine linux +# ref: https://askubuntu.com/questions/812420/chsh-always-asking-a-password-and-get-pam-authentication-failure. +if [ ! -f "/etc/pam.d/chsh" ] || ! grep -Eq '^auth(.*)pam_rootok\.so$' /etc/pam.d/chsh; then + echo "auth sufficient pam_rootok.so" >> /etc/pam.d/chsh +elif [[ -n "$(awk '/^auth(.*)pam_rootok\.so$/ && !/^auth[[:blank:]]+sufficient[[:blank:]]+pam_rootok\.so$/' /etc/pam.d/chsh)" ]]; then + awk '/^auth(.*)pam_rootok\.so$/ { $2 = "sufficient" } { print }' /etc/pam.d/chsh > /tmp/chsh.tmp && mv /tmp/chsh.tmp /etc/pam.d/chsh +fi diff --git a/.devcontainer/scripts/usr/local/bin/onCreateCommand.sh b/.devcontainer/scripts/usr/local/bin/onCreateCommand.sh new file mode 100755 index 000000000000..d788f5abeb61 --- /dev/null +++ b/.devcontainer/scripts/usr/local/bin/onCreateCommand.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Copyright (c) 2023 b-data GmbH. +# Distributed under the terms of the MIT License. + +set -e + +mkdir -p "$HOME/.cabal/bin" +mkdir -p "$HOME/.local/bin" + +# Copy Zsh-related files and folders from the untouched home directory +if [ "$(id -un)" == "root" ]; then + if [ ! -d /root/.oh-my-zsh ]; then + cp -R /home/*/.oh-my-zsh /root; + fi + if [ ! -f /root/.zshrc ]; then + cp /home/*/.zshrc /root; + fi +else + if [ ! -d "$HOME/.oh-my-zsh" ]; then + sudo cp -R /root/.oh-my-zsh "$HOME"; + sudo chown -R "$(id -u)":"$(id -g)" "$HOME/.oh-my-zsh"; + fi + if [ ! -f "$HOME/.zshrc" ]; then + sudo cp /root/.zshrc "$HOME"; + sudo chown "$(id -u)":"$(id -g)" "$HOME/.zshrc"; + fi +fi + +# Set PATH so it includes user's private bin if it exists +if ! grep -q "user's private bin" "$HOME/.zshrc"; then + echo -e "\n# set PATH so it includes user's private bin if it exists\nif [ -d \"\$HOME/bin\" ] && [[ \"\$PATH\" != *\"\$HOME/bin\"* ]] ; then\n PATH=\"\$HOME/bin:\$PATH\"\nfi" >> "$HOME/.zshrc"; + echo -e "\n# set PATH so it includes user's private bin if it exists\nif [ -d \"\$HOME/.local/bin\" ] && [[ \"\$PATH\" != *\"\$HOME/.local/bin\"* ]] ; then\n PATH=\"\$HOME/.local/bin:\$PATH\"\nfi" >> "$HOME/.zshrc"; +fi + +# Set PATH so it includes cabal's bin if it exists +if ! grep -q "cabal's bin" "$HOME/.zshrc"; then + echo -e "\n# set PATH so it includes cabal's bin if it exists\nif [ -d \"\$HOME/.cabal/bin\" ] && [[ \"\$PATH\" != *\"\$HOME/.cabal/bin\"* ]] ; then\n PATH=\"\$HOME/.cabal/bin:\$PATH\"\nfi" >> "$HOME/.zshrc"; +fi + +# Enable Oh My Zsh plugins +sed -i "s/plugins=(git)/plugins=(cabal git pip screen stack tmux vscode)/g" "$HOME/.zshrc" + +# Remove old .zcompdump files +rm -f "$HOME"/.zcompdump* diff --git a/.gitignore b/.gitignore index dbcbea11a2c6..0071a8f98ac3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /bench-* !.circleci/** !.cirrus.yml +!.devcontainer/ !.envrc !.editorconfig !.gitattributes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e7acb50e988..9cca0b2a605e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -428,6 +428,17 @@ If you've written a useful pandoc [lua filter](lua-filters.html), you may want to consider submitting a pull request to the [lua-filters repository](https://github.com/pandoc/lua-filters). +Dev Containers +-------------- + +A [Development Container] (or Dev Container for short) allows you to use a +container as a full‑featured development environment. + +You can run Dev Containers locally/remotely (with VS Code), or create a +[Codespace] for a branch in a repository to develop online. + +For further information, see [Pandoc's Dev Containers wiki page]. + [open issues]: https://github.com/jgm/pandoc/issues [closed issues]: https://github.com/jgm/pandoc/issues?q=is%3Aissue+is%3Aclosed [latest released version]: https://github.com/jgm/pandoc/releases/latest @@ -457,3 +468,6 @@ you may want to consider submitting a pull request to the [status:more-discussion-needed]: https://github.com/jgm/pandoc/labels/status:more-discussion-needed [status:more-info-needed]: https://github.com/jgm/pandoc/labels/status:more-info-needed [stack]: https://github.com/commercialhaskell/stack +[Development Container]: https://containers.dev +[Codespace]: https://github.com/features/codespaces +[Pandoc's Dev Containers wiki page]: https://github.com/jgm/pandoc/wiki/Dev-Containers