The great Flakes refactor

This commit is contained in:
Robert W. Pearce 2021-06-13 00:02:29 -04:00
parent 20e9bb70ba
commit 3d765d6805
No known key found for this signature in database
GPG Key ID: 07A0E482E5616C9B
28 changed files with 463 additions and 507 deletions

6
.envrc
View File

@ -1,6 +0,0 @@
use nix
eval "$(lorri direnv)"
# Install pre-commit hooks
eval "$shellHook"

5
.ghci
View File

@ -1,4 +1,7 @@
:def hoogle \x -> return $ ":!hoogle --count=15 \"" ++ x ++ "\""
:def doc \x -> return $ ":!hoogle --info \"" ++ x ++ "\""
:set -Wall
:set -fno-warn-type-defaults
:set -fno-warn-type-defaults -ferror-spans -freverse-errors -fprint-expanded-synonyms
:set prompt "\ESC[0;32m%s\n\ESC[m[ghci]\ESC[38;5;172mλ \ESC[m"
:set prompt-cont " \ESC[38;5;172m> \ESC[m"
:load ssg/src/Slug.hs ssg/src/Main.hs

View File

@ -9,22 +9,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2.3.4
- name: Install Nix
uses: cachix/install-nix-action@v12
uses: cachix/install-nix-action@v13
with:
skip_adding_nixpkgs_channel: true
install_url: https://nixos-nix-install-tests.cachix.org/serve/lb41az54kzk6j12p81br4bczary7m145/install
install_options: '--tarball-url-prefix https://nixos-nix-install-tests.cachix.org/serve'
extra_nix_config: |
experimental-features = nix-command flakes
- name: Build with cachix
uses: cachix/cachix-action@v8
uses: cachix/cachix-action@v10
with:
name: hakyll-nix-template
signingKey: ${{ secrets.CACHIX_SIGNING_KEY }}
#authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- run: nix-build
- run: nix-shell --run "echo OK"
- run: nix build
- name: Artifact pages
uses: actions/upload-artifact@v2
@ -46,7 +49,7 @@ jobs:
- name: GitHub Pages
if: success()
uses: crazy-max/ghaction-github-pages@v2
uses: crazy-max/ghaction-github-pages@v2.3.0
with:
build_dir: result
target_branch: gh-pages

4
.gitignore vendored
View File

@ -1,7 +1,7 @@
.ghc.environment.*
.pre-commit-config.yaml
_cache
_tmp
dist
dist-newstyle
hakyll-cache
node_modules
result

233
README.md
View File

@ -2,72 +2,175 @@
[![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org)
[Hakyll](https://jaspervdj.be/hakyll/) + [Nix](https://nixos.org/) template
## Usage
1. Click the "Use this template" button and create your repository
1. Renaming
1. Rename all instances of `hakyll-nix-template` with the name of your project
1. Rename `generator/hakyll-nix-template.cabal` to reflect your project name
1. Cachix
1. Create a cachix cache for your project on https://app.cachix.org
1. Follow the cachix instructions to generate a signing keypair
1. Copy the signing keypair value to a new `CACHIX_SIGNING_KEY` secret on
https://github.com/<MYUSER>/<MY-PROJECT>/settings/secrets
1. Run `nix-build` to build the project and `nix-shell` to open the nix shell
1. If you want to update `niv` and the other pinned dependencies, then in the
`nix-shell` run `niv init` and then `niv update` and then `exit` to leave the
nix shell
1. To start an environment for running hakyll commands like `hakyll-site watch`
(the dev server) and `hakyll-site build`: `cd generator && nix-shell`. You'll
then have access to the `hakyll-site` executable defined in
`generator/hakyll-nix-template.cabal`. While you can do `nix-shell` in the
root and then `cd generator && hakyll-site watch`, you get some more tools if
you `nix-shell` from within the `generator/` folder.
1. Once you're satisfied, create a branch, push your project up there, and check
that the GitHub Actions successfully build. If so, you're good to merge your
project with your main branch.
1. Once you have a successful build on your main branch, open
https://github.com/<MYUSER>/<MY-PROJECT>/settings and set the GitHub Pages
branch to be the `gh-pages` branch
[Hakyll](https://jaspervdj.be/hakyll/) + [Nix](https://nixos.org) template
## Features
tl;dr: `nix-build` will collect all your pinned dependencies, build your hakyll
site, and output the built site in a `result/` directory. If you set up the
[main GitHub Action](./.github/workflows/main.yml) with what it needs (your
[cachix](https://cachix.org) cache, and your app needs a `CACHIX_SIGNING_KEY`
secret), it will deploy your built site to a `gh-pages` branch.
### nix flakes
* Hakyll (see [the generator folder](./generator))
* Haskell `nix-shell` environment inside the `generator` folder through which
you can run `hakyll-site watch` and all other hakyll commands, including
the ability to run `ghci` and load haskell modules for testing
* Ability to patch hakyll via `hakyll.patch`
* Ability to provide nixpkgs overrides for packages whose versions need to
come from [hackage](https://hackage.haskell.org)
* RSS & Atom XML feed generation
* Sitemap generation
* Reasonable pandoc markdown customization to make it as close to GitHub's
style as possible
* `Slug.hs` module that makes nice URIs
* Many other opinionated general website setup features that should be very
helpful
* Nix
* Pinned [nixpkgs](https://github.com/NixOS/nixpkgs), [niv](https://github.com/nmattia/niv),
and [pre-commit-hooks.nix](https://github.com/cachix/pre-commit-hooks.nix)
* `nix-build` will build your site into a `result/` directory
* `nix-shell` in the root will give you a shell with the `tools` dependencies
in [./nix/default.nix](./nix/default.nix)
* `nix-shell` in [./generator](./generator) will give you a haskell shell with
your `hakyll-site` available, as well as `ghci`
* Dev linting via [pre-commit-hooks.nix](https://github.com/cachix/pre-commit-hooks.nix)
* [nix-linter](https://github.com/Synthetica9/nix-linter)
* [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt)
* [ormolu](https://github.com/tweag/ormolu)
* [shellcheck](https://github.com/koalaman/shellcheck)
* Encourages dev use of [lorri](https://github.com/target/lorri)
* Deployment through a [GitHub Actions](https://github.com/features/actions)
build with [cachix](https://cachix.org) and deploying to
[GitHub Pages](https://pages.github.com/) via a `gh-pages` branch
* Build your site into the `./result/dist` folder:
```sh
λ nix build
```
* Start hakyll's dev server that reloads when changes are made:
```sh
λ nix run . watch
Listening on http://127.0.0.1:8000
...more logs
```
* Run any hakyll command through `nix run .`!
```sh
λ nix run . clean
Removing dist...
Removing ssg/_cache...
Removing ssg/_tmp...
```
* Start a development environment that
* has your shell environment
* has `hakyll-site` (for building/watching/cleaning hakyll projects)
* has `hakyll-init` (for generating new projects)
* can have anything else you put in the `buildInputs` of the `devShell` in
`flake.nix`; for example: `haskell-language-server`, `hlint`, and `ormolu`
* is set up to run `ghci` with some defaults and the modules loaded so you can
make your own changes and test them out in the ghci REPL
```sh
λ nix develop
[hakyll]λ hakyll-site build
...
Success
[hakyll]λ ghci
...
[1 of 2] Compiling Slug ( ssg/src/Slug.hs, interpreted )
[2 of 2] Compiling Main ( ssg/src/Main.hs, interpreted )
...
λ > :type toSlug
toSlug :: T.Text -> T.Text
λ > import Data.Text (pack)
λ > toSlug (pack "What If I Told You...")
"what-if-i-told-you"
```
* Easily unbreak hakyll's nixpkgs distribution or change hakyll's compile flags
via the `./haskell-overlay.nix` and `hakyll.patch` files
### hakyll
All of this is custmomizable, and here are some things that are already done for
you:
* [pandoc](https://github.com/jgm/pandoc/) markdown customization to make it as
close to GitHub's markdown style as possible
* `Slug.hs` module that makes nice link URIs based on post titles
* RSS & Atom XML feed generation
* Sitemap generation
* Code syntax highlighting customization
* ...other reasonable defaults
Configure the dev server, cache & tmp directories, and more in
`./ssg/src/Main.hs`.
### Deployment
Deployment is set up through a [GitHub
Action](https://github.com/features/actions) with [cachix](https://cachix.org),
and it deploys to a [GitHub Pages](https://pages.github.com/) branch,
`gh-pages`, when you merge code into your main branch.
Setup information can be found below in the "Cachix" section.
Note: If your main branch's name isn't `main`, ensure `'refs/heads/main'` gets
updated to `'refs/heads/my-main-branch'` in `./github/workflows/main.yml`.
## Setup
### Nix Flakes
If you don't have [nix](https://nixos.org) _and are not running macOS_, follow
[the nix installation instructions](https://nixos.org/download.html).
At the time of writing, the macOS installation is in a weird place. You should
use this:
```sh
λ sh <(curl https://abathur-nix-install-tests.cachix.org/serve/yihf8zbs0jwph2rs9qfh80dnilijxdi2/install) --tarball-url-prefix https://abathur-nix-install-tests.cachix.org/serve
```
Once you have nix installed, follow the instructions here to get access to
flakes: https://nixos.wiki/wiki/Flakes.
### Cachix
The `./.github/workflows/main.yml` file builds with help from
[cachix](https://app.cachix.org), so you'll to generate a signing key to be able
to do this.
1. Create a cache on cachix for your project
1. Follow cachix's instructions to generate a signing keypair
1. Copy the signing keypair value to a new `CACHIX_SIGNING_KEY` secret on
https://github.com/settings/secrets
## Enable Content-Addressible Derivation (experimental)
Given you have your nix conf `experimental-features` set to something like
```
experimental-features = "nix-command flakes ca-derivations ca-references"
```
Uncomment the `__contentAddressed = true;` line in `haskell-ovelray.nix`, and
then run
```sh
λ nix build --experimental-features "ca-derivations flakes nix-command"
```
## Alternatives to the haskell overlay
### Overriding `legacyPackages`' haskell compiler packages
```nix
pkgs = nixpkgs.legacyPackages.${system};
myHaskellPackages = pkgs.haskell.packages.${haskellCompiler}.override {
overrides = hpFinal: hpPrev:
let
hakyll-src = hpPrev.callHackage "hakyll" "4.14.0.0" {};
pandoc-src = hpPrev.callHackage "pandoc" "2.11.4" {};
in {
hakyll = pipe hakyll-src [
doJailbreak
dontCheck
(withPatch ./hakyll.patch)
(withFlags [ "-f" "watchServer" "-f" "previewServer" ])
];
pandoc = pipe pandoc-src [
doJailbreak
dontCheck
];
};
};
```
## Pulling `hakyll-src` from GitHub
`hakyll-src`, used in the `haskell-overlay.nix` and in the prior example,
doesn't have to come from hackage; it could come from what your pinned nixpkgs
version has via `hakyll-src = hpPrev.hakyll`, or it could come from the hakyll
repo pinned as a nix flake input:
```nix
hakyll-src = {
url = "github:jaspervdj/hakyll/v4.14.0.0";
flake = false;
};
```
...and then:
```nix
hakyll-src = hpPrev.callCabal2nix "hakyll" hakyll-src {};
```

View File

@ -1,26 +0,0 @@
let
cfg = import ./nix/default.nix { };
in
{ pkgs ? cfg.pkgs }:
pkgs.stdenv.mkDerivation {
name = "hakyll-nix-template";
buildInputs = [
cfg.generator
];
src = cfg.src;
# https://github.com/jaspervdj/hakyll/issues/614
# https://github.com/NixOS/nix/issues/318#issuecomment-52986702
# https://github.com/MaxDaten/brutal-recipes/blob/source/default.nix#L24
LOCALE_ARCHIVE = pkgs.lib.optionalString (pkgs.buildPlatform.libc == "glibc") "${pkgs.glibcLocales}/lib/locale/locale-archive";
LANG = "en_US.UTF-8";
buildPhase = ''
hakyll-site build
'';
installPhase = ''
mkdir -p "$out/dist"
cp -r ../dist/* "$out/dist"
'';
}

42
flake.lock Normal file
View File

@ -0,0 +1,42 @@
{
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1623660459,
"narHash": "sha256-OTmOsh43po7r5F9s9H6lVCBQ2b0FikWbmiwLbMAGRdw=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "98c8d36b1828009b20f12544214683c7489935a1",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1623576761,
"narHash": "sha256-krXZQ0lObduC95f40K3JwIT//VIBpXBwVNclqh5njtE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1f91fd1040667e9265a760b0347f8bc416249da7",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-21.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

50
flake.nix Normal file
View File

@ -0,0 +1,50 @@
{
description = "hakyll-nix-template";
nixConfig.bash-prompt = "[nix]\\e\[38;5;172mλ \\e\[m";
inputs = {
nixpkgs.url = "nixpkgs/nixos-21.05";
flake-utils = {
url = "github:numtide/flake-utils";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { flake-utils, nixpkgs, self }:
flake-utils.lib.eachDefaultSystem (system:
let
config = {};
overlays = [ (import ./haskell-overlay.nix) ];
pkgs = import nixpkgs { inherit config overlays system; };
in rec {
defaultPackage = packages.website;
defaultApp = apps.hakyll-site;
packages = with pkgs.myHaskellPackages; { inherit ssg website; };
apps.hakyll-site = flake-utils.lib.mkApp {
drv = packages.ssg;
exePath = "/bin/hakyll-site";
};
devShell = pkgs.myHaskellPackages.shellFor {
packages = p: [ p.ssg ];
buildInputs = with pkgs.myHaskellPackages; [
ssg
# Helpful tools for `nix develop` shells
#
#ghcid # https://github.com/ndmitchell/ghcid
#haskell-language-server # https://github.com/haskell/haskell-language-server
#hlint # https://github.com/ndmitchell/hlint
#ormolu # https://github.com/tweag/ormolu
];
withHoogle = true;
};
}
);
}

View File

@ -1,30 +0,0 @@
Copyright (c) 2019, Robert Pearce
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Robert Pearce nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,3 +0,0 @@
{ pkgs }:
(pkgs.callPackage ./hpkgs.nix { }).hakyll-nix-template

View File

@ -1,32 +0,0 @@
{ compiler ? "ghc884"
, pkgs
}:
let
inherit (pkgs.lib.trivial) flip pipe;
inherit (pkgs.haskell.lib) appendPatch appendConfigureFlags dontCheck;
hakyllFlags = [ "-f" "watchServer" "-f" "previewServer" ];
haskellPackages = pkgs.haskell.packages.${compiler}.override {
overrides = hpNew: hpOld: {
hakyll =
pipe
hpOld.hakyll
[
(flip appendPatch ./hakyll.patch)
(flip appendConfigureFlags hakyllFlags)
];
hakyll-nix-template = hpNew.callCabal2nix "hakyll-nix-template" ./. { };
# when hakyll is marked as broken in nixpkgs
# because of version issues, fix them here:
hslua = dontCheck (hpNew.callHackage "hslua" "1.0.3.2" { });
jira-wiki-markup = dontCheck (hpNew.callHackage "jira-wiki-markup" "1.1.4" { });
pandoc = dontCheck (hpNew.callHackage "pandoc" "2.9.2.1" { });
pandoc-types = dontCheck (hpNew.callHackage "pandoc-types" "1.20" { });
};
};
in
haskellPackages

View File

@ -1,21 +0,0 @@
let
cfg = import ../nix/default.nix { };
hp = cfg.haskellPackages;
in
{}:
hp.shellFor {
packages = p: [
p.hakyll-nix-template
];
buildInputs = with hp; [
cabal-install
ghcid
hlint
hp.hakyll-nix-template
ormolu
];
withHoogle = true;
}

66
haskell-overlay.nix Normal file
View File

@ -0,0 +1,66 @@
final: prev:
let
inherit (prev.stdenv) mkDerivation;
inherit (prev.lib.trivial) flip pipe;
inherit (prev.haskell.lib)
appendPatch
appendConfigureFlags
dontCheck
doJailbreak;
withPatch = flip appendPatch;
withFlags = flip appendConfigureFlags;
haskellCompiler = "ghc884";
in {
myHaskellPackages = prev.haskell.packages.${haskellCompiler}.override {
overrides = hpFinal: hpPrev:
let
hakyll-src = hpPrev.callHackage "hakyll" "4.14.0.0" {};
pandoc-src = hpPrev.callHackage "pandoc" "2.11.4" {}; # version specified by hayll 4.14.0.0
in rec {
hakyll = pipe hakyll-src [
doJailbreak
dontCheck
(withPatch ./hakyll.patch)
(withFlags [ "-f" "watchServer" "-f" "previewServer" ])
];
pandoc = pipe pandoc-src [
doJailbreak
dontCheck
];
ssg = hpPrev.callCabal2nix "ssg" ./ssg {};
website = prev.stdenv.mkDerivation {
#__contentAddressed = true; # uncomment if using cas: https://www.tweag.io/blog/2020-09-10-nix-cas/
name = "website";
buildInputs = [ ssg ];
src = prev.nix-gitignore.gitignoreSourcePure [
./.gitignore
".git"
".github"
] ./.;
# LANG and LOCALE_ARCHIVE are fixes pulled from the community:
# https://github.com/jaspervdj/hakyll/issues/614#issuecomment-411520691
# https://github.com/NixOS/nix/issues/318#issuecomment-52986702
# https://github.com/MaxDaten/brutal-recipes/blob/source/default.nix#L24
LANG = "en_US.UTF-8";
LOCALE_ARCHIVE = prev.lib.optionalString
(prev.buildPlatform.libc == "glibc")
"${prev.glibcLocales}/lib/locale/locale-archive";
buildPhase = ''
hakyll-site build --verbose
'';
installPhase = ''
mkdir -p "$out/dist"
cp -r dist/* "$out/dist"
'';
};
};
};
}

View File

@ -1,44 +0,0 @@
let
sources = import ./sources.nix;
config = { allowBroken = true; };
in
{ pkgs ? import sources.nixpkgs { inherit config; } }:
let
pre-commit-hooks = import sources."pre-commit-hooks.nix";
haskellPackages = pkgs.callPackage ../generator/hpkgs.nix {};
generator = haskellPackages.callPackage ../generator/default.nix {};
src = ../src;
in
{
inherit generator haskellPackages pkgs src;
tools = [
# uncomment pkgs.cacert & pkgs.nix if nix-shell --pure
# (https://github.com/nmattia/niv/issues/222)
#pkgs.cacert
#pkgs.nix
generator
pkgs.niv
pkgs.pre-commit
pre-commit-hooks.hlint
pre-commit-hooks.nixpkgs-fmt
pre-commit-hooks.ormolu
];
ci = {
pre-commit-check = pre-commit-hooks.run {
inherit src;
hooks = {
hlint.enable = true;
nix-linter.enable = true;
nixpkgs-fmt.enable = true;
ormolu.enable = true;
shellcheck.enable = true;
};
excludes = [ "^nix/sources\.nix$" ];
};
};
}

View File

@ -1,38 +0,0 @@
{
"niv": {
"branch": "master",
"description": "Easy dependency management for Nix projects",
"homepage": "https://github.com/nmattia/niv",
"owner": "nmattia",
"repo": "niv",
"rev": "20c899271f288d33114760bc298838575fc6c7f9",
"sha256": "07zswk6dhlydihl9g6skmy52grjvqpra8r98f2dmbgwzc1yhjhxq",
"type": "tarball",
"url": "https://github.com/nmattia/niv/archive/20c899271f288d33114760bc298838575fc6c7f9.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"nixpkgs": {
"branch": "nixos-20.09",
"description": "A read-only mirror of NixOS/nixpkgs tracking the released channels. Send issues and PRs to",
"homepage": "https://github.com/NixOS/nixpkgs",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "edb26126d98bc696f4f3e206583faa65d3d6e818",
"sha256": "1cl4ka4kk7kh3bl78g06dhiidazf65q8miyzaxi9930d6gwyzkci",
"type": "tarball",
"url": "https://github.com/nixos/nixpkgs/archive/edb26126d98bc696f4f3e206583faa65d3d6e818.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"pre-commit-hooks.nix": {
"branch": "master",
"description": "Seamless integration of https://pre-commit.com git hooks with Nix.",
"homepage": "",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "117579f3cfe4c0abeff70631fa31261d5ea99cfd",
"sha256": "1bjvadx76rlf54b43agfx1w35wqpagzihdv2yy0jsrk1glxc15ax",
"type": "tarball",
"url": "https://github.com/cachix/pre-commit-hooks.nix/archive/117579f3cfe4c0abeff70631fa31261d5ea99cfd.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}

View File

@ -1,148 +0,0 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file = pkgs: spec:
if spec.builtin or true then
builtins_fetchurl { inherit (spec) url sha256; }
else
pkgs.fetchurl { inherit (spec) url sha256; };
fetch_tarball = pkgs: name: spec:
let
ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
# sanitize the name, though nix will still fail if name starts with period
name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
in
if spec.builtin or true then
builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
else
pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
fetch_git = spec:
builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };
fetch_local = spec: spec.path;
fetch_builtin-tarball = name: throw
''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=tarball -a builtin=true'';
fetch_builtin-url = name: throw
''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=file -a builtin=true'';
#
# Various helpers
#
# The set of packages used when specs are fetched using non-builtins.
mkPkgs = sources:
let
sourcesNixpkgs =
import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources
then sourcesNixpkgs
else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
import <nixpkgs> {}
else
abort
''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch = pkgs: name: spec:
if ! builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then fetch_file pkgs spec
else if spec.type == "tarball" then fetch_tarball pkgs name spec
else if spec.type == "git" then fetch_git spec
else if spec.type == "local" then fetch_local spec
else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
else if spec.type == "builtin-url" then fetch_builtin-url name
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# If the environment variable NIV_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
replace = name: drv:
let
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
in
if ersatz == "" then drv else ersatz;
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs = builtins.mapAttrs or (
f: set: with builtins;
listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatStrings = builtins.concatStringsSep "";
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball = { url, name, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball { inherit name url; }
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl = { url, sha256 }@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl { inherit url; }
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources = config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec
then abort
"The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = replace name (fetch config.pkgs name spec); }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{ sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
, sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
, pkgs ? mkPkgs sources
}: rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

View File

@ -1,14 +0,0 @@
let
sources = import ./nix/sources.nix;
in
{ pkgs ? import sources.nixpkgs {} }:
let
cfg = import ./nix/default.nix {};
in
pkgs.mkShell {
buildInputs = cfg.tools;
shellHook = ''
${cfg.ci.pre-commit-check.shellHook}
'';
}

View File

@ -1,44 +0,0 @@
:root {
font-size: 62.5%;
box-sizing: border-box;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
html,
body {
min-height: 100vh;
}
body {
font-kerning: normal;
-moz-font-feature-settings: "kern", "liga", "clig", "calt";
-ms-font-feature-settings: "kern", "liga", "clig", "calt";
-webkit-font-feature-settings: "kern", "liga", "clig", "calt";
font-feature-settings: "kern", "liga", "clig", "calt";
scroll-behavior: smooth;
}
article h1,
article small,
article p {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
article h1 {
font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif;
font-size: 4.0rem;
}
article small,
article p {
font-family: Tahoma, Arial, sans-serif;
}
article small {
font-size: 1.6rem;
font-style: italic;
}
article p {
font-size: 1.8rem;
}

View File

@ -20,11 +20,35 @@ body {
-webkit-font-feature-settings: "kern", "liga", "clig", "calt";
font-feature-settings: "kern", "liga", "clig", "calt";
scroll-behavior: smooth;
font-size: 2rem;
}
body,
input,
button {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1,
h2 {
font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif;
}
h1 {
font-size: 4.0rem;
}
h2 {
font-size: 2.6rem;
}
small,
p {
font-family: Tahoma, Arial, sans-serif;
}
small {
font-size: 1.6rem;
font-style: italic;
}
p {
font-size: 1.8rem;
}
pre.sourceCode {
padding: 2rem 1.5rem;
}
.ffs { font-family: "Palatino Linotype", "Book Antiqua", Palatino, serif; }
.ffss { font-family: Tahoma, Arial, sans-serif; }
.fs { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
.fs14 { font-size: 1.4rem; }
.fs18 { font-size: 1.8rem; }
.fs32 { font-size: 3.2rem; }
.fs40 { font-size: 4.0rem; }

View File

@ -7,7 +7,7 @@ title: "Hello, world!"
---
<header>
<h1 class="ffs fs fs40">Hello, world!</h1>
<h1>Hello, world!</h1>
<img
alt="A woman sitting on a bench amongst trees at the end of a boardwalk leading to a pond with mountains in the background"
src="./images/robert-pearce-UwHN0jU_YqQ-unsplash-800w.jpg"
@ -16,12 +16,12 @@ title: "Hello, world!"
</header>
<main>
<section>
<h2 class="ffs fs fs32">Blog Posts</h2>
<h2>Blog Posts</h2>
<ul>
$for(posts)$
<li>
<div><a href=".$url$" class="ffss fs fs18">$title$</a></div>
<small class="ffss fs fs14">$date$</small>
<div><a href=".$url$">$title$</a></div>
<small>$date$</small>
</li>
$endfor$
</ul>

View File

@ -5,7 +5,6 @@ desc: "I announce myself to the world"
image: "./images/waiheke-stony-batter.jpg"
keywords: "hello, announcement"
lang: "en"
stylesheet: "article"
title: "Hello, world!"
updated: "2020-09-22T12:00:00Z"
---
@ -17,3 +16,11 @@ Hello, world! I am here!
src="./images/waiheke-stony-batter.jpg"
style="max-width:500px;"
/>
Haskell, for example:
```haskell
toSlug :: T.Text -> T.Text
toSlug =
T.intercalate (T.singleton '-') . T.words . T.toLower . clean
```

View File

@ -5,7 +5,6 @@ desc: "Me anuncio al mundo"
image: "./images/waiheke-stony-batter.jpg"
keywords: "hola, anuncio"
lang: "es"
stylesheet: "article"
title: "¡Hola Mundo!"
updated: "2020-09-23T12:00:00Z"
---
@ -17,3 +16,11 @@ updated: "2020-09-23T12:00:00Z"
src="./images/waiheke-stony-batter.jpg"
style="max-width:500px;"
/>
Haskell, por ejemplo:
```haskell
toSlug :: T.Text -> T.Text
toSlug =
T.intercalate (T.singleton '-') . T.words . T.toLower . clean
```

View File

@ -40,9 +40,7 @@
<link rel="shortcut icon" href="/favicon.ico">
<link rel="canonical" href="$root$$url$">
<link rel="stylesheet" href="./css/default.css" />
$if(stylesheet)$
<link rel="stylesheet" href="./css/$stylesheet$.css" />
$endif$
<link rel="stylesheet" href="./css/code.css" />
</head>
<body>
$body$

29
ssg/LICENSE Normal file
View File

@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2020, Robert Pearce
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -9,18 +9,19 @@ import Text.Pandoc
( Extension (Ext_fenced_code_attributes, Ext_footnotes, Ext_gfm_auto_identifiers, Ext_implicit_header_references, Ext_smart),
Extensions,
ReaderOptions,
WriterOptions,
WriterOptions (writerHighlightStyle),
extensionsFromList,
githubMarkdownExtensions,
readerExtensions,
writerExtensions,
)
import Text.Pandoc.Highlighting (Style, breezeDark, styleToCss)
-- CONFIG
root :: String
root =
"https://rpearce.github.io/hakyll-nix-template"
"https://my-site.com"
siteName :: String
siteName =
@ -29,13 +30,13 @@ siteName =
config :: Configuration
config =
defaultConfiguration
{ destinationDirectory = "../dist",
{ destinationDirectory = "dist",
ignoreFile = const False,
previewHost = "127.0.0.1",
previewPort = 8000,
providerDirectory = "../src",
storeDirectory = "../hakyll-cache",
tmpDirectory = "../hakyll-cache/tmp"
providerDirectory = "src",
storeDirectory = "ssg/_cache",
tmpDirectory = "ssg/_tmp"
}
-- BUILD
@ -56,51 +57,75 @@ main = hakyllWith config $ do
$ \f -> match f $ do
route idRoute
compile copyFileCompiler
match "css/*" $ do
route idRoute
compile compressCssCompiler
match "posts/*" $ do
let ctx = constField "type" "article" <> postCtx
route $ metadataRoute titleRoute
compile $
pandocCompilerCustom
>>= loadAndApplyTemplate "templates/post.html" ctx
>>= saveSnapshot "content"
>>= loadAndApplyTemplate "templates/default.html" ctx
match "index.html" $ do
route idRoute
compile $ do
posts <- recentFirst =<< loadAll "posts/*"
let indexCtx =
listField "posts" postCtx (return posts)
<> constField "root" root
<> constField "siteName" siteName
<> defaultContext
getResourceBody
>>= applyAsTemplate indexCtx
>>= loadAndApplyTemplate "templates/default.html" indexCtx
match "templates/*" $
compile templateBodyCompiler
create ["sitemap.xml"] $ do
route idRoute
compile $ do
posts <- recentFirst =<< loadAll "posts/*"
let pages = posts
sitemapCtx =
constField "root" root
<> constField "siteName" siteName
<> listField "pages" postCtx (return pages)
makeItem ("" :: String)
>>= loadAndApplyTemplate "templates/sitemap.xml" sitemapCtx
create ["rss.xml"] $ do
route idRoute
compile (feedCompiler renderRss)
create ["atom.xml"] $ do
route idRoute
compile (feedCompiler renderAtom)
create ["css/code.css"] $ do
route idRoute
compile (makeStyle pandocHighlightStyle)
{- ORMOLU_ENABLE -}
-- COMPILER HELPERS
makeStyle :: Style -> Compiler (Item String)
makeStyle =
makeItem . compressCss . styleToCss
-- CONTEXT
feedCtx :: Context String
@ -165,8 +190,13 @@ pandocWriterOpts :: WriterOptions
pandocWriterOpts =
defaultHakyllWriterOptions
{ writerExtensions = pandocExtensionsCustom
, writerHighlightStyle = Just pandocHighlightStyle
}
pandocHighlightStyle :: Style
pandocHighlightStyle =
breezeDark -- https://hackage.haskell.org/package/pandoc/docs/Text-Pandoc-Highlighting.html
-- FEEDS
type FeedRenderer =

View File

@ -1,6 +1,6 @@
cabal-version: 2.4
name: hakyll-nix-template
name: ssg
version: 0.1.0.0
build-type: Simple
license: BSD-3-Clause
@ -10,10 +10,10 @@ executable hakyll-site
main-is: Main.hs
hs-source-dirs: src
build-depends: base == 4.*
, hakyll ^>= 4.13.3.0
, pandoc >= 2.0.5 && < 2.10
, text ^>= 1.2.4
, time >= 1.8 && < 1.10
, hakyll ^>= 4.14
, pandoc
, text
, time
other-modules: Slug
ghc-options: -Wall -threaded
default-language: Haskell2010