1 /*
2  * libgit2 "remote" example - shows how to modify remotes for a repo
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  * This is a sample program that is similar to "git remote".  See the
16  * documentation for that (try "git help remote") to understand what this
17  * program is emulating.
18  *
19  * This demonstrates using the libgit2 APIs to modify remotes of a repository.
20  *
21  * License: $(LINK2 https://creativecommons.org/publicdomain/zero/1.0/, CC0 1.0 Universal)
22  */
23 module libgit2.example.remote;
24 
25 
26 private static import core.stdc.stdio;
27 private static import core.stdc.stdlib;
28 private static import core.stdc.string;
29 private static import libgit2.example.common;
30 private static import libgit2.remote;
31 private static import libgit2.strarray;
32 private static import libgit2.types;
33 
34 public enum subcmd
35 {
36 	subcmd_add,
37 	subcmd_remove,
38 	subcmd_rename,
39 	subcmd_seturl,
40 	subcmd_show,
41 }
42 
43 //Declaration name in C language
44 public enum
45 {
46 	subcmd_add = .subcmd.subcmd_add,
47 	subcmd_remove = .subcmd.subcmd_remove,
48 	subcmd_rename = .subcmd.subcmd_rename,
49 	subcmd_seturl = .subcmd.subcmd_seturl,
50 	subcmd_show = .subcmd.subcmd_show,
51 }
52 
53 extern (C)
54 public struct remote_opts
55 {
56 	.subcmd cmd;
57 
58 	/* for command-specific args */
59 	int argc;
60 	char** argv;
61 }
62 
63 extern (C)
64 nothrow @nogc
65 public int lg2_remote(libgit2.types.git_repository* repo, int argc, char** argv)
66 
67 	in
68 	{
69 	}
70 
71 	do
72 	{
73 		int retval = 0;
74 		.remote_opts opt = .remote_opts.init;
75 
76 		.parse_subcmd(&opt, argc, argv);
77 
78 		switch (opt.cmd) {
79 			case .subcmd.subcmd_add:
80 				retval = .cmd_add(repo, &opt);
81 
82 				break;
83 
84 			case .subcmd.subcmd_remove:
85 				retval = .cmd_remove(repo, &opt);
86 
87 				break;
88 
89 			case .subcmd.subcmd_rename:
90 				retval = .cmd_rename(repo, &opt);
91 
92 				break;
93 
94 			case .subcmd.subcmd_seturl:
95 				retval = .cmd_seturl(repo, &opt);
96 
97 				break;
98 
99 			case .subcmd.subcmd_show:
100 				retval = .cmd_show(repo, &opt);
101 
102 				break;
103 
104 			default:
105 				break;
106 		}
107 
108 		return retval;
109 	}
110 
111 nothrow @nogc
112 private int cmd_add(libgit2.types.git_repository* repo, .remote_opts* o)
113 
114 	in
115 	{
116 	}
117 
118 	do
119 	{
120 		libgit2.types.git_remote* remote = null;
121 
122 		if (o.argc != 2) {
123 			.usage("you need to specify a name and URL", null);
124 		}
125 
126 		char* name = o.argv[0];
127 		char* url = o.argv[1];
128 
129 		libgit2.example.common.check_lg2(libgit2.remote.git_remote_create(&remote, repo, name, url), "could not create remote", null);
130 
131 		return 0;
132 	}
133 
134 nothrow @nogc
135 private int cmd_remove(libgit2.types.git_repository* repo, .remote_opts* o)
136 
137 	in
138 	{
139 	}
140 
141 	do
142 	{
143 		if (o.argc != 1) {
144 			.usage("you need to specify a name", null);
145 		}
146 
147 		char* name = o.argv[0];
148 
149 		libgit2.example.common.check_lg2(libgit2.remote.git_remote_delete(repo, name), "could not delete remote", name);
150 
151 		return 0;
152 	}
153 
154 nothrow @nogc
155 private int cmd_rename(libgit2.types.git_repository* repo, .remote_opts* o)
156 
157 	in
158 	{
159 	}
160 
161 	do
162 	{
163 		libgit2.strarray.git_strarray problems = libgit2.strarray.git_strarray.init;
164 
165 		if (o.argc != 2) {
166 			.usage("you need to specify old and new remote name", null);
167 		}
168 
169 		char* old = o.argv[0];
170 		char* new_ = o.argv[1];
171 
172 		int retval = libgit2.remote.git_remote_rename(&problems, repo, old, new_);
173 
174 		if (!retval) {
175 			return 0;
176 		}
177 
178 		for (int i = 0; i < cast(int)(problems.count); i++) {
179 			core.stdc.stdio.puts(problems.strings[0]);
180 		}
181 
182 		libgit2.strarray.git_strarray_dispose(&problems);
183 
184 		return retval;
185 	}
186 
187 nothrow @nogc
188 private int cmd_seturl(libgit2.types.git_repository* repo, .remote_opts* o)
189 
190 	in
191 	{
192 	}
193 
194 	do
195 	{
196 		int push = 0;
197 		char* name = null;
198 		char* url = null;
199 
200 		for (int i = 0; i < o.argc; i++) {
201 			char* arg = o.argv[i];
202 
203 			if (!core.stdc..string.strcmp(arg, "--push")) {
204 				push = 1;
205 			} else if ((arg[0] != '-') && (name == null)) {
206 				name = arg;
207 			} else if ((arg[0] != '-') && (url == null)) {
208 				url = arg;
209 			} else {
210 				.usage("invalid argument to set-url", arg);
211 			}
212 		}
213 
214 		if ((name == null) || (url == null)) {
215 			.usage("you need to specify remote and the new URL", null);
216 		}
217 
218 		int retval;
219 
220 		if (push) {
221 			retval = libgit2.remote.git_remote_set_pushurl(repo, name, url);
222 		} else {
223 			retval = libgit2.remote.git_remote_set_url(repo, name, url);
224 		}
225 
226 		libgit2.example.common.check_lg2(retval, "could not set URL", url);
227 
228 		return 0;
229 	}
230 
231 nothrow @nogc
232 private int cmd_show(libgit2.types.git_repository* repo, .remote_opts* o)
233 
234 	in
235 	{
236 	}
237 
238 	do
239 	{
240 		int verbose = 0;
241 		libgit2.strarray.git_strarray remotes = libgit2.strarray.git_strarray.init;
242 		libgit2.types.git_remote* remote = null;
243 
244 		for (int i = 0; i < o.argc; i++) {
245 			const (char)* arg = o.argv[i];
246 
247 			if ((!core.stdc..string.strcmp(arg, "-v")) || (!core.stdc..string.strcmp(arg, "--verbose"))) {
248 				verbose = 1;
249 			}
250 		}
251 
252 		libgit2.example.common.check_lg2(libgit2.remote.git_remote_list(&remotes, repo), "could not retrieve remotes", null);
253 
254 		for (int i = 0; i < cast(int)(remotes.count); i++) {
255 			const (char)* name = remotes.strings[i];
256 
257 			if (!verbose) {
258 				core.stdc.stdio.puts(name);
259 
260 				continue;
261 			}
262 
263 			libgit2.example.common.check_lg2(libgit2.remote.git_remote_lookup(&remote, repo, name), "could not look up remote", name);
264 
265 			const (char)* fetch = libgit2.remote.git_remote_url(remote);
266 
267 			if (fetch != null) {
268 				core.stdc.stdio.printf("%s\t%s (fetch)\n", name, fetch);
269 			}
270 
271 			const (char)* push = libgit2.remote.git_remote_pushurl(remote);
272 
273 			/* use fetch URL if no distinct push URL has been set */
274 			push = (push != null) ? (push) : (fetch);
275 
276 			if (push != null) {
277 				core.stdc.stdio.printf("%s\t%s (push)\n", name, push);
278 			}
279 
280 			libgit2.remote.git_remote_free(remote);
281 		}
282 
283 		libgit2.strarray.git_strarray_dispose(&remotes);
284 
285 		return 0;
286 	}
287 
288 nothrow @nogc
289 private void parse_subcmd(.remote_opts* opt, int argc, char** argv)
290 
291 	in
292 	{
293 	}
294 
295 	do
296 	{
297 		char* arg = argv[1];
298 		.subcmd cmd = cast(.subcmd)(0);
299 
300 		if (argc < 2) {
301 			.usage("no command specified", null);
302 		}
303 
304 		if (!core.stdc..string.strcmp(arg, "add")) {
305 			cmd = .subcmd.subcmd_add;
306 		} else if (!core.stdc..string.strcmp(arg, "remove")) {
307 			cmd = .subcmd.subcmd_remove;
308 		} else if (!core.stdc..string.strcmp(arg, "rename")) {
309 			cmd = .subcmd.subcmd_rename;
310 		} else if (!core.stdc..string.strcmp(arg, "set-url")) {
311 			cmd = .subcmd.subcmd_seturl;
312 		} else if (!core.stdc..string.strcmp(arg, "show")) {
313 			cmd = .subcmd.subcmd_show;
314 		} else {
315 			.usage("command is not valid", arg);
316 		}
317 
318 		opt.cmd = cmd;
319 
320 		/* executable and subcommand are removed */
321 		opt.argc = argc - 2;
322 
323 		opt.argv = argv + 2;
324 	}
325 
326 nothrow @nogc
327 private void usage(const (char)* msg, const (char)* arg)
328 
329 	in
330 	{
331 	}
332 
333 	do
334 	{
335 		core.stdc.stdio.fputs("usage: remote add <name> <url>\n", core.stdc.stdio.stderr);
336 		core.stdc.stdio.fputs("       remote remove <name>\n", core.stdc.stdio.stderr);
337 		core.stdc.stdio.fputs("       remote rename <old> <new>\n", core.stdc.stdio.stderr);
338 		core.stdc.stdio.fputs("       remote set-url [--push] <name> <newurl>\n", core.stdc.stdio.stderr);
339 		core.stdc.stdio.fputs("       remote show [-v|--verbose]\n", core.stdc.stdio.stderr);
340 
341 		if ((msg != null) && (arg == null)) {
342 			core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\n%s\n", msg);
343 		} else if ((msg != null) && (arg != null)) {
344 			core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\n%s: %s\n", msg, arg);
345 		}
346 
347 		core.stdc.stdlib.exit(1);
348 	}