2022年5月31日火曜日

シェルの結果をパイプを使ってRubyで受け取る方法

シェルの結果をパイプを使ってRubyで受け取る方法

概要

わざわざ Ruby スクリプトを書かないでも簡単に Ruby を使ってシェルの結果をパースしたりできます

環境

  • macOS 11.6.6
  • Ruby 3.1.1p18

echo を受け取る

とりえあずシェルの echo した文字列を Ruby の puts でそのまま出力する方法です

echo hoge | ruby -ne 'puts $_'

ポイント

  • $_ 最後に読み込んだ行になります
  • -ne はこの順番でなければなりません、n は結果を1行ごとに処理するオプションです、具体的には while gets … end で囲まれた状態で実行されています。e オプションは指定された Ruby スクリプトを実行するオプションです

ループさせる

シェルの結果がスペースで区切られた値を Ruby 側の Enumerator に変換して処理する場合などに使えます

echo hoge fuga | ruby -ne '$_.split(" ").each {|s| puts "Hello #{s}" }'

JSON をパースする

シェルの結果が JSON の場合に Ruby 側で受け取ってハッシュに変換して処理します

echo '{"name":"hawk","age":10}' | ruby -ne 'require "json"; JSON.parse($_).each {|k,v| puts "#{k} => #{v}" }'

もしくは -r オプションを使って require できます

echo '{"name":"hawk","age":10}' | ruby -rjson -ne 'JSON.parse($_).each {|k,v| puts "#{k} => #{v}" }'

最後に

慣れれば結構便利に使えます
そもそも ruby がインストールされていないケースが多いのでそこが何ともですが

2022年5月28日土曜日

macOS で cat や echo をクリップボードにコピーする方法

macOS で cat や echo をクリップボードにコピーする方法

環境

  • macOS 11.6.6

コマンド

基本はパイプで繋げば OK です

  • cat hoge | pbcopy

2022年5月27日金曜日

OpenAPI or Swagger ファイルを分割して管理する方法

OpenAPI or Swagger ファイルを分割して管理する方法

概要

今回は swagger-cli を使った方法を紹介します
どんなツールを使うにしろ最終的には分割した YAML ファイルを結合する処理が必要になります

環境

  • macOS 11.6.6
  • swagger-cli

swagger-cli のインストール

  • npm install -g @apidevtools/swagger-cli

分割前のファイル

共通部分などを各パートごとに分割します
以下は分割前のファイルになります

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  type: object
                  required:
                    - id
                    - name
                  properties:
                    id:
                      type: integer
                      format: int64
                    name:
                      type: string
                    tag:
                      type: string
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - name
                properties:
                  id:
                    type: integer
                    format: int64
                  name:
                    type: string
                  tag:
                    type: string

schemas/pet.yaml の作成

レスポンスで使用するオブジェクトが共通なので分割します
schemas/pet.yaml として切り出します

  • vim schemas/pet.yaml
type: object
required:
  - id
  - name
properties:
id:
  type: integer
  format: int64
name:
  type: string
tag:
  type: string

あとはこれを ref で参照します

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - name: limit
          in: query
          description: How many items to return at one time (max 100)
          required: false
          schema:
            type: integer
            format: int32
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "./schemas/pet.yaml"
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - name: petId
          in: path
          required: true
          description: The id of the pet to retrieve
          schema:
            type: string
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "./schemas/pet.yaml"

parameters の分割

今度は少し応用テクニックを紹介します
parameters の役割で分割して管理しやすくしてみます
まず定義した parameters をすべて読み込むファイルを作成します

  • vim parameters/_index.yaml
petId:
  $ref: './petId.yaml'
limit:
  $ref: './limit.yaml'

パラメータはそれぞれ個別ファイルに定義します

  • vim parameters/petId.yaml
name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
  type: string
  • vim parameters/limit.yaml
name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
  type: integer
  format: int32

あとはそれぞれのファイルをメインのファイルから参照するように変更します

  • vim openapi.yaml
openapi: 3.0.0
info:
  title: split test
  version: 1.0.0
paths:
  /pets:
    get:
      summary: List all pets
      operationId: listPets
      tags:
        - pets
      parameters:
        - $ref: "./parameters/limit.yaml"
      responses:
        '200':
          description: A paged array of pets
          content:
            application/json:
              schema:
                type: "array"
                items:
                  $ref: "./schemas/pet.yaml"
  /pets/{petId}:
    get:
      summary: Info for a specific pet
      operationId: showPetById
      tags:
        - pets
      parameters:
        - $ref: "./parameters/petId.yaml"
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                $ref: "./schemas/pet.yaml"
components:
  parameters:
    $ref: "./parameters/_index.yaml"

ファイルを結合して動作確認

ファイルの結合には swagger-cli を使います

  • swagger-cli bundle openapi.yaml --outfile _build/openapi.yaml --type yaml

これで _build/openapi.yaml が出来上がるので swagger ui などで確認するとちゃんと分割前と同じ情報が確認できると思います

できあたがったファイルを見ると ref 先をファイルに埋め込んでパスで無理やり参照しています

また今回の分割後のファイル構成は以下のようになっています

% tree .                     
.
├── _build
│   └── openapi.yaml
├── openapi.yaml
├── parameters
│   ├── _index.yaml
│   ├── limit.yaml
│   └── petId.yaml
└── schemas
    └── pet.yaml

3 directories, 6 file

最後に

基本は分割して ref で参照して結合するだけです
分割の仕方はいろいろありますが基本的には共通部分や役割ごとに分割すると良いと思います

参考サイトにあるように parameters, responses, schemas で分割してあとは paths ごとにもファイルを作成すると管理しやすそうです

参考サイト

2022年5月20日金曜日

Ubuntu でユーザを追加してノンパス sudo できるようにするまでの流れ

Ubuntu でユーザを追加してノンパス sudo できるようにするまでの流れ

概要

ユーザを追加してノンパス sudo できるようにする一連の流れをメモ
作業は root ユーザで行っています

環境

  • Ubuntu 18.04

ユーザ追加

  • adduser test

sudo 追加

  • gpasswd -a test sudo

sudo ノンパス化

  • visudo
#includedir /etc/sudoers.d
test  ALL=(ALL) NOPASSWD:ALL

おまけ: root グループ追加

  • usermod -aG root test

最後に

あとは各種 git の設定や言語の設定は作成したユーザで個別に行う必要があります

2022年5月18日水曜日

(Python) nifcloud と botocore を共存させる方法

(Python) nifcloud と botocore を共存させる方法

概要

nifcloud が botocore にパッチを当てているため使うたびに reload で切り替える必要がある

環境

  • Python 3.10.2
  • nifcloud 1.0.3
  • botocore 1.21.43

サンプルコード

nifcloud が import されている状態で nifcloud を再度 reload しようとすると無限ループになるので botocore のときに nifcloud に戻すように条件分岐する必要がある

import importlib

import botocore
import nifcloud

# nifcloud モードへ
if botocore.session.Session().user_agent_name != 'nifcloud':
    importlib.reload(nifcloud.session)
    importlib.reload(nifcloud.loaders)
from nifcloud import session

client = session.get_session().create_client(
    "computing",
    region_name="jp-east-1",
    nifcloud_access_key_id="xxx",
    nifcloud_secret_access_key="xxx")
client.describe_instances()

# botocore モードへ
importlib.reload(botocore.session)
importlib.reload(botocore.loaders)
from botocore import session

client = session.get_session().create_client(
    's3',
    aws_access_key_id='xxx',
    aws_secret_access_key='xxx',
)
client.list_buckets()

# 再度 nifcloud モードへ
if botocore.session.Session().user_agent_name != 'nifcloud':
    importlib.reload(nifcloud.session)
    importlib.reload(nifcloud.loaders)
from nifcloud import session

client = session.get_session().create_client(
    "computing",
    region_name="jp-east-1",
    nifcloud_access_key_id="xxx",
    nifcloud_secret_access_key="xxx")
client.describe_instances()

同一プロセスないで両方使う場合は上記のようにしないとダメなようです
面倒な場合は別プロセスにしても OK です

2022年5月17日火曜日

(Python) because these package versions have conflicting dependencies

(Python) because these package versions have conflicting dependencies

概要

pipenv install 時に依存関係を解決できずに発生するエラーです
バージョンを固定している場合に発生するケースが多い印象です

環境

  • macOS 11.6.5
  • Python 3.10.2

エラー概要

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/user_guide/#fixing-conflicting-dependencies となり pipenv install できない

原因

新規でインストールしようとしているパッケージが依存しているパッケージがすでにインストールされておりすでにインストールされているパッケージのバージョンと新規でインストールしようとしてるパッケージのバージョンに互換がなくエラーになっている

対策

新規でインストールしようとしているパッケージはバージョン指定せずに pipenv 側に一旦まかせる

  • pipenv install xxx

これで自動的にインストール可能なバージョンがインストールされるのでその後 Pipfile を編集してバージョン情報を記載する

xxx = "==1.2.3"

ただこの場合だとすでにインストールされているパッケージのバージョンに依存して新規のパッケージがインストールされるので必ずしも最新場のパッケージがインストールされるとは限りません

もし最新のバージョンをインストールしたい場合は依存しているパッケージのバージョンを最新にしてからインストールする必要があります

2022年5月12日木曜日

Ruby でセマンティクスバージョンニングの比較をする方法

Ruby でセマンティクスバージョンニングの比較をする方法

概要

Ruby でセマンティクスバージョニングを比較する場合は標準で使える Gem::Version クラスを使います

環境

  • macOS 11.6.5
  • Ruby 3.1.1p18

サンプルコード

puts Gem::Version.new('0.3.2') < Gem::Version.new('0.10.1')
puts Gem::Version.new('0.3.2-pre') < Gem::Version.new('0.3.2')
puts Gem::Version.new('14.7.7-ee.0') < Gem::Version.new('14.6.8-ee.0')

新しいバージョンが true になります