1 /*
2  * ggit-tree.c
3  * This file is part of libgit2-glib
4  *
5  * Copyright (C) 2012 - Jesse van den Kieboom
6  *
7  * libgit2-glib is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * libgit2-glib is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <git2.h>
22 
23 #include "ggit-tree.h"
24 #include "ggit-oid.h"
25 #include "ggit-error.h"
26 
27 /**
28  * GgitTree:
29  *
30  * Represents a tree object.
31  */
32 
G_DEFINE_TYPE(GgitTree,ggit_tree,GGIT_TYPE_OBJECT)33 G_DEFINE_TYPE (GgitTree, ggit_tree, GGIT_TYPE_OBJECT)
34 
35 static void
36 ggit_tree_class_init (GgitTreeClass *klass)
37 {
38 }
39 
40 static void
ggit_tree_init(GgitTree * self)41 ggit_tree_init (GgitTree *self)
42 {
43 }
44 
45 GgitTree *
_ggit_tree_wrap(git_tree * tree,gboolean owned)46 _ggit_tree_wrap (git_tree *tree,
47                  gboolean  owned)
48 {
49 	GgitTree *gtree;
50 
51 	gtree = g_object_new (GGIT_TYPE_TREE,
52 	                      "native", tree,
53 	                      NULL);
54 
55 	if (owned)
56 	{
57 		_ggit_native_set_destroy_func (gtree,
58 		                               (GDestroyNotify)git_object_free);
59 	}
60 
61 	return gtree;
62 }
63 
64 /**
65  * ggit_tree_get_id:
66  * @tree: a #GgitTree.
67  *
68  * Get the #GgitOId of the tree.
69  *
70  * Returns: (transfer full) (nullable): a #GgitOId or %NULL.
71  *
72  **/
73 GgitOId *
ggit_tree_get_id(GgitTree * tree)74 ggit_tree_get_id (GgitTree *tree)
75 {
76 	git_tree *t;
77 	const git_oid *oid;
78 
79 	g_return_val_if_fail (GGIT_IS_TREE (tree), NULL);
80 
81 	t = _ggit_native_get (tree);
82 
83 	oid = git_tree_id (t);
84 
85 	return _ggit_oid_wrap (oid);
86 }
87 
88 /**
89  * ggit_tree_get:
90  * @tree: a #GgitTree.
91  * @i: the index of the entry.
92  *
93  * Get a tree entry by index.
94  *
95  * Returns: (transfer full) (nullable): a #GgitTreeEntry or %NULL.
96  *
97  **/
98 GgitTreeEntry *
ggit_tree_get(GgitTree * tree,guint i)99 ggit_tree_get (GgitTree *tree,
100                guint     i)
101 {
102 	git_tree *t;
103 	const git_tree_entry *entry;
104 
105 	g_return_val_if_fail (GGIT_IS_TREE (tree), NULL);
106 
107 	t = _ggit_native_get (tree);
108 
109 	entry = git_tree_entry_byindex (t, i);
110 
111 	return _ggit_tree_entry_wrap ((git_tree_entry *)entry, FALSE);
112 }
113 
114 /**
115  * ggit_tree_size:
116  * @tree: a #GgitTree.
117  *
118  * Get the number of entries in the tree.
119  *
120  * Returns: the number of entries in the tree.
121  *
122  **/
123 guint
ggit_tree_size(GgitTree * tree)124 ggit_tree_size (GgitTree *tree)
125 {
126 	git_tree *t;
127 
128 	g_return_val_if_fail (GGIT_IS_TREE (tree), 0);
129 
130 	t = _ggit_native_get (tree);
131 
132 	return (guint)git_tree_entrycount (t);
133 }
134 
135 /**
136  * ggit_tree_get_by_name:
137  * @tree: a #GgitTree.
138  * @name: a filename.
139  *
140  * Get a tree entry by name.
141  *
142  * Returns: (transfer full) (nullable): a #GgitTreeEntry or %NULL.
143  *
144  **/
145 GgitTreeEntry *
ggit_tree_get_by_name(GgitTree * tree,const gchar * name)146 ggit_tree_get_by_name (GgitTree    *tree,
147                        const gchar *name)
148 {
149 	git_tree *t;
150 	GgitTreeEntry *entry = NULL;
151 	const git_tree_entry *tree_entry;
152 
153 	g_return_val_if_fail (GGIT_IS_TREE (tree), NULL);
154 	g_return_val_if_fail (name != NULL, NULL);
155 
156 	t = _ggit_native_get (tree);
157 
158 	tree_entry = git_tree_entry_byname (t, name);
159 
160 	if (tree_entry != NULL)
161 	{
162 		entry = _ggit_tree_entry_wrap ((git_tree_entry *)tree_entry, FALSE);
163 	}
164 
165 	return entry;
166 }
167 
168 /**
169  * ggit_tree_get_by_path:
170  * @tree: a #GgitTree.
171  * @path: a path.
172  * @error: a #GError for error reporting, or %NULL.
173  *
174  * Retrieves a tree entry contained in a tree or in any of its subtrees,
175  * given its relative path.
176  *
177  * Returns: (transfer full) (nullable): a #GgitTreeEntry or %NULL.
178  *
179  **/
180 GgitTreeEntry *
ggit_tree_get_by_path(GgitTree * tree,const gchar * path,GError ** error)181 ggit_tree_get_by_path (GgitTree     *tree,
182                        const gchar  *path,
183                        GError      **error)
184 {
185 	git_tree *t;
186 	GgitTreeEntry *entry = NULL;
187 	git_tree_entry *tree_entry;
188 	gint ret;
189 
190 	g_return_val_if_fail (GGIT_IS_TREE (tree), NULL);
191 	g_return_val_if_fail (path != NULL, NULL);
192 
193 	t = _ggit_native_get (tree);
194 
195 	ret = git_tree_entry_bypath (&tree_entry, t, path);
196 
197 	if (ret == GIT_OK)
198 	{
199 		entry = _ggit_tree_entry_wrap (tree_entry, TRUE);
200 	}
201 	else
202 	{
203 		_ggit_error_set (error, ret);
204 	}
205 
206 	return entry;
207 }
208 
209 typedef struct
210 {
211 	GgitTreeWalkCallback callback;
212 	gpointer user_data;
213 } WalkInfo;
214 
215 static int
walk_callback_wrapper(const char * root,const git_tree_entry * entry,gpointer payload)216 walk_callback_wrapper (const char           *root,
217                        const git_tree_entry *entry,
218                        gpointer              payload)
219 {
220 	gint ret;
221 	GgitTreeEntry *wentry;
222 	WalkInfo *info = (WalkInfo *)payload;
223 	git_tree_entry *dest;
224 
225 	ret = git_tree_entry_dup (&dest, entry);
226 	if (ret == GIT_OK)
227 	{
228 		wentry = _ggit_tree_entry_wrap (dest, TRUE);
229 
230 		ret = info->callback(root, wentry, info->user_data);
231 
232 		ggit_tree_entry_unref (wentry);
233 	}
234 
235 	return ret;
236 }
237 
238 /**
239  * ggit_tree_walk:
240  * @tree: a #GgitTree.
241  * @mode: the walking order.
242  * @callback: (scope call): the callback to call for each entry.
243  * @user_data: (closure): user data for the callback.
244  * @error: a #GError for error reporting, or %NULL.
245  *
246  * Walk all the entries of a tree object recursively (resolving and walking
247  * subtrees of the tree as needed). The @error will be set to the error returned
248  * by @callback (if any).
249  *
250  **/
251 void
ggit_tree_walk(GgitTree * tree,GgitTreeWalkMode mode,GgitTreeWalkCallback callback,gpointer user_data,GError ** error)252 ggit_tree_walk (GgitTree              *tree,
253                 GgitTreeWalkMode       mode,
254                 GgitTreeWalkCallback   callback,
255                 gpointer               user_data,
256                 GError               **error)
257 {
258 	gint ret;
259 	WalkInfo info = {0,};
260 
261 	g_return_if_fail (GGIT_IS_TREE (tree));
262 	g_return_if_fail (callback != NULL);
263 	g_return_if_fail (error == NULL || *error == NULL);
264 
265 	info.callback = callback;
266 	info.user_data = user_data;
267 
268 	ret = git_tree_walk (_ggit_native_get (tree),
269 	                     (git_treewalk_mode)mode,
270 	                     (git_treewalk_cb)walk_callback_wrapper,
271 	                     &info);
272 
273 	if (ret != GIT_OK)
274 	{
275 		_ggit_error_set (error, ret);
276 	}
277 }
278 
279 /* ex:set ts=8 noet: */
280