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.ReflogWriter;
60 import org.eclipse.jgit.lib.ObjectId;
61 import org.eclipse.jgit.lib.Ref;
62 import org.eclipse.jgit.lib.RefUpdate;
63 import org.eclipse.jgit.lib.RefUpdate.Result;
64 import org.eclipse.jgit.lib.ReflogEntry;
65 import org.eclipse.jgit.lib.ReflogReader;
66 import org.eclipse.jgit.lib.Repository;
67 import org.eclipse.jgit.util.FileUtils;
68
69
70
71
72
73
74
75
76 public class StashDropCommand extends GitCommand<ObjectId> {
77
78 private int stashRefEntry;
79
80 private boolean all;
81
82
83
84
85 public StashDropCommand(Repository repo) {
86 super(repo);
87 }
88
89
90
91
92
93
94
95
96
97
98 public StashDropCommand setStashRef(final int stashRef) {
99 if (stashRef < 0)
100 throw new IllegalArgumentException();
101
102 stashRefEntry = stashRef;
103 return this;
104 }
105
106
107
108
109
110
111
112
113
114 public StashDropCommand setAll(final boolean all) {
115 this.all = all;
116 return this;
117 }
118
119 private Ref getRef() throws GitAPIException {
120 try {
121 return repo.exactRef(R_STASH);
122 } catch (IOException e) {
123 throw new InvalidRefNameException(MessageFormat.format(
124 JGitText.get().cannotRead, R_STASH), e);
125 }
126 }
127
128 private RefUpdate createRefUpdate(final Ref stashRef) throws IOException {
129 RefUpdate update = repo.updateRef(R_STASH);
130 update.disableRefLog();
131 update.setExpectedOldObjectId(stashRef.getObjectId());
132 update.setForceUpdate(true);
133 return update;
134 }
135
136 private void deleteRef(final Ref stashRef) {
137 try {
138 Result result = createRefUpdate(stashRef).delete();
139 if (Result.FORCED != result)
140 throw new JGitInternalException(MessageFormat.format(
141 JGitText.get().stashDropDeleteRefFailed, result));
142 } catch (IOException e) {
143 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
144 }
145 }
146
147 private void updateRef(Ref stashRef, ObjectId newId) {
148 try {
149 RefUpdate update = createRefUpdate(stashRef);
150 update.setNewObjectId(newId);
151 Result result = update.update();
152 switch (result) {
153 case FORCED:
154 case NEW:
155 case NO_CHANGE:
156 return;
157 default:
158 throw new JGitInternalException(MessageFormat.format(
159 JGitText.get().updatingRefFailed, R_STASH, newId,
160 result));
161 }
162 } catch (IOException e) {
163 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
164 }
165 }
166
167
168
169
170
171
172
173
174 @Override
175 public ObjectId call() throws GitAPIException {
176 checkCallable();
177
178 Ref stashRef = getRef();
179 if (stashRef == null)
180 return null;
181
182 if (all) {
183 deleteRef(stashRef);
184 return null;
185 }
186
187 List<ReflogEntry> entries;
188 try {
189 ReflogReader reader = repo.getReflogReader(R_STASH);
190 if (reader == null) {
191 throw new RefNotFoundException(MessageFormat
192 .format(JGitText.get().refNotResolved, stashRef));
193 }
194 entries = reader.getReverseEntries();
195 } catch (IOException e) {
196 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
197 }
198
199 if (stashRefEntry >= entries.size())
200 throw new JGitInternalException(
201 JGitText.get().stashDropMissingReflog);
202
203 if (entries.size() == 1) {
204 deleteRef(stashRef);
205 return null;
206 }
207
208 ReflogWriter writer = new ReflogWriter(repo, true);
209 String stashLockRef = ReflogWriter.refLockFor(R_STASH);
210 File stashLockFile = writer.logFor(stashLockRef);
211 File stashFile = writer.logFor(R_STASH);
212 if (stashLockFile.exists())
213 throw new JGitInternalException(JGitText.get().stashDropFailed,
214 new LockFailedException(stashFile));
215
216 entries.remove(stashRefEntry);
217 ObjectId entryId = ObjectId.zeroId();
218 try {
219 for (int i = entries.size() - 1; i >= 0; i--) {
220 ReflogEntry entry = entries.get(i);
221 writer.log(stashLockRef, entryId, entry.getNewId(),
222 entry.getWho(), entry.getComment());
223 entryId = entry.getNewId();
224 }
225 try {
226 FileUtils.rename(stashLockFile, stashFile,
227 StandardCopyOption.ATOMIC_MOVE);
228 } catch (IOException e) {
229 throw new JGitInternalException(MessageFormat.format(
230 JGitText.get().renameFileFailed,
231 stashLockFile.getPath(), stashFile.getPath()),
232 e);
233 }
234 } catch (IOException e) {
235 throw new JGitInternalException(JGitText.get().stashDropFailed, e);
236 }
237 updateRef(stashRef, entryId);
238
239 try {
240 Ref newStashRef = repo.exactRef(R_STASH);
241 return newStashRef != null ? newStashRef.getObjectId() : null;
242 } catch (IOException e) {
243 throw new InvalidRefNameException(MessageFormat.format(
244 JGitText.get().cannotRead, R_STASH), e);
245 }
246 }
247 }