GoでCSVファイルを処理するCLIのツール(csvt)を作りました

CSVファイルを処理するcsvtというCLIのツールをGoで作りました。
作り始める時点で用意しようと思っていた機能が揃ったので紹介します。

下記のようなサブコマンドを用意しています。

  • choose CSVファイル内から一部の列を取り出して新しいCSVファイルを作成する
  • count CSVファイルの行をカウントする
  • filter CSVファイルの行を条件に応じてフィルタリングし、新しいCSVファイルを作成する
  • header CSVファイルのヘッダ内容を表示する
  • join 2つのCSVファイルを列の値をキーとして結合する
  • remove CSVファイル内から一部の列を削除して新しいCSVファイルを作成する

一番気に入っているコマンドはjoinです。
ExcelのVOOKUP的なことができます。

$ csvt join -1 INPUT1 -2 INPUT2 -c COLUMN -o OUTPUT
Usage:
  csvt join [flags]

Flags:
  -1, --first string     First CSV file path.
  -2, --second string    Second CSV file path.
  -c, --column string    Name of the column to use for joining.
      --column2 string   (optional) Name of the column to use for joining in the second CSV file. Specify if different from the first CSV file.
  -o, --output string    Output CSV file path.
      --usingfile        (optional) Use temporary files for joining. Use this when joining large files that will not fit in memory.
      --norecord         (optional) No error even if there is no record corresponding to sencod CSV.
  -h, --help             help for join

例えば、input1.csvとして下記内容のCSVファイルと、

UserID,Name,Age,CompanyID
1,"Taro, Yamada",10,2
2,Hanako,21,1
3,Smith,30,2
4,Jun,22,4

input2.csvとして下記内容のCSVファイルを用意して、

CompanyID,CompanyName
1,CompanyA
2,CompanyB
3,CompanyC
4,"AAA Inc"

CompanyIDの値を使って結合します。

$ csvt join -1 input1.csv -2 input2.csv -c CompanyID -o output.csv

できあがったoutput.csvは下記のような内容になります。
input1.csvを基準として、input2.csvの内容を足していくようなイメージです。

UserID,Name,Age,CompanyID,CompanyName
1,"Taro, Yamada",10,2,CompanyB
2,Hanako,21,1,CompanyA
3,Smith,30,2,CompanyB
4,Jun,22,4,AAA Inc

--usingfile というオプションを利用すると、メモリにファイル全体を載せることなく結合するので、どんな大きなファイルでも問題なく処理できます。(数GBのCSVファイルでも使用メモリは数十MB)

他のコマンドも含め、詳しい利用方法はREADMEをご参照ください。

使っているもの

サブコマンドの仕組みは Cobra を使いました。とても簡単にサブコマンドが作れます。

joinコマンドでのメモリを使わない実装では、キーバリューストアのBoltを使いました。手軽に使えてすばらしいです。

第20回 redmine.tokyo勉強会で『Redmine issue assign notice plugin の紹介』というタイトルで発表しました

第20回 redmine.tokyo にて、『Redmine issue assign notice plugin の紹介』というタイトルでLTさせていただきました。

資料はこちら。

Redmine issue assign notice pluginは、チケットの担当者を切り替えて進めていくようなプロジェクトでは、とても有用なプラグインだと思っていますので、今回このLTを見て試してみようという方がいたらうれしいです。

f:id:onozaty:20210523182619p:plain

今回の勉強会は、ところどころ抜けながらの参加(リモートだから家のことを途中で出来るので助かる)でしたが、聴いた発表はどれも良いものでした。
その中でも特に skys さんの「新型コロナウイルス感染者情報管理」は、Redmineをカスタマイズすることで、コロナウイルス感染者情報管理するという、とても面白い事例でした。

Redmineのカスタマイズ性の高さからか、開発以外の用途でも活用できる事例は多いですね。

2021年3月から4月にZennで書いた記事

2021年3月から4月までの記事

ShortcutKey2URLを使ってブラウザ操作を快適に(Chrome/Firefox拡張機能)

愛用しているShortcutKey2URLというChrome/Firefox用の拡張機能の紹介記事です。
個人的にはとても便利だと思っているので、もっといろんな人に使ってもらえたらなぁと思っています。

Gradle Shadow Pluginで作成したfat/uber JARで、複数のJDBCドライバがロードできない

Gradle Shadow Pluginで、デフォルトだとMETA-INF/services配下が上書きされてしまい、ハマった際の記事です。
忘れたころにまた嵌りそうです、、

社内勉強会で「最近作ったもの」というタイトルで発表しました

社内勉強会で最近作ったものってタイトルで、Goで作ったツールやRedmine issue assign notice pluginについて発表しました。

www.slideshare.net

在宅勤務で通勤時間&肉体的な負荷が無くなったことで、趣味でコード書ける時間が今までより増えたなーって思います。
あと、Goはちょっとしたツールを作って配布するためのものが全て揃っていて素晴らしいです。

Goでファイル一覧+αを出力するCLIのツール(filist)を作りました

Goの勉強も兼ねて、適当な課題見つけてCLIツールをちょこちょこ作っているのですが、他の人が使っても便利かもしれないものが出来たので紹介します。

指定したディレクトリ配下のファイル一覧を再帰的に表示するツールです。

$ filist -s -M .
a.txt   24  3d3a42d900823afcfdfeb6de338bcec1
b/1.txt 81  ae23e0b40e773ac132f477f661e89b86
b/2.txt 163 494ba81d0d828ff9a244da627b5ece47

ファイルパス以外にも、サイズ、更新日時、MD5、SHA1などといった情報も一緒に出力できます。

オプションは下記の通りです。

Usage: filist [options] directory ...
options
  -r, --rel      Print relative path (If neither 'rel' nor 'abs' is specified, 'rel' will be printed first column.)
  -a, --abs      Print absolute path
  -s, --size     Print file size
  -m, --mtime    Print modification time
  -M, --md5      Print MD5 hash
  -S, --sha1     Print SHA-1 hash
      --sha256   Print SHA-256 hash
  -h, --help     Help

オプションの指定順に情報が並ぶので、例えば先頭にMD5で、その後にファイル名、、といった指定もできます。

$ filist -M -r .
3d3a42d900823afcfdfeb6de338bcec1  a.txt
ae23e0b40e773ac132f477f661e89b86  b/1.txt
494ba81d0d828ff9a244da627b5ece47  b/2.txt

全てのファイルにmd5sumかけたい、、っていうようなときに、コマンド組み合わせてワンライナーで書けなくないですが、こういったツール用意しておくと便利かなーって思って作りました。
Goだと各OS用の実行ファイルをシングルバイナリで簡単に提供できるってのがほんと素晴らしいです。

Redmine issue assign notice plugin の v1.2.0 をリリースしました

チケットの担当者が変わったときに、SlackやRocket.Chat、Teamsなどに通知するプラグイン、Redmine issue assign notice pluginのv1.2.0をリリースしました。

Google Chatのメンションに対応しました。
Google ChatのIncoming Webhookの設定などは、下記をご参照ください。

また、下記の2つの問題を修正しています。

  • Rocket.Chat にて、"[]"がエスケープされることで \[KaTeX\] 表示となってしまう。
  • ドキュメントルート以外でRedmineがデプロイされている場合、カスタムフィールド作成へのリンクが正しく動作しない。

2021年1月から2月にZennで書いた記事

Zennで書くことについて

2021年から、技術的な記事(書くのに多少時間がかかるようなもの)は、Zennで書くことにしました。

Zennがとても良いと思ったのは、GitHubで記事が管理できるというところです。

使い慣れたエディタで、時間をかけて(必要に応じてコミットして)記事を書けるというのは、とても便利です。
また、GitHubで草が生えるのも、モチベーションの維持につながっています。

とはいえ、メインは今まで通り はてなBlog のままにするので、時々Zennで書いたことを、こちらのBlogでもリンクとして記載していこうと思います。

2021年1月から2月までの記事

PostgreSQLのtext型に対するINDEX

PostgreSQLのtext型に対してINDEXを張るといった記事です。あまりtext型に対してINDEXを張りたいって機会は無いとは思いますが、、そういった状況になった際に、参考になるかもしれません。
あとMySQLのプレフィックス長指定でINDEXを張れるのはとても便利なので、PostgreSQLにもぜひ入って欲しいです。

利用ライブラリをMavenリポジトリ形式でプロジェクト内のファイルとして保持する(JCenterシャットダウンに向けて)

ローカルにMavenリポジトリ形式でディレクトリ作っておいて、そこでライブラリを管理する方法について書いた記事です。
JCenterでしか公開されていないようなライブラリが、そのままインターネットから消えてしまうような場合になった際の回避策として書きました。

必要なライブラリをMavenリポジトリとして必要なディレクトリ構成でダウンロードするツールも作りました。

各チャットツールのIncoming Webhoookのまとめ

Redmine issue assign notice というRedmineのプラグインを公開しているのですが、こちらで各チャットツールのIncoming Webhookを使うにあたって、やり方を毎回調べる羽目になってしまっていたので、記事にまとめました。