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
47
48
49
50 package org.eclipse.jgit.storage.file;
51
52 import java.io.ByteArrayOutputStream;
53 import java.io.File;
54 import java.io.FileNotFoundException;
55 import java.io.IOException;
56 import java.text.MessageFormat;
57
58 import org.eclipse.jgit.errors.ConfigInvalidException;
59 import org.eclipse.jgit.errors.LockFailedException;
60 import org.eclipse.jgit.internal.JGitText;
61 import org.eclipse.jgit.internal.storage.file.FileSnapshot;
62 import org.eclipse.jgit.internal.storage.file.LockFile;
63 import org.eclipse.jgit.lib.Config;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.ObjectId;
66 import org.eclipse.jgit.lib.StoredConfig;
67 import org.eclipse.jgit.util.FS;
68 import org.eclipse.jgit.util.IO;
69 import org.eclipse.jgit.util.RawParseUtils;
70
71
72
73
74 public class FileBasedConfig extends StoredConfig {
75 private final File configFile;
76
77 private boolean utf8Bom;
78
79 private volatile FileSnapshot snapshot;
80
81 private volatile ObjectId hash;
82
83
84
85
86
87
88
89
90
91
92 public FileBasedConfig(File cfgLocation, FS fs) {
93 this(null, cfgLocation, fs);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 public FileBasedConfig(Config base, File cfgLocation, FS fs) {
108 super(base);
109 configFile = cfgLocation;
110 this.snapshot = FileSnapshot.DIRTY;
111 this.hash = ObjectId.zeroId();
112 }
113
114 @Override
115 protected boolean notifyUponTransientChanges() {
116
117 return false;
118 }
119
120
121 public final File getFile() {
122 return configFile;
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136 @Override
137 public void load() throws IOException, ConfigInvalidException {
138 final FileSnapshot oldSnapshot = snapshot;
139 final FileSnapshot newSnapshot = FileSnapshot.save(getFile());
140 try {
141 final byte[] in = IO.readFully(getFile());
142 final ObjectId newHash = hash(in);
143 if (hash.equals(newHash)) {
144 if (oldSnapshot.equals(newSnapshot))
145 oldSnapshot.setClean(newSnapshot);
146 else
147 snapshot = newSnapshot;
148 } else {
149 final String decoded;
150 if (isUtf8(in)) {
151 decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
152 in, 3, in.length);
153 utf8Bom = true;
154 } else {
155 decoded = RawParseUtils.decode(in);
156 }
157 fromText(decoded);
158 snapshot = newSnapshot;
159 hash = newHash;
160 }
161 } catch (FileNotFoundException noFile) {
162 if (configFile.exists()) {
163 throw noFile;
164 }
165 clear();
166 snapshot = newSnapshot;
167 } catch (IOException e) {
168 final IOException e2 = new IOException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()));
169 e2.initCause(e);
170 throw e2;
171 } catch (ConfigInvalidException e) {
172 throw new ConfigInvalidException(MessageFormat.format(JGitText.get().cannotReadFile, getFile()), e);
173 }
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187
188 @Override
189 public void save() throws IOException {
190 final byte[] out;
191 final String text = toText();
192 if (utf8Bom) {
193 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
194 bos.write(0xEF);
195 bos.write(0xBB);
196 bos.write(0xBF);
197 bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name()));
198 out = bos.toByteArray();
199 } else {
200 out = Constants.encode(text);
201 }
202
203 final LockFile lf = new LockFile(getFile());
204 if (!lf.lock())
205 throw new LockFailedException(getFile());
206 try {
207 lf.setNeedSnapshot(true);
208 lf.write(out);
209 if (!lf.commit())
210 throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile()));
211 } finally {
212 lf.unlock();
213 }
214 snapshot = lf.getCommitSnapshot();
215 hash = hash(out);
216
217 fireConfigChangedEvent();
218 }
219
220 @Override
221 public void clear() {
222 hash = hash(new byte[0]);
223 super.clear();
224 }
225
226 private static ObjectId hash(final byte[] rawText) {
227 return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
228 }
229
230 @SuppressWarnings("nls")
231 @Override
232 public String toString() {
233 return getClass().getSimpleName() + "[" + getFile().getPath() + "]";
234 }
235
236
237
238
239
240 public boolean isOutdated() {
241 return snapshot.isModified(getFile());
242 }
243 }