From 7ae181e09835a38d88990f18b8f0ed42835959ee Mon Sep 17 00:00:00 2001 From: Igor Pashev Date: Mon, 7 Oct 2019 16:38:46 +0200 Subject: Initial commit --- compiler/cabal.project | 2 + compiler/default.nix | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ compiler/site/Main.hs | 86 +++++++++++++++++++++++++++++++++++++++++++ compiler/site/Rules.hs | 54 +++++++++++++++++++++++++++ compiler/site/site.cabal | 16 ++++++++ 5 files changed, 254 insertions(+) create mode 100644 compiler/cabal.project create mode 100644 compiler/default.nix create mode 100644 compiler/site/Main.hs create mode 100644 compiler/site/Rules.hs create mode 100644 compiler/site/site.cabal (limited to 'compiler') diff --git a/compiler/cabal.project b/compiler/cabal.project new file mode 100644 index 0000000..37b8053 --- /dev/null +++ b/compiler/cabal.project @@ -0,0 +1,2 @@ +packages: ./*/*.cabal + diff --git a/compiler/default.nix b/compiler/default.nix new file mode 100644 index 0000000..b9bd640 --- /dev/null +++ b/compiler/default.nix @@ -0,0 +1,96 @@ +{ boot ? import {} }: + +let + + filtFn = root: path: type: + let + name = baseNameOf path; + hidden = builtins.match "\\..+" name != null; + nix = builtins.match ".*\\.nix" name != null; + r = !hidden && !nix ; + in builtins.trace (path + ": " + (if r then "yes" else "no")) r; + + fltsrc = builtins.filterSource (filtFn (builtins.toPath ./. + "/")); + + nixpkgs = boot.pkgs.fetchFromGitHub { + owner = "NixOS"; + repo = "nixpkgs"; + rev = "897ec814c9c234f3ed9d60a1a713025d2f9fab2d"; + sha256 = "0alg5h5zmxdrnfdj94fa4yr5g7j7z3424k78aq44r0a0aqm20iy5"; + }; + + config = { + allowUnfree = true; # for local packages + allowBroken = true; # some nixpkgs' nonsense + }; + + inherit (import nixpkgs { inherit config; }) pkgs; + inherit (pkgs) lib; + + nixHaskellPackages = + let + isnix = n: _: null != builtins.match ".*\\.nix" n && n != "default.nix"; + files = lib.filterAttrs isnix (builtins.readDir ./.); + in lib.mapAttrs' (n: _: + { name = lib.removeSuffix ".nix" n; + value = ./. + "/${n}"; + }) files; + + localHaskellPackages = + let + islocal = n: t: !lib.hasPrefix "." n && t == "directory"; + files = lib.filterAttrs islocal (builtins.readDir ./.); + in lib.mapAttrs (n: _: fltsrc (./. + "/${n}")) files; + + haskellPackages = + let + + hlib = pkgs.haskell.lib; + + set0 = pkgs.haskell.packages.ghc865; + + set1 = set0.extend ( + self: super: + lib.mapAttrs (_: f: super.callPackage f {}) nixHaskellPackages + ); + + set2 = set1.extend ( + self: super: + lib.mapAttrs (n: d: super.callCabal2nix n d {}) localHaskellPackages + ); + + set3 = set2.extend ( + self: super: { + mkDerivation = drv: super.mkDerivation (drv // { + buildTools = (drv.buildTools or []); + + # XXX a lot of troubles are cause by tests which require fancy packages of features. + # XXX Enable tests for critical packages when unsure. + doCheck = false; + + doHaddock = false; + + enableExecutableProfiling = false; + enableLibraryProfiling = false; + }); + + primitive = self.primitive_0_7_0_0; + primitive-extras = self.primitive-extras_0_8; + + }); + + set = set3.extend ( + self: super: + lib.mapAttrs (n: _: + hlib.overrideCabal super.${n} (drv: + { + doCheck = true; + configureFlags = (drv.configureFlags or []) ++ [ + "--ghc-option=-Werror" + ]; + }) + ) localHaskellPackages); + + in set; + +in haskellPackages diff --git a/compiler/site/Main.hs b/compiler/site/Main.hs new file mode 100644 index 0000000..e7fb92f --- /dev/null +++ b/compiler/site/Main.hs @@ -0,0 +1,86 @@ +module Main + ( main + ) where + +import Control.Applicative ((<**>)) +import System.Exit (exitWith) + +import qualified Options.Applicative as O +import System.FilePath (()) + +import qualified Hakyll.Commands as Cmd +import qualified Hakyll.Core.Configuration as Conf +import qualified Hakyll.Core.Logger as Logger + +import Rules (rules) + +data Command + = Build + | Clean + | Check Cmd.Check + +parseCheck :: O.Parser Cmd.Check +parseCheck = + O.flag + Cmd.InternalLinks + Cmd.All + (O.long "all" <> O.short 'a' <> O.help "Check external links as well") + +parseCommand :: O.Parser Command +parseCommand = + O.subparser $ + O.command "build" (O.info (pure Build) (O.progDesc "Build the site")) <> + O.command "clean" (O.info (pure Clean) (O.progDesc "Clean")) <> + O.command + "check" + (O.info ((Check <$> parseCheck) <**> O.helper) (O.progDesc "Check links")) + +data Options = Options + { verbose :: Bool + , outDir :: FilePath + , srcDir :: FilePath + , cacheDir :: FilePath + , command :: Command + } + +parseOptions :: O.Parser Options +parseOptions = + Options <$> + O.switch (O.long "verbose" <> O.short 'v' <> O.help "Run in verbose mode") <*> + O.strOption + (O.long "output" <> O.short 'o' <> O.metavar "DIR" <> O.showDefault <> + O.value (Conf.destinationDirectory Conf.defaultConfiguration) <> + O.help "Output directory") <*> + O.strOption + (O.long "source" <> O.short 's' <> O.metavar "DIR" <> O.showDefault <> + O.value ("." "src") <> + O.help "Source directory") <*> + O.strOption + (O.long "cache" <> O.short 'c' <> O.metavar "DIR" <> O.showDefault <> + O.value (Conf.storeDirectory Conf.defaultConfiguration) <> + O.help "Cache directory") <*> + parseCommand + +main :: IO () +main = do + opts <- + O.execParser + (O.info + (parseOptions <**> O.helper) + (O.fullDesc <> O.header "Static site compiler")) + let conf = + Conf.defaultConfiguration + { Conf.destinationDirectory = outDir opts + , Conf.providerDirectory = srcDir opts + , Conf.storeDirectory = cacheDir opts + , Conf.tmpDirectory = cacheDir opts "tmp" + } + log <- + Logger.new + (if verbose opts + then Logger.Debug + else Logger.Message) + case command opts of + Build -> Cmd.build conf log rules >>= exitWith + Clean -> Cmd.clean conf log + Check chk -> Cmd.check conf log chk >>= exitWith diff --git a/compiler/site/Rules.hs b/compiler/site/Rules.hs new file mode 100644 index 0000000..0cbf772 --- /dev/null +++ b/compiler/site/Rules.hs @@ -0,0 +1,54 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Rules + ( rules + ) where + +import Hakyll + +postCtx :: Context String +postCtx = dateField "date" "%B %e, %Y" <> defaultContext + +rules :: Rules () +rules = do + match "images/*" $ do + route idRoute + compile copyFileCompiler + match "css/*" $ do + route idRoute + compile compressCssCompiler + match (fromList ["about.rst", "contact.markdown"]) $ do + route $ setExtension "html" + compile $ + pandocCompiler >>= + loadAndApplyTemplate "templates/default.html" defaultContext >>= + relativizeUrls + match "posts/*" $ do + route $ setExtension "html" + compile $ + pandocCompiler >>= loadAndApplyTemplate "templates/post.html" postCtx >>= + loadAndApplyTemplate "templates/default.html" postCtx >>= + relativizeUrls + create ["archive.html"] $ do + route idRoute + compile $ do + posts <- recentFirst =<< loadAll "posts/*" + let archiveCtx = + listField "posts" postCtx (return posts) <> + constField "title" "Archives" <> + defaultContext + makeItem "" >>= loadAndApplyTemplate "templates/archive.html" archiveCtx >>= + loadAndApplyTemplate "templates/default.html" archiveCtx >>= + relativizeUrls + match "index.html" $ do + route idRoute + compile $ do + posts <- recentFirst =<< loadAll "posts/*" + let indexCtx = + listField "posts" postCtx (return posts) <> + constField "title" "Home" <> + defaultContext + getResourceBody >>= applyAsTemplate indexCtx >>= + loadAndApplyTemplate "templates/default.html" indexCtx >>= + relativizeUrls + match "templates/*" $ compile templateBodyCompiler diff --git a/compiler/site/site.cabal b/compiler/site/site.cabal new file mode 100644 index 0000000..072e8f2 --- /dev/null +++ b/compiler/site/site.cabal @@ -0,0 +1,16 @@ +cabal-version: >=1.10 +name: site +version: 0.1.0.0 +build-type: Simple + +executable site + main-is: Main.hs + other-modules: + Rules + default-language: Haskell2010 + ghc-options: -threaded + build-depends: + base -any, + filepath -any, + hakyll >=4.10, + optparse-applicative -any -- cgit v1.2.3