/******************************************************************************* * Copyright (c) 2013 Cloud Bees, Inc. * All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cloud Bees, Inc. - initial API and implementation *******************************************************************************/ package com.cloudbees.eclipse.dev.ui; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.plugin.AbstractUIPlugin; import org.osgi.framework.BundleContext; import com.cloudbees.eclipse.core.CBRemoteChangeAdapter; import com.cloudbees.eclipse.core.CBRemoteChangeListener; import com.cloudbees.eclipse.core.CloudBeesCorePlugin; import com.cloudbees.eclipse.core.CloudBeesException; import com.cloudbees.eclipse.core.JenkinsService; import com.cloudbees.eclipse.core.Logger; import com.cloudbees.eclipse.core.jenkins.api.ChangeSetPathItem; import com.cloudbees.eclipse.core.jenkins.api.JenkinsBuild; import com.cloudbees.eclipse.core.jenkins.api.JenkinsJobAndBuildsResponse; import com.cloudbees.eclipse.core.jenkins.api.JenkinsJobsResponse; import com.cloudbees.eclipse.core.jenkins.api.JenkinsJobsResponse.Job; import com.cloudbees.eclipse.core.jenkins.api.JenkinsScmConfig; import com.cloudbees.eclipse.dev.core.CloudBeesDevCorePlugin; import com.cloudbees.eclipse.dev.ui.views.build.BuildEditorInput; import com.cloudbees.eclipse.dev.ui.views.build.BuildHistoryView; import com.cloudbees.eclipse.dev.ui.views.build.BuildPart; import com.cloudbees.eclipse.dev.ui.views.jobs.JobConsoleManager; import com.cloudbees.eclipse.dev.ui.views.jobs.JobsView; import com.cloudbees.eclipse.ui.CloudBeesUIPlugin; /** * The activator class controls the plug-in life cycle */ public class CloudBeesDevUiPlugin extends AbstractUIPlugin { private CBRemoteChangeListener remoteChangeListener = new CBRemoteChangeAdapter() { public void activeAccountChanged(String email, String newAccountName) { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { @Override public void run() { closeBuildEditors(); } }); } private void closeBuildEditors() { try { // Close all editors that host cloud-hosted build IWorkbenchPage page = CloudBeesUIPlugin.getActiveWindow().getActivePage(); //com.cloudbees.eclipse.dev.ui.views.build.BuildPart //CloudBeesUIPlugin.getActiveWindow().getActivePage() for (IEditorReference ref : page.getEditorReferences()) { try { if (ref.getId() != null && ref.getId().equals(com.cloudbees.eclipse.dev.ui.views.build.BuildPart.ID)) { IEditorInput in; try { in = ref.getEditorInput(); } catch (PartInitException e) { e.printStackTrace(); continue; } IEditorPart p = ref.getEditor(false); if (in instanceof BuildEditorInput && p != null) { JenkinsService s = CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl( ((BuildEditorInput) in).getJobUrl()); if (s == null || s.isCloud()) { // if service not existing anymore or hosted at cloud, close the editor page.closeEditor(p, false); } } } } catch (Throwable t) { t.printStackTrace(); continue; } } } catch (Exception e) { getLogger().error(e); } } }; public static final String PLUGIN_ID = "com.cloudbees.eclipse.dev.ui"; //$NON-NLS-1$ private static CloudBeesDevUiPlugin plugin; private JobConsoleManager jobConsoleManager; private Logger logger; /** * The constructor */ public CloudBeesDevUiPlugin() { } /* * (non-Javadoc) * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) */ @Override public void start(final BundleContext context) throws Exception { super.start(context); CloudBeesDevUiPlugin.plugin = this; CloudBeesDevCorePlugin.getDefault(); this.logger = new Logger(getLog()); CloudBeesUIPlugin.getDefault().addCBRemoteChangeListener(this.remoteChangeListener); } /* * (non-Javadoc) * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) */ @Override public void stop(final BundleContext context) throws Exception { CloudBeesDevUiPlugin.plugin = null; this.logger = null; if (this.jobConsoleManager != null) { this.jobConsoleManager.unregister(); this.jobConsoleManager = null; } CloudBeesUIPlugin.getDefault().removeCBRemoteChangeListener(this.remoteChangeListener); super.stop(context); } /** * Returns the shared instance * * @return the shared instance */ public static CloudBeesDevUiPlugin getDefault() { return plugin; } public Logger getLogger() { return this.logger; } public JobConsoleManager getJobConsoleManager() { if (this.jobConsoleManager == null) { this.jobConsoleManager = new JobConsoleManager(); } return this.jobConsoleManager; } @Override protected void initializeImageRegistry(final ImageRegistry reg) { super.initializeImageRegistry(reg); reg.put(CBDEVImages.IMG_CONSOLE, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/monitor_obj.png"))); reg.put(CBDEVImages.IMG_REFRESH, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/refresh.png"))); reg.put(CBDEVImages.IMG_BROWSER, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/internal_browser.gif"))); reg.put(CBDEVImages.IMG_RUN, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/lrun_obj.png"))); reg.put(CBDEVImages.IMG_BUILD_HISTORY, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/history_view.gif"))); reg.put(CBDEVImages.IMG_DEPLOY, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/clock.gif"))); reg.put(CBDEVImages.IMG_FOLDER_HOSTED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/16x16/cb_folder_cb.png"))); reg.put(CBDEVImages.IMG_FOLDER_LOCAL, ImageDescriptor.createFromURL(getBundle().getResource("/icons/16x16/cb_folder_run_plain.png"))); reg.put(CBDEVImages.IMG_INSTANCE, ImageDescriptor.createFromURL(getBundle().getResource("/icons/16x16/jenkins.png"))); reg.put(CBDEVImages.IMG_VIEW, ImageDescriptor.createFromURL(getBundle().getResource("/icons/16x16/cb_view_dots_big.png"))); reg.put(CBDEVImages.IMG_VIEWR2, ImageDescriptor.createFromURL(getBundle().getResource("/icons/16x16/cb_view_dots_bigr2.png"))); //reg.put(CBImages.IMG_VIEW, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/det_pane_hide.gif"))); reg.put(CBDEVImages.IMG_FILE, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/file_obj.gif"))); reg.put(CBDEVImages.IMG_FILE_ADDED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/add_stat.gif"))); reg.put(CBDEVImages.IMG_FILE_MODIFIED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/mod_stat.gif"))); reg.put(CBDEVImages.IMG_FILE_DELETED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/del_stat.gif"))); reg.put(CBDEVImages.IMG_JUNIT, ImageDescriptor.createFromURL(getBundle().getResource("/icons/epl/junit.gif"))); reg.put(CBDEVImages.IMG_BUILD_DETAILS, ImageDescriptor.createFromURL(getBundle().getResource("icons/epl/debugt_obj.png"))); reg.put(CBDEVImages.IMG_DELETE, ImageDescriptor.createFromURL(getBundle().getResource("icons/epl/delete.gif"))); reg.put(CBDEVImages.IMG_DELETE_DISABLED, ImageDescriptor.createFromURL(getBundle().getResource("icons/epl/d/delete.gif"))); reg.put(CBDEVImages.IMG_COLOR_16_GREY, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/grey.gif"))); reg.put(CBDEVImages.IMG_COLOR_16_RED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/red.gif"))); reg.put(CBDEVImages.IMG_COLOR_16_BLUE, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/blue.gif"))); reg.put(CBDEVImages.IMG_COLOR_16_YELLOW, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/yellow.gif"))); reg.put(CBDEVImages.IMG_COLOR_24_RED, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/red.gif"))); reg.put(CBDEVImages.IMG_COLOR_24_BLUE, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/blue.gif"))); // HEALTH 16px reg.put(CBDEVImages.IMG_HEALTH_16_00_to_19, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/health-00to19.gif"))); reg.put(CBDEVImages.IMG_HEALTH_16_20_to_39, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/health-20to39.gif"))); reg.put(CBDEVImages.IMG_HEALTH_16_40_to_59, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/health-40to59.gif"))); reg.put(CBDEVImages.IMG_HEALTH_16_60_to_79, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/health-60to79.gif"))); reg.put(CBDEVImages.IMG_HEALTH_16_80PLUS, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/16x16/health-80plus.gif"))); // HEALTH 24px reg.put(CBDEVImages.IMG_HEALTH_24_00_to_19, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/health-00to19.gif"))); reg.put(CBDEVImages.IMG_HEALTH_24_20_to_39, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/health-20to39.gif"))); reg.put(CBDEVImages.IMG_HEALTH_24_40_to_59, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/health-40to59.gif"))); reg.put(CBDEVImages.IMG_HEALTH_24_60_to_79, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/health-60to79.gif"))); reg.put(CBDEVImages.IMG_HEALTH_24_80PLUS, ImageDescriptor.createFromURL(getBundle().getResource("/icons/jenkins-icons/24x24/health-80plus.gif"))); reg.put(CBDEVImages.IMG_CB_ICON_LARGE_64x66, ImageDescriptor.createFromURL(getBundle().getResource("/icons/cb_wiz_icon.png"))); } public static Image getImage(final String imgKey) { return CloudBeesDevUiPlugin.getDefault().getImageRegistry().get(imgKey); } public static ImageDescriptor getImageDescription(final String imgKey) { CloudBeesDevUiPlugin pl = CloudBeesDevUiPlugin.getDefault(); return pl != null ? pl.getImageRegistry().getDescriptor(imgKey) : null; } private org.eclipse.core.runtime.jobs.Job showJobsForHash(final String viewUrl, final boolean userAction, final String hash) throws CloudBeesException { // CloudBeesUIPlugin.getDefault().getLogger().info("Show jobs: " + viewUrl); //System.out.println("Show jobs: " + viewUrl); if (viewUrl == null) { return null; // no info } org.eclipse.core.runtime.jobs.Job job = new org.eclipse.core.runtime.jobs.Job("Loading Jenkins jobs") { @Override protected IStatus run(final IProgressMonitor monitor) { try { if (userAction) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { try { IWorkbenchPage activePage = CloudBeesUIPlugin.getActiveWindow().getActivePage(); //hashCode = viewUrl.hashCode(); int mode = userAction ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_CREATE; IViewPart view = activePage.showView(JobsView.ID, hash, mode); } catch (PartInitException e) { CloudBeesUIPlugin.showError("Failed to show Jobs view", e); } } }); } if (monitor.isCanceled()) { throw new OperationCanceledException(); } JenkinsService jenkinsService = CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(viewUrl); JenkinsJobsResponse jobs = jenkinsService.getJobs(viewUrl, monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } List<CBRemoteChangeListener> listeners = Collections.unmodifiableList(CloudBeesUIPlugin.getDefault() .getJenkinsChangeListeners()); monitor.subTask("Notifying jenkins components"); Iterator<CBRemoteChangeListener> iterator = listeners.iterator(); while (iterator.hasNext()) { CBRemoteChangeListener listener = iterator.next(); try { listener.activeJobViewChanged(jobs); } catch (Throwable e) { // listeners must not fail getLogger().error(e); } try { listener.jenkinsStatusUpdate(viewUrl, true); } catch (Throwable e) { // listeners must not fail getLogger().error(e); } monitor.worked(10); } return Status.OK_STATUS; } catch (CloudBeesException e) { // Failed to load jobs. Notify in order to show node as offline List<CBRemoteChangeListener> listeners = Collections.unmodifiableList(CloudBeesUIPlugin.getDefault() .getJenkinsChangeListeners()); monitor.subTask("Failed! Notifying jenkins components."); Iterator<CBRemoteChangeListener> iterator = listeners.iterator(); while (iterator.hasNext()) { CBRemoteChangeListener listener = iterator.next(); try { listener.jenkinsStatusUpdate(viewUrl, false); } catch (Throwable t) { // listeners must not fail getLogger().error(t); } monitor.worked(10); } getLogger().error(e); return new Status(Status.WARNING, PLUGIN_ID, 0, e.getLocalizedMessage(), e.getCause()); } } }; job.setUser(userAction); // Let's always show this job as non-user so it's less distracting in the UI //userAction job.schedule(); return job; } public org.eclipse.core.runtime.jobs.Job showJobs(final String viewUrl, final boolean userAction) throws CloudBeesException { String urlHash = Long.toString(CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(viewUrl).getUrl().hashCode()); return showJobsForHash(viewUrl, userAction, urlHash); } public void showView(final String viewId) { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { try { CloudBeesUIPlugin.getActiveWindow().getActivePage().showView(viewId); } catch (PartInitException e) { CloudBeesUIPlugin.showError("Failed to show view: " + viewId, e); } } }); } public void showBuildForJob(final Job job) { if (job == null) { return; } String name; String url; if (job.lastBuild != null && job.lastBuild.url != null) { name = job.lastBuild.getDisplayName(); url = job.lastBuild.url; } else { name = job.getDisplayName(); url = job.url; } try { CloudBeesUIPlugin.getActiveWindow().getActivePage().openEditor(new BuildEditorInput(name, url), BuildPart.ID); } catch (PartInitException e) { CloudBeesUIPlugin.getDefault().getLogger().error(e); } } public void showBuild(final JenkinsBuild build) { if (build == null) { return; } try { CloudBeesUIPlugin.getActiveWindow().getActivePage() .openEditor(new BuildEditorInput(build.getDisplayName(), build.url), BuildPart.ID); } catch (PartInitException e) { CloudBeesUIPlugin.getDefault().getLogger().error(e); } } /** * @param job * @param monitor * @return <code>true</code> if succeeded * @throws CloudBeesException */ public void deleteJob(final Job job) throws CloudBeesException { boolean openConfirm = MessageDialog.openConfirm(Display.getCurrent().getActiveShell(), "DELETING BUILD JOB!", "Are you sure you want to delete this build job?\n" + "Name: " + job.getDisplayName()); if (openConfirm) { JenkinsService service = CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(job.url); service.deleteJenkinsJob(job.url, new NullProgressMonitor()); } } public void openRemoteFile(final String jobUrl, final ChangeSetPathItem item) { org.eclipse.core.runtime.jobs.Job job = new org.eclipse.core.runtime.jobs.Job("Opening remote file") { @Override protected IStatus run(final IProgressMonitor monitor) { try { JenkinsService jenkins = CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(jobUrl); if (monitor.isCanceled()) { throw new OperationCanceledException(); } JenkinsScmConfig scmConfig = jenkins.getJenkinsScmConfig(jobUrl, monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } // boolean opened = CloudBeesCorePlugin.getDefault().getGrandCentralService().getForgeSyncService() // .openRemoteFile(scmConfig, item, monitor); // return opened ? Status.OK_STATUS : new Status(IStatus.INFO, PLUGIN_ID, "Can't open " + item.path); return new Status(IStatus.INFO, PLUGIN_ID, "Not implemented!"); } catch (CloudBeesException e) { getLogger().error(e); return new Status(Status.ERROR, PLUGIN_ID, 0, e.getLocalizedMessage(), e.getCause()); } } }; job.setUser(true); job.schedule(); } public void showBuildHistory(final String jobUrl, final boolean userAction) throws CloudBeesException { // CloudBeesUIPlugin.getDefault().getLogger().info("Show build history: " + jobUrl); //System.out.println("Show build history: " + jobUrl); if (jobUrl == null) { return; // no info } org.eclipse.core.runtime.jobs.Job job = new org.eclipse.core.runtime.jobs.Job("Loading build history") { @Override protected IStatus run(final IProgressMonitor monitor) { try { PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() { @Override public void run() { try { CloudBeesUIPlugin .getActiveWindow() .getActivePage() .showView( BuildHistoryView.ID, Long.toString(CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(jobUrl).getUrl() .hashCode()), userAction ? IWorkbenchPage.VIEW_ACTIVATE : IWorkbenchPage.VIEW_CREATE); } catch (PartInitException e) { CloudBeesUIPlugin.getDefault().showError("Failed to show build history view", e); } } }); if (monitor.isCanceled()) { throw new OperationCanceledException(); } JenkinsJobAndBuildsResponse builds = CloudBeesUIPlugin.getDefault().getJenkinsServiceForUrl(jobUrl) .getJobBuilds(jobUrl, monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } Iterator<CBRemoteChangeListener> iterator = CloudBeesUIPlugin.getDefault().getJenkinsChangeListeners() .iterator(); while (iterator.hasNext()) { CBRemoteChangeListener listener = iterator.next(); listener.activeJobHistoryChanged(builds); } return Status.OK_STATUS; } catch (CloudBeesException e) { CloudBeesUIPlugin.getDefault().getLogger().error(e); return new Status(Status.ERROR, PLUGIN_ID, 0, e.getLocalizedMessage(), e.getCause()); } } }; job.setUser(userAction); job.schedule(); } public static void logError(final Exception e) { IStatus status = new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()); plugin.getLog().log(status); } }