system-wide pyenv

# 前提条件

- CentOS 6
    - CentOS 7でも全く同じ手順でいけると思われるが未確認
- インストール先ディレクトリは `/usr/local/opt/pyenv`
    - 別の場所に変えたい場合は、以下に出てくるパスを適宜読み替える

# 手順

以下、全てrootで実行する。

```bash
# pythonのビルドに必要なパッケージを入れる
# https://github.com/pyenv/pyenv/wiki#suggested-build-environment
yum install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel

# install pyenv
mkdir -p /usr/local/opt
git clone https://github.com/pyenv/pyenv.git /usr/local/opt/pyenv

# バージョン指定
cd /usr/local/opt/pyenv
git log --oneline --decorate --tags
# これで一番上に来るtagが最新
git checkout v1.2.18

# 後でどのバージョンか確認するときは再度
# git log --oneline --decorate --tags
# で HEAD がどのタグと一致しているか分かる

cat << 'EOF' > /etc/profile.d/pyenv.sh
export PYENV_ROOT="/usr/local/opt/pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
EOF

source /etc/profile.d/pyenv.sh

# 必要なpythonを入れる
pyenv install 3.6.10
```

sudo経由で使いたい場合、以下のいずれかの2パターンでsudoの設定をする。

- `secure_path` にpyenvに必要なパスを追加する
- `secure_path` を無効化し、PATHを透過するようにする

どちらでもよいが、既存のsudoersの設定によって適している方を選択する。secure_pathに `+=` が使えれば良いのだが…


```bash
# パターン1: `secure_path` にpyenvに必要なパスを追加する

visudo
# secure_pathに以下2つを追加する
# - /usr/local/opt/pyenv/shims
# - /usr/local/opt/pyenv/bin

# 変更前
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

# 変更後
Defaults    secure_path = /usr/local/opt/pyenv/shims:/usr/local/opt/pyenv/bin:/sbin:/bin:/usr/sbin:/usr/bin
```

```bash
# パターン1: `secure_path` にpyenvに必要なパスを追加する (cont'd)

cat << 'EOF' > /etc/sudoers.d/pyenv
Defaults env_keep += "PYENV_ROOT PYENV_VERSION"
EOF
```

```bash
# パターン2: `secure_path` を無効化し、PATHを透過するようにする

cat << 'EOF' > /etc/sudoers.d/pyenv
Defaults !secure_path
Defaults env_keep += "PATH"

Defaults env_keep += "PYENV_ROOT PYENV_VERSION"
EOF
```

```bash
# (Optional) パスワードレスsudoの設定
# 特定のユーザー・グループでパスワードレスでpyenv関連のコマンドをsudoで実行出来るようにする
# パターン1, 2いずれの場合でも有効
# 以下はpyenvグループを使った場合の例

cat << 'EOF' > /etc/sudoers.d/pyenv_nopasswd
Cmnd_Alias PYENV = /usr/local/opt/pyenv/bin/
%pyenv ALL = (ALL) NOPASSWD: PYENV
EOF
```

sudoersは複数条件にマッチする場合、「最後のもの」が優先されるので注意。
https://askubuntu.com/questions/100051/why-is-sudoers-nopasswd-option-not-working/100112#100112

```bash
visudo
# 何も変更せずそのまま閉じる
# これをやると /etc/sudoers.d/* のpermissionを適切に直してくれる
```

# misc

## ログインした時に表示されるエラー

```
pyenv: cannot rehash: /usr/local/opt/pyenv/shims isn't writable
```

これは `/etc/profile.d/pyenv.sh` 内にある `eval "$(pyenv init -)"` の部分で、ログインしたユーザーが `/usr/local/opt/pyenv/shims` に書き込む権限がないから。害は無いので単に無視するか、気になるなら `/dev/null` にリダイレクトして落とす。

```/etc/profile.d/pyenv.sh
export PYENV_ROOT="/usr/local/opt/pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)" > /dev/null 2>&1
```

## python 3.4.0にpoetryを入れる

pipが古すぎてそのままでは `pip install poetry` がコケるので、まずpipのバージョンアップをする。

```bash
PYENV_VERSION=3.4.0 pip install --upgrade "pip<19.2"
PYENV_VERSION=3.4.0 pip install poetry
```

間違ってバージョン指定をせずに `pip install --upgrade pip` をしてしまい、3.4.0で動作しないpipが入ってしまった場合は以下の手順で復旧出来る。

```bash
pyenv shell 3.4.0
rm -Rf /usr/local/opt/pyenv/versions/3.4.0/lib/python3.4/site-packages/pip*
python -m ensurepip
python -m pip uninstall pip
python -m ensurepip

# pyenv shellを戻す
unset PYTHON_VERSION
```

手動で削除してensurepipでデフォルトのpipを入れ直したあと、もう一度pipコマンドを使って自身をアンインストールし、再度ensurepipで元に戻す。1回目のensurepipでは、直接 `pip` コマンドが叩ける状態に戻らない。