1 /**
2  * This part is not strictly libgit2-dependent, but you can use this
3  * as a starting point for a git-like tool
4  */
5 module libgit2.example.lg2;
6 
7 
8 private static import core.stdc.stdio;
9 private static import core.stdc.stdlib;
10 private static import core.stdc.string;
11 private static import libgit2.errors;
12 private static import libgit2.example.add;
13 private static import libgit2.example.args;
14 private static import libgit2.example.blame;
15 private static import libgit2.example.cat_file;
16 private static import libgit2.example.checkout;
17 private static import libgit2.example.clone;
18 private static import libgit2.example.commit;
19 private static import libgit2.example.common;
20 private static import libgit2.example.config;
21 private static import libgit2.example.describe;
22 private static import libgit2.example.diff;
23 private static import libgit2.example.fetch;
24 private static import libgit2.example.for_each_ref;
25 private static import libgit2.example.general;
26 private static import libgit2.example.index_pack;
27 private static import libgit2.example.init;
28 private static import libgit2.example.log;
29 private static import libgit2.example.ls_files;
30 private static import libgit2.example.ls_remote;
31 private static import libgit2.example.merge;
32 private static import libgit2.example.push;
33 private static import libgit2.example.remote;
34 private static import libgit2.example.rev_list;
35 private static import libgit2.example.rev_parse;
36 private static import libgit2.example.show_index;
37 private static import libgit2.example.stash;
38 private static import libgit2.example.status;
39 private static import libgit2.example.tag;
40 private static import libgit2.global;
41 private static import libgit2.repository;
42 private static import libgit2.types;
43 
44 
45 public alias git_command_fn = extern (C) nothrow @nogc int function(libgit2.types.git_repository*, int, char**);
46 
47 extern (C)
48 public struct commands_t
49 {
50 	immutable (char)* name;
51 	.git_command_fn fn;
52 	char requires_repo;
53 }
54 
55 public static immutable .commands_t[] commands =
56 [
57 	{"add".ptr, &libgit2.example.add.lg2_add, 1},
58 	{"blame".ptr, &libgit2.example.blame.lg2_blame, 1},
59 	{"cat-file".ptr, &libgit2.example.cat_file.lg2_cat_file, 1},
60 	{"checkout".ptr, &libgit2.example.checkout.lg2_checkout, 1},
61 	{"clone".ptr, &libgit2.example.clone.lg2_clone, 0},
62 	{"commit".ptr, &libgit2.example.commit.lg2_commit, 1},
63 	{"config".ptr, &libgit2.example.config.lg2_config, 1},
64 	{"describe".ptr, &libgit2.example.describe.lg2_describe, 1},
65 	{"diff".ptr, &libgit2.example.diff.lg2_diff, 1},
66 	{"fetch".ptr, &libgit2.example.fetch.lg2_fetch, 1},
67 	{"for-each-ref".ptr, &libgit2.example.for_each_ref.lg2_for_each_ref, 1},
68 	{"general".ptr, &libgit2.example.general.lg2_general, 0},
69 	{"index-pack".ptr, &libgit2.example.index_pack.lg2_index_pack, 1},
70 	{"init".ptr, &libgit2.example.init.lg2_init, 0},
71 	{"log".ptr, &libgit2.example.log.lg2_log, 1},
72 	{"ls-files".ptr, &libgit2.example.ls_files.lg2_ls_files, 1},
73 	{"ls-remote".ptr, &libgit2.example.ls_remote.lg2_ls_remote, 1},
74 	{"merge".ptr, &libgit2.example.merge.lg2_merge, 1},
75 	{"push".ptr, &libgit2.example.push.lg2_push, 1},
76 	{"remote".ptr, &libgit2.example.remote.lg2_remote, 1},
77 	{"rev-list".ptr, &libgit2.example.rev_list.lg2_rev_list, 1},
78 	{"rev-parse".ptr, &libgit2.example.rev_parse.lg2_rev_parse, 1},
79 	{"show-index".ptr, &libgit2.example.show_index.lg2_show_index, 0},
80 	{"stash".ptr, &libgit2.example.stash.lg2_stash, 1},
81 	{"status".ptr, &libgit2.example.status.lg2_status, 1},
82 	{"tag".ptr, &libgit2.example.tag.lg2_tag, 1},
83 ];
84 
85 nothrow @nogc
86 private int run_command(.git_command_fn fn, libgit2.types.git_repository* repo, libgit2.example.args.args_info args)
87 
88 	in
89 	{
90 	}
91 
92 	do
93 	{
94 		/* Run the command. If something goes wrong, print the error message to stderr */
95 		int error = fn(repo, args.argc - args.pos, &args.argv[args.pos]);
96 
97 		if (error < 0) {
98 			if (libgit2.errors.git_error_last() == null) {
99 				core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "Error without message");
100 			} else {
101 				core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "Bad news:\n %s\n", libgit2.errors.git_error_last().message);
102 			}
103 		}
104 
105 		return !!error;
106 	}
107 
108 nothrow @nogc
109 private void usage(const (char)* prog)
110 
111 	in
112 	{
113 	}
114 
115 	do
116 	{
117 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "usage: %s <cmd>...\n\nAvailable commands:\n\n", prog);
118 
119 		for (size_t i = 0; i < commands.length; i++) {
120 			core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\t%s\n", commands[i].name);
121 		}
122 
123 		core.stdc.stdlib.exit(core.stdc.stdlib.EXIT_FAILURE);
124 	}
125 
126 version (LIBGIT2_EXAMPLE)
127 extern (C)
128 nothrow @nogc
129 public int main(int argc, char** argv)
130 
131 	do
132 	{
133 		if (argc < 2) {
134 			.usage(argv[0]);
135 		}
136 
137 		libgit2.example.args.args_info args = libgit2.example.args.ARGS_INFO_INIT(argc, argv);
138 		libgit2.global.git_libgit2_init();
139 
140 		const (char)* git_dir = null;
141 
142 		for (args.pos = 1; args.pos < args.argc; ++args.pos) {
143 			char* a = args.argv[args.pos];
144 
145 			if (a[0] != '-') {
146 				/* non-arg */
147 				break;
148 			} else if (libgit2.example.args.optional_str_arg(&git_dir, &args, "--git-dir", ".git")) {
149 				continue;
150 			} else if (libgit2.example.args.match_arg_separator(&args)) {
151 				break;
152 			}
153 		}
154 
155 		if (args.pos == args.argc) {
156 			.usage(argv[0]);
157 		}
158 
159 		if (git_dir == null) {
160 			git_dir = ".";
161 		}
162 
163 		libgit2.types.git_repository* repo = null;
164 		int return_code = 1;
165 
166 		scope (exit) {
167 			libgit2.repository.git_repository_free(repo);
168 			libgit2.global.git_libgit2_shutdown();
169 		}
170 
171 		for (size_t i = 0; i < commands.length; ++i) {
172 			if (core.stdc..string.strcmp(args.argv[args.pos], commands[i].name)) {
173 				continue;
174 			}
175 
176 			/*
177 			 * Before running the actual command, create an instance
178 			 * of the local repository and pass it to the function.
179 			 */
180 			if (commands[i].requires_repo) {
181 				libgit2.example.common.check_lg2(libgit2.repository.git_repository_open_ext(&repo, git_dir, 0, null), "Unable to open repository '%s'", git_dir);
182 			}
183 
184 			return_code = run_command(commands[i].fn, repo, args);
185 
186 			return return_code;
187 		}
188 
189 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "Command not found: %s\n", argv[1]);
190 
191 		return return_code;
192 	}