1 /*
2  * libgit2 "add" example - shows how to modify the index
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  * <http://creativecommons.org/publicdomain/zero/1.0/>.
13  */
14 module libgit2_d.example.add;
15 
16 
17 private static import core.stdc.stdio;
18 private static import core.stdc.stdlib;
19 private static import core.stdc.string;
20 private static import libgit2_d.example.args;
21 private static import libgit2_d.example.common;
22 private static import libgit2_d.index;
23 private static import libgit2_d.repository;
24 private static import libgit2_d.status;
25 private static import libgit2_d.strarray;
26 private static import libgit2_d.types;
27 
28 package:
29 
30 /**
31  * The following example demonstrates how to add files with libgit2.
32  *
33  * It will use the repository in the current working directory, and act
34  * on files passed as its parameters.
35  *
36  * Recognized options are:
37  *   -v/--verbose: show the file's status after acting on it.
38  *   -n/--dry-run: do not actually change the index.
39  *   -u/--update: update the index instead of adding to it.
40  */
41 
42 public enum index_mode
43 {
44 	INDEX_NONE,
45 	INDEX_ADD,
46 }
47 
48 public struct index_options
49 {
50 	int dry_run;
51 	int verbose;
52 	libgit2_d.types.git_repository* repo;
53 	.index_mode mode;
54 	int add_update;
55 }
56 
57 /* Forward declarations for helpers */
58 //private void parse_opts(int* options, int* count, int argc, char*[] argv);
59 //void init_array(libgit2_d.strarray.git_strarray* array, int argc, char** argv);
60 //int print_matched_cb(const (char)* path, const (char)* matched_pathspec, void* payload);
61 
62 extern (C)
63 nothrow @nogc
64 public int lg2_add(libgit2_d.types.git_repository* repo, int argc, char** argv)
65 
66 	in
67 	{
68 	}
69 
70 	do
71 	{
72 		libgit2_d.example.args.args_info args = libgit2_d.example.args.ARGS_INFO_INIT(argc, argv);
73 
74 		/* Parse the options & arguments. */
75 		.index_options options;
76 		.parse_opts(null, &options, &args);
77 
78 		libgit2_d.strarray.git_strarray array = libgit2_d.strarray.git_strarray.init;
79 		libgit2_d.example.args.strarray_from_args(&array, &args);
80 
81 		/* Grab the repository's index. */
82 		libgit2_d.types.git_index* index;
83 		libgit2_d.example.common.check_lg2(libgit2_d.repository.git_repository_index(&index, repo), "Could not open repository index", null);
84 
85 		libgit2_d.index.git_index_matched_path_cb matched_cb = null;
86 
87 		/* Setup a callback if the requested options need it */
88 		if ((options.verbose) || (options.dry_run)) {
89 			matched_cb = &.print_matched_cb;
90 		}
91 
92 		options.repo = repo;
93 
94 		if (options.add_update) {
95 			libgit2_d.index.git_index_update_all(index, &array, matched_cb, &options);
96 		} else {
97 			libgit2_d.index.git_index_add_all(index, &array, 0, matched_cb, &options);
98 		}
99 
100 		/* Cleanup memory */
101 		libgit2_d.index.git_index_write(index);
102 		libgit2_d.index.git_index_free(index);
103 
104 		return 0;
105 	}
106 
107 /*
108  * This callback is called for each file under consideration by
109  * git_index_(update|add)_all above.
110  * It makes uses of the callback's ability to abort the action.
111  */
112 extern (C)
113 nothrow @nogc
114 public int print_matched_cb(const (char)* path, const (char)* matched_pathspec, void* payload)
115 
116 	in
117 	{
118 	}
119 
120 	do
121 	{
122 		.index_options opts = *cast(.index_options*)(payload);
123 		uint status;
124 		//cast(void)(matched_pathspec);
125 
126 		/* Get the file status */
127 		if (libgit2_d.status.git_status_file(&status, opts.repo, path) < 0) {
128 			return -1;
129 		}
130 
131 		int ret;
132 
133 		if ((status & libgit2_d.status.git_status_t.GIT_STATUS_WT_MODIFIED) || (status & libgit2_d.status.git_status_t.GIT_STATUS_WT_NEW)) {
134 			core.stdc.stdio.printf("add '%s'\n", path);
135 			ret = 0;
136 		} else {
137 			ret = 1;
138 		}
139 
140 		if (opts.dry_run) {
141 			ret = 1;
142 		}
143 
144 		return ret;
145 	}
146 
147 nothrow @nogc
148 public void init_array(libgit2_d.strarray.git_strarray* array, int argc, char** argv)
149 
150 	in
151 	{
152 	}
153 
154 	do
155 	{
156 		array.count = argc;
157 		array.strings = cast(char**)(core.stdc.stdlib.calloc(array.count, (char*).sizeof));
158 		assert(array.strings != null);
159 
160 		for (uint i = 0; i < array.count; i++) {
161 			array.strings[i] = argv[i];
162 		}
163 
164 		return;
165 	}
166 
167 nothrow @nogc
168 public void print_usage()
169 
170 	in
171 	{
172 	}
173 
174 	do
175 	{
176 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "usage: add [options] [--] file-spec [file-spec] [...]\n\n");
177 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\t-n, --dry-run    dry run\n");
178 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\t-v, --verbose    be verbose\n");
179 		core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "\t-u, --update     update tracked files\n");
180 		core.stdc.stdlib.exit(1);
181 	}
182 
183 nothrow @nogc
184 private void parse_opts(const (char)** repo_path, .index_options* opts, libgit2_d.example.args.args_info* args)
185 
186 	in
187 	{
188 	}
189 
190 	do
191 	{
192 		if (args.argc <= 1) {
193 			.print_usage();
194 		}
195 
196 		for (args.pos = 1; args.pos < args.argc; ++args.pos) {
197 			const (char)* curr = args.argv[args.pos];
198 
199 			if (curr[0] != '-') {
200 				if (!core.stdc..string.strcmp("add", curr)) {
201 					opts.mode = .index_mode.INDEX_ADD;
202 
203 					continue;
204 				} else if (opts.mode == .index_mode.INDEX_NONE) {
205 					core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "missing command: %s", curr);
206 					.print_usage();
207 
208 					break;
209 				} else {
210 					/* We might be looking at a filename */
211 					break;
212 				}
213 			} else if ((libgit2_d.example.args.match_bool_arg(&opts.verbose, args, "--verbose")) || (libgit2_d.example.args.match_bool_arg(&opts.dry_run, args, "--dry-run")) || (libgit2_d.example.args.match_str_arg(repo_path, args, "--git-dir")) || ((opts.mode == .index_mode.INDEX_ADD) && (libgit2_d.example.args.match_bool_arg(&opts.add_update, args, "--update")))) {
214 				continue;
215 			} else if (libgit2_d.example.args.match_bool_arg(null, args, "--help")) {
216 				.print_usage();
217 
218 				break;
219 			} else if (libgit2_d.example.args.match_arg_separator(args)) {
220 				break;
221 			} else {
222 				core.stdc.stdio.fprintf(core.stdc.stdio.stderr, "Unsupported option %s.\n", curr);
223 				.print_usage();
224 			}
225 		}
226 	}