rugged 0.21.0 → 0.21.1b0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -5
  3. data/ext/rugged/extconf.rb +8 -8
  4. data/ext/rugged/rugged.h +1 -1
  5. data/ext/rugged/rugged_cred.c +23 -0
  6. data/ext/rugged/rugged_index.c +5 -1
  7. data/ext/rugged/rugged_remote.c +68 -0
  8. data/ext/rugged/rugged_repo.c +287 -5
  9. data/ext/rugged/rugged_tag_collection.c +70 -2
  10. data/ext/rugged/rugged_tree.c +29 -10
  11. data/lib/rugged.rb +1 -0
  12. data/lib/rugged/attributes.rb +41 -0
  13. data/lib/rugged/diff.rb +0 -1
  14. data/lib/rugged/diff/line.rb +1 -3
  15. data/lib/rugged/patch.rb +12 -2
  16. data/lib/rugged/version.rb +1 -1
  17. data/vendor/libgit2/CMakeLists.txt +11 -0
  18. data/vendor/libgit2/cmake/Modules/FindGSSAPI.cmake +324 -0
  19. data/vendor/libgit2/deps/http-parser/http_parser.h +2 -0
  20. data/vendor/libgit2/deps/zlib/adler32.c +39 -29
  21. data/vendor/libgit2/deps/zlib/crc32.c +33 -50
  22. data/vendor/libgit2/deps/zlib/crc32.h +1 -1
  23. data/vendor/libgit2/deps/zlib/deflate.c +198 -65
  24. data/vendor/libgit2/deps/zlib/deflate.h +8 -4
  25. data/vendor/libgit2/deps/zlib/infback.c +640 -0
  26. data/vendor/libgit2/deps/zlib/inffast.c +3 -3
  27. data/vendor/libgit2/deps/zlib/inffixed.h +3 -3
  28. data/vendor/libgit2/deps/zlib/inflate.c +84 -52
  29. data/vendor/libgit2/deps/zlib/inftrees.c +15 -39
  30. data/vendor/libgit2/deps/zlib/trees.c +18 -36
  31. data/vendor/libgit2/deps/zlib/zconf.h +4 -0
  32. data/vendor/libgit2/deps/zlib/zlib.h +250 -95
  33. data/vendor/libgit2/deps/zlib/zutil.c +13 -10
  34. data/vendor/libgit2/deps/zlib/zutil.h +41 -62
  35. data/vendor/libgit2/include/git2/attr.h +16 -13
  36. data/vendor/libgit2/include/git2/buffer.h +16 -0
  37. data/vendor/libgit2/include/git2/checkout.h +12 -12
  38. data/vendor/libgit2/include/git2/cherrypick.h +15 -15
  39. data/vendor/libgit2/include/git2/clone.h +77 -69
  40. data/vendor/libgit2/include/git2/diff.h +7 -0
  41. data/vendor/libgit2/include/git2/errors.h +1 -0
  42. data/vendor/libgit2/include/git2/merge.h +16 -0
  43. data/vendor/libgit2/include/git2/oid.h +8 -4
  44. data/vendor/libgit2/include/git2/oidarray.h +40 -0
  45. data/vendor/libgit2/include/git2/remote.h +5 -24
  46. data/vendor/libgit2/include/git2/repository.h +4 -1
  47. data/vendor/libgit2/include/git2/reset.h +4 -0
  48. data/vendor/libgit2/include/git2/status.h +17 -14
  49. data/vendor/libgit2/include/git2/submodule.h +18 -0
  50. data/vendor/libgit2/include/git2/sys/transport.h +354 -0
  51. data/vendor/libgit2/include/git2/transport.h +34 -327
  52. data/vendor/libgit2/include/git2/types.h +16 -6
  53. data/vendor/libgit2/src/array.h +1 -1
  54. data/vendor/libgit2/src/attr_file.c +14 -1
  55. data/vendor/libgit2/src/blame.c +0 -1
  56. data/vendor/libgit2/src/buffer.c +67 -10
  57. data/vendor/libgit2/src/buffer.h +4 -2
  58. data/vendor/libgit2/src/cache.c +9 -9
  59. data/vendor/libgit2/src/cache.h +1 -1
  60. data/vendor/libgit2/src/checkout.c +118 -23
  61. data/vendor/libgit2/src/cherrypick.c +41 -44
  62. data/vendor/libgit2/src/clone.c +94 -56
  63. data/vendor/libgit2/src/config_file.c +4 -4
  64. data/vendor/libgit2/src/diff.c +21 -0
  65. data/vendor/libgit2/src/diff_file.c +1 -0
  66. data/vendor/libgit2/src/diff_print.c +11 -9
  67. data/vendor/libgit2/src/diff_tform.c +3 -1
  68. data/vendor/libgit2/src/errors.c +9 -7
  69. data/vendor/libgit2/src/fileops.c +5 -3
  70. data/vendor/libgit2/src/global.c +9 -1
  71. data/vendor/libgit2/src/global.h +1 -0
  72. data/vendor/libgit2/src/graph.c +2 -2
  73. data/vendor/libgit2/src/indexer.c +6 -1
  74. data/vendor/libgit2/src/merge.c +98 -144
  75. data/vendor/libgit2/src/merge.h +1 -1
  76. data/vendor/libgit2/src/netops.c +4 -0
  77. data/vendor/libgit2/src/oid.c +8 -0
  78. data/vendor/libgit2/src/oid.h +11 -0
  79. data/vendor/libgit2/src/oidarray.c +21 -0
  80. data/vendor/libgit2/src/oidarray.h +18 -0
  81. data/vendor/libgit2/src/pack.c +1 -4
  82. data/vendor/libgit2/src/path.c +93 -33
  83. data/vendor/libgit2/src/path.h +21 -0
  84. data/vendor/libgit2/src/pool.c +1 -1
  85. data/vendor/libgit2/src/posix.h +46 -28
  86. data/vendor/libgit2/src/refs.h +2 -2
  87. data/vendor/libgit2/src/refspec.c +54 -18
  88. data/vendor/libgit2/src/remote.c +31 -8
  89. data/vendor/libgit2/src/remote.h +3 -0
  90. data/vendor/libgit2/src/repository.c +27 -11
  91. data/vendor/libgit2/src/revert.c +4 -6
  92. data/vendor/libgit2/src/revparse.c +15 -18
  93. data/vendor/libgit2/src/revwalk.c +0 -3
  94. data/vendor/libgit2/src/signature.c +2 -2
  95. data/vendor/libgit2/src/stash.c +2 -1
  96. data/vendor/libgit2/src/status.c +11 -2
  97. data/vendor/libgit2/src/strnlen.h +2 -1
  98. data/vendor/libgit2/src/submodule.c +73 -33
  99. data/vendor/libgit2/src/thread-utils.h +0 -7
  100. data/vendor/libgit2/src/trace.h +9 -1
  101. data/vendor/libgit2/src/transport.c +93 -90
  102. data/vendor/libgit2/src/transports/auth.c +71 -0
  103. data/vendor/libgit2/src/transports/auth.h +63 -0
  104. data/vendor/libgit2/src/transports/auth_negotiate.c +275 -0
  105. data/vendor/libgit2/src/transports/auth_negotiate.h +27 -0
  106. data/vendor/libgit2/src/transports/cred.c +58 -0
  107. data/vendor/libgit2/src/transports/cred.h +14 -0
  108. data/vendor/libgit2/src/transports/cred_helpers.c +3 -0
  109. data/vendor/libgit2/src/transports/git.c +1 -0
  110. data/vendor/libgit2/src/transports/http.c +168 -76
  111. data/vendor/libgit2/src/transports/smart.h +1 -0
  112. data/vendor/libgit2/src/transports/smart_protocol.c +4 -2
  113. data/vendor/libgit2/src/transports/ssh.c +214 -38
  114. data/vendor/libgit2/src/transports/winhttp.c +26 -6
  115. data/vendor/libgit2/src/unix/posix.h +23 -9
  116. data/vendor/libgit2/src/unix/realpath.c +8 -7
  117. data/vendor/libgit2/src/util.c +2 -1
  118. data/vendor/libgit2/src/util.h +3 -3
  119. data/vendor/libgit2/src/win32/mingw-compat.h +5 -12
  120. data/vendor/libgit2/src/win32/msvc-compat.h +3 -32
  121. data/vendor/libgit2/src/win32/posix.h +20 -31
  122. data/vendor/libgit2/src/win32/posix_w32.c +33 -4
  123. metadata +81 -69
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0356879d784d17079ccdae0dfef24d5841c0774
4
- data.tar.gz: 2a4d772157bcc8b25f61a7745d1694507bc56ca4
3
+ metadata.gz: 71c12ca95964095a5400cc76eeb9b98c1c116a69
4
+ data.tar.gz: 752fefe7898903eeeef4139198eb6a719b044059
5
5
  SHA512:
6
- metadata.gz: d6f0d49db816f5337decf934efda9529ddbf8beaf6edfa72737f661e7b5759afd7b4f27f21734de0098e101bc7b714b90aad674c450344d7cd7865de5fe73e3b
7
- data.tar.gz: cf7dca7617881507c212c4c813bd41494d31ed1c3d8579092dc138a5b449d89af5264c9b673cf938f39a8781c000c768bcf498bd82136afb167e950d617b88bc
6
+ metadata.gz: 4b16dedcf38b935c0d7a17c3b4c34c11f3280dafc6247f6b8ce88fa81e1f66696b3e2ae695405f75e3f8cc9c45eeff8017375156b6328fc3c8f285d31f3d1043
7
+ data.tar.gz: 3b0f3d1bc1f12cf4f8f65cafc7ea4028239787225e0b04aa5e9476e85171dcf5ed0e1621b03eb070fa2273d3c7a5307932a82602b5cc2e76972b5fd54af676cd
data/README.md CHANGED
@@ -17,7 +17,12 @@ Rugged is a self-contained gem. You can install it by running:
17
17
 
18
18
  $ gem install rugged
19
19
 
20
- You need to have CMake installed on your system to be able to build the included version of `libgit2`. If you want to build Rugged with HTTPS and SSH support, check out the list of optional [libgit2 dependencies](https://github.com/libgit2/libgit2#optional-dependencies).
20
+ You need to have CMake and `pkg-config` installed on your system to be able to build the included version of `libgit2`. On OS X, after installing [Homebrew](http://brew.sh/), you can get CMake with:
21
+ ```bash
22
+ $ brew install cmake
23
+ ```
24
+
25
+ If you want to build Rugged with HTTPS and SSH support, check out the list of optional [libgit2 dependencies](https://github.com/libgit2/libgit2#optional-dependencies).
21
26
 
22
27
  If you're using bundler and want to bundle `libgit2` with Rugged, you can use the `:submodules` option:
23
28
 
@@ -96,7 +101,7 @@ repo.bare?
96
101
  # => false
97
102
  repo.empty?
98
103
  # => true
99
- repo.head_orphan?
104
+ repo.head_unborn?
100
105
  # => false
101
106
  repo.head_detached?
102
107
  # => false
@@ -109,13 +114,15 @@ repo.workdir
109
114
 
110
115
  # The HEAD of the repository.
111
116
  ref = repo.head
112
- # => #<Rugged::Reference:2228467240 {name: "refs/heads/master", target: "07b44cbda23b726e5d54e2ef383495922c024202"}>
117
+ # => #<Rugged::Reference:2228467240 {name: "refs/heads/master", target: #<Rugged::Commit:2228467250 {message: "helpful message", tree: #<Rugged::Tree:2228467260 {oid: 5d6f29220a0783b8085134df14ec4d960b6c3bf2}>}>
113
118
 
114
- # From the returned ref, you can also access the `name` and `target`:
119
+ # From the returned ref, you can also access the `name`, `target`, and target SHA:
115
120
  ref.name
116
121
  # => "refs/heads/master"
117
122
  ref.target
118
- # => "07b44cbda23b726e5d54e2ef383495922c024202"
123
+ # => #<Rugged::Commit:2228467250 {message: "helpful message", tree: #<Rugged::Tree:2228467260 {oid: 5d6f29220a0783b8085134df14ec4d960b6c3bf2}>}>
124
+ ref.target_id
125
+ # => "2bc6a70483369f33f641ca44873497f13a15cde5"
119
126
 
120
127
  # Reading an object
121
128
  object = repo.read('a0ae5566e3c8a3bddffab21022056f0b5e03ef07')
@@ -15,18 +15,10 @@ def sys(cmd)
15
15
  ret
16
16
  end
17
17
 
18
- if !find_executable('cmake')
19
- abort "ERROR: CMake is required to build Rugged."
20
- end
21
-
22
18
  if !(MAKE = find_executable('gmake') || find_executable('make'))
23
19
  abort "ERROR: GNU make is required to build Rugged."
24
20
  end
25
21
 
26
- if !find_executable('pkg-config')
27
- abort "ERROR: pkg-config is required to build Rugged."
28
- end
29
-
30
22
  if arg_config("--use-system-libraries", !!ENV['RUGGED_USE_SYSTEM_LIBRARIES'])
31
23
  puts "Building Rugged using system libraries.\n"
32
24
 
@@ -40,6 +32,14 @@ if arg_config("--use-system-libraries", !!ENV['RUGGED_USE_SYSTEM_LIBRARIES'])
40
32
  #endif
41
33
  SRC
42
34
  else
35
+ if !find_executable('cmake')
36
+ abort "ERROR: CMake is required to build Rugged."
37
+ end
38
+
39
+ if !find_executable('pkg-config')
40
+ abort "ERROR: pkg-config is required to build Rugged."
41
+ end
42
+
43
43
  CWD = File.expand_path(File.dirname(__FILE__))
44
44
  LIBGIT2_DIR = File.join(CWD, '..', '..', 'vendor', 'libgit2')
45
45
 
data/ext/rugged/rugged.h CHANGED
@@ -120,7 +120,7 @@ static inline VALUE rugged_owner(VALUE object)
120
120
  static inline void rugged_validate_remote_url(VALUE rb_url)
121
121
  {
122
122
  Check_Type(rb_url, T_STRING);
123
- if (!git_remote_valid_url(StringValueCStr(rb_url)))
123
+ if (!git_remote_supported_url(StringValueCStr(rb_url)))
124
124
  rb_raise(rb_eArgError, "Invalid URL format");
125
125
  }
126
126
 
@@ -88,19 +88,42 @@ static void rugged_cred_extract_default(git_cred **cred, VALUE rb_credential)
88
88
  rugged_exception_check(git_cred_default_new(cred));
89
89
  }
90
90
 
91
+ static void rugged_cred_extract_username(git_cred **cred, VALUE rb_credential)
92
+ {
93
+ VALUE rb_username = rb_iv_get(rb_credential, "@username");
94
+ Check_Type(rb_username, T_STRING);
95
+
96
+ rugged_exception_check(git_cred_username_new(cred, StringValueCStr(rb_username)));
97
+ }
98
+
91
99
  void rugged_cred_extract(git_cred **cred, int allowed_types, VALUE rb_credential)
92
100
  {
93
101
  if (rb_obj_is_kind_of(rb_credential, rb_cRuggedCredUserPassword)) {
102
+ if (allowed_types & GIT_CREDTYPE_USERNAME) {
103
+ rugged_cred_extract_username(cred, rb_credential);
104
+ return;
105
+ }
106
+
94
107
  if (!(allowed_types & GIT_CREDTYPE_USERPASS_PLAINTEXT))
95
108
  rb_raise(rb_eArgError, "Invalid credential type");
96
109
 
97
110
  rugged_cred_extract_userpass(cred, rb_credential);
98
111
  } else if (rb_obj_is_kind_of(rb_credential, rb_cRuggedCredSshKey)) {
112
+ if (allowed_types & GIT_CREDTYPE_USERNAME) {
113
+ rugged_cred_extract_username(cred, rb_credential);
114
+ return;
115
+ }
116
+
99
117
  if (!(allowed_types & GIT_CREDTYPE_SSH_KEY))
100
118
  rb_raise(rb_eArgError, "Invalid credential type");
101
119
 
102
120
  rugged_cred_extract_ssh_key(cred, rb_credential);
103
121
  } else if (rb_obj_is_kind_of(rb_credential, rb_cRuggedCredSshKeyFromAgent)) {
122
+ if (allowed_types & GIT_CREDTYPE_USERNAME) {
123
+ rugged_cred_extract_username(cred, rb_credential);
124
+ return;
125
+ }
126
+
104
127
  if (!(allowed_types & GIT_CREDTYPE_SSH_KEY))
105
128
  rb_raise(rb_eArgError, "Invalid credential type");
106
129
 
@@ -681,6 +681,10 @@ static VALUE rb_git_index_readtree(VALUE self, VALUE rb_tree)
681
681
  Data_Get_Struct(self, git_index, index);
682
682
  Data_Get_Struct(rb_tree, git_tree, tree);
683
683
 
684
+ if (!rb_obj_is_kind_of(rb_tree, rb_cRuggedTree)) {
685
+ rb_raise(rb_eTypeError, "A Rugged::Tree instance is required");
686
+ }
687
+
684
688
  error = git_index_read_tree(index, tree);
685
689
  rugged_exception_check(error);
686
690
 
@@ -831,7 +835,7 @@ static VALUE rb_git_index_diff(int argc, VALUE *argv, VALUE self)
831
835
  xfree(opts.pathspec.strings);
832
836
  rugged_exception_check(error);
833
837
 
834
- return rugged_diff_new(rb_cRuggedDiff, self, diff);
838
+ return rugged_diff_new(rb_cRuggedDiff, owner, diff);
835
839
  }
836
840
 
837
841
  /*
@@ -535,6 +535,73 @@ static VALUE rb_git_remote_rename(VALUE self, VALUE rb_new_name)
535
535
  return rb_result;
536
536
  }
537
537
 
538
+ /*
539
+ * call-seq:
540
+ * remote.check_connection(direction, options = {}) -> boolean
541
+ *
542
+ * Try to connect to the +remote+. Useful to simulate
543
+ * <tt>git fetch --dry-run</tt> and <tt>git push --dry-run</tt>.
544
+ *
545
+ * Returns +true+ if connection is successful, +false+ otherwise.
546
+ *
547
+ * +direction+ must be either +:fetch+ or +:push+.
548
+ *
549
+ * The following options can be passed in the +options+ Hash:
550
+ *
551
+ * +credentials+ ::
552
+ * The credentials to use for the connection. Can be either an instance of
553
+ * one of the Rugged::Credentials types, or a proc returning one of the
554
+ * former.
555
+ * The proc will be called with the +url+, the +username+ from the url (if
556
+ * applicable) and a list of applicable credential types.
557
+ *
558
+ * Example:
559
+ *
560
+ * remote = repo.remotes["origin"]
561
+ * success = remote.check_connection(:fetch)
562
+ * raise Error("Unable to pull without credentials") unless success
563
+ */
564
+ static VALUE rb_git_remote_check_connection(int argc, VALUE *argv, VALUE self)
565
+ {
566
+ git_remote *remote;
567
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
568
+ struct rugged_remote_cb_payload payload = { Qnil, Qnil, Qnil, Qnil, Qnil, 0 };
569
+ VALUE rb_direction, rb_options;
570
+ ID id_direction;
571
+ int error, direction;
572
+
573
+ Data_Get_Struct(self, git_remote, remote);
574
+ rb_scan_args(argc, argv, "01:", &rb_direction, &rb_options);
575
+
576
+ Check_Type(rb_direction, T_SYMBOL);
577
+ id_direction = SYM2ID(rb_direction);
578
+ if (id_direction == rb_intern("fetch"))
579
+ direction = GIT_DIRECTION_FETCH;
580
+ else if (id_direction == rb_intern("push"))
581
+ direction = GIT_DIRECTION_PUSH;
582
+ else
583
+ rb_raise(rb_eTypeError, "Invalid direction. Expected :fetch or :push");
584
+
585
+ if (!NIL_P(rb_options))
586
+ rugged_remote_init_callbacks_and_payload_from_options(rb_options, &callbacks, &payload);
587
+
588
+ if ((error = git_remote_set_callbacks(remote, &callbacks)) < 0)
589
+ goto cleanup;
590
+
591
+ if (git_remote_connect(remote, direction))
592
+ return Qfalse;
593
+ else {
594
+ git_remote_disconnect(remote);
595
+ return Qtrue;
596
+ }
597
+
598
+ cleanup:
599
+ if (payload.exception)
600
+ rb_jump_tag(payload.exception);
601
+ rugged_exception_check(error);
602
+ return Qfalse;
603
+ }
604
+
538
605
  /*
539
606
  * call-seq:
540
607
  * remote.fetch(refspecs = nil, options = {}) -> hash
@@ -827,6 +894,7 @@ void Init_rugged_remote(void)
827
894
  rb_define_method(rb_cRuggedRemote, "add_fetch", rb_git_remote_add_fetch, 1);
828
895
  rb_define_method(rb_cRuggedRemote, "add_push", rb_git_remote_add_push, 1);
829
896
  rb_define_method(rb_cRuggedRemote, "ls", rb_git_remote_ls, -1);
897
+ rb_define_method(rb_cRuggedRemote, "check_connection", rb_git_remote_check_connection, -1);
830
898
  rb_define_method(rb_cRuggedRemote, "fetch", rb_git_remote_fetch, -1);
831
899
  rb_define_method(rb_cRuggedRemote, "push", rb_git_remote_push, -1);
832
900
  rb_define_method(rb_cRuggedRemote, "clear_refspecs", rb_git_remote_clear_refspecs, 0);
@@ -643,9 +643,10 @@ static VALUE rb_git_repo_merge_commits(int argc, VALUE *argv, VALUE self)
643
643
  * repo.exists?(oid) -> true or false
644
644
  *
645
645
  * Return whether an object with the given SHA1 OID (represented as
646
- * a 40-character string) exists in the repository.
646
+ * a hex string of at least 7 characters) exists in the repository.
647
647
  *
648
648
  * repo.include?("d8786bfc97485e8d7b19b21fb88c8ef1f199fc3f") #=> true
649
+ * repo.include?("d8786bfc") #=> true
649
650
  */
650
651
  static VALUE rb_git_repo_exists(VALUE self, VALUE hex)
651
652
  {
@@ -653,21 +654,23 @@ static VALUE rb_git_repo_exists(VALUE self, VALUE hex)
653
654
  git_odb *odb;
654
655
  git_oid oid;
655
656
  int error;
656
- VALUE rb_result;
657
657
 
658
658
  Data_Get_Struct(self, git_repository, repo);
659
659
  Check_Type(hex, T_STRING);
660
660
 
661
- error = git_oid_fromstr(&oid, StringValueCStr(hex));
661
+ error = git_oid_fromstrn(&oid, RSTRING_PTR(hex), RSTRING_LEN(hex));
662
662
  rugged_exception_check(error);
663
663
 
664
664
  error = git_repository_odb(&odb, repo);
665
665
  rugged_exception_check(error);
666
666
 
667
- rb_result = git_odb_exists(odb, &oid) ? Qtrue : Qfalse;
667
+ error = git_odb_exists_prefix(NULL, odb, &oid, RSTRING_LEN(hex));
668
668
  git_odb_free(odb);
669
669
 
670
- return rb_result;
670
+ if (error == 0 || error == GIT_EAMBIGUOUS)
671
+ return Qtrue;
672
+
673
+ return Qfalse;
671
674
  }
672
675
 
673
676
  /*
@@ -736,6 +739,107 @@ static VALUE rb_git_repo_read_header(VALUE self, VALUE hex)
736
739
  return rb_hash;
737
740
  }
738
741
 
742
+ /**
743
+ * call-seq:
744
+ * repo.expand_oids([oid..], object_type = :any) -> hash
745
+ *
746
+ * Expand a list of short oids to their full value, assuming they exist
747
+ * in the repository. If `object_type` is passed, OIDs are expected to be
748
+ * of the given type.
749
+ *
750
+ * Returns a hash of `{ short_oid => full_oid }` for the short OIDs which
751
+ * exist in the repository and match the expected object type. Missing OIDs
752
+ * will not appear in the resulting hash.
753
+ */
754
+ static VALUE rb_git_repo_expand_oids(int argc, VALUE *argv, VALUE self)
755
+ {
756
+ VALUE rb_result, rb_oids, rb_expected_type;
757
+
758
+ git_otype expected_type = GIT_OBJ_ANY;
759
+
760
+ git_repository *repo;
761
+ git_oid oid;
762
+ git_odb *odb;
763
+ int i, error;
764
+
765
+ Data_Get_Struct(self, git_repository, repo);
766
+
767
+ rb_scan_args(argc, argv, "11", &rb_oids, &rb_expected_type);
768
+
769
+ Check_Type(rb_oids, T_ARRAY);
770
+ expected_type = rugged_otype_get(rb_expected_type);
771
+
772
+ error = git_repository_odb(&odb, repo);
773
+ rugged_exception_check(error);
774
+
775
+ rb_result = rb_hash_new();
776
+
777
+ for (i = 0; i < RARRAY_LEN(rb_oids); ++i) {
778
+ VALUE hex_oid = rb_ary_entry(rb_oids, i);
779
+ git_oid found_oid;
780
+
781
+ if (TYPE(hex_oid) != T_STRING) {
782
+ git_odb_free(odb);
783
+ rb_raise(rb_eTypeError, "Expected a SHA1 OID");
784
+ }
785
+
786
+ error = git_oid_fromstrn(&oid, RSTRING_PTR(hex_oid), RSTRING_LEN(hex_oid));
787
+ if (error < 0) {
788
+ git_odb_free(odb);
789
+ rugged_exception_check(error);
790
+ }
791
+
792
+ error = git_odb_exists_prefix(&found_oid, odb, &oid, RSTRING_LEN(hex_oid));
793
+
794
+ if (!error) {
795
+ if (expected_type != GIT_OBJ_ANY) {
796
+ size_t found_size;
797
+ git_otype found_type;
798
+
799
+ if (git_odb_read_header(&found_size, &found_type, odb, &found_oid) < 0)
800
+ continue;
801
+
802
+ if (found_type != expected_type)
803
+ continue;
804
+ }
805
+
806
+ rb_hash_aset(rb_result, hex_oid, rugged_create_oid(&found_oid));
807
+ }
808
+ }
809
+
810
+ git_odb_free(odb);
811
+ return rb_result;
812
+ }
813
+
814
+ /*
815
+ * call-seq:
816
+ * repo.descendant_of?(commit, ancestor) -> true or false
817
+ *
818
+ * +commit+ and +ancestor+ must be String commit OIDs or instances of Rugged::Commit.
819
+ *
820
+ * Returns true if +commit+ is a descendant of +ancestor+, or false if not.
821
+ */
822
+ static VALUE rb_git_repo_descendant_of(VALUE self, VALUE rb_commit, VALUE rb_ancestor)
823
+ {
824
+ int result;
825
+ int error;
826
+ git_repository *repo;
827
+ git_oid commit, ancestor;
828
+
829
+ Data_Get_Struct(self, git_repository, repo);
830
+
831
+ error = rugged_oid_get(&commit, repo, rb_commit);
832
+ rugged_exception_check(error);
833
+
834
+ error = rugged_oid_get(&ancestor, repo, rb_ancestor);
835
+ rugged_exception_check(error);
836
+
837
+ result = git_graph_descendant_of(repo, &commit, &ancestor);
838
+ rugged_exception_check(result);
839
+
840
+ return result ? Qtrue : Qfalse;
841
+ }
842
+
739
843
  /*
740
844
  * call-seq:
741
845
  * Repository.hash_data(str, type) -> oid
@@ -1924,6 +2028,179 @@ static VALUE rb_git_repo_is_path_ignored(VALUE self, VALUE rb_path) {
1924
2028
  return ignored ? Qtrue : Qfalse;
1925
2029
  }
1926
2030
 
2031
+ static void rugged_parse_cherrypick_options(git_cherrypick_options *opts, VALUE rb_options)
2032
+ {
2033
+ VALUE rb_value;
2034
+
2035
+ if (NIL_P(rb_options))
2036
+ return;
2037
+
2038
+ Check_Type(rb_options, T_HASH);
2039
+
2040
+ rb_value = rb_hash_aref(rb_options, CSTR2SYM("mainline"));
2041
+ if (!NIL_P(rb_value)) {
2042
+ opts->mainline = FIX2UINT(rb_value);
2043
+ }
2044
+ }
2045
+
2046
+ static VALUE rugged_create_attr(const char *attr)
2047
+ {
2048
+ switch (git_attr_value(attr)) {
2049
+ case GIT_ATTR_TRUE_T:
2050
+ return Qtrue;
2051
+
2052
+ case GIT_ATTR_FALSE_T:
2053
+ return Qfalse;
2054
+
2055
+ case GIT_ATTR_VALUE_T:
2056
+ return rb_str_new2(attr);
2057
+
2058
+ case GIT_ATTR_UNSPECIFIED_T:
2059
+ default:
2060
+ return Qnil;
2061
+ }
2062
+ }
2063
+
2064
+ static int foreach_attr_hash(const char *name, const char *value, void *payload)
2065
+ {
2066
+ VALUE rb_hash = (VALUE)payload;
2067
+ rb_hash_aset(rb_hash, rb_str_new2(name), rugged_create_attr(value));
2068
+ return 0;
2069
+ }
2070
+
2071
+ static VALUE rb_git_repo_attributes(int argc, VALUE *argv, VALUE self)
2072
+ {
2073
+ VALUE rb_path, rb_names, rb_options;
2074
+
2075
+ git_repository *repo;
2076
+ int error, options = 0;
2077
+
2078
+ rb_scan_args(argc, argv, "12", &rb_path, &rb_names, &rb_options);
2079
+
2080
+ Data_Get_Struct(self, git_repository, repo);
2081
+ Check_Type(rb_path, T_STRING);
2082
+
2083
+ if (!NIL_P(rb_options)) {
2084
+ Check_Type(rb_options, T_FIXNUM);
2085
+ options = FIX2INT(rb_options);
2086
+ }
2087
+
2088
+ switch (TYPE(rb_names)) {
2089
+ case T_ARRAY:
2090
+ {
2091
+ VALUE rb_result;
2092
+ const char **values;
2093
+ const char **names;
2094
+ int i, num_attr = RARRAY_LEN(rb_names);
2095
+
2096
+ if (num_attr > 32)
2097
+ rb_raise(rb_eRuntimeError, "Too many attributes requested");
2098
+
2099
+ values = alloca(num_attr * sizeof(const char *));
2100
+ names = alloca(num_attr * sizeof(const char *));
2101
+
2102
+ for (i = 0; i < num_attr; ++i) {
2103
+ VALUE attr = rb_ary_entry(rb_names, i);
2104
+ Check_Type(attr, T_STRING);
2105
+ names[i] = StringValueCStr(attr);
2106
+ }
2107
+
2108
+ error = git_attr_get_many(
2109
+ values, repo, options,
2110
+ StringValueCStr(rb_path),
2111
+ (size_t)num_attr, names);
2112
+
2113
+ rugged_exception_check(error);
2114
+
2115
+ rb_result = rb_hash_new();
2116
+ for (i = 0; i < num_attr; ++i) {
2117
+ VALUE attr = rb_ary_entry(rb_names, i);
2118
+ rb_hash_aset(rb_result, attr, rugged_create_attr(values[i]));
2119
+ }
2120
+ return rb_result;
2121
+ }
2122
+
2123
+ case T_STRING:
2124
+ {
2125
+ const char *value;
2126
+
2127
+ error = git_attr_get(
2128
+ &value, repo, options,
2129
+ StringValueCStr(rb_path),
2130
+ StringValueCStr(rb_names));
2131
+
2132
+ rugged_exception_check(error);
2133
+
2134
+ return rugged_create_attr(value);
2135
+ }
2136
+
2137
+ case T_NIL:
2138
+ {
2139
+ VALUE rb_result = rb_hash_new();
2140
+
2141
+ error = git_attr_foreach(
2142
+ repo, options,
2143
+ StringValueCStr(rb_path),
2144
+ &foreach_attr_hash,
2145
+ (void *)rb_result);
2146
+
2147
+ rugged_exception_check(error);
2148
+ return rb_result;
2149
+ }
2150
+
2151
+ default:
2152
+ rb_raise(rb_eTypeError,
2153
+ "Invalid attribute name (expected String or Array)");
2154
+ }
2155
+ }
2156
+
2157
+ /*
2158
+ * call-seq:
2159
+ * repo.cherrypick(commit[, options]) -> nil
2160
+ *
2161
+ * Cherry-pick the given commit and update the index and working
2162
+ * directory accordingly.
2163
+ *
2164
+ * `commit` can be either a string containing a commit id or a
2165
+ * `Rugged::Commit` object.
2166
+ *
2167
+ * The following options can be passed in the +options+ Hash:
2168
+ *
2169
+ * :mainline ::
2170
+ * When cherry-picking a merge, you need to specify the parent number
2171
+ * (starting from 1) which should be considered the mainline.
2172
+ */
2173
+ static VALUE rb_git_repo_cherrypick(int argc, VALUE *argv, VALUE self)
2174
+ {
2175
+ VALUE rb_options, rb_commit;
2176
+
2177
+ git_repository *repo;
2178
+ git_commit *commit;
2179
+ git_cherrypick_options opts = GIT_CHERRYPICK_OPTIONS_INIT;
2180
+
2181
+ int error;
2182
+
2183
+ rb_scan_args(argc, argv, "10:", &rb_commit, &rb_options);
2184
+
2185
+ if (TYPE(rb_commit) == T_STRING) {
2186
+ rb_commit = rugged_object_rev_parse(self, rb_commit, 1);
2187
+ }
2188
+
2189
+ if (!rb_obj_is_kind_of(rb_commit, rb_cRuggedCommit)) {
2190
+ rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
2191
+ }
2192
+
2193
+ Data_Get_Struct(self, git_repository, repo);
2194
+ Data_Get_Struct(rb_commit, git_commit, commit);
2195
+
2196
+ rugged_parse_cherrypick_options(&opts, rb_options);
2197
+
2198
+ error = git_cherrypick(repo, commit, &opts);
2199
+ rugged_exception_check(error);
2200
+
2201
+ return Qnil;
2202
+ }
2203
+
1927
2204
  void Init_rugged_repo(void)
1928
2205
  {
1929
2206
  id_call = rb_intern("call");
@@ -1942,6 +2219,8 @@ void Init_rugged_repo(void)
1942
2219
 
1943
2220
  rb_define_method(rb_cRuggedRepo, "exists?", rb_git_repo_exists, 1);
1944
2221
  rb_define_method(rb_cRuggedRepo, "include?", rb_git_repo_exists, 1);
2222
+ rb_define_method(rb_cRuggedRepo, "expand_oids", rb_git_repo_expand_oids, -1);
2223
+ rb_define_method(rb_cRuggedRepo, "descendant_of?", rb_git_repo_descendant_of, 2);
1945
2224
 
1946
2225
  rb_define_method(rb_cRuggedRepo, "read", rb_git_repo_read, 1);
1947
2226
  rb_define_method(rb_cRuggedRepo, "read_header", rb_git_repo_read_header, 1);
@@ -1986,6 +2265,9 @@ void Init_rugged_repo(void)
1986
2265
  rb_define_method(rb_cRuggedRepo, "checkout_tree", rb_git_checkout_tree, -1);
1987
2266
  rb_define_method(rb_cRuggedRepo, "checkout_head", rb_git_checkout_head, -1);
1988
2267
 
2268
+ rb_define_method(rb_cRuggedRepo, "cherrypick", rb_git_repo_cherrypick, -1);
2269
+ rb_define_method(rb_cRuggedRepo, "fetch_attributes", rb_git_repo_attributes, -1);
2270
+
1989
2271
  rb_cRuggedOdbObject = rb_define_class_under(rb_mRugged, "OdbObject", rb_cObject);
1990
2272
  rb_define_method(rb_cRuggedOdbObject, "data", rb_git_odbobj_data, 0);
1991
2273
  rb_define_method(rb_cRuggedOdbObject, "len", rb_git_odbobj_size, 0);