けけずんセルフハッキング

エンジニアっぽい雰囲気を醸しだしているかのようなブログです!

PhpStormからDockerコンテナ内のPHPUnitを実行する

この記事について

株式会社Re:Buildアドベントカレンダー Advent Calendar 2020 の11日目の記事。

PhpStorm開いてる人に「今開いているテストファイルのこのテスト関数実行してみて」というと、大体の人がphpunitコマンドを叩いて全てのテストを実行していた。テストコードが増えてきた段階でこんなことをしてしまうと待ち時間が大変なことになるので、PhpStormから特定のテストを実行する方法(というか設定)を書き残しておく。

準備

PHPUnitのテストをDockerコンテナ内で行うためのサンプルを作ったのでこれをcloneし、composer installを実行する(composerがローカルに入っていない人は申し訳ないが頑張ってインストールしてね。)

$ git clone git@github.com:kkznch/20201212-phpunit-with-phpstorm.git
$ cd 20201212-phpunit-with-phpstorm
$ composer install

準備できたらPhpStormで上記のプロジェクトを開いてね。

設定手順

PHP CLI Interpreterの設定

PHPを実行する際にどの環境のものを使用するのか設定する。

  1. PhpStormのPreferencesを開く
  2. "Languages & Frameworks"->"PHP"を開き、"CLI Interpreter"の右端にある"..."をクリックする f:id:kkznch:20201212165412p:plain
  3. 左上にある "+" ボタンをクリックし、"From Docker, Vagrant, VM, WSL, Remote..." を選択する f:id:kkznch:20201212170010p:plain
  4. "Docker Compose"を選択し、"Configuration file(s)"にPhpStormで開いているプロジェクトのdocker-compose.ymlファイルへのパスを入力、"Service"に起動するコンテナ名(今回はphpという名前)を指定する f:id:kkznch:20201212170610p:plain

ここまで設定すると以下の画面が表示される。 画面真ん中にある"Lifecycle"は、PHP実行時に都度コンテナを起動するか、または既に起動しているコンテナを使用してPHPを実行するか、の二択。 php-fpmのように常時起動しているコンテナであれば後者の方を選択してもいいが、今回は単発起動で十分なので前者を選択しておく。 ここで"OK"ボタンを押してCLI Interpreterの設定は完了。 f:id:kkznch:20201212170841p:plain

PHPUnit実行時のCLI Interpreterの設定

PHPUnitを実行する際にどのCLI Interpreterを使用して実行するか設定する。

  1. PhpStormのPreferencesを開く
  2. "Languages & Frameworks"->"PHP"->"Test Frameworks"を開き、"+"ボタンをクリックし、"PHPUnit by Remote Interpreter"を選択する f:id:kkznch:20201212171811p:plain
  3. "Interpreter"に先程PHP CLI Interpreterで設定した設定(今回はphpという名前)を選択し、"OK"ボタンをクリックする f:id:kkznch:20201212171829p:plain
  4. "Path to script"にコンテナ内にあるautoloaderへのパス(今回は/root/vendor/autoload.php)を指定し、"OK"ボタンをクリックする f:id:kkznch:20201212172056p:plain

これでPHPUnitの実行設定が完了。

実行方法

PhpStormで実行したいテストが記述されたファイル(tests/SampleTest.php)を開くと、エディタの行番号表示欄の右側に謎の緑色が見えるはず。クラス定義をしている行の緑色をクリックし"Run 'SampleTest'"を選択するとクラス全体のテストが実行される。

また、関数定義をしている行の緑色をクリックし"Run 'testFirst'"を選択すると、testFirstというテスト関数だけが実行される。 f:id:kkznch:20201212173335p:plain

おわりに

phpunitコマンドでも特定のテストファイル、特定のテスト関数のみを実行することはできるが、PhpStormからぽちぽち実行できると楽だよね。

この記事書いた後に「phpstorm コンテナ phpunit」で検索すると似たような内容の記事がいっぱいでてきたので、書く前に調べておけばよかったと反省している。

参考

qiita.com qiita.com

React Nativeを使ったプロジェクトを通して感じたこと

この記事について

株式会社Re:Buildアドベントカレンダー Advent Calendar 2020 の6日目の記事。 案件でReact Nativeのプロジェクトに携わった際にやっててよかったこと、やっておいたほうがよかったこと、やらなければよかったことなど書いていく。

はじめに

けけずんスキルセット

普段バックエンドばかり担当しているため、フロントエンドについてはJavaScriptが(本当に)少し分かり、Vue.jsが(本当に)少し書ける程度。 基本的にWebアプリを中心に開発をしているため、実務でのネイティブアプリ開発経験はないが、大昔に4人チームでiOSアプリの開発をしてリリースまではしたことがあるレベル。

使用したパッケージのバージョン

  • react-native@0.61.4
  • expo@37.0.11

開発当初はexpo@38が最新版だったが、最新版はバグが潜んでいる可能性が高いということで最新版よりひとつ前のexpo@37を使用した。

開発時にやってよかったこと

React Nativeのお勉強

  • 公式のドキュメントやUdemy、書籍などざっと目を通しつつ手を動かしつつ、一通りの流れを学んだ
  • Webとは異なった概念がいくつか見られ、そこを理解するのに苦労した
    • react-navigationのスタック、タブ、ドロワーなどの概念
    • 画面遷移の流れが開発に与える影響など大変だった

ネイティブアプリ開発経験のある方に手伝ってもらったこと

  • React Nativeの使い方などもそうだが、アプリ開発をする際に何から手を付ければいいのか、アプリのリリースをする際に何をしたらいいのかなど全く分からなかった
    • iOSだとApple Developerで証明書やらプロファイルやら色々と設定しないといけないし(開発環境に関してはExpoが自動で設定してくれる)、ビルドしたものを端末で確認するまでの手順がなかなか面倒だった
    • Androidはビルドしたapkファイルをインストールするだけで動く
  • アプリ開発からリリース・運用を一通り経験したことがある人が一人いるだけで疑問点や不安が解消されるので、初めてアプリ開発を行う場合は経験者に入ってもらう方がよい

生のReact Nativeではなく、Expoを使用したこと

  • Expoを使用することで開発時に実機での動作確認が楽にできる
  • OTAアップデートを利用し、ストアへ公開せずにアプリのアップデートを行える
  • しかし特定のライブラリ(Stripeとか)を使う際はExpoのままだと使用できないため、ejectする必要があるらしい
    • ejectする必要がでてくるとそれはそれで後で面倒なことになりそうな気もするので、何を作るのか決まっていて且つどのパッケージが必要なのか分かっているのであれば、その段階でexpo使うか使わないか決めるほうがよさそう

Textコンポーネントのデフォルトフォント対応したこと

  • React NativeでTextコンポーネントを使用した際、フォントファミリーにOSのデフォのフォントが使用される
  • 任意のフォントファミリーを使用したい場合、Textコンポーネントのスタイルに fontFamily: ほげほげ というように指定する必要があるが、Textコンポーネントを使用するたびに指定するのはさすがに面倒臭い
  • 任意のフォントをデフォルトフォントとして使用できるよう、Textコンポーネントをラップした自作Textコンポーネントを使用することで結構楽になった

こんな感じ。 OS毎にデフォルトフォント切り替えるようにしてる。

import React from 'react';
import { Platform, StyleSheet, Text as RNText, TextProps } from 'react-native';

export const Text: React.FC<TextProps> = (props: TextProps) => {
  const { style = {} } = props;
  return (
    <RNText
      allowFontScaling={false}
      {...props}
      style={[styles.default, style]}
    />
  );
};

const styles = StyleSheet.create({
  default: {
    fontFamily:
      Platform.OS === 'android' ? 'ほげフォント' : 'ふがフォント',
  },
});

やっておいたほうがよかったこと

Reactのお勉強

  • ReactとReact Nativeは全然別物だよと言われ、なるほどJavaJavaScript的な感じかと思いReactは基礎しか勉強してなかったが、普通にReactの構文やAPI使いまくりなので深く理解しておく必要があった
  • useEffectはVue.jsでいう変数の変更検知やmounted的なことができるというのはなんとなく理解して使っていたが、それ以外のhooksについては使い方や使い道が理解できていない部分が多く、開発を通しながら勉強して理解していった、大変だった

フォルダ、ファイルの役割を明確化

  • React NativeまたはExpoでプロジェクトを作成した際に生成されるフォルダはある程度役割が決まっており、ドキュメントを見るとその内容を開発者全体で共有できると思うが、自前で用意したフォルダ(helpersとかlibsとか)についてはREADMEに役割など明記した上で全体に共有する方がよい
  • @types の例
    • type.d.ts: プロジェクト内で使用される概念の型を定める
    • request.d.ts: APIのリクエストを投げる際に渡す引数の型を定める
      • 引数がid, uuidなど単純で且つ引数の数が少ない場合は型定義をせず、APIをコールする関数の引数に直接定義してよいと思っている
      • プロジェクト全体で使用せず、リクエスト時のみ使用したい型定義などは本ファイルに定義する
    • response.d.ts: APIをリクエストして返ってくるレスポンスの型を定める
      • 本ファイルで定義した型を、kAPIをコールする関数の返り値の型として使用するが、type.d.ts で定義した型とほぼ同一の場合は type.d.ts の型を使用してよいと思っている
      • プロジェクト全体で使用せず、レスポンスを受け取る箇所でのみ使用したい型定義などは本ファイルに定義する

ビルドする際のバージョン番号のルール決め

  • デプロイする環境が本番環境以外にも存在する場合はそれも考慮してバージョン番号のルールを決める方がよい
  • 例えば複数の環境にデプロイする場合、x.y.z というバージョン番号のうち x はメジャー番号、 y はマイナー番号、 z はデプロイする環境に対応する番号、というふうに決めるなど
  • バージョン番号を上記のようにしておけば

Expoのバージョンアップ

  • プロジェクト開始初期はExpo SDK 37だったが、現在はExpo SDK 39らしい
  • 使用できるコンポーネントなども増えてより一層便利になってるっぽいので、早めにバージョンアップしておけばよかった

デザインのコンポーネント

  • お客さんからあがってきたデザインがある程度固まっているのであれば、その段階で共通部分を抽出してコンポーネント化したほうがよい。さもなくば死ぬ
  • というかこれはそもそもエンジニアサイドで行う作業なのか?どこが共通の箇所かというのはデザイナーが把握しているから、デザイナーが行うべき作業?

画面遷移の流れや、スタック、タブ、ドロワーのどちらを使用するか決める

  • 画面がどこにどう遷移するかを決めておかないとデータの持ち方や渡し方など決めることができない。適切にコンポーネント化されてあるのであれば例え画面の遷移が変わったとしてもコンポーネントの組み合わせを工夫すればどうにかなると思うが、適切にコンポーネント化されていなければ辛いところ
  • iOSの場合だとアプリのガイドラインなどに従って画面のデザイン、流れなどを考えておくほうがアプリの審査に通りやすくなるので、基本的にはアプリをデザインするデザイナーさんにはiOSアプリガイドラインを一通り見ておいて欲しい、エンジニアも然り

実装が困難なデザインや、実装できたとしても動作に支障をきたすようなデザインは避けてもらう

  • 頑張ればある程度どんなデザインが来ても対応できなくはないが、デザインに合わせて地味に難しい実装をするのは現実的ではない
  • そのデザインがアプリのメインの機能だったりした場合は頑張って実装し、特にこだわりも何もないデザインであれば事情を説明して別の提案を持ちかけるのはありだと思う

用語の統一(プロジェクトの話)

  • お客さん、社内どちらも統一しておくべき
  • 同じ事柄を指しているのに異なる用語を使用したり、同じ用語だけど異なる事柄を指していたりすることが多々あった
  • 必ずしも最初に定める必要はないと思うが、話が噛み合っていない場合など都度用語を確認しあい、以降は定めた用語を使用してやり取りを行うほうがよさそう

やらなければよかったこと

なんちゃってAtomic Design

まずはよくあるAtoms, Molecules, Organismsフォルダを作成。そしてある画面を作成するとき、Organismsフォルダに画面の一部をコンポーネントとして作成しておき、その中で更に細分化できそうであればMoleculesフォルダにコンポーネントを作成、そこから更に細分化できそうであればAtomsフォルダにコンポーネントを作成する、という流れでやっていこうと考えていたが、エンジニアが数名増えた段階でなんだか色んなコンポーネントが色んなところに置かれるようになってしまった。多分一人で開発していても同じような状況になっていたかもしれん。デザインが確定しているのであれば、先にデザインからコンポーネントを抽出すべきだったかも。

外部パッケージのUIコンポーネントの使用

デザインをNative Baseというライブラリをベースに作成してくれるということでプロジェクト開始初期段階からNative Baseをインストールして画面を作成していたが、デザインに変更がかかりNative Baseを使用したデザインとは全く異なったデザインになった。Native Baseのコンポーネントのスタイルを書き換えるのも大変なので、結局Native Baseが使われている箇所はNative Baseを使わないように修正する作業を行うはめになった。今回はNative Baseは使わないほうがよかったが、簡易的なモックなど作る場合であれば割と効果的かもしれない。

ボタンクリック時に副作用を考慮せず実装したこと

ボタンをクリックしてAPIを実行する際は、クリックされたことをuseEffectで検知してAPIを実行する方がよい。useEffectを使わない場合、ボタンを押したときに発火する関数の中で変数の値が変わるとコンポーネントの再レンダリングがされてしまい思った通りの挙動にならないときがあった。

修正前

export const  Component = () => {
  const onClick = () => {
    // API 実行する処理
  }
  
  return  <button onClick={onClick}>;
}

修正後

export const  Component = () => {
  const [isClick, setIsClick] = useState<boolean>(false);
  
  useEffect(() => {
    // API実行する処理
  }, [isClick]);
  
  const onClick = () => {
    setIsClick(true);
  }
  
  return  <button onClick={onClick}>;
}

iOSのセーフエリアをスタイルで設定したこと

iOSのセーフエリア分の高さを空けるためにreact-native-safe-area-contextのuseSafeArea hooksを使って必要な箇所で const { top } = useSafeArea(); と呼び出しtop分の高さをスタイルに指定していた。しかしそんなことをしなくてもセーフエリア分の高さを空けたい箇所に <SafeAreaView /> とするだけで自動で計算してセーフエリア分の高さを確保してくれるので、素直にSafeAreaViewを使うべきだった。

修正前

export const  Component = () => {
  const { top } = useSafeArea();
  
  return (
    <View style={{ height: top }}>
     // 何かしらのコンテンツ
    </View>
  );
}

修正後

export const  Component = () => {
  return (
    <SafeAreaView>
     // 何かしらのコンテンツ
    </SafeAreaView>
  );
}

おわりに

開発中にこうしておけばよかったということをよく考えるが、それを今思い出そうとしても中々思い出せないものだな。 思い出したら都度更新していきたい。 あともう少しキレイにまとめたい気持ちもある。

参考サイト

Terraform使ってみる(2) 〜 設定に変数用いて外から値を注入してみる編

概要

前回に引き続き、今回もTerraform触ってみる。 今回は設定ファイルに変数を使用し、コマンド実行時に外から値を注入してみる。

前回の記事はこちら

Terraform使ってみる

Terraformで設定ファイルに変数を使用する

公式的なサイトはこちら。 HashCorp Learn - Define Input Variables

事前準備

前回同様、任意の場所フォルダを作成する。

$ mkdir terraform-example
$ cd terraform-example

以下の内容で設定ファイル main.tf を作成する。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 2.70"
    }
  }
}

provider "aws" {
  profile = "default"
  region = "ap-northeast-1"
}

resource "aws_instance"  "example" {
  ami = "ami-830c94e3"
  instance_type = "t2.micro"
}

準備おっけー。

変数定義ファイルの作成と参照

設定ファイル main.tf と同じ場所に、以下の内容で変数定義ファイル variables.tf を作成する。 ここで変数として定義しておくことで、 terraform apply コマンド実行時にオプションで変数に値を割り当てることができる。 変数の値を指定していない場合は variables.tf で定義した default 値が使用される。

variables "region" {
   default = "ap-northeast-1"
}

これで設定ファイル main.tf の中で変数の値を参照できるようになった。 設定ファイル main.tf を以下のように編集する。

provider "aws" {
  profile = "default"
-  region = "ap-northeast-1"
+  region = var.region
}

変数への値割当て

上述したように terraform apply コマンド実行時にオプションで変数に値を割り当てることができる。 以下では region という変数に ap-northeast-1 という値を割り当てている。

$ terraform apply -var 'region=ap-northeast-1'

また、変数への値の割当をファイルから行うこともできる。 以下の内容の terraform.tfvars というファイルを作成する。 terraform.tfvarsterraform apply コマンド実行時にデフォルトとして自動で読み込まれる。

region = "ap-northeast-1"

なお terraform.tfvars ではなく my-variables.tfvars といった任意の名前をつけたとき、 以下のように terraform apply コマンド実行時にオプションでファイルを指定することで、ファイルに記述された値を変数に割り当てることができる。

$ terraform apply -var-file 'my-variables.tfvars'

変数のタイプ

変数には List や Map を使用することができる。

List

こちらが変数の定義。

variable "cidrs" { default = [] }

こちらが値の割当て。

cidrs = [ "10.0.0.0/16", "10.1.0.0/16" ]

Map

こちらが変数の定義。

variable "amis" {
  type = "map"
  default = {
    "us-east-1" = "ami-b374d5a5"
    "us-west-2" = "ami-fc0b939c"
  }
}

こちらが値の割当て。

resource "aws_instance" "example" {
  ami = var.amis[var.region]
  instance_type = "t2.micro"
}

おわりに

Terraformの設定ファイルに変数を用いて、値を外部から注入してインフラを構築できるようにはなった。 ファイル内に値を直書きするのもいいけど、それだと再利用性低いので、可変な値は変数化して使いまわしできるようにしていくとよさそう。

Terraform使ってみる(1) 〜 インストールして動かしてみる編

概要

いつも簡単なインフラばかり構築してたからコード化する必要ないよねって思ってたけど、最近それすら億劫になっている。 というわけで今更だけどTerraformを使ってみるよ。

Terraformのインストール

公式サイト的なのはこちら。

HashCorp Learn - Install Terraform

ひとまずコマンド実行。

$ brew tap hashicorp/tap
$ brew install hashicorp/tap/terraform

インストールされたか確認する。

$ terraform -help
Usage: terraform [-version] [-help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

...

ヘルプっぽいものが表示されたからおそくら大丈夫でしょう。

Terraformで最低限のAWSインフラ作る

公式サイト的なのの手順に従ってAWSでインフラ作っていこう。

HashCorp Learn - Build Infrastructure

事前準備

以下の手順を済ませておく。

設定ファイルの作成と初期化

作業用のフォルダを作成し、その下に移動する。

$ mkdir terraform-example
$ cd terraform-example

設定ファイルを以下の内容で作成する。 今回はEC2インスタンスを一台立ち上げるだけ。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 2.70"
    }
  }
}

provider "aws" {
  profile = "default"
  region = 'ap-northeast-1"
}

resource "aws_instance"  "example" {
  ami = "ami-830c94e3"
  instance_type = "t2.micro"
}

以下のコマンドでそれぞれコードの整形と設定の検証してくれる。

$ terraform fmt
$ terraform validate
Success! The configuration is valid.

初期化処理を実行する。

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 2.70"...
- Installing hashicorp/aws v2.70.0...
- Installed hashicorp/aws v2.70.0 (signed by HashiCorp)

terraform init を実行すると .terraform というフォルダが作成される。 terraform init は設定ファイルを作成した際や、gitなど既存の設定ファイルをcheckoutした際に実行すればよいらしい。

インフラの作成

以下のコマンドを実行するとAWS上にインフラが構築される。

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # ここに作成されるリソースが一覧される
  + resource "aws_instance" "example" {
      + ami = "ami-830c94e3"
      + arn = (known after apply)
      ...略
    }

...略

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.  

ここでAWSのコンソールを見てみるとEC2インスタンスが作成されている、すごい。

Terraformその他コマンド

インフラの更新

更新は設定ファイルを書き換えた後、terraform apply を再度実行するだけ。 このときに差分が見れるので、差分を見ながら問題がなければ yes と入力して実行する。

インフラの詳細確認

以下のコマンドで作成したリソースの情報を表示できる。

$ terraform show

インフラの削除

以下のコマンドで作成したリソースの削除ができる。

$ terraform destroy

おわりに

Terraformの基本的な使い方だけ書いた。 設定ファルで変数を使用したり、モジュール化したりなど色々なことができるらしいので、次回はそれを触ってみたい。

VSCodeでAwesome Emacs Keymap使ってるときに検索バー内でカーソル移動したい

概要

VSCodeのキーマップ拡張「Awesome Emacs Keymap」を使っている際、ctrl+sまたは⌘Fで出した検索バー内でカーソルの移動ができないことに微妙に不便を感じていたので自分でVSCodeのkeybindings.jsonを触ってカーソル移動できるようにした。

ちなみに検索時にカーソル移動できないのはEmacsのデフォの挙動なので、キーマップ拡張が悪いとかいう話ではない。 キーマップ拡張自体はとても優れていると思う、心から感謝してる。

方法

まず「VSCodeでキーバインドを設定する。keybindings.jsonが無い時の対処法」通りに keybindings.json を開く。

次に以下のコードをコピーしてペタッと貼る。

[
    {
      "key":  "enter",
      "command": "editor.action.nextMatchFindAction",
      "when": "editorFocus && findWidgetVisible && !replaceInputFocussed"
    },
    {
      "key": "ctrl+a",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    },
    {
      "key": "ctrl+b",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    },
    {
      "key": "ctrl+e",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    },
    {
      "key": "ctrl+f",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    },
    {
      "key": "ctrl+n",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    },
    {
      "key": "ctrl+p",
      "command": "",
      "when": "editorFocus && findWidgetVisible && findInputFocussed",
    }
]

今回は自分がカーソル移動時によく使う ctrl+a, ctrl+b, ctrl+e, ctrl+f, ctrl+n, ctrl+p だけを設定した。 上記以外の高度なカーソル移動(ワード毎に移動とか)をご所望の際は同じように書けば動作するはず。

終わりに

あ〜〜〜〜〜〜ちょっとだけ楽になった。

今回の件でキーマップ拡張のコードとか読んだりしたけど、OSS作ってくれる人ってホント凄いね、感謝。

参考リンク

/bin/launchctl で色々と自動で起動する設定する

はじめに

よく分からんコマンド調べてみようシリーズ。

kkznch.hatenablog.com

今回は /bin/launchctl について。

/bin/launchctl

名前から推測するに CentOS でいう systemctl みたいな、 OS 起動時に自動でサービスの起動を設定する奴かね。 ということで man launchctl したときの DESCRIPTION の内容はこちら。

launchctl interfaces with launchd to manage and inspect daemons, agents and XPC services.

launchctl はデーモンやエージェント、XPC サービスの管理や検査をする launchd のインターフェース。よく分からない。

念の為 launchd についても man launchd してみた。

launchd manages processes, both for the system as a whole and for individual users.

launchd はシステム全体と個別のユーザのプロセスを管理するらしい。 なるほど、launchctl は launchd をどうこうするためのコマンドということでしょうか、そういうことにしておきましょう。

/bin/launchctl 実行してみる

説明だけだとよく分からんので動かそう。

plist ファイルを書く

何を実行するのか、どの間隔で実行するのか、などといった様々なオプションを plist 形式のファイルに書く。 今回は 10 秒間隔で echo するだけの test.plist というファイルを作成してみた。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
 <dict>
  <key>Label</key>
  <string>test</string>
  <key>ProgramArguments</key>
  <array>
     <string>echo</string>
     <string>Hello,World!</string>
  </array>
  <key>StandardOutPath</key>
  <string>/path/to/output.log</string>
  <key>StartInterval</key>
  <integer>10</integer>
 </dict>
</plist>

ロードと起動

作成後は以下のコマンドで、フルパスで test.plist を指定してロードする。

$ launchctl load /path/to/test.plist

この時点ではまだ起動はしていない。 ロードした時点で起動するオプションもあるが、今回はないので手動で起動する。 起動時には test.plist の Label キーで指定した値(今回は test )を引数に渡す。

$ launchctl start test

これで完了。 このあと少し時間をおくと以下のように /path/to/output.logHello, World! が出力されているはず。

$ cat /path/to/output.log
Hello,World!
Hello,World!
Hello,World!

停止とアンロード

止める際は以下のコマンドで止めて、 unload してあげる。

$ launchctl stop test
$ launchctl unload /path/to/test.plist

以上。

おわりに

これは今後自分で plist を書いて何かを動かすということはあるのだろうか。 Linux とかだとなんとなく使い道は分かるが、mac だと何をするねん。

plist の書き方だったり細かいオプションは参考リンク先を見てね。

参考リンク

qiita.com www.minimalab.com

/bin/pax でファイルのアーカイブする

はじめに

久しぶりのよく分からんコマンド調べてみようシリーズ。

kkznch.hatenablog.com

今回は /bin/pax について。

/bin/pax

名前から推測するに、なんとなくパッキングしてくれそうな雰囲気を感じる。 ただ全く使ったことないし使ってる人見たことない、一体こいつは何者だ。

ということで man pax したときの DESCRIPTION の内容はこちら。

pax will read, write, and list the members of an archive file and will copy directory hierarchies.

pax は圧縮ファイルの読み書きや一覧、ディレクトリ構造のコピーをするらしい。

tar とか zip みたいに圧縮解凍ができるコマンドという認識でいいのかねこれは?と思って調べてみると微妙に違うっぽい。 tar とか zip は圧縮ファイルに対する操作で、 pax はアーカイブファイルに対する操作ができるのかも。 圧縮ファイルとアーカイブファイルについての違いは以下を参照してくれ。

linuxfan.info

/bin/pax 実行してみる

以下のサイトで色々試されている。

qiita.com

基本的な構文は以下の通り。

# ファイルをアーカイブする
$ pax -w 入力元

# アーカイブされたファイルを展開する
$ pax -r 入力元

なるほどそんなに難しくなさそう。 以下のファイルがある状態でアーカイブと展開をそれぞれやってみる。

$ ls -1
fuga.txt
hoge.txt
piyo.txt

ファイルをアーカイブする

まずはアーカイブから。

$ pax -w *
fuga.txt0000644 0000765 0000024 00000000017 13644250623 0013557 0ustar00kkznchstaff0000000 0000000 fuga
fuga
fuga
hoge.txt0000644 0000765 0000024 00000000017 13644250612 0013555 0ustar00kkznchstaff0000000 0000000 hoge
hoge
hoge
piyo.txt0000644 0000765 0000024 00000000017 13644250631 0013614 0ustar00kkznchstaff0000000 0000000 piyo
piyo
piyo

なんか出力された。 ファイルの内容とかメタ情報っぽいのが出力されているっぽい。

ちなみに標準出力に出力されているだけなので、上記のコマンドだとアーカイブファイルは作成されない。 アーカイブファイルを作成したい場合はリダイレクトさせる。

$ pax -w * > archive
$  ls -1
archive
fuga.txt
hoge.txt
piyo.txt

標準出力には何も出力されず、archive というファイルが新たに作成される。

アーカイブされたファイルを展開する

では次にアーカイブしたファイルを展開してみよう。 展開時にフォルダを指定して展開することは可能らしいが、ちょっと面倒なので別のフォルダを作成して archive を移動し、そこで展開する。

$ mkdir test
$ mv archive test

この状態で展開用のコマンドを実行する。

$ pax -r < archive

ここで ls を実行すると、アーカイブされていたファイルが展開でできていることが確認できる。

$ ls -1
archive
fuga.txt
hoge.txt
piyo.txt

展開できているっぽい。

ちなみに pax で作ったアーカイブファイルのファイルサイズは 10KB で、zip で圧縮した場合のファイルサイズは 481B だった。 こんなに違うのか、アーカイブファイルの使いみちが最早よく分からん。