Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

オプションの振る舞いを HKD? で畳み込んで構築する #23

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 88 additions & 36 deletions app/Main.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Main where

Expand All @@ -23,44 +26,29 @@ import qualified Git
import Mix
import Mix.Plugin.Logger as MixLogger
import qualified Mix.Plugin.Shell as MixShell
import Options.Magic
import qualified ScrapBook
import System.Cron (addJob, execSchedule)
import qualified Version

main :: IO ()
main = withGetOpt' "[options] [input-file]" opts $ \r args usage ->
if | r ^. #help -> hPutBuilder stdout (fromString usage)
| r ^. #version -> hPutBuilder stdout (Version.build version)
| r ^. #daily -> runCmd r (listToMaybe args) `withCron` "0 8 * * *"
| r ^. #hourly -> runCmd r (listToMaybe args) `withCron` "0 * * * *"
| r ^. #minutely -> runCmd r (listToMaybe args) `withCron` "* * * * *"
| otherwise -> runCmd r (listToMaybe args)
main = withGetOpt' "[options] [input-file]" opts $ \r args ->
let cmdEnchantments = shrink r :: Record CmdEnchantments
defaultCmd = Cmd $ \_ -> runCmd r (listToMaybe args)
in exec (peel $ Continue defaultCmd `withEnchantment` cmdEnchantments)
where
opts = #help @= helpOpt
<: #version @= versionOpt
<: #verbose @= verboseOpt
<: #daily @= dailyOpt
<: #hourly @= hourlyOpt
<: #minutely @= minutelyOpt
<: #verbose @= verboseOpt
<: #skip @= skipOpt
<: #withCopy @= withCopyOpt
<: #withCommit @= withCommitOpt
<: #withPush @= withPushOpt
<: nil

type Options = Record
'[ "help" >: Bool
, "version" >: Bool
, "verbose" >: Bool
, "daily" >: Bool
, "hourly" >: Bool
, "minutely" >: Bool
, "skip" >: Bool
, "withCopy" >: Bool
, "withCommit" >: Bool
, "withPush" >: Bool
]

helpOpt :: OptDescr' Bool
helpOpt = optFlag ['h'] ["help"] "Show this help text"

Expand Down Expand Up @@ -91,6 +79,72 @@ withCommitOpt = optFlag [] ["with-commit"] "Create commit after generate HTML"
withPushOpt :: OptDescr' Bool
withPushOpt = optFlag [] ["with-push"] "Push commit after create commit"

type Options =
Record (CmdEnchantments ++ LogOptEnchantemnts ++ ActionEnchantments)

type CmdEnchantments =
'[ "help" >: Bool
, "version" >: Bool
, "daily" >: Bool
, "hourly" >: Bool
, "minutely" >: Bool
]

newtype Cmd = Cmd { exec :: String -> IO () }

instance Magic (Enchantment (Breakable Cmd)) ("help" >: Bool) where
magic _ = enchantmentIfTrue $ onlyOnce $ \_ ->
Cmd $ \usage -> hPutBuilder stdout (fromString usage)

instance Magic (Enchantment (Breakable Cmd)) ("version" >: Bool) where
magic _ = enchantmentIfTrue $ onlyOnce $ \_ ->
Cmd $ \_ -> hPutBuilder stdout (Version.build version)

instance Magic (Enchantment (Breakable Cmd)) ("daily" >: Bool) where
magic _ = enchantmentIfTrue $ onlyOnce $ \(Cmd cmd) ->
Cmd $ \x -> cmd x `withCron` "0 8 * * *"

instance Magic (Enchantment (Breakable Cmd)) ("hourly" >: Bool) where
magic _ = enchantmentIfTrue $ onlyOnce $ \(Cmd cmd) ->
Cmd $ \x -> cmd x `withCron` "0 * * * *"

instance Magic (Enchantment (Breakable Cmd)) ("minutely" >: Bool) where
magic _ = enchantmentIfTrue $ onlyOnce $ \(Cmd cmd) ->
Cmd $ \x -> cmd x `withCron` "* * * * *"

type LogOptEnchantemnts =
'[ "verbose" >: Bool
]

instance Magic (Enchantment MixLogger.MixLoggerConfig) ("verbose" >: Bool) where
magic _ = Enchantment . set #verbose

type ActionEnchantments =
'[ "skip" >: Bool
, "withCopy" >: Bool
, "withCommit" >: Bool
, "withPush" >: Bool
]

instance Magic (Enchantment (RIO Env ())) ("skip" >: Bool) where
magic _ = enchantmentIfTrue $ \_ -> pure ()

instance Magic (Enchantment (RIO Env ())) ("withCopy" >: Bool) where
magic _ = enchantmentIfTrue $ \act -> do
copyFilesByAnotherBranch
act

instance Magic (Enchantment (RIO Env ())) ("withCommit" >: Bool) where
magic _ = enchantmentIfTrue $ \act -> do
MixShell.exec (Git.pull [])
act
commitGeneratedFiles

instance Magic (Enchantment (RIO Env ())) ("withPush" >: Bool) where
magic _ = enchantmentIfTrue $ \act -> do
act
pushCommit

type Env = Record
'[ "logger" >: LogFunc
, "config" >: Config
Expand All @@ -102,20 +156,18 @@ runCmd _ Nothing = error "please input config file path."
runCmd opts (Just path) = do
config <- readConfig path
let plugin = hsequence
$ #logger <@=> MixLogger.buildPlugin logOpts
$ #logger <@=> MixLogger.buildPlugin logOpts'
<: #config <@=> pure config
<: #work <@=> pure "."
<: nil
Mix.run plugin $ do
when (opts ^. #withCommit) $ MixShell.exec (Git.pull [])
when (opts ^. #withCopy) $ copyFilesByAnotherBranch
when (not $ opts ^. #skip) $ generate path
when (opts ^. #withCommit) $ commitGeneratedFiles
when (opts ^. #withPush) $ pushCommit
Mix.run plugin $
generate path `withEnchantment` (shrink opts :: Record ActionEnchantments)
where
logOpts = #handle @= stdout
<: #verbose @= (opts ^. #verbose)
logOpts = #handle @= stdout
<: #verbose @= False
<: nil
logOpts' = logOpts `withEnchantment` (shrink opts :: Record LogOptEnchantemnts)


readConfig :: FilePath -> IO Config
readConfig = either (error . show) pure <=< Y.decodeFileEither
Expand Down
7 changes: 7 additions & 0 deletions lib/Options/Magic.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module Options.Magic
( module X
) where

import Options.Magic.Breakable as X
import Options.Magic.Enchantment as X
import Options.Magic.Internal as X
17 changes: 17 additions & 0 deletions lib/Options/Magic/Breakable.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Options.Magic.Breakable where

import RIO

data Breakable a = Break a | Continue a

instance Functor Breakable where
fmap f (Continue a) = Continue (f a)
fmap f (Break a) = Break (f a)

onlyOnce :: (a -> a) -> Breakable a -> Breakable a
onlyOnce f (Continue a) = Break (f a)
onlyOnce _ brk = brk

peel :: Breakable a -> a
peel (Break a) = a
peel (Continue a) = a
27 changes: 27 additions & 0 deletions lib/Options/Magic/Enchantment.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Options.Magic.Enchantment where

import RIO

import Data.Extensible
import Options.Magic.Internal (Magic (..))

newtype Enchantment a = Enchantment { enchantment :: a -> a }

withEnchantment ::
forall a xs . Forall (Magic (Enchantment a)) xs
=> a -> Record xs -> a
withEnchantment =
hfoldlWithIndexWith @ (Magic (Enchantment a))
(\m acc x -> enchantment (magic m (runIdentity $ getField x)) acc)

enchantmentIfTrue ::
(a -> a) -> Bool -> Enchantment a
enchantmentIfTrue _ False = Enchantment id
enchantmentIfTrue e True = Enchantment e
9 changes: 9 additions & 0 deletions lib/Options/Magic/Internal.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}

module Options.Magic.Internal where

import Data.Extensible

class Magic a kv where
magic :: proxy kv -> TargetOf kv -> a
4 changes: 3 additions & 1 deletion package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ default-extensions:
executables:
antenna:
main: Main.hs
source-dirs: app
source-dirs:
- app
- lib
dependencies:
- blaze-html
- cron
Expand Down