rugged 0.24.0b12 → 0.24.0b13

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.
@@ -41,6 +41,18 @@ VALUE rugged_ref_new(VALUE klass, VALUE owner, git_reference *ref)
41
41
  return rb_ref;
42
42
  }
43
43
 
44
+
45
+ const char * rugged_refname_from_string_or_ref(VALUE rb_name_or_ref)
46
+ {
47
+ if (rb_obj_is_kind_of(rb_name_or_ref, rb_cRuggedReference))
48
+ rb_name_or_ref = rb_funcall(rb_name_or_ref, rb_intern("canonical_name"), 0);
49
+
50
+ if (TYPE(rb_name_or_ref) != T_STRING)
51
+ rb_raise(rb_eTypeError, "Expecting a String or Rugged::Reference instance");
52
+
53
+ return StringValueCStr(rb_name_or_ref);
54
+ }
55
+
44
56
  /*
45
57
  * call-seq:
46
58
  * Reference.valid_name?(ref_name) -> true or false
@@ -1934,7 +1934,7 @@ static int rugged__checkout_notify_cb(
1934
1934
  /**
1935
1935
  * The caller has to free the returned git_checkout_options paths strings array.
1936
1936
  */
1937
- static void rugged_parse_checkout_options(git_checkout_options *opts, VALUE rb_options)
1937
+ void rugged_parse_checkout_options(git_checkout_options *opts, VALUE rb_options)
1938
1938
  {
1939
1939
  VALUE rb_value;
1940
1940
 
@@ -2530,6 +2530,61 @@ static VALUE rb_git_repo_cherrypick(int argc, VALUE *argv, VALUE self)
2530
2530
  return Qnil;
2531
2531
  }
2532
2532
 
2533
+ /*
2534
+ * call-seq:
2535
+ * repo.cherrypick_commit(commit, our_commit, [mainline, options]) -> nil
2536
+ *
2537
+ * Cherry-pick the given commit on the given base in-memory and
2538
+ * return an index with the result.
2539
+ *
2540
+ * `commit` can be either a string containing a commit id or a
2541
+ * `Rugged::Commit` object.
2542
+ *
2543
+ * `our_commit` is the base commit, can be either a string containing
2544
+ * a commit id or a `Rugged::Commit` object.
2545
+ *
2546
+ * `mainline` when cherry-picking a merge, this is the parent number
2547
+ * (starting from 1) which should be considered the mainline.
2548
+ */
2549
+ static VALUE rb_git_repo_cherrypick_commit(int argc, VALUE *argv, VALUE self)
2550
+ {
2551
+ VALUE rb_options, rb_commit, rb_our_commit, rb_mainline;
2552
+
2553
+ git_repository *repo;
2554
+ git_commit *commit, *our_commit;
2555
+ git_merge_options opts = GIT_MERGE_OPTIONS_INIT;
2556
+ git_index *index;
2557
+ int error, mainline;
2558
+
2559
+ rb_scan_args(argc, argv, "21:", &rb_commit, &rb_our_commit, &rb_mainline, &rb_options);
2560
+
2561
+ if (TYPE(rb_commit) == T_STRING) {
2562
+ rb_commit = rugged_object_rev_parse(self, rb_commit, 1);
2563
+ }
2564
+ if (TYPE(rb_our_commit) == T_STRING) {
2565
+ rb_our_commit = rugged_object_rev_parse(self, rb_our_commit, 1);
2566
+ }
2567
+
2568
+ if (!rb_obj_is_kind_of(rb_commit, rb_cRuggedCommit)) {
2569
+ rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
2570
+ }
2571
+ if (!rb_obj_is_kind_of(rb_our_commit, rb_cRuggedCommit)) {
2572
+ rb_raise(rb_eArgError, "Expected a Rugged::Commit.");
2573
+ }
2574
+
2575
+ Data_Get_Struct(self, git_repository, repo);
2576
+ Data_Get_Struct(rb_commit, git_commit, commit);
2577
+ Data_Get_Struct(rb_our_commit, git_commit, our_commit);
2578
+
2579
+ rugged_parse_merge_options(&opts, rb_options);
2580
+
2581
+ mainline = NIL_P(rb_mainline) ? 0 : FIX2UINT(rb_mainline);
2582
+ error = git_cherrypick_commit(&index, repo, commit, our_commit, mainline, &opts);
2583
+ rugged_exception_check(error);
2584
+
2585
+ return rugged_index_new(rb_cRuggedIndex, self, index);
2586
+ }
2587
+
2533
2588
  void Init_rugged_repo(void)
2534
2589
  {
2535
2590
  id_call = rb_intern("call");
@@ -2603,6 +2658,7 @@ void Init_rugged_repo(void)
2603
2658
  rb_define_method(rb_cRuggedRepo, "checkout_head", rb_git_checkout_head, -1);
2604
2659
 
2605
2660
  rb_define_method(rb_cRuggedRepo, "cherrypick", rb_git_repo_cherrypick, -1);
2661
+ rb_define_method(rb_cRuggedRepo, "cherrypick_commit", rb_git_repo_cherrypick_commit, -1);
2606
2662
  rb_define_method(rb_cRuggedRepo, "fetch_attributes", rb_git_repo_attributes, -1);
2607
2663
 
2608
2664
  rb_cRuggedOdbObject = rb_define_class_under(rb_mRugged, "OdbObject", rb_cObject);
@@ -190,6 +190,29 @@ static VALUE rb_git_walker_simplify_first_parent(VALUE self)
190
190
  return Qnil;
191
191
  }
192
192
 
193
+ /*
194
+ * call-seq:
195
+ * walker.count -> Fixnum
196
+ *
197
+ * Returns the amount of objects a walker iterated over.
198
+ */
199
+ static VALUE rb_git_walker_count(VALUE self)
200
+ {
201
+ git_revwalk *walk;
202
+ git_oid commit_oid;
203
+ int error = 0;
204
+ uint64_t count = 0;
205
+
206
+ Data_Get_Struct(self, git_revwalk, walk);
207
+
208
+ while (((error = git_revwalk_next(&commit_oid, walk)) == 0) && ++count != UINT64_MAX);
209
+
210
+ if (error != GIT_ITEROVER)
211
+ rugged_exception_check(error);
212
+
213
+ return ULONG2NUM(count);
214
+ }
215
+
193
216
  /*
194
217
  * call-seq:
195
218
  * walker.reset -> nil
@@ -492,4 +515,5 @@ void Init_rugged_revwalk(void)
492
515
  rb_define_method(rb_cRuggedWalker, "reset", rb_git_walker_reset, 0);
493
516
  rb_define_method(rb_cRuggedWalker, "sorting", rb_git_walker_sorting, 1);
494
517
  rb_define_method(rb_cRuggedWalker, "simplify_first_parent", rb_git_walker_simplify_first_parent, 0);
518
+ rb_define_method(rb_cRuggedWalker, "count", rb_git_walker_count, 0);
495
519
  }
data/lib/rugged/commit.rb CHANGED
@@ -9,6 +9,10 @@ module Rugged
9
9
  "#<Rugged::Commit:#{object_id} {message: #{message.inspect}, tree: #{tree.inspect}, parents: #{parent_oids}}>"
10
10
  end
11
11
 
12
+ def header_field?(field)
13
+ !!header_field(field)
14
+ end
15
+
12
16
  # Return a diff between this commit and its first parent or another commit or tree.
13
17
  #
14
18
  # See Rugged::Tree#diff for more details.
data/lib/rugged/tag.rb CHANGED
@@ -1,5 +1,24 @@
1
1
  module Rugged
2
2
  class Tag < Rugged::Reference
3
+ GPG_SIGNATURE_PREFIX = "-----BEGIN PGP SIGNATURE-----".freeze
4
+
5
+ def self.extract_signature(repo, oid, prefix=GPG_SIGNATURE_PREFIX)
6
+ object = repo.read(oid)
7
+
8
+ unless object.type == :tag
9
+ raise GitRPC::InvalidObject, "Invalid object type #{object.type}, expected tag"
10
+ end
11
+
12
+ if index = object.data.index(prefix)
13
+ [
14
+ object.data.byteslice(index..-1),
15
+ object.data.byteslice(0...index)
16
+ ]
17
+ else
18
+ [nil, object.data]
19
+ end
20
+ end
21
+
3
22
  def name
4
23
  canonical_name.sub(%r{^refs/tags/}, "")
5
24
  end
@@ -1,3 +1,3 @@
1
1
  module Rugged
2
- Version = VERSION = '0.24.0b12'
2
+ Version = VERSION = '0.24.0b13'
3
3
  end
@@ -257,7 +257,7 @@ IF (WIN32 AND WINHTTP)
257
257
  LINK_DIRECTORIES(${LIBWINHTTP_PATH})
258
258
  ENDIF ()
259
259
 
260
- LINK_LIBRARIES(winhttp rpcrt4 crypt32)
260
+ LINK_LIBRARIES(winhttp rpcrt4 crypt32 ole32)
261
261
  LIST(APPEND LIBGIT2_PC_LIBS "-lwinhttp" "-lrpcrt4" "-lcrypt32" "-lole32")
262
262
  ELSE ()
263
263
  IF (CURL)
@@ -340,7 +340,8 @@ IF (LIBSSH2_FOUND)
340
340
  ADD_DEFINITIONS(-DGIT_SSH)
341
341
  INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIRS})
342
342
  LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})
343
- SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} libssh2")
343
+ LIST(APPEND LIBGIT2_PC_LIBS ${LIBSSH2_LDFLAGS})
344
+ #SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} ${LIBSSH2_LDFLAGS}")
344
345
  SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
345
346
 
346
347
  CHECK_LIBRARY_EXISTS("${LIBSSH2_LIBRARIES}" libssh2_userauth_publickey_frommemory "${LIBSSH2_LIBRARY_DIRS}" HAVE_LIBSSH2_MEMORY_CREDENTIALS)
@@ -263,6 +263,18 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
263
263
  */
264
264
  GIT_EXTERN(int) git_commit_header_field(git_buf *out, const git_commit *commit, const char *field);
265
265
 
266
+ /**
267
+ * Extract the signature from a commit
268
+ *
269
+ * @param signature the signature block
270
+ * @param signed_data signed data; this is the commit contents minus the signature block
271
+ * @param repo the repository in which the commit exists
272
+ * @param commit_id the commit from which to extract the data
273
+ * @param field the name of the header field containing the signature
274
+ * block; pass `NULL` to extract the default 'gpgsig'
275
+ */
276
+ GIT_EXTERN(int) git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_repository *repo, git_oid *commit_id, const char *field);
277
+
266
278
  /**
267
279
  * Create new commit in the repository from a list of `git_object` pointers
268
280
  *
@@ -1194,7 +1194,7 @@ typedef enum {
1194
1194
  } git_diff_stats_format_t;
1195
1195
 
1196
1196
  /**
1197
- * Accumlate diff statistics for all patches.
1197
+ * Accumulate diff statistics for all patches.
1198
1198
  *
1199
1199
  * @param out Structure containg the diff statistics.
1200
1200
  * @param diff A git_diff generated by one of the above functions.
@@ -527,10 +527,6 @@ GIT_EXTERN(int) git_merge_trees(
527
527
  * or checked out. If the index is to be converted to a tree, the caller
528
528
  * should resolve any conflicts that arose as part of the merge.
529
529
  *
530
- * The merge performed uses the first common ancestor, unlike the
531
- * `git-merge-recursive` strategy, which may produce an artificial common
532
- * ancestor tree when there are multiple ancestors.
533
- *
534
530
  * The returned index must be freed explicitly with `git_index_free`.
535
531
  *
536
532
  * @param out pointer to store the index result in
@@ -553,10 +549,6 @@ GIT_EXTERN(int) git_merge_commits(
553
549
  * to the index. Callers should inspect the repository's index after this
554
550
  * completes, resolve any conflicts and prepare a commit.
555
551
  *
556
- * The merge performed uses the first common ancestor, unlike the
557
- * `git-merge-recursive` strategy, which may produce an artificial common
558
- * ancestor tree when there are multiple ancestors.
559
- *
560
552
  * For compatibility with git, the repository is put into a merging
561
553
  * state. Once the commit is done (or if the uses wishes to abort),
562
554
  * you should clear this state by calling
@@ -38,16 +38,30 @@ typedef struct {
38
38
  */
39
39
  int quiet;
40
40
 
41
+ /**
42
+ * Used by `git_rebase_init`, this will begin an in-memory rebase,
43
+ * which will allow callers to step through the rebase operations and
44
+ * commit the rebased changes, but will not rewind HEAD or update the
45
+ * repository to be in a rebasing state. This will not interfere with
46
+ * the working directory (if there is one).
47
+ */
48
+ int inmemory;
49
+
41
50
  /**
42
51
  * Used by `git_rebase_finish`, this is the name of the notes reference
43
52
  * used to rewrite notes for rebased commits when finishing the rebase;
44
- * if NULL, the contents of the coniguration option `notes.rewriteRef`
53
+ * if NULL, the contents of the configuration option `notes.rewriteRef`
45
54
  * is examined, unless the configuration option `notes.rewrite.rebase`
46
55
  * is set to false. If `notes.rewriteRef` is also NULL, notes will
47
56
  * not be rewritten.
48
57
  */
49
58
  const char *rewrite_notes_ref;
50
59
 
60
+ /**
61
+ * Options to control how trees are merged during `git_rebase_next`.
62
+ */
63
+ git_merge_options merge_options;
64
+
51
65
  /**
52
66
  * Options to control how files are written during `git_rebase_init`,
53
67
  * `git_checkout_next` and `git_checkout_abort`. Note that a minimum
@@ -101,7 +115,8 @@ typedef enum {
101
115
 
102
116
  #define GIT_REBASE_OPTIONS_VERSION 1
103
117
  #define GIT_REBASE_OPTIONS_INIT \
104
- {GIT_REBASE_OPTIONS_VERSION, 0, NULL, GIT_CHECKOUT_OPTIONS_INIT}
118
+ { GIT_REBASE_OPTIONS_VERSION, 0, 0, NULL, GIT_MERGE_OPTIONS_INIT, \
119
+ GIT_CHECKOUT_OPTIONS_INIT}
105
120
 
106
121
  /** Indicates that a rebase operation is not (yet) in progress. */
107
122
  #define GIT_REBASE_NO_OPERATION SIZE_MAX
@@ -226,6 +241,21 @@ GIT_EXTERN(int) git_rebase_next(
226
241
  git_rebase_operation **operation,
227
242
  git_rebase *rebase);
228
243
 
244
+ /**
245
+ * Gets the index produced by the last operation, which is the result
246
+ * of `git_rebase_next` and which will be committed by the next
247
+ * invocation of `git_rebase_commit`. This is useful for resolving
248
+ * conflicts in an in-memory rebase before committing them. You must
249
+ * call `git_index_free` when you are finished with this.
250
+ *
251
+ * This is only applicable for in-memory rebases; for rebases within
252
+ * a working directory, the changes were applied to the repository's
253
+ * index.
254
+ */
255
+ GIT_EXTERN(int) git_rebase_inmemory_index(
256
+ git_index **index,
257
+ git_rebase *rebase);
258
+
229
259
  /**
230
260
  * Commits the current patch. You must have resolved any conflicts that
231
261
  * were introduced during the patch application from the `git_rebase_next`
@@ -150,7 +150,7 @@ typedef struct git_stash_apply_options {
150
150
  * `GIT_STASH_APPLY_OPTIONS_INIT` here.
151
151
  * @return Zero on success; -1 on failure.
152
152
  */
153
- int git_stash_apply_init_options(
153
+ GIT_EXTERN(int) git_stash_apply_init_options(
154
154
  git_stash_apply_options *opts, unsigned int version);
155
155
 
156
156
  /**
@@ -123,7 +123,7 @@ int git_attr_file__load(
123
123
  break;
124
124
  }
125
125
  case GIT_ATTR_FILE__FROM_FILE: {
126
- int fd;
126
+ int fd = -1;
127
127
 
128
128
  /* For open or read errors, pretend that we got ENOTFOUND. */
129
129
  /* TODO: issue warning when warning API is available */
@@ -133,7 +133,8 @@ int git_attr_file__load(
133
133
  (fd = git_futils_open_ro(entry->fullpath)) < 0 ||
134
134
  (error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0)
135
135
  nonexistent = true;
136
- else
136
+
137
+ if (fd >= 0)
137
138
  p_close(fd);
138
139
 
139
140
  break;
@@ -1487,8 +1487,10 @@ static int blob_content_to_file(
1487
1487
  if (!data->opts.disable_filters &&
1488
1488
  (error = git_filter_list__load_ext(
1489
1489
  &fl, data->repo, blob, hint_path,
1490
- GIT_FILTER_TO_WORKTREE, &filter_opts)))
1490
+ GIT_FILTER_TO_WORKTREE, &filter_opts))) {
1491
+ p_close(fd);
1491
1492
  return error;
1493
+ }
1492
1494
 
1493
1495
  /* setup the writer */
1494
1496
  memset(&writer, 0, sizeof(struct checkout_stream));
@@ -2519,7 +2521,8 @@ int git_checkout_iterator(
2519
2521
 
2520
2522
  if (data.opts.baseline_index) {
2521
2523
  if ((error = git_iterator_for_index(
2522
- &baseline, data.opts.baseline_index, &baseline_opts)) < 0)
2524
+ &baseline, git_index_owner(data.opts.baseline_index),
2525
+ data.opts.baseline_index, &baseline_opts)) < 0)
2523
2526
  goto cleanup;
2524
2527
  } else {
2525
2528
  if ((error = git_iterator_for_tree(
@@ -2631,7 +2634,7 @@ int git_checkout_index(
2631
2634
  return error;
2632
2635
  GIT_REFCOUNT_INC(index);
2633
2636
 
2634
- if (!(error = git_iterator_for_index(&index_i, index, NULL)))
2637
+ if (!(error = git_iterator_for_index(&index_i, repo, index, NULL)))
2635
2638
  error = git_checkout_iterator(index_i, index, opts);
2636
2639
 
2637
2640
  if (owned)
@@ -564,17 +564,97 @@ int git_commit_nth_gen_ancestor(
564
564
 
565
565
  int git_commit_header_field(git_buf *out, const git_commit *commit, const char *field)
566
566
  {
567
- const char *buf = commit->raw_header;
568
- const char *h, *eol;
567
+ const char *eol, *buf = commit->raw_header;
569
568
 
570
569
  git_buf_sanitize(out);
570
+
571
+ while ((eol = strchr(buf, '\n'))) {
572
+ /* We can skip continuations here */
573
+ if (buf[0] == ' ') {
574
+ buf = eol + 1;
575
+ continue;
576
+ }
577
+
578
+ /* Skip until we find the field we're after */
579
+ if (git__prefixcmp(buf, field)) {
580
+ buf = eol + 1;
581
+ continue;
582
+ }
583
+
584
+ buf += strlen(field);
585
+ /* Check that we're not matching a prefix but the field itself */
586
+ if (buf[0] != ' ') {
587
+ buf = eol + 1;
588
+ continue;
589
+ }
590
+
591
+ buf++; /* skip the SP */
592
+
593
+ git_buf_put(out, buf, eol - buf);
594
+ if (git_buf_oom(out))
595
+ goto oom;
596
+
597
+ /* If the next line starts with SP, it's multi-line, we must continue */
598
+ while (eol[1] == ' ') {
599
+ git_buf_putc(out, '\n');
600
+ buf = eol + 2;
601
+ eol = strchr(buf, '\n');
602
+ if (!eol)
603
+ goto malformed;
604
+
605
+ git_buf_put(out, buf, eol - buf);
606
+ }
607
+
608
+ if (git_buf_oom(out))
609
+ goto oom;
610
+
611
+ return 0;
612
+ }
613
+
614
+ giterr_set(GITERR_OBJECT, "no such field '%s'", field);
615
+ return GIT_ENOTFOUND;
616
+
617
+ malformed:
618
+ giterr_set(GITERR_OBJECT, "malformed header");
619
+ return -1;
620
+ oom:
621
+ giterr_set_oom();
622
+ return -1;
623
+ }
624
+
625
+ int git_commit_extract_signature(git_buf *signature, git_buf *signed_data, git_repository *repo, git_oid *commit_id, const char *field)
626
+ {
627
+ git_odb_object *obj;
628
+ git_odb *odb;
629
+ const char *buf;
630
+ const char *h, *eol;
631
+ int error;
632
+
633
+ git_buf_sanitize(signature);
634
+ git_buf_sanitize(signed_data);
635
+
636
+ if (!field)
637
+ field = "gpgsig";
638
+
639
+ if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
640
+ return error;
641
+
642
+ if ((error = git_odb_read(&obj, odb, commit_id)) < 0)
643
+ return error;
644
+
645
+ buf = git_odb_object_data(obj);
646
+
571
647
  while ((h = strchr(buf, '\n')) && h[1] != '\0' && h[1] != '\n') {
572
648
  h++;
573
- if (git__prefixcmp(h, field)) {
649
+ if (git__prefixcmp(buf, field)) {
650
+ if (git_buf_put(signed_data, buf, h - buf) < 0)
651
+ return -1;
652
+
574
653
  buf = h;
575
654
  continue;
576
655
  }
577
656
 
657
+ h = buf;
578
658
  h += strlen(field);
579
659
  eol = strchr(h, '\n');
580
660
  if (h[0] != ' ') {
@@ -586,33 +666,44 @@ int git_commit_header_field(git_buf *out, const git_commit *commit, const char *
586
666
 
587
667
  h++; /* skip the SP */
588
668
 
589
- git_buf_put(out, h, eol - h);
590
- if (git_buf_oom(out))
669
+ git_buf_put(signature, h, eol - h);
670
+ if (git_buf_oom(signature))
591
671
  goto oom;
592
672
 
593
673
  /* If the next line starts with SP, it's multi-line, we must continue */
594
674
  while (eol[1] == ' ') {
595
- git_buf_putc(out, '\n');
675
+ git_buf_putc(signature, '\n');
596
676
  h = eol + 2;
597
677
  eol = strchr(h, '\n');
598
678
  if (!eol)
599
679
  goto malformed;
600
680
 
601
- git_buf_put(out, h, eol - h);
681
+ git_buf_put(signature, h, eol - h);
602
682
  }
603
683
 
604
- if (git_buf_oom(out))
684
+ if (git_buf_oom(signature))
605
685
  goto oom;
606
686
 
607
- return 0;
687
+ git_odb_object_free(obj);
688
+ return git_buf_puts(signed_data, eol+1);
608
689
  }
609
690
 
610
- return GIT_ENOTFOUND;
691
+ giterr_set(GITERR_INVALID, "this commit is not signed");
692
+ error = GIT_ENOTFOUND;
693
+ goto cleanup;
611
694
 
612
695
  malformed:
613
696
  giterr_set(GITERR_OBJECT, "malformed header");
614
- return -1;
697
+ error = -1;
698
+ goto cleanup;
615
699
  oom:
616
700
  giterr_set_oom();
617
- return -1;
701
+ error = -1;
702
+ goto cleanup;
703
+
704
+ cleanup:
705
+ git_odb_object_free(obj);
706
+ git_buf_clear(signature);
707
+ git_buf_clear(signed_data);
708
+ return error;
618
709
  }