🐳

Fossil と SQLite が使える VS Code 開発コンテナーの用意 - Linux 使いになりたい人向け

2024/01/15に公開

はじめに

これは、「VS Code 開発コンテナーを使って Fossil 分散バージョン管理システムを試す - Linux 使いになりたい人向け」の続きです。

分散バージョン管理システム Fossil というものがあると知ったので、簡単に調べてみたのですが、そのときに使った VS Code 開発コンテナーについて、使いやすいものにしてみました。

Fossil をインストールして使ってみるにあたって、結局のところ node ユーザーを追加したり、Node.js 環境をインストールしたりしました。既存の VS Code 開発コンテナー用のイメージには、TypeScript が使えるものがあるので、ここではそちらを使う場合について説明します。

Fossil について調べてみると VS Code の拡張機能もあるようですし、SSH を使ったアクセスにも対応しているようです。git コマンドに近いコマンド体系ですから、VS Code 開発コンテナー内で使えるようにしておくバージョン管理システムとして良いかもしれないと思い始めています。

この記事は VS Code と Docker が使える人で Linux 使いになりたい人向けの内容で書いてあり、対象者は次の人です。

  • 分散バージョン管理システム Fossil に興味がある
  • VS Code 開発コンテナーに興味がある
  • Linux が使えるようになりたい

筆者は Linux 使いで、基本的に Linux 環境で動作確認をしています。ここで紹介しているようなちょっとしたことを少しずつ知ることを毎日続けることで Linux の機能を少しずつ理解することができるようになりました。Linux が使えるようになりたいと思っている人向けに、記事を公開していく予定です。

開発コンテナー devcon-fossil

前回と同様に、今回用意した VS Code 開発コンテナーは下記で公開しています。

ここでは、この devcon-fossil 開発コンテナーについて説明します。

動作に必要な環境 については次の通りです。

  • Docker Engine
    • Docker Compose Plugin
  • VS Code
    • Docker 拡張機能
    • Dev Containers 拡張機能

次のように ZIP ファイルをダウンロードして展開し、カレントディレクトリーを ZIP ファイルを展開したディレクトリー内にある devcon-fossil ディレクトリーとします。

curl -o dcfwd.zip -L https://codeload.github.com/hiro345g/dcfwd/zip/refs/heads/main
unzip dcfwd.zip
cd dcfwd-main/devcon-fossil

ここでは、以降、devcon-fossil ディレクトリー(フォルダ)を ${REPO_DIR} と表記します。

ディレクトリー構造

devcon-fossil 用のディレクトリー構造は次のようになっています。

devcon-fossil/
├── .devcontainer/
│   ├── devcontainer.json
│   └── script/ ... devcon-fossil 開発コンテナー内で使えるスクリプト
│       ├── postCreateCommand-node.sh ... 開発コンテナー作成後に node ユーザーで実行するスクリプト
│       └── postCreateCommand.sh ... 開発コンテナー作成後に root ユーザーで実行するスクリプト
├── README.md ... このファイル
├── docker-compose.yml ... devcon-fossil 開発コンテナー用 Docker Compose 設定ファイル
└── script/ ... Docker ホストで使用するスクリプト
    └── fossil-clean.sh

ここでは、dev-fossil 開発コンテナーのときよりも本格的に VS Code 開発コンテナーを使うために、.devcontainer/devcontainer.json ファイルを用意しています。

VS Code の Dev Containers 拡張機能は、このファイルが置いてあるフォルダを開くと、開発コンテナーとして認識して通知を表示します。

/images/20240117_devcon_fossil_vscode/devcon-fossil_01.png
開発コンテナーで再度開く

表示された通知にある「開発コンテナーで再度開く」をクリックすることで、devcon-fossil 開発コンテナーをアタッチした VS Code の画面を自動で開きます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_02.png
devcon-fossil 開発コンテナーをアタッチした VS Code の画面

devcontainer.json

devcontainer.json は次のようにしてあります。

devcontainer.json
// https://github.com/devcontainers/
{
    "name": "devcon-fossil",
    "dockerComposeFile": "../docker-compose.yml",
    "service": "devcon-fossil",
    "postCreateCommand": "sudo sh /script/postCreateCommand.sh",
    "shutdownAction": "stopCompose",
    "customizations": {
        "vscode": {
            "settings": {
                "sqltools.connections": [
                    {
                        "previewLimit": 50,
                        "driver": "SQLite",
                        "name": "proj001",
                        "database": "${workspaceFolder:repo}/proj001.fossil"
                    }
                ]
            },
            "extensions": [
                "koog1000.fossil",
                "mtxr.sqltools",
                "mtxr.sqltools-driver-sqlite"
            ]
        }
    },
    "remoteUser": "node", // "node" or "root",
    "workspaceFolder": "/home/node/repo"
}

"dockerComposeFile": で使用する docker-compose.yml ファイルを指定します。また、開発コンテナーとして利用するサービスを "service": で指定します。

開発コンテナーが用意できた後に実行するスクリプトを "postCreateCommand": で指定し、開発コンテナーの初期化処理をしています。

"shutdownAction": は開発コンテナーをアタッチした VS Code の画面を閉じた時の開発コンテナーの挙動を指定するものです。ここでは docker compose stop コマンドを実行することに相当する "stopCompose" を指定しました。

"customizations": には、開発コンテナーをアタッチした VS Code をカスタマイズする設定を指定します。SQLTools を使うので、その設定をしてあります。また、使用する拡張機能を "extensions": に指定しました。

"remoteUser": は開発コンテナーをアタッチした VS Code で使用するユーザーを指定します。今回使用する開発コンテナー用のイメージは、これを省略すると node になります。そのため、指定しなくても良いのですが、設定ファイルを見れば使うユーザーがわかる方が便利なので明示的に指定しました。ここを root とすると、管理者で開発コンテナーを利用することになります。

"workspaceFolder": は使用する docker-compose.yml に合わせて指定してあります。

開発コンテナーを起動したときに、開発コンテナー内で .devcontainer にあるファイルを編集できてしまうのはトラブルにつながりやすいのでやらないようにしています。また、バインドマウントしたファイルを操作するよりは、コンテナー内へコピーしてファイル操作した方がトラブルが少ないので、そういう方針にしています。

docker-compose.yml

docker-compose.yml ファイルは次のようになります。https://github.com/devcontainers/images で公開されている開発コンテナー用の mcr.microsoft.com/devcontainers/typescript-node:20-bookworm イメージを使っています。

docker-compose.yml
name: devcon-fossil
services:
  devcon-fossil:
    image: mcr.microsoft.com/devcontainers/typescript-node:20-bookworm
    container_name: devcon-fossil
    hostname: devcon-fossil
    init: true
    tty: true
    # node なら 1000:1000, root なら 0:0
    user: 1000:1000
    working_dir: /home/node/repo
    volumes:
      - repo-data:/home/node/repo
      - type: bind
        source: ${SCRIPT_DIR:-./.devcontainer/script}
        target: /script
        read_only: true

volumes:
  repo-data:
    name: devcon-fossil-home-node-repo-data

ここで使っている Docker イメージは、イメージ名からわかるように Node.js バージョン 20 の環境で TypeScript が使えます。また、Debian の bookworm をベースとしています。

作業で使用するボリュームは Docker ボリュームで用意して、初期化で使用するスクリプトはバインドマウントを使って devcon-fossil:/script へマウントしています。

user:working_dir:devcontainers.json と合わせたものを指定してあります。

devcon-fossil-home-node-repo-data ボリューム

この開発コンテナー用の docker-compose.yml では、devcon-fossil-home-node-repo-data ボリュームを用意していて、devcon-fossil:/home/node/repo を永続化しています。そのため、開発コンテナーを破棄しても、ここに作成したリポジトリは残ります。

postCreateCommand.sh

ここでは少し戻って、devcontainers.json"postCreateCommand": "sudo sh /script/postCreateCommand.sh", の指定について説明します。

ここで使っている /script/postCreateCommand.sh が利用可能なのは、docker-compose.yml${REPO_DIR}/.devcontainer/scriptdevcon-fossil:/script へバインドマウントしているからです。

"postCreateCommand": の指定されたコマンドは、開発コンテナーが作成された後に、node ユーザーで実行されます。

devcon-fossil 開発コンテナーでは、パッケージのインストールなど root 権限が必要なコマンドを初期化で実行したいので、sudo を使って管理者権限を付与した状態でのコマンド実行としてあります。

postCreateCommand.sh の具体的な内容は次のようになっています。

postCreateCommand.sh
#!/bin/sh

apt update \
    && apt -y upgrade \
    && apt -y install fossil sqlite3 \
    && chown node:node /home/node/repo \
    && sudo -u node /usr/bin/sh /script/postCreateCommand-node.sh

最後に実行している postCreateCommand-node.sh は node ユーザーで実行するコマンドです。別ファイルにした方が書きやすかったので別にしています。また、"postCreateCommand": で指定するコマンドは長くしたくなかったので、postCreateCommand.sh 内で実行するようにしてあります。

このスクリプトは、SQLTools で使用する sqlite3 の npm パッケージをインストールする処理を実行し、初期状態の Fossil のリポジトリ proj001.fossil を用意します。具体的な内容は次のようになります。

postCreateCommand-node.sh
#!/bin/sh
REPO_FILE=/home/node/repo/proj001.fossil

if [ -e ${HOME}/.local/share/vscode-sqltools/ ]; then
  cd ${HOME}/.local/share/vscode-sqltools/
  npm install sqlite3@5.1.1
fi
if [ ! -e ${REPO_FILE} ]; then
  fossil new ${REPO_FILE}
fi

VS Code 開発コンテナー devcon-fossil の利用

ファイルが用意できたら、VS Code 開発コンテナー devcon-fossil を起動します。手順は次の通りです。

  1. VS Code の「ファイル」-「フォルダーを開く」で ${REPO_DIR} を開く
  2. 右下に表示される通知で「開発コンテナーで再度開く」をクリック
  3. 左下に 開発コンテナー:devcon-fossil と表示された開発コンテナーが開く

これ以降、開発コンテナーの VS Code は devcon-fossil の VS Code と表記します。

サンプルリポジトリ

devcon-fossil の VS Code では、すでに説明したように、開発コンテナー起動時に、/home/node/repo/proj001.fossil というサンプルリポジトリのファイルを自動で作成するようにしてあります。そのため、devcon-fossil の VS Code のエクスプローラーにサンプルリポジトリ proj001.fossil が表示されているはずです。

/images/20240117_devcon_fossil_vscode/devcon-fossil_02.png
devcon-fossil の VS Code のエクスプローラー画面

ターミナルを起動して、/home/node/repo をカレントディレクトリーとすれば fossil コマンドを使って proj001.fossil リポジトリを利用できます。

なお、devcon-fossil の VS Code では Fossil の拡張機能 koog1000.fossil が最初から使えるようになっています。これを使って Fossil のリポジトリを使うこともできます。

Fossil の拡張機能を使ってみよう

ここでは、Fossil の拡張機能を使ってみましょう。Fossil の拡張機能は VS Code のソース管理の画面を表示すると使えます。少しわかりにくいですが、サイドバーの画面上部に表示されます。なお、サンプルリポジトリは、ここでは使いません。SQLTools の機能を使うときに利用します。

メニューにはリポジトリをクローンするための Clone と、リポジトリから作業用ディレクトリを作成するための Open のメニューが用意されています。

/images/20240117_devcon_fossil_vscode/devcon-fossil_03.png
Fossil の拡張機能で Clone と Open が可能

また、Fossil のアイコンをクリックすると、「Initialize Fossil Repository」のメニューが表示されます。これを使うことで Fossil のリポジトリファイルを作成できます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_04.png
Fossil の拡張機能でリポジトリの作成が可能

リポジトリの作成

それではリポジトリを作成してみましょう。Fossil のアイコンをクリックしてから「Initialize Fossil Repository」をクリックすると、作成するリポジトリファイル名を指定する入力欄が表示されます。ここでは /home/node/repo/repo.fossil と指定します。

/images/20240117_devcon_fossil_vscode/devcon-fossil_05.png
作成するリポジトリファイル名の指定

「OK」をクリックすると、プロジェクト名を入力する欄が表示されます。ここでは repo とします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_06.png
プロジェクト名の指定

「OK」をクリックすると、プロジェクトの説明を入力する欄が表示されます。ここでは repo プロジェクト とします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_07.png
プロジェクトの説明の指定

「OK」をクリックすると、/home/node/repo/repo.fossil というリポジトリのファイルが作成されます。通知にリポジトリをオープンするためのボタンが表示されます。ここでは、このリポジトリのファイルを直接使うことはしないので、そのままにしておきます。

リポジトリのクローン

Fossil は分散バージョン管理システムとして使えるので、リポジトリのクローンを作成することができます。普通は HTTPS や SSH といったネットワーク・プロトコル経由でリモートにあるリポジトリをクローンするときに使うのですが、ここでは機能の確認なので、同じローカルにあるファイルシステムのリポジトリをリモートにあるものと見立てて使ってみます。

単純にファイルコピーをすれば良いと思うかもしれませんが、クローンをした場合は、クローンにより作成されたローカルのリポジトリには、リモートのリポジトリの情報を持つようになります。そのため、単純にファイルコピーで別ファイルを作成した場合とはリポジトリに含まれる情報が変わります。

さて、リポジトリのクローンをするには URL を指定します。ファイルの場合は次のようになります。

file://<絶対パス>

ここでクローンするファイルは /home/node/repo/repo.fossil なので、URL は file:///home/node/repo/repo.fossil となります。

devcon-fossil の VS Code のソース管理の画面で Fossil のメニューを表示して、Clone Fossil Repository をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_03.png
Fossil の拡張機能で Clone (図では Open が反転しているが、Clone の方をクリックすること)

すると、クローンする URL を入力する画面になるので、file:///home/node/repo/repo.fossil を指定して「OK」をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_09-clone01.png
クローンする URL の指定

次に、ローカルに作成するリポジトリファイル名を入力する画面になるので、/home/node/repo/repo-clone.fossil を指定して「OK」をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_09-clone02.png
ローカルに作成するリポジトリファイル名の指定

これでリモートリポジトリから、ローカルのリポジトリをクローンできます。ここまでのリポジトリ作成とクローンでローカルリポジトリ作成を見てわかるように、Fossil ではリポジトリは1つのファイルになっています。

バージョン管理の情報はこのファイルに全部含まれるので、このファイルを複数のマシンで管理しておけば、分散バージョン管理ができるようになります。

このファイルの実体は SQLite という組み込み型リレーショナル・データベースの DB ファイルなので、後で中身を少し調べてみます。

作業用ディレクトリーの用意

さて、リポジトリファイルはバージョン管理をしたいファイルとは別のものです。バージョン管理対象としたいファイルを置くためのディレクトリーは作業用ディレクトリーとして別途用意する必要があります。ここでは、作業用に repo-clone ディレクトリーを用意することにします。

devcon-fossil の VS Code のエクスプローラーの画面で用意するなら、「新しいフォルダー」のアイコンをクリックすると用意されるエクスプローラー内の入力欄でrepo-clone と指定して Enter キーを入力します。すると、/home/node/repo/repo-clone フォルダーが作成されます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open01.png
/home/node/repo/repo-clone フォルダーの作成

ターミナルで作成することもできます。その場合は mkdir コマンドを使います。

mkdir /home/node/repo/repo-clone

作業用ディレクトリーの用意が出来たら devcon-fossil の VS Code のソース管理の画面で Fossil のメニューを表示して、Open Fossil Repository をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_03.png
Fossil の拡張機能で Open

すると、リポジトリーファイルのパスを入力する画面が表示されるので、そこへローカルのリポジトリーファイルである /home/node/repo/repo-clone.fossil を指定して「OK」をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open02.png
repo-clone.fossil リポジトリーファイルの指定

今度は、作業用ディレクトリーのパスを入力する画面が表示されるので、用意した /home/node/repo/repo-clone を指定して「OK」をクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open03.png
作業用ディレクトリー /home/node/repo/repo-clone の指定

これで devcon-fossil の VS Code のソース管理画面で Fossil リポジトリを開いた状態になります。見た目としては Git のリポジトリ作成を促す画面が消えているはずです。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open04.png
Fossil リポジトリを開いた直後の VS Code のソース管理画面

なお、ソース管理画面でサイドバーの中のメニューを開くと、Fossil 用のものが表示されていることがわかります。また、画面下にブランチ情報に trunk が表示されます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open05.png
ソース管理画面でサイドバーの中の Fossil 用メニュー

devcon-fossil の VS Code 画面でエクスプローラーをサイドバーに表示すると、/home/node/repo/repo-clone/ には .fslckout という特別なファイルが作成されいます。このことから、Fossil のリポジトリの内容を作業用ディレクトリーへ取り出せたことがわかります。といっても、まだバージョン管理をする対象ファイルがないので、他にはファイルがなくて空の状態です。

/images/20240117_devcon_fossil_vscode/devcon-fossil_10-open06.png
Fossil リポジトリを開いた後の VS Code 画面でエクスプローラー画面

バージョン管理をするファイルの追加方法については、ここでは省略して、次にリポジトリファイルの方を調べてみます。

SQLTools

fossil のリポジトリファイルの実体は SQLite の DB です。VS Code では、SQLite の DB を参照するには、SQLTools という拡張機能が使えます。この devcon-fossil 開発コンテナーでは最初から使えるようになっています。

初期状態のリポジトリファイル

devcon-fossil の VS Code の画面でアクティビティーバーにある SQLTools のアイコンをクリックすると、サイドバーに SQLTools の画面が表示されます。proj001 という接続設定名で proj001.fossil を SQLite の DB ファイルとして接続できる設定がすでにされているので、それが表示されるはずです。

ここで、proj001.fossil は、fossil コマンドで作成した初期状態のリポジトリファイルです。これを DB として開いて中を見てみましょう。proj001 のコンセントのアイコンをクリックすると、DB 接続ができます。それをクリックして proj001.fossil に接続すると、テーブルやビューの情報を確認することができます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_20-sqltool01.png
VS Code の SQLTools の画面

DB 接続をするとわかりますが、proj001.fossil にはリポジトリの情報を保存するためのテーブルが複数あります。その中に user テーブルがあるので、確認してみます。

SQLTools の画面でテーブル一覧を展開して user を表示し、それをマウス右クリックするとメニューが表示されます。その中にある Show Table Records をクリックすると、user テーブルのレコードが VS Code の画面に表示されて確認できます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_20-sqltool02.png
user テーブルのレコード表示

接続を閉じるには、マウスポインタを重ねると Disconnect と表示されるアイコンをクリックします。

/images/20240117_devcon_fossil_vscode/devcon-fossil_20-sqltool03.png
接続を閉じる

DB 接続をすると用意される proj001.session.sql には、実行したい SQL 文を記述して、ファイルの上部にある再生ボタン(▶)をクリックすると実行できます。

例えば、user テーブルの uidlogin カラムを抽出する SELECT 文を実行してみましょう。

SELECT uid, login FROM user;

これを proj001.session.sql に保存して実行すると次のような画面になります。

/images/20240117_devcon_fossil_vscode/devcon-fossil_20-sqltool04.png
proj001.session.sql の利用

このファイルは残しておけば次に DB 接続するときにも使えます。

クローンしたリポジトリファイル

クローンしたリポジトリファイルについても調べてみましょう。新規に接続情報を作成するには SQLTools の画面でマウスを重ねるとAdd New Connection と表示されるアイコンをクリックします。すると、Connection Assistant の画面が表示されます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_21-sqltool-new_01.png
Connection Assistant の画面

画面内にある SQLite(Node) をクリックすると SQLite の DB 接続設定用の画面になります。

ここでは、repo-clone という接続名で repo-clone.fossil リポジトリファイルへ接続する指定をします。ファイルは SELECT FILE で選択しようとしたところ開発コンテナー内のパスが表示されなかったので、手入力で /home/node/repo/repo-clone.fossil を指定しました。

入力できたら TEST CONNECTION をクリックするとテスト接続がされます。これが成功すると Successfully connected! というメッセージが画面に表示されます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_21-sqltool-new_02.png
DB 接続の情報を指定し、接続テストが成功したときの画面

DB 接続が成功したら、SAVE CONNECTION をクリックして接続情報を保存します。すると、DB 接続情報の保存画面になります。

/images/20240117_devcon_fossil_vscode/devcon-fossil_21-sqltool-new_03.png
DB 接続情報の保存画面

この情報は、VS Code の setting.json に保存されます。devcon-fossil の VS Code のエクスプローラーの画面から .vscode/setting.json を開いて確認することができます。

/images/20240117_devcon_fossil_vscode/devcon-fossil_21-sqltool-new_04.png
.vscode/setting.json の確認

ここでは、元から用意されていた proj001 の接続情報も追加されています。proj001 の接続情報については、.devcontainer/devcontainer.json で指定されていたものが自動で追加されたということになります。.vscode/setting.json が開いたフォルダーにあると、そちらが優先されますし、SQLTools の画面で接続情報を更新すると、このファイルに反映されるので、このままにしておきます。

さて、repo-clone.fossil については、config テーブルを確認してみましょう。repo-clone.sessin.sql ファイルに次の SQL 文を保存して実行してみます。

SELECT name, value FROM config
WHERE name in (
    'project-name',
    'project-description',
    'last-sync-url',
    'ckout:/home/node/repo/repo-clone/'
);

実行結果は次のようになります。リモートリポジトリの情報と、クローンして作成されたファイルの情報が含まれていることがわかります。

/images/20240117_devcon_fossil_vscode/devcon-fossil_21-sqltool-new_05.png
config テーブルの確認

こういった実装情報は知らなくても良いのですが、こうやって確認ができると実際の動作についても推測できることが増えます。ということで個人的にはこうやって興味があって、わかる範囲で調べてみています。

おわりに

devcon-fossil 開発コンテナーを使うと fossil コマンドを実行したり、リポジトリの実体である SQLite DB ファイルを調べたりすることができるようになります。また、Fossil 用の VS Code の拡張機能についても、使い勝手を確認することが簡単にできます。

終了するときは、devcon-fossil の VS Code 画面を閉じます。次回使うときは、最初に devcon-fossil の VS Code 画面を開いた時と同じようにします。

開発コンテナーを破棄するには、devcon-fossil の VS Code 画面を閉じた後に、Docker ホストの VS Code の画面で Docker 拡張機能の画面にして、CONTAINERS にある devcon-fossil をマウス右ボタンでクリックします。それから、メニューに表示される Compose Down をクリックすると、開発コンテナーが破棄されます。

devcon-fossil 開発コンテナーのクリーニング

devcon-fossil 開発コンテナーのクリーニングをするには、次のように Docker ホストで fossil-clean.sh スクリプトを実行します。シェルスクリプトが実行できない OS を Docker ホストで使っている場合は、相当する処理を手作業で実行してください。基本的にスクリプト内にある docker コマンドの部分を実行すれば大丈夫です。なお、クリーニングしても良い状態にしてから、実行するようにしてください。

cd ${REPO_DIR}
sh script/fossil-clean.sh

このスクリプトは、devcon-fossil 開発コンテナーが使っていた Docker ボリュームと Docker ネットワークといったリソースについて、完全に破棄します。実行すると、開発コンテナーを破棄してから、Docker ボリュームと Docker ネットワークも破棄します。

Discussion