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
44
45
46 package org.eclipse.jgit.internal.storage.file;
47
48 import static org.eclipse.jgit.lib.Constants.HEAD;
49 import static org.eclipse.jgit.lib.Constants.LOGS;
50 import static org.eclipse.jgit.lib.Constants.R_HEADS;
51 import static org.eclipse.jgit.lib.Constants.R_REFS;
52 import static org.eclipse.jgit.lib.Constants.R_REMOTES;
53 import static org.eclipse.jgit.lib.Constants.R_STASH;
54
55 import java.io.File;
56 import java.io.FileNotFoundException;
57 import java.io.FileOutputStream;
58 import java.io.IOException;
59 import java.nio.ByteBuffer;
60 import java.nio.channels.FileChannel;
61 import java.text.MessageFormat;
62
63 import org.eclipse.jgit.internal.JGitText;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.CoreConfig;
66 import org.eclipse.jgit.lib.ObjectId;
67 import org.eclipse.jgit.lib.PersonIdent;
68 import org.eclipse.jgit.lib.Ref;
69 import org.eclipse.jgit.lib.RefUpdate;
70 import org.eclipse.jgit.lib.ReflogEntry;
71 import org.eclipse.jgit.lib.Repository;
72 import org.eclipse.jgit.util.FS;
73 import org.eclipse.jgit.util.FileUtils;
74
75
76
77
78 public class ReflogWriter {
79
80
81
82
83
84
85
86
87
88 public static String refLockFor(final String name) {
89 return name + LockFile.SUFFIX;
90 }
91
92 private final Repository parent;
93
94 private final File logsDir;
95
96 private final File logsRefsDir;
97
98 private final boolean forceWrite;
99
100
101
102
103
104
105 public ReflogWriter(final Repository repository) {
106 this(repository, false);
107 }
108
109
110
111
112
113
114
115
116
117 public ReflogWriter(final Repository repository, final boolean forceWrite) {
118 final FS fs = repository.getFS();
119 parent = repository;
120 File gitDir = repository.getDirectory();
121 logsDir = fs.resolve(gitDir, LOGS);
122 logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS);
123 this.forceWrite = forceWrite;
124 }
125
126
127
128
129
130
131 public Repository getRepository() {
132 return parent;
133 }
134
135
136
137
138
139
140
141 public ReflogWriter create() throws IOException {
142 FileUtils.mkdir(logsDir);
143 FileUtils.mkdir(logsRefsDir);
144 FileUtils.mkdir(new File(logsRefsDir,
145 R_HEADS.substring(R_REFS.length())));
146 return this;
147 }
148
149
150
151
152
153
154
155
156
157 public File logFor(String name) {
158 if (name.startsWith(R_REFS)) {
159 name = name.substring(R_REFS.length());
160 return new File(logsRefsDir, name);
161 }
162 return new File(logsDir, name);
163 }
164
165
166
167
168
169
170
171
172
173
174 public ReflogWriter log(final String refName, final ReflogEntry entry)
175 throws IOException {
176 return log(refName, entry.getOldId(), entry.getNewId(), entry.getWho(),
177 entry.getComment());
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191 public ReflogWriter log(final String refName, final ObjectId oldId,
192 final ObjectId newId, final PersonIdent ident, final String message)
193 throws IOException {
194 byte[] encoded = encode(oldId, newId, ident, message);
195 return log(refName, encoded);
196 }
197
198
199
200
201
202
203
204
205
206
207 public ReflogWriter log(final RefUpdate update, final String msg,
208 final boolean deref) throws IOException {
209 final ObjectId oldId = update.getOldObjectId();
210 final ObjectId newId = update.getNewObjectId();
211 final Ref ref = update.getRef();
212
213 PersonIdent ident = update.getRefLogIdent();
214 if (ident == null)
215 ident = new PersonIdent(parent);
216 else
217 ident = new PersonIdent(ident);
218
219 final byte[] rec = encode(oldId, newId, ident, msg);
220 if (deref && ref.isSymbolic()) {
221 log(ref.getName(), rec);
222 log(ref.getLeaf().getName(), rec);
223 } else
224 log(ref.getName(), rec);
225
226 return this;
227 }
228
229 private byte[] encode(ObjectId oldId, ObjectId newId, PersonIdent ident,
230 String message) {
231 final StringBuilder r = new StringBuilder();
232 r.append(ObjectId.toString(oldId));
233 r.append(' ');
234 r.append(ObjectId.toString(newId));
235 r.append(' ');
236 r.append(ident.toExternalString());
237 r.append('\t');
238 r.append(message.replace("\r\n", " ").replace("\n", " "));
239 r.append('\n');
240 return Constants.encode(r.toString());
241 }
242
243 private ReflogWriter log(final String refName, final byte[] rec)
244 throws IOException {
245 final File log = logFor(refName);
246 final boolean write = forceWrite
247 || (isLogAllRefUpdates() && shouldAutoCreateLog(refName))
248 || log.isFile();
249 if (!write)
250 return this;
251
252 WriteConfig wc = getRepository().getConfig().get(WriteConfig.KEY);
253 FileOutputStream out;
254 try {
255 out = new FileOutputStream(log, true);
256 } catch (FileNotFoundException err) {
257 final File dir = log.getParentFile();
258 if (dir.exists())
259 throw err;
260 if (!dir.mkdirs() && !dir.isDirectory())
261 throw new IOException(MessageFormat.format(
262 JGitText.get().cannotCreateDirectory, dir));
263 out = new FileOutputStream(log, true);
264 }
265 try {
266 if (wc.getFSyncRefFiles()) {
267 FileChannel fc = out.getChannel();
268 ByteBuffer buf = ByteBuffer.wrap(rec);
269 while (0 < buf.remaining())
270 fc.write(buf);
271 fc.force(true);
272 } else
273 out.write(rec);
274 } finally {
275 out.close();
276 }
277 return this;
278 }
279
280 private boolean isLogAllRefUpdates() {
281 return parent.getConfig().get(CoreConfig.KEY).isLogAllRefUpdates();
282 }
283
284 private boolean shouldAutoCreateLog(final String refName) {
285 return refName.equals(HEAD)
286 || refName.startsWith(R_HEADS)
287 || refName.startsWith(R_REMOTES)
288 || refName.equals(R_STASH);
289 }
290 }