1 module libgit2.example.fetch;
2 
3 
4 private static import core.stdc.stdio;
5 private static import core.stdc.stdlib;
6 private static import libgit2.example.common;
7 private static import libgit2.indexer;
8 private static import libgit2.oid;
9 private static import libgit2.remote;
10 private static import libgit2.types;
11 
12 extern (C)
13 nothrow @nogc
14 private int progress_cb(const (char)* str, int len, void* data)
15 
16 	in
17 	{
18 	}
19 
20 	do
21 	{
22 		//cast(void)(data);
23 		core.stdc.stdio.printf("remote: %.*s", len, str);
24 
25 		/* We don't have the \n to force the flush */
26 		core.stdc.stdio.fflush(core.stdc.stdio.stdout);
27 
28 		return 0;
29 	}
30 
31 /**
32  * This function gets called for each remote-tracking branch that gets
33  * updated. The message we output depends on whether it's a new one or
34  * an update.
35  */
36 extern (C)
37 nothrow @nogc
38 private int update_cb(const (char)* refname, const (libgit2.oid.git_oid)* a, const (libgit2.oid.git_oid)* b, void* data)
39 
40 	in
41 	{
42 	}
43 
44 	do
45 	{
46 		//cast(void)(data);
47 
48 		char[libgit2.oid.GIT_OID_SHA1_HEXSIZE + 1] b_str;
49 		libgit2.oid.git_oid_fmt(&(b_str[0]), b);
50 		b_str[libgit2.oid.GIT_OID_SHA1_HEXSIZE] = '\0';
51 
52 		if (libgit2.oid.git_oid_is_zero(a)) {
53 			core.stdc.stdio.printf("[new]     %.20s %s\n", &(b_str[0]), refname);
54 		} else {
55 			char[libgit2.oid.GIT_OID_SHA1_HEXSIZE + 1] a_str;
56 			libgit2.oid.git_oid_fmt(&(a_str[0]), a);
57 			a_str[libgit2.oid.GIT_OID_SHA1_HEXSIZE] = '\0';
58 			core.stdc.stdio.printf("[updated] %.10s..%.10s %s\n", &(a_str[0]), &(b_str[0]), refname);
59 		}
60 
61 		return 0;
62 	}
63 
64 /**
65  * This gets called during the download and indexing. Here we show
66  * processed and total objects in the pack and the amount of received
67  * data. Most frontends will probably want to show a percentage and
68  * the download rate.
69  */
70 extern (C)
71 nothrow @nogc
72 private int transfer_progress_cb(const (libgit2.indexer.git_indexer_progress)* stats, void* payload)
73 
74 	in
75 	{
76 	}
77 
78 	do
79 	{
80 		//cast(void)(payload);
81 
82 		if (stats.received_objects == stats.total_objects) {
83 			core.stdc.stdio.printf("Resolving deltas %u/%u\r", stats.indexed_deltas, stats.total_deltas);
84 		} else if (stats.total_objects > 0) {
85 			core.stdc.stdio.printf("Received %u/%u objects (%u) in %" ~ libgit2.example.common.PRIuZ ~ " bytes\r", stats.received_objects, stats.total_objects, stats.indexed_objects, stats.received_bytes);
86 		}
87 
88 		return 0;
89 	}
90 
91 /**
92  * Entry point for this command
93  */
94 extern (C)
95 nothrow @nogc
96 public int lg2_fetch(libgit2.types.git_repository* repo, int argc, char** argv)
97 
98 	in
99 	{
100 	}
101 
102 	do
103 	{
104 		if (argc < 2) {
105 			core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "usage: %s fetch <repo>\n", argv[-1]);
106 
107 			return core.stdc.stdlib.EXIT_FAILURE;
108 		}
109 
110 		/* Figure out whether it's a named remote or a URL */
111 		core.stdc.stdio.printf("Fetching %s for repo %p\n", argv[1], repo);
112 
113 		libgit2.types.git_remote* remote = null;
114 
115 		scope (exit) {
116 			libgit2.remote.git_remote_free(remote);
117 		}
118 
119 		if (libgit2.remote.git_remote_lookup(&remote, repo, argv[1]) < 0) {
120 			if (libgit2.remote.git_remote_create_anonymous(&remote, repo, argv[1]) < 0) {
121 				return -1;
122 			}
123 		}
124 
125 		/* Set up the callbacks (only update_tips for now) */
126 		libgit2.remote.git_fetch_options fetch_opts = libgit2.remote.GIT_FETCH_OPTIONS_INIT();
127 		fetch_opts.callbacks.update_tips = &.update_cb;
128 		fetch_opts.callbacks.sideband_progress = &.progress_cb;
129 		fetch_opts.callbacks.transfer_progress = &.transfer_progress_cb;
130 		fetch_opts.callbacks.credentials = &libgit2.example.common.cred_acquire_cb;
131 
132 		/**
133 		 * Perform the fetch with the configured refspecs from the
134 		 * config. Update the reflog for the updated references with
135 		 * "fetch".
136 		 */
137 		if (libgit2.remote.git_remote_fetch(remote, null, &fetch_opts, "fetch") < 0) {
138 			return -1;
139 		}
140 
141 		/**
142 		 * If there are local objects (we got a thin pack), then tell
143 		 * the user how many objects we saved from having to cross the
144 		 * network.
145 		 */
146 		const (libgit2.indexer.git_indexer_progress)* stats = libgit2.remote.git_remote_stats(remote);
147 
148 		if (stats.local_objects > 0) {
149 			core.stdc.stdio.printf("\rReceived %u/%u objects in %" ~ libgit2.example.common.PRIuZ ~ " bytes (used %u local objects)\n", stats.indexed_objects, stats.total_objects, stats.received_bytes, stats.local_objects);
150 		} else {
151 			core.stdc.stdio.printf("\rReceived %u/%u objects in %" ~ libgit2.example.common.PRIuZ ~ "bytes\n", stats.indexed_objects, stats.total_objects, stats.received_bytes);
152 		}
153 
154 		libgit2.remote.git_remote_free(remote);
155 
156 		return 0;
157 	}