この投稿は学生LT Advent Calendar 2018の12日目の記事です。
学生LTについて、公式Discordから引用させていただきますと
学生LTコミュニティへようこそ!
ここは技術に関心のある学生と様々な交流が出来る場所となっております。
主にはDiscordでの交流、LT会の企画運営参加?などをしています。
Youtube等を使ったオンラインLT会もあるので遠方の方でも参加できます!(みんな割とバラバラな地域の人で構成されています)
学生LT公式HP: https://student-lt.tech/
まだbeta段階ですがちょうどいい機会なので、今作っているbash用ライブラリマネージャー、Cj-bc/blibを紹介します
- 前半: 使い方
- 後半: 技術的な話
軽く使い方。
Installation
homebrew
に対応しています
$ brew install Cj-bc/blib/blib
また、(個人的には)初の試みとしてMakefileを使ってみたのでそちらでもいけます(いけるはず)
$ git clone https://github.com/Cj-bc/blib
$ cd blib
$ make install
その他対応予定
bpkg
使い方
ライブラリのインストール
- 該当ライブラリ用のformulaレポジトリが存在することを確認します
-
blib install <user>/<repo>
でインストールできます
この時、<user>/<repo>
はそのformulaレポジトリの/であることに注意してください。
また、<repo>
はblib-
のプレフィックスを除いた状態で記載してください。
例:
$ blib install Cj-bc/libtar
インストール済みライブラリの一覧取得
$ blib list
bash-oo-framework
とlibblib
はデフォルトで表示されます(blibで使用するため)
blibライブラリを使用してスクリプトを書くには
たった1行付け足すだけで対応できます
source "$(blib --prefix)/bash-oo-framework/lib/oo-bootstrap.sh"
これでblibのライブラリをimport
できるようになりました(勿論、bash-oo-framework
の各種ライブラリも使用可能です)
blibでインストールされたライブラリをimport
する際は、prefix: blib:
をつけてください
import blib:libtar
ここから後半
動機
- コードスニペットを共有して使いたかった
-
source
時にパスを考えなければならなかったりして少し面倒 - 純粋に、同じコードは同じ場所から呼び出したい
- パッケージマネージャーがあるのにライブラリマネージャーがないのが納得いかん
だって楽しそうじゃん
ちなみに、bash用のパッケージマネージャーは幾つか存在します
主な仕様
現状
- Homebrewライクなライブラリ管理システム。
formula
を作成することでライブラリとして認識できるようになる- これにより、他者のコードを使うこともできますね!やったね!
-
bash-oo-framework
のimport
文を使用してライブラリ読み込み-
bash-oo-framework
は標準で使用可能になります。import
するだけでお手軽。
-
- 内部的にはファイルを
source
しているだけのため、bash-oo-framework
を用いているものもそうでないものも管理可能 - 管理者権限のいらないパスにライブラリを保存
- どの場所からでも
blib
さえあれば動く!!
現状のコマンド群
$ blib --prefix # ライブラリの格納先
/usr/local/etc/blib/lib
$ blib list # install済みライブラリの一覧
bash-oo-framework libblib
$ blib install <user>/<repo> # github上の<user>/<repo>レポジトリのformulaを探してインストール
$ blib uninstall <library_name> # <library_name>をアンインストール(Cellarからは消えない)
追加予定の仕様
- ライブラリ情報の表示コマンド
- バージョン管理
- ライブラリのドキュメント表示機能
-
blib
対応バージョンのbash-oo-framework
をいつか本家にPR出したい
追加予定のコマンド群
$ blib cleanup # `Cellar`内に残っているcacheを削除する
$ blib switch <library_name> <version> # ライブラリのバージョン切り替え
$ blib init # 冒頭に必要になる文字列を簡略化する(詳細はissueを参照)
実装
おそらくこのツールの実装面の一番の特徴はshellscriptで書かれていること、bash-oo-framework
を使っていることだと思います。
今回の実装では、以下の機能を使って書かれています:
ライブラリ名 | 説明 | |
---|---|---|
util/class | オブジェクト指向で書けるようにする | |
util/log | ロガーの追加 | |
util/tryCatch | try-Catch構文を追加 | |
util/exception | 例外を追加 | |
UI/Console | 標準エラー出力への一律のアクセス | |
UI/Color | 色エイリアスの追加 | util/logでエラーが出るため追加 |
大雑把な実装
大雑把に実装の流れを書いておきます。
その後、実装に際して詰まった部分を書いていきます。
1. blib
クラスを作成
静的クラスとしてblib
クラスを作成します。
(高速化したい場合、個別に関数を作成した方が良いです)
(この場合、どちらの書き方でも速度以外の違いはありません。多分。)
class:blib() {
# クラスメゾットを追加します
}
Type::InitializeStatic blib
2. クラスメゾットをいくつか作成
機能ごとにクラスメゾットを追加します(当たり前)
とりあえず必要なものをリストアップ
class:blib() {
# オプションを取り扱う
blib::option() {
:
}
# インストール用処理
blib::install() {
:
}
# アンインストール処理
blib::uninstall() {
:
}
# インストールされたライブラリの一覧表示
blib::list() {
:
}
# manコマンド(未実装)
blib::man() {
:
}
# infoコマンド(未実装)
blib::info() {
:
}
}
Type::InitializeStatic blib
3. 内容に応じて必要なライブラリを開発
本来、blib
クラス自体も分けるべきなのですがまだ分けてません(気づいたのが後だった)
blib
の依存ライブラリはlibblib
にまとめられています。
いずれ汎用性を上げたのち、別途ライブラリを分ける予定でいます。
今回使っているライブラリは二つです
ライブラリ名 | 説明 |
---|---|
formula | formulaの検証等するライブラリ |
user | Githubのユーザーの検証等するライブラリ |
4. main関数を書く
別に名前はなんでもいいのですが他に倣ってmain関数を書き、それを実行することにしました。
main() {
# この中からblibを呼ぶ
:
}
main $@
これはshellscriptとしてはどうなものかといったものですが、オブジェクト指向的、ということでスルーします。
とりあえずこれで大雑把な流れは終了
困ったところ、詰まったところ、etc
今後の人のリファレンスになればいいなぁというのも思っているので一問一答形式で書いていきます
1. ライブラリインストール先 [WIP]
これに関してはまだあまり詰められてません
今は暫定的なものとなっていますがより良いものがあれば知りたいです。
2. ライブラリはレポジトリごと置いておくか否か
結論: Yes
ライブラリをレポジトリごとおくことにより、バージョン管理が楽になります(git checkout
で行えるので)
(尚、この記事を書いていてタグによるバージョン管理を思いついたので、細部は現状の仕様とは異なります)
(現状の仕様: バージョンごとにディレクトリを分けてクローン)
3. 完全なアンインストール処理にrm -rf
を使って良いか否か
結論: 使う
(ここでの「完全なアンインストール」というのは、blib cleanup
として実装予定の機能で、Cellar内も消去します)
ライブラリがgitレポジトリである以上、.git
を消去しないといけなくなるため、結局強制的にrm -rf`を使うことになります。
なので元から使ってしまおうということです。
4. classからの例外が捕捉できない [BUG]
これは明確なバグです
正確には、class
から例外が返ってきていないようです。
bash-oo-framework
本家にもissueが上がっています。
* niieani/bash-oo-framework
鋭意捜査中ですがまだ治ってません。
5. mainから存在しないはずの例外が返ってくる [BUG]
結論: おそらく4.のバグ
対処: main呼び出し元もtryCatchで囲む。
6. mainをtryCatchで囲むと、main関数の戻り値(=プログラムの戻り値)が戻らず、常に0になってしまう
対処: main呼び出し元を囲むtryCatchにて、mainの戻り値を例外として投げる
main関数からの例外は基本的に存在しないはずなため、緊急策としてmainの戻り値を変数に格納して例外として送出、それをそのままプログラムの戻り値として設定。
[2018-12-12]@ Qiita 学生LT Advent Calendar参加日
[2018-12-02 08:45]