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