From c35d336a56ee76aebea66f2ec21bb8bbdfc5ede3 Mon Sep 17 00:00:00 2001 From: Aleksey Kulikov Date: Tue, 24 May 2022 16:07:57 +0300 Subject: [PATCH] feat: add ability to get and set libgit2 global options (#59) --- lib/src/bindings/libgit2_opts_bindings.dart | 712 ++++++++++++-------- lib/src/libgit2.dart | 500 +++++++++++++- test/libgit2_test.dart | 196 +++++- 3 files changed, 1127 insertions(+), 281 deletions(-) diff --git a/lib/src/bindings/libgit2_opts_bindings.dart b/lib/src/bindings/libgit2_opts_bindings.dart index d17ea96..0c1df6c 100644 --- a/lib/src/bindings/libgit2_opts_bindings.dart +++ b/lib/src/bindings/libgit2_opts_bindings.dart @@ -1,6 +1,7 @@ // coverage:ignore-file import 'dart:ffi' as ffi; +import 'package:libgit2dart/src/bindings/libgit2_bindings.dart'; /// Bindings to libgit2 global options class Libgit2Opts { @@ -12,283 +13,456 @@ class Libgit2Opts { Libgit2Opts(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup; - /// Set or query a library global option - /// - /// Available options: - /// - /// * opts(GIT_OPT_GET_MWINDOW_SIZE, size_t *): - /// - /// > Get the maximum mmap window size - /// - /// * opts(GIT_OPT_SET_MWINDOW_SIZE, size_t): - /// - /// > Set the maximum mmap window size - /// - /// * opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, size_t *): - /// - /// > Get the maximum memory that will be mapped in total by the library - /// - /// * opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, size_t): - /// - /// > Set the maximum amount of memory that can be mapped at any time - /// > by the library - /// - /// * opts(GIT_OPT_GET_MWINDOW_FILE_LIMIT, size_t *): - /// - /// > Get the maximum number of files that will be mapped at any time by the - /// > library - /// - /// * opts(GIT_OPT_SET_MWINDOW_FILE_LIMIT, size_t): - /// - /// > Set the maximum number of files that can be mapped at any time - /// > by the library. The default (0) is unlimited. - /// - /// * opts(GIT_OPT_GET_SEARCH_PATH, int level, git_buf *buf) - /// - /// > Get the search path for a given level of config data. "level" must - /// > be one of `GIT_CONFIG_LEVEL_SYSTEM`, `GIT_CONFIG_LEVEL_GLOBAL`, - /// > `GIT_CONFIG_LEVEL_XDG`, or `GIT_CONFIG_LEVEL_PROGRAMDATA`. - /// > The search path is written to the `out` buffer. - /// - /// * opts(GIT_OPT_SET_SEARCH_PATH, int level, const char *path) - /// - /// > Set the search path for a level of config data. The search path - /// > applied to shared attributes and ignore files, too. - /// > - /// > - `path` lists directories delimited by GIT_PATH_LIST_SEPARATOR. - /// > Pass NULL to reset to the default (generally based on environment - /// > variables). Use magic path `$PATH` to include the old value - /// > of the path (if you want to prepend or append, for instance). - /// > - /// > - `level` must be `GIT_CONFIG_LEVEL_SYSTEM`, - /// > `GIT_CONFIG_LEVEL_GLOBAL`, `GIT_CONFIG_LEVEL_XDG`, or - /// > `GIT_CONFIG_LEVEL_PROGRAMDATA`. - /// - /// * opts(GIT_OPT_SET_CACHE_OBJECT_LIMIT, git_object_t type, size_t size) - /// - /// > Set the maximum data size for the given type of object to be - /// > considered eligible for caching in memory. Setting to value to - /// > zero means that that type of object will not be cached. - /// > Defaults to 0 for GIT_OBJECT_BLOB (i.e. won't cache blobs) and 4k - /// > for GIT_OBJECT_COMMIT, GIT_OBJECT_TREE, and GIT_OBJECT_TAG. - /// - /// * opts(GIT_OPT_SET_CACHE_MAX_SIZE, ssize_t max_storage_bytes) - /// - /// > Set the maximum total data size that will be cached in memory - /// > across all repositories before libgit2 starts evicting objects - /// > from the cache. This is a soft limit, in that the library might - /// > briefly exceed it, but will start aggressively evicting objects - /// > from cache when that happens. The default cache size is 256MB. - /// - /// * opts(GIT_OPT_ENABLE_CACHING, int enabled) - /// - /// > Enable or disable caching completely. - /// > - /// > Because caches are repository-specific, disabling the cache - /// > cannot immediately clear all cached objects, but each cache will - /// > be cleared on the next attempt to update anything in it. - /// - /// * opts(GIT_OPT_GET_CACHED_MEMORY, ssize_t *current, ssize_t *allowed) - /// - /// > Get the current bytes in cache and the maximum that would be - /// > allowed in the cache. - /// - /// * opts(GIT_OPT_GET_TEMPLATE_PATH, git_buf *out) - /// - /// > Get the default template path. - /// > The path is written to the `out` buffer. - /// - /// * opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path) - /// - /// > Set the default template path. - /// > - /// > - `path` directory of template. - /// - /// * opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, const char *file, const char *path) - /// - /// > Set the SSL certificate-authority locations. - /// > - /// > - `file` is the location of a file containing several - /// > certificates concatenated together. - /// > - `path` is the location of a directory holding several - /// > certificates, one per file. - /// > - /// > Either parameter may be `NULL`, but not both. - /// - /// * opts(GIT_OPT_SET_USER_AGENT, const char *user_agent) - /// - /// > Set the value of the User-Agent header. This value will be - /// > appended to "git/1.0", for compatibility with other git clients. - /// > - /// > - `user_agent` is the value that will be delivered as the - /// > User-Agent header on HTTP requests. - /// - /// * opts(GIT_OPT_SET_WINDOWS_SHAREMODE, unsigned long value) - /// - /// > Set the share mode used when opening files on Windows. - /// > For more information, see the documentation for CreateFile. - /// > The default is: FILE_SHARE_READ | FILE_SHARE_WRITE. This is - /// > ignored and unused on non-Windows platforms. - /// - /// * opts(GIT_OPT_GET_WINDOWS_SHAREMODE, unsigned long *value) - /// - /// > Get the share mode used when opening files on Windows. - /// - /// * opts(GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, int enabled) - /// - /// > Enable strict input validation when creating new objects - /// > to ensure that all inputs to the new objects are valid. For - /// > example, when this is enabled, the parent(s) and tree inputs - /// > will be validated when creating a new commit. This defaults - /// > to enabled. - /// - /// * opts(GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, int enabled) - /// - /// > Validate the target of a symbolic ref when creating it. For - /// > example, `foobar` is not a valid ref, therefore `foobar` is - /// > not a valid target for a symbolic ref by default, whereas - /// > `refs/heads/foobar` is. Disabling this bypasses validation - /// > so that an arbitrary strings such as `foobar` can be used - /// > for a symbolic ref target. This defaults to enabled. - /// - /// * opts(GIT_OPT_SET_SSL_CIPHERS, const char *ciphers) - /// - /// > Set the SSL ciphers use for HTTPS connections. - /// > - /// > - `ciphers` is the list of ciphers that are eanbled. - /// - /// * opts(GIT_OPT_GET_USER_AGENT, git_buf *out) - /// - /// > Get the value of the User-Agent header. - /// > The User-Agent is written to the `out` buffer. - /// - /// * opts(GIT_OPT_ENABLE_OFS_DELTA, int enabled) - /// - /// > Enable or disable the use of "offset deltas" when creating packfiles, - /// > and the negotiation of them when talking to a remote server. - /// > Offset deltas store a delta base location as an offset into the - /// > packfile from the current location, which provides a shorter encoding - /// > and thus smaller resultant packfiles. - /// > Packfiles containing offset deltas can still be read. - /// > This defaults to enabled. - /// - /// * opts(GIT_OPT_ENABLE_FSYNC_GITDIR, int enabled) - /// - /// > Enable synchronized writes of files in the gitdir using `fsync` - /// > (or the platform equivalent) to ensure that new object data - /// > is written to permanent storage, not simply cached. This - /// > defaults to disabled. - /// - /// opts(GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, int enabled) - /// - /// > Enable strict verification of object hashsums when reading - /// > objects from disk. This may impact performance due to an - /// > additional checksum calculation on each object. This defaults - /// > to enabled. - /// - /// opts(GIT_OPT_SET_ALLOCATOR, git_allocator *allocator) - /// - /// > Set the memory allocator to a different memory allocator. This - /// > allocator will then be used to make all memory allocations for - /// > libgit2 operations. If the given `allocator` is NULL, then the - /// > system default will be restored. - /// - /// opts(GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, int enabled) - /// - /// > Ensure that there are no unsaved changes in the index before - /// > beginning any operation that reloads the index from disk (eg, - /// > checkout). If there are unsaved changes, the instruction will - /// > fail. (Using the FORCE flag to checkout will still overwrite - /// > these changes.) - /// - /// opts(GIT_OPT_GET_PACK_MAX_OBJECTS, size_t *out) - /// - /// > Get the maximum number of objects libgit2 will allow in a pack - /// > file when downloading a pack file from a remote. This can be - /// > used to limit maximum memory usage when fetching from an untrusted - /// > remote. - /// - /// opts(GIT_OPT_SET_PACK_MAX_OBJECTS, size_t objects) - /// - /// > Set the maximum number of objects libgit2 will allow in a pack - /// > file when downloading a pack file from a remote. - /// - /// opts(GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, int enabled) - /// > This will cause .keep file existence checks to be skipped when - /// > accessing packfiles, which can help performance with remote filesystems. - /// - /// opts(GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, int enabled) - /// > When connecting to a server using NTLM or Negotiate - /// > authentication, use expect/continue when POSTing data. - /// > This option is not available on Windows. - /// - /// opts(GIT_OPT_SET_ODB_PACKED_PRIORITY, int priority) - /// > Override the default priority of the packed ODB backend which - /// > is added when default backends are assigned to a repository - /// - /// opts(GIT_OPT_SET_ODB_LOOSE_PRIORITY, int priority) - /// > Override the default priority of the loose ODB backend which - /// > is added when default backends are assigned to a repository - /// - /// opts(GIT_OPT_GET_EXTENSIONS, git_strarray *out) - /// > Returns the list of git extensions that are supported. This - /// > is the list of built-in extensions supported by libgit2 and - /// > custom extensions that have been added with - /// > `GIT_OPT_SET_EXTENSIONS`. Extensions that have been negated - /// > will not be returned. The returned list should be released - /// > with `git_strarray_dispose`. - /// - /// opts(GIT_OPT_SET_EXTENSIONS, const char **extensions, size_t len) - /// > Set that the given git extensions are supported by the caller. - /// > Extensions supported by libgit2 may be negated by prefixing - /// > them with a `!`. For example: setting extensions to - /// > { "!noop", "newext" } indicates that the caller does not want - /// > to support repositories with the `noop` extension but does want - /// > to support repositories with the `newext` extension. - /// - /// opts(GIT_OPT_GET_OWNER_VALIDATION, int *enabled) - /// > Gets the owner validation setting for repository - /// > directories. - /// - /// opts(GIT_OPT_SET_OWNER_VALIDATION, int enabled) - /// > Set that repository directories should be owned by the current - /// > user. The default is to validate ownership. - /// - /// @param option Option key - /// @param ... value to set the option - /// @return 0 on success, <0 on failure - int git_libgit2_opts( - int option, - ffi.Pointer out, - ) { - return _git_libgit2_opts( - option, + /// Get the maximum mmap window size. + int git_libgit2_opts_get_mwindow_size(ffi.Pointer out) { + return _git_libgit2_opts_get_int( + git_libgit2_opt_t.GIT_OPT_GET_MWINDOW_SIZE, out, ); } - late final _git_libgit2_optsPtr = _lookup< - ffi.NativeFunction)>>( - 'git_libgit2_opts'); - late final _git_libgit2_opts = _git_libgit2_optsPtr - .asFunction)>(); - - /// Set a library global option. - /// - /// Look at [git_libgit2_opts] - int git_libgit2_opts_set( - int option, - int value, - ) { - return _git_libgit2_opts_set( - option, + /// Set the maximum mmap window size. + int git_libgit2_opts_set_mwindow_size(int value) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_MWINDOW_SIZE, value, ); } - late final _git_libgit2_opts_setPtr = + /// Get the maximum memory that will be mapped in total by the library. + /// + /// The default (0) is unlimited. + int git_libgit2_opts_get_mwindow_mapped_limit(ffi.Pointer out) { + return _git_libgit2_opts_get_int( + git_libgit2_opt_t.GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, + out, + ); + } + + /// Set the maximum amount of memory that can be mapped at any time by the + /// library. + int git_libgit2_opts_set_mwindow_mapped_limit(int value) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, + value, + ); + } + + /// Get the maximum number of files that will be mapped at any time by the + /// library. + /// + /// The default (0) is unlimited. + int git_libgit2_opts_get_mwindow_file_limit(ffi.Pointer out) { + return _git_libgit2_opts_get_int( + git_libgit2_opt_t.GIT_OPT_GET_MWINDOW_FILE_LIMIT, + out, + ); + } + + /// Set the maximum number of files that can be mapped at any time by the + /// library. + int git_libgit2_opts_set_mwindow_file_limit(int value) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_MWINDOW_FILE_LIMIT, + value, + ); + } + + /// Get the search path for a given level of config data. + /// + /// [level] must be one of `GIT_CONFIG_LEVEL_SYSTEM`, + /// `GIT_CONFIG_LEVEL_GLOBAL`, `GIT_CONFIG_LEVEL_XDG`, or + /// `GIT_CONFIG_LEVEL_PROGRAMDATA`. + /// + /// The search path is written to the [out] buffer. + int git_libgit2_opts_get_search_path(int level, ffi.Pointer out) { + return _git_libgit2_opts_get_search_path( + git_libgit2_opt_t.GIT_OPT_GET_SEARCH_PATH, + level, + out, + ); + } + + /// Set the search path for a level of config data. The search path applied + /// to shared attributes and ignore files, too. + /// + /// [path] lists directories delimited by GIT_PATH_LIST_SEPARATOR. + /// Pass NULL to reset to the default (generally based on environment + /// variables). Use magic path `$PATH` to include the old value of the path + /// (if you want to prepend or append, for instance). + /// + /// [level] must be one of `GIT_CONFIG_LEVEL_SYSTEM`, + /// `GIT_CONFIG_LEVEL_GLOBAL`, `GIT_CONFIG_LEVEL_XDG`, or + /// `GIT_CONFIG_LEVEL_PROGRAMDATA`. + int git_libgit2_opts_set_search_path(int level, ffi.Pointer path) { + return _git_libgit2_opts_set_search_path( + git_libgit2_opt_t.GIT_OPT_SET_SEARCH_PATH, + level, + path, + ); + } + + /// Set the maximum data size for the given [type] of object to be + /// considered eligible for caching in memory. Setting the [value] to + /// zero means that that type of object will not be cached. + /// + /// Defaults to 0 for GIT_OBJECT_BLOB (i.e. won't cache blobs) and 4k + /// for GIT_OBJECT_COMMIT, GIT_OBJECT_TREE, and GIT_OBJECT_TAG. + int git_libgit2_opts_set_cache_object_limit(int type, int value) { + return _git_libgit2_opts_set_cache_object_limit( + git_libgit2_opt_t.GIT_OPT_SET_CACHE_OBJECT_LIMIT, + type, + value, + ); + } + + /// Set the maximum total data size that will be cached in memory + /// across all repositories before libgit2 starts evicting objects + /// from the cache. This is a soft limit, in that the library might + /// briefly exceed it, but will start aggressively evicting objects + /// from cache when that happens. + /// + /// The default cache size is 256MB. + int git_libgit2_opts_set_cache_max_size(int bytes) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_CACHE_MAX_SIZE, + bytes, + ); + } + + /// Get the current bytes in cache and the maximum that would be + /// allowed in the cache. + int git_libgit2_opts_get_cached_memory( + ffi.Pointer current, + ffi.Pointer allowed, + ) { + return _git_libgit2_opts_get_cached_memory( + git_libgit2_opt_t.GIT_OPT_GET_CACHED_MEMORY, + current, + allowed, + ); + } + + /// Enable or disable caching completely. + /// + /// Because caches are repository-specific, disabling the cache + /// cannot immediately clear all cached objects, but each cache will + /// be cleared on the next attempt to update anything in it. + int git_libgit2_opts_enable_caching(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_CACHING, + enabled, + ); + } + + /// Get the default template path. + /// The path is written to the `out` buffer. + int git_libgit2_opts_get_template_path(ffi.Pointer out) { + return _git_libgit2_opts_get_buf( + git_libgit2_opt_t.GIT_OPT_GET_TEMPLATE_PATH, + out, + ); + } + + /// Set the default template [path]. + int git_libgit2_opts_set_template_path(ffi.Pointer path) { + return _git_libgit2_opts_set_char( + git_libgit2_opt_t.GIT_OPT_SET_TEMPLATE_PATH, + path, + ); + } + + /// Set the SSL certificate-authority locations. + /// + /// - [file] is the location of a file containing several + /// certificates concatenated together. + /// - [path] is the location of a directory holding several + /// certificates, one per file. + /// + /// Either parameter may be `NULL`, but not both. + int git_libgit2_opts_set_ssl_cert_locations( + ffi.Pointer file, + ffi.Pointer path, + ) { + return _git_libgit2_opts_set_ssl_cert_locations( + git_libgit2_opt_t.GIT_OPT_SET_SSL_CERT_LOCATIONS, + file, + path, + ); + } + + /// Get the value of the User-Agent header. + /// + /// The User-Agent is written to the `out` buffer. + int git_libgit2_opts_get_user_agent(ffi.Pointer out) { + return _git_libgit2_opts_get_buf( + git_libgit2_opt_t.GIT_OPT_GET_USER_AGENT, + out, + ); + } + + /// Set the value of the User-Agent header. This value will be + /// appended to "git/1.0", for compatibility with other git clients. + /// + /// - [user_agent] is the value that will be delivered as the + /// User-Agent header on HTTP requests. + int git_libgit2_opts_set_user_agent(ffi.Pointer user_agent) { + return _git_libgit2_opts_set_char( + git_libgit2_opt_t.GIT_OPT_SET_USER_AGENT, + user_agent, + ); + } + + /// Enable strict input validation when creating new objects + /// to ensure that all inputs to the new objects are valid. + /// + /// For example, when this is enabled, the parent(s) and tree inputs + /// will be validated when creating a new commit. + /// + /// This defaults to enabled. + int git_libgit2_opts_enable_strict_object_creation(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_STRICT_OBJECT_CREATION, + enabled, + ); + } + + /// Validate the target of a symbolic ref when creating it. + /// + /// For example, `foobar` is not a valid ref, therefore `foobar` is + /// not a valid target for a symbolic ref by default, whereas + /// `refs/heads/foobar` is. + /// + /// Disabling this bypasses validation so that an arbitrary strings + /// such as `foobar` can be used for a symbolic ref target. + /// + /// This defaults to enabled. + int git_libgit2_opts_enable_strict_symbolic_ref_creation(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION, + enabled, + ); + } + + /// Enable or disable the use of "offset deltas" when creating packfiles, + /// and the negotiation of them when talking to a remote server. + /// + /// Offset deltas store a delta base location as an offset into the + /// packfile from the current location, which provides a shorter encoding + /// and thus smaller resultant packfiles. + /// + /// Packfiles containing offset deltas can still be read. + /// + /// This defaults to enabled. + int git_libgit2_opts_enable_offset_delta(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_OFS_DELTA, + enabled, + ); + } + + /// Enable synchronized writes of files in the gitdir using `fsync` + /// (or the platform equivalent) to ensure that new object data + /// is written to permanent storage, not simply cached. + /// + /// This defaults to disabled. + int git_libgit2_opts_enable_fsync_gitdir(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_FSYNC_GITDIR, + enabled, + ); + } + + /// Enable strict verification of object hashsums when reading + /// objects from disk. + /// + /// This may impact performance due to an additional checksum calculation + /// on each object. + /// + /// This defaults to enabled. + int git_libgit2_opts_enable_strict_hash_verification(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION, + enabled, + ); + } + + /// Ensure that there are no unsaved changes in the index before + /// beginning any operation that reloads the index from disk (e.g., + /// checkout). + /// + /// If there are unsaved changes, the instruction will fail (using + /// the FORCE flag to checkout will still overwrite these changes). + int git_libgit2_opts_enable_unsaved_index_safety(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY, + enabled, + ); + } + + /// Get the maximum number of objects libgit2 will allow in a pack + /// file when downloading a pack file from a remote. This can be + /// used to limit maximum memory usage when fetching from an untrusted + /// remote. + int git_libgit2_opts_get_pack_max_objects(ffi.Pointer out) { + return _git_libgit2_opts_get_int( + git_libgit2_opt_t.GIT_OPT_GET_PACK_MAX_OBJECTS, + out, + ); + } + + /// Set the maximum number of objects libgit2 will allow in a pack + /// file when downloading a pack file from a remote. + int git_libgit2_opts_set_pack_max_objects(int value) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_PACK_MAX_OBJECTS, + value, + ); + } + + /// This will cause .keep file existence checks to be skipped when + /// accessing packfiles, which can help performance with remote filesystems. + int git_libgit2_opts_disable_pack_keep_file_checks(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS, + enabled, + ); + } + + /// When connecting to a server using NTLM or Negotiate + /// authentication, use expect/continue when POSTing data. + /// + /// This option is not available on Windows. + int git_libgit2_opts_enable_http_expect_continue(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE, + enabled, + ); + } + + /// Gets the owner validation setting for repository directories. + int git_libgit2_opts_get_owner_validation(ffi.Pointer out) { + return _git_libgit2_opts_get_int( + git_libgit2_opt_t.GIT_OPT_GET_OWNER_VALIDATION, + out, + ); + } + + /// Set that repository directories should be owned by the current + /// user. The default is to validate ownership. + int git_libgit2_opts_set_owner_validation(int enabled) { + return _git_libgit2_opts_set_int( + git_libgit2_opt_t.GIT_OPT_SET_OWNER_VALIDATION, + enabled, + ); + } + + /// Returns the list of git extensions that are supported. + /// This is the list of built-in extensions supported by libgit2 and + /// custom extensions that have been added with [git_libgit2_opts_set_extensions]. + /// + /// Extensions that have been negated will not be returned. + int git_libgit2_opts_get_extensions(ffi.Pointer out) { + return _git_libgit2_opts_get_extensions( + git_libgit2_opt_t.GIT_OPT_GET_EXTENSIONS, + out, + ); + } + + /// Set that the given git extensions are supported by the caller. + /// + /// Extensions supported by libgit2 may be negated by prefixing + /// them with a `!`. For example: setting extensions to + /// { "!noop", "newext" } indicates that the caller does not want + /// to support repositories with the `noop` extension but does want + /// to support repositories with the `newext` extension. + int git_libgit2_opts_set_extensions( + ffi.Pointer> extensions, + int len, + ) { + return _git_libgit2_opts_set_extensions( + git_libgit2_opt_t.GIT_OPT_SET_EXTENSIONS, + extensions, + len, + ); + } + + late final _git_libgit2_opts_get_intPtr = _lookup< + ffi.NativeFunction)>>( + 'git_libgit2_opts'); + late final _git_libgit2_opts_get_int = _git_libgit2_opts_get_intPtr + .asFunction)>(); + + late final _git_libgit2_opts_set_intPtr = _lookup>( 'git_libgit2_opts'); - late final _git_libgit2_opts_set = - _git_libgit2_opts_setPtr.asFunction(); + late final _git_libgit2_opts_set_int = + _git_libgit2_opts_set_intPtr.asFunction(); + + late final _git_libgit2_opts_get_bufPtr = _lookup< + ffi.NativeFunction)>>( + 'git_libgit2_opts'); + late final _git_libgit2_opts_get_buf = _git_libgit2_opts_get_bufPtr + .asFunction)>(); + + late final _git_libgit2_opts_set_charPtr = _lookup< + ffi.NativeFunction)>>( + 'git_libgit2_opts'); + late final _git_libgit2_opts_set_char = _git_libgit2_opts_set_charPtr + .asFunction)>(); + + late final _git_libgit2_opts_get_search_pathPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function( + ffi.Int, ffi.Int, ffi.Pointer)>>('git_libgit2_opts'); + late final _git_libgit2_opts_get_search_path = + _git_libgit2_opts_get_search_pathPtr + .asFunction)>(); + + late final _git_libgit2_opts_set_search_pathPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function( + ffi.Int, ffi.Int, ffi.Pointer)>>('git_libgit2_opts'); + late final _git_libgit2_opts_set_search_path = + _git_libgit2_opts_set_search_pathPtr + .asFunction)>(); + + late final _git_libgit2_opts_set_cache_object_limitPtr = + _lookup>( + 'git_libgit2_opts'); + late final _git_libgit2_opts_set_cache_object_limit = + _git_libgit2_opts_set_cache_object_limitPtr + .asFunction(); + + late final _git_libgit2_opts_get_cached_memoryPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function(ffi.Int, ffi.Pointer, + ffi.Pointer)>>('git_libgit2_opts'); + late final _git_libgit2_opts_get_cached_memory = + _git_libgit2_opts_get_cached_memoryPtr.asFunction< + int Function(int, ffi.Pointer, ffi.Pointer)>(); + + late final _git_libgit2_opts_set_ssl_cert_locationsPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function(ffi.Int, ffi.Pointer, + ffi.Pointer)>>('git_libgit2_opts'); + late final _git_libgit2_opts_set_ssl_cert_locations = + _git_libgit2_opts_set_ssl_cert_locationsPtr.asFunction< + int Function(int, ffi.Pointer, ffi.Pointer)>(); + + late final _git_libgit2_opts_get_extensionsPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function( + ffi.Int, ffi.Pointer)>>('git_libgit2_opts'); + late final _git_libgit2_opts_get_extensions = + _git_libgit2_opts_get_extensionsPtr + .asFunction)>(); + + late final _git_libgit2_opts_set_extensionsPtr = _lookup< + ffi.NativeFunction< + ffi.Int Function(ffi.Int, ffi.Pointer>, + ffi.Int)>>('git_libgit2_opts'); + late final _git_libgit2_opts_set_extensions = + _git_libgit2_opts_set_extensionsPtr.asFunction< + int Function(int, ffi.Pointer>, int)>(); } diff --git a/lib/src/libgit2.dart b/lib/src/libgit2.dart index a39bb46..29ab98d 100644 --- a/lib/src/libgit2.dart +++ b/lib/src/libgit2.dart @@ -35,29 +35,509 @@ class Libgit2 { .toSet(); } + /// Maximum mmap window size. + static int get mmapWindowSize { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_mwindow_size(out); + final result = out.value; + calloc.free(out); + + return result; + } + + static set mmapWindowSize(int value) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_mwindow_size(value); + } + + /// Maximum memory that will be mapped in total by the library. + /// + /// The default (0) is unlimited. + static int get mmapWindowMappedLimit { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_mwindow_mapped_limit(out); + final result = out.value; + calloc.free(out); + + return result; + } + + static set mmapWindowMappedLimit(int value) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_mwindow_mapped_limit(value); + } + + /// Maximum number of files that will be mapped at any time by the library. + /// + /// The default (0) is unlimited. + static int get mmapWindowFileLimit { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_mwindow_file_limit(out); + final result = out.value; + calloc.free(out); + + return result; + } + + static set mmapWindowFileLimit(int value) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_mwindow_file_limit(value); + } + + /// Returns search path for a given [level] of config data. + /// + /// [level] must be one of: + /// - [GitConfigLevel.system] + /// - [GitConfigLevel.global] + /// - [GitConfigLevel.xdg] + /// - [GitConfigLevel.programData] + static String getConfigSearchPath(GitConfigLevel level) { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_search_path(level.value, out); + final result = out.ref.ptr.cast().toDartString(length: out.ref.size); + + libgit2.git_buf_dispose(out); + calloc.free(out); + + return result; + } + + /// Sets the search path for a [level] of config data. The search path + /// applied to shared attributes and ignore files. + /// + /// [path] lists directories delimited by `:`. + /// Pass null to reset to the default (generally based on environment + /// variables). Use magic path `$PATH` to include the old value of the path + /// (if you want to prepend or append, for instance). + /// + /// [level] must be one of: + /// - [GitConfigLevel.system] + /// - [GitConfigLevel.global] + /// - [GitConfigLevel.xdg] + /// - [GitConfigLevel.programData] + static void setConfigSearchPath({ + required GitConfigLevel level, + required String? path, + }) { + libgit2.git_libgit2_init(); + + final pathC = path?.toNativeUtf8().cast() ?? nullptr; + libgit2Opts.git_libgit2_opts_set_search_path(level.value, pathC); + calloc.free(pathC); + } + + /// Sets the maximum data size for the given [type] of object to be + /// considered eligible for caching in memory. Setting the [value] to + /// zero means that that type of object will not be cached. + /// + /// Defaults to 0 for [GitObject.blob] (i.e. won't cache blobs) and 4k + /// for [GitObject.commit], [GitObject.tree] and [GitObject.tag]. + static void setCacheObjectLimit({ + required GitObject type, + required int value, + }) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_cache_object_limit(type.value, value); + } + + /// Sets the maximum total data size that will be cached in memory + /// across all repositories before libgit2 starts evicting objects + /// from the cache. This is a soft limit, in that the library might + /// briefly exceed it, but will start aggressively evicting objects + /// from cache when that happens. + /// + /// The default cache size is 256MB. + static void setCacheMaxSize(int bytes) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_cache_max_size(bytes); + } + + /// [CachedMemory] object containing current bytes in cache and the maximum + /// that would be allowed in the cache. + static CachedMemory get cachedMemory { + libgit2.git_libgit2_init(); + + final current = calloc(); + final allowed = calloc(); + libgit2Opts.git_libgit2_opts_get_cached_memory(current, allowed); + + final result = CachedMemory._( + current: current.value, + allowed: allowed.value, + ); + + calloc.free(current); + calloc.free(allowed); + return result; + } + + /// Enables caching. + static void enableCaching() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_caching(1); + } + + /// Disables caching completely. + /// + /// Because caches are repository-specific, disabling the cache + /// cannot immediately clear all cached objects, but each cache will + /// be cleared on the next attempt to update anything in it. + static void disableCaching() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_caching(0); + } + + /// Default template path. + static String get templatePath { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_template_path(out); + final result = out.ref.ptr.cast().toDartString(length: out.ref.size); + + libgit2.git_buf_dispose(out); + calloc.free(out); + + return result; + } + + static set templatePath(String path) { + libgit2.git_libgit2_init(); + + final pathC = path.toNativeUtf8().cast(); + libgit2Opts.git_libgit2_opts_set_template_path(pathC); + + calloc.free(pathC); + } + + /// Sets the SSL certificate-authority locations. + /// + /// - [file] is the location of a file containing several + /// certificates concatenated together. + /// - [path] is the location of a directory holding several + /// certificates, one per file. + /// + /// Either parameter may be null, but not both. + /// + /// Throws [ArgumentError] if both arguments are null. + static void setSSLCertLocations({String? file, String? path}) { + if (file == null && path == null) { + throw ArgumentError("Both file and path can't be null"); + } else { + libgit2.git_libgit2_init(); + + final fileC = file?.toNativeUtf8().cast() ?? nullptr; + final pathC = path?.toNativeUtf8().cast() ?? nullptr; + + libgit2Opts.git_libgit2_opts_set_ssl_cert_locations(fileC, pathC); + + calloc.free(fileC); + calloc.free(pathC); + } + } + + /// Value of the User-Agent header. + /// + /// This value will be appended to "git/1.0", for compatibility with other + /// git clients. + static String get userAgent { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_user_agent(out); + final result = out.ref.ptr.cast().toDartString(length: out.ref.size); + + libgit2.git_buf_dispose(out); + calloc.free(out); + + return result; + } + + static set userAgent(String userAgent) { + libgit2.git_libgit2_init(); + + final userAgentC = userAgent.toNativeUtf8().cast(); + libgit2Opts.git_libgit2_opts_set_user_agent(userAgentC); + + calloc.free(userAgentC); + } + + /// Enables strict input validation when creating new objects + /// to ensure that all inputs to the new objects are valid. + /// + /// For example, when this is enabled, the parent(s) and tree inputs + /// will be validated when creating a new commit. + /// + /// Enabled by default. + static void enableStrictObjectCreation() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_object_creation(1); + } + + /// Disables strict input validation when creating new objects. + /// + /// Enabled by default. + static void disableStrictObjectCreation() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_object_creation(0); + } + + /// Enables validation of a symbolic ref target when creating it. + /// + /// For example, `foobar` is not a valid ref, therefore `foobar` is + /// not a valid target for a symbolic ref by default, whereas + /// `refs/heads/foobar` is. + /// + /// Disabling this bypasses validation so that an arbitrary strings + /// such as `foobar` can be used for a symbolic ref target. + /// + /// Enabled by default. + static void enableStrictSymbolicRefCreation() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_symbolic_ref_creation(1); + } + + /// Disables validation of a symbolic ref target when creating it. + /// + /// For example, `foobar` is not a valid ref, therefore `foobar` is + /// not a valid target for a symbolic ref by default, whereas + /// `refs/heads/foobar` is. + /// + /// Disabling this bypasses validation so that an arbitrary strings + /// such as `foobar` can be used for a symbolic ref target. + /// + /// Enabled by default. + static void disableStrictSymbolicRefCreation() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_symbolic_ref_creation(0); + } + + /// Enables the use of "offset deltas" when creating packfiles, + /// and the negotiation of them when talking to a remote server. + /// + /// Offset deltas store a delta base location as an offset into the + /// packfile from the current location, which provides a shorter encoding + /// and thus smaller resultant packfiles. + /// + /// Enabled by default. + static void enableOffsetDelta() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_offset_delta(1); + } + + /// Disables the use of "offset deltas" when creating packfiles, + /// and the negotiation of them when talking to a remote server. + /// + /// Offset deltas store a delta base location as an offset into the + /// packfile from the current location, which provides a shorter encoding + /// and thus smaller resultant packfiles. + /// + /// Packfiles containing offset deltas can still be read. + /// + /// Enabled by default. + static void disableOffsetDelta() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_offset_delta(0); + } + + /// Enables synchronized writes of files in the gitdir using `fsync` + /// (or the platform equivalent) to ensure that new object data + /// is written to permanent storage, not simply cached. + /// + /// Disabled by default. + static void enableFsyncGitdir() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_fsync_gitdir(1); + } + + /// Disables synchronized writes of files in the gitdir using `fsync` + /// (or the platform equivalent). + /// + /// Disabled by default. + static void disableFsyncGitdir() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_fsync_gitdir(0); + } + + /// Enables strict verification of object hashsums when reading objects from + /// disk. + /// + /// This may impact performance due to an additional checksum calculation + /// on each object. + /// + /// Enabled by default. + static void enableStrictHashVerification() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_hash_verification(1); + } + + /// Disables strict verification of object hashsums when reading objects from + /// disk. + /// + /// Enabled by default. + static void disableStrictHashVerification() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_strict_hash_verification(0); + } + + /// Enables check for unsaved changes in the index before beginning any + /// operation that reloads the index from disk (e.g., checkout). + /// + /// If there are unsaved changes, the instruction will fail (using + /// the FORCE flag to checkout will still overwrite these changes). + /// + /// Enabled by default. + static void enableUnsavedIndexSafety() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_unsaved_index_safety(1); + } + + /// Disables check for unsaved changes in the index before beginning any + /// operation that reloads the index from disk (e.g., checkout). + /// + /// If there are unsaved changes, the instruction will fail (using + /// the FORCE flag to checkout will still overwrite these changes). + /// + /// Enabled by default. + static void disableUnsavedIndexSafety() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_unsaved_index_safety(0); + } + + /// Maximum number of objects libgit2 will allow in a pack file when + /// downloading a pack file from a remote. This can be used to limit maximum + /// memory usage when fetching from an untrusted remote. + static int get packMaxObjects { + libgit2.git_libgit2_init(); + + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_pack_max_objects(out); + final result = out.value; + calloc.free(out); + + return result; + } + + static set packMaxObjects(int value) { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_set_pack_max_objects(value); + } + + /// Enables checks of .keep file existence to be skipped when accessing + /// packfiles. + static void enablePackKeepFileChecks() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_disable_pack_keep_file_checks(0); + } + + /// Disables checks of .keep file existence to be skipped when accessing + /// packfiles, which can help performance with remote filesystems. + static void disablePackKeepFileChecks() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_disable_pack_keep_file_checks(1); + } + + /// When connecting to a server using NTLM or Negotiate + /// authentication, use expect/continue when POSTing data. + /// + /// This option is not available on Windows. + static void enableHttpExpectContinue() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_http_expect_continue(1); + } + + /// When connecting to a server using NTLM or Negotiate + /// authentication, don't use expect/continue when POSTing data. + /// + /// This option is not available on Windows. + static void disableHttpExpectContinue() { + libgit2.git_libgit2_init(); + libgit2Opts.git_libgit2_opts_enable_http_expect_continue(0); + } + + /// List of git extensions that are supported. + /// + /// This is the list of built-in extensions supported by libgit2 and + /// custom extensions that have been added. + /// + /// Extensions supported by libgit2 may be negated by prefixing + /// them with a `!`. For example: setting extensions to + /// `"!noop", "newext"` indicates that the caller does not want + /// to support repositories with the `noop` extension but does want + /// to support repositories with the `newext` extension. + /// + /// Extensions that have been negated will not be returned. + static List get extensions { + libgit2.git_libgit2_init(); + + final array = calloc(); + libgit2Opts.git_libgit2_opts_get_extensions(array); + + final result = [ + for (var i = 0; i < array.ref.count; i++) + array.ref.strings.elementAt(i).value.cast().toDartString() + ]; + + calloc.free(array); + + return result; + } + + static set extensions(List extensions) { + libgit2.git_libgit2_init(); + + final array = calloc>(extensions.length); + for (var i = 0; i < extensions.length; i++) { + array[i] = extensions[i].toNativeUtf8().cast(); + } + + libgit2Opts.git_libgit2_opts_set_extensions(array, extensions.length); + + for (var i = 0; i < extensions.length; i++) { + calloc.free(array[i]); + } + calloc.free(array); + } + /// Owner validation setting for repository directories. + /// + /// Enabled by default. static bool get ownerValidation { libgit2.git_libgit2_init(); - final out = calloc(); - libgit2Opts.git_libgit2_opts( - git_libgit2_opt_t.GIT_OPT_GET_OWNER_VALIDATION, - out, - ); + final out = calloc(); + libgit2Opts.git_libgit2_opts_get_owner_validation(out); final result = out.value; calloc.free(out); return result == 1 || false; } - /// Sets owner validation setting for repository directories. static set ownerValidation(bool value) { libgit2.git_libgit2_init(); final valueC = value ? 1 : 0; - libgit2Opts.git_libgit2_opts_set( - git_libgit2_opt_t.GIT_OPT_SET_OWNER_VALIDATION, - valueC, - ); + libgit2Opts.git_libgit2_opts_set_owner_validation(valueC); + } +} + +/// Current bytes in cache and the maximum that would be allowed in the cache. +class CachedMemory { + const CachedMemory._({required this.current, required this.allowed}); + + final int current; + final int allowed; + + @override + String toString() { + return 'CachedMemory{current: $current, allowed: $allowed}'; } } diff --git a/test/libgit2_test.dart b/test/libgit2_test.dart index 744c280..0e42630 100644 --- a/test/libgit2_test.dart +++ b/test/libgit2_test.dart @@ -20,10 +20,202 @@ void main() { 'directories', () { final oldValue = Libgit2.ownerValidation; Libgit2.ownerValidation = !oldValue; - expect(Libgit2.ownerValidation, equals(!oldValue)); + expect(Libgit2.ownerValidation, isNot(oldValue)); - // Set it back + // Reset to avoid side effects in later tests Libgit2.ownerValidation = oldValue; }); + + test('sets and returns the maximum mmap window size', () { + final oldValue = Libgit2.mmapWindowSize; + Libgit2.mmapWindowSize = 420 * 1024; + expect(Libgit2.mmapWindowSize, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.mmapWindowSize = oldValue; + }); + + test( + 'sets and returns the maximum memory that will be mapped in total by ' + 'the library', () { + final oldValue = Libgit2.mmapWindowMappedLimit; + Libgit2.mmapWindowMappedLimit = 420 * 1024; + expect(Libgit2.mmapWindowMappedLimit, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.mmapWindowMappedLimit = oldValue; + }); + + test( + 'sets and returns the maximum number of files that will be mapped ' + 'at any time by the library', () { + final oldValue = Libgit2.mmapWindowFileLimit; + Libgit2.mmapWindowFileLimit = 69; + expect(Libgit2.mmapWindowFileLimit, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.mmapWindowFileLimit = oldValue; + }); + + test('sets and returns the search path for a given level of config data', + () { + const paths = '/tmp/global:/tmp/another'; + Libgit2.setConfigSearchPath(level: GitConfigLevel.global, path: paths); + expect(Libgit2.getConfigSearchPath(GitConfigLevel.global), paths); + + // Reset to avoid side effects in later tests + Libgit2.setConfigSearchPath(level: GitConfigLevel.global, path: null); + }); + + test( + 'sets the maximum data size for the given type of object ' + 'to be considered eligible for caching in memory', () { + expect( + () => Libgit2.setCacheObjectLimit(type: GitObject.blob, value: 420), + returnsNormally, + ); + + // Reset to avoid side effects in later tests + Libgit2.setCacheObjectLimit(type: GitObject.blob, value: 0); + }); + + test('sets the maximum cache size', () { + expect(Libgit2.cachedMemory.allowed, 256 * (1024 * 1024)); + + Libgit2.setCacheMaxSize(128 * (1024 * 1024)); + + expect(Libgit2.cachedMemory.allowed, 128 * (1024 * 1024)); + + // Reset to avoid side effects in later tests + Libgit2.setCacheMaxSize(256 * (1024 * 1024)); + }); + + test('returns CachedMemory object', () { + expect(Libgit2.cachedMemory.allowed, 256 * (1024 * 1024)); + expect(Libgit2.cachedMemory.toString(), contains('CachedMemory{')); + }); + + test('disables and enables caching', () { + expect(() => Libgit2.disableCaching(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableCaching(); + }); + + test('sets and returns the default template path', () { + final oldValue = Libgit2.templatePath; + Libgit2.templatePath = '/tmp/template'; + expect(Libgit2.templatePath, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.templatePath = oldValue; + }); + + test('sets location for ssl certificates', () { + expect( + () => Libgit2.setSSLCertLocations(file: 'etc/ssl/cert.pem'), + returnsNormally, + ); + expect( + () => Libgit2.setSSLCertLocations(path: 'etc/ssl/certs/'), + returnsNormally, + ); + }); + + test('throws when trying to set both ssl certificates location to null', + () { + expect( + () => Libgit2.setSSLCertLocations(), + throwsA(isA()), + ); + }); + + test('sets and returns the User-Agent header', () { + final oldValue = Libgit2.userAgent; + Libgit2.userAgent = 'Mozilla/5.0'; + expect(Libgit2.userAgent, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.userAgent = oldValue; + }); + + test('disables and enables strict object creation', () { + expect(() => Libgit2.disableStrictObjectCreation(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableStrictObjectCreation(); + }); + + test('disables and enables strict symbolic reference creation', () { + expect(() => Libgit2.disableStrictSymbolicRefCreation(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableStrictSymbolicRefCreation(); + }); + + test( + 'disables and enables the use of offset deltas when creating packfiles', + () { + expect(() => Libgit2.disableOffsetDelta(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableOffsetDelta(); + }); + + test('enables and disables the fsync of files in gitdir', () { + expect(() => Libgit2.enableFsyncGitdir(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.disableFsyncGitdir(); + }); + + test('disables and enables strict hash verification', () { + expect(() => Libgit2.disableStrictHashVerification(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableStrictHashVerification(); + }); + + test('disables and enables check for unsaved changes in index', () { + expect(() => Libgit2.disableUnsavedIndexSafety(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableUnsavedIndexSafety(); + }); + + test('sets and returns the pack maximum objects', () { + final oldValue = Libgit2.packMaxObjects; + Libgit2.packMaxObjects = 69; + expect(Libgit2.packMaxObjects, isNot(oldValue)); + + // Reset to avoid side effects in later tests + Libgit2.packMaxObjects = oldValue; + }); + + test('disables and enables check for unsaved changes in index', () { + expect(() => Libgit2.disablePackKeepFileChecks(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enablePackKeepFileChecks(); + }); + + test( + 'disables and enables check for unsaved changes in index', + testOn: '!windows', + () { + expect(() => Libgit2.disableHttpExpectContinue(), returnsNormally); + + // Reset to avoid side effects in later tests + Libgit2.enableHttpExpectContinue(); + }, + ); + + test('sets and returns the list of git extensions', () { + Libgit2.extensions = ['newext', 'anotherext']; + expect(Libgit2.extensions, ['noop', 'newext', 'anotherext']); + + // Reset to avoid side effects in later tests + Libgit2.extensions = ['!newext', '!anotherext']; + }); }); }