Open9

cargoコマンドでプライベートなGitHubリポジトリのRustプロジェクトを参照できるようにしたい

booinkbooink

cargoコマンドからプライベートリポジトリを参照できるようにするために、まずは https://doc.rust-lang.org/cargo/appendix/git-authentication.html を読む。

HTTPS を利用する前提でざっくり要約すると、

booinkbooink

https://git-scm.com/book/ja/v2/Git-のさまざまなツール-認証情報の保存
.gitconfig に設定するのは↓こんな書式。

[credential]
    helper = store --file /mnt/thumbdrive/.git-credentials
    helper = cache --timeout 30000

同じページの少し上に書いてある git config --global credential.helper store --file ~/.my-credentials は手元 (rust:1.58.1-slim-bullseye イメージのコンテナ内) では usage: git config [<options>]... が出力されて git config コマンドのオプションが認識されていないようだった。

booinkbooink

.gitconfig ファイルの配置場所は、実行ユーザーのホームディレクトリじゃないと、設定を読み込んでくれなかった。
プロジェクトルートにファイルを置いても反映されなかった。
クレデンシャルファイルは絶対パスを指定しておけば、readできる場所ならどこに置いても良さそうだった。

booinkbooink

インストールする側の Cargo.toml

Cargo.toml
[package]
name = "crate-install-test"
version = "0.1.0"
authors = ["booink <booink.work@gmail.com>"]
repository = "https://github.com/booink/crate-install-test"
description = """
Crate install test
"""
edition = "2018"

[dependencies]
crate-test-1 = { git = "https://github.com/booink/private-crate" }
booinkbooink

インストールされる側のファイル / フォルダ構成

  • Cargo.toml
  • crate-test-1/
    • Cargo.toml
    • src/lib.rs
  • crate-test-2/
    • Cargo.toml
    • src/lib.rs

/Cargo.toml

Cargo.toml
[workspace]
resolver = "2"
members = ["crate-test-1", "crate-test-2"]

/crate-test-1/Cargo.toml

/crate-test-1/Cargo.toml
[package]
name = "crate-test-1"
version = "0.1.0"
authors = ["booink <booink.work@gmail.com>"]
repository = "https://github.com/booink/private-crate"
description = """
Crate test 1
"""
edition = "2018"

[dependencies]
anyhow = "1"
thiserror = "1"

/crate-test-1/src/lib.rs

/crate-test-1/src/lib.rs
pub struct Hoge;

以下 crate-test-1 と同様の構成の crate-test-2 を作る。

booinkbooink

何の設定も無しに cargo build を叩くと↓こんなふうに怒られる

root@665a8f6e3151:~# cargo build
    Updating git repository `https://github.com/booink/private-crate`
error: failed to get `crate-test-1` as a dependency of package `crate-install-test v0.1.0 (/root)`

Caused by:
  failed to load source for dependency `crate-test-1`

Caused by:
  Unable to update https://github.com/booink/private-crate#6adc17f3

Caused by:
  failed to fetch into: /usr/local/cargo/git/db/private-crate-29a491d060f6c1c8

Caused by:
  failed to authenticate when downloading repository

  * attempted to find username/password via git's `credential.helper` support, but failed

  if the git CLI succeeds then `net.git-fetch-with-cli` may help here
  https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli

Caused by:
  failed to acquire username/password from local configuration
root@665a8f6e3151:~#
booinkbooink

インストールする側の Dockerfile の例。

FROM rust:1.58.1-slim-bullseye

ENV CARGO_TARGET_DIR=/tmp/target \
  DEBIAN_FRONTEND=noninteractive \
  LC_CTYPE=ja_JP.utf8 \
  LANG=ja_JP.utf8 \
  CARGO_NET_GIT_FETCH_WITH_CLI=true

RUN apt-get update \
  && apt-get install -y -q \
  ca-certificates \
  locales \
  libpq-dev \
  gnupg \
  apt-transport-https\
  libssl-dev \
  pkg-config \
  curl \
  build-essential \
  git \
  && echo "ja_JP UTF-8" > /etc/locale.gen \
  && locale-gen

RUN echo "[credential]\n\
  helper = store --file /root/.git-credential\n" > ~/.gitconfig

ARG GITHUB_USER
ARG GITHUB_TOKEN
RUN echo "https://${GITHUB_USER}:${GITHUB_TOKEN}@github.com" > /root/.git-credential

WORKDIR /app

COPY ./Cargo.toml Cargo.toml
  • CARGO_NET_GIT_FETCH_WITH_CLI=true の環境変数は固定なので Dockerfile 内に定義してしまう。
  • .gitconfig ファイルは、プロジェクト内に実ファイルとして持っていても良いが、間違って消してしまう可能性もあるので、Dockerfile 内で echo で実行ユーザーのホームに強制的に配置しておく。
  • クレデンシャルファイルは .gitconfig に記述したパスに配置する。クレデンシャルファイルの書式は https://{github_user}:{github_token}@github.com
    • GITHUB_USERGITHUB_TOKEN を ARG で受け取るようにしておく。
    • ビルド時には値が確定していないとならないので、ただの環境変数だと空文字になってしまう。
  • apt-get で git をインストールは必須。gitコマンドが使えないと以下のエラーが出る。
root@6ebb90425cf5:/app# cargo build
    Updating git repository `https://github.com/booink/private-crate`
error: failed to get `crate-test-1` as a dependency of package `crate-install-test v0.1.0 (/app)`

Caused by:
  failed to load source for dependency `crate-test-1`

Caused by:
  Unable to update https://github.com/booink/private-crate

Caused by:
  failed to clone into: /usr/local/cargo/git/db/private-crate-f90e54980aa1ea32

Caused by:
  could not execute process `git fetch --force --update-head-ok 'https://github.com/booink/private-crate' '+HEAD:refs/remotes/origin/HEAD'` (never executed)

Caused by:
  No such file or directory (os error 2)
root@6ebb90425cf5:/app#
booinkbooink

Cloud Build でコンテナイメージをビルドする場合は、GITHUB_USERGITHUB_TOKEN を設定して、ビルドの引数に渡す。(未検証)

GitHub のトークンは Expiration を No expiration (無期限) にできるので、無期限にしておく。
日数の指定をしても良いが、ある日急にビルドできなくなるのをビクビクしながら、定期的に値を入れ替えないとならないのが煩わしい。
いざとなったら revoke すれば良いので、無期限で問題ないはず。

booinkbooink

VSCode の rust-analyzer を使っていると同様の問題が発生するので、とりあえずエラーがなくなる設定を確認した。

プロジェクト以下のsettings.jsonで環境変数を設定する。

.vscode/settings.json
{
  ...
  "rust-analyzer.server.extraEnv": {
    "CARGO_NET_GIT_FETCH_WITH_CLI": "true"
  }
}

プロジェクト以下のgitの設定を追記する。

./.git/config
[credential]
  helper = store --file /path/to/.git/credential

クレデンシャル情報をファイルに保存する。

{GITHUB_USER}, {GITHUB_TOKEN} は実際の設定値で置換する。

./git/credential
https://{GITHUB_USER}:{GITHUB_TOKEN}@github.com