feat(submodule): add bindings and api

This commit is contained in:
Aleksey Kulikov 2021-10-08 17:34:59 +03:00
parent 5be0d0a6b5
commit 1d47b06955
37 changed files with 1893 additions and 0 deletions

View file

@ -0,0 +1,465 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import '../callbacks.dart';
import 'libgit2_bindings.dart';
import '../error.dart';
import '../util.dart';
import 'remote_callbacks.dart';
/// List of submodule paths.
///
/// IMPORTANT: make sure to clear that list since it's a global variable.
List<String> _pathsList = [];
/// Function to be called with the name of each submodule.
int _listCb(
Pointer<git_submodule> submodule,
Pointer<Int8> name,
Pointer<Void> payload,
) {
_pathsList.add(path(submodule));
return 0;
}
/// Returns a list with all tracked submodules paths of a repository.
///
/// Throws a [LibGit2Error] if error occured.
List<String> list(Pointer<git_repository> repo) {
const except = -1;
final callback = Pointer.fromFunction<
Int32 Function(Pointer<git_submodule>, Pointer<Int8>, Pointer<Void>)>(
_listCb, except);
final error = libgit2.git_submodule_foreach(repo, callback, nullptr);
if (error < 0) {
_pathsList.clear();
throw LibGit2Error(libgit2.git_error_last());
} else {
final result = _pathsList.toList(growable: false);
_pathsList.clear();
return result;
}
}
/// Lookup submodule information by name or path.
///
/// Given either the submodule name or path (they are usually the same), this
/// returns a structure describing the submodule.
///
/// You must call [free] when done with the submodule.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_submodule> lookup({
required Pointer<git_repository> repoPointer,
required String name,
}) {
final out = calloc<Pointer<git_submodule>>();
final nameC = name.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_lookup(out, repoPointer, nameC);
calloc.free(nameC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Copy submodule info into ".git/config" file.
///
/// Just like `git submodule init`, this copies information about the
/// submodule into `.git/config`.
///
/// By default, existing entries will not be overwritten, but setting [overwrite]
/// to true forces them to be updated.
///
/// Throws a [LibGit2Error] if error occured.
void init({
required Pointer<git_submodule> submodulePointer,
bool overwrite = false,
}) {
final overwriteC = overwrite ? 1 : 0;
final error = libgit2.git_submodule_init(submodulePointer, overwriteC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Update a submodule. This will clone a missing submodule and checkout the
/// subrepository to the commit specified in the index of the containing repository.
/// If the submodule repository doesn't contain the target commit (e.g. because
/// fetchRecurseSubmodules isn't set), then the submodule is fetched using the fetch
/// options supplied in [callbacks].
///
/// If the submodule is not initialized, setting [init] to true will initialize the
/// submodule before updating. Otherwise, this will return an error if attempting
/// to update an uninitialzed repository.
///
/// Throws a [LibGit2Error] if error occured.
void update({
required Pointer<git_submodule> submodulePointer,
bool init = false,
required Callbacks callbacks,
}) {
final initC = init ? 1 : 0;
final options = calloc<git_submodule_update_options>();
final optionsError = libgit2.git_submodule_update_options_init(
options,
GIT_SUBMODULE_UPDATE_OPTIONS_VERSION,
);
if (optionsError < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
RemoteCallbacks.plug(
callbacksOptions: options.ref.fetch_opts.callbacks,
callbacks: callbacks,
);
final error = libgit2.git_submodule_update(submodulePointer, initC, options);
calloc.free(options);
RemoteCallbacks.reset();
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Open the repository for a submodule.
///
/// This is a newly opened repository object. The caller is responsible for calling
/// `free()` on it when done. Multiple calls to this function will return distinct
/// git repository objects. This will only work if the submodule is checked out into
/// the working directory.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_repository> open(Pointer<git_submodule> submodule) {
final out = calloc<Pointer<git_repository>>();
final error = libgit2.git_submodule_open(out, submodule);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Set up a new git submodule for checkout.
///
/// This does `git submodule add` up to the fetch and checkout of the submodule contents.
/// It preps a new submodule, creates an entry in `.gitmodules` and creates an empty
/// initialized repository either at the given path in the working directory or in
/// `.git/modules` with a gitlink from the working directory to the new repo.
///
/// Throws a [LibGit2Error] if error occured.
Pointer<git_submodule> addSetup({
required Pointer<git_repository> repoPointer,
required String url,
required String path,
bool useGitlink = true,
}) {
final out = calloc<Pointer<git_submodule>>();
final urlC = url.toNativeUtf8().cast<Int8>();
final pathC = path.toNativeUtf8().cast<Int8>();
final useGitlinkC = useGitlink ? 1 : 0;
final error = libgit2.git_submodule_add_setup(
out,
repoPointer,
urlC,
pathC,
useGitlinkC,
);
calloc.free(urlC);
calloc.free(pathC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Perform the clone step for a newly created submodule.
///
/// Throws a [LibGit2Error] if error occured.
void clone({
required Pointer<git_submodule> submodule,
required Callbacks callbacks,
}) {
final out = calloc<Pointer<git_repository>>();
final options = calloc<git_submodule_update_options>();
final optionsError = libgit2.git_submodule_update_options_init(
options,
GIT_SUBMODULE_UPDATE_OPTIONS_VERSION,
);
if (optionsError < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
RemoteCallbacks.plug(
callbacksOptions: options.ref.fetch_opts.callbacks,
callbacks: callbacks,
);
final error = libgit2.git_submodule_clone(out, submodule, options);
calloc.free(options);
calloc.free(out);
RemoteCallbacks.reset();
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Resolve the setup of a new git submodule.
///
/// This should be called on a submodule once you have called add setup and done
/// the clone of the submodule. This adds the `.gitmodules` file and the newly
/// cloned submodule to the index to be ready to be committed (but doesn't actually
/// do the commit).
///
/// Throws a [LibGit2Error] if error occured.
void addFinalize(Pointer<git_submodule> submodule) {
final error = libgit2.git_submodule_add_finalize(submodule);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the status for a submodule.
///
/// This looks at a submodule and tries to determine the status. How deeply it examines
/// the working directory to do this will depend on the [ignore] value.
///
/// Throws a [LibGit2Error] if error occured.
int status({
required Pointer<git_repository> repoPointer,
required String name,
required int ignore,
}) {
final out = calloc<Uint32>();
final nameC = name.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_status(out, repoPointer, nameC, ignore);
calloc.free(nameC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
} else {
return out.value;
}
}
/// Copy submodule remote info into submodule repo.
///
/// This copies the information about the submodules URL into the checked out submodule
/// config, acting like `git submodule sync`. This is useful if you have altered the URL
/// for the submodule (or it has been altered by a fetch of upstream changes) and you
/// need to update your local repo.
///
/// Throws a [LibGit2Error] if error occured.
void sync(Pointer<git_submodule> submodule) {
final error = libgit2.git_submodule_sync(submodule);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Reread submodule info from config, index, and HEAD.
///
/// Call this to reread cached submodule information for this submodule if you have
/// reason to believe that it has changed.
///
/// Set [force] to true to reload even if the data doesn't seem out of date.
void reload({
required Pointer<git_submodule> submodulePointer,
bool force = false,
}) {
final forceC = force ? 1 : 0;
final error = libgit2.git_submodule_reload(submodulePointer, forceC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the name of submodule.
String name(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_name(submodule);
return result.cast<Utf8>().toDartString();
}
/// Get the path to the submodule.
///
/// The path is almost always the same as the submodule name, but the two
/// are actually not required to match.
String path(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_path(submodule);
return result.cast<Utf8>().toDartString();
}
/// Get the URL for the submodule.
String url(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_url(submodule);
return result.cast<Utf8>().toDartString();
}
/// Set the URL for the submodule in the configuration.
///
/// After calling this, you may wish to call [sync] to write the changes to
/// the checked out submodule repository.
///
/// Throws a [LibGit2Error] if error occured.
void setUrl({
required Pointer<git_repository> repoPointer,
required String name,
required String url,
}) {
final nameC = name.toNativeUtf8().cast<Int8>();
final urlC = url.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_set_url(repoPointer, nameC, urlC);
calloc.free(nameC);
calloc.free(urlC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the branch for the submodule.
String branch(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_branch(submodule);
return result == nullptr ? '' : result.cast<Utf8>().toDartString();
}
/// Set the branch for the submodule in the configuration.
///
/// After calling this, you may wish to call [sync] to write the changes to
/// the checked out submodule repository.
///
/// Throws a [LibGit2Error] if error occured.
void setBranch({
required Pointer<git_repository> repoPointer,
required String name,
required String branch,
}) {
final nameC = name.toNativeUtf8().cast<Int8>();
final branchC = branch.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_set_branch(repoPointer, nameC, branchC);
calloc.free(nameC);
calloc.free(branchC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the OID for the submodule in the current HEAD tree.
///
/// Returns null if submodule is not in the HEAD.
Pointer<git_oid>? headId(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_head_id(submodule);
return result == nullptr ? null : result;
}
/// Get the OID for the submodule in the index.
///
/// Returns null if submodule is not in index.
Pointer<git_oid>? indexId(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_index_id(submodule);
return result == nullptr ? null : result;
}
/// Get the OID for the submodule in the current working directory.
///
/// This returns the OID that corresponds to looking up `HEAD` in the checked out
/// submodule. If there are pending changes in the index or anything else, this
/// won't notice that. You should call [status] for a more complete picture about
/// the state of the working directory.
///
/// Returns null if submodule is not checked out.
Pointer<git_oid>? workdirId(Pointer<git_submodule> submodule) {
final result = libgit2.git_submodule_wd_id(submodule);
return result == nullptr ? null : result;
}
/// Get the ignore rule that will be used for the submodule.
int ignore(Pointer<git_submodule> submodule) {
return libgit2.git_submodule_ignore(submodule);
}
/// Set the ignore rule for the submodule in the configuration.
///
/// This does not affect any currently-loaded instances.
///
/// Throws a [LibGit2Error] if error occured.
void setIgnore({
required Pointer<git_repository> repoPointer,
required String name,
required int ignore,
}) {
final nameC = name.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_set_ignore(repoPointer, nameC, ignore);
calloc.free(nameC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the update rule that will be used for the submodule.
///
/// This value controls the behavior of the `git submodule update` command.
int updateRule(Pointer<git_submodule> submodule) {
return libgit2.git_submodule_update_strategy(submodule);
}
/// Set the update rule for the submodule in the configuration.
///
/// This setting won't affect any existing instances.
///
/// Throws a [LibGit2Error] if error occured.
void setUpdateRule({
required Pointer<git_repository> repoPointer,
required String name,
required int update,
}) {
final nameC = name.toNativeUtf8().cast<Int8>();
final error = libgit2.git_submodule_set_update(repoPointer, nameC, update);
calloc.free(nameC);
if (error < 0) {
throw LibGit2Error(libgit2.git_error_last());
}
}
/// Get the containing repository for a submodule.
///
/// This returns a pointer to the repository that contains the submodule.
/// This is a just a reference to the repository that was passed to the original
/// [lookup] call, so if that repository has been freed, then this may be a dangling
/// reference.
Pointer<git_repository> owner(Pointer<git_submodule> submodule) {
return libgit2.git_submodule_owner(submodule);
}
/// Release a submodule.
void free(Pointer<git_submodule> submodule) =>
libgit2.git_submodule_free(submodule);

View file

@ -1525,3 +1525,176 @@ class GitDescribeStrategy {
@override
String toString() => 'GitDescribeStrategy.$_name';
}
/// Submodule ignore values.
///
/// These values represent settings for the `submodule.$name.ignore`
/// configuration value which says how deeply to look at the working
/// directory when getting submodule status.
class GitSubmoduleIgnore {
const GitSubmoduleIgnore._(this._value, this._name);
final int _value;
final String _name;
// Use the submodule's configuration.
static const unspecified = GitSubmoduleIgnore._(-1, 'unspecified');
/// Don't ignore any change - i.e. even an untracked file, will mark the
/// submodule as dirty. Ignored files are still ignored, of course.
static const none = GitSubmoduleIgnore._(1, 'none');
/// Ignore untracked files; only changes to tracked files, or the index or
/// the HEAD commit will matter.
static const untracked = GitSubmoduleIgnore._(2, 'untracked');
/// Ignore changes in the working directory, only considering changes if
/// the HEAD of submodule has moved from the value in the superproject.
static const dirty = GitSubmoduleIgnore._(3, 'dirty');
/// Never check if the submodule is dirty.
static const all = GitSubmoduleIgnore._(4, 'all');
static const List<GitSubmoduleIgnore> values = [
unspecified,
none,
untracked,
dirty,
all,
];
int get value => _value;
@override
String toString() => 'GitSubmoduleIgnore.$_name';
}
/// Submodule update values
///
/// These values represent settings for the `submodule.$name.update`
/// configuration value which says how to handle `git submodule update` for
/// this submodule. The value is usually set in the `.gitmodules` file and
/// copied to `.git/config` when the submodule is initialized.
class GitSubmoduleUpdate {
const GitSubmoduleUpdate._(this._value, this._name);
final int _value;
final String _name;
/// The default; when a submodule is updated, checkout the new detached HEAD
/// to the submodule directory.
static const checkout = GitSubmoduleUpdate._(1, 'checkout');
/// Update by rebasing the current checked out branch onto the commit from
/// the superproject.
static const rebase = GitSubmoduleUpdate._(2, 'rebase');
/// Update by merging the commit in the superproject into the current checkout
/// out branch of the submodule.
static const merge = GitSubmoduleUpdate._(3, 'merge');
/// Do not update this submodule even when the commit in the superproject is updated.
static const none = GitSubmoduleUpdate._(4, 'none');
static const List<GitSubmoduleUpdate> values = [
checkout,
rebase,
merge,
none,
];
int get value => _value;
@override
String toString() => 'GitSubmoduleUpdate.$_name';
}
/// A combination of these flags will be returned to describe the status of a
/// submodule. Depending on the "ignore" property of the submodule, some of
/// the flags may never be returned because they indicate changes that are
/// supposed to be ignored.
///
/// Submodule info is contained in 4 places: the HEAD tree, the index, config
/// files (both .git/config and .gitmodules), and the working directory. Any
/// or all of those places might be missing information about the submodule
/// depending on what state the repo is in. We consider all four places to
/// build the combination of status flags.
class GitSubmoduleStatus {
const GitSubmoduleStatus._(this._value, this._name);
final int _value;
final String _name;
/// Superproject head contains submodule.
static const inHead = GitSubmoduleStatus._(1, 'inHead');
/// Superproject index contains submodule.
static const inIndex = GitSubmoduleStatus._(2, 'inIndex');
/// Superproject gitmodules has submodule.
static const inConfig = GitSubmoduleStatus._(4, 'inConfig');
/// Superproject workdir has submodule.
static const inWorkdir = GitSubmoduleStatus._(8, 'inWorkdir');
/// In index, not in head.
static const indexAdded = GitSubmoduleStatus._(16, 'indexAdded');
/// In head, not in index.
static const indexDeleted = GitSubmoduleStatus._(32, 'indexDeleted');
/// Index and head don't match.
static const indexModified = GitSubmoduleStatus._(64, 'indexModified');
/// Workdir contains empty directory.
static const workdirUninitialized = GitSubmoduleStatus._(
128,
'workdirUninitialized',
);
/// In workdir, not index.
static const workdirAdded = GitSubmoduleStatus._(256, 'workdirAdded');
/// In index, not workdir.
static const workdirDeleted = GitSubmoduleStatus._(512, 'workdirDeleted');
/// Index and workdir head don't match.
static const workdirModified = GitSubmoduleStatus._(1024, 'workdirModified');
/// Submodule workdir index is dirty.
static const workdirIndexModified = GitSubmoduleStatus._(
2048,
'workdirIndexModified',
);
/// Submodule workdir has modified files.
static const smWorkdirModified = GitSubmoduleStatus._(
4096,
'smWorkdirModified',
);
/// Workdir contains untracked files.
static const workdirUntracked = GitSubmoduleStatus._(
8192,
'workdirUntracked',
);
static const List<GitSubmoduleStatus> values = [
inHead,
inIndex,
inConfig,
inWorkdir,
indexAdded,
indexDeleted,
indexModified,
workdirUninitialized,
workdirAdded,
workdirDeleted,
workdirModified,
workdirIndexModified,
smWorkdirModified,
workdirUntracked,
];
int get value => _value;
@override
String toString() => 'GitSubmoduleStatus.$_name';
}

View file

@ -1333,4 +1333,83 @@ class Repository {
return result;
}
/// Returns a list with all tracked submodules paths of a repository.
///
/// Throws a [LibGit2Error] if error occured.
List<String> get submodules => Submodule.list(this);
/// Lookups submodule by name or path.
///
/// You must free submodule when done with it.
///
/// Throws a [LibGit2Error] if error occured.
Submodule lookupSubmodule(String submodule) {
return Submodule.lookup(repo: this, submodule: submodule);
}
/// Copies submodule info into ".git/config" file.
///
/// Just like `git submodule init`, this copies information about the
/// submodule into `.git/config`.
///
/// By default, existing entries will not be overwritten, but setting [overwrite]
/// to true forces them to be updated.
///
/// Throws a [LibGit2Error] if error occured.
void initSubmodule({
required String submodule,
bool overwrite = false,
}) {
Submodule.init(repo: this, submodule: submodule, overwrite: overwrite);
}
/// Updates a submodule. This will clone a missing submodule and checkout the
/// subrepository to the commit specified in the index of the containing repository.
/// If the submodule repository doesn't contain the target commit (e.g. because
/// fetchRecurseSubmodules isn't set), then the submodule is fetched using the fetch
/// options supplied in [callbacks].
///
/// If the submodule is not initialized, setting [init] to true will initialize the
/// submodule before updating. Otherwise, this will return an error if attempting
/// to update an uninitialzed repository.
///
/// Throws a [LibGit2Error] if error occured.
void updateSubmodule({
required String submodule,
bool init = false,
Callbacks callbacks = const Callbacks(),
}) {
Submodule.update(
repo: this,
submodule: submodule,
init: init,
callbacks: callbacks,
);
}
/// Adds a submodule to the index.
///
/// [url] is URL for the submodule's remote.
///
/// [path] is path at which the submodule should be created.
///
/// [link] determines if workdir should contain a gitlink to the repo in `.git/modules`
/// vs. repo directly in workdir. Default is true.
///
/// Throws a [LibGit2Error] if error occured.
Submodule addSubmodule({
required String url,
required String path,
bool useGitlink = true,
Callbacks callbacks = const Callbacks(),
}) {
return Submodule.add(
repo: this,
url: url,
path: path,
useGitlink: useGitlink,
callbacks: callbacks,
);
}
}

297
lib/src/submodule.dart Normal file
View file

@ -0,0 +1,297 @@
import 'dart:ffi';
import 'package:libgit2dart/libgit2dart.dart';
import 'bindings/libgit2_bindings.dart';
import 'bindings/submodule.dart' as bindings;
class Submodule {
/// Initializes a new instance of [Submodule] class from provided
/// pointer to submodule object in memory.
Submodule(this._submodulePointer);
/// Initializes a new instance of [Submodule] class by looking up
/// submodule information by name or path.
///
/// Given either the submodule name or path (they are usually the same), this
/// returns a structure describing the submodule.
///
/// You must call [free] when done with the submodule.
///
/// Throws a [LibGit2Error] if error occured.
Submodule.lookup({required Repository repo, required String submodule}) {
_submodulePointer = bindings.lookup(
repoPointer: repo.pointer,
name: submodule,
);
}
/// Adds a submodule to the index.
///
/// [url] is URL for the submodule's remote.
///
/// [path] is path at which the submodule should be created.
///
/// [link] determines if workdir should contain a gitlink to the repo in `.git/modules`
/// vs. repo directly in workdir. Default is true.
///
/// Throws a [LibGit2Error] if error occured.
Submodule.add({
required Repository repo,
required String url,
required String path,
bool useGitlink = true,
Callbacks callbacks = const Callbacks(),
}) {
_submodulePointer = bindings.addSetup(
repoPointer: repo.pointer,
url: url,
path: path,
useGitlink: useGitlink,
);
bindings.clone(submodule: _submodulePointer, callbacks: callbacks);
bindings.addFinalize(_submodulePointer);
}
late final Pointer<git_submodule> _submodulePointer;
/// Pointer to memory address for allocated submodule object.
Pointer<git_submodule> get pointer => _submodulePointer;
/// Copies submodule info into ".git/config" file.
///
/// Just like `git submodule init`, this copies information about the
/// submodule into `.git/config`.
///
/// By default, existing entries will not be overwritten, but setting [overwrite]
/// to true forces them to be updated.
///
/// Throws a [LibGit2Error] if error occured.
static void init({
required Repository repo,
required String submodule,
bool overwrite = false,
}) {
final submodulePointer = bindings.lookup(
repoPointer: repo.pointer,
name: submodule,
);
bindings.init(submodulePointer: submodulePointer, overwrite: overwrite);
bindings.free(submodulePointer);
}
/// Updates a submodule. This will clone a missing submodule and checkout the
/// subrepository to the commit specified in the index of the containing repository.
/// If the submodule repository doesn't contain the target commit (e.g. because
/// fetchRecurseSubmodules isn't set), then the submodule is fetched using the fetch
/// options supplied in [callbacks].
///
/// If the submodule is not initialized, setting [init] to true will initialize the
/// submodule before updating. Otherwise, this will return an error if attempting
/// to update an uninitialzed repository.
///
/// Throws a [LibGit2Error] if error occured.
static void update({
required Repository repo,
required String submodule,
bool init = false,
Callbacks callbacks = const Callbacks(),
}) {
final submodulePointer = bindings.lookup(
repoPointer: repo.pointer,
name: submodule,
);
bindings.update(
submodulePointer: submodulePointer,
init: init,
callbacks: callbacks,
);
bindings.free(submodulePointer);
}
/// Returns a list with all tracked submodules paths of a repository.
///
/// Throws a [LibGit2Error] if error occured.
static List<String> list(Repository repo) => bindings.list(repo.pointer);
/// Opens the repository for a submodule.
///
/// This is a newly opened repository object. The caller is responsible for calling
/// `free()` on it when done. Multiple calls to this function will return distinct
/// git repository objects. This will only work if the submodule is checked out into
/// the working directory.
///
/// Throws a [LibGit2Error] if error occured.
Repository open() {
return Repository(bindings.open(_submodulePointer));
}
/// Returns the status for a submodule.
///
/// This looks at a submodule and tries to determine the status. How deeply it examines
/// the working directory to do this will depend on the combination of [GitSubmoduleIgnore]
/// values provided to [ignore] .
///
/// Throws a [LibGit2Error] if error occured.
Set<GitSubmoduleStatus> status({
GitSubmoduleIgnore ignore = GitSubmoduleIgnore.unspecified,
}) {
final repo = bindings.owner(_submodulePointer);
final resultInt = bindings.status(
repoPointer: repo,
name: name,
ignore: ignore.value,
);
var result = <GitSubmoduleStatus>{};
for (var status in GitSubmoduleStatus.values) {
if (resultInt & status.value == status.value) {
result.add(status);
}
}
return result;
}
/// Copies submodule remote info into submodule repo.
///
/// This copies the information about the submodules URL into the checked out submodule
/// config, acting like `git submodule sync`. This is useful if you have altered the URL
/// for the submodule (or it has been altered by a fetch of upstream changes) and you
/// need to update your local repo.
///
/// Throws a [LibGit2Error] if error occured.
void sync() => bindings.sync(_submodulePointer);
/// Rereads submodule info from config, index, and HEAD.
///
/// Call this to reread cached submodule information for this submodule if you have
/// reason to believe that it has changed.
///
/// Set [force] to true to reload even if the data doesn't seem out of date.
void reload({bool force = false}) {
bindings.reload(submodulePointer: _submodulePointer, force: force);
}
/// Returns the name of submodule.
String get name => bindings.name(_submodulePointer);
/// Returns the path to the submodule.
///
/// The path is almost always the same as the submodule name, but the two
/// are actually not required to match.
String get path => bindings.path(_submodulePointer);
/// Returns the URL for the submodule.
String get url => bindings.url(_submodulePointer);
/// Sets the URL for the submodule in the configuration.
///
/// After calling this, you may wish to call [sync] to write the changes to
/// the checked out submodule repository.
///
/// Throws a [LibGit2Error] if error occured.
set url(String url) {
final repo = bindings.owner(_submodulePointer);
bindings.setUrl(repoPointer: repo, name: name, url: url);
}
/// Returns the branch for the submodule.
String get branch => bindings.branch(_submodulePointer);
/// Sets the branch for the submodule in the configuration.
///
/// After calling this, you may wish to call [sync] to write the changes to
/// the checked out submodule repository.
///
/// Throws a [LibGit2Error] if error occured.
set branch(String branch) {
final repo = bindings.owner(_submodulePointer);
bindings.setBranch(repoPointer: repo, name: name, branch: branch);
}
/// Returns the [Oid] for the submodule in the current HEAD tree or
/// null if submodule is not in the HEAD.
Oid? get headId {
final result = bindings.headId(_submodulePointer);
return result == null ? null : Oid(result);
}
/// Returns the [Oid] for the submodule in the index or null if submodule
/// is not in the index.
Oid? get indexId {
final result = bindings.indexId(_submodulePointer);
return result == null ? null : Oid(result);
}
/// Returns the OID for the submodule in the current working directory or null if
/// submodule is not checked out.
///
/// This returns the OID that corresponds to looking up `HEAD` in the checked out
/// submodule. If there are pending changes in the index or anything else, this
/// won't notice that. You should call [status] for a more complete picture about
/// the state of the working directory.
Oid? get workdirId {
final result = bindings.workdirId(_submodulePointer);
return result == null ? null : Oid(result);
}
/// Returns the ignore rule that will be used for the submodule.
GitSubmoduleIgnore get ignore {
late GitSubmoduleIgnore result;
final ruleInt = bindings.ignore(_submodulePointer);
for (var rule in GitSubmoduleIgnore.values) {
if (ruleInt == rule.value) {
result = rule;
break;
}
}
return result;
}
/// Sets the ignore rule for the submodule in the configuration.
///
/// This does not affect any currently-loaded instances.
///
/// Throws a [LibGit2Error] if error occured.
set ignore(GitSubmoduleIgnore ignore) {
final repo = bindings.owner(_submodulePointer);
bindings.setIgnore(repoPointer: repo, name: name, ignore: ignore.value);
}
/// Returns the update rule that will be used for the submodule.
///
/// This value controls the behavior of the `git submodule update` command.
GitSubmoduleUpdate get updateRule {
late GitSubmoduleUpdate result;
final ruleInt = bindings.updateRule(_submodulePointer);
for (var rule in GitSubmoduleUpdate.values) {
if (ruleInt == rule.value) {
result = rule;
break;
}
}
return result;
}
/// Sets the update rule for the submodule in the configuration.
///
/// This setting won't affect any existing instances.
///
/// Throws a [LibGit2Error] if error occured.
set updateRule(GitSubmoduleUpdate rule) {
final repo = bindings.owner(_submodulePointer);
bindings.setUpdateRule(repoPointer: repo, name: name, update: rule.value);
}
/// Releases memory allocated for submodule object.
void free() => bindings.free(_submodulePointer);
}