[小ネタ][Golang]Surveyでインストーラ風のターミナル入力を作ってみた

2021.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

とある調査にてインタラクティブにターミナルから入力や選択できるインストーラのようなものを作れるかを調べる機会がありました。 使用している言語がGolangであったため、Golangでライブラリがあるかを調べたところ、survey というライブラリがありました。

surveyのサイトを見れば何ができるかは分かりますが、自分のユースケースに合うかを検証するため、インストーラ風の入力のサンプルを作ってみました。今回はこのサンプルについて書いてみたいと思います。

作ったプログラムのターミナル入力

先にどのようなターミナル入力ができたかを書きたいと思います。何かのインストールやシステム設定する処理を想定し

  • ユーザ名
  • パスワード
  • OSを選択
  • インストールするオプションを複数選択
  • 詳細コメントを入力するかを yes/no で選択
  • (yesを選択時)複数行の詳細コメントを入力
  • インストールするかを yes/no で確認

の入力や選択を行うサンプルとなります。ターミナル上での入力は以下のようになります(分かりやすいように一部改行を入れるなど加工をしております)。

? Please input user name. testname
? Please type your system password.: *****
? Please select install OS.:  [Use arrows to move, type to filter]
  Windows
  Linux
> Mac

? Please select install options:  [Use arrows to move, space to select, <right> to all, <left> to none, type to filter]
  [x]  data backup
  [ ]  log backup
> [x]  alert email

? Input detail?: (y/N) y
? Please input detail comment. [Enter 2 empty lines to finish]this is a sample.
something.

? Would you like to insatll now?: (y/N) y

インストールやシステム設定でよくありそうな入力や選択、yes/no での処理の分岐は実現できそうでした。

作ったサンプルプログラム

上記のターミナル入力を行なった、今回作成したサンプルプログラムは以下となります。

package main

import (
	"fmt"

	"github.com/AlecAivazis/survey/v2"
)

var questions = []*survey.Question{
	{
		Name:     "userName",
		Prompt:   &survey.Input{Message: "Please input user name."},
		Validate: survey.Required,
	},
	{
		Name: "password",
		Prompt: &survey.Password{
			Message: "Please type your system password.:",
		},
		Validate: survey.Required,
	},
	{
		Name: "os",
		Prompt: &survey.Select{
			Message: "Please select install OS.:",
			Options: []string{"Windows", "Linux", "Mac"},
			Default: "Mac",
		},
		Validate: survey.Required,
	},
	{
		Name: "options",
		Prompt: &survey.MultiSelect{
			Message: "Please select install options:",
			Options: []string{"data backup", "log backup", "alert email"},
		},
	},
	{
		Name: "inputDetail",
		Prompt: &survey.Confirm{
			Message: "Input detail?:",
		},
		Validate: survey.Required,
	},
}

var answers struct {
	UserName    string   `survey:"userName"`
	Passowrd    string   `survey:"password"`
	OS          string   `survey:"os"`
	Options     []string `survey:"options"`
	InputDetail bool     `survey:"inputDetail"`
}

func main() {
	err := survey.Ask(questions, &answers)
	if err != nil {
		panic(err)
	}

	var detail string
	if answers.InputDetail {
		prompt := &survey.Multiline{
			Message: "Please input detail comment.",
		}
		survey.AskOne(prompt, &detail)
	}

	var install bool
	prompt := &survey.Confirm{
		Message: "Would you like to insatll now?:",
	}
	survey.AskOne(prompt, &install)

	if !install {
		fmt.Println("not install. finish.")
		return
	}

	fmt.Println("install start ...")
	fmt.Println(answers.UserName, answers.OS, answers.Options)
	fmt.Printf("detail comment:\n%s\n", detail)
}

動かすには、Golangの実行環境と、「$ go get github.com/AlecAivazis/survey/v2」でのインストールを行う必要があります。

ユーザー名の入力〜詳細を入力するかのyes/no の選択までの連続した質問は、「questions」に格納して一括で出力しています(56行目)。

詳細を入力するかでyesを選択した場合の入力やインストールをするかの確認については、独立して出力し(66行目、73行目)、入力値によって処理を分岐させています。

まとめ

このような感じで、インストーラ風のターミナル入力を実現できることが分かりました。何かの役に立てば幸いです。