1 /*******************************************************************************
2 * Copyright (C) 2008, 2009 Robin Rosenberg <robin.rosenberg@dewire.com>
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * See LICENSE for the full license text, also available.
7 *******************************************************************************/
8 package org
.spearce
.egit
.ui
.internal
.decorators
;
10 import java
.io
.IOException
;
12 import java
.util
.WeakHashMap
;
14 import org
.eclipse
.core
.resources
.IEncodedStorage
;
15 import org
.eclipse
.core
.resources
.IProject
;
16 import org
.eclipse
.core
.resources
.IResource
;
17 import org
.eclipse
.core
.runtime
.CoreException
;
18 import org
.eclipse
.jface
.text
.Document
;
19 import org
.eclipse
.team
.core
.RepositoryProvider
;
20 import org
.spearce
.egit
.core
.GitProvider
;
21 import org
.spearce
.egit
.core
.project
.RepositoryMapping
;
22 import org
.spearce
.egit
.ui
.Activator
;
23 import org
.spearce
.jgit
.lib
.AnyObjectId
;
24 import org
.spearce
.jgit
.lib
.Commit
;
25 import org
.spearce
.jgit
.lib
.Constants
;
26 import org
.spearce
.jgit
.lib
.IndexChangedEvent
;
27 import org
.spearce
.jgit
.lib
.ObjectId
;
28 import org
.spearce
.jgit
.lib
.ObjectLoader
;
29 import org
.spearce
.jgit
.lib
.RefsChangedEvent
;
30 import org
.spearce
.jgit
.lib
.Repository
;
31 import org
.spearce
.jgit
.lib
.RepositoryListener
;
32 import org
.spearce
.jgit
.lib
.Tree
;
33 import org
.spearce
.jgit
.lib
.TreeEntry
;
35 class GitDocument
extends Document
implements RepositoryListener
{
36 private final IResource resource
;
38 private ObjectId lastCommit
;
39 private ObjectId lastTree
;
40 private ObjectId lastBlob
;
42 static Map
<GitDocument
,Repository
> doc2repo
= new WeakHashMap
<GitDocument
, Repository
>();
44 static GitDocument
create(final IResource resource
) throws IOException
{
45 Activator
.trace("(GitDocument) create: " + resource
);
46 GitDocument ret
= null;
47 if (RepositoryProvider
.getProvider(resource
.getProject()) instanceof GitProvider
) {
48 ret
= new GitDocument(resource
);
50 final Repository repository
= ret
.getRepository();
51 if (repository
!= null)
52 repository
.addRepositoryChangedListener(ret
);
57 private GitDocument(IResource resource
) {
58 this.resource
= resource
;
59 GitDocument
.doc2repo
.put(this, getRepository());
62 private void setResolved(final AnyObjectId commit
, final AnyObjectId tree
, final AnyObjectId blob
, final String value
) {
63 lastCommit
= commit
!= null ? commit
.copy() : null;
64 lastTree
= tree
!= null ? tree
.copy() : null;
65 lastBlob
= blob
!= null ? blob
.copy() : null;
68 Activator
.trace("(GitDocument) resolved " + resource
+ " to " + lastBlob
+ " in " + lastCommit
+ "/" + lastTree
);
70 Activator
.trace("(GitDocument) unresolved " + resource
);
73 void populate() throws IOException
{
74 Activator
.trace("(GitDocument) populate: " + resource
);
75 final IProject project
= resource
.getProject();
76 RepositoryMapping mapping
= RepositoryMapping
.getMapping(project
);
77 if (mapping
== null) {
78 setResolved(null, null, null, "");
81 final String gitPath
= mapping
.getRepoRelativePath(resource
);
82 final Repository repository
= mapping
.getRepository();
83 String baseline
= GitQuickDiffProvider
.baseline
.get(repository
);
85 baseline
= Constants
.HEAD
;
86 ObjectId commitId
= repository
.resolve(baseline
);
87 if (commitId
!= null) {
88 if (commitId
.equals(lastCommit
)) {
89 Activator
.trace("(GitDocument) already resolved");
93 Activator
.logError("Could not resolve quickdiff baseline "
94 + baseline
+ " corresponding to " + resource
+ " in "
95 + repository
, new Throwable());
96 setResolved(null, null, null, "");
99 Commit baselineCommit
= repository
.mapCommit(commitId
);
100 if (baselineCommit
== null) {
101 Activator
.logError("Could not load commit " + commitId
+ " for "
102 + baseline
+ " corresponding to " + resource
+ " in "
103 + repository
, new Throwable());
104 setResolved(null, null, null, "");
107 ObjectId treeId
= baselineCommit
.getTreeId();
108 if (treeId
.equals(lastTree
)) {
109 Activator
.trace("(GitDocument) already resolved");
112 Tree baselineTree
= baselineCommit
.getTree();
113 if (baselineTree
== null) {
114 Activator
.logError("Could not load tree " + treeId
+ " for "
115 + baseline
+ " corresponding to " + resource
+ " in "
116 + repository
, new Throwable());
117 setResolved(null, null, null, "");
120 TreeEntry blobEntry
= baselineTree
.findBlobMember(gitPath
);
121 if (blobEntry
!= null && !blobEntry
.getId().equals(lastBlob
)) {
122 Activator
.trace("(GitDocument) compareTo: " + baseline
);
123 ObjectLoader loader
= repository
.openBlob(blobEntry
.getId());
124 byte[] bytes
= loader
.getBytes();
126 // Get the encoding for the current version. As a matter of
127 // principle one might want to use the eclipse settings for the
128 // version we are retrieving as that may be defined by the
129 // project settings, but there is no historic API for this.
130 IEncodedStorage encodedStorage
= ((IEncodedStorage
)resource
);
132 if (encodedStorage
!= null)
133 charset
= encodedStorage
.getCharset();
135 charset
= resource
.getParent().getDefaultCharset();
136 } catch (CoreException e
) {
137 charset
= Constants
.CHARACTER_ENCODING
;
139 // Finally we could consider validating the content with respect
140 // to the content. We don't do that here.
141 String s
= new String(bytes
, charset
);
142 setResolved(commitId
, baselineTree
.getId(), blobEntry
.getId(), s
);
143 Activator
.trace("(GitDocument) has reference doc, size=" + s
.length() + " bytes");
145 if (blobEntry
== null)
146 setResolved(null, null, null, "");
148 Activator
.trace("(GitDocument) already resolved");
153 Activator
.trace("(GitDocument) dispose: " + resource
);
154 doc2repo
.remove(this);
155 Repository repository
= getRepository();
156 if (repository
!= null)
157 repository
.removeRepositoryChangedListener(this);
160 public void refsChanged(final RefsChangedEvent e
) {
163 } catch (IOException e1
) {
164 Activator
.logError("Failed to refresh quickdiff", e1
);
168 public void indexChanged(final IndexChangedEvent e
) {
169 // Index not relevant at this moment
172 private Repository
getRepository() {
173 IProject project
= resource
.getProject();
174 RepositoryMapping mapping
= RepositoryMapping
.getMapping(project
);
176 return mapping
.getRepository();
181 * A change occurred to a repository. Update any GitDocument instances
182 * referring to such repositories.
184 * @param repository Repository which changed
185 * @throws IOException
187 static void refreshRelevant(final Repository repository
) throws IOException
{
188 for (Map
.Entry
<GitDocument
, Repository
> i
: doc2repo
.entrySet()) {
189 if (i
.getValue() == repository
) {
190 i
.getKey().populate();