weblog of key_amb

主にIT関連の技術メモ

"clenv" というシェルスクリプトのパッケージ管理ツールのようなものを作った

主に先月、開発していました。
いまバージョンは 0.1.12 です。

最近、久しぶりにやりかけだった機能拡張を進めようかと思ったのですが、拡張した機能を今後、自分自身でもあまり使うイメージが持てなくて、現状をひとまずこの記事にまとめておくことにしました。

目次:

clenv とは

シェルスクリプトのパッケージ管理システムがあったら、流行るんじゃないかという妄想があって、試しにちょっと作ってみた、という感じです。

今のところ、シェルスクリプトに限らず、コマンドラインで実行可能なファイルをまとめる用途には使えるかな、というぐらいのもので、実際に自分でも使っています。

できること:

  • $CLENV_ROOT/shims/ というパス配下にモジュールの実行ファイルの symlink を貼る
  • $CLENV_ROOT/environments/ に任意の名前で「環境」を作り、モジュール群をその「環境」にインストール

お察しかと思いますが、clenv という名前は rbenvplenv の類推です。

clam モジュール

clenv で利用されるモジュールを clam モジュールと呼ぶことにしました。

モジュールの形式としては「Git リポジトリ」か、「ローカル環境からアクセスできるファイルシステム内の特定ディレクトリ」のみサポートされています。
いずれの場合も、clam.spec というファイルをトップ階層に持つ必要があります。

拙作のシェルスクリプトテストツールである shove も、実はこの clam モジュール形式に対応しておりまして、その clam.spec は下のようになっています。

# bash
name=shove
version=0.7.2
executables=bin/shove
resources=lib/*

このファイルは clam という bash スクリプト内で評価されます。

clam スクリプトRubygem, Perlcpan コマンド相当です。

clam https://github.com/key-amb/shove.git を実行すると shoveclenv の環境下にインストールします。
デフォルトの default environment を使っている場合、$CLENV_ROOT/environments/ 以下のディレクトリ構成は以下のようになります。

~/.clenv/environments
└── default
    ├── Clamdb.txt
    ├── bin
    │   └── shove -> ~/.clenv/environments/default/modules/shove/bin/shove
    ├── lib
    │   ├── shove.bashrc -> ~/.clenv/environments/default/modules/shove/lib/shove.bashrc
    │   └── t.shrc -> ~/.clenv/environments/default/modules/shove/lib/t.shrc
    └── modules
        └── shove/ # モジュールのディレクトリが丸っとコピーされる

で、 ~/.clenv/environments/default/bin~/.clenv/shims に symlink されるので、 ~/.clenv/shims に PATH を通しておけば shove をパスなしで実行できる、というわけです。

clam を使う前に 〜 clenv セットアップ

順番が前後したのですが、上の clam の機能を使う前に clenv のセットアップが必要です。
README.md にも書いている通りですが、転記しておきます。

インストール:

git clone https://github.com/key-amb/clenv.git ~/.clenv

シェルの設定:

export CLENV_ROOT=$HOME/.clenv
export PATH="$HOME/.clenv/bin:$PATH"
export PATH="$HOME/.clenv/shims:$PATH"
. ${CLENV_ROOT}/shrc.d/clenv.shrc

初回はこれを .bashrc ないし .zshenv に書いて exec $SHELL -l を実行して下さい。
最後の . clenv.shrcclenv_switchclenv_use という2つのシェル関数をロードします。

環境の作成には clenv init-env [ENV] を実行します。(ENV のデフォルトは default)
これは $CLENV_ROOT/environments/ 以下に所定のディレクトリを作るだけです。

clenv_switch ENV で、~/.clenv/environments/ENV/bin~/.clenv/shims に symlink されます。
clenv_use ENV だと更に ~/.clenv/environments/ENV/lib/*シェルスクリプトとして現在のシェルに読み込みます。(が、この機能は要らないかなと思っていたりします。)

その他便利かもしれない使い方

Clamfile

RubyGemfile, Perlcpanfile 相当です。

モジュールをこのファイルに記述して clam -r Clamfile でまとめてインストールできます。
気になる方は README.md をご覧ください。

任意の実行ファイルを勝手に clam 化してインストール

「この実行ファイルに PATH を通したいから clenv 下に入れておきたい」というときに便利な使い方です。
単純にソースをローカルにダウンロードして clam.spec を記述すればいいです。

wget https://example.com/any-program.zip
unzip any-program.zip
cd any-program
cat <<EOS > clam.spec
name=any-program
version=0.x
executables=bin/*
EOS
clam . # インストール

こんな感じで any-program/bin/* 以下の実行ファイルに PATH を通せます。

clenv を作ってよかったこと

自分は割とリポジトリを細かく分ける性格で、小さな CLI を含むリポジトリがちらほらあります。
clenv 以前は、それらを submodule にまとめて管理していました。 その管理や、各環境で PATH を通す作業がやや面倒だったのですが、clenv + clam に移行して Clamfile だけの管理になったので、ちょっと楽になった気がします。

clam は消すのも簡単なので、ツールを試しに使うようなときに、とりあえず PATH を通しておくことも気軽にできます。

あれ、シェルスクリプトあんまり関係ない…?

そうなんです。
一応シェル・リソースをロードする機能もあるにはあるのですが、今のところ、「任意の実行ファイルをまとめる君」になっており、「シェルスクリプトのパッケージ管理ツール」としては不完全かな、と思います。

最初に考えていた構想では、シェル関数などを再利用しやすいようにしようなどの企てもあったのですが、今は手が止まってる感じです。
Bash でライブラリ関数的なものを作る気になったら、この構想も進めたい気持ちが高まるかもしれません。

Zsh だとけっこうプラグインがたくさんあって、プラグインの管理ツールもあるようなので、ひょっとしたらここで考えているようなことは実現されているかもしれませんね。

(そもそもシェル関数にしたいケースってけっこう限られそうだと最近思いました。その話はまた機会があれば。)

他に似たようなものないの?

シェルスクリプトのパッケージ管理システムとして見つけたのは下の2つです。

それぞれ、各々のフレームワークの中でモジュール化して再利用できそうな雰囲気ですが、さらっと眺めたところ、各々の形式に合わせてモジュール/パッケージを作らないといけなさそうな感じ。
自分が妄想しているものとは少し違うかなー、と思いました。

余談 〜 shove との関係

下の記事でもちらっと言及していましたが、shove を作ったのは、この clenv のテストを書くためでした。

おわりに

…というわけで、かなり個人用途な感じのツールですが、GitHub で公開していますので、ご利用・ツッコミなどご自由にどうぞ。

また、他に「こういうのあるよ」という情報をいただけましたら幸いに思います。

Enjoy!

アラートをまとめるシステム "poloxy" の v0.2 をリリースしました

前回の記事で紹介した poloxy をその後リリースして、本稿の執筆時点で v0.2.1 までバージョンが進みました。

※5/8 v0.3.1 になったので追記しました。

目次:

"poloxy" とは

繰り返しになるので詳しい説明は割愛しますが、スライドや README に載せている図を再掲しておきます。

f:id:key_amb:20160503224310p:plain

こんな感じで、アラートをまとめて通知してくれるものです。
まとめられたアラートの内容は Web Dashboard で確認できます。

Motivation

サーバサイドアプリケーションの開発・運用従事者の方は何かやらかしてアラートを大量に飛ばした経験はあるでしょうか。

私は、あります^^;

アラートがたくさん届くと心臓に悪いですね。
たくさんアラートが発火したとしても、1通にまとまって届いてくれたら安心ですね。

…というわけで、それをやってくれるものを作ってみた、というものです。

4/28 の西日暮里.rb で、発表スライドの3ページ目に「1時間に1000件以上アラートを受信したことがある人」という質問を入れていました。
発表中に聞いてみたところ、若干名いらっしゃったので、多少はニーズがあるかなと思っています。

Current Status (※5/8 追記アリ)

できた:

  • Web Dashboard
  • HTTP API
  • Worker
  • 送信
  • まとめる
    • 単位時間(1分程度。configで変更可能)に受信したアラートの品目単位
    • 単位時間に受信したアラートのグループ単位
    • 単位時間に受信したアラートの宛先(と送信タイプ)単位
  • (5/8 追加) アラートのスヌーズ ... 単位時間じゃなくて一定時間アラートを飛ばさなくする
    • 該当アラートと同じ (品目、グループ、深刻度) のアラートを message.default_snooze で設定した秒数(デフォルト30分)スヌーズします。

まだできてない:

  • SMTP 受信/中継
  • 古いデータのパージ機能
  • WebUI でのページング等

その他スライド発表時点から変更した点:

  • Redis キューを使わなくして、DB に統合しました

ドキュメントは今のところ README にざっと書いています。
config や curl のサンプルも載せているので、一応お試しいただけるかな、と思います。

Milestone

上の「まだできてない」に挙げていることは v1.0 リリースまでにはやろうと思っていることです。

趣味でやっていることもあり、いついつまでというのは特に決めてませんが。

試してみて「困った」など、何かフィードバックがありましたら、GitHub 等でお知らせ頂ければ幸いです。

(余談) Another Approach 〜 Fluentd との相似について

受信はさておき、送信は今後種類が増えるかもしれないので、Pluggable にしておいた方がよさそうです。
一応、それを見越して動的に各送信タイプの class をロードするようにしています。
そんなことを考えていたら、ふと「あれ、送信と受信があってなんだか Fluentd っぽい」と思った瞬間がありました。

ひょっとしたら、Daioikachan *1みたいに Fluentd の仕組みに乗っかった方が筋がよかっただろうか、とちょっと悩んでいたりします。

Fluentd の既存のプラグインでも、ログを間引いたり*2、suppression を入れたりできるもの*3はあるようなので、そっちのアプローチもアリだったかもしれません。

とはいえ、"poloxy" には Dashboard や DB が付いていたり、アラートのグルーピングなど独自な概念もあるので、Fluentd プラグイン化はやりすぎですかね。。

5/8 追記: AdminLTE という UI テンプレートについて

追記ついでに、AdminLTE について触れておきます。

自分にはフロントエンドをイチから作り込めるほどスキルも余裕もないので、Bootstrap ベースのテンプレートを使って、必要な部分だけカスタマイズする、という方針にしています。

"poloxy" の WebUI では、管理画面向けで多機能なテンプレートである AdminLTE を使ってみました。

その豊富な機能を使いこなすところまでは全然至っていませんが、作りたかった UI を割といい感じに整えることができたかなと思います。
いろいろパーツも揃っているので、便利です。

以前、はてブで上がっていた Gentellela *4でもいいかなと思いましたが、色調の好みでこちらにしました。

ドキュメンテーション用の Hugo のテーマ "bootie-docs" を改善しました #gohugo

Bootie Docs はちょうど一年前ぐらいにドキュメンテーション用の静的サイトジェネレータがほしくて作った Hugo*1 の Theme (テンプレート)です。
当時の記事はこちら:

色々イケてないところがあったので、GW 連休中にがっつり手を入れて、機能追加もしましたので、お知らせします。

ほとんど CHANGELOG に書いた内容に相当します。

※5/7 更に変更点有り、追記しました。

デフォルトアイコンがかっこ悪い

見るたびに気持ちが萎えていたので、パワーポイントでちょっと図形をいじって、こんな感じ になりました。
雰囲気おしゃれになったかなと。

依存コンポーネントを最新版にアップデートし、シンタックスハイライトのスタイルを選択可能に

Bootstrap と jQuery (v1系) と highlight.js を最新化しました。
highlight.js については、config.toml の params.highlightStyle という設定値で好みのスタイルを選べるようにしました。
どんなスタイルがあるかは こちら に highlight.js のデモページがありますので、ご参考まで。

サイトマップ的なページを作った

/index/ というパスで全ページリストを表示できるようにしました。
Hugo は自由にディレクトリを切ってページを階層化できるのですが、2段階までは階層表示できます。
やり方は Bootie Docs の マニュアルサイト をアップデートしていますので、こちらをご確認下さい。

サイドバーをスクロールに追従するようにした

久しぶりに JavaScript を書きました。
Chrome, Firefox, Safari では動作確認しました。
※もっといい書き方があったら教えてほしい^^;

5/7 追記:

  • ケータイなど幅の狭いブラウザで表示が崩れてしまっていたのを修正し、元通りのレスポンシブな表示になるようにしました。

Google のサイト検索機能を使った検索フォームを付けられるようにした

config で params.searchDomain を設定した場合のみ、有効になります。

(5/7 追記)メニューのテキストを変更可能に、任意ページをメニューに追加可能に

今までは content/ 直下のページ or section しかメニューに足せなかったのですが、v1.1.0 で任意ページを足せるようにしました。
これにより config の書き方が変わりましたので、ご注意下さい。

Before v1.0.x:

[params]
  mainMenu = ["about", "usage"]

After v1.1.0:

[[params.mainMenu]]
  name = "About"
  link = "about"

[[params.mainMenu]]
  name = "Usage"
  link = "usage"

TOML の Array of Tables という記法を使っています。
下の書き方も試したのですが、たぶん Hugo 内部で使われているパーサが inline table 記法に未対応で、エラーになってしまいました。

[params]
  mainMenu = [
    { name = "About", link = "about" },
    { name = "Usage", link = "usage" },
  ]

(5/7 追記) カテゴリ > ページの一覧をサイドバーやTOPページで表示するようにした

これにより、上述のサイトマップ的ページを設置する意義は薄れました^^;
まあ、お好みでどうぞ。

その他、細かいスタイルの改善

  • table にスタイルが付いてなかったので、bootstrap の .table-striped, .table-bordered 相当のスタイルを付けて GitHub っぽく見えるようにした。
  • コードブロック内が折り返しされていたので、折り返さないように。*2
  • ページ幅が最大 970px だったが、1200px に変更

自分のプロダクトのドキュメントサイトも更新しました

見本としてご参考にどうぞ。

fireap は GitHub Wiki から引っ越しました。
Markdown 形式なので引越しそのものは簡単でした。
(※その過程で色々スタイルのイケてないところを見つけたので v1.0.1 => v1.0.2 になりましたが。)

終わりに

ドキュメント用のテーマとして、より使いやすくなったと思います。
Markdown でドキュメントを管理したいときに、選択肢としてご一考いただければ幸いです。

既にお使いの方は、ぜひアップデートしてみてください。*3

Enjoy!

*1:Golang 製の静的サイトジェネレータ

*2:参考: Bootstrapを使った場合にpreタグを改行させたくない

*3:5/8 本家 hugoThemes にも最新版が取り込まれました :D https://github.com/spf13/hugoThemes/pull/133

西日暮里.rb で "poloxy" というアラートシステムの話をした #ninirb

昨夜、GW 突入前に下の勉強会に参加してきました。

poloxy は未完成なのですが、"pool" + "proxy" の造語で、通知の送信者と受信者の間で動いて、流量をコントロールしたりしてくれるものです。
「アラートまとめる君」と言うとわかりやすいでしょうか。

まだリリースバージョンは作っていませんが、リポジトリGitHub で公開しています。

発表後にちょっとだけ README.md を作っておきました。
といっても、まだスライド以上の情報は(ソースコードを除いて)無いので、「どんなものか」というのはそちらを見てもらった方がよさそうです。

というわけで、下が発表したスライドです。

GW 中に 1st リリース出来るといいなあ、と思っています。

また、勉強会中に @mtsmfm さんから「Docker 化してはどうか」という示唆を頂きました。

確かに、サーバアプリだし Docker ですぐに使えると便利ですね。
リリース後にトライしてみたいと思います!

西日暮里.rb という勉強会について

西日暮里.rb なのに、会場は秋葉原UDX でした。
なんでも「西日暮里は概念化している」とのこと(笑)

「俺が、俺達が西日暮里なんだ!!」

…なんてセリフも聞こえてきそうですね(笑)

先週の渋谷.rb は割と年代・職種もばらばらで、全体としては落ち着いた雰囲気だった気がしますが、今回の西日暮里.rb は全体に活気のある雰囲気だったなーというのが感想です。
飛び込み LT の後、2回目の LT をやる人も2, 3人いました。

会場は弥生株式会社さんにご提供いただいたのですが、なんとご厚意で参加費も無料にしていただきました。

ありがとうございました!

余談 - "poloxy" 命名について

"fireap", "shove" に続き、またまた造語を作ってしまいました。
ユニークな名前にしようと思うと造語かイニシャルかしかないかなあ、という気もします。

命名は毎回悩みます。

実は最初は "mforwd" という名前でした。
あと、"m4x" とか "bufferay" とか "fubako"(和風)とか考えましたが、最終的に "poloxy" にしました。

短くてわかりやすくてユニークなものがいいかな、と思います。

おわりに

"poloxy" のリリースは Coming Soon ということで、気長にお待ち下さい^^;

良い GW をお過ごしください。

find ... xargs ~ のラッパーを2つ書いたけど ag に移行していこうと思う

自分がよく使うコマンドを、自分が使いやすいオプション付きでラッパー化しました。

自分はこれまで ag(the silver searcher) をほとんど使っていなかった *1 ので、いつもこんなコマンドを叩いていました。
…が、このエントリを書くにあたって改めて調べたところ、ag の方が便利そうで、下の機能はだいたいまかなえそうなので、今後は ag にしていこうとしているところです。*2

後者の xfperl-pie の方は少し便利かもしれませんが、でもやっぱり ag でいいかなという気もしています。

ともあれ、下の2つは GitHub で公開していますので、お気に召しましたらご自由にお使い下さい。

xfgrep

# 使い方
xfgrep KEYWORD [-i|--ignore IGNORE_FILE_PATTERN] [-d|--dir DIR] \
  [-f|--file FILE]

# 実行されるコマンド
find $DIR -type f -name "$FILE" [ | egrep -v "$IGNORE" ] | xargs egrep \
  --color=always -Hn "$KEYWORD"

xfperl-pie

# 使い方
xfperl-pie PL_CODE [-f|--file FILE] [-i|--ignore IGNORE_FILE_PATTERN] \
  [-d|--dir DIR] [-b|--backup BACKUP] [-n|--dry-run]

# 実行されるコマンド
find $DIR -type f -name '$FILE' [ | egrep -v '$IGNORE' ] | \
  xargs perl -pi'$BACKUP' -e '$PL_CODE'

利用例

# カレントディレクトリ以下の .pm に対してバックアップしつつ 'foo' => 'bar' に一括置換
xfperl-pie 's/foo/bar/g' -f '*.pm' -b '.bak'

参考

*1:一応 Mac に ag を入れていたことを、これを書いた後に思い出しました^^;

*2:早速、昨日 Qiita に ag (The Silver Searcher) コマンド覚え書き というエントリを書きました。