1 /*
2  * libgit2 "rev-list" example - shows how to transform a rev-spec into a list
3  * of commit ids
4  *
5  * Written by the libgit2 contributors
6  *
7  * To the extent possible under law, the author(s) have dedicated all copyright
8  * and related and neighboring rights to this software to the public domain
9  * worldwide. This software is distributed without any warranty.
10  *
11  * You should have received a copy of the CC0 Public Domain Dedication along
12  * with this software. If not, see
13  * <http://creativecommons.org/publicdomain/zero/1.0/>.
14  */
15 module libgit2_d.example.rev_list;
16 
17 
18 private static import core.stdc.stdio;
19 private static import core.stdc.stdlib;
20 private static import core.stdc.string;
21 private static import libgit2_d.errors;
22 private static import libgit2_d.example.args;
23 private static import libgit2_d.example.common;
24 private static import libgit2_d.object;
25 private static import libgit2_d.oid;
26 private static import libgit2_d.revparse;
27 private static import libgit2_d.revwalk;
28 private static import libgit2_d.types;
29 
30 package:
31 
32 //private int revwalk_parseopts(libgit2_d.types.git_repository* repo, libgit2_d.types.git_revwalk* walk, int nopts, char** opts);
33 
34 extern (C)
35 nothrow @nogc
36 public int lg2_rev_list(libgit2_d.types.git_repository* repo, int argc, char** argv)
37 
38 	in
39 	{
40 	}
41 
42 	do
43 	{
44 		libgit2_d.example.args.args_info args = libgit2_d.example.args.ARGS_INFO_INIT(argc, argv);
45 		libgit2_d.types.git_revwalk* walk;
46 		libgit2_d.revwalk.git_sort_t sort;
47 
48 		libgit2_d.example.common.check_lg2(.revwalk_parse_options(&sort, &args), "parsing options", null);
49 
50 		libgit2_d.example.common.check_lg2(libgit2_d.revwalk.git_revwalk_new(&walk, repo), "allocating revwalk", null);
51 		libgit2_d.revwalk.git_revwalk_sorting(walk, sort);
52 		libgit2_d.example.common.check_lg2(.revwalk_parse_revs(repo, walk, &args), "parsing revs", null);
53 
54 		libgit2_d.oid.git_oid oid;
55 		char[libgit2_d.oid.GIT_OID_HEXSZ + 1] buf;
56 
57 		while (!libgit2_d.revwalk.git_revwalk_next(&oid, walk)) {
58 			libgit2_d.oid.git_oid_fmt(&(buf[0]), &oid);
59 			buf[libgit2_d.oid.GIT_OID_HEXSZ] = '\0';
60 			core.stdc.stdio.printf("%s\n", &(buf[0]));
61 		}
62 
63 		libgit2_d.revwalk.git_revwalk_free(walk);
64 
65 		return 0;
66 	}
67 
68 nothrow @nogc
69 private int push_commit(libgit2_d.types.git_revwalk* walk, const (libgit2_d.oid.git_oid)* oid, int hide)
70 
71 	in
72 	{
73 	}
74 
75 	do
76 	{
77 		if (hide) {
78 			return libgit2_d.revwalk.git_revwalk_hide(walk, oid);
79 		} else {
80 			return libgit2_d.revwalk.git_revwalk_push(walk, oid);
81 		}
82 	}
83 
84 nothrow @nogc
85 private int push_spec(libgit2_d.types.git_repository* repo, libgit2_d.types.git_revwalk* walk, const (char)* spec, int hide)
86 
87 	in
88 	{
89 	}
90 
91 	do
92 	{
93 		libgit2_d.types.git_object* obj;
94 		int error = libgit2_d.revparse.git_revparse_single(&obj, repo, spec);
95 
96 		if (error < 0) {
97 			return error;
98 		}
99 
100 		error = .push_commit(walk, libgit2_d.object.git_object_id(obj), hide);
101 		libgit2_d.object.git_object_free(obj);
102 
103 		return error;
104 	}
105 
106 nothrow @nogc
107 private int push_range(libgit2_d.types.git_repository* repo, libgit2_d.types.git_revwalk* walk, const (char)* range, int hide)
108 
109 	in
110 	{
111 	}
112 
113 	do
114 	{
115 		libgit2_d.revparse.git_revspec revspec;
116 		int error = libgit2_d.revparse.git_revparse(&revspec, repo, range);
117 
118 		if (error) {
119 			return error;
120 		}
121 
122 		scope (exit) {
123 			libgit2_d.object.git_object_free(revspec.from);
124 			libgit2_d.object.git_object_free(revspec.to);
125 		}
126 
127 		if (revspec.flags & libgit2_d.revparse.git_revparse_mode_t.GIT_REVPARSE_MERGE_BASE) {
128 			/* TODO: support "<commit>...<commit>" */
129 			return libgit2_d.errors.git_error_code.GIT_EINVALIDSPEC;
130 		}
131 
132 		error = .push_commit(walk, libgit2_d.object.git_object_id(revspec.from), !hide);
133 
134 		if (error) {
135 			return error;
136 		}
137 
138 		error = .push_commit(walk, libgit2_d.object.git_object_id(revspec.to), hide);
139 
140 		return error;
141 	}
142 
143 nothrow @nogc
144 private void print_usage()
145 
146 	do
147 	{
148 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "rev-list [--git-dir=dir] [--topo-order|--date-order] [--reverse] <revspec>\n");
149 		core.stdc.stdlib.exit(-1);
150 	}
151 
152 nothrow @nogc
153 private int revwalk_parse_options(libgit2_d.revwalk.git_sort_t* sort, libgit2_d.example.args.args_info* args)
154 
155 	in
156 	{
157 		assert((sort) && (args));
158 	}
159 
160 	do
161 	{
162 		*sort = libgit2_d.revwalk.git_sort_t.GIT_SORT_NONE;
163 
164 		if (args.argc < 1) {
165 			.print_usage();
166 		}
167 
168 		for (args.pos = 1; args.pos < args.argc; ++args.pos) {
169 			const (char)* curr = args.argv[args.pos];
170 
171 			if (!core.stdc..string.strcmp(curr, "--topo-order")) {
172 				*sort |= libgit2_d.revwalk.git_sort_t.GIT_SORT_TOPOLOGICAL;
173 			} else if (!core.stdc..string.strcmp(curr, "--date-order")) {
174 				*sort |= libgit2_d.revwalk.git_sort_t.GIT_SORT_TIME;
175 			} else if (!core.stdc..string.strcmp(curr, "--reverse")) {
176 				*sort |= (*sort & ~libgit2_d.revwalk.git_sort_t.GIT_SORT_REVERSE) ^ libgit2_d.revwalk.git_sort_t.GIT_SORT_REVERSE;
177 			} else {
178 				break;
179 			}
180 		}
181 
182 		return 0;
183 	}
184 
185 nothrow @nogc
186 private int revwalk_parse_revs(libgit2_d.types.git_repository* repo, libgit2_d.types.git_revwalk* walk, libgit2_d.example.args.args_info* args)
187 
188 	in
189 	{
190 	}
191 
192 	do
193 	{
194 		int hide = 0;
195 		int error;
196 		libgit2_d.oid.git_oid oid;
197 
198 		for (; args.pos < args.argc; ++args.pos) {
199 			const (char)* curr = args.argv[args.pos];
200 
201 			if (!core.stdc..string.strcmp(curr, "--not")) {
202 				hide = !hide;
203 			} else if (curr[0] == '^') {
204 				error = .push_spec(repo, walk, curr + 1, !hide);
205 
206 				if (error) {
207 					return error;
208 				}
209 			} else if (core.stdc..string.strstr(curr, "..")) {
210 				error = .push_range(repo, walk, curr, hide);
211 
212 				if (error) {
213 					return error;
214 				}
215 			} else {
216 				if (.push_spec(repo, walk, curr, hide) == 0) {
217 					continue;
218 				}
219 
220 				error = libgit2_d.oid.git_oid_fromstr(&oid, curr);
221 
222 				if (error) {
223 					return error;
224 				}
225 
226 				error = .push_commit(walk, &oid, hide);
227 
228 				if (error) {
229 					return error;
230 				}
231 			}
232 		}
233 
234 		return 0;
235 	}