46

Go 语言解析 git config

 5 years ago
source link: http://www.worldhello.net/2019/03/17/goconfig.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近做的一个 go 语言的项目需要频繁读写 git config 文件,一些看似现成的解决方案并不能满足需要:

git config
libgit2

在 github 上找到一个能够解析 git config 文件的项目 goconfig ,该项目的代码直接从 Git 项目的 git/config.c 移植过来,可以确保兼容性。但是这个项目只是一个半成品,因为:

  1. 不支持多值配置项。Git 的很多设置实际上是多值配置项,例如: push.pushOptionremote.<name>.fetch 等。
  2. 不支持配置文件嵌套,即不支持通过 include.path 指令包含其他配置文件,而这在我们要开发的应用中至关重要。
  3. 不支持配置文件继承(多级配置)。Git 在读取一个配置项时,会依次读取系统级配置( /etc/gitconfig )、用户全局配置( $HOME/.gitconfig )、仓库级配置文件( .git/config )、嵌套的配置文件( include.path 指向的配置文件)。从优先级上看,仓库级配置文件高于全局配置,更高于系统级配置。
  4. 不支持写配置文件。

于是派生了一个项目到 jiangxin/goconfig ,实现了上述特性。

增加多值配置特性

实际上 Git 配置项,无论单值(如 user.name ),还是多值(如 remote.<name>.fetch ),都应该一视同仁当做多值来处理,这样配置文件嵌套、配置文件继承的处理就非常简单了。即:

user.name

为此将 goconfig.go 的返回值由 map[string]string 替换为支持多值配置的自定义类型

type GitConfig map[string]GitConfigKeys
type GitConfigKeys map[string][]string

其中 GitConfig 的索引对应 config 配置文件的小节(section)名称,GitConfigKeys 的索引对应于配置项在小节内的 key。

GitConfig 最核心的方法是 GetAll ,其他方法 Get , GetBool , GetInt 等都是基于 GetAll 方法。

参见提交 9e83c31 (Add GitConfig to read boolean, int, multi-values, 2019-02-28)

增加配置文件嵌套特性

配置文件嵌套,涉及到迭代和配置文件的合并。核心方法是 GitConfig 的 Merge 方法。

参见提交 83a00ae (Parse include config files from include.path, 2019-03-05)

增加配置文件继承

配置文件继承和配置文件嵌套非常相似,都是 GitConfig 结构体的 Merge,只不过多了一些文件 IO,以及缓存机制。

参见提交 a033f72 (Add Load() function to read git config from disk, 2019-03-04)

增加配置文件写操作

实际上第一个版本的 GitConfig 结构体定义为 map[string][]string ,就可以实现多值配置。为了支持将 GitConfig 结构体回写为文件,对其做了提交修补(git commit –amend)操作。 GitConfig 的 map 索引变成了小节(section)名称。

为了支持写操作所做的第二个改变是为每一个值增加了一个范围(scope),这样在保存 GitConfig 到文件的时候,知道哪些配置来自于系统级(ScopeSystem)、全局级(ScopeGlobal)、 文件嵌套(ScopeGlobal),只将配置文件中的 ScopeSelf 记录到配置文件中。

参见提交:

一个简单的 git-config 实现

作为一个 lib,goconfig 项目的根目录是名为 goconfig 的包,为了演示如何用 goconfig 实现一个完整的 git config 命令的功能,在 cmd/gocongig 目录下写了一个 main 包。

可以用如下命令编译安装这一 goconfig 示例:

go get github.com/jiangxin/goconfig/cmd/goconfig

示例代码参见: cmd/goconfig/main.go

欢迎使用 goconfig 并帮助改进


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK