/* * The MIT License * * Copyright (c) 2014 GitHub, Inc * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "rugged.h" extern VALUE rb_mRugged; VALUE rb_cRuggedSubmodule; static VALUE id_in_head, id_in_index, id_in_config, id_in_workdir; static VALUE id_index_added, id_index_deleted, id_index_modified; static VALUE id_wd_uninitialized, id_wd_added, id_wd_deleted, id_wd_modified; static VALUE id_wd_index_modified, id_wd_wd_modified, id_wd_untracked; static ID id_ignore_none, id_ignore_untracked, id_ignore_dirty, id_ignore_all; static ID id_update_checkout, id_update_rebase, id_update_merge, id_update_none; void init_status_list(void) { id_in_head = CSTR2SYM("in_head"); id_in_index = CSTR2SYM("in_index"); id_in_config = CSTR2SYM("in_config"); id_in_workdir = CSTR2SYM("in_workdir"); id_index_added = CSTR2SYM("added_to_index"); id_index_deleted = CSTR2SYM("deleted_from_index"); id_index_modified = CSTR2SYM("modified_in_index"); id_wd_uninitialized = CSTR2SYM("uninitialized"); id_wd_added = CSTR2SYM("added_to_workdir"); id_wd_deleted = CSTR2SYM("deleted_from_workdir"); id_wd_modified = CSTR2SYM("modified_in_workdir"); id_wd_index_modified = CSTR2SYM("dirty_workdir_index"); id_wd_wd_modified = CSTR2SYM("modified_files_in_workdir"); id_wd_untracked = CSTR2SYM("untracked_files_in_workdir"); return; } static VALUE submodule_status_flags_to_rb(unsigned int flags) { VALUE rb_flags = rb_ary_new(); if (flags & GIT_SUBMODULE_STATUS_IN_HEAD) rb_ary_push(rb_flags, id_in_head); if (flags & GIT_SUBMODULE_STATUS_IN_INDEX) rb_ary_push(rb_flags, id_in_index); if (flags & GIT_SUBMODULE_STATUS_IN_CONFIG) rb_ary_push(rb_flags, id_in_config); if (flags & GIT_SUBMODULE_STATUS_IN_WD) rb_ary_push(rb_flags, id_in_workdir); if (flags & GIT_SUBMODULE_STATUS_INDEX_ADDED) rb_ary_push(rb_flags, id_index_added); if (flags & GIT_SUBMODULE_STATUS_INDEX_DELETED) rb_ary_push(rb_flags, id_index_deleted); if (flags & GIT_SUBMODULE_STATUS_INDEX_MODIFIED) rb_ary_push(rb_flags, id_index_modified); if (flags & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) rb_ary_push(rb_flags, id_wd_uninitialized); if (flags & GIT_SUBMODULE_STATUS_WD_ADDED) rb_ary_push(rb_flags, id_wd_added); if (flags & GIT_SUBMODULE_STATUS_WD_DELETED) rb_ary_push(rb_flags, id_wd_deleted); if (flags & GIT_SUBMODULE_STATUS_WD_MODIFIED) rb_ary_push(rb_flags, id_wd_modified); if (flags & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) rb_ary_push(rb_flags, id_wd_index_modified); if (flags & GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) rb_ary_push(rb_flags, id_wd_wd_modified); if (flags & GIT_SUBMODULE_STATUS_WD_UNTRACKED) rb_ary_push(rb_flags, id_wd_untracked); return rb_flags; } /* * call-seq: * submodule.status -> array * * Returns an +array+ with the status flags for a submodule. * * Depending on the #ignore_rule 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 repository is in. We consider * all four places to build the combination of status flags. * * There are four values that are not really status, but give basic info * about what sources of submodule data are available. These will be * returned even if ignore is set to +:all+. * * :in_head :: * superproject +HEAD+ contains submodule * :in_index :: * superproject index contains submodule * :in_config :: * superproject +.gitmodules+ has submodule * :in_workdir :: * superproject workdir has submodule * * The following values will be returned as long as ignore is not +:all+. * * :added_to_index :: * submodule is in index, not in +HEAD+ * :deleted_from_index :: * submodule is in +HEAD+, not in index * :modified_in_index :: * submodule in index and +HEAD+ don't match * :uninitialized :: * submodule in workdir is not initialized * :added_to_workdir :: * submodule is in workdir, not index * :deleted_from_workdir :: * submodule is in index, not workdir * :modified_in_workdir :: * submodule in index and workdir +HEAD+ don't match * * The following can only be returned if ignore is +:none+ or +:untracked+. * * :dirty_workdir_index :: * submodule workdir index is dirty * :modified_files_in_workdir :: * submodule workdir has modified files * * Lastly, the following will only be returned for ignore +:none+. * * :untracked_files_in_workdir :: * submodule workdir contains untracked files */ static VALUE rb_git_submodule_status(VALUE self) { git_submodule *submodule; unsigned int flags; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_status(&flags, submodule) ); return submodule_status_flags_to_rb(flags); } #define RB_GIT_SUBMODULE_LOCATION_FLAG_CHECK(flag) \ git_submodule *submodule; \ unsigned int flags; \ Data_Get_Struct(self, git_submodule, submodule); \ rugged_exception_check( \ git_submodule_location(&flags, submodule) \ ); \ return (flags & flag) ? Qtrue : Qfalse; \ /* * call-seq: * submodule.in_head? -> true or false * * Returns +true+ if superproject +HEAD+ contains submodule. */ static VALUE rb_git_submodule_status_in_head(VALUE self) { RB_GIT_SUBMODULE_LOCATION_FLAG_CHECK(GIT_SUBMODULE_STATUS_IN_HEAD) } /* * call-seq: * submodule.in_index? -> true or false * * Returns +true+ if superproject index contains submodule. */ static VALUE rb_git_submodule_status_in_index(VALUE self) { RB_GIT_SUBMODULE_LOCATION_FLAG_CHECK(GIT_SUBMODULE_STATUS_IN_INDEX) } /* * call-seq: * submodule.in_config? -> true or false * * Returns +true+ if superproject +.gitmodules+ has submodule. */ static VALUE rb_git_submodule_status_in_config(VALUE self) { RB_GIT_SUBMODULE_LOCATION_FLAG_CHECK(GIT_SUBMODULE_STATUS_IN_CONFIG) } /* * call-seq: * submodule.in_workdir? -> true or false * * Returns +true+ if superproject workdir has submodule. */ static VALUE rb_git_submodule_status_in_workdir(VALUE self) { RB_GIT_SUBMODULE_LOCATION_FLAG_CHECK(GIT_SUBMODULE_STATUS_IN_WD) } #define RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(flag) \ git_submodule *submodule; \ unsigned int flags; \ Data_Get_Struct(self, git_submodule, submodule); \ rugged_exception_check( \ git_submodule_status(&flags, submodule) \ ); \ return (flags & flag) ? Qtrue : Qfalse; \ /* * call-seq: * submodule.added_to_index? -> true or false * * Returns +true+ if submodule is in index, not in +HEAD+. */ static VALUE rb_git_submodule_status_added_to_index(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_INDEX_ADDED) } /* * call-seq: * submodule.deleted_from_index? -> true or false * * Returns +true+ if submodule is in +HEAD+, not in index */ static VALUE rb_git_submodule_status_deleted_from_index(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_INDEX_DELETED) } /* * call-seq: * submodule.modified_in_index? -> true or false * * Returns +true+ if submodule in index and +HEAD+ don't match. */ static VALUE rb_git_submodule_status_modified_in_index(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_INDEX_MODIFIED) } /* * call-seq: * submodule.uninitialized? -> true or false * * Returns +true+ if submodule in workdir is not initialized. */ static VALUE rb_git_submodule_status_uninitialized(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) } /* * call-seq: * submodule.added_to_workdir? -> true or false * * Returns +true+ if submodule is in workdir, not index. */ static VALUE rb_git_submodule_status_added_to_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_ADDED) } /* * call-seq: * submodule.deleted_from_workdir? -> true or false * * Returns +true+ if submodule is in index, not workdir. */ static VALUE rb_git_submodule_status_deleted_from_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_DELETED) } /* * call-seq: * submodule.modified_in_workdir? -> true or false * * Returns +true+ if submodule in index and workdir +HEAD+ don't match. */ static VALUE rb_git_submodule_status_modified_in_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_MODIFIED) } /* * call-seq: * submodule.dirty_workdir_index? -> true or false * * Returns +true+ if submodule workdir index is dirty. */ static VALUE rb_git_submodule_status_dirty_workdir_index(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED) } /* * call-seq: * submodule.modified_files_in_workdir? -> true or false * * Returns +true+ if submodule workdir has modified files. */ static VALUE rb_git_submodule_status_modified_files_in_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_WD_MODIFIED) } /* * call-seq: * submodule.untracked_files_in_workdir? -> true or false * * Returns +true+ if submodule workdir contains untracked files. */ static VALUE rb_git_submodule_status_untracked_files_in_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_FLAG_CHECK(GIT_SUBMODULE_STATUS_WD_UNTRACKED) } #define RB_GIT_SUBMODULE_STATUS_CHECK(check) \ git_submodule *submodule; \ unsigned int flags; \ Data_Get_Struct(self, git_submodule, submodule); \ rugged_exception_check( \ git_submodule_status(&flags, submodule) \ ); \ return check(flags) ? Qtrue : Qfalse; \ /* * call-seq: * submodule.unmodified? -> true or false * * Returns +true+ if the submodule is unmodified. */ static VALUE rb_git_submodule_status_unmodified(VALUE self) { RB_GIT_SUBMODULE_STATUS_CHECK(GIT_SUBMODULE_STATUS_IS_UNMODIFIED) } /* * call-seq: * submodule.dirty_workdir? -> true or false * * Returns +true+ if the submodule workdir is dirty. * * The workdir is considered dirty if the workdir index is modified, there * are modified files in the workdir or if there are untracked files in the * workdir. */ static VALUE rb_git_submodule_status_dirty_workdir(VALUE self) { RB_GIT_SUBMODULE_STATUS_CHECK(GIT_SUBMODULE_STATUS_IS_WD_DIRTY) } /* * call-seq: * submodule.add_to_index([options]) -> submodule * * Add current submodule +HEAD+ commit to the index of superproject. * * The following options can be passed in the +options+ Hash: * * :write_index :: * (default +true+) If this should immediately write the index file. * If passed as +false+, Rugged::Repository#index can be used to explicitly * call Rugged::Index#write to save the change. */ static VALUE rb_git_submodule_add_to_index(int argc, VALUE *argv, VALUE self) { git_submodule *submodule; VALUE rb_options; int write_index = 1; Data_Get_Struct(self, git_submodule, submodule); rb_scan_args(argc, argv, ":", &rb_options); if (!NIL_P(rb_options)) { VALUE rb_val; rb_val = rb_hash_aref(rb_options, CSTR2SYM("write_index")); write_index = (rb_val != Qfalse); } rugged_exception_check( git_submodule_add_to_index(submodule, write_index) ); return self; } /* * call-seq: * submodule.reload -> submodule * * Reread submodule info from config, index, and +HEAD+. * * Call this to reread cached submodule information for this submodule if * there is reason to believe that it has changed. */ static VALUE rb_git_submodule_reload(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_reload(submodule, 1) ); return self; } /* * call-seq: * submodule.save -> submodule * * Write submodule settings to +.gitmodules+ file. * * This commits any in-memory changes to the submodule to the +.gitmodules+ * file on disk. */ static VALUE rb_git_submodule_save(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_save(submodule) ); return self; } /* * call-seq: * submodule.sync -> submodule * * Copy submodule remote info into submodule repository. * * This copies the information about the submodules URL into the checked out * submodule config, acting like "git submodule sync". This is useful * if the URL for the submodule was altered (by a manual change, or a fetch of * upstream changes) and the local repository needs to be updated. */ static VALUE rb_git_submodule_sync(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_sync(submodule) ); return self; } /* * call-seq: * submodule.init([options]) -> submodule * * Copy submodule info into +.git/config+ file. * * Just like "git submodule init", this copies information about the * submodule into +.git/config+. * * The following options can be passed in the +options+ Hash: * * :overwrite :: * (defaults to +false+) - By default, existing entries * will not be overwritten, but setting this to +true+ forces them to be * updated. */ static VALUE rb_git_submodule_init(int argc, VALUE *argv, VALUE self) { git_submodule *submodule; VALUE rb_options; int overwrite = 0; Data_Get_Struct(self, git_submodule, submodule); rb_scan_args(argc, argv, ":", &rb_options); if (!NIL_P(rb_options)) { VALUE rb_val; rb_val = rb_hash_aref(rb_options, CSTR2SYM("overwrite")); overwrite = RTEST(rb_val); } rugged_exception_check( git_submodule_init(submodule, overwrite) ); return self; } /* * call-seq: * submodule.name -> string * * Returns the name of the submodule. */ static VALUE rb_git_submodule_name(VALUE self) { git_submodule *submodule; const char *name; Data_Get_Struct(self, git_submodule, submodule); name = git_submodule_name(submodule); return rb_str_new_utf8(name); } /* * call-seq: * submodule.url -> string or nil * * Returns the URL of the submodule. */ static VALUE rb_git_submodule_url(VALUE self) { git_submodule *submodule; const char *url; Data_Get_Struct(self, git_submodule, submodule); url = git_submodule_url(submodule); return url ? rb_str_new_utf8(url) : Qnil; } /* * call-seq: * submodule.url = url -> url * * Set the URL in memory for the submodule. * * This will be used for any following submodule actions while this submodule * data is in memory. * * After calling this, #save can be called to write the changes back to * the +.gitmodules+ file and #sync to write the changes to the checked out * submodule repository. */ static VALUE rb_git_submodule_set_url(VALUE self, VALUE rb_url) { git_submodule *submodule; Check_Type(rb_url, T_STRING); Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_set_url(submodule, StringValueCStr(rb_url)) ); return rb_url; } /* * call-seq: * submodule.path -> string * * Returns the path of the submodule. * * The +path+ is almost always the same as the #name, * but the two are actually not required to match. */ static VALUE rb_git_submodule_path(VALUE self) { git_submodule *submodule; const char *path; Data_Get_Struct(self, git_submodule, submodule); path = git_submodule_path(submodule); return rb_str_new_utf8(path); } #define RB_GIT_OID_GETTER(_klass, _attribute) \ git_##_klass *object; \ const git_oid * oid; \ Data_Get_Struct(self, git_##_klass, object); \ oid = git_##_klass##_##_attribute(object); \ return oid ? rugged_create_oid(oid) : Qnil; \ /* * call-seq: * submodule.head_oid -> string or nil * * Returns the OID for the submodule in the current +HEAD+ tree or +nil+ * if the submodule is not in the +HEAD+. */ static VALUE rb_git_submodule_head_id(VALUE self) { RB_GIT_OID_GETTER(submodule, head_id); } /* * call-seq: * submodule.index_oid -> string or nil * * Returns the OID for the submodule in the index or +nil+ if the submodule * is not in the index. */ static VALUE rb_git_submodule_index_id(VALUE self) { RB_GIT_OID_GETTER(submodule, index_id); } /* * call-seq: * submodule.workdir_oid -> string or nil * * Returns the OID for the submodule in the current working directory or * +nil+ of the 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. #status can be called for a more complete * picture about the state of the working directory. */ static VALUE rb_git_submodule_wd_id(VALUE self) { RB_GIT_OID_GETTER(submodule, wd_id); } /* * call-seq: * submodule.fetch_recurse_submodules? -> true or false * * Returns the +fetchRecurseSubmodules+ rule for a submodule. * * This accesses the submodule..fetchRecurseSubmodules value * for the submodule that controls fetching behavior for the submodule. * * Note that at this time, +Rugged+ does not honor this setting and the fetch * functionality currently ignores submodules. * */ static VALUE rb_git_submodule_fetch_recurse_submodules(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); return git_submodule_fetch_recurse_submodules(submodule) ? Qtrue : Qfalse; } /* * call-seq: * submodule.fetch_recurse_submodules= bool -> bool * * Set the +fetchRecurseSubmodules+ rule in memory for a submodule. * * This sets the submodule..fetchRecurseSubmodules value for * the submodule. #save can be called to persist the new value. */ static VALUE rb_git_submodule_set_fetch_recurse_submodules(VALUE self, VALUE rb_fetch_recursive) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); git_submodule_set_fetch_recurse_submodules( submodule, rugged_parse_bool(rb_fetch_recursive) ); return rb_fetch_recursive; } static VALUE rb_git_subm_ignore_rule_fromC(git_submodule_ignore_t rule) { switch(rule) { case GIT_SUBMODULE_IGNORE_NONE: return ID2SYM(id_ignore_none); case GIT_SUBMODULE_IGNORE_UNTRACKED: return ID2SYM(id_ignore_untracked); case GIT_SUBMODULE_IGNORE_DIRTY: return ID2SYM(id_ignore_dirty); case GIT_SUBMODULE_IGNORE_ALL: return ID2SYM(id_ignore_all); default: return CSTR2SYM("unknown"); } } /* * call-seq: * submodule.ignore_rule -> symbol * * Returns the ignore rule for a submodule. * * There are four ignore values: * * :none (default):: * will consider any change to the contents of the submodule from * a clean checkout to be dirty, including the addition of untracked files. * :untracked :: * examines the contents of the working tree but untracked files will not * count as making the submodule dirty. * :dirty :: * means to only check if the +HEAD+ of the submodule has moved for status. * This is fast since it does not need to scan the working tree * of the submodule at all. * :all :: * means not to open the submodule repository. The working directory will be * considered clean so long as there is a checked out version present. * * See #status on how ignore rules reflect the returned status info * for a submodule. */ static VALUE rb_git_submodule_ignore_rule(VALUE self) { git_submodule *submodule; git_submodule_ignore_t ignore; Data_Get_Struct(self, git_submodule, submodule); ignore = git_submodule_ignore(submodule); return rb_git_subm_ignore_rule_fromC(ignore); } static git_submodule_ignore_t rb_git_subm_ignore_rule_toC(VALUE rb_ignore_rule) { ID id_ignore_rule; Check_Type(rb_ignore_rule, T_SYMBOL); id_ignore_rule = SYM2ID(rb_ignore_rule); if (id_ignore_rule == id_ignore_none) { return GIT_SUBMODULE_IGNORE_NONE; } else if (id_ignore_rule == id_ignore_untracked) { return GIT_SUBMODULE_IGNORE_UNTRACKED; } else if (id_ignore_rule == id_ignore_dirty) { return GIT_SUBMODULE_IGNORE_DIRTY; } else if (id_ignore_rule == id_ignore_all) { return GIT_SUBMODULE_IGNORE_ALL; } else { rb_raise(rb_eArgError, "Invalid submodule ignore rule type."); } } /* * call-seq: * submodule.ignore_rule = rule -> rule * * Set the ignore_rule to +rule+ in memory for a submodule. * See #ignore for a list of accepted rules. * * This will be used for any following actions (such as * #status) while the submodule is in memory. The ignore * rule can be persisted to the config with #save. * * Calling #reset_ignore_rule or #reload will * revert the rule to the value that was in the config. */ static VALUE rb_git_submodule_set_ignore_rule(VALUE self, VALUE rb_ignore_rule) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); git_submodule_set_ignore( submodule, rb_git_subm_ignore_rule_toC(rb_ignore_rule) ); return rb_ignore_rule; } /* * call-seq: * submodule.reset_ignore_rule -> submodule * * Revert the ignore rule set by #ignore_rule= to the value that * was in the config. */ static VALUE rb_git_submodule_reset_ignore_rule(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); git_submodule_set_ignore(submodule, GIT_SUBMODULE_IGNORE_RESET); return self; } static VALUE rb_git_subm_update_rule_fromC(git_submodule_update_t rule) { switch(rule) { case GIT_SUBMODULE_UPDATE_CHECKOUT: return ID2SYM(id_update_checkout); case GIT_SUBMODULE_UPDATE_REBASE: return ID2SYM(id_update_rebase); case GIT_SUBMODULE_UPDATE_MERGE: return ID2SYM(id_update_merge); case GIT_SUBMODULE_UPDATE_NONE: return ID2SYM(id_update_none); default: return CSTR2SYM("unknown"); } } /* * call-seq: * submodule.update_rule -> symbol * * Returns the update rule for a submodule. * * There are four update_rule values: * * :checkout (default):: * the new commit specified in the superproject will be checked out in the * submodule on a detached +HEAD+. * :rebase :: * the current branch of the submodule will be rebased onto the commit * specified in the superproject. * :merge :: * the commit specified in the superproject will be merged into the current * branch of the submodule. * :none :: * the submodule will not be updated */ static VALUE rb_git_submodule_update_rule(VALUE self) { git_submodule *submodule; git_submodule_update_t update; Data_Get_Struct(self, git_submodule, submodule); update = git_submodule_update(submodule); return rb_git_subm_update_rule_fromC(update); } static git_submodule_update_t rb_git_subm_update_rule_toC(VALUE rb_update_rule) { ID id_update_rule; Check_Type(rb_update_rule, T_SYMBOL); id_update_rule = SYM2ID(rb_update_rule); if (id_update_rule == id_update_checkout) { return GIT_SUBMODULE_UPDATE_CHECKOUT; } else if (id_update_rule == id_update_rebase) { return GIT_SUBMODULE_UPDATE_REBASE; } else if (id_update_rule == id_update_merge) { return GIT_SUBMODULE_UPDATE_MERGE; } else if (id_update_rule == id_update_none) { return GIT_SUBMODULE_UPDATE_NONE; } else { rb_raise(rb_eArgError, "Invalid submodule update rule type."); } } /* * call-seq: * submodule.update_rule = rule -> rule * * Set the update_rule to +rule+ in memory for a submodule. * See #update_rule for a list of accepted rules. * * Calling #reset_update_rule or #reload will * revert the +rule+ to the value that was in the config. */ static VALUE rb_git_submodule_set_update_rule(VALUE self, VALUE rb_update_rule) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); git_submodule_set_update( submodule, rb_git_subm_update_rule_toC(rb_update_rule) ); return rb_update_rule; } /* * call-seq: * submodule.reset_update_rule -> submodule * * Revert the update rule set by #update_rule= to the value that * was in the config. */ static VALUE rb_git_submodule_reset_update_rule(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); git_submodule_set_update(submodule, GIT_SUBMODULE_UPDATE_RESET); return self; } /* * call-seq: * submodule.repository -> repository * * Returns the +repository+ for the submodule. * * The returned +repository+ is a newly opened Rugged::Repository object. * This will only work if the submodule is checked out into the working * directory. */ static VALUE rb_git_submodule_repository(VALUE self) { git_submodule *submodule; git_repository *repo; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_open(&repo, submodule) ); return rugged_repo_new(rb_cRuggedRepo, repo); } /* * call-seq: * submodule.finalize_add -> submodule * * Resolve the setup of a new submodule. * * This should be called on a submodule once * Rugged::SubmoduleCollection#setup_add is finished and the sumodule repo is * cloned. * * 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). */ static VALUE rb_git_submodule_finalize_add(VALUE self) { git_submodule *submodule; Data_Get_Struct(self, git_submodule, submodule); rugged_exception_check( git_submodule_add_finalize(submodule) ); return self; } void Init_rugged_submodule(void) { init_status_list(); id_ignore_none = rb_intern("none"); id_ignore_dirty = rb_intern("dirty"); id_ignore_untracked = rb_intern("untracked"); id_ignore_all = rb_intern("all"); id_update_checkout = rb_intern("checkout"); id_update_rebase = rb_intern("rebase"); id_update_merge = rb_intern("merge"); id_update_none = rb_intern("none"); rb_cRuggedSubmodule = rb_define_class_under(rb_mRugged, "Submodule", rb_cObject); rb_define_method(rb_cRuggedSubmodule, "finalize_add", rb_git_submodule_finalize_add, 0); rb_define_method(rb_cRuggedSubmodule, "name", rb_git_submodule_name, 0); rb_define_method(rb_cRuggedSubmodule, "url", rb_git_submodule_url, 0); rb_define_method(rb_cRuggedSubmodule, "url=", rb_git_submodule_set_url, 1); rb_define_method(rb_cRuggedSubmodule, "path", rb_git_submodule_path, 0); rb_define_method(rb_cRuggedSubmodule, "fetch_recurse_submodules?", rb_git_submodule_fetch_recurse_submodules, 0); rb_define_method(rb_cRuggedSubmodule, "fetch_recurse_submodules=", rb_git_submodule_set_fetch_recurse_submodules, 1); rb_define_method(rb_cRuggedSubmodule, "ignore_rule", rb_git_submodule_ignore_rule, 0); rb_define_method(rb_cRuggedSubmodule, "ignore_rule=", rb_git_submodule_set_ignore_rule, 1); rb_define_method(rb_cRuggedSubmodule, "reset_ignore_rule", rb_git_submodule_reset_ignore_rule, 0); rb_define_method(rb_cRuggedSubmodule, "update_rule", rb_git_submodule_update_rule, 0); rb_define_method(rb_cRuggedSubmodule, "update_rule=", rb_git_submodule_set_update_rule, 1); rb_define_method(rb_cRuggedSubmodule, "reset_update_rule", rb_git_submodule_reset_update_rule, 0); rb_define_method(rb_cRuggedSubmodule, "head_oid", rb_git_submodule_head_id, 0); rb_define_method(rb_cRuggedSubmodule, "index_oid", rb_git_submodule_index_id, 0); rb_define_method(rb_cRuggedSubmodule, "workdir_oid", rb_git_submodule_wd_id, 0); rb_define_method(rb_cRuggedSubmodule, "status", rb_git_submodule_status, 0); rb_define_method(rb_cRuggedSubmodule, "in_head?", rb_git_submodule_status_in_head, 0); rb_define_method(rb_cRuggedSubmodule, "in_index?", rb_git_submodule_status_in_index, 0); rb_define_method(rb_cRuggedSubmodule, "in_config?", rb_git_submodule_status_in_config, 0); rb_define_method(rb_cRuggedSubmodule, "in_workdir?", rb_git_submodule_status_in_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "added_to_index?", rb_git_submodule_status_added_to_index, 0); rb_define_method(rb_cRuggedSubmodule, "deleted_from_index?", rb_git_submodule_status_deleted_from_index, 0); rb_define_method(rb_cRuggedSubmodule, "modified_in_index?", rb_git_submodule_status_modified_in_index, 0); rb_define_method(rb_cRuggedSubmodule, "uninitialized?", rb_git_submodule_status_uninitialized, 0); rb_define_method(rb_cRuggedSubmodule, "added_to_workdir?", rb_git_submodule_status_added_to_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "deleted_from_workdir?", rb_git_submodule_status_deleted_from_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "modified_in_workdir?", rb_git_submodule_status_modified_in_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "dirty_workdir_index?", rb_git_submodule_status_dirty_workdir_index, 0); rb_define_method(rb_cRuggedSubmodule, "modified_files_in_workdir?", rb_git_submodule_status_modified_files_in_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "untracked_files_in_workdir?", rb_git_submodule_status_untracked_files_in_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "unmodified?", rb_git_submodule_status_unmodified, 0); rb_define_method(rb_cRuggedSubmodule, "dirty_workdir?", rb_git_submodule_status_dirty_workdir, 0); rb_define_method(rb_cRuggedSubmodule, "repository", rb_git_submodule_repository, 0); rb_define_method(rb_cRuggedSubmodule, "add_to_index", rb_git_submodule_add_to_index, -1); rb_define_method(rb_cRuggedSubmodule, "reload", rb_git_submodule_reload, 0); rb_define_method(rb_cRuggedSubmodule, "save", rb_git_submodule_save, 0); rb_define_method(rb_cRuggedSubmodule, "sync", rb_git_submodule_sync, 0); rb_define_method(rb_cRuggedSubmodule, "init", rb_git_submodule_init, -1); }