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 package org.eclipse.jgit.internal.storage.file;
48
49 import static org.eclipse.jgit.lib.RefDatabase.ALL;
50
51 import java.io.File;
52 import java.io.FileInputStream;
53 import java.io.FileNotFoundException;
54 import java.io.IOException;
55 import java.text.MessageFormat;
56 import java.util.HashSet;
57 import java.util.Set;
58
59 import org.eclipse.jgit.attributes.AttributesNode;
60 import org.eclipse.jgit.attributes.AttributesNodeProvider;
61 import org.eclipse.jgit.errors.ConfigInvalidException;
62 import org.eclipse.jgit.events.ConfigChangedEvent;
63 import org.eclipse.jgit.events.ConfigChangedListener;
64 import org.eclipse.jgit.events.IndexChangedEvent;
65 import org.eclipse.jgit.internal.JGitText;
66 import org.eclipse.jgit.internal.storage.reftree.RefTreeDatabase;
67 import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateHandle;
68 import org.eclipse.jgit.internal.storage.file.ObjectDirectory.AlternateRepository;
69 import org.eclipse.jgit.lib.BaseRepositoryBuilder;
70 import org.eclipse.jgit.lib.ConfigConstants;
71 import org.eclipse.jgit.lib.Constants;
72 import org.eclipse.jgit.lib.CoreConfig.HideDotFiles;
73 import org.eclipse.jgit.lib.CoreConfig.SymLinks;
74 import org.eclipse.jgit.lib.ObjectId;
75 import org.eclipse.jgit.lib.Ref;
76 import org.eclipse.jgit.lib.RefDatabase;
77 import org.eclipse.jgit.lib.RefUpdate;
78 import org.eclipse.jgit.lib.ReflogReader;
79 import org.eclipse.jgit.lib.Repository;
80 import org.eclipse.jgit.storage.file.FileBasedConfig;
81 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
82 import org.eclipse.jgit.util.FS;
83 import org.eclipse.jgit.util.FileUtils;
84 import org.eclipse.jgit.util.StringUtils;
85 import org.eclipse.jgit.util.SystemReader;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 public class FileRepository extends Repository {
113 private final FileBasedConfig systemConfig;
114
115 private final FileBasedConfig userConfig;
116
117 private final FileBasedConfig repoConfig;
118
119 private final RefDatabase refs;
120
121 private final ObjectDirectory objectDatabase;
122
123 private FileSnapshot snapshot;
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 public FileRepository(final File gitDir) throws IOException {
145 this(new FileRepositoryBuilder().setGitDir(gitDir).setup());
146 }
147
148
149
150
151
152
153
154
155
156
157
158 public FileRepository(final String gitDir) throws IOException {
159 this(new File(gitDir));
160 }
161
162
163
164
165
166
167
168
169
170
171 public FileRepository(final BaseRepositoryBuilder options) throws IOException {
172 super(options);
173
174 if (StringUtils.isEmptyOrNull(SystemReader.getInstance().getenv(
175 Constants.GIT_CONFIG_NOSYSTEM_KEY)))
176 systemConfig = SystemReader.getInstance().openSystemConfig(null,
177 getFS());
178 else
179 systemConfig = new FileBasedConfig(null, FS.DETECTED) {
180 public void load() {
181
182 }
183
184 public boolean isOutdated() {
185
186 return false;
187 }
188 };
189 userConfig = SystemReader.getInstance().openUserConfig(systemConfig,
190 getFS());
191 repoConfig = new FileBasedConfig(userConfig, getFS().resolve(
192 getDirectory(), Constants.CONFIG),
193 getFS());
194
195 loadSystemConfig();
196 loadUserConfig();
197 loadRepoConfig();
198
199 repoConfig.addChangeListener(new ConfigChangedListener() {
200 public void onConfigChanged(ConfigChangedEvent event) {
201 fireEvent(event);
202 }
203 });
204
205 final long repositoryFormatVersion = getConfig().getLong(
206 ConfigConstants.CONFIG_CORE_SECTION, null,
207 ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
208
209 String reftype = repoConfig.getString(
210 "extensions", null, "refsStorage");
211 if (repositoryFormatVersion >= 1 && reftype != null) {
212 if (StringUtils.equalsIgnoreCase(reftype, "reftree")) {
213 refs = new RefTreeDatabase(this, new RefDirectory(this));
214 } else {
215 throw new IOException(JGitText.get().unknownRepositoryFormat);
216 }
217 } else {
218 refs = new RefDirectory(this);
219 }
220
221 objectDatabase = new ObjectDirectory(repoConfig,
222 options.getObjectDirectory(),
223 options.getAlternateObjectDirectories(),
224 getFS(),
225 new File(getDirectory(), Constants.SHALLOW));
226
227 if (objectDatabase.exists()) {
228 if (repositoryFormatVersion > 1)
229 throw new IOException(MessageFormat.format(
230 JGitText.get().unknownRepositoryFormat2,
231 Long.valueOf(repositoryFormatVersion)));
232 }
233
234 if (!isBare())
235 snapshot = FileSnapshot.save(getIndexFile());
236 }
237
238 private void loadSystemConfig() throws IOException {
239 try {
240 systemConfig.load();
241 } catch (ConfigInvalidException e1) {
242 IOException e2 = new IOException(MessageFormat.format(JGitText
243 .get().systemConfigFileInvalid, systemConfig.getFile()
244 .getAbsolutePath(), e1));
245 e2.initCause(e1);
246 throw e2;
247 }
248 }
249
250 private void loadUserConfig() throws IOException {
251 try {
252 userConfig.load();
253 } catch (ConfigInvalidException e1) {
254 IOException e2 = new IOException(MessageFormat.format(JGitText
255 .get().userConfigFileInvalid, userConfig.getFile()
256 .getAbsolutePath(), e1));
257 e2.initCause(e1);
258 throw e2;
259 }
260 }
261
262 private void loadRepoConfig() throws IOException {
263 try {
264 repoConfig.load();
265 } catch (ConfigInvalidException e1) {
266 IOException e2 = new IOException(JGitText.get().unknownRepositoryFormat);
267 e2.initCause(e1);
268 throw e2;
269 }
270 }
271
272
273
274
275
276
277
278
279
280
281
282 public void create(boolean bare) throws IOException {
283 final FileBasedConfig cfg = getConfig();
284 if (cfg.getFile().exists()) {
285 throw new IllegalStateException(MessageFormat.format(
286 JGitText.get().repositoryAlreadyExists, getDirectory()));
287 }
288 FileUtils.mkdirs(getDirectory(), true);
289 HideDotFiles hideDotFiles = getConfig().getEnum(
290 ConfigConstants.CONFIG_CORE_SECTION, null,
291 ConfigConstants.CONFIG_KEY_HIDEDOTFILES,
292 HideDotFiles.DOTGITONLY);
293 if (hideDotFiles != HideDotFiles.FALSE && !isBare()
294 && getDirectory().getName().startsWith("."))
295 getFS().setHidden(getDirectory(), true);
296 refs.create();
297 objectDatabase.create();
298
299 FileUtils.mkdir(new File(getDirectory(), "branches"));
300 FileUtils.mkdir(new File(getDirectory(), "hooks"));
301
302 RefUpdate head = updateRef(Constants.HEAD);
303 head.disableRefLog();
304 head.link(Constants.R_HEADS + Constants.MASTER);
305
306 final boolean fileMode;
307 if (getFS().supportsExecute()) {
308 File tmp = File.createTempFile("try", "execute", getDirectory());
309
310 getFS().setExecute(tmp, true);
311 final boolean on = getFS().canExecute(tmp);
312
313 getFS().setExecute(tmp, false);
314 final boolean off = getFS().canExecute(tmp);
315 FileUtils.delete(tmp);
316
317 fileMode = on && !off;
318 } else {
319 fileMode = false;
320 }
321
322 SymLinks symLinks = SymLinks.FALSE;
323 if (getFS().supportsSymlinks()) {
324 File tmp = new File(getDirectory(), "tmplink");
325 try {
326 getFS().createSymLink(tmp, "target");
327 symLinks = null;
328 FileUtils.delete(tmp);
329 } catch (IOException e) {
330
331 }
332 }
333 if (symLinks != null)
334 cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
335 ConfigConstants.CONFIG_KEY_SYMLINKS, symLinks.name()
336 .toLowerCase());
337 cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null,
338 ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
339 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
340 ConfigConstants.CONFIG_KEY_FILEMODE, fileMode);
341 if (bare)
342 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
343 ConfigConstants.CONFIG_KEY_BARE, true);
344 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
345 ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, !bare);
346 if (SystemReader.getInstance().isMacOS())
347
348 cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
349 ConfigConstants.CONFIG_KEY_PRECOMPOSEUNICODE, true);
350 if (!bare) {
351 File workTree = getWorkTree();
352 if (!getDirectory().getParentFile().equals(workTree)) {
353 cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
354 ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree()
355 .getAbsolutePath());
356 LockFile dotGitLockFile = new LockFile(new File(workTree,
357 Constants.DOT_GIT));
358 try {
359 if (dotGitLockFile.lock()) {
360 dotGitLockFile.write(Constants.encode(Constants.GITDIR
361 + getDirectory().getAbsolutePath()));
362 dotGitLockFile.commit();
363 }
364 } finally {
365 dotGitLockFile.unlock();
366 }
367 }
368 }
369 cfg.save();
370 }
371
372
373
374
375 public File getObjectsDirectory() {
376 return objectDatabase.getDirectory();
377 }
378
379
380
381
382 public ObjectDirectory getObjectDatabase() {
383 return objectDatabase;
384 }
385
386
387 public RefDatabase getRefDatabase() {
388 return refs;
389 }
390
391
392
393
394 public FileBasedConfig getConfig() {
395 if (systemConfig.isOutdated()) {
396 try {
397 loadSystemConfig();
398 } catch (IOException e) {
399 throw new RuntimeException(e);
400 }
401 }
402 if (userConfig.isOutdated()) {
403 try {
404 loadUserConfig();
405 } catch (IOException e) {
406 throw new RuntimeException(e);
407 }
408 }
409 if (repoConfig.isOutdated()) {
410 try {
411 loadRepoConfig();
412 } catch (IOException e) {
413 throw new RuntimeException(e);
414 }
415 }
416 return repoConfig;
417 }
418
419
420
421
422
423
424
425
426
427
428
429 public Set<ObjectId> getAdditionalHaves() {
430 HashSet<ObjectId> r = new HashSet<ObjectId>();
431 for (AlternateHandle d : objectDatabase.myAlternates()) {
432 if (d instanceof AlternateRepository) {
433 Repository repo;
434
435 repo = ((AlternateRepository) d).repository;
436 for (Ref ref : repo.getAllRefs().values()) {
437 if (ref.getObjectId() != null)
438 r.add(ref.getObjectId());
439 if (ref.getPeeledObjectId() != null)
440 r.add(ref.getPeeledObjectId());
441 }
442 r.addAll(repo.getAdditionalHaves());
443 }
444 }
445 return r;
446 }
447
448
449
450
451
452
453
454
455
456
457 public void openPack(final File pack) throws IOException {
458 objectDatabase.openPack(pack);
459 }
460
461 @Override
462 public void scanForRepoChanges() throws IOException {
463 getRefDatabase().getRefs(ALL);
464 detectIndexChanges();
465 }
466
467
468
469
470 private void detectIndexChanges() {
471 if (isBare())
472 return;
473
474 File indexFile = getIndexFile();
475 if (snapshot == null)
476 snapshot = FileSnapshot.save(indexFile);
477 else if (snapshot.isModified(indexFile))
478 notifyIndexChanged();
479 }
480
481 @Override
482 public void notifyIndexChanged() {
483 snapshot = FileSnapshot.save(getIndexFile());
484 fireEvent(new IndexChangedEvent());
485 }
486
487
488
489
490
491
492
493 public ReflogReader getReflogReader(String refName) throws IOException {
494 Ref ref = findRef(refName);
495 if (ref != null)
496 return new ReflogReaderImpl(this, ref.getName());
497 return null;
498 }
499
500 @Override
501 public AttributesNodeProvider createAttributesNodeProvider() {
502 return new AttributesNodeProviderImpl(this);
503 }
504
505
506
507
508
509
510
511
512 static class AttributesNodeProviderImpl implements
513 AttributesNodeProvider {
514
515 private AttributesNode infoAttributesNode;
516
517 private AttributesNode globalAttributesNode;
518
519
520
521
522
523
524
525 protected AttributesNodeProviderImpl(Repository repo) {
526 infoAttributesNode = new InfoAttributesNode(repo);
527 globalAttributesNode = new GlobalAttributesNode(repo);
528 }
529
530 public AttributesNode getInfoAttributesNode() throws IOException {
531 if (infoAttributesNode instanceof InfoAttributesNode)
532 infoAttributesNode = ((InfoAttributesNode) infoAttributesNode)
533 .load();
534 return infoAttributesNode;
535 }
536
537 public AttributesNode getGlobalAttributesNode() throws IOException {
538 if (globalAttributesNode instanceof GlobalAttributesNode)
539 globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
540 .load();
541 return globalAttributesNode;
542 }
543
544 static void loadRulesFromFile(AttributesNode r, File attrs)
545 throws FileNotFoundException, IOException {
546 if (attrs.exists()) {
547 FileInputStream in = new FileInputStream(attrs);
548 try {
549 r.parse(in);
550 } finally {
551 in.close();
552 }
553 }
554 }
555
556 }
557
558 }