[libgit2-glib] Bind blame file



commit 0e83587ead6e51b9c625de7e103761c1f74856f7
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Mon Nov 25 12:51:14 2013 +0100

    Bind blame file

 libgit2-glib/Makefile.am       |    2 +
 libgit2-glib/ggit-blame.c      |  341 ++++++++++++++++++++++++++++++++++++++++
 libgit2-glib/ggit-blame.h      |   87 ++++++++++
 libgit2-glib/ggit-repository.c |   46 ++++++
 libgit2-glib/ggit-repository.h |    5 +
 libgit2-glib/ggit-types.h      |   14 ++
 6 files changed, 495 insertions(+), 0 deletions(-)
---
diff --git a/libgit2-glib/Makefile.am b/libgit2-glib/Makefile.am
index 4173b1a..b85d497 100644
--- a/libgit2-glib/Makefile.am
+++ b/libgit2-glib/Makefile.am
@@ -18,6 +18,7 @@ libgit2_glib_1_0_la_LDFLAGS =                         \
 libgit2_glib_1_0_la_LIBADD = $(LIBGIT2_GLIB_LIBS)
 
 INST_H_FILES =                         \
+       ggit-blame.h                    \
        ggit-blame-options.h            \
        ggit-blob.h                     \
        ggit-blob-output-stream.h       \
@@ -74,6 +75,7 @@ NOINST_H_FILES =                      \
        ggit-utils.h
 
 C_FILES =                              \
+       ggit-blame.c                    \
        ggit-blame-options.c            \
        ggit-blob.c                     \
        ggit-blob-output-stream.c       \
diff --git a/libgit2-glib/ggit-blame.c b/libgit2-glib/ggit-blame.c
new file mode 100644
index 0000000..ae8e240
--- /dev/null
+++ b/libgit2-glib/ggit-blame.c
@@ -0,0 +1,341 @@
+/*
+ * ggit-blame.h
+ * This file is part of libgit2-glib
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * libgit2-glib is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libgit2-glib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ggit-blame.h"
+#include "ggit-oid.h"
+#include "ggit-signature.h"
+
+struct _GgitBlameHunk
+{
+       guint16 lines_in_hunk;
+
+       GgitOId       *final_commit_id;
+       guint16        final_start_line_number;
+       GgitSignature *final_signature;
+
+       GgitOId       *orig_commit_id;
+       gchar         *orig_path;
+       guint16        orig_start_line_number;
+       GgitSignature *orig_signature;
+
+       gboolean       boundary;
+
+       gint           ref_count;
+};
+
+G_DEFINE_TYPE (GgitBlame, ggit_blame, GGIT_TYPE_NATIVE)
+
+G_DEFINE_BOXED_TYPE (GgitBlameHunk, ggit_blame_hunk,
+                     ggit_blame_hunk_ref, ggit_blame_hunk_unref);
+
+/**
+ * ggit_blame_hunk_ref:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Atomically increments the reference count of @blame_hunk by one.
+ * This function is MT-safe and may be called from any thread.
+ *
+ * Returns: (transfer none): a #GgitBlameHunk.
+ */
+GgitBlameHunk *
+ggit_blame_hunk_ref (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       g_atomic_int_inc (&blame_hunk->ref_count);
+
+       return blame_hunk;
+}
+
+/**
+ * ggit_blame_hunk_unref:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Atomically decrements the reference count of @blame_hunk by one.
+ * If the reference count drops to 0, @blame_hunk is freed.
+ */
+void
+ggit_blame_hunk_unref (GgitBlameHunk *blame_hunk)
+{
+       g_return_if_fail (blame_hunk != NULL);
+
+       if (g_atomic_int_dec_and_test (&blame_hunk->ref_count))
+       {
+               if (blame_hunk->final_commit_id != NULL)
+               {
+                       ggit_oid_free (blame_hunk->final_commit_id);
+               }
+
+               g_clear_object (&blame_hunk->final_signature);
+
+               if (blame_hunk->orig_commit_id != NULL)
+               {
+                       ggit_oid_free (blame_hunk->orig_commit_id);
+               }
+
+               g_clear_object (&blame_hunk->orig_signature);
+
+               g_free (blame_hunk->orig_path);
+
+               g_slice_free (GgitBlameHunk, blame_hunk);
+       }
+}
+
+static GgitBlameHunk *
+ggit_blame_hunk_wrap (const git_blame_hunk *gblame_hunk)
+{
+       GgitBlameHunk *blame_hunk;
+
+       blame_hunk = g_slice_new0 (GgitBlameHunk);
+       blame_hunk->ref_count = 1;
+
+       blame_hunk->lines_in_hunk = gblame_hunk->lines_in_hunk;
+
+       blame_hunk->final_commit_id = _ggit_oid_wrap (&gblame_hunk->final_commit_id);
+       blame_hunk->final_start_line_number = gblame_hunk->final_start_line_number;
+
+       if (gblame_hunk->final_signature)
+       {
+               blame_hunk->final_signature =
+                       _ggit_signature_wrap (gblame_hunk->final_signature,
+                                             NULL,
+                                             FALSE);
+       }
+
+       blame_hunk->orig_commit_id = _ggit_oid_wrap (&gblame_hunk->orig_commit_id);
+       blame_hunk->orig_start_line_number = gblame_hunk->orig_start_line_number;
+
+       if (gblame_hunk->orig_signature)
+       {
+               blame_hunk->orig_signature =
+                       _ggit_signature_wrap (gblame_hunk->orig_signature,
+                                             NULL,
+                                             FALSE);
+       }
+
+       blame_hunk->orig_path = g_strdup (gblame_hunk->orig_path);
+       return blame_hunk;
+}
+
+/**
+ * ggit_blame_hunk_get_lines_in_hunk:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the number of lines in the hunk.
+ *
+ * Returns: the number of lines in the hunk.
+ *
+ **/
+guint16
+ggit_blame_hunk_get_lines_in_hunk (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, 0);
+
+       return blame_hunk->lines_in_hunk;
+}
+
+/**
+ * ggit_blame_hunk_get_final_commit_id:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the id of the commit where this hunk was last changed.
+ *
+ * Returns: (transfer none): a #GgitOId.
+ *
+ **/
+GgitOId *
+ggit_blame_hunk_get_final_commit_id (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       return blame_hunk->final_commit_id;
+}
+
+/**
+ * ggit_blame_hunk_get_final_start_line_number:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the line number where the hunk begins in the final version of the file.
+ * Line numbers start at 1.
+ *
+ * Returns: the final hunk line number.
+ *
+ **/
+guint16
+ggit_blame_hunk_get_final_start_line_number (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, 0);
+
+       return blame_hunk->final_start_line_number;
+}
+
+/**
+ * ggit_blame_hunk_get_final_signature:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the signature of the final version of the hunk.
+ *
+ * Returns: (transfer none): a #GgitSignature.
+ *
+ **/
+GgitSignature *
+ggit_blame_hunk_get_final_signature (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       return blame_hunk->final_signature;
+}
+
+/**
+ * ggit_blame_hunk_get_orig_commit_id:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the id of the commit where the hunk was found. This is usually the same
+ * the final commit id, except when #GGIT_BLAME_TRACK_COPIES_ANY_COMMIT was used.
+ *
+ * Returns: (transfer none): a #GgitOId.
+ *
+ **/
+GgitOId *
+ggit_blame_hunk_get_orig_commit_id (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       return blame_hunk->orig_commit_id;
+}
+
+/**
+ * ggit_blame_hunk_get_orig_start_line_number:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the line number where the hunk begins in the file specified by
+ * #ggit_blame_hunk_get_orig_path at the commit specified by
+ * #ggit_blame_hunk_get_orig_commit_id. Line numbers start at 1.
+ *
+ * Returns: the orig hunk line number.
+ *
+ **/
+guint16
+ggit_blame_hunk_get_orig_start_line_number (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, 0);
+
+       return blame_hunk->orig_start_line_number;
+}
+
+/**
+ * ggit_blame_hunk_get_orig_signature:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the signature of the commit specified by #ggit_blame_hunk_get_orig_commit_id.
+ *
+ * Returns: (transfer none): a #GgitSignature.
+ *
+ **/
+GgitSignature *
+ggit_blame_hunk_get_orig_signature (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       return blame_hunk->orig_signature;
+}
+
+/**
+ * ggit_blame_hunk_get_orig_path:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get the path of the file where this hunk originated, as of the commit
+ * specified by #ggit_blame_hunk_get_orig_commit_id.
+ *
+ * Returns: the path.
+ */
+const gchar *
+ggit_blame_hunk_get_orig_path (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, NULL);
+
+       return blame_hunk->orig_path;
+}
+
+/**
+ * ggit_blame_hunk_is_boundary:
+ * @blame_hunk: a #GgitBlameHunk.
+ *
+ * Get whether the hunk has been tracked to a boundary commit (the root,
+ * or the commit specified in #ggit_blame_options_set_oldest_commit).
+ *
+ * Returns: whether the hunk is at a boundary commit.
+ *
+ **/
+gboolean
+ggit_blame_hunk_is_boundary (GgitBlameHunk *blame_hunk)
+{
+       g_return_val_if_fail (blame_hunk != NULL, FALSE);
+
+       return blame_hunk->boundary;
+}
+
+static void
+ggit_blame_class_init (GgitBlameClass *klass)
+{
+}
+
+static void
+ggit_blame_init (GgitBlame *self)
+{
+}
+
+GgitBlame *
+_ggit_blame_wrap (git_blame *blame)
+{
+       GgitBlame *ret;
+
+       ret = g_object_new (GGIT_TYPE_BLAME, NULL);
+       _ggit_native_set (ret, blame, (GDestroyNotify)git_blame_free);
+
+       return ret;
+}
+
+guint32
+ggit_blame_get_hunk_count (GgitBlame *blame)
+{
+       g_return_val_if_fail (GGIT_IS_BLAME (blame), 0);
+       return git_blame_get_hunk_count (_ggit_native_get (blame));
+}
+
+GgitBlameHunk *
+ggit_blame_get_hunk_by_line (GgitBlame *blame,
+                             guint32    line)
+{
+       g_return_val_if_fail (GGIT_IS_BLAME (blame), NULL);
+
+       return ggit_blame_hunk_wrap (git_blame_get_hunk_byline (_ggit_native_get (blame),
+                                                               line));
+}
+
+GgitBlameHunk *
+ggit_blame_get_hunk_by_index (GgitBlame *blame,
+                              guint32    idx)
+{
+       g_return_val_if_fail (GGIT_IS_BLAME (blame), NULL);
+
+       return ggit_blame_hunk_wrap (git_blame_get_hunk_byindex (_ggit_native_get (blame),
+                                                                idx));
+} 
diff --git a/libgit2-glib/ggit-blame.h b/libgit2-glib/ggit-blame.h
new file mode 100644
index 0000000..cc562b2
--- /dev/null
+++ b/libgit2-glib/ggit-blame.h
@@ -0,0 +1,87 @@
+/*
+ * ggit-blame.h
+ * This file is part of libgit2-glib
+ *
+ * Copyright (C) 2013 - Jesse van den Kieboom
+ *
+ * libgit2-glib is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * libgit2-glib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GGIT_BLAME_H__
+#define __GGIT_BLAME_H__
+
+#include <glib-object.h>
+#include <libgit2-glib/ggit-native.h>
+#include <libgit2-glib/ggit-types.h>
+#include <git2.h>
+
+G_BEGIN_DECLS
+
+#define GGIT_TYPE_BLAME                        (ggit_blame_get_type ())
+#define GGIT_BLAME(obj)                        (G_TYPE_CHECK_INSTANCE_CAST ((obj), GGIT_TYPE_BLAME, 
GgitBlame))
+#define GGIT_BLAME_CONST(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GGIT_TYPE_BLAME, GgitBlame const))
+#define GGIT_BLAME_CLASS(klass)                (G_TYPE_CHECK_CLASS_CAST ((klass), GGIT_TYPE_BLAME, 
GgitBlameClass))
+#define GGIT_IS_BLAME(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GGIT_TYPE_BLAME))
+#define GGIT_IS_BLAME_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GGIT_TYPE_BLAME))
+#define GGIT_BLAME_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), GGIT_TYPE_BLAME, GgitBlameClass))
+
+typedef struct _GgitBlameClass         GgitBlameClass;
+
+struct _GgitBlame
+{
+       /*< private >*/
+       GgitNative parent;
+
+       /* priv padding */
+       gpointer priv;
+};
+
+struct _GgitBlameClass
+{
+       /*< private >*/
+       GgitNativeClass parent_class;
+};
+
+GType          ggit_blame_hunk_get_type (void) G_GNUC_CONST;
+GgitBlameHunk *ggit_blame_hunk_ref      (GgitBlameHunk *blame_hunk);
+void           ggit_blame_hunk_unref    (GgitBlameHunk *blame_hunk);
+
+guint16        ggit_blame_hunk_get_lines_in_hunk (GgitBlameHunk *blame_hunk);
+
+GgitOId       *ggit_blame_hunk_get_final_commit_id         (GgitBlameHunk *blame_hunk);
+guint16        ggit_blame_hunk_get_final_start_line_number (GgitBlameHunk *blame_hunk);
+GgitSignature *ggit_blame_hunk_get_final_signature         (GgitBlameHunk *blame_hunk);
+
+GgitOId       *ggit_blame_hunk_get_orig_commit_id          (GgitBlameHunk *blame_hunk);
+guint16        ggit_blame_hunk_get_orig_start_line_number  (GgitBlameHunk *blame_hunk);
+GgitSignature *ggit_blame_hunk_get_orig_signature          (GgitBlameHunk *blame_hunk);
+const gchar   *ggit_blame_hunk_get_orig_path               (GgitBlameHunk *blame_hunk);
+
+gboolean       ggit_blame_hunk_is_boundary                 (GgitBlameHunk *blame_hunk);
+
+GType ggit_blame_get_type (void) G_GNUC_CONST;
+
+GgitBlame     *_ggit_blame_wrap             (git_blame *blame);
+
+guint32        ggit_blame_get_hunk_count    (GgitBlame *blame);
+
+GgitBlameHunk *ggit_blame_get_hunk_by_line  (GgitBlame *blame,
+                                             guint32    line);
+
+GgitBlameHunk *ggit_blame_get_hunk_by_index (GgitBlame *blame,
+                                             guint32    idx);
+
+G_END_DECLS
+
+#endif /* __GGIT_BLAME_H__ */
diff --git a/libgit2-glib/ggit-repository.c b/libgit2-glib/ggit-repository.c
index d1fab4b..9e1d058 100644
--- a/libgit2-glib/ggit-repository.c
+++ b/libgit2-glib/ggit-repository.c
@@ -34,6 +34,8 @@
 #include "ggit-status-options.h"
 #include "ggit-tree-builder.h"
 #include "ggit-branch-enumerator.h"
+#include "ggit-blame.h"
+#include "ggit-blame-options.h"
 
 #define GGIT_REPOSITORY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GGIT_TYPE_REPOSITORY, 
GgitRepositoryPrivate))
 
@@ -2348,4 +2350,48 @@ ggit_repository_create_index_entry_for_path (GgitRepository  *repository,
        return ret;
 }
 
+/**
+ * ggit_repository_blame_file:
+ * @repository: a #GgitRepository.
+ * @file: the file to blame.
+ * @blame_options: (allow-none): blame options.
+ * @error: a #GError.
+ *
+ * Get a blame for a single file.
+ *
+ * Returns: (transfer full): a #GgitBlame.
+ *
+ **/
+GgitBlame *
+ggit_repository_blame_file (GgitRepository    *repository,
+                            GFile             *file,
+                            GgitBlameOptions  *blame_options,
+                            GError           **error)
+{
+       git_blame *blame;
+       gchar *path;
+       int ret;
+
+       g_return_val_if_fail (GGIT_IS_REPOSITORY (repository), NULL);
+       g_return_val_if_fail (G_IS_FILE (file), NULL);
+       g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+       path = g_file_get_relative_path (repository->priv->workdir, file);
+
+       ret = git_blame_file (&blame,
+                             _ggit_native_get (repository),
+                             path,
+                             _ggit_blame_options_get_blame_options (blame_options));
+
+       g_free (path);
+
+       if (ret != GIT_OK)
+       {
+               _ggit_error_set (error, ret);
+               return NULL;
+       }
+
+       return _ggit_blame_wrap (blame);
+}
+
 /* ex:set ts=8 noet: */
diff --git a/libgit2-glib/ggit-repository.h b/libgit2-glib/ggit-repository.h
index 94eac5e..8f2a348 100644
--- a/libgit2-glib/ggit-repository.h
+++ b/libgit2-glib/ggit-repository.h
@@ -305,6 +305,11 @@ void                ggit_repository_get_ahead_behind  (GgitRepository        *re
                                                        gsize                 *behind,
                                                        GError               **error);
 
+GgitBlame          *ggit_repository_blame_file        (GgitRepository        *repository,
+                                                       GFile                 *file,
+                                                       GgitBlameOptions      *blame_options,
+                                                       GError               **error);
+
 G_END_DECLS
 
 #endif /* __GGIT_REPOSITORY_H__ */
diff --git a/libgit2-glib/ggit-types.h b/libgit2-glib/ggit-types.h
index 7072206..97a9ae5 100644
--- a/libgit2-glib/ggit-types.h
+++ b/libgit2-glib/ggit-types.h
@@ -152,6 +152,20 @@ typedef struct _GgitDiffOptions GgitDiffOptions;
 typedef struct _GgitDiffSimilarityMetric GgitDiffSimilarityMetric;
 
 /**
+ * GgitBlame:
+ *
+ * Represents a blame.
+ */
+typedef struct _GgitBlame GgitBlame;
+
+/**
+ * GgitBlameHunk:
+ *
+ * Represents a blame hunk.
+ */
+typedef struct _GgitBlameHunk GgitBlameHunk;
+
+/**
  * GgitIndex:
  *
  * Represents an index object.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]