意外に簡単！ MacPortsのportを更新してコントリビューションする方法

## はじめに

MacPortsには、さまざまなportがあり、コマンド一発で簡単にインストールできます。

ですが、「お目当てのportが見つかったけれど、バージョンが古い……」そんな経験はありませんか？

その場合、portを使わずに、しかたなく新しいバージョンをビルドしてインストールすることも多いと思います。

でも、ちょっと待ってください。

せっかくなら、portを更新して、MacPortsへのコントリビューションに挑戦してみませんか？

コントリビューションには、さまざまなメリットがあります。

* macOSのアップグレード時の、再インストール作業が軽減される
* ほかのMacPortsユーザーも、port更新の恩恵を受けられる
* コントリビューションの達成感がある

「でも、コントリビューションは難しいんでしょう」と感じるかもしれません。

そこで本記事では、筆者の経験をもとに、portを更新してコントリビューションするまでの手順を解説します。

簡単にバージョンアップできるportであれば、手順どおりに進めるだけでコントリビューションできます。

「これならできそう」と感じた方は、ぜひチャレンジしてみてください。

### 対象読者

本記事は、MacPortsを活用している方や、GitやGitHubの基本操作ができる方を対象としています。

そのため、MacPortsや、Git、GitHubの使い方の解説は割愛しています。

もしGitやGitHubの使い方について不明点があれば、インターネット上にわかりやすい解説がたくさんありますので、調べていただけるとうれしいです。

### 例として取り上げるport

本記事では、例としてreuseというportを取り上げます。

[reuse](https://github.com/fsfe/reuse-tool)は、さまざまなファイルのライセンスをまとめて管理できるPython製のコマンドラインツールです。

このツールを使用すると、オープンソースプロジェクトを公開する際に、ライセンスが付与されていないファイルを簡単に見つけられるので、便利です。

### 筆者のコントリビューション経験

筆者は、reuseのportに対して、2回コントリビューションをおこなったことがあります。

* [reuse: update to 3.0.2 #23467](https://github.com/macports/macports-ports/pull/23467)
* [reuse: update to 5.0.2 #27441](https://github.com/macports/macports-ports/pull/27441)

この経験が、reuseを例として使用する理由です。

## コントリビューションまでの手順

portを更新してコントリビューションするまでの手順は、以下のとおりです。

1. portの現状を確認する
2. ローカルリポジトリを準備する
3. portを更新する
4. Pull Requestを送信する

以下では、この手順を順に説明します。

## portの現状を確認する

最初に、portの現状を確認します。これが重要な理由は、次のとおりです。

<dl>
  <dt>作業の無駄を防ぐため</dt>
  <dd>すでにportが更新されている場合に、同じ作業を繰り返さないようにするためです</dd>
  <dt>コントリビューションの可能性を見極めるため</dt>
  <dd>portのメンテナンス担当者（メンテナー）が、外部からのコントリビューションを受け入れる意向があるか知る必要があるためです</dd>
</dl>

現状を効率よく確認するには、以下の順におこなうと良いでしょう。

1. portの最新バージョンを確認する
2. portのメンテナーを確認する
3. 進行中のPull Requestがないか確認する

### portの最新バージョンを確認する

portの最新バージョンを確認するには、「[Ports | MacPorts](https://ports.macports.org/)」にアクセスし、目的のportを検索します。検索結果から、portの最新バージョンがわかります。たとえば、reuseの検索結果は、https://ports.macports.org/port/reuse/ です。5.0.2が、portのバージョンだとわかります。

![MacPortsのreuseのページ。バージョンにv5.0.2と書かれている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/f147039d-1a8e-4020-b620-a61088946f45.png "MacPortsのreuseのページ")

もしportがすでに最新バージョンに更新されていた場合、コントリビューションの必要はありません。この場合は、以下のコマンドを実行してportを最新版に更新しましょう。

```zsh
% sudo port selfupdate
% sudo port upgrade outdated
```
更新されたportがインストールされます。これで作業は完了です。お疲れ様でした。

portが最新バージョンでない場合は、次にportのメンテナーを確認します。この時点で、検索結果のportのページは、そのまま開いておいてください。

### portのメンテナーを確認する

portのメンテナー情報は、Portfileに記載されています。

Portfileを確認するために、ports treeの公式リポジトリにアクセスしましょう。

先ほど開いたままにしたportのページに、「Details」のボタンがあります。

![MacPortsのreuseのページ。Detailsのボタンに注目。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/3a29ad1f-41e3-45d1-a30c-0c9896e7f4bb.png "MacPortsのreuseのページにあるDetailsボタン")

このボタンをクリックしたあと、GitHubアイコンをクリックします。

![MacPortsのreuseの詳細ページ。GitHubのアイコンに注目。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/cf33650c-e16c-44ed-ab63-88309c4fee04.png "MacPortsのreuseのページにあるGitHubアイコン")

すると、ports treeの公式リポジトリにあるPortfileを確認できます。reuseの場合は、 https://github.com/macports/macports-ports/blob/master/devel/reuse/Portfile です。2025/03/16時点のPortfileの一部を以下に転載します。

```tcl:Portfile
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4

PortSystem          1.0
PortGroup           python 1.0

name                reuse
version             5.0.2
revision            0

checksums           rmd160  e30da944759932c95b7b5847f09506792d162349 \
                    sha256  878016ae5dd29c10bad4606d6676c12a268c12aa9fcfea66403598e16eed085c \
                    size    358798

categories          devel
supported_archs     noarch
platforms           {darwin any}
maintainers         nomaintainer
license             GPL-3+
...
```

Portfile内の「maintainers」の行を確認してください。この行に、メンテナーが書かれています。reuseのメンテナーは「nomaintainer」です。

メンテナー情報におうじて、外部からのコントリビューションの対応が変わります。

<dl>
  <dt>nomaintainer</dt>
  <dd>外部からのコントリビューションを積極的に受け付けています</dd>
  <dt>個人名に加えて「openmaintainer」と書かれている場合</dt>
  <dd>外部からのコントリビューションは受け付けていますが、大規模な変更をおこなう場合は、事前にメンテナーの許可が必要です</dd>
  <dt>それ以外の場合</dt>
  <dd>通常、外部からのコントリビューションは受け付けていません</dd>
</dl>

詳細は、「[MacPorts Guide](https://guide.macports.org/)」の「[7.4.1. Non-Maintainer Port Updates](https://guide.macports.org/#project.update-policies.nonmaintainer)」をご参照ください。

初めのうちは、「nomaintainer」のportを選んだほうがよいです。バージョン番号を上げるていどで済むのであれば、「openmaintainer」を選んでもよいと思います。

### 進行中のPull Requestがないか確認する

最後に、進行中のPull Requestがないか確認します。

ports treeのGitHubのページから「[Pull Request](https://github.com/macports/macports-ports/pulls)」を選び、「Filters」欄にport名を入力して検索します。たとえば、reuseの場合は「reuse」です。

検索の結果、Open状態のPull Requestが表示された場合は、コントリビューションの必要はありません。このPull Requestがマージされるのを待ちましょう。お疲れ様でした。

Open状態のPull Requestがない場合は、コントリビューションを進めましょう。

## ローカルリポジトリを準備する

通常、portは公式のports treeからインストールされます。

しかし、MacPortsには、手元のMac上でportを管理できる仕組みも用意されています。

手元のMac上でportを管理するには、ローカルリポジトリを作成します。

このローカルリポジトリに、コントリビューション対象のPortfileを配置して、作業を進めます。

ローカルリポジトリの準備は、次の手順でおこないます。

1. ローカルリポジトリを作る
2. Portfileを配置する
3. portindexコマンドを実行する

### ローカルリポジトリを作る

ローカルリポジトリを作るには、まずローカルリポジトリ用のディレクトリを作成します。

本記事では、ホームディレクトリ（/Users/xxx）直下にportsディレクトリ（/Users/xxx/ports）を作成します。

次に、ports treeの取得元を設定するsources.confファイルを編集し、ローカルリポジトリを追加します。

sources.confのパスは、通常は/opt/local/etc/macports/sources.confです。もしMacPortsをカスタムインストールしている場合は、インストール先のetc/macports/sources.confを確認してください。

sources.confの末尾には、以下の行があります。このURLは、公式のports treeのリポジトリを指しています。

```:sources.conf
rsync://rsync.macports.org/macports/release/tarballs/ports.tar.gz [default]
```

この行の*前に*、ローカルリポジトリのURLを指定します。たとえば、ローカルリポジトリが/Users/xxx/portsの場合は、このパスの先頭に「file://」を付けます。つまり、次のようになります。

```:sources.conf
file:///Users/xxx/ports
rsync://rsync.macports.org/macports/release/tarballs/ports.tar.gz [default]
```

### Portfileを配置する

ローカルリポジトリを作成したら、公式のports treeと同じディレクトリ構造を再現し、そこにPortfileをGitHubからダウンロードしましょう。

たとえば、reuseの場合は、[公式のports treeのdevel/reuse](https://github.com/macports/macports-ports/tree/master/devel/reuse)配下にあるPortfileをダウンロードし、ローカルリポジトリ上のdevel/reuse配下に配置します。

### portindexコマンドを実行する

Portfileを配置したら、ローカルリポジトリのトップディレクトリでportindexコマンドを実行します。

以下は、reuseのPortfileを追加した際のコマンド実行例です。

```
% cd ~/port
% portindex
Creating port index in /Users/xxx/ports
Adding port devel/reuse

Total number of ports parsed:	1
Ports successfully parsed:	1
Ports failed:			0
Up-to-date ports skipped:	0
```

上記のように、「Adding port」とportが追加された内容や、「Ports successfully parsed」とPortfileが正常に解析されたことを示すメッセージが出力されれば、準備は完了です。

## portを更新する

ローカルリポジトリが準備できましたので、portを更新しましょう。

あとで必要になりますので、新しいバージョンのアーカイブをダウンロードしておきます。ソースコードとバイナリの両方のアーカイブがある場合は、ソースコードのほうをダウンロードします。アーカイブの展開は不要です。

### Portfileのいちばん簡単な更新方法

本記事では、いちばん簡単な場合を説明します。

それは、旧バージョンと同じ方法で、新バージョンのダウンロードとビルドが可能な場合です。つまり、新バージョンでは、以下の変更がない状況です。

* ダウンロード元の変更
* port間の依存関係の増減
* ビルドツールの変更

この場合、Portfileの「version」と「checksums」の2項目を変更するだけです。

<dl>
  <dt>version</dt>
  <dd>新しいバージョン番号に変更します</dd>
  <dt>checksums</dt>
  <dd>以下の3つの項目を変更します。ここで、先ほどダウンロードしたアーカイブを使用します。以下に示したコマンドの実行結果に、内容を置き換えてください。
    <dl>
      <dt>rmd160</dt>
      <dd>openssl dgst -rmd160 &lt;新しいバージョンのアーカイブ&gt;</dd>
      <dt>sha256</dt>
      <dd>openssl dgst -sha256 &lt;新しいバージョンのアーカイブ&gt;</dd>
      <dt>size</dt>
      <dd>ls -l &lt;新しいバージョンのアーカイブ&gt;</dd>
    </dl>
  </dd>
</dl>

以上で完了です。

### 追加の作業が必要な場合

もちろん、新しいバージョンをダウンロードするだけでは更新できないportもあります。

追加作業はportごとに異なるため、本記事では具体的な手順を説明しません。依存関係の変化だけでも、対応方法がプログラミング言語ごとに異なるため、すべてを一記事で網羅することが難しいためです。

もし追加作業が必要な場合は、公式ドキュメントの以下の章を参照してください。

* [Chapter 4. Portfile Development](https://guide.macports.org/chunked/development.html)
* [Chapter 5. Portfile Reference](https://guide.macports.org/chunked/reference.html)

なお、次に示すreuseの例では、依存関係の追加が必要でした。この例は、Pythonパッケージのportを更新する際に、参考になると思います。

### reuseの例

reuseの場合は、まず[Python Package Indexのreuseのページ](https://pypi.org/project/reuse/)から、ソースコードのアーカイブ（Source Distribution）をダウンロードします。この例では、reuse-5.0.2.tar.gzをダウンロードしました。


![Python Package Indexのreuseのページから、reuse-5.0.2.tar.gzがダウンロードできる](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/95729593-e008-486a-9bed-5c52b211661f.png "Python Package Indexのreuseにあるダウンロードページ")

この場合、「versions」は5.0.2となりました。

「checksums」は、次のように算出します。

rmd160：
```
% openssl dgst -rmd160 reuse-5.0.2.tar.gz
RIPEMD-160(reuse-5.0.2.tar.gz)= e30da944759932c95b7b5847f09506792d162349
```

sha256：
```
% openssl dgst -sha256 reuse-5.0.2.tar.gz
SHA2-256(reuse-5.0.2.tar.gz)= 878016ae5dd29c10bad4606d6676c12a268c12aa9fcfea66403598e16eed085c
```

size：
```
% ls -l reuse-5.0.2.tar.gz
-rw-r--r--@ 1 xxx  staff  358798  2 19 11:33 reuse-5.0.2.tar.gz
```

これらをもとに、「checksums」を以下のように書き換えました。

<dl>
  <dt>rmd160</dt>
  <dd>e30da944759932c95b7b5847f09506792d162349</dd>
  <dt>sha256</dt>
  <dd>878016ae5dd29c10bad4606d6676c12a268c12aa9fcfea66403598e16eed085c</dd>
  <dt>size</dt>
  <dd>358798</dd>
</dl>

また、reuseのportの更新時には、依存portの追加が必要でした。

以下は、Pythonパッケージ特有の内容ですので、情報が不要な方は読み飛ばしてください。

依存関係を確認するため、Portfileのdepends_lib-appendの内容と、reuseの依存パッケージ情報とを比較します。

Portfileのdepends_lib-appendには、以下のように書かれていました。

```tcl:Portfile
depends_lib-append  port:py${python.version}-binaryornot \
                    port:py${python.version}-boolean.py \
                    port:py${python.version}-jinja2 \
                    port:py${python.version}-license-expression \
                    port:py${python.version}-python-debian
```

いっぽう、[reuse 5.0.2のpyproject.toml](https://github.com/fsfe/reuse-tool/blob/v5.0.2/pyproject.toml#L54)には、次のように書かれていました。

```toml:pyproject.toml
[tool.poetry.dependencies]
python = "^3.9"
Jinja2 = ">=3.0.0"
binaryornot = ">=0.4.4"
"boolean.py" = ">=3.8"
license-expression = ">=1.0"
python-debian = ">=0.1.34,!=0.1.45,!=0.1.46,!=0.1.47"
# TODO: Consider removing this dependency in favour of tomllib when dropping
# Python 3.10.
tomlkit = ">=0.8"
attrs = ">=21.3"
click = ">=8.0"
```

ここから、Portfileのdepends_lib-appendに、以下のportを追加すればよいことがわかります。

* [py-tomlkit](https://ports.macports.org/port/py-tomlkit/)
* [py-attrs](https://ports.macports.org/port/py-attrs/)
* [py-click](https://ports.macports.org/port/py-click/)

最終的に、depends_lib-appendは以下のようになりました。

```tcl:Portfile
depends_lib-append  port:py${python.version}-binaryornot \
                    port:py${python.version}-boolean.py \
                    port:py${python.version}-jinja2 \
                    port:py${python.version}-license-expression \
                    port:py${python.version}-python-debian \
                    port:py${python.version}-tomlkit \
                    port:py${python.version}-attrs \
                    port:py${python.version}-click
```

### 更新したportの反映とインストール

Portfileの変更を終えたら、以下のコマンドを実行して、更新内容をローカルリポジトリに反映させましょう。

```
% cd ~/port
% portindex
```

以下のように出力されれば、Portfileの変更が正しく反映されています。

```
Creating port index in /Users/xxx/ports
Adding port devel/reuse

Total number of ports parsed:	1
Ports successfully parsed:	1
Ports failed:			0
Up-to-date ports skipped:	0
```

つづいて、以下のコマンドを実行して、更新したportをインストールします。

```
% sudo port upgrade <port名>
```

### 更新がうまくいかないときは

portの更新を正常におこなえない場合、以下の点を確認してください。

* Portfileに記述ミスがないか
* ローカルリポジトリが公式リポジトリより優先されているか

#### Portfileに記述ミスがないか

Portfile更新後のportindexコマンドの実行時に、「Ports successfully parsed」がカウントされているか確認しましょう。

```
Total number of ports parsed:	1
Ports successfully parsed:	1
Ports failed:			0
Up-to-date ports skipped:	0
```

もし「Ports failed」や「Up-to-date ports skipped」がカウントされている場合は、Portfileの記述ミスや保存し忘れが原因かもしれません。

#### ローカルリポジトリが公式リポジトリより優先されているか

ローカルリポジトリのパスがsources.confに書かれているか確認しましょう。

macOSのアップグレード後、MacPortsを再インストールした際に、sources.confが初期状態に戻る可能性があります。

sources.conf内で、ローカルリポジトリのURLが、公式リポジトリのURLより前に書かれていることを確認してください。ローカルリポジトリのパスが/Users/xxx/portsの場合、以下のようになるはずです。

```:sources.conf
file:///Users/xxx/ports
rsync://rsync.macports.org/macports/release/tarballs/ports.tar.gz [default]
```

## Pull Requestを作成する

Portfileが完成し、動作確認ができたら、Pull Requestを作成しましょう。

まず、MacPortsのports treeの公式リポジトリをcloneし、新しいブランチを作成します。そのブランチでPortfileを置き換えた後、commitとpushをおこないます。

次に、リポジトリのPull Request作成ページに移動します。このページには、説明欄にあらかじめ定型文が入力されています。

![MacPortsのports treeのPull Requestのページ。説明欄にあらかじめ定型文が入っている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/bd2acf5e-e866-4321-9231-0014f452777c.png "MacPortsのports treeのPull Request")

説明欄には「&lt;!--」と「--&gt;」に囲まれたコメントが含まれています。それにしたがって情報を入力してください。また、説明欄にあるチェックボックスの項目も忘れずに確認してチェックを入れましょう。

![説明欄のチェックボックス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30639/0e291a5e-ab88-45f1-8158-d90a676468e2.png "説明欄のチェックボックス")

説明文の書き方に迷った場合は、[Mergedされた他のPull Request](https://github.com/macports/macports-ports/pulls?q=is%3Apr+is%3Amerged)を参考にすると良いでしょう。

Pull Requestを作成したら、レビューを受けてマージされるのを待つだけです。お疲れ様でした！

## おわりに

ここまで、MacPortsのportの更新してコントリビューションする方法について説明しました。

バージョンアップが簡単なportの場合は、Portfileの「version」と「checksums」を更新するだけで済みます。本記事の手順にしたがうだけで、はじめてでもコントリビューションできます。

もし、お気に入りのportの更新が滞っているようなら、コントリビューションをぜひ試してみてください。

## 参考文献

本記事は、MacPortsの公式ドキュメントである「[MacPorts Guide](https://guide.macports.org/)」を参考にしました。

詳しい内容を知りたい場合は、ぜひ公式ドキュメントをご覧ください。本記事で取り上げた内容に関連する章は、以下のとおりです。

* ローカルリポジトリ
  * [4.7. Local Portfile Repositories](https://guide.macports.org/chunked/development.local-repositories.html)
* portのメンテナーの種類
  * [7.4. Port Update Policies](https://guide.macports.org/chunked/project.update-policies.html)
* Portfileの書き方
  * [Chapter 4. Portfile Development](https://guide.macports.org/chunked/development.html)
  * [Chapter 5. Portfile Reference](https://guide.macports.org/chunked/reference.html)