1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.api;
44
45 import static org.eclipse.jgit.lib.Constants.R_STASH;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.nio.file.StandardCopyOption;
50 import java.text.MessageFormat;
51 import java.util.List;
52
53 import org.eclipse.jgit.api.errors.GitAPIException;
54 import org.eclipse.jgit.api.errors.InvalidRefNameException;
55 import org.eclipse.jgit.api.errors.JGitInternalException;
56 import org.eclipse.jgit.api.errors.RefNotFoundException;
57 import org.eclipse.jgit.errors.LockFailedException;
58 import org.eclipse.jgit.internal.JGitText;
59 import org.eclipse.jgit.internal.storage.file.RefDirectory;
60 import org.eclipse.jgit.internal.storage.file.ReflogWriter;
61 import org.eclipse.jgit.lib.ObjectId;
62 import org.eclipse.jgit.lib.Ref;
63 import org.eclipse.jgit.lib.RefUpdate;
64 import org.eclipse.jgit.lib.RefUpdate.Result;
65 import org.eclipse.jgit.lib.ReflogEntry;
66 import org.eclipse.jgit.lib.ReflogReader;
67 import org.eclipse.jgit.lib.Repository;
68 import org.eclipse.jgit.util.FileUtils;
69
70
71
72
73
74
75
76
77
78
79
80 public class StashDropCommand extends GitCommand<ObjectId> {
81
82 private int stashRefEntry;
83
84 private boolean all;
85
86
87
88
89
90
91
92 public StashDropCommand(Repository repo) {
93 super(repo);
94 if (!(repo.getRefDatabase() instanceof RefDirectory)) {
95 throw new UnsupportedOperationException(
96 JGitText.get().stashDropNotSupported);
97 }
98 }
99
100
101
102
103
104
105
106
107
108
109
110 public StashDropCommand setStashRef(int stashRef) {
111 if (stashRef < 0)
112 throw new IllegalArgumentException();
113
114 stashRefEntry = stashRef;
115 return this;
116 }
117
118
119
120
121
122
123
124
125
126
127 public StashDropCommand setAll(boolean all) {
128 this.all = all;
129 return this;
130 }
131
132 private Ref getRef() throws GitAPIException {
133 try {
134 return repo.exactRef(R_STASH);
135 } catch (IOException e) {
136 throw new InvalidRefNameException(MessageFormat.format(
137 JGitText.get().cannotRead, R_STASH), e);
138 }
139 }
140
141 private RefUpdate createRefUpdate(Ref stashRef) throws IOException {
142 RefUpdate update = repo.updateRef(R_STASH);
143 update.disableRefLog();
144 update.setExpectedOldObjectId(stashRef.getObjectId());
145 update.setForceUpdate(true);
146 return update;
147 }
148
149 private void deleteRef(Ref stashRef) {
150 try {
151 Result result = createRefUpdate(stashRef).delete();
152 if (Result.FORCED != result)
153 throw new JGitInternalException(MessageFormat.format(
154 JGitText.get().stashDropDeleteRefFailed, result));
155 } catch (IOException e) {
156 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
157 }
158 }
159
160 private void updateRef(Ref stashRef, ObjectId newId) {
161 try {
162 RefUpdate update = createRefUpdate(stashRef);
163 update.setNewObjectId(newId);
164 Result result = update.update();
165 switch (result) {
166 case FORCED:
167 case NEW:
168 case NO_CHANGE:
169 return;
170 default:
171 throw new JGitInternalException(MessageFormat.format(
172 JGitText.get().updatingRefFailed, R_STASH, newId,
173 result));
174 }
175 } catch (IOException e) {
176 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
177 }
178 }
179
180
181
182
183
184
185
186 @Override
187 public ObjectId call() throws GitAPIException {
188 checkCallable();
189
190 Ref stashRef = getRef();
191 if (stashRef == null)
192 return null;
193
194 if (all) {
195 deleteRef(stashRef);
196 return null;
197 }
198
199 List<ReflogEntry> entries;
200 try {
201 ReflogReader reader = repo.getReflogReader(R_STASH);
202 if (reader == null) {
203 throw new RefNotFoundException(MessageFormat
204 .format(JGitText.get().refNotResolved, stashRef));
205 }
206 entries = reader.getReverseEntries();
207 } catch (IOException e) {
208 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
209 }
210
211 if (stashRefEntry >= entries.size())
212 throw new JGitInternalException(
213 JGitText.get().stashDropMissingReflog);
214
215 if (entries.size() == 1) {
216 deleteRef(stashRef);
217 return null;
218 }
219
220 RefDirectory refdb = (RefDirectory) repo.getRefDatabase();
221 ReflogWriter writer = new ReflogWriter(refdb, true);
222 String stashLockRef = ReflogWriter.refLockFor(R_STASH);
223 File stashLockFile = refdb.logFor(stashLockRef);
224 File stashFile = refdb.logFor(R_STASH);
225 if (stashLockFile.exists())
226 throw new JGitInternalException(JGitText.get().stashDropFailed,
227 new LockFailedException(stashFile));
228
229 entries.remove(stashRefEntry);
230 ObjectId entryId = ObjectId.zeroId();
231 try {
232 for (int i = entries.size() - 1; i >= 0; i--) {
233 ReflogEntry entry = entries.get(i);
234 writer.log(stashLockRef, entryId, entry.getNewId(),
235 entry.getWho(), entry.getComment());
236 entryId = entry.getNewId();
237 }
238 try {
239 FileUtils.rename(stashLockFile, stashFile,
240 StandardCopyOption.ATOMIC_MOVE);
241 } catch (IOException e) {
242 throw new JGitInternalException(MessageFormat.format(
243 JGitText.get().renameFileFailed,
244 stashLockFile.getPath(), stashFile.getPath()),
245 e);
246 }
247 } catch (IOException e) {
248 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
249 }
250 updateRef(stashRef, entryId);
251
252 try {
253 Ref newStashRef = repo.exactRef(R_STASH);
254 return newStashRef != null ? newStashRef.getObjectId() : null;
255 } catch (IOException e) {
256 throw new InvalidRefNameException(MessageFormat.format(
257 JGitText.get().cannotRead, R_STASH), e);
258 }
259 }
260 }