PythonでCLIツールを作ってみた

2022/08/24に公開

PythonでCLIツールを作成しました。

LT会でも発表しました。

▼発表したLT会
https://yumenosora.connpass.com/event/255075/

▼スライド

▼ソースコード
https://github.com/OHMORIYUSUKE/grech

概要

このツールを実行させることで、YAMLで定義されたテストを実行させることができます。
YAMLファイルにはshellが記載されており、shellの実行結果が正規表現にマッチするかどうかで正誤判定を行います。

▼テストを実行した様子

工夫した点

YAMLファイル

# このチェック項目の名前
name: OS-lecture-check
description: オペレーティングシステムのチェックシナリオ
# ハンズオンシナリオのURL
docs_url: https://cist-operating-system.netlify.app/
# 作者
author: yusuke-ohmori
# コピーライト
copyright: © 2022 yusuke-ohmori

# ユーザーごとに値が異なる場合に、ユーザーに指定してもらう
config:
  # rootはデフォルトでの値(ユーザーが設定しなければこの値になる)
  MYSQL_USER: root
  MYSQL_PASSWORD: root

# ユーザーの設定が正しいかを確認するためのシナリオ
check:
  # Apache2などの値は、シナリオ設定者が項目ごとに分割するために設定する
  Apache2:
    # Apache2 内でテストする項目を記載する
    # name : 確認項目の名前
    - name: Apacheがインストールできているか確認
      # 確認するためのコマンド
      cmd: apache2 -v
      # 複数の正規表現の「いずれかにマッチ」か「すべてにマッチ」を指定
      # or または andを指定
      regexp:
        - type: or
        # 正規表現
        - list: ["Server version: Apache/"]
      # 上記のコマンドを実行するディレクトリを指定
      working-directory: /home/ubuntu
      # 上記の正規表現にマッチしなかった場合に表示されるヒント
      message: |
        Apacheが正常にインストールできていない可能性があります。
  MySQL:
    - name: MySQLアクセスできるか確認
      cmd: echo "SELECT Host, User FROM mysql.user" | mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD}
      regexp:
        - type: and
        - list: ["localhost", "root"]
      working-directory: /var/www/html
      message: |
        MySQLにアクセスできません。
        `sudo grech config set`でMySQLのユーザー名(root)とあなたが設定したrootのパスワードを設定してください。
    - name: MySQLにユーザーを作成されているか確認
      cmd: echo "SELECT Host, User FROM mysql.user" | mysql -u${MYSQL_USER} -p${MYSQL_PASSWORD}
      regexp:
        - type: and
        - list: ["localhost", "webapp"]
      working-directory: /var/www/html
      message: |
        指定されたユーザーが作成されていません。webappユーザーを作成しましょう。

このツールをpipでインストールし、このようなYAMLを指定します。YAMlファイルは公開し、ツールを実行するユーザーはYAMLのURLを指定し、テストを実行します。

configで環境ごとに異なる値を設定させることができます。

コード

def __change_env_value(self, cmd: str) -> str:
        yaml_data = TestSetUp().init()
        for config_data in yaml_data["config"]:
            if config_data in cmd:
                cmd = re.sub(
                    "\$\{( *" + config_data + " *)\}",
                    ReadConfig().read_config(name=config_data).value,
                    cmd,
                )
        return cmd

正規表現でマッチした箇所をユーザーが設定した値に置換する処理を行い実装しました。

型を定義

エラーを回避するため、型定義も行いました。

最初にYAMLファイルをどうするかを決定し、そこから型をひたすら定義しました。

▼テスト1つの型を定義

from typing import List
from pydantic import BaseModel


class Regexp(BaseModel):
    type: str
    list: List[str]


# テスト1つ
class Test(BaseModel):
    name: str
    cmd: str
    working_directory: str
    regexp: Regexp
    message: str

https://pydantic-docs.helpmanual.io/

pydanticを用いることで、Pythonで型のエラーが発生するようにしました。

最後に

CLIツールを作るのは初めてだったのですが、WEBアプリケーションを作るような感覚で作ってみました。

Discussion