Visual Studio Code Remote Development で ~/.bash_profile (~/.profile) が読み込まれなかった

先日、個人的なPython学習のための環境を作ろうと思った。

自分のマシンの環境を汚したくないし、Dockerで環境を作って、Visual Studio CodeのRemote Developmentでコードを書くことにした。

せっかくPythonの環境を作るのだからパッケージマネージャーのPoetryでライブラリをインストールしてやろうと考えた。

しかし、DockerコンテナにRemote Developmentで接続後にVisual Studio Codeのコンソールで`poetry`を実行すると`poetry: command not found`が表示される。

困った。

# 結論

先に結論を書いておくとVisual Studio CodeでLinux環境のターミナルを起動した時、デフォルト設定のままではログインシェルを起動しないので
`~/.bash_profile`や`~/.profile`が読み込まれない。

ログインシェルを起動したいのであれば`"terminal.integrated.shellArgs.linux": ["-l"]`を`settings.json`に記述しなければいけない。

## 2021年6月25日追記

Visual Studio Code 1.57.1 で確認すると`"terminal.integrated.shellArgs.linux"`などは動作するが非推奨扱いになっていた。

今後は`"terminal.integrated.profiles.linux"`に対してシェルのプロファイル名を記述して詳細な設定を記載していくというスタイルになる様子。

さらに、ターミナルを起動したときに実行するデフォルトのプロファイルは`"terminal.integrated.defaultProfile.linux"`で指定する。

`settings.json`のサンプル:

```json
...
    // デフォルトで`"terminal.integrated.profiles.linux"`の`"bash"`をターミナルで起動させる。
    "terminal.integrated.defaultProfile.linux": "bash",
    // シェルのプロファイル名に対して`"path"`で実行するシェルのパスを指定し、`"args"`で起動時の引数を指定する。
    "terminal.integrated.profiles.linux": {
        "bash": {
            "path": "bash",
            "args": [
                "-l"
            ]
        },
        "zsh": {
            "path": "zsh"
        },
        "fish": {
            "path": "fish"
        },
        "tmux": {
            "path": "tmux",
            "icon": "terminal-tmux"
        },
        "pwsh": {
            "path": "pwsh",
            "icon": "terminal-powershell"
        }
    },
...
```


# 何がやりたかったか

「Docker使うのに何でPoetry使うの？」と言われそうなのでPoetryを使う理由を先に書いておく。

残念ながら私が身を置いている環境ではDockerがまったくと言っていいくらいに使われていない。
もし、業務でアプリケーションを開発する際にPythonを使う機会があってもDockerを使える可能性は低いと考えられる。

この理由に基づいてPythonと一緒にパッケージマネージャーの使い方も学んでやろうと考えて、
PoetryをDockerコンテナの中で使うことにしました。

# 問題の仮想環境構成ファイル

Remote Development用に作成したファイルは、関連個所を抜粋すると大体以下のような内容だった。

```json:.devcontainer/devcontainer.json
{
    "name": "Python 3",
    "dockerComposeFile": [
        "../docker-compose.yml",
        "./devcontainer.extend.yml"
    ],
    "service": "python",
    "workspaceFolder": "/workspace",
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash",
        "python.pythonPath": "/usr/local/bin/python",
        "python.linting.pylintPath": "/usr/local/bin/pylint",
        "python.linting.pylintEnabled": false,
        "python.linting.flake8Enabled": true,
        "python.linting.mypyEnabled": true,
        "editor.formatOnSave": true,
        "python.linting.lintOnSave": true
    },
    "extensions": [
        "ms-python.python"
    ],
    "shutdownAction": "stopCompose"
}

```

```yaml:docker-compose.yml
version: "3"

services:
  python:
    image: python
    container_name: python
    build:
      context: ./docker/python
      dockerfile: Dockerfile
```

```yaml:.devcontainer/devcontainer.extend.yml
version: "3"

services:
  python:
    volumes:
      - ./:/workspace:cached
```

```dockerfile:docker/python/Dockerfile
FROM python:3.8.1-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    apt-utils \
    gcc \
    build-essential \
    curl \
    libpq-dev \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
```

このような環境でRemote DevelopmentでDocker Compose upしていたが、
Visual Studio Codeのターミナルで`poetry`を実行しようとすると`command not found`が表示される。

この時のPoetryはバージョン 1.0.5で、公式推奨のインストール方法に従って
`curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python`を実行していた。

`get-poetry.py`が`PATH`に`poetry`を追加しているのだろうと中身を確認したところ
`~/.bash_profile`と`~/.profile`で`PATH`に`~/.poetry/bin`を追加していた。

ターミナルで`cat ~/.profile`して中身を確認すると、`export PATH="$HOME/.poetry/bin:$PATH"`はちゃんと書き込まれている。

「なんで`poetry`が`command not found`になるんだ？」と考えながら`source ~/.profile`を実行すると、
それ以降`poetry`コマンドは実行できてしまう。

手順に間違いがあるのだろうと考え、比較のために非推奨の`pip install --user poetry`でインストールを行うも、
こちらも`poetry`コマンドは正常に実行できてしまう。

ここから「どこかに間違いや勘違いがあるから`PATH`が通っていない」と思いながら四苦八苦を開始する。
この時、自分が使い慣れていないDocker周りに勘違いがあるのだろうという思い込みの元、
`Dockerfile`に`RUN . ~/.profile`を書いてみたりするなど試して間違いを重ねて時間を浪費する。

何が間違っているか分からないまま小一時間が経過し、嫌になってきたので「`PATH`通せばいいや」と考え以下の変更を追加。

Dockerコンテナビルドして、`poetry`コマンドが実行できることを確認。

```diff:docker/python/Dockerfile
FROM python:3.8.1-slim

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
    apt-utils \
    gcc \
    build-essential \
    curl \
    libpq-dev \
    && apt-get autoremove -y \
    && apt-get clean -y \
    && rm -rf /var/lib/apt/lists/*

RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
+ # The path of poetry is added to PATH.
+ ENV PATH="/root/.poetry/bin:${PATH}"
```

普段からDockerをバリバリ使っているわけでは無いし、時間もあまり使いたくなかった（この時点で一時間使っているけど）。

原因究明は一旦あきらめて、Poetry周りの環境構築はとりあえずOKということにしておいた。

## 数日後

作業中にふと閃く、「`cron`でありがちなログインシェルを経由していないせいで発生する`~/.bash_profile`経由しないとコマンドが動作しない現象と同じだ・・・」。

「Visual Studio CodeがRemote Developmentしている時のシェル設定はどこだ」と思ったが、
自分で`.devcontainer/devcontainer.json`に`"terminal.integrated.shell.linux": "/bin/bash"`を書いていることに気が付く。

しかし、該当設定値はシェルの指定だけのようで`/bin/bash`を指定しているが、`-l`オプションの指定は別の設定の様だった。
Visual Studio CodeのSettingsを開くと、`"terminal.integrated.shellArgs.linux": []`が見つかる。

「デフォルト設定でログインシェル読み込まないのか」と思っていると、
Mac OSは`"terminal.integrated.shellArgs.osx": ["-l"]`がデフォルトになっている。

念のためにドキュメントを確認すると__親切に書いてる。

[Integrated Terminal in Visual Studio Code](https://code.visualstudio.com/docs/editor/integrated-terminal#_shell-arguments)

> You can pass arguments to the shell when it is launched.
>
> For example, to enable running bash as a login shell (which runs .bash_profile), pass in the -l argument (with double quotes):
>
> ```json
> // Linux
"terminal.integrated.shellArgs.linux": ["-l"]
> ```

`.devcontainer/devcontainer.json`に
`terminal.integrated.shellArgs.linux": ["-l"]`を追加し、
`Dockerfile`に追記した`ENV PATH="/root/.poetry/bin:${PATH}"`を削除。

DockerコンテナリビルドしてRemote Development起動し、`poetry`コマンドにPATHが通っている事を確認。

そして、ここまで事実確認ができたことで、これはLinux OSでVisual Studio Codeのターミナル使ったときに、
いつでも発生する問題なのでは無いかと思い当たり、検索をかけるといくつも事例が出てくる。

* [VSCodeのRemote\-SSHでリモート先のLinuxのbash\_profileを読み込む \- Qiita](https://qiita.com/S_SenSq/items/c949844749ed8d02ae5e)
* [vscodeのterminalで\.bash\_profileが読み込まれない \- Qiita](https://qiita.com/hikaruworld@github/items/bbe7718874bf1fa9e940)
* [bash \- VSCode Integrated Terminal Doesn't Load \.bashrc or \.bash\_profile \- Stack Overflow](https://stackoverflow.com/questions/51820921/vscode-integrated-terminal-doesnt-load-bashrc-or-bash-profile)

完全に自分の見落としだった。