@@ -15,7 +15,7 @@ Haskell-jpのコンテンツの一つとして[Haskell Antenna](https://haskell.
15
15
16
16
[ 2019年の今頃、これを自動毎時更新しようと Drone Cloudによる毎時更新を設定しました] ( https://haskell.jp/blog/posts/2019/hourly-antenna.html ) 。
17
17
18
- しかし。。。なんと3月ぐらいからこれが止まっています(どうやら、Drone Cloudのこの機能を利用してマイニングをした人がいたらしく止めてしまったようです )。
18
+ しかし。。。なんと3月ぐらいからこれが止まっています(どうやら、[ Drone Cloudのこの機能を利用してマイニングをした人がいたらしく止めてしまった ] ( https://discourse.drone.io/t/cron-on-cloud-drone-io/3899/2 ) ようです )。
19
19
現在は** 僕がだいたい毎朝1回、手動でCIを回しています** 。。。
20
20
21
21
ずっとなんとかしなきゃなぁと思い続けてはや9ヶ月。
@@ -24,14 +24,14 @@ Haskell-jpのコンテンツの一つとして[Haskell Antenna](https://haskell.
24
24
25
25
# どうするか?
26
26
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プログラムを仕込んでおけば良いではないかということに気づきました 。
29
29
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か何かで毎時実行すればいいんですけど
32
32
33
- 1 . cronとDockerの組み合わせが割とめんどくさい(antenna は Docker Image として提供している )
34
- 2 . cronにした場合更新を GitHub にどうやってプッシュしようかなどを考えるのがめんどくさい
33
+ 1 . cronとDockerの組み合わせが割とめんどくさい(antennaはDocker Imageとして提供している )
34
+ 2 . cronにした場合更新をGitHubにどうやってプッシュしようかなどを考えるのがめんどくさい
35
35
36
36
という問題があります。
37
37
@@ -40,17 +40,17 @@ Haskell Antenna自体はGitHub Pagesであり、HTMLなどは [haskell-jp/antenn
40
40
41
41
# 実装する
42
42
43
- antennaプログラムに「gitコマンドを読んでGitHubリポジトリに更新をプッシュする機能 」と「全てを毎時実行する機能」の2つを組み込む必要があります。
43
+ antennaプログラムに「gitコマンドを使ってGitHubリポジトリに更新をプッシュする機能 」と「全てを毎時実行する機能」の2つを組み込む必要があります。
44
44
ここで後方互換性を維持するために、これらはオプションでオンする機能にしましょう。
45
45
なのでまずは、antenna CLIアプリケーションのオプションを整理するところから始めます。
46
46
47
47
## オプションの整理
48
48
49
- 改修前の antenna は特別オプションを持っていません 。
49
+ 改修前のantennaはオプションを持っていません 。
50
50
` getArgs ` で引数(設定ファイルのパス)を受け取るだけです
51
51
52
52
``` haskell
53
- import System.Environment (getArgs )
53
+ import System.Environment (getArgs )
54
54
55
55
-- generate 関数が設定から HTML ファイル群を生成する IO アクション
56
56
main :: IO ()
@@ -63,7 +63,6 @@ main = (listToMaybe <$> getArgs) >>= \case
63
63
64
64
``` haskell
65
65
-- withGetOpt' は usage を独自で扱えるように拡張した Data.Extensible.withGetOpt です
66
- -- runCmd 関数が内部で runCmd を呼び出します
67
66
main :: IO ()
68
67
main = withGetOpt' " [options] [input-file]" opts $ \ r args usage ->
69
68
if | r ^. # help -> hPutBuilder stdout (fromString usage)
@@ -93,18 +92,38 @@ verboseOpt = optFlag ['v'] ["verbose"] "Enable verbose mode: verbosity level \"d
93
92
94
93
差分全体はこの[ PR] ( https://github.com/haskell-jp/antenna/pull/20 ) で確認することができます。
95
94
興味のある人はみてみてください。
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 () ` のボイラーテンプレートを減らしています(実はおいおい役に立ちます)。
97
117
98
118
## git コマンドを呼ぶ
99
119
100
- Haskellアプリケーションからgitコマンドを実行するにはShellyを使うことにします 。
101
- そこで、mix .hsのshellプラグインを使うことで簡単に実装することができます。
120
+ Haskellアプリケーションからgitコマンドを実行するには [ Shelly ] ( https://hackage.haskell.org/package/shelly ) を使うことにします 。
121
+ Shellyはmix .hsのshellプラグインを使うことで簡単に実装することができます。
102
122
まずはコミットを作る部分を実装しましょう
103
123
104
124
``` haskell
105
125
import qualified Git -- 自作Shelly製gitコマンド関数群
106
- import Mix
107
- import qualified Mix.Plugin.Shell as MixShell
126
+ import qualified Mix.Plugin.Shell as MixShell
108
127
109
128
runCmd :: Options -> Maybe FilePath -> IO ()
110
129
runCmd opts (Just path) = do
@@ -133,7 +152,7 @@ commitGeneratedFiles = do
133
152
```
134
153
135
154
全ての差分はこの[ 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 ` を追加しています)。
137
156
mix.hsのshellプラグインを使うことでShellyのログをだいたいそれっぽくrioのロガーに流してくれます。
138
157
139
158
次に、` git push ` も実装します
@@ -156,16 +175,16 @@ pushCommit = do
156
175
157
176
前から使っている ` gitConfig ` は設定ファイルからgitコマンドに関する設定を取ってきています(例えば、どのファイルをコミットするかやどのブランチにプッシュするかなど)。
158
177
159
- 差分があった場合は` git commit ` を実行し、最後に` git push ` するようなオプション、` --with-commit ` と` --with-push ` を実装できました(他にも実装していますが割愛)。
178
+ これで、 差分があった場合は` git commit ` を実行し、最後に` git push ` するようなオプション、` --with-commit ` と` --with-push ` を実装できました(他にも実装していますが割愛)。
160
179
161
180
## 毎時実行
162
181
163
182
メインディッシュである毎時実行です。
164
- Haskell-jp Slackで、スケジューリング実行をHaskellアプリケーション内で行うのにちょうど良いパッケージはありますか?と尋ねたところcronというパッケージを紹介してもらいました (名前がややこしい笑)。
183
+ Haskell-jp Slackで、スケジューリング実行をHaskellアプリケーション内で行うのにちょうど良いパッケージはありますか?と尋ねたところ [ cron ] ( https://hackage.haskell.org/package/cron ) というパッケージを紹介してもらいました (名前がややこしい笑)。
165
184
調べてみたところ、ちょうど良さそうなのでこれを使うことにします
166
185
167
186
``` haskell
168
- import System.Cron (addJob , execSchedule )
187
+ import System.Cron (addJob , execSchedule )
169
188
170
189
main :: IO ()
171
190
main = withGetOpt' " [options] [input-file]" opts $ \ r args usage ->
@@ -184,10 +203,11 @@ withCron act t = do
184
203
185
204
全ての差分はこの[ PR] ( https://github.com/haskell-jp/antenna/pull/22 ) から確認できます。
186
205
すっごい簡単ですね。
187
-
188
206
ついでに、毎日実行と毎分実行するオプションも追加しています。
189
207
190
- # インスタンスを起動する
208
+ これでアプリケーションの方は出来上がったので、こいつをGCEインスタンスで動作させてみましょう。
209
+
210
+ # インスタンスで起動する
191
211
192
212
まずはGCP Consoleからインスタンス作成します。
193
213
構成は次の通りです
@@ -200,7 +220,7 @@ withCron act t = do
200
220
GCP ConsoleからSSHして、docker コマンドをインストールします(やり方は[ 公式サイト] ( https://docs.docker.com/install/linux/docker-ce/ubuntu/ ) のをそのまま)。
201
221
ここまでできたら試しに ` sudo docker pull haskelljp/antenna ` して最新のイメージを取得してみましょう。
202
222
203
- 次に、GitHubにプッシュするためにSSH Keyを生成してデプロイキーを haskell-jp/Antenna に設定します 。
223
+ 次に、GitHubにプッシュするためにSSH Keyを生成してデプロイキーを haskell-jp/antenna リポジトリに設定します 。
204
224
できたら適当に
` git clone [email protected] :haskell-jp/antenna.git ` してブランチを
` gh-pages ` に切り替えます。
205
225
206
226
あとは次のコマンドでantennaプログラムを実行するだけです
0 commit comments