feat(config): add api for config entry

This commit is contained in:
Aleksey Kulikov 2021-09-20 15:52:04 +03:00
parent cf677e488a
commit 7b8dfcc1af
6 changed files with 163 additions and 45 deletions

View file

@ -131,10 +131,10 @@ Pointer<git_config> snapshot(Pointer<git_config> config) {
}
}
/// Get the value of a config variable.
/// Get the config entry of a config variable.
///
/// Throws a [LibGit2Error] if error occured.
String getValue(Pointer<git_config> cfg, String variable) {
Pointer<git_config_entry> getEntry(Pointer<git_config> cfg, String variable) {
final out = calloc<Pointer<git_config_entry>>();
final name = variable.toNativeUtf8().cast<Int8>();
final error = libgit2.git_config_get_entry(out, cfg, name);
@ -144,7 +144,7 @@ String getValue(Pointer<git_config> cfg, String variable) {
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value.ref.value.cast<Utf8>().toDartString();
return out.value;
}
}
@ -197,23 +197,10 @@ void setString(Pointer<git_config> cfg, String variable, String value) {
}
/// Iterate over all the config variables.
Map<String, String> getEntries(Pointer<git_config> cfg) {
final iterator = calloc<Pointer<git_config_iterator>>();
final entry = calloc<Pointer<git_config_entry>>();
libgit2.git_config_iterator_new(iterator, cfg);
var error = 0;
final entries = <String, String>{};
while (error != -31) {
error = libgit2.git_config_next(entry, iterator.value);
entries[entry.value.ref.name.cast<Utf8>().toDartString()] =
entry.value.ref.value.cast<Utf8>().toDartString();
}
calloc.free(iterator);
calloc.free(entry);
return entries;
Pointer<git_config_iterator> iterator(Pointer<git_config> cfg) {
final out = calloc<Pointer<git_config_iterator>>();
libgit2.git_config_iterator_new(out, cfg);
return out.value;
}
/// Delete a config variable from the config file with the highest level
@ -298,5 +285,13 @@ void deleteMultivar(Pointer<git_config> cfg, String variable, String regexp) {
calloc.free(regexpC);
}
/// Free a config iterator.
void iteratorFree(Pointer<git_config_iterator> iter) =>
libgit2.git_config_iterator_free(iter);
/// Free a config entry.
void entryFree(Pointer<git_config_entry> entry) =>
libgit2.git_config_entry_free(entry);
/// Free the configuration and its associated memory and files.
void free(Pointer<git_config> cfg) => libgit2.git_config_free(cfg);

View file

@ -1,10 +1,13 @@
import 'dart:collection';
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'bindings/libgit2_bindings.dart';
import 'bindings/config.dart' as bindings;
import 'git_types.dart';
import 'util.dart';
class Config {
class Config with IterableMixin<ConfigEntry> {
/// Initializes a new instance of [Config] class from provided
/// pointer to config object in memory.
///
@ -89,18 +92,15 @@ class Config {
/// Throws a [LibGit2Error] if error occured.
Config get snapshot => Config(bindings.snapshot(_configPointer));
/// Returns map of all the config variables and their values.
Map<String, String> get variables => bindings.getEntries(_configPointer);
/// Returns the value of config [variable].
String operator [](String variable) =>
bindings.getValue(_configPointer, variable);
/// Returns the [ConfigEntry] of a [variable].
ConfigEntry operator [](String variable) =>
ConfigEntry(bindings.getEntry(_configPointer, variable));
/// Sets the [value] of config [variable].
void operator []=(String variable, dynamic value) {
if (value.runtimeType == bool) {
if (value is bool) {
bindings.setBool(_configPointer, variable, value);
} else if (value.runtimeType == int) {
} else if (value is int) {
bindings.setInt(_configPointer, variable, value);
} else {
bindings.setString(_configPointer, variable, value);
@ -141,4 +141,73 @@ class Config {
/// Releases memory allocated for config object.
void free() => bindings.free(_configPointer);
@override
Iterator<ConfigEntry> get iterator =>
ConfigIterator(bindings.iterator(_configPointer));
}
class ConfigEntry {
ConfigEntry(this._configEntryPointer);
/// Pointer to memory address for allocated config entry object.
final Pointer<git_config_entry> _configEntryPointer;
/// Returns name of the entry (normalised).
String get name => _configEntryPointer.ref.name.cast<Utf8>().toDartString();
/// Returns value of the entry.
String get value => _configEntryPointer.ref.value.cast<Utf8>().toDartString();
/// Returns depth of includes where this variable was found
int get includeDepth => _configEntryPointer.ref.include_depth;
/// Returns which config file this was found in.
GitConfigLevel get level {
late GitConfigLevel result;
for (var level in GitConfigLevel.values) {
if (_configEntryPointer.ref.level == level.value) {
result = level;
break;
}
}
return result;
}
/// Releases memory allocated for config entry object.
void free() => bindings.entryFree(_configEntryPointer);
@override
String toString() {
return 'ConfigEntry{name: $name, value: $value, includeDepth: $includeDepth, level: $level}';
}
}
class ConfigIterator implements Iterator<ConfigEntry> {
ConfigIterator(this._iteratorPointer);
/// Pointer to memory address for allocated config iterator.
final Pointer<git_config_iterator> _iteratorPointer;
ConfigEntry? _currentEntry;
int error = 0;
final entry = calloc<Pointer<git_config_entry>>();
@override
ConfigEntry get current => _currentEntry!;
@override
bool moveNext() {
if (error < 0) {
return false;
} else {
error = libgit2.git_config_next(entry, _iteratorPointer);
if (error != -31) {
_currentEntry = ConfigEntry(entry.value);
return true;
} else {
return false;
}
}
}
}

View file

@ -1072,3 +1072,51 @@ class GitApplyLocation {
@override
String toString() => 'GitApplyLocation.$_name';
}
/// Priority level of a config file.
/// These priority levels correspond to the natural escalation logic
/// (from higher to lower) when searching for config entries in git.
class GitConfigLevel {
const GitConfigLevel._(this._value, this._name);
final int _value;
final String _name;
/// System-wide on Windows, for compatibility with portable git.
static const programData = GitConfigLevel._(1, 'programData');
/// System-wide configuration file; /etc/gitconfig on Linux systems.
static const system = GitConfigLevel._(2, 'system');
/// XDG compatible configuration file; typically ~/.config/git/config
static const xdg = GitConfigLevel._(3, 'xdg');
/// User-specific configuration file (also called Global configuration
/// file); typically ~/.gitconfig
static const global = GitConfigLevel._(4, 'global');
/// Repository specific configuration file; $WORK_DIR/.git/config on
/// non-bare repos.
static const local = GitConfigLevel._(5, 'local');
/// Application specific configuration file; freely defined by applications.
static const app = GitConfigLevel._(6, 'app');
/// Represents the highest level available config file (i.e. the most
/// specific config file available that actually is loaded).
static const highest = GitConfigLevel._(-1, 'highest');
static const List<GitConfigLevel> values = [
programData,
system,
xdg,
global,
local,
app,
highest,
];
int get value => _value;
@override
String toString() => 'GitConfigLevel.$_name';
}