1 /*******************************************************************************
2 * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved. This program and the accompanying materials
6 * are made available under the terms of the Eclipse Public License v1.0
7 * See LICENSE for the full license text, also available.
8 *******************************************************************************/
9 package org
.spearce
.egit
.ui
;
11 import java
.net
.Authenticator
;
12 import java
.net
.ProxySelector
;
13 import java
.util
.HashSet
;
14 import java
.util
.Iterator
;
15 import java
.util
.LinkedHashSet
;
18 import org
.eclipse
.core
.net
.proxy
.IProxyService
;
19 import org
.eclipse
.core
.resources
.IProject
;
20 import org
.eclipse
.core
.resources
.IResource
;
21 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
22 import org
.eclipse
.core
.runtime
.CoreException
;
23 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
24 import org
.eclipse
.core
.runtime
.IStatus
;
25 import org
.eclipse
.core
.runtime
.Platform
;
26 import org
.eclipse
.core
.runtime
.Status
;
27 import org
.eclipse
.core
.runtime
.SubProgressMonitor
;
28 import org
.eclipse
.core
.runtime
.jobs
.ISchedulingRule
;
29 import org
.eclipse
.core
.runtime
.jobs
.Job
;
30 import org
.eclipse
.jsch
.core
.IJSchService
;
31 import org
.eclipse
.swt
.graphics
.Font
;
32 import org
.eclipse
.ui
.plugin
.AbstractUIPlugin
;
33 import org
.eclipse
.ui
.themes
.ITheme
;
34 import org
.osgi
.framework
.BundleContext
;
35 import org
.osgi
.framework
.ServiceReference
;
36 import org
.spearce
.egit
.core
.project
.RepositoryMapping
;
37 import org
.spearce
.jgit
.lib
.IndexChangedEvent
;
38 import org
.spearce
.jgit
.lib
.RefsChangedEvent
;
39 import org
.spearce
.jgit
.lib
.Repository
;
40 import org
.spearce
.jgit
.lib
.RepositoryListener
;
41 import org
.spearce
.jgit
.transport
.SshSessionFactory
;
44 * This is a plugin singleton mostly controlling logging.
46 public class Activator
extends AbstractUIPlugin
{
47 private static Activator plugin
;
50 * @return the {@link Activator} singleton.
52 public static Activator
getDefault() {
57 * @return the id of the egit ui plugin
59 public static String
getPluginId() {
60 return getDefault().getBundle().getSymbolicName();
64 * Instantiate an error exception.
67 * description of the error
69 * cause of the error or null
70 * @return an initialized {@link CoreException}
72 public static CoreException
error(final String message
, final Throwable thr
) {
73 return new CoreException(new Status(IStatus
.ERROR
, getPluginId(), 0,
78 * Log an error via the Eclipse logging routines.
84 public static void logError(final String message
, final Throwable thr
) {
85 getDefault().getLog().log(
86 new Status(IStatus
.ERROR
, getPluginId(), 0, message
, thr
));
91 * name of debug option
92 * @return whether a named debug option is set
94 private static boolean isOptionSet(final String optionId
) {
95 final String option
= getPluginId() + optionId
;
96 final String value
= Platform
.getDebugOption(option
);
97 return value
!= null && value
.equals("true");
101 * Log a debug message
106 public static void trace(final String what
) {
107 if (getDefault().traceVerbose
) {
108 System
.out
.println("[" + getPluginId() + "] " + what
);
113 * Get the theme used by this plugin.
117 public static ITheme
getTheme() {
118 return plugin
.getWorkbench().getThemeManager().getCurrentTheme();
122 * Get a font known to this plugin.
125 * one of our THEME_* font preference ids (see
126 * {@link UIPreferences});
127 * @return the configured font, borrowed from the registry.
129 public static Font
getFont(final String id
) {
130 return getTheme().getFontRegistry().get(id
);
134 * Get a font known to this plugin, but with bold style applied over top.
137 * one of our THEME_* font preference ids (see
138 * {@link UIPreferences});
139 * @return the configured font, borrowed from the registry.
141 public static Font
getBoldFont(final String id
) {
142 return getTheme().getFontRegistry().getBold(id
);
145 private boolean traceVerbose
;
147 private RIRefresh refreshJob
;
150 * Constructor for the egit ui plugin singleton
156 public void start(final BundleContext context
) throws Exception
{
157 super.start(context
);
158 traceVerbose
= isOptionSet("/trace/verbose");
161 setupRepoChangeScanner();
162 setupRepoIndexRefresh();
165 private void setupRepoIndexRefresh() {
166 refreshJob
= new RIRefresh();
167 Repository
.addAnyRepositoryChangedListener(refreshJob
);
170 static class RIRefresh
extends Job
implements RepositoryListener
{
173 super("Git index refresh Job");
176 private Set
<IProject
> projectsToScan
= new LinkedHashSet
<IProject
>();
179 protected IStatus
run(IProgressMonitor monitor
) {
180 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
181 monitor
.beginTask("Refreshing git managed projects", projects
.length
);
183 while (projectsToScan
.size() > 0) {
185 synchronized (projectsToScan
) {
186 if (projectsToScan
.size() == 0)
188 Iterator
<IProject
> i
= projectsToScan
.iterator();
192 ISchedulingRule rule
= p
.getWorkspace().getRuleFactory().refreshRule(p
);
194 getJobManager().beginRule(rule
, monitor
);
195 p
.refreshLocal(IResource
.DEPTH_INFINITE
, new SubProgressMonitor(monitor
, 1));
196 } catch (CoreException e
) {
197 logError("Failed to refresh projects from index changes", e
);
198 return new Status(IStatus
.ERROR
, getPluginId(), e
.getMessage());
200 getJobManager().endRule(rule
);
204 return Status
.OK_STATUS
;
207 public void indexChanged(IndexChangedEvent e
) {
208 // Check the workspace setting "refresh automatically" setting first
209 if (!ResourcesPlugin
.getPlugin().getPluginPreferences().getBoolean(
210 ResourcesPlugin
.PREF_AUTO_REFRESH
))
213 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
214 Set
<IProject
> toRefresh
= new HashSet
<IProject
>();
215 for (IProject p
: projects
) {
216 RepositoryMapping mapping
= RepositoryMapping
.getMapping(p
);
217 if (mapping
!= null && mapping
.getRepository() == e
.getRepository()) {
221 synchronized (projectsToScan
) {
222 projectsToScan
.addAll(toRefresh
);
224 if (projectsToScan
.size() > 0)
228 public void refsChanged(RefsChangedEvent e
) {
234 static class RCS
extends Job
{
236 super("Repository Change Scanner");
239 // FIXME, need to be more intelligent about this to avoid too much work
240 private static final long REPO_SCAN_INTERVAL
= 10000L;
243 protected IStatus
run(IProgressMonitor monitor
) {
245 // A repository can contain many projects, only scan once
246 // (a project could in theory be distributed among many
247 // repositories. We discard that as being ugly and stupid for
249 IProject
[] projects
= ResourcesPlugin
.getWorkspace().getRoot().getProjects();
250 monitor
.beginTask("Scanning Git repositories for changes", projects
.length
);
251 Set
<Repository
> scanned
= new HashSet
<Repository
>();
252 for (IProject p
: projects
) {
253 RepositoryMapping mapping
= RepositoryMapping
.getMapping(p
);
254 if (mapping
!= null) {
255 Repository r
= mapping
.getRepository();
256 if (!scanned
.contains(r
)) {
257 if (monitor
.isCanceled())
259 trace("Scanning " + r
+ " for changes");
261 ISchedulingRule rule
= p
.getWorkspace().getRuleFactory().modifyRule(p
);
262 getJobManager().beginRule(rule
, monitor
);
264 r
.scanForRepoChanges();
266 getJobManager().endRule(rule
);
273 trace("Rescheduling " + getName() + " job");
274 schedule(REPO_SCAN_INTERVAL
);
275 } catch (Exception e
) {
276 trace("Stopped rescheduling " + getName() + "job");
281 "An error occurred while scanning for changes. Scanning aborted",
284 return Status
.OK_STATUS
;
288 private void setupRepoChangeScanner() {
290 rcs
.schedule(RCS
.REPO_SCAN_INTERVAL
);
293 private void setupSSH(final BundleContext context
) {
294 final ServiceReference ssh
;
296 ssh
= context
.getServiceReference(IJSchService
.class.getName());
298 SshSessionFactory
.setInstance(new EclipseSshSessionFactory(
299 (IJSchService
) context
.getService(ssh
)));
303 private void setupProxy(final BundleContext context
) {
304 final ServiceReference proxy
;
306 proxy
= context
.getServiceReference(IProxyService
.class.getName());
308 ProxySelector
.setDefault(new EclipseProxySelector(
309 (IProxyService
) context
.getService(proxy
)));
310 Authenticator
.setDefault(new EclipseAuthenticator(
311 (IProxyService
) context
.getService(proxy
)));
315 public void stop(final BundleContext context
) throws Exception
{
316 trace("Trying to cancel " + rcs
.getName() + " job");
318 trace("Trying to cancel " + refreshJob
.getName() + " job");
324 trace("Jobs terminated");