Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Homebrewの自作コマンドを正しく作る with ShellScript

More than 3 years have passed since last update.

Homebrewの自作コマンドの作成は様々な言語で実装された記事がありました。ここではShellScriptでHomebrewのコマンドを作成します。

今回は普段管理するライブラリの数が増えて大変になってきていたために必要に感じてgit-pullsというコマンドを作成しました。これは指定したディレクトリ以下のレポジトリを一括でgit pullしてくれるHomebrewのコマンドを作成しました。
https://github.com/hayashier/git-pulls

作成コマンドの利用方法

以下の2つのコマンドを入力するだけで利用できるようになります。

$ brew tap hayashier/git-pulls
$ brew install git-pulls

利用方法は以下のように一括でgit pullするパスを指定します。除外するパスも-eオプションでカンマ区切りで複数指定できます。

$ git-pulls -h
Usage: git-pulls [-h] [-e /exclusivePath1/to,/exclusivePath2/to,/exclusivePath3/to ] /path/to

例えば、git-pulls ./のようにコマンドを打つと以下のように一括でgit pullしてくれます。

$ git-pulls ./
Start pulling all git project in /Users/hayashier/repository/.
Exclude path: []
/Users/hayashier/repository/me/sample-repository1
Already up-to-date.
/Users/hayashier/repository/me/sample-repository2
Already up-to-date.
/Users/hayashier/repository/me/sample-repository3
Already up-to-date.

-eオプションで除外するパスも指定できます。またカンマ区切りで除外するパスを複数指定もできます。

$ git-pulls -e me ./
Start pulling all git project in /Users/hayashier/repository/
Exclude path: me
/Users/hayashier/repository/me/sample-repository1
Passing...
/Users/hayashier/repository/me/sample-repository2
Passing...
/Users/hayashier/repository/me/sample-repository3
Passing...
/Users/hayashier/repository/team1/sample-repository1
Already up-to-date.
/Users/hayashier/repository/team2/sample-repository2
Already up-to-date.

Homebrewコマンドの作成

コマンドのプロジェクト作成

1.ディレクトリを作成します。

$ mkdir -p git-pulls/bin
$ cd git-pulls

必要なファイルを編集します。

$ vim bin/git-pulls
#!/bin/bash

GIT_PULLS_VESION="0.0.1"

function contains() {
  target=$1
  shift
  paths=$(echo $@ | tr -s ' ' ' ')
  if [ "${paths[1]}" == " " ]; then
    flag=$(echo $target | grep ${paths[0]})
    if [[ -n $flag ]]; then
      return 0
    fi
  else
    for ((i=0;i < ${#paths[@]};i++)) {
      if [ ${paths[$i]} == [] ]; then
        continue
      fi
      flag=$(echo $target | grep ${paths[$i]})
      if [[ -n $flag  ]]; then
        return  0
      fi
    }
  fi

  return 1
}

function formArrayPaths() {
  exclude_paths=$(echo $1 | tr -s ',' ' ')
  for ((i=0;i < ${#exclude_paths[@]};i++)) {
    path=${exclude_paths[$i]}
    flag=$(echo $path | grep $EXECUTING_PLACE)
    if [ -n $flag ] && [ $i -ne 0 ] && ([ ${path:0:1} == "/" ] || [ ${path:0:1} == "~" ]); then
      num=$(( ${#path} - 1))
      exclude_paths[$i]="$EXECUTING_PLACE${path:1:num}"
    fi
  }
  echo ${exclude_paths[@]}
}

if [ -z $1 ]; then
  echo 'Usage: git-pulls [-h] [-e /exclusivePath1/to,/exclusivePath2/to,/exclusivePath3/to ] /path/to'
  exit
fi

EXECUTING_PLACE=$PWD
trap "cd $EXECUTING_PLACE && exit" {1,2,3,15}

FLAG=true
origin=$HOME
exclude_paths=[]

if [ ${1:0:1} != "-" ]; then
  origin=$1
  shift 1
  FLAG=false
fi

while getopts ":e:hv" OPT ;
do
  case $OPT in
  e)
    result=$(formArrayPaths $OPTARG)
    exclude_paths=${result[@]}
    ;;
  h)
    echo 'Usage: git-pulls [-h] [-e /exclusivePath1/to,/exclusivePath2/to,/exclusivePath3/to ] /path/to'
    exit
    ;;
  v)
    echo "git-pulls version $GIT_PULLS_VESION"
    exit
    ;;
  esac
done

SHIFT_NUM=$((OPTIND - 2))
if [ $SHIFT_NUM -gt 0 ]; then
  shift $SHIFT_NUM
fi

if $FLAG; then
  shift 1
  origin=$1
fi

if [ ${origin:0:1} != "/" ] && [ ${origin:0:1} != "~" ]; then
  origin="$PWD/$origin"
fi

echo "Start pulling all git project in $origin."
if [ -n $exclusive_path ]; then
  echo "Exclude path: ${exclude_paths[@]}"
fi

find $origin -type d -name .git | xargs -n 1 dirname | sort | while read line; do echo $line ; contains $line ${exclude_paths[@]}; if [ $? -eq 0 ]; then echo "Passing..."; continue; fi  && cd $line && git pull && cd $origin; done
$ vim README.md
README.md
# git-pulls
`git-pulls` command pulls all git repositories under specified path.

# Install (OSX)

$ brew tap hayashier/git-pulls
$ brew install git-pulls

# Usage

$ git-pulls [-v] [-h] [-e /exclusivePath1/to,/exclusivePath2/to,/exclusivePath3/to ] /path/to

## Options

-v : Display version
-h : Display usage
-e : Specify path which exclude paths. If you specify multiple paths, enumerate paths separated by comma

予めGitHubにgit-pullsというレポジトリを作成しておき、これにpushします。

$ git init
$ git add ./
$ git commit -m "first commit"
$ git remote add origin https://github.com/hayashier/git-pulls.git
$ git push -u origin master

tag付けをしてpushします。

$ git tag 0.0.1
$ git push origin 0.0.1

Formulaの作成

Formulaを作成します。ファイル名は[アプリケーション名].rbです。ここではアプリケーション名はgit-pullsとなります。

1.ディレクトリを作成して移動します。

$ mkdir homebrew-git-pulls && cd $_

2.Formulaを作成して編集します。

$ brew create https://github.com/hayashier/git-pulls.git
$ cp /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/git-pulls.rb git-pulls.rb
$ vim git-pulls.rb

Formulaは以下の通りとなります。

git-pulls.rb
REPOSITORY_URL="https://github.com/hayashier/git-pulls".freeze
HOMEBREW_GITPULLS_VERSION="0.0.1".freeze

class GitPulls < Formula
  desc "Pulls all git repository under specified paths."
  homepage REPOSITORY_URL
  url "#{REPOSITORY_URL}/archive/#{HOMEBREW_GITPULLS_VERSION}.tar.gz"
  sha256 "ed3b6451a05567505bd718db8fdf343f47e97d70fc7d4d92e7f5cb3c9532b753"
  head "#{REPOSITORY_URL}.git", :tag => HOMEBREW_GITPULLS_VERSION

  def install
    bin.install "bin/git-pulls"
  end

  test do
    system "false"
  end
end

なお、sha256の値はtag付したバージョンのtar.gzの形式のファイルを以下のようなURLからダウンロードしてきます。
https://github.com/<ユーザ名>/git-pulls/releases

そして、opensslコマンドを用いて以下のようにファイルのハッシュ値を調べます。ハッシュ値はxxxxxxに当たる部分となります。

$ openssl dgst -sha256 ~/Downloads/git-pulls-0.0.1.tar.gz
SHA256(homebrew-git-pulls-0.0.1.zip)= xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

予めGitHubにhomebrew-git-pullsというレポジトリを作成しておき、これにpushします。
レポジトリ名をhomebrew-から始まるものでないといけないので注意。

$ git init
$ git add ./
$ git commit -m "first commit"
$ git remote add origin https://github.com/hayashier/homebrew-git-pulls.git
$ git push -u origin master

利用してみる

作成したコマンドは他のユーザも以下のコマンドでインストールできます。

$ brew tap hayashier/git-pulls
$ brew install hayashier/git-pulls

注意点

  • 同じバージョンでタグを切り直したとき場合のインストール方法 同じバージョンでタグを切り直したときはアンインストールした上でキャッシュを消しておく。
$ brew uninstall git-pulls
$ rm /Users/hayashier/Library/Caches/Homebrew/git-pulls-0.0.1.zip

改めてインストールします。

$ brew install git-pulls
  • 古いバージョンをインストールしていて新しいバージョンをインストールする場合のインストール方法
$ brew uninstall git-pulls
$ brew unlink git-pulls

改めてインストールします。

$ brew install git-pulls

Formulaの構文チェック

brew auditコマンドでFormulaの構文チェックを行うことができます。

$ brew audit --strict git-pulls
hayashier/git-pulls/git-pulls:
  * `version` (line 10) should be put before `checksum` (line 8)
  * Stable: version 0.0.1 is redundant with version scanned from URL
  * Stable: Use GitHub tarballs rather than zipballs (url is https://github.com/hayashier/homebrew-git-pulls/archive/0.0.2.zip).
  * Description shouldn't include the formula name
  * C: 1: col 16: Freeze mutable objects assigned to constants.
  * C: 1: col 16: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
  * C: 2: col 27: Freeze mutable objects assigned to constants.
  * C: 2: col 27: Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
  * C: 9: col 41: Prefer `to_s` over string interpolation.
  * C: 10: col 11: Prefer `to_s` over string interpolation.
Error: 10 problems in 1 formula

コマンド実行時のFormulaが以下の状態のときの修正方法について説明します。

git-pulls.rb
REPOSITORY_URL='https://github.com/hayashier/git-pulls'
HOMEBREW_GITPULLS_VERSION='0.0.1'

class GitPulls < Formula
  desc "git-pulls command pulls all git repository under specified paths."
  homepage "#{REPOSITORY_URL}/README.md"
  url "#{REPOSITORY_URL}/archive/#{HOMEBREW_GITPULLS_VERSION}.zip"
  sha256 "04777124c8e1ef8b3ba2d884f91ad47378437611b2b1349e730ef85913c2fa30"
  head "#{REPOSITORY_URL}.git", :tag => "#{HOMEBREW_GITPULLS_VERSION}"
  version "#{HOMEBREW_GITPULLS_VERSION}"

  def install
    bin.install "bin/git-pulls"
  end

  test do
    system "false"
  end
end

1.

Stable: version 0.0.1 is redundant with version scanned from URL

URLにバージョンが含まれているのでversionは冗長だからいらない。

2.

`version` (line 10) should be put before `checksum` (line 8)

バージョンは消すからこれは無視。

3.

Stable: Use GitHub tarballs rather than zipballs (url is https://github.com/hayashier/homebrew-git-pulls/archive/0.0.1.zip).

.zipじゃなくて.tar.gzで圧縮したものを指定する。

4.

Freeze mutable objects assigned to constants.

文字列に.freezeをつけて可変でないようにする

5.

Prefer double-quoted strings unless you need single quotes

定数はシングルクオテーションじゃなくてダブルクオテーション

6.

Prefer `to_s` over string interpolation.

"#{CONSTANT}"のようにしているところをCONSTANTとする。

以上となります。

--new-formulaオプションでさらに厳格に

$ brew audit --strict --new-formula git-pulls
hayashier/git-pulls/git-pulls:
  * The URL https://github.com/hayashier/homebrew-git-pulls/README.md is not reachable (HTTP status code 404)
  * GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars)
  * GitHub repository too new (<30 days old)
Error: 3 problems in 1 formula

1.

The URL https://github.com/hayashier/homebrew-git-pulls/README.md is not reachable (HTTP status code 404)

アクセス可能なURLを指定する。

2.

GitHub repository not notable enough (<20 forks, <20 watchers and <50 stars)

20フォーク以上、または20watcher以上、もしくは50スター以上

3.

GitHub repository too new (<30 days old)

レポジトリ作成から30日以上

参考

http://tbpgr.hatenablog.com/entry/2016/07/08/015327
http://girigiribauer.com/archives/20161004/
http://qiita.com/masawada/items/484bbf83ef39cad7af74
http://qiita.com/sakajunquality/items/48b5138986056eb4b49c

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away