1 /*
2  *              Copyright David Nadlinger 2014.
3  *  Distributed under the Boost Software License, Version 1.0.
4  *     (See accompanying file LICENSE_1_0.txt or copy at
5  *           http://www.boost.org/LICENSE_1_0.txt)
6  */
7 module git.checkout;
8 
9 // Note: This file includes none of the original comments, as they might
10 // be copyrightable material.
11 
12 import git.object_;
13 import git.repository;
14 import git.tree;
15 import git.util;
16 
17 import deimos.git2.checkout;
18 import deimos.git2.common;
19 import deimos.git2.diff;
20 import deimos.git2.strarray;
21 import deimos.git2.types;
22 import deimos.git2.util;
23 
24 ///
25 enum GitCheckoutStrategy
26 {
27     ///
28     none = GIT_CHECKOUT_NONE,
29 
30     ///
31     safe = GIT_CHECKOUT_SAFE,
32 
33     ///
34     safeCreate = GIT_CHECKOUT_SAFE_CREATE,
35 
36     ///
37     force = GIT_CHECKOUT_FORCE,
38 
39     ///
40     allowConflicts = GIT_CHECKOUT_ALLOW_CONFLICTS,
41 
42     ///
43     removeUntracked = GIT_CHECKOUT_REMOVE_UNTRACKED,
44 
45     ///
46     removeIgnored = GIT_CHECKOUT_REMOVE_IGNORED,
47 
48     ///
49     updateOnly = GIT_CHECKOUT_UPDATE_ONLY,
50 
51     ///
52     dontUpdateIndex = GIT_CHECKOUT_DONT_UPDATE_INDEX,
53 
54     ///
55     noRefresh = GIT_CHECKOUT_NO_REFRESH,
56 
57     ///
58     disablePathspecMatch = GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH,
59 
60     ///
61     skipLockedDirs = GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES,
62 
63     /// Not implemented yet!
64     skipUnmerged = GIT_CHECKOUT_SKIP_UNMERGED,
65 
66     /// ditto
67     useOurs = GIT_CHECKOUT_USE_OURS,
68 
69     /// ditto
70     useTheirs = GIT_CHECKOUT_USE_THEIRS,
71 
72     /// ditto
73     updateSubmods = GIT_CHECKOUT_UPDATE_SUBMODULES,
74 
75     /// ditto
76     updateSubmodsIfChanged = GIT_CHECKOUT_UPDATE_SUBMODULES_IF_CHANGED,
77 }
78 
79 ///
80 enum GitCheckoutNotify
81 {
82     ///
83     none = GIT_CHECKOUT_NOTIFY_NONE,
84 
85     ///
86     conflict = GIT_CHECKOUT_NOTIFY_CONFLICT,
87 
88     ///
89     dirty = GIT_CHECKOUT_NOTIFY_DIRTY,
90 
91     ///
92     updated = GIT_CHECKOUT_NOTIFY_UPDATED,
93 
94     ///
95     untracked = GIT_CHECKOUT_NOTIFY_UNTRACKED,
96 
97     ///
98     notify_ignored = GIT_CHECKOUT_NOTIFY_IGNORED,
99 
100     ///
101     notify_all = GIT_CHECKOUT_NOTIFY_ALL,
102 }
103 
104 alias GitCheckoutNotifyDelegate = void delegate(
105     GitCheckoutNotify why,
106     const(char)[] path,
107     const(git_diff_file)* baseline,
108     const(git_diff_file)* target,
109     const(git_diff_file)* workdir);
110 
111 extern(C) int cCheckoutNotifyCallback(
112     git_checkout_notify_t why,
113     const(char)* path,
114     const(git_diff_file)* baseline,
115     const(git_diff_file)* target,
116     const(git_diff_file)* workdir,
117     void *payload)
118 {
119     auto dg = (cast(GitCheckoutOptions*)payload).notifyCallback;
120     dg(cast(GitCheckoutNotify)why, toSlice(path), baseline, target, workdir);
121     return 0; // TODO: What does this return value indicate?
122 }
123 
124 alias GitCheckoutProgressDelegate = void delegate(
125     const(char)[] path,
126     size_t completed_steps,
127     size_t total_steps
128 );
129 
130 extern(C) void cCheckoutProgressCallback(
131     const(char)* path,
132     size_t completed_steps,
133     size_t total_steps,
134     void *payload)
135 {
136     auto dg = (cast(GitCheckoutOptions*)payload).progressCallback;
137     dg(toSlice(path), completed_steps, total_steps);
138 }
139 
140 struct GitCheckoutOptions
141 {
142     uint version_ = git_checkout_opts.init.version_;
143 
144     GitCheckoutStrategy strategy;
145 
146     int disableFilters;
147     uint dirMode;
148     uint fileMode;
149     int fileOpenFlags;
150 
151     uint notifyFlags;
152 
153     GitCheckoutNotifyDelegate notifyCallback;
154     GitCheckoutProgressDelegate progressCallback;
155 
156     git_strarray paths; // TODO: Translate.
157     git_tree* baseline; // TODO: Translate.
158 
159     string targetDir;
160 }
161 
162 package void toCCheckoutOpts(ref GitCheckoutOptions dOpts, ref git_checkout_opts cOpts)
163 {
164     with (dOpts)
165     {
166         cOpts.version_ = version_;
167         cOpts.checkout_strategy = cast(uint)strategy;
168         cOpts.disable_filters = disableFilters;
169         cOpts.dir_mode = fileMode;
170         cOpts.file_mode = fileMode;
171         cOpts.file_open_flags = fileOpenFlags;
172         cOpts.notify_flags = notifyFlags;
173         if (notifyCallback)
174         {
175             cOpts.notify_cb = &cCheckoutNotifyCallback;
176             cOpts.notify_payload = cast(void*)&dOpts;
177         }
178         if (progressCallback)
179         {
180             cOpts.progress_cb = &cCheckoutProgressCallback;
181             cOpts.progress_payload = cast(void*)&dOpts;
182         }
183         cOpts.paths = paths;
184         cOpts.baseline = baseline;
185         cOpts.target_directory = targetDir.gitStr;
186     }
187 }
188 
189 void checkoutHead(GitRepo repo, GitCheckoutOptions opts = GitCheckoutOptions.init)
190 {
191     git_checkout_opts cOpts;
192     opts.toCCheckoutOpts(cOpts);
193     require(git_checkout_head(repo.cHandle, &cOpts) == 0);
194 }
195 
196 void checkout(GitRepo repo, git_index* index, GitCheckoutOptions opts = GitCheckoutOptions.init) // TODO: Convert.
197 {
198     git_checkout_opts cOpts;
199     opts.toCCheckoutOpts(cOpts);
200     require(git_checkout_index(repo.cHandle, index, &cOpts) == 0);
201 }
202 
203 void checkout(GitRepo repo, GitObject treeish, GitCheckoutOptions opts = GitCheckoutOptions.init)
204 {
205     git_checkout_opts cOpts;
206     opts.toCCheckoutOpts(cOpts);
207     require(git_checkout_tree(repo.cHandle, treeish.cHandle, &cOpts) == 0);
208 }
209 
210 void checkout(GitRepo repo, GitTree treeish, GitCheckoutOptions opts = GitCheckoutOptions.init)
211 {
212     git_checkout_opts cOpts;
213     opts.toCCheckoutOpts(cOpts);
214     require(git_checkout_tree(repo.cHandle, cast(git_object*)treeish.cHandle, &cOpts) == 0);
215 }