Closed6

Rustの勉強のためにpretty-envコマンドを作成してみる

Yuki ShindoYuki Shindo

Rustの学習ネタを探して

最近Rustを触り始めたので勉強のネタを探している。
今回、作業の合間に息抜き感覚で作れそうなネタを探していたが、ふと env コマンドをいい感じに出力するコマンドはどうだろうかと考えた。

これを pretty-env コマンドと名付けてみることにする。

表示内容を整形するだけのツールであれば、おそらくコードの規模感的にも気軽に作れるのではないだろうか。

いきなりRustで書くのでもよいが、まずはプログラムの全体像を把握する意味でも一度慣れている言語で試し書きをしてみることにした。
というわけで、まずはJavaScript(Node.js)で作成してみる。

Yuki ShindoYuki Shindo

envコマンドの出力結果は execSync を利用して取得する。

env コマンドの結果は一行に対して一つの環境変数となっているので、最初は Readline を利用して一行ずつ処理をしていこうとしたが、これがエラーになってしまうので、ひとまず下記のように一行を一つのenvとして扱い、配列化して処理していくことにする。
(readline を利用した際のエラーの詳細はメモするの忘れてしまっていたので割愛...ハマりそうだったので、このやり方に変えた)

envコマンドの出力結果を1行ごとに配列に格納していくサンプル(Node.js)

const { execSync } = require("child_process");

// envコマンドの出力結果が入る
const stdout = execSync("env");

// 一行に対して一つの環境変数、となっているのでこのようにして配列化してしまう
const envList = stdout.toString().trim().split("\n");

ちなみにとにかく動けりゃヨシ的な形でコードは書いています。
あとひとまずは手元のmacでのみ動かすことを目的としています。そのため各OSごとの対応などは今のところ実装しない予定です。

Yuki ShindoYuki Shindo

swc-nodeを利用してTypeScriptでNode.jsを書いていく

せっかくなのでswc-nodeを利用して TypeScriptで書いていくことにした。
https://github.com/swc-project/swc-node

下記でインストールして、

yarn add -D @swc-node/register

npm scriptsに下記を追加する。

※一部抜粋

  "scripts": {
    "dev": "node -r @swc-node/register src/pretty-env.ts"
  },

DenoのlintとfmtをNode.jsのプロジェクトで利用する

ついでに lintfmt コマンドも用意する。
自分しか触らないつもりのコードだし、わざわざeslintprettierを入れるのも面倒に思えたので、Denoのlintfmt コマンドをプロジェクト内で利用することにする。

deno.jsonc をプロジェクトルートに配置し、下記を記述する。

{
  "lint": {
    "files": {
      "include": [
        "src"
      ],
      "exclude": ["node_modules"]
    },
    "rules": {
      "tags": ["recommend"],
      "exclude": []
    }
  },
  "fmt": {
    "files": {
      "include": [
        "src",
        "deno.jsonc"
      ],
      "exclude": ["node_modules"]
    }
  }
}

lint.rules.exclude には何も入力していないがコードを書き出して入れたくなったら入れていく。

package.jsonに下記を記述する。

  "scripts": {
    "dev": "node -r @swc-node/register src/pretty-env.ts",
    "lint": "deno lint -c deno.jsonc",
    "fmt": "deno fmt -c deno.jsonc"
  },

これでひとまず準備はOKそうなので、コードを書いていく。

Yuki ShindoYuki Shindo

書いてみたコードがこちら。GitHubにあげている。

https://github.com/shinshin86/pretty-env-js

頑張りすぎて途中で挫折するのは一番避けたいと思い、実装する上で結構楽をしている。
例えば、

  • env の出力結果を表示するだけのツールという限定的な機能しか持ち合わせておらず、日本語などは扱わないので、文字数の扱いは雑( foo.length みたいな感じで文字数を扱ってしまっている)
  • 長いパスについてはテーブルの見た目を優先するために、途中で省略している
  • テーブルの枠組みは -| だけで作った。(本当は を使うような方法もあるが、実装料も増えるし、この2つだけでも最低限の見た目になるので、そうした)

というわけで、こちらの実装をベースにRustで実装していってみる。

Yuki ShindoYuki Shindo

envコマンドの出力結果を1行ごとに配列に格納していくサンプル(Rust)

Rustで早速envコマンドの出力結果を1行ごとに配列に格納していくサンプルを作ってみた。

use std::process::Command;

fn main() {
    let output = Command::new("sh")
        .arg("-c")
        .arg("env")
        .output()
        .expect("failed to execute process");
    let env_str = String::from_utf8(output.stdout).unwrap();
    let env_list: Vec<&str> = env_str.split('\n').collect();
    println!("{:?}", env_list);
}

これで

["env1行分の文字列", "env1行分の文字列", "env1行分の文字列",...]

という形で出力される。

これをベースにして実装していってみる。

Yuki ShindoYuki Shindo

書いてみたコードがこちら。GitHubにあげている。
https://github.com/shinshin86/pretty-env-rs

出力結果をよくよく見ていると、項目によって1文字分ずれているような気がする...
(もしかしたらJS側の実装もそうなっている??)

テストコードなどは一切書いていないし、そこらへんも書いていきながら、今後実装は洗練させていきたいところ。
せっかく pretty-env と名付けたので、もう少し pretty 感も加えていきたい。

ひとまず学習の記録としてはこれで一区切り。

このスクラップは2022/04/17にクローズされました