Git development
 help / color / mirror / Atom feed
* Re: [CFH] Broken permissions in repo.or.cz repositories
From: Petr Baudis @ 2008-07-10 23:19 UTC (permalink / raw)
  To: git; +Cc: Jesper Louis Andersen
In-Reply-To: <20080710230058.GQ10151@machine.or.cz>

  Hi,

On Fri, Jul 11, 2008 at 01:00:58AM +0200, Petr Baudis wrote:
>   turns out current git has buggy handling of the sharedRepository
> config parameter, resulting in permission problems. Hopefully fixed.

  sorry, this was not supposed to be cc'd to the mailing list in the
end, and is not CFH anymore. I'm trying to send a patch to the mailing
list now. :-)

-- 
				Petr "Pasky" Baudis
The last good thing written in C++ was the Pachelbel Canon. -- J. Olson

^ permalink raw reply

* Re: [PATCH] bisect: test merge base if good rev is not an ancestor of bad rev
From: Christian Couder @ 2008-07-10 23:21 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, Michael Haggerty, Jeff King, git
In-Reply-To: <alpine.DEB.1.00.0807110035180.3279@eeepc-johanness>

Le vendredi 11 juillet 2008, Johannes Schindelin a écrit :
> Hi,
>
> On Fri, 11 Jul 2008, Christian Couder wrote:
> > Le jeudi 10 juillet 2008, Junio C Hamano a écrit :
> > >  - "Test this merge-base before going forward, please" will add
> > >    typically only one round of check (if you have more merge bases
> > >    between good and bad, you need to test all of them are good to be
> > >    sure), so it is not "slower nor more complex".
> >
> > By "slower" I meant that it would need more rounds of check on average.
> > By "more complex" I meant that more code is needed.
> >
> > And I think you are right, all the merge bases need to be tested so I
> > will send a patch on top of the patch discussed here.
>
> Good luck.  This will open the scenario where people use a proper
> ancestor as "good" revision.  In this case, you test that.

If a proper ancestor is used as good rev, then the merge base between this 
good rev and the bad rev is this good rev, and as it is known to be good it 
doesn't need to be tested by the user. I think my patch handles this well.

> If it is 
> "bad" you report that it is the _first_ one.
>
> You are opening a can of worms here, and I doubt that this is a good
> idea.
>
> git-bisect as-is has very precise, and _simple_ semantics, and users
> should really know what they are doing (i.e. not marking something as
> "good" which is on a branch containing a fix).

I think that users don't and can't always know what they are doing. If there 
is a revert in a branch for example, how can they know all the bugs that it 
fixes?

> Trying to be too clever here might just make the whole tool rather
> useless.

I don't think so. I think that if user can trust "git bisect" more, they 
will use it more, and in more automated ways and everyone will win in the 
end.

Regards,
Christian.

^ permalink raw reply

* Re: [PATCH] bisect: test merge base if good rev is not an ancestor of bad rev
From: Junio C Hamano @ 2008-07-10 23:10 UTC (permalink / raw)
  To: Christian Couder; +Cc: Johannes Schindelin, Michael Haggerty, Jeff King, git
In-Reply-To: <200807110036.17504.chriscool@tuxfamily.org>

Christian Couder <chriscool@tuxfamily.org> writes:

> Another idea to fix the problem, might be to bisect as usual and at the end 
> before saying "X is first bad commit" to check if some of X parents are 
> merge bases between the bad rev and a good rev. If that is the case, then 
> we could ask the user to check that these parents are all good. On average 
> this would probably reduce the number of revs the user must check.

I do not think that would fly well.  After spending long bisection cycle,
you will be telling the user that it was a wild goose chase (iow, the user
did an invalid bisection and what we stopped at was not the first
breakage).  If the bisection topology is invalid, we should tell the user
before he wastes too much time.

The sad part is that the biesction log from such an initial round would
not be very useful for reusing even if the user then chooses to hunt for
the "fix" on the side branch to forward port, in which case the meaning of
good and bad needs to be swapped from the beginning.

^ permalink raw reply

* Re: feature request: git-log should accept sth like v2.6.26-rc8-227
From: Jakub Narebski @ 2008-07-10 23:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, Toralf Förster, git
In-Reply-To: <7vk5ftnyhp.fsf@gitster.siamese.dyndns.org>

Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>> On Thu, 10 Jul 2008, Junio C Hamano wrote:
>>> Jakub Narebski <jnareb@gmail.com> writes:
>>> 
>>>> Besides, it would be nice to have some command (git-rev-parse 
>>>> perhaps?) which could take ambiguous commit-ish, and list all commit 
>>>> which matches it.
>>> 
>>> Have fun writing it and send in a patch.
>>
>> Note that this really could be a patch, but not for rev-parse.  Patch 
>> revision.c instead to parse the argument into _all_ matching revisions.
> 
> As Linus pointed out, that is "all _locally_ matching revisions".  It is
> of dubious value in a distributed environment.

It can be useful for example in situation where shortened sha-1 of
a commit (for example to 6 characters) stops being ambiguous...

-- 
Jakub Narebski
Poland

^ permalink raw reply

* [CFH] Broken permissions in repo.or.cz repositories
From: Petr Baudis @ 2008-07-10 23:00 UTC (permalink / raw)
  To: Jesper Louis Andersen; +Cc: git
In-Reply-To: <56a0a2840807101218n7a280b67gfb3c579ada6b0e02@mail.gmail.com>

  Hi,

On Thu, Jul 10, 2008 at 09:18:18PM +0200, Jesper Louis Andersen wrote:
> I have run into a problem with your new fine cloud-changes: whenever I
> push changes to the 'master'
> branch of the etorrent.git repository, the overview page at
> http://repo.or.cz/w/etorrent.git removes
> the shortlog and shows no master branch at all. This problem means that we get:
> 
> jlouis@ogre:~/tmp$ git clone git://repo.or.cz/etorrent.git/
> Initialized empty Git repository in /home/jlouis/tmp/etorrent/.git/
> fatal: The remote end hung up unexpectedly
> 
> for new checkouts. Now, I've found a fix which is to pull over ssh:
> 
> jlouis@ogre:~/tmp$ git clone git+ssh://repo.or.cz/srv/git/etorrent.git
> Initialized empty Git repository in /home/jlouis/tmp/etorrent/.git/
> remote: Counting objects: 7510, done.
> remote: Compressing objReceiving objects:   9% (676/7510), 100.00 KiB
> | 167 KiB/remote: Compressing objects:  69% (1649/238Receiving
> objects:  10% (751/7510), 1remote: Compressing obReceiving objects:
> 12% (902/7510), 100.00 KiB | 167 KiB/sremote: Comremote: pressing
> objects: 100% (2389/2389), done.
> remote: Total 7510 (delta 4432), reused 7510 (delta 4432)
> Receiving objects: 100% (7510/7510), 1.93 MiB | 517 KiB/s, done.
> Resolving deltas: 100% (4432/4432), done.
> jlouis@ogre:~/tmp$ ls
> 
> which, as you can see, works. Then one can clone via git://... until I
> make another push and we are
> back to square one. I have not been able to find another repository
> having the same problem which
> makes me wonder if there is something wrong with my repository state
> which becomes fixed when it compresses
> the objects when I use the git+ssh transport?
> 
> For the sake of completeness, it is Ubuntu 8.04 here with git --version:
> 
> jlouis@ogre:~$ git --version
> git version 1.5.4.3

  turns out current git has buggy handling of the sharedRepository
config parameter, resulting in permission problems. Hopefully fixed.

-- 
				Petr "Pasky" Baudis
The last good thing written in C++ was the Pachelbel Canon. -- J. Olson

^ permalink raw reply

* Re: feature request: git-log should accept sth like v2.6.26-rc8-227
From: Junio C Hamano @ 2008-07-10 22:52 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Jakub Narebski, Toralf Förster, git
In-Reply-To: <alpine.DEB.1.00.0807110022510.3279@eeepc-johanness>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> On Thu, 10 Jul 2008, Junio C Hamano wrote:
>
>> Jakub Narebski <jnareb@gmail.com> writes:
>> 
>> > Besides, it would be nice to have some command (git-rev-parse 
>> > perhaps?) which could take ambiguous commit-ish, and list all commit 
>> > which matches it.
>> 
>> Have fun writing it and send in a patch.
>
> Note that this really could be a patch, but not for rev-parse.  Patch 
> revision.c instead to parse the argument into _all_ matching revisions.

As Linus pointed out, that is "all _locally_ matching revisions".  It is
of dubious value in a distributed environment.

^ permalink raw reply

* Re: [JGIT PATCH 2/5] Don't display passwords on the console in fetch/push output
From: Robin Rosenberg @ 2008-07-10 22:42 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Shawn O. Pearce, Marek Zawirski, git
In-Reply-To: <alpine.DEB.1.00.0807110024480.3279@eeepc-johanness>

fredagen den 11 juli 2008 00.25.27 skrev Johannes Schindelin:
> Hi,
> 
> On Thu, 10 Jul 2008, Robin Rosenberg wrote:
> 
> > >From 99c09cf2321f36eb81043aed2fa6834811ee762b Mon Sep 17 00:00:00 2001
> > From: Robin Rosenberg <robin.rosenberg@dewire.com>
> > Date: Thu, 10 Jul 2008 22:16:19 +0200
> > Subject: [PATCH] Avoid password leak from URIIsh
> 
> What is this new fashion of sending them headers in the mail body?  Robin, 
> I thought you knew better.

Laziness, I suppose, and that's not a new fashion. I'll try to have better in the future.

-- robin

^ permalink raw reply

* [EGIT PATCH 0/2] Quickdiff improvement
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg

Connect quickdiff to the repository event mechanism and allow us
to specify what to compare against.

-- robin

Robin Rosenberg (2):
  Make quick diff aware of changes in the repository.
  Provide the ability to configure the quickdiff baseline

 org.spearce.egit.ui/plugin.properties              |    2 +-
 org.spearce.egit.ui/plugin.xml                     |   14 +++
 .../actions/QuickdiffBaselineOperation.java        |   44 ++++++++++
 .../actions/ResetQuickdiffBaselineAction.java      |   24 +++++
 .../actions/SetQuickdiffBaselineAction.java        |   26 ++++++
 .../egit/ui/internal/decorators/GitDocument.java   |   86 +++++++++++++++++++
 .../internal/decorators/GitQuickDiffProvider.java  |   90 +++++++++-----------
 7 files changed, 236 insertions(+), 50 deletions(-)
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/QuickdiffBaselineOperation.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ResetQuickdiffBaselineAction.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SetQuickdiffBaselineAction.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java

^ permalink raw reply

* [EGIT PATCH 2/2] Provide the ability to configure the quickdiff baseline
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729672-26906-2-git-send-email-robin.rosenberg@dewire.com>

By default quickdiff compares to HEAD, but you can change that
using the context menu in the history graph. The setting is
remembered during a session on a per Git repository basis.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 org.spearce.egit.ui/plugin.properties              |    2 +-
 org.spearce.egit.ui/plugin.xml                     |   14 +++++
 .../actions/QuickdiffBaselineOperation.java        |   44 +++++++++++++++
 .../actions/ResetQuickdiffBaselineAction.java      |   24 ++++++++
 .../actions/SetQuickdiffBaselineAction.java        |   26 +++++++++
 .../egit/ui/internal/decorators/GitDocument.java   |   57 ++++++-------------
 .../internal/decorators/GitQuickDiffProvider.java  |   33 +++++++++++-
 7 files changed, 158 insertions(+), 42 deletions(-)
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/QuickdiffBaselineOperation.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ResetQuickdiffBaselineAction.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SetQuickdiffBaselineAction.java

diff --git a/org.spearce.egit.ui/plugin.properties b/org.spearce.egit.ui/plugin.properties
index 64a88c3..3240ec0 100644
--- a/org.spearce.egit.ui/plugin.properties
+++ b/org.spearce.egit.ui/plugin.properties
@@ -6,7 +6,7 @@ Git_clone_wizard=Git Repository
 Git_clone_description=Clone an existing Git repository.
 
 SharingWizard_name=Git
-GitRemoteQuickDiffProvider_label=Latest Git Revision
+GitRemoteQuickDiffProvider_label=A Git Revision
 
 DisconnectAction_label=Disconnect
 DisconnectAction_tooltip=Disconnect the Git team provider.
diff --git a/org.spearce.egit.ui/plugin.xml b/org.spearce.egit.ui/plugin.xml
index cfd4b80..b809300 100644
--- a/org.spearce.egit.ui/plugin.xml
+++ b/org.spearce.egit.ui/plugin.xml
@@ -124,6 +124,20 @@
                enablesFor="1"
                tooltip="Resets HEAD and index, and working directory (changed in tracked files will be lost)">
          </action>
+	 <action
+	       class="org.spearce.egit.ui.internal.actions.SetQuickdiffBaselineAction"
+	       enablesFor="1"
+	       id="org.spearce.egit.ui.setquickdiffbaseline"
+	       label="Set as quickdiff baseline"
+	       menubarPath="additions">
+	 </action>
+	 <action
+	       class="org.spearce.egit.ui.internal.actions.ResetQuickdiffBaselineAction"
+	       enablesFor="*"
+	       id="org.spearce.egit.ui.resetquickdiffbaseline"
+	       label="Reset quickdiff baseline to HEAD"
+	       menubarPath="additions">
+	 </action>
 	  </objectContribution>
    </extension>
 
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/QuickdiffBaselineOperation.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/QuickdiffBaselineOperation.java
new file mode 100644
index 0000000..990958f
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/QuickdiffBaselineOperation.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.spearce.egit.ui.Activator;
+import org.spearce.egit.ui.internal.decorators.GitQuickDiffProvider;
+import org.spearce.jgit.lib.Repository;
+
+/**
+ * UI operation to change the git quickdiff baseline
+ */
+public class QuickdiffBaselineOperation extends AbstractRevObjectOperation {
+
+	private final String baseline;
+
+	/**
+	 * Construct a QuickdiffBaselineOperation for changing quickdiff baseline
+	 * @param repository
+	 *
+	 * @param baseline
+	 */
+	QuickdiffBaselineOperation(final Repository repository, final String baseline) {
+		super(repository);
+		this.baseline = baseline;
+	}
+
+	public void run(IProgressMonitor monitor) throws CoreException {
+		try {
+			GitQuickDiffProvider.setBaselineReference(repository, baseline);
+		} catch (IOException e) {
+			Activator.logError("Cannot set quickdiff basekine", e);
+		}
+	}
+
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ResetQuickdiffBaselineAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ResetQuickdiffBaselineAction.java
new file mode 100644
index 0000000..a42635a
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/ResetQuickdiffBaselineAction.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.jface.action.IAction;
+
+/**
+ * Changes the reference for the quickdiff
+ */
+public class ResetQuickdiffBaselineAction extends AbstractRevObjectAction {
+
+	@Override
+	protected IWorkspaceRunnable createOperation(IAction act, List selection) {
+		return new QuickdiffBaselineOperation(getActiveRepository(), "HEAD");
+	}
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SetQuickdiffBaselineAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SetQuickdiffBaselineAction.java
new file mode 100644
index 0000000..05686cf
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SetQuickdiffBaselineAction.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.jface.action.IAction;
+import org.spearce.jgit.revwalk.RevObject;
+
+/**
+ * Changes the reference for the quickdiff
+ */
+public class SetQuickdiffBaselineAction extends AbstractRevObjectAction {
+
+	@Override
+	protected IWorkspaceRunnable createOperation(IAction act, List selection) {
+		return new QuickdiffBaselineOperation(getActiveRepository(), ((RevObject)selection.get(0)).getId().toString());
+	}
+
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java
index 23e06d9..ebed0cf 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java
@@ -7,33 +7,26 @@
  *******************************************************************************/
 package org.spearce.egit.ui.internal.decorators;
 
-import java.io.BufferedReader;
-import java.io.CharArrayWriter;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IStorage;
-import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jface.text.Document;
 import org.eclipse.team.core.RepositoryProvider;
-import org.eclipse.team.core.history.IFileHistory;
-import org.eclipse.team.core.history.IFileHistoryProvider;
-import org.eclipse.team.core.history.IFileRevision;
 import org.spearce.egit.core.GitProvider;
 import org.spearce.egit.core.project.RepositoryMapping;
 import org.spearce.egit.ui.Activator;
 import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.ObjectLoader;
 import org.spearce.jgit.lib.RefsChangedEvent;
 import org.spearce.jgit.lib.Repository;
 import org.spearce.jgit.lib.RepositoryListener;
+import org.spearce.jgit.lib.TreeEntry;
 
 class GitDocument extends Document implements RepositoryListener {
 	private final IResource resource;
 
-	static GitDocument create(IResource resource) throws IOException, CoreException {
+	static GitDocument create(final IResource resource) throws IOException {
 		GitDocument ret = null;
 		if (RepositoryProvider.getProvider(resource.getProject()) instanceof GitProvider) {
 			ret = new GitDocument(resource);
@@ -44,36 +37,24 @@ class GitDocument extends Document implements RepositoryListener {
 
 	private GitDocument(IResource resource) {
 		this.resource = resource;
+		GitQuickDiffProvider.doc2repo.put(this, getRepository());
 	}
 
-	void populate() throws IOException, CoreException {
+	void populate() throws IOException {
 		set("");
-		IProject project = resource.getProject();
-		RepositoryProvider provider = RepositoryProvider.getProvider(project);
-		getRepository().addRepositoryChangedListener(this);
-		IFileHistoryProvider fileHistoryProvider = provider
-				.getFileHistoryProvider();
-		IFileHistory fileHistoryFor = fileHistoryProvider.getFileHistoryFor(
-				resource, IFileHistoryProvider.SINGLE_REVISION, null);
-		IFileRevision[] revisions = fileHistoryFor.getFileRevisions();
-		if (revisions != null && revisions.length > 0) {
-			IFileRevision revision = revisions[0];
-			Activator.trace("(GitQuickDiffProvider) compareTo: "
-					+ revision.getContentIdentifier());
-			IStorage storage = revision.getStorage(null);
-			InputStream contents = storage.getContents();
-			BufferedReader in = new BufferedReader(new InputStreamReader(
-					contents));
-			final int DEFAULT_FILE_SIZE = 15 * 1024;
-
-			CharArrayWriter caw = new CharArrayWriter(DEFAULT_FILE_SIZE);
-			char[] readBuffer = new char[2048];
-			int n = in.read(readBuffer);
-			while (n > 0) {
-				caw.write(readBuffer, 0, n);
-				n = in.read(readBuffer);
-			}
-			String s = caw.toString();
+		final IProject project = resource.getProject();
+		final String gitPath = RepositoryMapping.getMapping(project).getRepoRelativePath(resource);
+		final Repository repository = getRepository();
+		repository.addRepositoryChangedListener(this);
+		String baseline = GitQuickDiffProvider.baseline.get(repository);
+		if (baseline == null)
+			baseline = "HEAD";
+		TreeEntry blobEnry = repository.mapTree(baseline).findBlobMember(gitPath);
+		if (blobEnry != null) {
+			Activator.trace("(GitQuickDiffProvider) compareTo: " + baseline);
+			ObjectLoader loader = repository.openBlob(blobEnry.getId());
+			byte[] bytes = loader.getBytes();
+			String s = new String(bytes); // FIXME Platform default charset. should be Eclipse default
 			set(s);
 			Activator.trace("(GitQuickDiffProvider) has reference doc, size=" + s.length() + " bytes");
 		} else {
@@ -90,8 +71,6 @@ class GitDocument extends Document implements RepositoryListener {
 			populate();
 		} catch (IOException e1) {
 			Activator.logError("Failed to refresh quickdiff", e1);
-		} catch (CoreException e1) {
-			Activator.logError("Failed to refresh quickdiff", e1);
 		}
 	}
 
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
index 052552e..88f5ea0 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
@@ -9,6 +9,8 @@
 package org.spearce.egit.ui.internal.decorators;
 
 import java.io.IOException;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
@@ -21,6 +23,7 @@ import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.quickdiff.IQuickDiffReferenceProvider;
 import org.spearce.egit.ui.Activator;
 import org.spearce.egit.ui.UIText;
+import org.spearce.jgit.lib.Repository;
 
 /**
  * This class provides input for the Eclipse Quick Diff feature.
@@ -33,8 +36,19 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 
 	private IResource resource;
 
+	static Map<Repository,String> baseline = new WeakHashMap<Repository,String>();
+	static Map<GitDocument,Repository> doc2repo = new WeakHashMap<GitDocument, Repository>();
+
+	/**
+	 * Create the GitQuickDiffProvider instance
+	 */
+	public GitQuickDiffProvider() {
+		// Empty
+	}
+
 	public void dispose() {
 		Activator.trace("(GitQuickDiffProvider) dispose");
+		doc2repo.remove(document);
 		if (document != null)
 			document.dispose();
 	}
@@ -51,8 +65,6 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 		if (provider != null) {
 			try {
 				document = GitDocument.create(resource);
-			} catch (CoreException e) {
-				Activator.error(UIText.QuickDiff_failedLoading, e);
 			} catch (IOException e) {
 				Activator.error(UIText.QuickDiff_failedLoading, e);
 			}
@@ -74,4 +86,21 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 	public void setId(String id) {
 		this.id = id;
 	}
+
+	/**
+	 * Set a new baseline for quickdiff
+	 *
+	 * @param repository
+	 * @param baseline any commit reference, ref, symref or sha-1
+	 * @throws IOException
+	 */
+	public static void setBaselineReference(final Repository repository, final String baseline) throws IOException {
+		GitQuickDiffProvider.baseline.put(repository, baseline);
+		for (Map.Entry<GitDocument, Repository> i : doc2repo.entrySet()) {
+			if (i.getValue() == repository) {
+				i.getKey().populate();
+			}
+		}
+	}
+
 }
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 1/2] Make quick diff aware of changes in the repository.
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729672-26906-1-git-send-email-robin.rosenberg@dewire.com>

Currently only refs changes are relevant.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../egit/ui/internal/decorators/GitDocument.java   |  107 ++++++++++++++++++++
 .../internal/decorators/GitQuickDiffProvider.java  |   57 ++---------
 2 files changed, 117 insertions(+), 47 deletions(-)
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java
new file mode 100644
index 0000000..23e06d9
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitDocument.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.decorators;
+
+import java.io.BufferedReader;
+import java.io.CharArrayWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.history.IFileHistory;
+import org.eclipse.team.core.history.IFileHistoryProvider;
+import org.eclipse.team.core.history.IFileRevision;
+import org.spearce.egit.core.GitProvider;
+import org.spearce.egit.core.project.RepositoryMapping;
+import org.spearce.egit.ui.Activator;
+import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.RefsChangedEvent;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.RepositoryListener;
+
+class GitDocument extends Document implements RepositoryListener {
+	private final IResource resource;
+
+	static GitDocument create(IResource resource) throws IOException, CoreException {
+		GitDocument ret = null;
+		if (RepositoryProvider.getProvider(resource.getProject()) instanceof GitProvider) {
+			ret = new GitDocument(resource);
+			ret.populate();
+		}
+		return ret;
+	}
+
+	private GitDocument(IResource resource) {
+		this.resource = resource;
+	}
+
+	void populate() throws IOException, CoreException {
+		set("");
+		IProject project = resource.getProject();
+		RepositoryProvider provider = RepositoryProvider.getProvider(project);
+		getRepository().addRepositoryChangedListener(this);
+		IFileHistoryProvider fileHistoryProvider = provider
+				.getFileHistoryProvider();
+		IFileHistory fileHistoryFor = fileHistoryProvider.getFileHistoryFor(
+				resource, IFileHistoryProvider.SINGLE_REVISION, null);
+		IFileRevision[] revisions = fileHistoryFor.getFileRevisions();
+		if (revisions != null && revisions.length > 0) {
+			IFileRevision revision = revisions[0];
+			Activator.trace("(GitQuickDiffProvider) compareTo: "
+					+ revision.getContentIdentifier());
+			IStorage storage = revision.getStorage(null);
+			InputStream contents = storage.getContents();
+			BufferedReader in = new BufferedReader(new InputStreamReader(
+					contents));
+			final int DEFAULT_FILE_SIZE = 15 * 1024;
+
+			CharArrayWriter caw = new CharArrayWriter(DEFAULT_FILE_SIZE);
+			char[] readBuffer = new char[2048];
+			int n = in.read(readBuffer);
+			while (n > 0) {
+				caw.write(readBuffer, 0, n);
+				n = in.read(readBuffer);
+			}
+			String s = caw.toString();
+			set(s);
+			Activator.trace("(GitQuickDiffProvider) has reference doc, size=" + s.length() + " bytes");
+		} else {
+			Activator.trace("(GitQuickDiffProvider) no revision.");
+		}
+	}
+
+	void dispose() {
+		getRepository().removeRepositoryChangedListener(this);
+	}
+
+	public void refsChanged(final RefsChangedEvent e) {
+		try {
+			populate();
+		} catch (IOException e1) {
+			Activator.logError("Failed to refresh quickdiff", e1);
+		} catch (CoreException e1) {
+			Activator.logError("Failed to refresh quickdiff", e1);
+		}
+	}
+
+	public void indexChanged(final IndexChangedEvent e) {
+		// Index not relevant at this moment
+	}
+
+	private Repository getRepository() {
+		IProject project = resource.getProject();
+		RepositoryMapping mapping = RepositoryMapping.getMapping(project);
+		return mapping.getRepository();
+	}
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
index 5525914..052552e 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitQuickDiffProvider.java
@@ -8,22 +8,13 @@
  *******************************************************************************/
 package org.spearce.egit.ui.internal.decorators;
 
-import java.io.BufferedReader;
-import java.io.CharArrayWriter;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.team.core.RepositoryProvider;
-import org.eclipse.team.core.history.IFileHistory;
-import org.eclipse.team.core.history.IFileHistoryProvider;
-import org.eclipse.team.core.history.IFileRevision;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.ide.ResourceUtil;
 import org.eclipse.ui.texteditor.ITextEditor;
@@ -38,12 +29,14 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 
 	private String id;
 
-	private Document document;
+	private GitDocument document;
 
-	private IFile file;
+	private IResource resource;
 
 	public void dispose() {
-		// No resources to free
+		Activator.trace("(GitQuickDiffProvider) dispose");
+		if (document != null)
+			document.dispose();
 	}
 
 	public String getId() {
@@ -52,42 +45,12 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 
 	public IDocument getReference(IProgressMonitor monitor)
 			throws CoreException {
-		document = new Document();
-		Activator.trace("(GitQuickDiffProvider) file: " + file);
-
-		RepositoryProvider provider = RepositoryProvider.getProvider(file
+		Activator.trace("(GitQuickDiffProvider) file: " + resource);
+		RepositoryProvider provider = RepositoryProvider.getProvider(resource
 				.getProject());
 		if (provider != null) {
 			try {
-				IFileHistoryProvider fileHistoryProvider = provider
-						.getFileHistoryProvider();
-				IFileHistory fileHistoryFor = fileHistoryProvider
-						.getFileHistoryFor(file,
-								IFileHistoryProvider.SINGLE_REVISION, null);
-				IFileRevision[] revisions = fileHistoryFor.getFileRevisions();
-				if (revisions != null && revisions.length > 0) {
-					IFileRevision revision = revisions[0];
-					Activator.trace("(GitQuickDiffProvider) compareTo: "
-							+ revision.getContentIdentifier());
-					IStorage storage = revision.getStorage(null);
-					InputStream contents = storage.getContents();
-					BufferedReader in = new BufferedReader(
-							new InputStreamReader(contents));
-					final int DEFAULT_FILE_SIZE = 15 * 1024;
-
-					CharArrayWriter caw = new CharArrayWriter(DEFAULT_FILE_SIZE);
-					char[] readBuffer = new char[2048];
-					int n = in.read(readBuffer);
-					while (n > 0) {
-						caw.write(readBuffer, 0, n);
-						n = in.read(readBuffer);
-					}
-					String s = caw.toString();
-					document.set(s);
-				} else {
-					Activator.trace("(GitQuickDiffProvider) no revision.");
-					document.set("");
-				}
+				document = GitDocument.create(resource);
 			} catch (CoreException e) {
 				Activator.error(UIText.QuickDiff_failedLoading, e);
 			} catch (IOException e) {
@@ -105,7 +68,7 @@ public class GitQuickDiffProvider implements IQuickDiffReferenceProvider {
 
 	public void setActiveEditor(ITextEditor editor) {
 		IEditorInput editorInput = editor.getEditorInput();
-		file = ResourceUtil.getFile(editorInput);
+		resource = ResourceUtil.getResource(editorInput);
 	}
 
 	public void setId(String id) {
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 2/3] Avoid errors by allowing phantoms during traversal in the resource decorator
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729668-26865-2-git-send-email-robin.rosenberg@dewire.com>

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../internal/decorators/GitResourceDecorator.java  |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
index c625ce6..8d4a7c7 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
@@ -137,7 +137,9 @@ public class GitResourceDecorator extends LabelProvider implements
 								getActiveDecorator().clearDecorationState(resource);
 								return true;
 							}
-						});
+						},
+						IResource.DEPTH_INFINITE,
+						true);
 					} finally {
 						getJobManager().endRule(markerRule);
 					}
@@ -164,7 +166,9 @@ public class GitResourceDecorator extends LabelProvider implements
 						}
 						return true;
 					}
-				});
+				},
+				true
+				);
 			} catch (Exception e) {
 				Activator.logError("Problem during decorations. Stopped", e);
 			}
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 1/3] Use a job for the resource decorator
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729668-26865-1-git-send-email-robin.rosenberg@dewire.com>

Scanning directories for changes is slow so we want to use
a background job. We also connect to the repository event mechanism

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../internal/decorators/GitResourceDecorator.java  |  162 +++++++++++---------
 1 files changed, 92 insertions(+), 70 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
index dcb87b7..c625ce6 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
@@ -11,6 +11,8 @@ package org.spearce.egit.ui.internal.decorators;
 
 import java.io.IOException;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.eclipse.core.resources.IContainer;
@@ -25,14 +27,19 @@ import org.eclipse.core.resources.IResourceVisitor;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jface.viewers.IDecoration;
 import org.eclipse.jface.viewers.ILightweightLabelDecorator;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.team.core.Team;
-import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.IDecoratorManager;
 import org.spearce.egit.core.project.GitProjectData;
 import org.spearce.egit.core.project.RepositoryChangeListener;
 import org.spearce.egit.core.project.RepositoryMapping;
@@ -65,17 +72,24 @@ import org.spearce.jgit.lib.GitIndex.Entry;
 public class GitResourceDecorator extends LabelProvider implements
 		ILightweightLabelDecorator {
 
-	private static final RCL myrcl = new RCL();
+	static final String decoratorId = "org.spearce.egit.ui.internal.decorators.GitResourceDecorator";
+	static class ResCL extends Job implements IResourceChangeListener, RepositoryChangeListener, RepositoryListener {
 
-	static class RCL implements RepositoryChangeListener, RepositoryListener, Runnable {
-		private boolean requested;
+		ResCL() {
+			super("Git resource decorator trigger");
+		}
 
-		public synchronized void run() {
-			requested = false;
-			PlatformUI.getWorkbench().getDecoratorManager().update(
-					GitResourceDecorator.class.getName());
+		GitResourceDecorator getActiveDecorator() {
+			IDecoratorManager decoratorManager = Activator.getDefault()
+					.getWorkbench().getDecoratorManager();
+			if (decoratorManager.getEnabled(decoratorId))
+				return (GitResourceDecorator) decoratorManager
+						.getLightweightLabelDecorator(decoratorId);
+			return null;
 		}
 
+		private Set<IResource> resources = new LinkedHashSet<IResource>();
+
 		public void refsChanged(RefsChangedEvent e) {
 			repositoryChanged(e);
 		}
@@ -97,76 +111,87 @@ public class GitResourceDecorator extends LabelProvider implements
 		}
 
 		public void repositoryChanged(final RepositoryMapping which) {
-			try {
-				which.getContainer().accept(new IResourceVisitor() {
-					public boolean visit(IResource resource) throws CoreException {
-						if (resource instanceof IContainer)
-							clearDecorationState(resource);
-						return true;
-					}
-				});
-			} catch (CoreException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
+			synchronized (resources) {
+				resources.add(which.getContainer());
 			}
-			start();
+			schedule();
 		}
 
-		synchronized void start() {
-			if (requested)
-				return;
-			final Display d = PlatformUI.getWorkbench().getDisplay();
-			if (d.getThread() == Thread.currentThread())
-				run();
-			else {
-				requested = true;
-				d.asyncExec(this);
+		@Override
+		protected IStatus run(IProgressMonitor arg0) {
+			try {
+				if (resources.size() > 0) {
+					IResource m;
+					synchronized(resources) {
+						Iterator<IResource> i = resources.iterator();
+						m = i.next();
+						i.remove();
+						if (resources.size() > 0)
+							schedule();
+					}
+					ISchedulingRule markerRule = m.getWorkspace().getRuleFactory().markerRule(m);
+					getJobManager().beginRule(markerRule, arg0);
+					try {
+						m.accept(new IResourceVisitor() {
+							public boolean visit(IResource resource) throws CoreException {
+								getActiveDecorator().clearDecorationState(resource);
+								return true;
+							}
+						});
+					} finally {
+						getJobManager().endRule(markerRule);
+					}
+				}
+				return Status.OK_STATUS;
+			} catch (Exception e) {
+				return new Status(IStatus.ERROR, Activator.getPluginId(), "Failed to trigger resource decoration", e);
 			}
 		}
-	}
 
-	static class ResCL implements IResourceChangeListener {
 		public void resourceChanged(IResourceChangeEvent event) {
 			if (event.getType() != IResourceChangeEvent.POST_CHANGE) {
 				return;
 			}
 			try {
 				event.getDelta().accept(new IResourceDeltaVisitor() {
-
 					public boolean visit(IResourceDelta delta)
 							throws CoreException {
 						for (IResource r = delta.getResource(); r.getType() != IResource.ROOT; r = r
 								.getParent()) {
-							try {
-								clearDecorationState(r);
-							} catch (CoreException e) {
-								// TODO Auto-generated catch block
-								e.printStackTrace();
+							synchronized (resources) {
+								resources.add(r);
 							}
 						}
 						return true;
 					}
-
 				});
-			} catch (CoreException e2) {
-				// TODO Auto-generated catch block
-				e2.printStackTrace();
-				return;
+			} catch (Exception e) {
+				Activator.logError("Problem during decorations. Stopped", e);
 			}
-			myrcl.start();
+			schedule();
 		}
-	}
 
-	static void clearDecorationState(IResource r) throws CoreException {
+		void force() {
+			for (IProject p : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+				synchronized (resources) {
+					resources.add(p);
+				}
+			}
+			schedule();
+		}
+	} // End ResCL
+
+	void clearDecorationState(IResource r) throws CoreException {
 		if (r.isAccessible())
 			r.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, null);
+		fireLabelProviderChanged(new LabelProviderChangedEvent(this, r));
 	}
 
 	static ResCL myrescl = new ResCL();
 
 	static {
-		Repository.addAnyRepositoryChangedListener(myrcl);
-		GitProjectData.addRepositoryChangeListener(myrcl);
+		Repository.addAnyRepositoryChangedListener(myrescl);
+		GitProjectData.addRepositoryChangeListener(myrescl);
 		ResourcesPlugin.getWorkspace().addResourceChangeListener(myrescl,
 				IResourceChangeEvent.POST_CHANGE);
 	}
@@ -179,7 +204,7 @@ public class GitResourceDecorator extends LabelProvider implements
 	 * </p>
 	 */
 	public static void refresh() {
-		myrcl.start();
+		myrescl.force();
 	}
 
 	private static IResource toIResource(final Object e) {
@@ -368,36 +393,33 @@ public class GitResourceDecorator extends LabelProvider implements
 
 		try {
 			Integer dirty = (Integer) rsrc.getSessionProperty(GITFOLDERDIRTYSTATEPROPERTY);
+			Runnable runnable = new Runnable() {
+				public void run() {
+					// Async could be called after a
+					// project is closed or a
+					// resource is deleted
+					if (!rsrc.isAccessible())
+						return;
+					fireLabelProviderChanged(new LabelProviderChangedEvent(
+							GitResourceDecorator.this, rsrc));
+				}
+			};
 			if (dirty == null) {
 				rsrc.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, new Integer(flag));
 				orState(rsrc.getParent(), flag);
-				Display.getDefault().asyncExec(new Runnable() {
-					public void run() {
-						// Async could be called after a
-						// project is closed or a
-						// resource is deleted
-						if (!rsrc.isAccessible())
-							return;
-						fireLabelProviderChanged(new LabelProviderChangedEvent(
-								GitResourceDecorator.this, rsrc));
-					}
-				});
+//				if (Thread.currentThread() == Display.getDefault().getThread())
+//					runnable.run();
+//				else
+					Display.getDefault().asyncExec(runnable);
 			} else {
 				if ((dirty.intValue() | flag) != dirty.intValue()) {
 					dirty = new Integer(dirty.intValue() | flag);
 					rsrc.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, dirty);
 					orState(rsrc.getParent(), dirty.intValue());
-					Display.getDefault().asyncExec(new Runnable() {
-						public void run() {
-							// Async could be called after a
-							// project is closed or a
-							// resource is deleted
-							if (!rsrc.isAccessible())
-								return;
-							fireLabelProviderChanged(new LabelProviderChangedEvent(
-									GitResourceDecorator.this, rsrc));
-						}
-					});
+//					if (Thread.currentThread() == Display.getDefault().getThread())
+//						runnable.run();
+//					else
+						Display.getDefault().asyncExec(runnable);
 				}
 			}
 		} catch (CoreException e) {
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 3/3] Log decoration problems more silently
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729668-26865-3-git-send-email-robin.rosenberg@dewire.com>

Seems our logging caused too much alerts in the UI.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../internal/decorators/GitResourceDecorator.java  |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
index 8d4a7c7..6d2f88e 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
@@ -146,7 +146,9 @@ public class GitResourceDecorator extends LabelProvider implements
 				}
 				return Status.OK_STATUS;
 			} catch (Exception e) {
-				return new Status(IStatus.ERROR, Activator.getPluginId(), "Failed to trigger resource decoration", e);
+				// We must be silent here or the UI will panic with lots of error messages
+				Activator.logError("Failed to trigger resource re-decoration", e);
+				return Status.OK_STATUS;
 			}
 		}
 
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 0/3] Resource decorator improvements
From: Robin Rosenberg @ 2008-07-10 22:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg

Connect the decorator and fix some problems. The first patch depends
on the repository event mechanism.

-- robin

Robin Rosenberg (3):
  Use a job for the resource decorator
  Avoid errors by allowing phantoms during traversal in the resource
    decorator
  Log decoration problems more silently

 .../internal/decorators/GitResourceDecorator.java  |  168 ++++++++++++--------
 1 files changed, 98 insertions(+), 70 deletions(-)

^ permalink raw reply

* [EGIT PATCH 9/9] Attach the resource decorator to the repository change event mechanism
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-9-git-send-email-robin.rosenberg@dewire.com>

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../internal/decorators/GitResourceDecorator.java  |   29 +++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
index 0308f6a..dcb87b7 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java
@@ -10,6 +10,8 @@
 package org.spearce.egit.ui.internal.decorators;
 
 import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
@@ -38,7 +40,11 @@ import org.spearce.egit.ui.Activator;
 import org.spearce.egit.ui.UIIcons;
 import org.spearce.egit.ui.UIText;
 import org.spearce.jgit.lib.GitIndex;
+import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.RefsChangedEvent;
 import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.RepositoryChangedEvent;
+import org.spearce.jgit.lib.RepositoryListener;
 import org.spearce.jgit.lib.RepositoryState;
 import org.spearce.jgit.lib.Tree;
 import org.spearce.jgit.lib.TreeEntry;
@@ -61,7 +67,7 @@ public class GitResourceDecorator extends LabelProvider implements
 
 	private static final RCL myrcl = new RCL();
 
-	static class RCL implements RepositoryChangeListener, Runnable {
+	static class RCL implements RepositoryChangeListener, RepositoryListener, Runnable {
 		private boolean requested;
 
 		public synchronized void run() {
@@ -70,6 +76,26 @@ public class GitResourceDecorator extends LabelProvider implements
 					GitResourceDecorator.class.getName());
 		}
 
+		public void refsChanged(RefsChangedEvent e) {
+			repositoryChanged(e);
+		}
+
+		public void indexChanged(IndexChangedEvent e) {
+			repositoryChanged(e);
+		}
+
+		private void repositoryChanged(RepositoryChangedEvent e) {
+			Set<RepositoryMapping> ms = new HashSet<RepositoryMapping>();
+			for (IProject p : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+				RepositoryMapping mapping = RepositoryMapping.getMapping(p);
+				if (mapping != null && mapping.getRepository() == e.getRepository())
+					ms.add(mapping);
+			}
+			for (RepositoryMapping m : ms) {
+				repositoryChanged(m);
+			}
+		}
+
 		public void repositoryChanged(final RepositoryMapping which) {
 			try {
 				which.getContainer().accept(new IResourceVisitor() {
@@ -139,6 +165,7 @@ public class GitResourceDecorator extends LabelProvider implements
 	static ResCL myrescl = new ResCL();
 
 	static {
+		Repository.addAnyRepositoryChangedListener(myrcl);
 		GitProjectData.addRepositoryChangeListener(myrcl);
 		ResourcesPlugin.getWorkspace().addResourceChangeListener(myrescl,
 				IResourceChangeEvent.POST_CHANGE);
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 7/9] Add a job to refresh projects when the index changes.
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-7-git-send-email-robin.rosenberg@dewire.com>

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/egit/ui/Activator.java         |   83 +++++++++++++++++++-
 1 files changed, 79 insertions(+), 4 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
index 3e02c44..39d3bc9 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
@@ -11,16 +11,19 @@ package org.spearce.egit.ui;
 import java.net.Authenticator;
 import java.net.ProxySelector;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.eclipse.core.net.proxy.IProxyService;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
 import org.eclipse.core.runtime.jobs.ISchedulingRule;
 import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jsch.core.IJSchService;
@@ -30,7 +33,10 @@ import org.eclipse.ui.themes.ITheme;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.spearce.egit.core.project.RepositoryMapping;
+import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.RefsChangedEvent;
 import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.RepositoryListener;
 import org.spearce.jgit.transport.SshSessionFactory;
 
 /**
@@ -137,6 +143,7 @@ public class Activator extends AbstractUIPlugin {
 
 	private boolean traceVerbose;
 	private RCS rcs;
+	private RIRefresh refreshJob;
 
 	/**
 	 * Constructor for the egit ui plugin singleton
@@ -151,6 +158,70 @@ public class Activator extends AbstractUIPlugin {
 		setupSSH(context);
 		setupProxy(context);
 		setupRepoChangeScanner();
+		setupRepoIndexRefresh();
+	}
+
+	private void setupRepoIndexRefresh() {
+		refreshJob = new RIRefresh();
+		Repository.addAnyRepositoryChangedListener(refreshJob);
+	}
+
+	static class RIRefresh extends Job implements RepositoryListener {
+
+		RIRefresh() {
+			super("Git index refresh Job");
+		}
+
+		private Set<IProject> projectsToScan = new LinkedHashSet<IProject>();
+
+		@Override
+		protected IStatus run(IProgressMonitor monitor) {
+			IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+			monitor.beginTask("Refreshing git managed projects", projects.length);
+
+			while (projectsToScan.size() > 0) {
+				IProject p;
+				synchronized (projectsToScan) {
+					if (projectsToScan.size() == 0) {
+					}
+					p = projectsToScan.iterator().next();
+					projectsToScan.remove(p);
+				}
+				ISchedulingRule rule = p.getWorkspace().getRuleFactory().refreshRule(p);
+				try {
+					getJobManager().beginRule(rule, monitor);
+					p.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 1));
+				} catch (CoreException e) {
+					logError("Failed to refresh projects from index changes", e);
+					return new Status(IStatus.ERROR, getPluginId(), e.getMessage());
+				} finally {
+					getJobManager().endRule(rule);
+				}
+			}
+			monitor.done();
+			return Status.OK_STATUS;
+		}
+
+		public void indexChanged(IndexChangedEvent e) {
+			IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+			Set<IProject> toRefresh= new HashSet<IProject>();
+			for (IProject p : projects) {
+				RepositoryMapping mapping = RepositoryMapping.getMapping(p);
+				if (mapping != null && mapping.getRepository() == e.getRepository()) {
+					toRefresh.add(p);
+				}
+			}
+			synchronized (projectsToScan) {
+				projectsToScan.addAll(toRefresh);
+			}
+			if (projectsToScan.size() > 0)
+				schedule();
+		}
+
+		public void refsChanged(RefsChangedEvent e) {
+			// Do not react here
+		}
+
 	}
 
 	static class RCS extends Job {
@@ -236,10 +307,14 @@ public class Activator extends AbstractUIPlugin {
 
 	public void stop(final BundleContext context) throws Exception {
 		trace("Trying to cancel " + rcs.getName() + " job");
-		if (!rcs.cancel()) {
-			rcs.join();
-		}
-		trace("rcs.getName() " + rcs.getName() + " cancelled ok");
+		rcs.cancel();
+		trace("Trying to cancel " + refreshJob.getName() + " job");
+		refreshJob.cancel();
+
+		rcs.join();
+		refreshJob.join();
+
+		trace("Jobs terminated");
 		super.stop(context);
 		plugin = null;
 	}
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 8/9] Make git dectected changes depend on the automatic refresh setting
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-8-git-send-email-robin.rosenberg@dewire.com>

This is the same setting that scans the workspace regularly for
changes in resources. We scan more often can can trigger sooner because
we can scan fewer files.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/egit/ui/Activator.java         |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
index 39d3bc9..d8928cb 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
@@ -203,6 +203,11 @@ public class Activator extends AbstractUIPlugin {
 		}
 
 		public void indexChanged(IndexChangedEvent e) {
+			// Check the workspace setting "refresh automatically" setting first
+			if (!ResourcesPlugin.getPlugin().getPluginPreferences().getBoolean(
+					ResourcesPlugin.PREF_AUTO_REFRESH))
+				return;
+
 			IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
 			Set<IProject> toRefresh= new HashSet<IProject>();
 			for (IProject p : projects) {
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 1/9] Create a listener structure for changes to refs and index
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-1-git-send-email-robin.rosenberg@dewire.com>

This version does not tell you which refs have changed, nor
what changes have happened. There is not scanning for externally
initiated changes either, though such changes can be found when
a JGit client wants to read index or refs information.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../egit/ui/internal/history/GitHistoryPage.java   |   31 +++++++++-
 .../src/org/spearce/jgit/lib/GitIndex.java         |    3 +
 .../org/spearce/jgit/lib/IndexChangedEvent.java    |   55 +++++++++++++++++
 .../src/org/spearce/jgit/lib/RefDatabase.java      |   17 +++++
 .../src/org/spearce/jgit/lib/RefsChangedEvent.java |   55 +++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |   41 +++++++++++++
 .../org/spearce/jgit/lib/RepositoryAdapter.java    |   54 ++++++++++++++++
 .../spearce/jgit/lib/RepositoryChangedEvent.java   |   64 ++++++++++++++++++++
 .../org/spearce/jgit/lib/RepositoryListener.java   |   63 +++++++++++++++++++
 9 files changed, 382 insertions(+), 1 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/IndexChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RefsChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryAdapter.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryListener.java

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
index 6b55185..7e2f726 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
@@ -61,7 +61,10 @@ import org.spearce.egit.ui.UIIcons;
 import org.spearce.egit.ui.UIPreferences;
 import org.spearce.egit.ui.UIText;
 import org.spearce.jgit.lib.AnyObjectId;
+import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.RefsChangedEvent;
 import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.RepositoryListener;
 import org.spearce.jgit.revplot.PlotCommit;
 import org.spearce.jgit.revwalk.RevCommit;
 import org.spearce.jgit.revwalk.RevFlag;
@@ -73,7 +76,7 @@ import org.spearce.jgit.treewalk.filter.PathFilterGroup;
 import org.spearce.jgit.treewalk.filter.TreeFilter;
 
 /** Graphical commit history viewer. */
-public class GitHistoryPage extends HistoryPage {
+public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 	private static final String PREF_COMMENT_WRAP = UIPreferences.RESOURCEHISTORY_SHOW_COMMENT_WRAP;
 
 	private static final String PREF_COMMENT_FILL = UIPreferences.RESOURCEHISTORY_SHOW_COMMENT_FILL;
@@ -230,6 +233,32 @@ public class GitHistoryPage extends HistoryPage {
 		layout();
 	}
 
+	private Runnable refschangedRunnable;
+
+	public void refsChanged(final RefsChangedEvent e) {
+		if (getControl().isDisposed())
+			return;
+
+		synchronized (this) {
+			if (refschangedRunnable == null) {
+				refschangedRunnable = new Runnable() {
+					public void run() {
+						if (!getControl().isDisposed()) {
+							Activator.trace("Executing async repository changed event");
+							refschangedRunnable = null;
+							inputSet();
+						}
+					}
+				};
+				getControl().getDisplay().asyncExec(refschangedRunnable);
+			}
+		}
+	}
+
+	public void indexChanged(final IndexChangedEvent e) {
+		// We do not use index information here now
+	}
+
 	private void finishContextMenu() {
 		popupMgr.add(new Separator());
 		popupMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
index 5be404e..c7a4402 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/GitIndex.java
@@ -146,6 +146,7 @@ public class GitIndex {
 	public void rereadIfNecessary() throws IOException {
 		if (cacheFile.exists() && cacheFile.lastModified() != lastCacheTime) {
 			read();
+			db.fireIndexChanged();
 		}
 	}
 
@@ -269,6 +270,8 @@ public class GitIndex {
 						"Could not rename temporary index file to index");
 			changed = false;
 			statDirty = false;
+			lastCacheTime = cacheFile.lastModified();
+			db.fireIndexChanged();
 		} finally {
 			if (!lock.delete())
 				throw new IOException(
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/IndexChangedEvent.java b/org.spearce.jgit/src/org/spearce/jgit/lib/IndexChangedEvent.java
new file mode 100644
index 0000000..30a40d1
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/IndexChangedEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+/**
+ * This class passes information about a changed Git index to a
+ * {@link RepositoryListener}
+ *
+ * Currently only a reference to the repository is passed.
+ */
+public class IndexChangedEvent extends RepositoryChangedEvent {
+	IndexChangedEvent(final Repository repository) {
+		super(repository);
+	}
+
+	@Override
+	public String toString() {
+		return "IndexChangedEvent[" + getRepository() + "]";
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 9e3e020..4be33b8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -81,6 +81,10 @@ class RefDatabase {
 
 	private long packedRefsLength;
 
+	long lastRefModification;
+
+	long lastNotifiedRefModification;
+
 	RefDatabase(final Repository r) {
 		db = r;
 		gitDir = db.getDirectory();
@@ -132,6 +136,8 @@ class RefDatabase {
 
 	void stored(final String name, final ObjectId id, final long time) {
 		looseRefs.put(name, new CachedRef(Ref.Storage.LOOSE, name, id, time));
+		setModified();
+		db.fireRefsMaybeChanged();
 	}
 
 	/**
@@ -155,6 +161,12 @@ class RefDatabase {
 		}
 		if (!lck.commit())
 			throw new ObjectWritingException("Unable to write " + name);
+		setModified();
+		db.fireRefsMaybeChanged();
+	}
+
+	void setModified() {
+		lastRefModification = System.currentTimeMillis();
 	}
 
 	Ref readRef(final String partialName) throws IOException {
@@ -192,6 +204,7 @@ class RefDatabase {
 		readPackedRefs(avail);
 		readLooseRefs(avail, REFS_SLASH, refsDir);
 		readOneLooseRef(avail, Constants.HEAD, new File(gitDir, Constants.HEAD));
+		db.fireRefsMaybeChanged();
 		return avail;
 	}
 
@@ -321,6 +334,8 @@ class RefDatabase {
 			return r != null ? r : new Ref(Ref.Storage.LOOSE, target, null);
 		}
 
+		setModified();
+
 		final ObjectId id;
 		try {
 			id = ObjectId.fromString(line);
@@ -378,6 +393,7 @@ class RefDatabase {
 			packedRefsLastModified = currTime;
 			packedRefsLength = currLen;
 			packedRefs = newPackedRefs;
+			setModified();
 		} catch (FileNotFoundException noPackedRefs) {
 			// Ignore it and leave the new map empty.
 			//
@@ -414,4 +430,5 @@ class RefDatabase {
 			lastModified = mtime;
 		}
 	}
+
 }
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefsChangedEvent.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefsChangedEvent.java
new file mode 100644
index 0000000..c8936c7
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefsChangedEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+/**
+ * This class passes information about a changed Git index to a
+ * {@link RepositoryListener}
+ *
+ * Currently only a reference to the repository is passed.
+ */
+public class RefsChangedEvent extends RepositoryChangedEvent {
+	RefsChangedEvent(final Repository repository) {
+		super(repository);
+	}
+
+	@Override
+	public String toString() {
+		return "RefsChangedEvent[" + getRepository() + "]";
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 04d9b13..6f78652 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -49,7 +49,9 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.Vector;
 
 import org.spearce.jgit.errors.IncorrectObjectTypeException;
 import org.spearce.jgit.errors.RevisionSyntaxException;
@@ -92,6 +94,8 @@ public class Repository {
 
 	private GitIndex index;
 
+	private List<RepositoryListener> listeners = new Vector<RepositoryListener>(); // thread safe
+
 	/**
 	 * Construct a representation of a Git repository.
 	 * 
@@ -1028,4 +1032,41 @@ public class Repository {
 	public File getWorkDir() {
 		return getDirectory().getParentFile();
 	}
+
+	/**
+	 * Register a {@link RepositoryListener} which will be notified
+	 * when ref changes are detected.
+	 *
+	 * @param l
+	 */
+	public void addRepositoryChangedListener(final RepositoryListener l) {
+		listeners.add(l);
+	}
+
+	/**
+	 * Remove a registered {@link RepositoryListener}
+	 * @param l
+	 */
+	public void removeRepositoryChangedListener(final RepositoryListener l) {
+		listeners.remove(l);
+	}
+
+	void fireRefsMaybeChanged() {
+		if (refs.lastRefModification != refs.lastNotifiedRefModification) {
+			refs.lastNotifiedRefModification = refs.lastRefModification;
+			final RefsChangedEvent event = new RefsChangedEvent(this);
+			for (final RepositoryListener l :
+				listeners.toArray(new RepositoryListener[listeners.size()])) {
+				l.refsChanged(event);
+			}
+		}
+	}
+
+	void fireIndexChanged() {
+		final IndexChangedEvent event = new IndexChangedEvent(this);
+		for (final RepositoryListener l :
+			listeners.toArray(new RepositoryListener[listeners.size()])) {
+			l.indexChanged(event);
+		}
+	}
 }
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryAdapter.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryAdapter.java
new file mode 100644
index 0000000..d1ff07d
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryAdapter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+/**
+ * A default {@link RepositoryListener} that does nothing except invoke an
+ * optional general method for any repository change.
+ */
+public class RepositoryAdapter implements RepositoryListener {
+
+	public void indexChanged(final IndexChangedEvent e) {
+		// Empty
+	}
+
+	public void refsChanged(final RefsChangedEvent e) {
+		// Empty
+	}
+
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryChangedEvent.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryChangedEvent.java
new file mode 100644
index 0000000..b58df87
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryChangedEvent.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+/**
+ * This class passes information about changed refs to a
+ * {@link RepositoryListener}
+ *
+ * Currently only a reference to the repository is passed.
+ */
+public class RepositoryChangedEvent {
+	private final Repository repository;
+
+	RepositoryChangedEvent(final Repository repository) {
+		this.repository = repository;
+	}
+
+	/**
+	 * @return the repository that was changed
+	 */
+	public Repository getRepository() {
+		return repository;
+	}
+
+	@Override
+	public String toString() {
+		return "RepositoryChangedEvent[" + repository + "]";
+	}
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryListener.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryListener.java
new file mode 100644
index 0000000..ceb14ce
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryListener.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.lib;
+
+/**
+ * A RepositoryListener gets notification about changes in refs or repository.
+ * <p>
+ * It currently does <em>not</em> get notification about which items are
+ * changed.
+ */
+public interface RepositoryListener {
+	/**
+	 * Invoked when a ref changes
+	 *
+	 * @param e
+	 *            information about the changes.
+	 */
+	void refsChanged(RefsChangedEvent e);
+
+	/**
+	 * Invoked when the index changes
+	 *
+	 * @param e
+	 *            information about the changes.
+	 */
+	void indexChanged(IndexChangedEvent e);
+
+}
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 6/9] Change GitHistoryPage to listen on any repository.
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-6-git-send-email-robin.rosenberg@dewire.com>

This makes listening simpler.
---
 .../egit/ui/internal/history/GitHistoryPage.java   |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
index 418f3b6..e3ff8d4 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
@@ -234,11 +234,16 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 		attachContextMenu(commentViewer.getControl());
 		attachContextMenu(fileViewer.getControl());
 		layout();
+
+		Repository.addAnyRepositoryChangedListener(this);
 	}
 
 	private Runnable refschangedRunnable;
 
 	public void refsChanged(final RefsChangedEvent e) {
+		if (e.getRepository() != db)
+			return;
+
 		if (getControl().isDisposed())
 			return;
 
@@ -480,6 +485,7 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 	}
 
 	public void dispose() {
+		Repository.removeAnyRepositoryChangedListener(this);
 		cancelRefreshJob();
 		if (popupMgr != null) {
 			for (final IContributionItem i : popupMgr.getItems()) {
@@ -539,9 +545,6 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 			revObjectSelectionProvider.setActiveRepository(null);
 		cancelRefreshJob();
 
-		if (db != null)
-			db.removeRepositoryChangedListener(this);
-
 		if (graph == null)
 			return false;
 
@@ -570,8 +573,6 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 		if (db == null)
 			return false;
 
-		db.addRepositoryChangedListener(this);
-
 		final AnyObjectId headId;
 		try {
 			headId = db.resolve("HEAD");
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 5/9] Add a job to periodically scan for repository changes
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-5-git-send-email-robin.rosenberg@dewire.com>

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/egit/ui/Activator.java         |   75 ++++++++++++++++++++
 .../src/org/spearce/jgit/lib/Repository.java       |   10 +++
 2 files changed, 85 insertions(+), 0 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
index 8d1b8cd..3e02c44 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
@@ -10,18 +10,27 @@ package org.spearce.egit.ui;
 
 import java.net.Authenticator;
 import java.net.ProxySelector;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.eclipse.core.net.proxy.IProxyService;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.jsch.core.IJSchService;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.ui.themes.ITheme;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
+import org.spearce.egit.core.project.RepositoryMapping;
+import org.spearce.jgit.lib.Repository;
 import org.spearce.jgit.transport.SshSessionFactory;
 
 /**
@@ -127,6 +136,7 @@ public class Activator extends AbstractUIPlugin {
 	}
 
 	private boolean traceVerbose;
+	private RCS rcs;
 
 	/**
 	 * Constructor for the egit ui plugin singleton
@@ -140,6 +150,66 @@ public class Activator extends AbstractUIPlugin {
 		traceVerbose = isOptionSet("/trace/verbose");
 		setupSSH(context);
 		setupProxy(context);
+		setupRepoChangeScanner();
+	}
+
+	static class RCS extends Job {
+		RCS() {
+			super("Repository Change Scanner");
+		}
+
+		// FIXME, need to be more intelligent about this to avoid too much work
+		private static final long REPO_SCAN_INTERVAL = 10000L;
+
+		@Override
+		protected IStatus run(IProgressMonitor monitor) {
+			try {
+				// A repository can contain many projects, only scan once
+				// (a project could in theory be distributed among many
+				// repositories. We discard that as being ugly and stupid for
+				// the moment.
+				IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
+				monitor.beginTask("Scanning Git repositories for changes", projects.length);
+				Set<Repository> scanned = new HashSet<Repository>();
+				for (IProject p : projects) {
+					RepositoryMapping mapping = RepositoryMapping.getMapping(p);
+					if (mapping != null) {
+						Repository r = mapping.getRepository();
+						if (!scanned.contains(r)) {
+							if (monitor.isCanceled())
+								break;
+							trace("Scanning " + r + " for changes");
+							scanned.add(r);
+							ISchedulingRule rule = p.getWorkspace().getRuleFactory().modifyRule(p);
+							getJobManager().beginRule(rule, monitor);
+							try {
+								r.scanForRepoChanges();
+							} finally {
+								getJobManager().endRule(rule);
+							}
+						}
+					}
+					monitor.worked(1);
+				}
+				monitor.done();
+				trace("Rescheduling " + getName() + " job");
+				schedule(REPO_SCAN_INTERVAL);
+			} catch (Exception e) {
+				trace("Stopped rescheduling " + getName() + "job");
+				return new Status(
+						IStatus.ERROR,
+						getPluginId(),
+						0,
+						"An error occurred while scanning for changes. Scanning aborted",
+						e);
+			}
+			return Status.OK_STATUS;
+		}
+	}
+
+	private void setupRepoChangeScanner() {
+		rcs = new RCS();
+		rcs.schedule(RCS.REPO_SCAN_INTERVAL);
 	}
 
 	private void setupSSH(final BundleContext context) {
@@ -165,6 +235,11 @@ public class Activator extends AbstractUIPlugin {
 	}
 
 	public void stop(final BundleContext context) throws Exception {
+		trace("Trying to cancel " + rcs.getName() + " job");
+		if (!rcs.cancel()) {
+			rcs.join();
+		}
+		trace("rcs.getName() " + rcs.getName() + " cancelled ok");
 		super.stop(context);
 		plugin = null;
 	}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index dfa3045..9b65154 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -1092,4 +1092,14 @@ public class Repository {
 			l.indexChanged(event);
 		}
 	}
+
+	/**
+	 * Force a scan for changed refs.
+	 *
+	 * @throws IOException
+	 */
+	public void scanForRepoChanges() throws IOException {
+		getAllRefs(); // This will look for changes to refs
+		getIndex(); // This will detect changes in the index
+	}
 }
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 3/9] Connect the history page to the refs update subscription mechanism
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-3-git-send-email-robin.rosenberg@dewire.com>

Now the history page can get updated automatically without polling.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../egit/ui/internal/history/GitHistoryPage.java   |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
index 7e2f726..418f3b6 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/history/GitHistoryPage.java
@@ -168,6 +168,9 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 	/** Last HEAD */
 	private AnyObjectId currentHeadId;
 
+	/** We need to remember the current repository */
+	private Repository db;
+
 	/**
 	 * Highlight flag that can be applied to commits to make them stand out.
 	 * <p>
@@ -536,6 +539,9 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 			revObjectSelectionProvider.setActiveRepository(null);
 		cancelRefreshJob();
 
+		if (db != null)
+			db.removeRepositoryChangedListener(this);
+
 		if (graph == null)
 			return false;
 
@@ -543,7 +549,8 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 		if (in == null || in.length == 0)
 			return false;
 
-		Repository db = null;
+		db = null;
+
 		final ArrayList<String> paths = new ArrayList<String>(in.length);
 		for (final IResource r : in) {
 			final RepositoryMapping map = RepositoryMapping.getMapping(r);
@@ -563,6 +570,8 @@ public class GitHistoryPage extends HistoryPage implements RepositoryListener {
 		if (db == null)
 			return false;
 
+		db.addRepositoryChangedListener(this);
+
 		final AnyObjectId headId;
 		try {
 			headId = db.resolve("HEAD");
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 4/9] Add a method to listen to changes in any repository
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-4-git-send-email-robin.rosenberg@dewire.com>

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/lib/Repository.java       |   31 +++++++++++++++++--
 1 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 6f78652..dfa3045 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -95,6 +95,7 @@ public class Repository {
 	private GitIndex index;
 
 	private List<RepositoryListener> listeners = new Vector<RepositoryListener>(); // thread safe
+	static private List<RepositoryListener> allListeners = new Vector<RepositoryListener>(); // thread safe
 
 	/**
 	 * Construct a representation of a Git repository.
@@ -1051,12 +1052,32 @@ public class Repository {
 		listeners.remove(l);
 	}
 
+	/**
+	 * Register a global {@link RepositoryListener} which will be notified
+	 * when a ref changes in any repository are detected.
+	 *
+	 * @param l
+	 */
+	public static void addAnyRepositoryChangedListener(final RepositoryListener l) {
+		allListeners.add(l);
+	}
+
+	/**
+	 * Remove a globally registered {@link RepositoryListener}
+	 * @param l
+	 */
+	public static void removeAnyRepositoryChangedListener(final RepositoryListener l) {
+		allListeners.remove(l);
+	}
+
 	void fireRefsMaybeChanged() {
 		if (refs.lastRefModification != refs.lastNotifiedRefModification) {
 			refs.lastNotifiedRefModification = refs.lastRefModification;
 			final RefsChangedEvent event = new RefsChangedEvent(this);
-			for (final RepositoryListener l :
-				listeners.toArray(new RepositoryListener[listeners.size()])) {
+			List<RepositoryListener> all = new ArrayList<RepositoryListener>(
+					listeners);
+			all.addAll(allListeners);
+			for (final RepositoryListener l : all) {
 				l.refsChanged(event);
 			}
 		}
@@ -1064,8 +1085,10 @@ public class Repository {
 
 	void fireIndexChanged() {
 		final IndexChangedEvent event = new IndexChangedEvent(this);
-		for (final RepositoryListener l :
-			listeners.toArray(new RepositoryListener[listeners.size()])) {
+		List<RepositoryListener> all = new ArrayList<RepositoryListener>(
+				listeners);
+		all.addAll(allListeners);
+		for (final RepositoryListener l : all) {
 			l.indexChanged(event);
 		}
 	}
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 2/9] Cached modification times for symbolic refs too
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729651-26781-2-git-send-email-robin.rosenberg@dewire.com>

We want to detect changes to symbolic refs like HEAD. When HEAD is
redirected to another branch, that's a change even if if the branch
head itself did not change.

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 .../src/org/spearce/jgit/lib/RefDatabase.java      |   48 +++++++++++---------
 1 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
index 4be33b8..17a74e5 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/RefDatabase.java
@@ -71,7 +71,8 @@ class RefDatabase {
 
 	private final File refsDir;
 
-	private Map<String, CachedRef> looseRefs;
+	private Map<String, Ref> looseRefs;
+	private Map<String, Long> looseRefsMTime;
 
 	private final File packedRefsFile;
 
@@ -94,7 +95,8 @@ class RefDatabase {
 	}
 
 	void clearCache() {
-		looseRefs = new HashMap<String, CachedRef>();
+		looseRefs = new HashMap<String, Ref>();
+		looseRefsMTime = new HashMap<String, Long>();
 		packedRefs = new HashMap<String, Ref>();
 		packedRefsLastModified = 0;
 		packedRefsLength = 0;
@@ -135,7 +137,8 @@ class RefDatabase {
 	}
 
 	void stored(final String name, final ObjectId id, final long time) {
-		looseRefs.put(name, new CachedRef(Ref.Storage.LOOSE, name, id, time));
+		looseRefs.put(name, new Ref(Ref.Storage.LOOSE, name, id));
+		looseRefsMTime.put(name, time);
 		setModified();
 		db.fireRefsMaybeChanged();
 	}
@@ -203,7 +206,11 @@ class RefDatabase {
 		final HashMap<String, Ref> avail = new HashMap<String, Ref>();
 		readPackedRefs(avail);
 		readLooseRefs(avail, REFS_SLASH, refsDir);
-		readOneLooseRef(avail, Constants.HEAD, new File(gitDir, Constants.HEAD));
+		try {
+			avail.put(Constants.HEAD, readRefBasic(Constants.HEAD, 0));
+		} catch (IOException e) {
+			// ignore here
+		}
 		db.fireRefsMaybeChanged();
 		return avail;
 	}
@@ -231,13 +238,15 @@ class RefDatabase {
 			final String refName, final File ent) {
 		// Unchanged and cached? Don't read it again.
 		//
-		CachedRef ref = looseRefs.get(refName);
+		Ref ref = looseRefs.get(refName);
 		if (ref != null) {
-			if (ref.lastModified == ent.lastModified()) {
+			Long cachedlastModified = looseRefsMTime.get(refName);
+			if (cachedlastModified != null && cachedlastModified == ent.lastModified()) {
 				avail.put(ref.getName(), ref);
 				return;
 			}
 			looseRefs.remove(refName);
+			looseRefsMTime.remove(refName);
 		}
 
 		// Recurse into the directory.
@@ -269,9 +278,9 @@ class RefDatabase {
 					return;
 				}
 
-				ref = new CachedRef(Ref.Storage.LOOSE, refName, id, ent
-						.lastModified());
+				ref = new Ref(Ref.Storage.LOOSE, refName, id);
 				looseRefs.put(ref.getName(), ref);
+				looseRefsMTime.put(ref.getName(), ent.lastModified());
 				avail.put(ref.getName(), ref);
 			} finally {
 				in.close();
@@ -297,13 +306,15 @@ class RefDatabase {
 		// Prefer loose ref to packed ref as the loose
 		// file can be more up-to-date than a packed one.
 		//
-		CachedRef ref = looseRefs.get(name);
+		Ref ref = looseRefs.get(name);
 		final File loose = fileForRef(name);
 		final long mtime = loose.lastModified();
 		if (ref != null) {
-			if (ref.lastModified == mtime)
+			Long cachedlastModified = looseRefsMTime.get(name);
+			if (cachedlastModified != null && cachedlastModified == mtime)
 				return ref;
 			looseRefs.remove(name);
+			looseRefsMTime.remove(name);
 		}
 
 		if (mtime == 0) {
@@ -331,6 +342,10 @@ class RefDatabase {
 
 			final String target = line.substring("ref: ".length());
 			final Ref r = readRefBasic(target, depth + 1);
+			Long cachedMtime = looseRefsMTime.get(name);
+			if (cachedMtime != null && cachedMtime != mtime)
+				setModified();
+			looseRefsMTime.put(name, mtime);
 			return r != null ? r : new Ref(Ref.Storage.LOOSE, target, null);
 		}
 
@@ -343,8 +358,9 @@ class RefDatabase {
 			throw new IOException("Not a ref: " + name + ": " + line);
 		}
 
-		ref = new CachedRef(Ref.Storage.LOOSE, name, id, mtime);
+		ref = new Ref(Ref.Storage.LOOSE, name, id);
 		looseRefs.put(name, ref);
+		looseRefsMTime.put(name, mtime);
 		return ref;
 	}
 
@@ -421,14 +437,4 @@ class RefDatabase {
 				fileLocation), CHAR_ENC));
 	}
 
-	private static class CachedRef extends Ref {
-		final long lastModified;
-
-		CachedRef(final Storage st, final String refName, final ObjectId id,
-				final long mtime) {
-			super(st, refName, id);
-			lastModified = mtime;
-		}
-	}
-
 }
-- 
1.5.6.2.220.g44701

^ permalink raw reply related

* [EGIT PATCH 0/9] Repository change listeners
From: Robin Rosenberg @ 2008-07-10 22:40 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg

We want to make the UI react on changes to the repo, but the parts
of the code that makes the changes doesn't know who wants to react
on them. This adds a publish-subcribe mechanism, including detection
of externally made changes, e.g. by C Git.

-- robin

Robin Rosenberg (9):
  Create a listener structure for changes to refs and index
  Cached modification times for symbolic refs too
  Connect the history page to the refs update subscription mechanism
  Add a method to listen to changes in any repository
  Add a job to periodically scan for repository changes
  Change GitHistoryPage to listen on any repository.
  Add a job to refresh projects when the index changes.
  Make git dectected changes depend on the automatic refresh setting
  Attach the resource decorator to the repository change event
    mechanism

 .../src/org/spearce/egit/ui/Activator.java         |  155 ++++++++++++++++++++
 .../internal/decorators/GitResourceDecorator.java  |   29 ++++-
 .../egit/ui/internal/history/GitHistoryPage.java   |   43 +++++-
 .../src/org/spearce/jgit/lib/GitIndex.java         |    3 +
 .../org/spearce/jgit/lib/IndexChangedEvent.java    |   55 +++++++
 .../src/org/spearce/jgit/lib/RefDatabase.java      |   63 ++++++---
 .../src/org/spearce/jgit/lib/RefsChangedEvent.java |   55 +++++++
 .../src/org/spearce/jgit/lib/Repository.java       |   74 ++++++++++
 .../org/spearce/jgit/lib/RepositoryAdapter.java    |   54 +++++++
 .../spearce/jgit/lib/RepositoryChangedEvent.java   |   64 ++++++++
 .../org/spearce/jgit/lib/RepositoryListener.java   |   63 ++++++++
 11 files changed, 635 insertions(+), 23 deletions(-)
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/IndexChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RefsChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryAdapter.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryChangedEvent.java
 create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/RepositoryListener.java

^ permalink raw reply

* [EGIT PATCH 6/6] Add actions in history view to perform reset actions
From: Robin Rosenberg @ 2008-07-10 22:39 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git, Marek Zawirski, Robin Rosenberg
In-Reply-To: <1215729573-26536-6-git-send-email-robin.rosenberg@dewire.com>

Soft, mixed and hard reset supported

Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
---
 org.spearce.egit.ui/plugin.xml                     |   43 +++++++++++---------
 .../actions/HardResetToRevisionAction.java         |   26 ++++++++++++
 .../actions/MixedResetToRevisionAction.java        |   26 ++++++++++++
 .../actions/SoftResetToRevisionAction.java         |   26 ++++++++++++
 4 files changed, 102 insertions(+), 19 deletions(-)
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/HardResetToRevisionAction.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/MixedResetToRevisionAction.java
 create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SoftResetToRevisionAction.java

diff --git a/org.spearce.egit.ui/plugin.xml b/org.spearce.egit.ui/plugin.xml
index 924c6e5..cfd4b80 100644
--- a/org.spearce.egit.ui/plugin.xml
+++ b/org.spearce.egit.ui/plugin.xml
@@ -97,29 +97,34 @@
                menubarPath="team.main/group1"
                tooltip="%CommitAction_tooltip"/>
 	  </objectContribution>
-      <objectContribution
-            id="org.spearce.egit.ui.revobjectContributions"
-            adaptable="true"
-            objectClass="org.spearce.jgit.revwalk.RevObject">
+	  <objectContribution
+         id="org.spearce.egit.ui.resetto"
+         objectClass="org.spearce.jgit.revwalk.RevCommit">
          <action
-               class="org.spearce.egit.ui.internal.actions.BranchAction"
-               id="org.spearce.egit.ui.action1"
-               label="Kolla"
-               enablesFor="*"
-               menubarPath="additions">
+               class="org.spearce.egit.ui.internal.actions.SoftResetToRevisionAction"
+               id="org.spearce.egit.ui.softresettorevision"
+               label="Soft Reset"
+               menubarPath="additions"
+               enablesFor="1"
+               tooltip="Resets HEAD but not working directory nor index">
          </action>
-      </objectContribution>
-      <viewerContribution
-            id="org.spearce.egit.ui.viewerContribution1"
-            targetID="org.spearce.egit.ui.historyPageContributions">
          <action
-               class="org.spearce.egit.ui.internal.actions.ResetAction"
-               id="org.spearce.egit.ui.action1"
-               label="Titta"
-               enablesFor="*"
-               menubarPath="additions">
+               class="org.spearce.egit.ui.internal.actions.MixedResetToRevisionAction"
+               id="org.spearce.egit.ui.mixedresettorevision"
+               label="Mixed Reset"
+               menubarPath="additions"
+               enablesFor="1"
+               tooltip="Resets HEAD and index, but not working directory">
          </action>
-      </viewerContribution>
+         <action
+               class="org.spearce.egit.ui.internal.actions.HardResetToRevisionAction"
+               id="org.spearce.egit.ui.hardresettorevision"
+               label="Hard Reset"
+               menubarPath="additions"
+               enablesFor="1"
+               tooltip="Resets HEAD and index, and working directory (changed in tracked files will be lost)">
+         </action>
+	  </objectContribution>
    </extension>
 
    <extension
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/HardResetToRevisionAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/HardResetToRevisionAction.java
new file mode 100644
index 0000000..78fd87f
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/HardResetToRevisionAction.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.jface.action.IAction;
+import org.spearce.egit.core.op.ResetOperation;
+
+/**
+ * Hard reset to selected revision
+ */
+public class HardResetToRevisionAction extends AbstractRevObjectAction {
+
+	@Override
+	protected IWorkspaceRunnable createOperation(IAction act, List selection) {
+		return new ResetOperation(getActiveRepository(), selection.get(0)
+				.toString(), ResetOperation.ResetType.HARD);
+	}
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/MixedResetToRevisionAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/MixedResetToRevisionAction.java
new file mode 100644
index 0000000..6e4a9bf
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/MixedResetToRevisionAction.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.jface.action.IAction;
+import org.spearce.egit.core.op.ResetOperation;
+
+/**
+ * Mixed reset to selected revision
+ */
+public class MixedResetToRevisionAction extends AbstractRevObjectAction {
+
+	@Override
+	protected IWorkspaceRunnable createOperation(IAction act, List selection) {
+		return new ResetOperation(getActiveRepository(), selection.get(0)
+				.toString(), ResetOperation.ResetType.MIXED);
+	}
+}
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SoftResetToRevisionAction.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SoftResetToRevisionAction.java
new file mode 100644
index 0000000..7abbc92
--- /dev/null
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/actions/SoftResetToRevisionAction.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * See LICENSE for the full license text, also available.
+ *******************************************************************************/
+package org.spearce.egit.ui.internal.actions;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.jface.action.IAction;
+import org.spearce.egit.core.op.ResetOperation;
+
+/**
+ * Soft reset to selected revision
+ */
+public class SoftResetToRevisionAction extends AbstractRevObjectAction {
+
+	@Override
+	protected IWorkspaceRunnable createOperation(IAction act, List selection) {
+		return new ResetOperation(getActiveRepository(), selection.get(0)
+				.toString(), ResetOperation.ResetType.SOFT);
+	}
+}
-- 
1.5.6.2.220.g44701

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox