/******************************************************************************* * Copyright (c) 2012, 2016 VMware, Inc. * All rights reserved. This program and the accompanying materials * are 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: * VMware, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.wizard.template.util; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.dialogs.IOverwriteQuery; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.eclipse.ui.internal.wizards.datatransfer.DataTransferMessages; import org.eclipse.ui.wizards.datatransfer.FileSystemStructureProvider; import org.eclipse.ui.wizards.datatransfer.ImportOperation; import org.springframework.ide.eclipse.maven.MavenCorePlugin; import org.springframework.ide.eclipse.wizard.WizardPlugin; import org.springsource.ide.eclipse.commons.core.FileUtil; import org.springsource.ide.eclipse.commons.core.ZipFileUtil; public class ExampleProjectsImporterJob extends WorkspaceJob implements IOverwriteQuery { private final String projectName; private final URI uri; private final Shell shell; public static final String URL_SUFFIX = "/zipball/master"; public ExampleProjectsImporterJob(URI myUri, String myProjectName, Shell myShell) { super("Importing " + myProjectName); this.uri = myUri; this.projectName = myProjectName; this.shell = myShell; } @Override public IStatus runInWorkspace(IProgressMonitor monitor) { File archiveFile = getArchiveFile(projectName); File targetDirectory = new File(projectName); URL url; try { url = uri.toURL(); if (url.getProtocol().startsWith("http")) { if (url.getHost().endsWith("github.com")) { if (!url.getPath().endsWith(URL_SUFFIX)) { String urlString = url.getProtocol() + "://" + url.getAuthority(); if (url.getPort() != -1) { urlString += ":" + url.getPort(); } urlString += url.getPath() + URL_SUFFIX; // Ignoring query part because github URLs that we are // looking for do not have query parts. If there // is a query part, something has changed. url = new URL(urlString); } } else { // We should never get here: non-github URLs should have // been filtered out by here System.err.println("Uh-oh, this is not a github URL"); } } } catch (MalformedURLException e) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("The URL {0} is malformed", uri)); } try { ZipFileUtil.unzip(url, targetDirectory, new SubProgressMonitor(monitor, 50)); } catch (IOException e1) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Error downloading {0} to {1}", url, archiveFile.getAbsolutePath())); } catch (OperationCanceledException e) { System.err.println("Operation cancelled!"); monitor.done(); return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Cancelled download of {0} to {1}.", url, archiveFile.getAbsolutePath())); } if (!targetDirectory.exists()) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Download of {0} failed", archiveFile.getAbsolutePath())); } File[] subdirs = targetDirectory.listFiles(); if (subdirs.length <= 0) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind( "The zip file downloaded from {0} was empty", url)); } File projectFile = null; File pomFile = null; // This allows for multiple directories, where we believe there will // only be one... for (File subdir : subdirs) { if (subdir.isDirectory()) { boolean hasClasspath = false; File[] projectFiles = subdir.listFiles(); for (File aFile : projectFiles) { if (aFile.getName().equals(IProjectDescription.DESCRIPTION_FILE_NAME)) { projectFile = aFile; } if (aFile.getName().equals(".classpath")) { hasClasspath = true; } if (aFile.getName().equals("pom.xml")) { pomFile = aFile; } } IStatus creationStatus; if (hasClasspath && (projectFile != null)) { creationStatus = createExistingEclipseProject(projectFile, monitor); deleteRecursive(targetDirectory); } else if (pomFile != null) { creationStatus = createExistingMavenProject(pomFile, monitor); if (!hasMaven()) { String message = NLS .bind("You do not appear to have Maven installed. This project requires Maven to import and build.", null); creationStatus = new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, message); } } else { creationStatus = new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind( "Project {0} does not have either pom.xml or .project/.classpath", projectName)); } monitor.done(); return creationStatus; } else { monitor.done(); return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Download of {0} successful", projectName)); } } monitor.done(); return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Unforeseen error downloading {0} from {1}", projectName, url)); } private IStatus createExistingEclipseProject(File projectFile, IProgressMonitor monitor) { SubMonitor sub = SubMonitor.convert(monitor, 100); sub.setTaskName("Loading Eclipse project"); final IWorkspace workspace = ResourcesPlugin.getWorkspace(); final IProject project = workspace.getRoot().getProject(projectName); URI locationURI = projectFile.toURI(); IProjectDescription newDesc; IProjectDescription downloadedDescription; try { downloadedDescription = IDEWorkbenchPlugin.getPluginWorkspace().loadProjectDescription( new Path(projectFile.getPath())); downloadedDescription.setLocation(null); } catch (CoreException e) { return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Could parse{0}, maybe it is corrupted?", projectFile.getAbsolutePath())); } if (locationURI != null) { // validate the location of the project being copied IStatus result = ResourcesPlugin.getWorkspace().validateProjectLocationURI(project, locationURI); if (!result.isOK()) { return result; } newDesc = workspace.newProjectDescription(projectName); newDesc.setBuildSpec(downloadedDescription.getBuildSpec()); newDesc.setComment(downloadedDescription.getComment()); newDesc.setDynamicReferences(downloadedDescription.getDynamicReferences()); newDesc.setNatureIds(downloadedDescription.getNatureIds()); newDesc.setReferencedProjects(downloadedDescription.getReferencedProjects()); try { monitor.beginTask(DataTransferMessages.WizardProjectsImportPage_CreateProjectsTask, 100); if (!project.exists()) { project.create(newDesc, new SubProgressMonitor(monitor, 30)); project.open(IResource.BACKGROUND_REFRESH, new SubProgressMonitor(monitor, 70)); sub.worked(30); } else { sub.worked(30); return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Project {0} already exists.", project.getName())); } } catch (CoreException e) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Could not create project from {0}", projectFile)); } File importSource = new File(locationURI).getParentFile(); List filesToImport = FileSystemStructureProvider.INSTANCE.getChildren(importSource); ImportOperation operation = new ImportOperation(project.getFullPath(), importSource, FileSystemStructureProvider.INSTANCE, this, filesToImport); operation.setContext(shell); operation.setOverwriteResources(true); // need to overwrite operation.setCreateContainerStructure(false); try { operation.run(monitor); } catch (InvocationTargetException e) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind( "Error: Could not create project from {0}", projectFile)); } catch (InterruptedException e) { return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Import of {0} interrupted", projectName)); } sub.worked(70); // clean up after self deleteRecursive(importSource.getParentFile()); } return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Import of {0} successful", projectName)); } public IStatus createExistingMavenProject(File pomFile, IProgressMonitor monitor) { SubMonitor sub = SubMonitor.convert(monitor, 100); sub.setTaskName("Loading Maven project"); IPath projectPath = Platform.getLocation().append(projectName); File downloadDirectory = pomFile.getParentFile(); File projectWorkspaceDirectory = projectPath.toFile(); if (!projectWorkspaceDirectory.exists() && !projectWorkspaceDirectory.mkdir()) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Error: Could not make directory {0}", projectWorkspaceDirectory)); } try { FileUtil.copyDirectory(downloadDirectory.getAbsoluteFile(), projectWorkspaceDirectory.getAbsoluteFile(), monitor); } catch (CoreException e) { return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind( "Error: Could not copy project files from {0} to {1}", downloadDirectory.getAbsoluteFile(), projectWorkspaceDirectory.getAbsoluteFile())); } sub.worked(50); File newPomFile = projectPath.append("pom.xml").toFile(); if (!newPomFile.exists()) { monitor.done(); return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind("Error: Pom file not found at", newPomFile.getAbsolutePath())); } IStatus creationStatus; if (hasMaven()) { creationStatus = createEclipseProjectFromExistingMavenProject(newPomFile, monitor); } else { // FIXME: do what we can to extract something from the archive, even // though we can't make a maven project from it creationStatus = new Status(IStatus.WARNING, WizardPlugin.PLUGIN_ID, NLS.bind( "Error: Maven is not installed, cannot create a project from {0}", pomFile)); } sub.worked(50); // clean up after self deleteRecursive(pomFile.getParentFile().getParentFile()); return creationStatus; } public static IStatus createEclipseProjectFromExistingMavenProject(File pomFile, IProgressMonitor monitor) { try { MavenCorePlugin.createEclipseProjectFromExistingMavenProject(pomFile, monitor); } catch (CoreException e) { monitor.done(); return new Status(IStatus.ERROR, WizardPlugin.PLUGIN_ID, NLS.bind( "Error: Could not create project from {0}", pomFile)); } monitor.done(); return new Status(IStatus.OK, WizardPlugin.PLUGIN_ID, NLS.bind("Import of {0} successful", pomFile)); } // For now, always overwrite public String queryOverwrite(String pathString) { return IOverwriteQuery.YES; } private File getArchiveFile(String projectName) { // TODO strip dangerous characters from the file name? return new File(projectName + ".zip"); } private static boolean hasMaven() { return (MavenCorePlugin.IS_M2ECLIPSE_PRESENT); } private void deleteRecursive(File file) { File[] files = file.listFiles(); if (files != null) { for (File subFile : files) { deleteRecursive(subFile); } } file.delete(); } }