PyPIを支えるPython Package Repository (Warehouse)を動かしてみた

# 概要
- PyPIは2018年頃から次世代のリポジトリ実装(`Warehouse`)に移行しており、このソースコードがGitHub(`https://github.com/pypa/warehouse`)で公開されている。
    - `docker-compose`用の定義ファイルが提供されており、開発環境を比較的簡単に起動することが可能。
- `twine`などのクライアントから`warehouse`のインスタンスに対してパッケージの登録も可能なため、簡易的なパッケージ操作のテスト環境としても利用できそう。
    - PyPIはテスト用インスタンス(`https://test.pypi.org/`)を提供してはいるものの、外部に公開されてしまうサーバではある。
    - `warehouse`の場合、Privateな環境で利用可能＆アカウントの登録が不要のため、サンドボックス的に利用しやすい側面もあり(PyPIでの見え方を確認したいモチベーションがある場合に限定されるかもしれないが)。

#  評価メモ
`CentOS 7.7`で動かしてみた際の手順メモ。

## 前提
docker / docker-composeをインストールする。
GitHubリポジトリの[requirements/main.in] (https://github.com/pypa/warehouse/blob/2acb5d2a4c228123ceb3179280c839e96de03d6e/requirements/main.in)を見ると、(`elasticsearch`や`postgresql`などを含む）相応に複雑なスタックだが、基本的にコンテナ内で解決される。

- docker
    - https://docs.docker.com/install/linux/docker-ce/centos/
- docker-compose
    - https://docs.docker.com/compose/install/

### インストール
インストール手順は、[Warehouse - Docs » Development » Getting started]
(https://warehouse.readthedocs.io/development/getting-started/)に説明がある。

githubからソースコードをcloneした後、`make build`コマンドを実行するとdocker image群が生成される。

```shell
$ git clone https://github.com/pypa/warehouse.git
$ cd warehouse
$ make build
$ docker images
REPOSITORY          TAG                  IMAGE ID            CREATED             SIZE
warehouse_web       latest               a78a164cbb8f        2 minutes ago       376MB
warehouse_worker    latest               a78a164cbb8f        2 minutes ago       376MB
<none>              <none>               5768f70bcf35        2 minutes ago       676MB
<none>              <none>               c34b08b4ed16        5 minutes ago       1.16GB
warehouse_static    latest               15277f26921d        6 minutes ago       1.14GB
python              3.7.3-slim-stretch   338ae06dfca5        6 months ago        143MB
node                8.15.1               8c51cec97ebf        9 months ago        895MB
```

以下のコマンドで、生成したイメージからコンテナ群を起動する。

```
$ make serve
```

`static`コンテナが起動しきった後で、(例えば、別ターミナルで)以下のコマンドを実行する。
(実行しない場合、DBが存在しないため、Web GUIにアクセスした際にErrorが発生する）

```
$ make initdb
```

ブラウザで80番ポートにアクセスすると、`pypi`とほぼ同一の画面が表示される。主な差異としては以下。

- リポジトリに含まれるパッケージにテストデータが含まれる(`test.pypi.org`のスナップショットから、Privateな情報を除去したもの)。
- [pyramid_debugtoolbar](https://github.com/Pylons/pyramid_debugtoolbar)が設定されており、デバッグ情報にアクセスできる。
    - 性能情報などに加えて、REST APIのRoute一覧なども参照可能。


`curl`でREST-API (package情報取得のEndpoint)を実行したサンプルは以下。

```
$ yum install jq
$ curl -s http://127.0.0.1/pypi/logmmse/1.2/json | jq .info.name
"logmmse"

$ curl -s http://127.0.0.1/pypi/logmmse/json | jq '.releases|keys'
[
  "1.1",
  "1.2"
]
```

## パッケージのアップロード

`twine`などのクライアントから、アップロード先を切り替えるだけで登録可能。
以下は、`cookiecuter`で生成したサンプルパッケージをアップロードする例。

前提ライブラリをインストール。

```
$ yum install python36 -y
$ pip3 install twine wheel
$ pip3 install cookiecutter
```

テンプレート(`audreyr/cookiecutter-pypackage`)を使ってサンプルパッケージを生成。競合を避けるため`project_slug`だけ変更したが、その他はデフォルト。

```
$ cookiecutter https://github.com/audreyr/cookiecutter-pypackage
full_name [Audrey Roy Greenfeld]:
email [audreyr@example.com]:
github_username [audreyr]:
project_name [Python Boilerplate]:
project_slug [python_boilerplate]: python_boilerplate_1234
project_short_description [Python Boilerplate contains all the boilerplate you need to create a Python package.]:
pypi_username [audreyr]:
version [0.1.0]:
use_pytest [n]:
use_pypi_deployment_with_travis [y]:
add_pyup_badge [n]:
Select command_line_interface:
1 - Click
2 - Argparse
3 - No command-line interface
Choose from 1, 2, 3 [1]:
create_author_file [y]:
Select open_source_license:
1 - MIT license
2 - BSD license
3 - ISC license
4 - Apache Software License 2.0
5 - GNU General Public License v3
6 - Not open source
Choose from 1, 2, 3, 4, 5, 6 [1]:
```

パッケージのdistributionを生成(source + binary)。`dist`フォルダにファイルが生成されていることを確認。

```
$ cd python_boilerplate_1234
$ python3 setup.py sdist
$ python3 setup.py bdist_wheel
$ ls dist
python_boilerplate_1234-0.1.0-py2.py3-none-any.whl  python_boilerplate_1234-0.1.0.tar.gz
```

`twine upload`でパッケージをアップロード。

- `--repository-url`に`warehouse`のホストを指定(この例では`127.0.0.1`)。
- アップロードに必要な認証情報には、`warehouse`のテスト用アカウント(`ewdurbin/password`)を利用。
    - https://warehouse.readthedocs.io/development/getting-started/#logging-in-to-warehouse

```
$ twine upload --repository-url http://127.0.0.1/legacy/ dist/*
Uploading distributions to http://127.0.0.1/legacy/
Enter your username: ewdurbin
Enter your password:
Uploading python_boilerplate_1234-0.1.0-py2.py3-none-any.whl
100%|███████████████████████████████████████████████████████████████████████████████████████████████████| 9.28k/9.28k [00:05<00:00, 1.73kB/s]
Uploading python_boilerplate_1234-0.1.0.tar.gz
100%|███████████████████████████████████████████████████████████████████████████████████████████████████| 13.2k/13.2k [00:00<00:00, 25.6kB/s]
```

アップロードが正常に終了すると、GUIからパッケージが確認できる。また、REST-APIでもパッケージ情報を参照可能。

```
$ curl -s http://127.0.0.1/pypi/python-boilerplate-1234/json | jq '.releases|keys'
[
  "0.1.0"
]
```

# 参考
- [GitHub - pypa/warehouse](https://github.com/pypa/warehouse)
- [Docs » Welcome to Warehouse’s documentation!](https://warehouse.readthedocs.io/)
- [PythonWiki - WarehouseRoadmap](https://wiki.python.org/psf/WarehouseRoadmap)