Skip to content

Commit

Permalink
Add Rugged::Config#add
Browse files Browse the repository at this point in the history
This method allows you to set multiple values for the same key in a
particular config, similar to `git config --add "include.path" some/path`.

For example, I have a git config with an existing `include.path` value:

```
$ cat ~/src/opensource/rugged/.git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        ignorecase = true
        precomposeunicode = true
[remote "origin"]
        url = [email protected]:codenamev/rugged.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
[submodule "vendor/libgit2"]
        active = true
        url = https://github.com/libgit2/libgit2.git
[include]
        path = /Users/codenamev/.gitconfig.reflow
```

With `Rugged::Config#add` I can set another value for `include.path`
without overwriting the existing value:

```
ruby -I lib -rrugged -e'\
config = Rugged::Repository.new("/Users/codenamev/src/opensource/rugged").config;
config.add("include.path", "/Users/codenamev/.gitconfig.extras");
p config.get_all("include.path")'
["/Users/codenamev/.gitconfig.reflow", "/Users/codenamev/.gitconfig.extras"]
```

References #725
  • Loading branch information
codenamev committed Mar 6, 2020
1 parent 683ae66 commit acb8949
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,32 @@ repo.config['user.name'] = true
repo.config.delete('user.name')
```

#### Targeting a specific config file

You can also target a specific config file to perform the same actions
as above.

```ruby
# Target a specific git-config file
config = Rugged::Config.new "absolute/path/to/file"

# Read values from the above file
repo.config['core.bare']
```

#### Working with multiple values

Rugged also makes it easy to work with configurations that have multiple values
for the same key (`multivar`s).

```ruby
# Read all values for the 'remote.origin.fetch' key
repo.config.get_all('remote.origin.fetch')

# Add a new value to the 'remote.origin.fetch' key
repo.config.add('remote.origin.fetch', '+refs/pull/*:refs/prs/*')
```

---

### General methods
Expand Down
48 changes: 48 additions & 0 deletions ext/rugged/rugged_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,53 @@ static VALUE rb_git_config_store(VALUE self, VALUE rb_key, VALUE rb_val)
return Qnil;
}

/*
* call-seq:
* cfg.add(key, value)
*
* Store the given +value+ in the Config file, under the section
* and name specified by +key+, without replacing any existing
* entries. Value can be any of the following Ruby types:
* +String+, +true+, +false+ and +Fixnum+.
*
* The config file will be automatically stored to disk.
*
* cfg.add('custom.multi.value', 'fix')
* cfg.add('custom.multi.value', true)
* cfg.add('custom.multi.value', 90)
*/
static VALUE rb_git_config_add(VALUE self, VALUE rb_key, VALUE rb_val)
{
git_config *config;
const char *key;
int error;

Data_Get_Struct(self, git_config, config);
Check_Type(rb_key, T_STRING);

key = StringValueCStr(rb_key);

/*
* "$^" is an unmatchable regexp: it will not match anything at all, so
* all values will be considered new and will not replace any present value.
*/
if (RB_TYPE_P(rb_val, T_STRING)) {
error = git_config_set_multivar(config, key, "$^", StringValueCStr(rb_val));
} else if (RB_TYPE_P(rb_val, T_TRUE) || RB_TYPE_P(rb_val, T_FALSE)) {
error = git_config_set_multivar(config, key, "$^", (rb_val == Qtrue) ? "true" : "false");
} else if (FIXNUM_P(rb_val)) {
char str_value[32];
snprintf(str_value, sizeof(str_value), "%" PRId64, (int64_t)FIX2INT(rb_val));
error = git_config_set_multivar(config, key, "$^", str_value);
} else {
rb_raise(rb_eTypeError,
"Invalid value; config files can only store string, bool or int keys");
}

rugged_exception_check(error);
return Qnil;
}

/*
* call-seq:
* cfg.delete(key) -> true or false
Expand Down Expand Up @@ -415,6 +462,7 @@ void Init_rugged_config(void)

rb_define_method(rb_cRuggedConfig, "store", rb_git_config_store, 2);
rb_define_method(rb_cRuggedConfig, "[]=", rb_git_config_store, 2);
rb_define_method(rb_cRuggedConfig, "add", rb_git_config_add, 2);

rb_define_method(rb_cRuggedConfig, "get", rb_git_config_get, 1);
rb_define_method(rb_cRuggedConfig, "[]", rb_git_config_get, 1);
Expand Down
16 changes: 16 additions & 0 deletions test/config_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,22 @@ def test_write_config_values
assert_match(/value = my value/, content)
end

def test_write_multivar_config_values
config = @repo.config
config.add('custom.multivalue', 'my value')
config.add('custom.multivalue', true)
config.add('custom.multivalue', 42)

config2 = @repo.config
custom_multivar = ['my value', 'true', '42']
assert_equal custom_multivar, config2.get_all('custom.multivalue')

content = File.read(File.join(@repo.path, 'config'))
assert_match(/multivalue = my value/, content)
assert_match(/multivalue = true/, content)
assert_match(/multivalue = 42/, content)
end

def test_delete_config_values
config = @repo.config
config.delete('core.bare')
Expand Down
26 changes: 26 additions & 0 deletions test/fixtures/text_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,32 @@ repo.config['user.name'] = true
repo.config.delete('user.name')
```

#### Targeting a specific config file

You can also target a specific config file to perform the same actions
as above.

```ruby
# Target a specific git-config file
config = Rugged::Config.new "absolute/path/to/file"

# Read values from the above file
repo.config['core.bare']
```

#### Working with multiple values

Rugged also makes it easy to work with configurations that have multiple values
for the same key (`multivar`s).

```ruby
# Read all values for the 'remote.origin.fetch' key
repo.config.get_all('remote.origin.fetch')

# Add a new value to the 'remote.origin.fetch' key
repo.config.add('remote.origin.fetch', '+refs/pull/*:refs/prs/*')
```

---

### General methods
Expand Down

0 comments on commit acb8949

Please sign in to comment.