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