🍇

GoでちょっとしたCLI作ってみた

2024/12/16に公開

Go言語初心者のkurakkeです。
最近Go言語気になってるので簡単なCLI作ってみました。

作ったもの

実行するとプロジェクトのリストが出てきて、起動したいプロジェクトを選択するとcodeコマンドでvscodeを立ち上げます。
プロジェクトの起動コマンドなどを事前に書いておくと、プロジェクトを開いた後に実行してくれます。

コードのポイント

go-multiplechoiceを使ってマルチセレクトを実装しました。
他は標準ライブラリを用いて実装しています。
標準ライブラリが充実していて、簡単にCLIを実装出来たので結構いいな〜と思ってます。

コード

boot-project
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"

	"github.com/TheWolfNL/go-multiplechoice"
)

type Project struct {
	Name    string   `json:"name"`
	Path    string   `json:"path"`
	Commands []string `json:"commands"`
}

func main() {
	projects, err := loadProjects("project-list.json")
	if err != nil {
		fmt.Printf("プロジェクトリストの読み込みに失敗しました: %v\n", err)
		return
	}

	var projectNames []string
	for _, project := range projects {
		projectNames = append(projectNames, project.Name)
	}

	selectedName := MultipleChoice.Selection("開きたいプロジェクトを選択してください: ", projectNames)

	runCommands := MultipleChoice.Selection("プロジェクト起動後にコマンドを実行しますか?", []string{"yes", "no"})

	var selectedProject *Project
	for _, project := range projects {
		if project.Name == selectedName {
			selectedProject = &project
			break
		}
	}

	if selectedProject == nil {
		fmt.Println("選択されたプロジェクトが見つかりませんでした。")
		return
	}

	err = openVSCode(selectedProject.Path)
	if err != nil {
		fmt.Printf("VSCode の起動に失敗しました: %v\n", err)
		return
	}
	fmt.Printf("VSCode でプロジェクトを開きました: %s (%s)\n", selectedProject.Name, selectedProject.Path)

	if runCommands == "yes" && len(selectedProject.Commands) > 0 {
		for _, command := range selectedProject.Commands {
			fmt.Printf("コマンド実行中: %s\n", command)
			err := runCommandInTerminal(selectedProject.Path, command)
			if err != nil {
				fmt.Printf("コマンドの実行に失敗しました: %v\n", err)
			} else {
				fmt.Printf("コマンドが実行されました: %s\n", command)
			}
		}
	}
}

func loadProjects(filePath string) ([]Project, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var projects []Project
	decoder := json.NewDecoder(file)
	err = decoder.Decode(&projects)
	if err != nil {
		return nil, err
	}

	return projects, nil
}

func openVSCode(projectPath string) error {
	cmd := exec.Command("code", projectPath)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func runCommandInTerminal(projectPath, command string) error {
	cmd := exec.Command("sh", "-c", command)
	cmd.Dir = projectPath
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}
project-list
[
  {
      "name": "Project A",
      "path": "Project A Path",
      "commands": ["echo 'project A'", "echo 'hello'"]
  },
  {
      "name": "Project B",
      "path": "Project B Path",
      "commands": ["command"]
  }
]

終わりに

Go言語ちゃんと書いたことないので簡単なCLIの実装してみました。
Go言語割と読みやすいのと標準ライブラリが充実してるのが結構好きです。
プロジェクトを沢山抱えてるとプロジェクトの起動コマンド忘れたりすることもあるので割と使えそうなもの作れて良かったな〜と思ってます。

Discussion