TAKOYAKING’s blog 一覧

TAKOYAKING’s blog

たこ焼き系

Rust: gitのincludeIfで設定したgitconfigがCargo newで生成されるCargo.tomlに反映されない

現象

includeIfをしようしてgitconfigを切り替えている場合に、cargo new <プロジェクト名>をするとCargo.tomlのauthorsに切り替えたgitconfigの情報が入らずに、globalで設定しているgitconfig情報が入ってしまう。

例えばglobalのgitconfigの設定が
username: global_takoyaki

includeIfで設定したgitconfigの設定が
username: local_takoyaki

とした場合に、切り替わるはずのディレクトリでcargo new <プロジェクト名>をするとglobal_takoyakiが設定されてしまう。
local_takoyakiにしたい!

追跡

GitHub - rust-lang/cargo: The Rust package manager
ここからCargoのRepoがあるので追跡してみる。
src/cargo/ops配下にCargoのコマンドのファイルがあります。
src/cargo/ops/cargo_new.rs
にはcargo newとcargo initのコマンド記述があります。

これらのメソッドは共通して

fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()>

を呼び出しており、ここでgit initやCargo.tomlの一連の処理を行なっているようです。

特にgit initの処理は

fn init_vcs(path: &Path, vcs: VersionControl, config: &Config) -> CargoResult<()>

を呼び出しており、そこからバージョン管理のツールごとに場合分けを行なっています。

Gitの処理はsrc/cargo/util/vcs.rsのGitRepo構造体で管理されており、実態はlibgit2 for Rustが使用されているようです。

gitのincludeIfの仕様

対象のフォルダへ行ってgit config user.nameを実行しただけでは、globalのgitconfigが参照される。
git initをして、gitリポジトリが生成されてからgit config user.nameを実行するとincludeIfのgitconfigが参照される。

gitのincludeIfで指定したgitconfigが反映されない理由

原因はgitが生成されるディレクトリからgitconfigを取得しようとしていないためです。
例えば、takoyakiフォルダでCargo new <プロジェクト名>とした時の現在のディレクトリはtakoyakiなので、gitはtakoyakiフォルダにgitがないのでグローバルの設定を取得しにいこうとします。

かなり雑にCargoのソースコード修正

impl GitRepo {
    pub fn init(path: &Path, _: &Path) -> CargoResult<GitRepo> {
        let _ = env::set_current_dir(path).is_ok(); // <=====ここ
        git2::Repository::init(path)?;
        Ok(GitRepo)
    }
   // 省略
}
 let _ = env::set_current_dir(path).is_ok();

git initの処理される前に、現在の作業ディレクトリをgitが生成されるディレクトリに変更すれば、includeIfで設定したgitconfigが反映されます。

※ かなり雑です。何も考慮してません。

代替案

mkdir sample
cd sample
cargo init .

でcargo initを使用する方法ならgitの生成されるディレクトと作業ディレクトリが一致するので、想定のgitconfigの情報が反映されます。

修正すべきか?

微妙な気がします。
一応cargoのヘルプをみると以下のように記載されていて、

USAGE:
    cargo new [OPTIONS] <path>

OPTIONS:
    -q, --quiet                  No output printed to stdout
        --registry <REGISTRY>    Registry to use
        --vcs <VCS>              Initialize a new repository for the given version control system (git, hg, pijul, or
                                 fossil) or do not initialize any version control at all (none), overriding a global
                                 configuration. [possible values: git, hg, pijul, fossil, none]
        --bin                    Use a binary (application) template [default]
        --lib                    Use a library template
        --edition <YEAR>         Edition to set for the crate generated [possible values: 2015, 2018]
        --name <NAME>            Set the resulting package name, defaults to the directory name
    -v, --verbose                Use verbose output (-vv very verbose/build.rs output)
        --color <WHEN>           Coloring: auto, always, never
        --frozen                 Require Cargo.lock and cache are up to date
        --locked                 Require Cargo.lock is up to date
        --offline                Run without accessing the network
    -Z <FLAG>...                 Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
    -h, --help                   Prints help information

ARGS:
    <path>

と書いてあるので、大丈夫と言えば、大丈夫なのですが、意識しないと、うっかりとglobalの方のgitconfigがtomlに反映されてしまうので、個人的には自動でincludeIfで設定したgitconfigを参照してほしい気がします。