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