|
| 1 | +#!/usr/bin/env stack |
| 2 | +{- stack runghc |
| 3 | + --package rio |
| 4 | + --package conduit |
| 5 | + --package project-template |
| 6 | + -- -hide-all-packages |
| 7 | +-} |
| 8 | +{-# LANGUAGE NoImplicitPrelude #-} |
| 9 | +{-# LANGUAGE OverloadedStrings #-} |
| 10 | +{-# LANGUAGE RecordWildCards #-} |
| 11 | +import Conduit |
| 12 | +import RIO |
| 13 | +import qualified RIO.ByteString as B |
| 14 | +import qualified RIO.ByteString.Lazy as BL |
| 15 | +import RIO.FilePath |
| 16 | +import RIO.Process |
| 17 | +import qualified RIO.Text as T |
| 18 | +import qualified RIO.Text.Partial as T (replace) |
| 19 | +import RIO.Time |
| 20 | +import Text.ProjectTemplate |
| 21 | + |
| 22 | +data App = App |
| 23 | + { appLogFunc :: !LogFunc |
| 24 | + , appProcessContext :: !ProcessContext |
| 25 | + } |
| 26 | + |
| 27 | +instance HasLogFunc App where |
| 28 | + logFuncL = lens appLogFunc (\x y -> x { appLogFunc = y }) |
| 29 | +instance HasProcessContext App where |
| 30 | + processContextL = lens appProcessContext (\x y -> x { appProcessContext = y }) |
| 31 | + |
| 32 | +start :: RIO App a -> IO a |
| 33 | +start inner = do |
| 34 | + appProcessContext <- mkDefaultProcessContext |
| 35 | + lo <- logOptionsHandle stderr True |
| 36 | + withLogFunc lo $ \appLogFunc -> runRIO App {..} inner |
| 37 | + |
| 38 | +splitNulls :: ByteString -> [ByteString] |
| 39 | +splitNulls bs |
| 40 | + | B.null bs = [] |
| 41 | + | otherwise = |
| 42 | + let (x, y) = B.break (== 0) bs |
| 43 | + in x : splitNulls (B.drop 1 y) |
| 44 | + |
| 45 | +decode :: ByteString -> RIO App FilePath |
| 46 | +decode bs = |
| 47 | + case decodeUtf8' bs of |
| 48 | + Left e -> throwIO e |
| 49 | + Right x -> return $ T.unpack x |
| 50 | + |
| 51 | +readReplace :: MonadIO m => FilePath -> m ByteString |
| 52 | +readReplace fp = do |
| 53 | + (year, _, _) <- toGregorian . utctDay <$> getCurrentTime |
| 54 | + (encodeUtf8 . replaces year) <$> readFileUtf8 fp |
| 55 | + where |
| 56 | + replaces year |
| 57 | + = T.replace "PROJECTNAME" "{{name}}" |
| 58 | + . T.replace "AUTHOR" "{{author-name}}{{^author-name}}Author name here{{/author-name}}" |
| 59 | + . T.replace "MAINTAINER" "{{author-email}}{{^author-email}}example@example.com{{/author-email}}" |
| 60 | + . T.replace "GITHUB" "{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}" |
| 61 | + . T.replace "DESCRIPTION" "Please see the README on Github at <https://github.com/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}#readme>" |
| 62 | + . T.replace "COPYRIGHT" |
| 63 | + (T.concat |
| 64 | + [ "{{copyright}}{{^copyright}}{{year}}{{^year}}" |
| 65 | + , T.pack $ show year |
| 66 | + , "{{/year}} {{author-name}}{{^author-name}}Author name here{{/author-name}}{{/copyright}}" |
| 67 | + ]) |
| 68 | + |
| 69 | +main :: IO () |
| 70 | +main = start $ do |
| 71 | + let templatedir = "template" |
| 72 | + |
| 73 | + -- Make sure it passes |
| 74 | + proc "stack" ["test"] runProcess_ |
| 75 | + |
| 76 | + rawout <- withWorkingDir templatedir |
| 77 | + $ proc "git" ["ls-files", "-z"] |
| 78 | + readProcessStdout_ |
| 79 | + files <- mapM decode $ splitNulls $ BL.toStrict rawout |
| 80 | + let src = forM_ files $ \fp -> yield (fp, readFileBinary $ templatedir </> fp) |
| 81 | + runConduitRes $ src .| createTemplate .| sinkFile "rio.hsfiles" |
0 commit comments