1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jgit.internal.storage.file;
14
15 import static org.eclipse.jgit.lib.Constants.HEAD;
16 import static org.eclipse.jgit.lib.Constants.LOCK_SUFFIX;
17 import static org.eclipse.jgit.lib.Constants.R_HEADS;
18 import static org.eclipse.jgit.lib.Constants.R_NOTES;
19 import static org.eclipse.jgit.lib.Constants.R_REFS;
20 import static org.eclipse.jgit.lib.Constants.R_REMOTES;
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.nio.ByteBuffer;
27 import java.nio.channels.FileChannel;
28 import java.text.MessageFormat;
29
30 import org.eclipse.jgit.internal.JGitText;
31 import org.eclipse.jgit.lib.ConfigConstants;
32 import org.eclipse.jgit.lib.Constants;
33 import org.eclipse.jgit.lib.CoreConfig;
34 import org.eclipse.jgit.lib.ObjectId;
35 import org.eclipse.jgit.lib.PersonIdent;
36 import org.eclipse.jgit.lib.Ref;
37 import org.eclipse.jgit.lib.RefUpdate;
38 import org.eclipse.jgit.lib.ReflogEntry;
39 import org.eclipse.jgit.lib.Repository;
40 import org.eclipse.jgit.util.FileUtils;
41
42
43
44
45
46 public class ReflogWriter {
47
48
49
50
51
52
53
54
55
56 public static String refLockFor(String name) {
57 return name + LOCK_SUFFIX;
58 }
59
60 private final RefDirectory refdb;
61
62 private final boolean forceWrite;
63
64
65
66
67
68
69
70
71 public ReflogWriter(RefDirectory refdb) {
72 this(refdb, false);
73 }
74
75
76
77
78
79
80
81
82
83
84
85 public ReflogWriter(RefDirectory refdb, boolean forceWrite) {
86 this.refdb = refdb;
87 this.forceWrite = forceWrite;
88 }
89
90
91
92
93
94
95
96 public ReflogWriter create() throws IOException {
97 FileUtils.mkdir(refdb.logsDir);
98 FileUtils.mkdir(refdb.logsRefsDir);
99 FileUtils.mkdir(
100 new File(refdb.logsRefsDir, R_HEADS.substring(R_REFS.length())));
101 return this;
102 }
103
104
105
106
107
108
109
110
111
112
113
114 public ReflogWriter log(String refName, ReflogEntry entry)
115 throws IOException {
116 return log(refName, entry.getOldId(), entry.getNewId(), entry.getWho(),
117 entry.getComment());
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 public ReflogWriter log(String refName, ObjectId oldId,
137 ObjectId newId, PersonIdent ident, String message) throws IOException {
138 byte[] encoded = encode(oldId, newId, ident, message);
139 return log(refName, encoded);
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public ReflogWriter log(RefUpdate update, String msg,
155 boolean deref) throws IOException {
156 ObjectId oldId = update.getOldObjectId();
157 ObjectId newId = update.getNewObjectId();
158 Ref ref = update.getRef();
159
160 PersonIdent ident = update.getRefLogIdent();
161 if (ident == null)
162 ident = new PersonIdent(refdb.getRepository());
163 else
164 ident = new PersonIdent(ident);
165
166 byte[] rec = encode(oldId, newId, ident, msg);
167 if (deref && ref.isSymbolic()) {
168 log(ref.getName(), rec);
169 log(ref.getLeaf().getName(), rec);
170 } else
171 log(ref.getName(), rec);
172
173 return this;
174 }
175
176 private byte[] encode(ObjectId"../../../../../../org/eclipse/jgit/lib/ObjectId.html#ObjectId">ObjectId oldId, ObjectId newId, PersonIdent ident,
177 String message) {
178 StringBuilder r = new StringBuilder();
179 r.append(ObjectId.toString(oldId));
180 r.append(' ');
181 r.append(ObjectId.toString(newId));
182 r.append(' ');
183 r.append(ident.toExternalString());
184 r.append('\t');
185 r.append(
186 message.replace("\r\n", " ")
187 .replace("\n", " "));
188 r.append('\n');
189 return Constants.encode(r.toString());
190 }
191
192 private FileOutputStream getFileOutputStream(File log) throws IOException {
193 try {
194 return new FileOutputStream(log, true);
195 } catch (FileNotFoundException err) {
196 File dir = log.getParentFile();
197 if (dir.exists()) {
198 throw err;
199 }
200 if (!dir.mkdirs() && !dir.isDirectory()) {
201 throw new IOException(MessageFormat
202 .format(JGitText.get().cannotCreateDirectory, dir));
203 }
204 return new FileOutputStream(log, true);
205 }
206 }
207
208 private ReflogWriter log(String refName, byte[] rec) throws IOException {
209 File log = refdb.logFor(refName);
210 boolean write = forceWrite
211 || shouldAutoCreateLog(refName)
212 || log.isFile();
213 if (!write)
214 return this;
215
216 WriteConfig wc = refdb.getRepository().getConfig().get(WriteConfig.KEY);
217 try (FileOutputStream out = getFileOutputStream(log)) {
218 if (wc.getFSyncRefFiles()) {
219 FileChannel fc = out.getChannel();
220 ByteBuffer buf = ByteBuffer.wrap(rec);
221 while (0 < buf.remaining()) {
222 fc.write(buf);
223 }
224 fc.force(true);
225 } else {
226 out.write(rec);
227 }
228 }
229 return this;
230 }
231
232 private boolean shouldAutoCreateLog(String refName) {
233 Repository repo = refdb.getRepository();
234 CoreConfig.LogRefUpdates value = repo.isBare()
235 ? CoreConfig.LogRefUpdates.FALSE
236 : CoreConfig.LogRefUpdates.TRUE;
237 value = repo.getConfig().getEnum(ConfigConstants.CONFIG_CORE_SECTION,
238 null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, value);
239 if (value != null) {
240 switch (value) {
241 case FALSE:
242 break;
243 case TRUE:
244 return refName.equals(HEAD) || refName.startsWith(R_HEADS)
245 || refName.startsWith(R_REMOTES)
246 || refName.startsWith(R_NOTES);
247 case ALWAYS:
248 return refName.equals(HEAD) || refName.startsWith(R_REFS);
249 default:
250 break;
251 }
252 }
253 return false;
254 }
255 }