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