rugged 0.21.0 → 0.21.1b0

Sign up to get free protection for your applications and to get access to all the features.
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);