git2-rs icon indicating copy to clipboard operation
git2-rs copied to clipboard

Config object is always live - get_str() fails

Open drahnr opened this issue 6 years ago • 7 comments

When attempting to

    let cfg = repo.config().expect("Failed to obtain config struct");
    let name = cfg.get_str("user.name").unwrap(); // <<<  fails here
    let email = cfg.get_str("user.email").unwrap();

it always fails with:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { code: -1, klass: 7, message: "get_string called on a live config object" }', src/libcore/result.rs:999:5
stack backtrace:

which I backtraced down to is_readonly returning 1.

int git_config_get_string(
	const char **out, const git_config *cfg, const char *name)
{
	git_config_entry *entry;
	int ret;

	if (!is_readonly(cfg)) { // <<<< always fails
		git_error_set(GIT_ERROR_CONFIG, "get_string called on a live config object");
		return -1;
	}

	ret = get_entry(&entry, cfg, name, true, GET_ALL_ERRORS);
	*out = !ret ? (entry->value ? entry->value : "") : NULL;

	git_config_entry_free(entry);

	return ret;
}

Minimal fully runnable demo of the issue: https://github.com/drahnr/gitconfigtest/

$ git config user.name
Bernhard

works fine

(Or maybe I do not understand the meaning of this error and it's a layer 8 problem)

drahnr avatar Sep 21 '19 10:09 drahnr

$ dnf info libgit2
Name         : libgit2
Version      : 0.27.8
Release      : 2.fc30
Architecture : x86_64
Size         : 1.2 M
Quelle       : libgit2-0.27.8-2.fc30.src.rpm
Repository   : @System
Aus Paketque : fedora
Summary      : C implementation of the Git core methods as a library with a solid API
<snip>

drahnr avatar Sep 21 '19 10:09 drahnr

Interestingly:

    for entry in &cfg.entries(None).unwrap() {
        let entry = entry.unwrap();
        println!("{} => {}", entry.name().unwrap(), entry.value().unwrap());
    }

yields:

filter.lfs.clean => git-lfs clean -- %f
filter.lfs.smudge => git-lfs smudge -- %f
filter.lfs.process => git-lfs filter-process
filter.lfs.required => true
user.name => Bernhard
user.email => my github email
core.editor => micro
sequence.editor => interactive-rebase-tool
core.bare => false
core.repositoryformatversion => 0
core.filemode => true
core.logallrefupdates => true
remote.origin.url => [email protected]:drahnr/gitconfigtest.git
remote.origin.fetch => +refs/heads/*:refs/remotes/origin/*
branch.master.remote => origin
branch.master.merge => refs/heads/master

drahnr avatar Sep 21 '19 11:09 drahnr

Derived from that:

    let name = cfg.get_entry("user.name").unwrap();
    let name = name.value().unwrap();
    let email = cfg.get_entry("user.email").unwrap();
    let email = email.value().unwrap();

works just fine.

So this is probably rather a request clarifying what should be used, since the get_str clearly has some constraints the get_entry does not which is not reflected in the documentation.

drahnr avatar Sep 21 '19 11:09 drahnr

Note that the readonly requirment is only present in git_config_get_str but in none of the others: All others use the git_config_entry APIs internally and thus do not have this check.

drahnr avatar Sep 21 '19 11:09 drahnr

I've fallen foul of this exact problem too! It's not clear looking at the upstream c why this behaves this way... Is it worth opening an issue upstream?

bradwood avatar Apr 10 '20 21:04 bradwood

I would suggest to fix the binding to use the entry API or at least document it sufficiently :) I never got around to do so though.

drahnr avatar Apr 13 '20 13:04 drahnr

I know it's almost 5 years later, but still.

Could you try this?

    let cfg = repo.config().expect("Failed to obtain config struct").snapshot().unwrap();
    let name = cfg.get_str("user.name").unwrap();
    let email = cfg.get_str("user.email").unwrap();

I encountered exactly the same issue - attempt to read anything from config resulted in this error:

Error { code: -1, klass: 7, message: "get_string called on a live config object" }

Not sure why that is, and I don't want to jump to conclusions before inspecting underlying C code. I'm curious though, so I'll definitely do it when I have a moment.

jakublaba avatar Jul 30 '24 20:07 jakublaba

Still broken.

However, this works: repo.config.get_entry()

As a workaround, anywhere that I would use something equivalent to:

repo.config().unwrap().get_str("core.bare").unwrap()

I would instead use:

repo.config().unwrap().get_entry("core.bare").unwrap().value()

roylaurie avatar Aug 03 '25 15:08 roylaurie