$(git branch)でカレントディレクトリのファイル一覧も出てしまう時の対処法
とあるシェルでgitのブランチ一覧を取りたくて echo $(git branch)
と書いたのだが、なぜかファイル一覧も出てしまい戸惑った。
前提
下記のようなディレクトリがあって、それがgit管理されていたとする。
$ ls README.md main.go main_test.go
そして以下のようなブランチが存在する。
$ git branch develop feature/bar feature/baz feature/foo * master
事象
echo $(git branch)
を実行すると下記のようにブランチ一覧の間にファイル一覧が差し込まれてしまう。
$ echo $(git branch) develop feature/bar feature/baz feature/foo README.md main.go main_test.go master
原因
勘のいい人はもうお分かりかもしれませんが、 git branch
した時にmasterの前に *
がついていますよね。
それが echo
にワイルドカードとみなされてファイル一覧が出てしまいます。
$ echo * README.md main.go main_test.go
と同じになるわけです。
対処法
ダブルクオートで囲めばワイルドカードが展開されずに出力されます。
$ echo "$(git branch)" develop feature/bar feature/baz feature/foo * master
ブランチ一覧を1行で取得したい場合
tr
を使って *
をスペースに変換したリストをダブルクオート無しで echo
すれば取得可能です。
$ echo $(echo "$(git branch | tr '*' ' ')") develop feature/bar feature/baz feature/foo master
でも、そもそも git branch
を使ってスクリプトを書かないほうがいいらしい。
上記によれば、Gitはスクリプトで使用するために明示的に設計されたplumbingインターフェースを提供しているとのこと。
なので自分はplumbingインターフェースを使ってみようと思います。
参考
特定のディレクトリ内にあるjavascriptを全てMinifyする
例えば static/js
ディレクトリにjsが置いてあるとする。
$ tree . └── static └── js ├── bar.js ├── baz.js └── foo.js
そのディレクトリ内にあるjavascriptを全てMinifyしたい場合のbashスクリプト。
for f in $(ls static/js/*.js); do uglifyjs -cm -o "${f/.js/.min.js}" "${f}" done
Minifyには uglify-js
を使用する。
オプションの c
が単純なソース圧縮、 m
が変数名の圧縮(1文字にする)、 o
はアウトプットするファイルを指定。
これを minify.sh
というファイル名で作成し、実行する。
注意点としては ${f/.js/.min.js}
がbashの文字列置換を使用しているのでbashで実行すること。
$ bash minify.sh
すると全てのjavascriptがMinifyされる。
$ tree . ├── minify.sh └── static └── js ├── bar.js ├── bar.min.js ├── baz.js ├── baz.min.js ├── foo.js └── foo.min.js
ちなみにMinifyしたjavascriptをgit管理したくない場合は .gitignore
に *.min.js
を入れると無視してくれる。
もうひと工夫
シバンを入れて実行権限をつけるとスッキリして良い。
実行権限をつけるのでファイル名も minify
にすると綺麗かも。
#!/bin/bash for f in $(ls static/js/*.js); do uglifyjs -cm -o "${f/.js/.min.js}" "${f}" done
$ mv minify.sh minify $ chmod u+x minify $ ./minify $ tree . ├── minify └── static └── js ├── bar.js ├── bar.min.js ├── baz.js ├── baz.min.js ├── foo.js └── foo.min.js
参考
CircleCIのYAMLの仕様が変わった
CircleCIを使っている。
今週水曜(2018年10月10日)なぜか本番デプロイができなくなっていた。
調査すると設定を書いているYAMLの仕様が変更されたようで、キーの上書きができなくなっていた。
元々の仕様
デプロイにはFabricを使用している。
fab dev deploy
で開発環境、 fab prod deploy
で本番環境にデプロイされるように設定ファイルを書いている。
references: env_dev: &env_dev environment: ENV: dev env_prod: &env_prod environment: ENV: prod jobs: deploy_dev: &deploy docker: - image: circleci/python:3.6 environment: AWS_DEFAULT_REGION: ap-northeast-1 steps: - checkout - run: name: Install python package command: sudo pip install -r requirements.txt - run: name: Deploy command: fab $ENV deploy <<: *env_dev deploy: <<: *deploy <<: *env_prod
Anchor(&name)とAlias(*name)を使用してコンパクトに書いている。
CircleCIは各jobページのConfigurationタブで展開されたYAMLを確認することができる。
展開されたYAMLを確認すると下記のようになっている。
jobs: deploy_dev: environment: - ENV: dev steps: - checkout - run: name: Install python package command: sudo pip install -r requirements.txt - run: name: Deploy command: fab $ENV deploy docker: - image: circleci/python:3.6 environment: AWS_DEFAULT_REGION: ap-northeast-1 deploy: environment: - ENV: prod docker: - image: circleci/python:3.6 environment: AWS_DEFAULT_REGION: ap-northeast-1 steps: - checkout - run: name: Install python package command: sudo pip install -r requirements.txt - run: name: Deploy command: fab $ENV deploy
ちゃんと environment
に ENV
が上書きされて展開されているのがわかります。
仕様変更後
水曜日、本番デプロイのCIが失敗することで仕様変更を知る。
仕様変更後に展開されたYAMLを確認すると deploy
jobの ENV
が上書きされず、 dev
のままになってしまっていた。
jobs: ... deploy: ... environment: - ENV: dev
Twitterでつぶやかれている方も居た。
違うっぽい。circleciのYAMLパーザがおかしくなってないっすか
— こうげ (@koooge) October 10, 2018
修正
AnchorとAlias周りがおかしいのではないかという事はすぐわかったので、以下のように修正を行った。
deploy: - <<: *deploy - <<: *env_prod + <<: [*env_prod, *deploy]
元々は *deploy
を先に書き、そこに *env_prod
を上書きするという意図で書いていた。
しかし、上書きされないため書く順番を逆にし、 *env_prod
を先に書き、 *deploy
を後に書いた。
この時、Aliasの書き方もCircleCIで推奨されている []
を使用した書き方に変更した。
すると下記のように以前の想定通り展開されました。
jobs: ... deploy: environment: - ENV: prod docker: - image: circleci/python:3.6 environment: AWS_DEFAULT_REGION: ap-northeast-1 steps: - checkout - run: name: Install python package command: sudo pip install -r requirements.txt - run: name: Deploy command: fab $ENV deploy
そして無事デプロイされるようになった。
ブログ再始動
お久しぶりです。
178inabaです。
久しぶりにブログを書いています。
最近、技術書典で技術書を販売した方のブログを見ました。
このブログを見て
(自分もいつかは本が書けたら楽しいだろうな)
(沢山の人が来場していて交流できるし、報酬も得られる!)
などと思い、
でも本を出すにはまず、休止状態のブログを再始動して技術的な記事とか書くべきだろうと思いこのブログを書いています。
Kyash始めてみた
Kyashは同僚と食事に行った時に割り勘代金を渡すために入れてみたのですが便利です。
上の技術書典のブログを読んだときに、KyashのAndroidエンジニアのこにふぁーさんのブログを思い出しました。
このこにふぁーさんのブログには投げ銭の話が書いてあって、上の技術書典の話と 『技術情報の発信で報酬を得る』 という所で通ずるなと思いました。
なので真似してKyashのIDとQRコードを貼ってみます。
kyash_id: 178inaba
今後
今後は定期的に技術情報をブログに書いていけたらと思います。
よろしくです!
GitHub Gistにファイルをアップロードするコマンドをgolangで作った
Gistを作る時、毎回catでファイル内容を表示してコピーして、GistのWeb画面にペーストしてたんだけど、
これが地味にめんどくなってきたので、ファイルを渡すとGistを作ってくれるコマンドをgolangで作った。
使い方
target.go
をGistにアップロードする場合。
$ gistup target.go
- 複数ファイルをGistにアップロードする場合。
$ gistup target.go target_test.go target_linux.go
- 標準入力をGistにアップロードする場合。
$ stdin | gistup
アップロードが成功するとブラウザで作成されたGistのページを開きます。
(開けなかった場合はURLを表示。)
デフォルトでは最初にユーザ名とパスワードでログインを求められます。
(後述のオプションで匿名を選択すればログイン不要。)
また、デフォルトでは非公開のGistとして作成されます。
(こちらもオプションで公開のGistとして作成することも可能です。)
オプション
-a
- 匿名のGistを投稿します。
-d <description>
- Gistの説明を追加します。
-n <file_name>
- 標準入力からGistにアップロードする場合のファイル名を設定します。
- 指定しない場合はGistのデフォルト
gistfile1.txt
になります。
-p
- パブリック(公開)のGistを投稿します。
所感など
入力時のコンテキストキャンセル検知
ユーザ名、パスワード入力は下記のようにコンテキストのキャンセルを検知できるようにしている。
func readString(ctx context.Context, hint string, readFunc func(t *tty.TTY) (string, error), t *tty.TTY) (string, error) { fmt.Printf("%s: ", hint) ch := make(chan string) errCh := make(chan error) go func() { s, err := readFunc(t) if err != nil { errCh <- err } ch <- s }() var s string select { case <-ctx.Done(): return "", ctx.Err() case s = <-ch: case err := <-errCh: return "", err } return s, nil }
理由はgistupはInterruptシグナル(Ctrl+C
)を受けてコンテキストをキャンセルする仕組み(下記参照)になっているのだが、
sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt) ctx, cancel := context.WithCancel(context.Background()) go func() { <-sigCh cancel() }()
これだと、入力中にCtrl+C
を押しても終わらない。
なので、ゴルーチンで入力処理を実行して、コンテキストのキャンセルと、入力終了をselect
で同時に待つようにした。
結果、入力中にCtrl+C
を押すと終了するようにできた。
ユーザ名、パスワードの入力はTTY
を使用
gistupではユーザ名とパスワードの入力にTTY
を使用している。
理由は、最初、標準入力からユーザ名とパスワードを取得していたけど、
標準入力をGistにアップロードする箇所を実装してる時にユーザ名、パスワードの取得ができなくなる事に気づいた。
いろいろ調べたけど引き続き標準入力からユーザ名、パスワードを取得するのは難しそうで、調べて出てきたのはperlの質問でTTY
を使っているやつだった。
「goでTTY
って確かmattnさんが作ってたよな」と探したらあって、
ただ、パスワードを読むメソッドしか無かったのでReadString
メソッドをプルリクエストした。
その後、速攻でマージして頂けたのでユーザ名の入力にはReadString
を使用。
パイプで前のコマンドの結果貰うツールでStdinからユーザ名とかパスワードを入力しようとするとパイプの方を拾っちゃってうまくいかなかった。
— 178inaba (@i178inaba) 2017年7月26日
go-ttyのReadString(さっきPRした)を使ったらうまくいった。
皆さんもぜひ!https://t.co/PGlJcQEUJr
結果、ユーザ名、パスワードを入力しつつ、標準入力から取得した文字列をGistにアップロードすることができた。
まとめ
これでコピペせずにGistにアップロードできるようになった。
またなんか作ったら書きます。
あと、PR大歓迎です😆
Raspberry Piで使うSDカードをコマンドラインで作る
新しいRaspberry Piを買ったので起動SDを作るコマンドをメモしておきます。
使用するOSはRaspbianです。
# ダウンロード $ wget https://downloads.raspberrypi.org/raspbian_lite_latest -O raspbian.zip # zip解凍 $ unzip raspbian.zip # SDカードのマウント箇所を確認 $ diskutil list ... /dev/disk2 (internal, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *2.0 GB disk2 ... # SDカードのマウントを解除 $ diskutil unmountDisk /dev/disk2 # SDカードにイメージを書き込む $ sudo dd bs=1m if=2017-03-02-raspbian-jessie-lite.img of=/dev/rdisk2
イメージを書き込むのが結構時間かかります。
マウント箇所(上記だとdisk2)はPCによって異なります。
イメージファイル名(上記だと2017-03-02-raspbian-jessie-lite.img)もRaspbianがアップデートされると変わります。
参考:
Raspberry Pi(Raspbian)の更新
新しいRaspberry Piを買ったので、ついでに以前GitLabを入れたRaspberry Piの更新をした。
# パッケージリスト更新 $ sudo apt-get update # パッケージ更新 $ sudo apt-get dist-upgrade # ダウンロードしたパッケージの削除 $ sudo apt-get clean
sudo apt-get dist-upgrade
は結構時間かかる。
GitLabもRaspbian版は長らくバージョン8.7.9で止まっていたのだが、最近更新されてバージョン9.0.2が使えるようになっていた。
Dockerレジストリも使えるようになった。
参考: