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.LockFailedException;
59 import org.eclipse.jgit.errors.ConfigInvalidException;
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 public void save() throws IOException {
189 final byte[] out;
190 final String text = toText();
191 if (utf8Bom) {
192 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
193 bos.write(0xEF);
194 bos.write(0xBB);
195 bos.write(0xBF);
196 bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET.name()));
197 out = bos.toByteArray();
198 } else {
199 out = Constants.encode(text);
200 }
201
202 final LockFile lf = new LockFile(getFile());
203 if (!lf.lock())
204 throw new LockFailedException(getFile());
205 try {
206 lf.setNeedSnapshot(true);
207 lf.write(out);
208 if (!lf.commit())
209 throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile()));
210 } finally {
211 lf.unlock();
212 }
213 snapshot = lf.getCommitSnapshot();
214 hash = hash(out);
215
216 fireConfigChangedEvent();
217 }
218
219 @Override
220 public void clear() {
221 hash = hash(new byte[0]);
222 super.clear();
223 }
224
225 private static ObjectId hash(final byte[] rawText) {
226 return ObjectId.fromRaw(Constants.newMessageDigest().digest(rawText));
227 }
228
229 @SuppressWarnings("nls")
230 @Override
231 public String toString() {
232 return getClass().getSimpleName() + "[" + getFile().getPath() + "]";
233 }
234
235
236
237
238
239 public boolean isOutdated() {
240 return snapshot.isModified(getFile());
241 }
242 }