Skip to content

Commit d43637f

Browse files
committed
refactor post
1 parent 90e9db2 commit d43637f

File tree

1 file changed

+43
-23
lines changed

1 file changed

+43
-23
lines changed

preprocessed-site/posts/2020/revenge-of-hourly-antenna.md

+43-23
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Haskell-jpのコンテンツの一つとして[Haskell Antenna](https://haskell.
1515

1616
[2019年の今頃、これを自動毎時更新しようと Drone Cloudによる毎時更新を設定しました](https://haskell.jp/blog/posts/2019/hourly-antenna.html)
1717

18-
しかし。。。なんと3月ぐらいからこれが止まっています(どうやら、Drone Cloudのこの機能を利用してマイニングをした人がいたらしく止めてしまったようです)。
18+
しかし。。。なんと3月ぐらいからこれが止まっています(どうやら、[Drone Cloudのこの機能を利用してマイニングをした人がいたらしく止めてしまった](https://discourse.drone.io/t/cron-on-cloud-drone-io/3899/2)ようです)。
1919
現在は**僕がだいたい毎朝1回、手動でCIを回しています**。。。
2020

2121
ずっとなんとかしなきゃなぁと思い続けてはや9ヶ月。
@@ -24,14 +24,14 @@ Haskell-jpのコンテンツの一つとして[Haskell Antenna](https://haskell.
2424

2525
# どうするか?
2626

27-
[GCPにはalways freeプランというのがあり](https://cloud.google.com/free/docs/gcp-free-tier?hl=ja#always-free)GCEインスタンスはf1-microであれば一台だけ無料です(2020/1現在)。
28-
これに、毎時実行して更新をプッシュする antenna プログラムを仕込んでおけば良いではないかということに気づきました
27+
[GCPにはalways freeプランというのがあり](https://cloud.google.com/free/docs/gcp-free-tier?hl=ja#always-free)GCEインスタンスの場合はf1-microであれば一台だけ無料です(2020/1現在)。
28+
これに、毎時実行して更新をプッシュするantennaプログラムを仕込んでおけば良いではないかということに気づきました
2929

30-
Haskell Antenna自体はGitHub Pagesであり、HTMLなどは [haskell-jp/antenna](https://github.com/haskell-jp/antenna) という Haskell製CLIアプリケーションで生成しています。
31-
これをcronか何かで毎時実行しても良いですが
30+
Haskell Antenna自体はGitHub Pagesであり、HTMLなどは[haskell-jp/antenna](https://github.com/haskell-jp/antenna)という Haskell製CLIアプリケーションで生成しています。
31+
これをcronか何かで毎時実行すればいいんですけど
3232

33-
1. cronとDockerの組み合わせが割とめんどくさい(antenna は Docker Image として提供している
34-
2. cronにした場合更新を GitHub にどうやってプッシュしようかなどを考えるのがめんどくさい
33+
1. cronとDockerの組み合わせが割とめんどくさい(antennaはDocker Imageとして提供している
34+
2. cronにした場合更新をGitHubにどうやってプッシュしようかなどを考えるのがめんどくさい
3535

3636
という問題があります。
3737

@@ -40,17 +40,17 @@ Haskell Antenna自体はGitHub Pagesであり、HTMLなどは [haskell-jp/antenn
4040

4141
# 実装する
4242

43-
antennaプログラムに「gitコマンドを読んでGitHubリポジトリに更新をプッシュする機能」と「全てを毎時実行する機能」の2つを組み込む必要があります。
43+
antennaプログラムに「gitコマンドを使ってGitHubリポジトリに更新をプッシュする機能」と「全てを毎時実行する機能」の2つを組み込む必要があります。
4444
ここで後方互換性を維持するために、これらはオプションでオンする機能にしましょう。
4545
なのでまずは、antenna CLIアプリケーションのオプションを整理するところから始めます。
4646

4747
## オプションの整理
4848

49-
改修前の antenna は特別オプションを持っていません
49+
改修前のantennaはオプションを持っていません
5050
`getArgs` で引数(設定ファイルのパス)を受け取るだけです
5151

5252
```haskell
53-
import System.Environment (getArgs)
53+
import System.Environment (getArgs)
5454

5555
-- generate 関数が設定から HTML ファイル群を生成する IO アクション
5656
main :: IO ()
@@ -63,7 +63,6 @@ main = (listToMaybe <$> getArgs) >>= \case
6363

6464
```haskell
6565
-- withGetOpt' は usage を独自で扱えるように拡張した Data.Extensible.withGetOpt です
66-
-- runCmd 関数が内部で runCmd を呼び出します
6766
main :: IO ()
6867
main = withGetOpt' "[options] [input-file]" opts $ \r args usage ->
6968
if | r ^. #help -> hPutBuilder stdout (fromString usage)
@@ -93,18 +92,38 @@ verboseOpt = optFlag ['v'] ["verbose"] "Enable verbose mode: verbosity level \"d
9392

9493
差分全体はこの[PR](https://github.com/haskell-jp/antenna/pull/20)で確認することができます。
9594
興味のある人はみてみてください。
96-
ついでに `runCmd` 関数は[mix.hs](https://github.com/matsubara0507/mix.hs)を使って `RIO env ()` のボイラーテンプレートを減らしています(実はおいおい役に立ちます)。
95+
`generate` 関数は以下の `runCmd` 関数から呼ばれています
96+
97+
```haskell
98+
import Mix
99+
import Mix.Plugin.Logger as MixLogger
100+
101+
runCmd :: Options -> Maybe FilePath -> IO ()
102+
runCmd _ Nothing = error "please input config file path."
103+
runCmd opts (Just path) = do
104+
config <- readConfig path
105+
let plugin = hsequence
106+
$ #logger <@=> MixLogger.buildPlugin logOpts
107+
<: #config <@=> pure config
108+
<: nil
109+
Mix.run plugin $ generate path
110+
where
111+
logOpts = #handle @= stdout
112+
<: #verbose @= (opts ^. #verbose)
113+
<: nil
114+
```
115+
116+
`runCmd` 関数は[mix.hs](https://github.com/matsubara0507/mix.hs)を使って `RIO env ()` のボイラーテンプレートを減らしています(実はおいおい役に立ちます)。
97117

98118
## git コマンドを呼ぶ
99119

100-
Haskellアプリケーションからgitコマンドを実行するにはShellyを使うことにします
101-
そこで、mix.hsのshellプラグインを使うことで簡単に実装することができます。
120+
Haskellアプリケーションからgitコマンドを実行するには[Shelly](https://hackage.haskell.org/package/shelly)を使うことにします
121+
Shellyはmix.hsのshellプラグインを使うことで簡単に実装することができます。
102122
まずはコミットを作る部分を実装しましょう
103123

104124
```haskell
105125
import qualified Git -- 自作Shelly製gitコマンド関数群
106-
import Mix
107-
import qualified Mix.Plugin.Shell as MixShell
126+
import qualified Mix.Plugin.Shell as MixShell
108127

109128
runCmd :: Options -> Maybe FilePath -> IO ()
110129
runCmd opts (Just path) = do
@@ -133,7 +152,7 @@ commitGeneratedFiles = do
133152
```
134153

135154
全ての差分はこの[PR](https://github.com/haskell-jp/antenna/pull/21)から確認できます。
136-
PRを見ればわかりますが、`runCmd` 関数に追記したのは `when (opts ^. #withCommit)` から始まる2行です(`Options``#withCommit` を追加しています)。
155+
`runCmd` 関数に追記したのは `when (opts ^. #withCommit)` から始まる2行です(`Options``#withCommit` を追加しています)。
137156
mix.hsのshellプラグインを使うことでShellyのログをだいたいそれっぽくrioのロガーに流してくれます。
138157

139158
次に、`git push`も実装します
@@ -156,16 +175,16 @@ pushCommit = do
156175

157176
前から使っている `gitConfig` は設定ファイルからgitコマンドに関する設定を取ってきています(例えば、どのファイルをコミットするかやどのブランチにプッシュするかなど)。
158177

159-
差分があった場合は`git commit`を実行し、最後に`git push`するようなオプション、`--with-commit``--with-push`を実装できました(他にも実装していますが割愛)。
178+
これで、差分があった場合は`git commit`を実行し、最後に`git push`するようなオプション、`--with-commit``--with-push`を実装できました(他にも実装していますが割愛)。
160179

161180
## 毎時実行
162181

163182
メインディッシュである毎時実行です。
164-
Haskell-jp Slackで、スケジューリング実行をHaskellアプリケーション内で行うのにちょうど良いパッケージはありますか?と尋ねたところcronというパッケージを紹介してもらいました(名前がややこしい笑)。
183+
Haskell-jp Slackで、スケジューリング実行をHaskellアプリケーション内で行うのにちょうど良いパッケージはありますか?と尋ねたところ[cron](https://hackage.haskell.org/package/cron)というパッケージを紹介してもらいました(名前がややこしい笑)。
165184
調べてみたところ、ちょうど良さそうなのでこれを使うことにします
166185

167186
```haskell
168-
import System.Cron (addJob, execSchedule)
187+
import System.Cron (addJob, execSchedule)
169188

170189
main :: IO ()
171190
main = withGetOpt' "[options] [input-file]" opts $ \r args usage ->
@@ -184,10 +203,11 @@ withCron act t = do
184203

185204
全ての差分はこの[PR](https://github.com/haskell-jp/antenna/pull/22)から確認できます。
186205
すっごい簡単ですね。
187-
188206
ついでに、毎日実行と毎分実行するオプションも追加しています。
189207

190-
# インスタンスを起動する
208+
これでアプリケーションの方は出来上がったので、こいつをGCEインスタンスで動作させてみましょう。
209+
210+
# インスタンスで起動する
191211

192212
まずはGCP Consoleからインスタンス作成します。
193213
構成は次の通りです
@@ -200,7 +220,7 @@ withCron act t = do
200220
GCP ConsoleからSSHして、docker コマンドをインストールします(やり方は[公式サイト](https://docs.docker.com/install/linux/docker-ce/ubuntu/)のをそのまま)。
201221
ここまでできたら試しに `sudo docker pull haskelljp/antenna` して最新のイメージを取得してみましょう。
202222

203-
次に、GitHubにプッシュするためにSSH Keyを生成してデプロイキーを haskell-jp/Antenna に設定します
223+
次に、GitHubにプッシュするためにSSH Keyを生成してデプロイキーを haskell-jp/antenna リポジトリに設定します
204224
できたら適当に `git clone [email protected]:haskell-jp/antenna.git` してブランチを `gh-pages` に切り替えます。
205225

206226
あとは次のコマンドでantennaプログラムを実行するだけです

0 commit comments

Comments
 (0)