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