Skip to main content

Command Palette

Search for a command to run...

用gum给IRedis增加数据源选择能力

gum 是一个很有趣的“胶水”工具,可以方便地为 shell 脚本提供交互能力,本文以整体IRedis为例展示其使用方法

Updated
•2 min read•View as Markdown
用gum给IRedis增加数据源选择能力

前言

gum 是一个命令行工具, 它可以方便地为脚本提供TUI 交互能力。 本文以扩展 IRedis 为例,展示了 gum 的使用方法。

问题

IRedis 是一个非常好用的 redis 命令行客户端, 它提供很多方便实用的功能(语法高亮,自动完成等)

要连接到指定数据源 , 只要执行以下命令:

iredis --url 'redis://usr:passwd@foo-bar.com:6379?db=0'

但工作中经常需要连接不同的数据源,每次都需要输入不同的地址很麻烦。得记住每个数据库的地址和密码。 如果不能为数据源设置别名,命令行历史也无助于缓解心智负担。

iredis --url 'redis://usr:passwd@server-1.com:6379/0'
iredis --url 'redis://usr:passwd@server-2.com:6379/2'
iredis --url 'redis://:auth@server-3.com:6379'
...

好在IRedis 支持把数据源保存到指定配置文件中( .iredisrc) 中,可以为数据指定别名, 其格式如下:

[alias_dsn]
dev=redis://localhost:6379/4
staging=redis://username:password@staging-redis.example.com:6379/1

有了 .iredisrc 文件之后, 就可以用 dsn 来连接不同的数据库了

iredis --dsn dev
iredis -d staging

虽然这样有助于降低心智负担,但还是有点不方便: 如果忘记了dsn 的准确名字, 还是无法快速完成连接。

如果能有从 iredisrc 读取数据源列表供用户选择, 无疑可以提高效率并降低心智负担。要达成这个目标, 可以分两个步骤:

  1. 解析别名

  2. 用 gum 提供列表选择并调用iredis

解决方案

先说解析别名

要解析.iredisrc 这个 ini 格式的文件, 最简单的办法是使用python 脚本:

import configparser
import os
config = configparser.ConfigParser()
config.read(os.path.expanduser('~/.iredisrc')) # read ini file
for key, _ in config.items('alias_dsn'):
  print(key) # print all key in alias_dsn

上述脚本解析ini 文件,并打印出 alias_dsn 下的所有别名。

执行此脚本即可打印所有别名:

> python3 iredis.py
dev
staging

用gum提供选择能力

这时 gum 就可以出场了。结合前面写好的python脚本, 先读取别名列表, 用 gum filter 作选择, 然后用iredis打开选取的dsn

#!/usr/bin/env sh
DSN=$(python3 iredis.py | gum filter) # choose alias
iredis -d $DSN

最终效果如下:

更多思考

其实这个模式可以应用到所有类似场景。

例如,usql 这个数据库 cli 几乎支持所有RDBMS, 在日常使用中也存在同样的问题。 而 usql 又不像 iredis, 它不支持在配置文件中保存数据源。

这时需要以某种形式来表达别名与数据源的对应关系, 然后传递给gum 进行选择。 遗憾的是 gum 目前不支持传入map 进行选择(虽然很久以前就有用户提出过这个需求, 但被开发团队拒绝掉了)。

不过我们可以用其中提到的思路,用shell 来达成目标:

#!/usr/bin/env sh

# define db alias map
DBMAP=$(cat <<END
dev => pg://user:pass@localhost/dbname?sslmode=disable
staging => mysql:/var/run/mysqld/mysqld.sock
prod => sqlserver://user:pass@remote-host.com/dbname
END)

# choose alias
ALIAS=$(echo "$DBMAP" | awk -F ' => ' '{print $1}' | gum filter)

# grep dsn
DSN=$(echo "$DBMAP" | grep "$ALIAS =>" | awk -F ' => ' '{print $2}')

# open db
usql $DSN

这样,我们就拥行了一个可以连接任何RDBMS的统一cli 客户端,如需连接其它数据库,只需要在脚本中增加一行即可

结论

有了 gum 的帮助, 我们可以方便地为任何 cli 程序增加 TUI 交互能力,增加其易用性。本文只是展示了 gum 的多项强大功能中的一项, 如有兴趣, 可以到 gum 官网了解更多。