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