1 /*
2  * libgit2 "general" example - shows basic libgit2 concepts
3  *
4  * Written by the libgit2 contributors
5  *
6  * To the extent possible under law, the author(s) have dedicated all copyright
7  * and related and neighboring rights to this software to the public domain
8  * worldwide. This software is distributed without any warranty.
9  *
10  * You should have received a copy of the CC0 Public Domain Dedication along
11  * with this software. If not, see
12  * <http://creativecommons.org/publicdomain/zero/1.0/>.
13  */
14 
15 /**
16  * [**libgit2**][lg] is a portable, pure C implementation of the Git core
17  * methods provided as a re-entrant linkable library with a solid API,
18  * allowing you to write native speed custom Git applications in any
19  * language which supports C bindings.
20  *
21  * This file is an example of using that API in a real, compilable C file.
22  * As the API is updated, this file will be updated to demonstrate the new
23  * functionality.
24  *
25  * If you're trying to write something in C using [libgit2][lg], you should
26  * also check out the generated [API documentation][ap]. We try to link to
27  * the relevant sections of the API docs in each section in this file.
28  *
29  * **libgit2** (for the most part) only implements the core plumbing
30  * functions, not really the higher level porcelain stuff. For a primer on
31  * Git Internals that you will need to know to work with Git at this level,
32  * check out [Chapter 10][pg] of the Pro Git book.
33  *
34  * [lg]: http://libgit2.github.com
35  * [ap]: http://libgit2.github.com/libgit2
36  * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
37  */
38 module libgit2_d.example.general;
39 
40 
41 private static import core.stdc.config;
42 private static import core.stdc.stdio;
43 private static import core.stdc.stdlib;
44 private static import core.stdc.time;
45 private static import libgit2_d.blob;
46 private static import libgit2_d.commit;
47 private static import libgit2_d.common;
48 private static import libgit2_d.config;
49 private static import libgit2_d.deprecated_;
50 private static import libgit2_d.errors;
51 private static import libgit2_d.global;
52 private static import libgit2_d.index;
53 private static import libgit2_d.object;
54 private static import libgit2_d.odb;
55 private static import libgit2_d.oid;
56 private static import libgit2_d.refs;
57 private static import libgit2_d.repository;
58 private static import libgit2_d.revwalk;
59 private static import libgit2_d.signature;
60 private static import libgit2_d.strarray;
61 private static import libgit2_d.tag;
62 private static import libgit2_d.tree;
63 private static import libgit2_d.types;
64 
65 package:
66 
67 /**
68  * ### Includes
69  *
70  * Including the `git2.h` header will include all the other libgit2 headers
71  * that you need.  It should be the only thing you need to include in order
72  * to compile properly and get all the libgit2 API.
73  */
74 //private void oid_parsing(libgit2_d.oid.git_oid* out_);
75 //private void object_database(libgit2_d.types.git_repository* repo, libgit2_d.oid.git_oid* oid);
76 //private void commit_writing(libgit2_d.types.git_repository* repo);
77 //private void commit_parsing(libgit2_d.types.git_repository* repo);
78 //private void tag_parsing(libgit2_d.types.git_repository* repo);
79 //private void tree_parsing(libgit2_d.types.git_repository* repo);
80 //private void blob_parsing(libgit2_d.types.git_repository* repo);
81 //private void revwalking(libgit2_d.types.git_repository* repo);
82 //private void index_walking(libgit2_d.types.git_repository* repo);
83 //private void reference_listing(libgit2_d.types.git_repository* repo);
84 //private void config_files(const (char)* repo_path, libgit2_d.types.git_repository* repo);
85 
86 /**
87  * Almost all libgit2 functions return 0 on success or negative on error.
88  * This is not production quality error checking, but should be sufficient
89  * as an example.
90  */
91 nothrow @nogc
92 private void check_error(int error_code, const (char)* action)
93 
94 	in
95 	{
96 	}
97 
98 	do
99 	{
100 		const (libgit2_d.errors.git_error)* error = libgit2_d.errors.git_error_last();
101 
102 		if (!error_code) {
103 			return;
104 		}
105 
106 		core.stdc.stdio.printf("Error %d %s - %s\n", error_code, action, ((error) && (error.message)) ? (error.message) : ("???"));
107 
108 		core.stdc.stdlib.exit(1);
109 	}
110 
111 extern (C)
112 nothrow @nogc
113 public int lg2_general(libgit2_d.types.git_repository* repo, int argc, char** argv)
114 
115 	in
116 	{
117 	}
118 
119 	do
120 	{
121 		/**
122 		 * Initialize the library, this will set up any global state which libgit2 needs
123 		 * including threading and crypto
124 		 */
125 		libgit2_d.global.git_libgit2_init();
126 
127 		/**
128 		 * ### Opening the Repository
129 		 *
130 		 * There are a couple of methods for opening a repository, this being the
131 		 * simplest.  There are also [methods][me] for specifying the index file
132 		 * and work tree locations, here we assume they are in the normal places.
133 		 *
134 		 * (Try running this program against tests/resources/testrepo.git.)
135 		 *
136 		 * [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
137 		 */
138 		const char* repo_path = (argc > 1) ? (argv[1]) : ("/opt/libgit2-test/.git");
139 
140 		int error = libgit2_d.repository.git_repository_open(&repo, repo_path);
141 		.check_error(error, "opening repository");
142 
143 		libgit2_d.oid.git_oid oid;
144 		.oid_parsing(&oid);
145 		.object_database(repo, &oid);
146 		.commit_writing(repo);
147 		.commit_parsing(repo);
148 		.tag_parsing(repo);
149 		.tree_parsing(repo);
150 		.blob_parsing(repo);
151 		.revwalking(repo);
152 		.index_walking(repo);
153 		.reference_listing(repo);
154 		.config_files(repo_path, repo);
155 
156 		/**
157 		 * Finally, when you're done with the repository, you can free it as well.
158 		 */
159 		libgit2_d.repository.git_repository_free(repo);
160 
161 		return 0;
162 	}
163 
164 /**
165  * ### SHA-1 Value Conversions
166  */
167 nothrow @nogc
168 private void oid_parsing(libgit2_d.oid.git_oid* oid)
169 
170 	in
171 	{
172 	}
173 
174 	do
175 	{
176 		core.stdc.stdio.printf("*Hex to Raw*\n");
177 
178 		/**
179 		 * For our first example, we will convert a 40 character hex value to the
180 		 * 20 byte raw SHA1 value.
181 		 *
182 		 * The `libgit2_d.oid.git_oid` is the structure that keeps the SHA value. We will use
183 		 * this throughout the example for storing the value of the current SHA
184 		 * key we're working with.
185 		 */
186 		const char* hex = "4a202b346bb0fb0db7eff3cffeb3c70babbd2045";
187 		libgit2_d.oid.git_oid_fromstr(oid, hex);
188 
189 		/*
190 		 * Once we've converted the string into the oid value, we can get the raw
191 		 * value of the SHA by accessing `oid.id`
192 		 *
193 		 * Next we will convert the 20 byte raw SHA1 value to a human readable 40
194 		 * char hex value.
195 		 */
196 		core.stdc.stdio.printf("\n*Raw to Hex*\n");
197 		char[libgit2_d.oid.GIT_OID_HEXSZ + 1] out_ = '\0';
198 
199 		/**
200 		 * If you have a oid, you can easily get the hex value of the SHA as well.
201 		 */
202 		libgit2_d.oid.git_oid_fmt(&(out_[0]), oid);
203 
204 		/**
205 		 * If you have a oid, you can easily get the hex value of the SHA as well.
206 		 */
207 		libgit2_d.oid.git_oid_fmt(&(out_[0]), oid);
208 		core.stdc.stdio.printf("SHA hex string: %s\n", &(out_[0]));
209 	}
210 
211 /**
212  * ### Working with the Object Database
213  *
214  * **libgit2** provides [direct access][odb] to the object database.  The
215  * object database is where the actual objects are stored in Git. For
216  * working with raw objects, we'll need to get this structure from the
217  * repository.
218  *
219  * [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb
220  */
221 nothrow @nogc
222 private void object_database(libgit2_d.types.git_repository* repo, libgit2_d.oid.git_oid* oid)
223 
224 	in
225 	{
226 	}
227 
228 	do
229 	{
230 		libgit2_d.types.git_odb* odb;
231 		libgit2_d.repository.git_repository_odb(&odb, repo);
232 
233 		/**
234 		 * #### Raw Object Reading
235 		 */
236 
237 		core.stdc.stdio.printf("\n*Raw Object Read*\n");
238 
239 		/**
240 		 * We can read raw objects directly from the object database if we have
241 		 * the oid (SHA) of the object.  This allows us to access objects without
242 		 * knowing their type and inspect the raw bytes unparsed.
243 		 */
244 		libgit2_d.types.git_odb_object* obj;
245 		int error = libgit2_d.odb.git_odb_read(&obj, odb, oid);
246 		.check_error(error, "finding object in repository");
247 
248 		/**
249 		 * A raw object only has three properties - the type (commit, blob, tree
250 		 * or tag), the size of the raw data and the raw, unparsed data itself.
251 		 * For a commit or tag, that raw data is human readable plain ASCII
252 		 * text. For a blob it is just file contents, so it could be text or
253 		 * binary data. For a tree it is a special binary format, so it's unlikely
254 		 * to be hugely helpful as a raw object.
255 		 */
256 		const (ubyte)* data = cast(const (ubyte)*)(libgit2_d.odb.git_odb_object_data(obj));
257 		libgit2_d.types.git_object_t otype = libgit2_d.odb.git_odb_object_type(obj);
258 
259 		/**
260 		 * We provide methods to convert from the object type which is an enum, to
261 		 * a string representation of that value (and vice-versa).
262 		 */
263 		const (char)* str_type = libgit2_d.object.git_object_type2string(otype);
264 		core.stdc.stdio.printf("object length and type: %d, %s\nobject data: %s\n", cast(int)(libgit2_d.odb.git_odb_object_size(obj)), str_type, data);
265 
266 		/**
267 		 * For proper memory management, close the object when you are done with
268 		 * it or it will leak memory.
269 		 */
270 		libgit2_d.odb.git_odb_object_free(obj);
271 
272 		/**
273 		 * #### Raw Object Writing
274 		 */
275 
276 		core.stdc.stdio.printf("\n*Raw Object Write*\n");
277 
278 		/**
279 		 * You can also write raw object data to Git. This is pretty cool because
280 		 * it gives you direct access to the key/value properties of Git.  Here
281 		 * we'll write a new blob object that just contains a simple string.
282 		 * Notice that we have to specify the object type as the `libgit2_d.deprecated_.git_object_t` enum.
283 		 */
284 		enum test_data = "test data";
285 		libgit2_d.odb.git_odb_write(oid, odb, test_data.ptr, test_data.length, libgit2_d.types.git_object_t.GIT_OBJECT_BLOB);
286 
287 		/**
288 		 * Now that we've written the object, we can check out what SHA1 was
289 		 * generated when the object was written to our database.
290 		 */
291 		char[libgit2_d.oid.GIT_OID_HEXSZ + 1] oid_hex  = '\0';
292 		libgit2_d.oid.git_oid_fmt(&(oid_hex[0]), oid);
293 		core.stdc.stdio.printf("Written Object: %s\n", &(oid_hex[0]));
294 
295 		/**
296 		 * Free the object database after usage.
297 		 */
298 		libgit2_d.odb.git_odb_free(odb);
299 	}
300 
301 /**
302  * #### Writing Commits
303  *
304  * libgit2 provides a couple of methods to create commit objects easily as
305  * well. There are four different create signatures, we'll just show one
306  * of them here.  You can read about the other ones in the [commit API
307  * docs][cd].
308  *
309  * [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit
310  */
311 nothrow @nogc
312 private void commit_writing(libgit2_d.types.git_repository* repo)
313 
314 	in
315 	{
316 	}
317 
318 	do
319 	{
320 		core.stdc.stdio.printf("\n*Commit Writing*\n");
321 
322 		/**
323 		 * Creating signatures for an authoring identity and time is simple.  You
324 		 * will need to do this to specify who created a commit and when.  Default
325 		 * values for the name and email should be found in the `user.name` and
326 		 * `user.email` configuration options.  See the `config` section of this
327 		 * example file to see how to access config values.
328 		 */
329 		libgit2_d.types.git_signature* author;
330 		libgit2_d.signature.git_signature_new(&author, "Scott Chacon", "schacon@gmail.com", 123456789, 60);
331 		libgit2_d.types.git_signature* committer;
332 		libgit2_d.signature.git_signature_new(&committer, "Scott A Chacon", "scott@github.com", 987654321, 90);
333 
334 		/**
335 		 * Commit objects need a tree to point to and optionally one or more
336 		 * parents.  Here we're creating oid objects to create the commit with,
337 		 * but you can also use
338 		 */
339 		libgit2_d.oid.git_oid tree_id;
340 		libgit2_d.oid.git_oid_fromstr(&tree_id, "f60079018b664e4e79329a7ef9559c8d9e0378d1");
341 		libgit2_d.types.git_tree* tree;
342 		libgit2_d.tree.git_tree_lookup(&tree, repo, &tree_id);
343 		libgit2_d.oid.git_oid parent_id;
344 		libgit2_d.oid.git_oid_fromstr(&parent_id, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
345 		libgit2_d.types.git_commit* parent;
346 		libgit2_d.commit.git_commit_lookup(&parent, repo, &parent_id);
347 
348 		/**
349 		 * Here we actually create the commit object with a single call with all
350 		 * the values we need to create the commit.  The SHA key is written to the
351 		 * `commit_id` variable here.
352 		 */
353 		libgit2_d.oid.git_oid commit_id;
354 		libgit2_d.commit.git_commit_create_v(&commit_id, /* out id */
355 			repo, null, /* do not update the HEAD */
356 			author, committer, null, /* use default message encoding */
357 			"example commit", tree, 1, parent);
358 
359 		/**
360 		 * Now we can take a look at the commit SHA we've generated.
361 		 */
362 		char[libgit2_d.oid.GIT_OID_HEXSZ + 1] oid_hex  = '\0';
363 		libgit2_d.oid.git_oid_fmt(&(oid_hex[0]), &commit_id);
364 		core.stdc.stdio.printf("New Commit: %s\n", &(oid_hex[0]));
365 
366 		/**
367 		 * Free all objects used in the meanwhile.
368 		 */
369 		libgit2_d.tree.git_tree_free(tree);
370 		libgit2_d.commit.git_commit_free(parent);
371 		libgit2_d.signature.git_signature_free(author);
372 		libgit2_d.signature.git_signature_free(committer);
373 	}
374 
375 /**
376  * ### Object Parsing
377  *
378  * libgit2 has methods to parse every object type in Git so you don't have
379  * to work directly with the raw data. This is much faster and simpler
380  * than trying to deal with the raw data yourself.
381  */
382 
383 /**
384  * #### Commit Parsing
385  *
386  * [Parsing commit objects][pco] is simple and gives you access to all the
387  * data in the commit - the author (name, email, datetime), committer
388  * (same), tree, message, encoding and parent(s).
389  *
390  * [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit
391  */
392 nothrow @nogc
393 private void commit_parsing(libgit2_d.types.git_repository* repo)
394 
395 	in
396 	{
397 	}
398 
399 	do
400 	{
401 		core.stdc.stdio.printf("\n*Commit Parsing*\n");
402 
403 		libgit2_d.oid.git_oid oid;
404 		libgit2_d.oid.git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479");
405 
406 		libgit2_d.types.git_commit* commit;
407 		int error = libgit2_d.commit.git_commit_lookup(&commit, repo, &oid);
408 		.check_error(error, "looking up commit");
409 
410 		/**
411 		 * Each of the properties of the commit object are accessible via methods,
412 		 * including commonly needed variations, such as `libgit2_d.commit.git_commit_time` which
413 		 * returns the author time and `libgit2_d.commit.git_commit_message` which gives you the
414 		 * commit message (as a NUL-terminated string).
415 		 */
416 		const (char)* message = libgit2_d.commit.git_commit_message(commit);
417 		const (libgit2_d.types.git_signature)* author = libgit2_d.commit.git_commit_author(commit);
418 		const (libgit2_d.types.git_signature)* cmtter = libgit2_d.commit.git_commit_committer(commit);
419 
420 		//ToDo:
421 		//core.stdc.time.time_t time = libgit2_d.commit.git_commit_time(commit);
422 		core.stdc.time.time_t time = cast(core.stdc.time.time_t)(libgit2_d.commit.git_commit_time(commit));
423 
424 		/**
425 		 * The author and committer methods return [libgit2_d.types.git_signature] structures,
426 		 * which give you name, email and `when`, which is a `libgit2_d.types.git_time` structure,
427 		 * giving you a timestamp and timezone offset.
428 		 */
429 		core.stdc.stdio.printf("Author: %s (%s)\nCommitter: %s (%s)\nDate: %s\nMessage: %s\n", author.name, author.email, cmtter.name, cmtter.email, core.stdc.time.ctime(&time), message);
430 
431 		/**
432 		 * Commits can have zero or more parents. The first (root) commit will
433 		 * have no parents, most commits will have one (i.e. the commit it was
434 		 * based on) and merge commits will have two or more.  Commits can
435 		 * technically have any number, though it's rare to have more than two.
436 		 */
437 		uint parents = libgit2_d.commit.git_commit_parentcount(commit);
438 
439 		char[libgit2_d.oid.GIT_OID_HEXSZ + 1] oid_hex;
440 		libgit2_d.types.git_commit* parent;
441 
442 		for (uint p = 0; p < parents; p++) {
443 			oid_hex[] = 0;
444 
445 			libgit2_d.commit.git_commit_parent(&parent, commit, p);
446 			libgit2_d.oid.git_oid_fmt(&(oid_hex[0]), libgit2_d.commit.git_commit_id(parent));
447 			core.stdc.stdio.printf("Parent: %s\n", &(oid_hex[0]));
448 			libgit2_d.commit.git_commit_free(parent);
449 		}
450 
451 		libgit2_d.commit.git_commit_free(commit);
452 	}
453 
454 /**
455  * #### Tag Parsing
456  *
457  * You can parse and create tags with the [tag management API][core.stdc.time.tm], which
458  * functions very similarly to the commit lookup, parsing and creation
459  * methods, since the objects themselves are very similar.
460  *
461  * [core.stdc.time.tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag
462  */
463 nothrow @nogc
464 private void tag_parsing(libgit2_d.types.git_repository* repo)
465 
466 	in
467 	{
468 	}
469 
470 	do
471 	{
472 		core.stdc.stdio.printf("\n*Tag Parsing*\n");
473 
474 		/**
475 		 * We create an oid for the tag object if we know the SHA and look it up
476 		 * the same way that we would a commit (or any other object).
477 		 */
478 		libgit2_d.oid.git_oid oid;
479 		libgit2_d.oid.git_oid_fromstr(&oid, "b25fa35b38051e4ae45d4222e795f9df2e43f1d1");
480 
481 		libgit2_d.types.git_tag* tag;
482 		int error = libgit2_d.tag.git_tag_lookup(&tag, repo, &oid);
483 		.check_error(error, "looking up tag");
484 
485 		/**
486 		 * Now that we have the tag object, we can extract the information it
487 		 * generally contains: the target (usually a commit object), the type of
488 		 * the target object (usually 'commit'), the name ('v1.0'), the tagger (a
489 		 * git_signature - name, email, timestamp), and the tag message.
490 		 */
491 		libgit2_d.types.git_commit* commit;
492 		libgit2_d.tag.git_tag_target(cast(libgit2_d.types.git_object**)(&commit), tag);
493 
494 		/* "test" */
495 		const (char)* name = libgit2_d.tag.git_tag_name(tag);
496 
497 		/* libgit2_d.types.git_object_t.GIT_OBJECT_COMMIT (object_t enum) */
498 		libgit2_d.types.git_object_t type = libgit2_d.tag.git_tag_target_type(tag);
499 
500 		/* "tag message\n" */
501 		const (char)* message = libgit2_d.tag.git_tag_message(tag);
502 
503 		core.stdc.stdio.printf("Tag Name: %s\nTag Type: %s\nTag Message: %s\n", name, libgit2_d.object.git_object_type2string(type), message);
504 
505 		/**
506 		 * Free both the commit and tag after usage.
507 		 */
508 		libgit2_d.commit.git_commit_free(commit);
509 		libgit2_d.tag.git_tag_free(tag);
510 	}
511 
512 /**
513  * #### Tree Parsing
514  *
515  * [Tree parsing][tp] is a bit different than the other objects, in that
516  * we have a subtype which is the tree entry.  This is not an actual
517  * object type in Git, but a useful structure for parsing and traversing
518  * tree entries.
519  *
520  * [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree
521  */
522 nothrow @nogc
523 private void tree_parsing(libgit2_d.types.git_repository* repo)
524 
525 	in
526 	{
527 	}
528 
529 	do
530 	{
531 		core.stdc.stdio.printf("\n*Tree Parsing*\n");
532 
533 		/**
534 		 * Create the oid and lookup the tree object just like the other objects.
535 		 */
536 		libgit2_d.oid.git_oid oid;
537 		libgit2_d.oid.git_oid_fromstr(&oid, "f60079018b664e4e79329a7ef9559c8d9e0378d1");
538 		libgit2_d.types.git_tree* tree;
539 		libgit2_d.tree.git_tree_lookup(&tree, repo, &oid);
540 
541 		/**
542 		 * Getting the count of entries in the tree so you can iterate over them
543 		 * if you want to.
544 		 */
545 		/* 2 */
546 		size_t cnt = libgit2_d.tree.git_tree_entrycount(tree);
547 
548 		core.stdc.stdio.printf("tree entries: %d\n", cast(int)(cnt));
549 
550 		const (libgit2_d.types.git_tree_entry)* entry = libgit2_d.tree.git_tree_entry_byindex(tree, 0);
551 
552 		/* "README" */
553 		core.stdc.stdio.printf("Entry name: %s\n", libgit2_d.tree.git_tree_entry_name(entry));
554 
555 		/**
556 		 * You can also access tree entries by name if you know the name of the
557 		 * entry you're looking for.
558 		 */
559 		entry = libgit2_d.tree.git_tree_entry_byname(tree, "README");
560 
561 		/* "README" */
562 		libgit2_d.tree.git_tree_entry_name(entry);
563 
564 		/**
565 		 * Once you have the entry object, you can access the content or subtree
566 		 * (or commit, in the case of submodules) that it points to.  You can also
567 		 * get the mode if you want.
568 		 */
569 		libgit2_d.types.git_object* obj;
570 
571 		/* blob */
572 		libgit2_d.tree.git_tree_entry_to_object(&obj, repo, entry);
573 
574 		/**
575 		 * Remember to close the looked-up object and tree once you are done using it
576 		 */
577 		libgit2_d.object.git_object_free(obj);
578 		libgit2_d.tree.git_tree_free(tree);
579 	}
580 
581 /**
582  * #### Blob Parsing
583  *
584  * The last object type is the simplest and requires the least parsing
585  * help. Blobs are just file contents and can contain anything, there is
586  * no structure to it. The main advantage to using the [simple blob
587  * api][ba] is that when you're creating blobs you don't have to calculate
588  * the size of the content.  There is also a helper for reading a file
589  * from disk and writing it to the db and getting the oid back so you
590  * don't have to do all those steps yourself.
591  *
592  * [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob
593  */
594 nothrow @nogc
595 private void blob_parsing(libgit2_d.types.git_repository* repo)
596 
597 	in
598 	{
599 	}
600 
601 	do
602 	{
603 		core.stdc.stdio.printf("\n*Blob Parsing*\n");
604 
605 		libgit2_d.oid.git_oid oid;
606 		libgit2_d.oid.git_oid_fromstr(&oid, "1385f264afb75a56a5bec74243be9b367ba4ca08");
607 		libgit2_d.types.git_blob* blob;
608 		libgit2_d.blob.git_blob_lookup(&blob, repo, &oid);
609 
610 		/**
611 		 * You can access a buffer with the raw contents of the blob directly.
612 		 * Note that this buffer may not be contain ASCII data for certain blobs
613 		 * (e.g. binary files): do not consider the buffer a null-terminated
614 		 * string, and use the `libgit2_d.blob.git_blob_rawsize` attribute to find out its exact
615 		 * size in bytes
616 		 */
617 		/* 8 */
618 		core.stdc.stdio.printf("Blob Size: %ld\n", cast(core.stdc.config.c_long)(libgit2_d.blob.git_blob_rawsize(blob)));
619 
620 		/* "content" */
621 		libgit2_d.blob.git_blob_rawcontent(blob);
622 
623 		/**
624 		 * Free the blob after usage.
625 		 */
626 		libgit2_d.blob.git_blob_free(blob);
627 	}
628 
629 /**
630  * ### Revwalking
631  *
632  * The libgit2 [revision walking api][rw] provides methods to traverse the
633  * directed graph created by the parent pointers of the commit objects.
634  * Since all commits point back to the commit that came directly before
635  * them, you can walk this parentage as a graph and find all the commits
636  * that were ancestors of (reachable from) a given starting point.  This
637  * can allow you to create `git log` type functionality.
638  *
639  * [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk
640  */
641 nothrow @nogc
642 private void revwalking(libgit2_d.types.git_repository* repo)
643 
644 	in
645 	{
646 	}
647 
648 	do
649 	{
650 		core.stdc.stdio.printf("\n*Revwalking*\n");
651 
652 		libgit2_d.oid.git_oid oid;
653 		libgit2_d.oid.git_oid_fromstr(&oid, "5b5b025afb0b4c913b4c338a42934a3863bf3644");
654 
655 		/**
656 		 * To use the revwalker, create a new walker, tell it how you want to sort
657 		 * the output and then push one or more starting points onto the walker.
658 		 * If you want to emulate the output of `git log` you would push the SHA
659 		 * of the commit that HEAD points to into the walker and then start
660 		 * traversing them.  You can also 'hide' commits that you want to stop at
661 		 * or not see any of their ancestors.  So if you want to emulate `git log
662 		 * branch1..branch2`, you would push the oid of `branch2` and hide the oid
663 		 * of `branch1`.
664 		 */
665 		libgit2_d.types.git_revwalk* walk;
666 		libgit2_d.revwalk.git_revwalk_new(&walk, repo);
667 		libgit2_d.revwalk.git_revwalk_sorting(walk, libgit2_d.revwalk.git_sort_t.GIT_SORT_TOPOLOGICAL | libgit2_d.revwalk.git_sort_t.GIT_SORT_REVERSE);
668 		libgit2_d.revwalk.git_revwalk_push(walk, &oid);
669 
670 		/**
671 		 * Now that we have the starting point pushed onto the walker, we start
672 		 * asking for ancestors. It will return them in the sorting order we asked
673 		 * for as commit oids.  We can then lookup and parse the committed pointed
674 		 * at by the returned OID; note that this operation is specially fast
675 		 * since the raw contents of the commit object will be cached in memory
676 		 */
677 		libgit2_d.types.git_commit* wcommit;
678 
679 		while ((libgit2_d.revwalk.git_revwalk_next(&oid, walk)) == 0) {
680 			int error = libgit2_d.commit.git_commit_lookup(&wcommit, repo, &oid);
681 			.check_error(error, "looking up commit during revwalk");
682 
683 			const (char)* cmsg = libgit2_d.commit.git_commit_message(wcommit);
684 			const (libgit2_d.types.git_signature)* cauth = libgit2_d.commit.git_commit_author(wcommit);
685 			core.stdc.stdio.printf("%s (%s)\n", cmsg, cauth.email);
686 
687 			libgit2_d.commit.git_commit_free(wcommit);
688 		}
689 
690 		/**
691 		 * Like the other objects, be sure to free the revwalker when you're done
692 		 * to prevent memory leaks.  Also, make sure that the repository being
693 		 * walked it not deallocated while the walk is in progress, or it will
694 		 * result in undefined behavior
695 		 */
696 		libgit2_d.revwalk.git_revwalk_free(walk);
697 	}
698 
699 /**
700  * ### Index File Manipulation *
701  * The [index file API][gi] allows you to read, traverse, update and write
702  * the Git index file (sometimes thought of as the staging area).
703  *
704  * [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index
705  */
706 nothrow @nogc
707 private void index_walking(libgit2_d.types.git_repository* repo)
708 
709 	in
710 	{
711 	}
712 
713 	do
714 	{
715 		core.stdc.stdio.printf("\n*Index Walking*\n");
716 
717 		/**
718 		 * You can either open the index from the standard location in an open
719 		 * repository, as we're doing here, or you can open and manipulate any
720 		 * index file with `git_index_open_bare()`. The index for the repository
721 		 * will be located and loaded from disk.
722 		 */
723 		libgit2_d.types.git_index* index;
724 		libgit2_d.repository.git_repository_index(&index, repo);
725 
726 		/**
727 		 * For each entry in the index, you can get a bunch of information
728 		 * including the SHA (oid), path and mode which map to the tree objects
729 		 * that are written out.  It also has filesystem properties to help
730 		 * determine what to inspect for changes (ctime, mtime, dev, ino, uid,
731 		 * gid, file_size and flags) All these properties are exported publicly in
732 		 * the `libgit2_d.index.git_index_entry` struct
733 		 */
734 		size_t ecount = libgit2_d.index.git_index_entrycount(index);
735 
736 		for (size_t i = 0; i < ecount; ++i) {
737 			const (libgit2_d.index.git_index_entry)* e = libgit2_d.index.git_index_get_byindex(index, i);
738 
739 			core.stdc.stdio.printf("path: %s\n", e.path);
740 			core.stdc.stdio.printf("mtime: %d\n", cast(int)(e.mtime.seconds));
741 			core.stdc.stdio.printf("fs: %d\n", cast(int)(e.file_size));
742 		}
743 
744 		libgit2_d.index.git_index_free(index);
745 	}
746 
747 /**
748  * ### References
749  *
750  * The [reference API][ref] allows you to list, resolve, create and update
751  * references such as branches, tags and remote references (everything in
752  * the .git/refs directory).
753  *
754  * [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference
755  */
756 nothrow @nogc
757 private void reference_listing(libgit2_d.types.git_repository* repo)
758 
759 	in
760 	{
761 	}
762 
763 	do
764 	{
765 		core.stdc.stdio.printf("\n*Reference Listing*\n");
766 
767 		/**
768 		 * Here we will implement something like `git for-each-ref` simply listing
769 		 * out all available references and the object SHA they resolve to.
770 		 *
771 		 * Now that we have the list of reference names, we can lookup each ref
772 		 * one at a time and resolve them to the SHA, then print both values out.
773 		 */
774 
775 		libgit2_d.strarray.git_strarray ref_list;
776 		libgit2_d.refs.git_reference_list(&ref_list, repo);
777 
778 		libgit2_d.types.git_reference* ref_;
779 
780 		for (uint i = 0; i < ref_list.count; ++i) {
781 			char[libgit2_d.oid.GIT_OID_HEXSZ + 1] oid_hex = libgit2_d.common.GIT_OID_HEX_ZERO;
782 			const (char)* refname = ref_list.strings[i];
783 			libgit2_d.refs.git_reference_lookup(&ref_, repo, refname);
784 
785 			switch (libgit2_d.refs.git_reference_type(ref_)) {
786 				case libgit2_d.types.git_reference_t.GIT_REFERENCE_DIRECT:
787 					libgit2_d.oid.git_oid_fmt(&(oid_hex[0]), libgit2_d.refs.git_reference_target(ref_));
788 					core.stdc.stdio.printf("%s [%s]\n", refname, &(oid_hex[0]));
789 
790 					break;
791 
792 				case libgit2_d.types.git_reference_t.GIT_REFERENCE_SYMBOLIC:
793 					core.stdc.stdio.printf("%s => %s\n", refname, libgit2_d.refs.git_reference_symbolic_target(ref_));
794 
795 					break;
796 
797 				default:
798 					core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "Unexpected reference type\n");
799 					core.stdc.stdlib.exit(1);
800 
801 					break;
802 			}
803 
804 			libgit2_d.refs.git_reference_free(ref_);
805 		}
806 
807 		libgit2_d.strarray.git_strarray_free(&ref_list);
808 	}
809 
810 /**
811  * ### Config Files
812  *
813  * The [config API][config] allows you to list and updatee config values
814  * in any of the accessible config file locations (system, global, local).
815  *
816  * [config]: http://libgit2.github.com/libgit2/#HEAD/group/config
817  */
818 nothrow @nogc
819 private void config_files(const (char)* repo_path, libgit2_d.types.git_repository* repo)
820 
821 	in
822 	{
823 	}
824 
825 	do
826 	{
827 		core.stdc.stdio.printf("\n*Config Listing*\n");
828 
829 		/**
830 		 * Open a config object so we can read global values from it.
831 		 */
832 		char[256] config_path;
833 		core.stdc.stdio.sprintf(&(config_path[0]), "%s/config", repo_path);
834 		libgit2_d.types.git_config* cfg;
835 		.check_error(libgit2_d.config.git_config_open_ondisk(&cfg, &(config_path[0])), "opening config");
836 
837 		int autocorrect;
838 
839 		if (libgit2_d.config.git_config_get_int32(&autocorrect, cfg, "help.autocorrect") == 0) {
840 			core.stdc.stdio.printf("Autocorrect: %d\n", autocorrect);
841 		}
842 
843 		libgit2_d.types.git_config* snap_cfg;
844 		.check_error(libgit2_d.repository.git_repository_config_snapshot(&snap_cfg, repo), "config snapshot");
845 		const (char)* email;
846 		libgit2_d.config.git_config_get_string(&email, snap_cfg, "user.email");
847 		core.stdc.stdio.printf("Email: %s\n", email);
848 
849 		int error_code = libgit2_d.config.git_config_get_int32(&autocorrect, cfg, "help.autocorrect");
850 
851 		switch (error_code) {
852 			case 0:
853 				core.stdc.stdio.printf("Autocorrect: %d\n", autocorrect);
854 
855 				break;
856 
857 			case libgit2_d.errors.git_error_code.GIT_ENOTFOUND:
858 				core.stdc.stdio.printf("Autocorrect: Undefined\n");
859 
860 				break;
861 
862 			default:
863 				.check_error(error_code, "get_int32 failed");
864 
865 				break;
866 		}
867 
868 		libgit2_d.config.git_config_free(cfg);
869 
870 		.check_error(libgit2_d.repository.git_repository_config_snapshot(&snap_cfg, repo), "config snapshot");
871 		error_code = libgit2_d.config.git_config_get_string(&email, snap_cfg, "user.email");
872 
873 		switch (error_code) {
874 			case 0:
875 				core.stdc.stdio.printf("Email: %s\n", email);
876 
877 				break;
878 
879 			case libgit2_d.errors.git_error_code.GIT_ENOTFOUND:
880 				core.stdc.stdio.printf("Email: Undefined\n");
881 
882 				break;
883 
884 			default:
885 				.check_error(error_code, "get_string failed");
886 
887 				break;
888 		}
889 
890 		libgit2_d.config.git_config_free(snap_cfg);
891 	}