Go로 프로그램을 작성하다 보면 인터넷 검색이나 뭐를 통해서 유용한 라이브러리를 많이 접하게 된다. 그냥 혼자 쓰기는 아까우니까 여기에 한번 간단히 적어보는 것도 나쁘지 않겠다 싶었다.


Live reload for Go apps

프로젝트 디렉토리 안의 코드가 변경된 것을 감지하고 일정한 명령을 다시 수행하도록 해주는 어플리케이션이다. echo로 예를 들어, 핸들러 코드를 수정한 후에 테스트를 해 보려면 매번 코드를 다시 실행해야 하는데 Air를 사용하면 파일 변경을 자동으로 감지하여 어플리케이션을 다시 실행하게 된다. 설정 파일에는 어떤 실행 파일을 실행할 것인가에 대해서 명시할 수 있다. 설정 파일으 포맷은 air_example.toml을 확인하면 된다.

# Config file for [Air](https://github.com/cosmtrek/air) in TOML format

# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"

# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ."
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# Exclude specific regular expressions.
exclude_regex = []
# Exclude unchanged files.
exclude_unchanged = true
# Follow symlink for directories
follow_symlink = true
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms

# Show log time
time = false

# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

# Delete tmp directory on exit
clean_on_exit = true


Take a golang map and flatten it or unfatten a map with delimited key.

json을 받아서 map으로 변경하거나 map을 다시 json으로 변경한다. 그런데 이게 이름처럼 flattten/unflatten하게 데이터를 가공할 수 있다.

in := map[string]interface{}{
    "a": "b",
    "c": map[string]interface{}{
        "d": "e",
        "f": "g",
    "z": [2, 1.4567],

out, err := flat.Flatten(in, nil)
// out = map[string]interface{}{
//     "a": "b",
//     "c.d": "e",
//     "c.f": "g",
//     "z.0": 2,
//     "z.1": 1.4567,
// }
in := map[string]interface{}{
    "foo.bar": map[string]interface{}{"t": 123},
    "foo":     map[string]interface{}{"k": 456},

out, err := flat.Unflatten(in, nil)
// out = map[string]interface{}{
//     "foo": map[string]interface{}{
//         "bar": map[string]interface{}{
//             "t": 123,
//         },
//         "k": 456,
//     },
// }

json의 키에 delimeter가 포함되면 이를 적절히 핸들링해서 nested map으로 변경하는 역할을 한다. delimeter도 변경할 수 있으므로 코드가 매우 간편해진다.