/******************************************************************************* * Copyright (c) 2012 Red Hat Inc. and others. * 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 *******************************************************************************/ package org.eclipse.cdt.autotools.tests; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.zip.ZipFile; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.CommandLauncher; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.internal.autotools.core.configure.AutotoolsConfigurationManager; import org.eclipse.cdt.internal.autotools.core.configure.IAConfiguration; import org.eclipse.cdt.internal.autotools.ui.wizards.ConvertToAutotoolsProjectWizard; import org.eclipse.cdt.internal.autotools.ui.wizards.ConvertToAutotoolsProjectWizardPage; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.IProjectType; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.ui.wizards.conversion.ConvertProjectWizardPage; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; 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.IWorkspaceDescription; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.eclipse.ui.dialogs.IOverwriteQuery; import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; import org.eclipse.ui.wizards.datatransfer.ImportOperation; import org.eclipse.ui.wizards.datatransfer.ZipFileStructureProvider; import org.osgi.framework.FrameworkUtil; @SuppressWarnings("restriction") public class ProjectTools { static IWorkspace workspace; static IWorkspaceRoot root; static NullProgressMonitor monitor; static String pluginRoot; static ConvertProjectWizardPage page; static boolean setupComplete; /** * Setup routine for tests. * @return true if setup successful, false otherwise * @throws CoreException */ public static boolean setup() throws CoreException { if (!setupComplete) { IWorkspaceDescription desc; workspace = ResourcesPlugin.getWorkspace(); if (workspace == null) { return false; } root = workspace.getRoot(); monitor = new NullProgressMonitor(); if (root == null) { return false; } desc = workspace.getDescription(); desc.setAutoBuilding(false); workspace.setDescription(desc); } setupComplete = true; return true; } /** * Build the project. * @return true if build started successfully or false otherwise */ public static boolean build() { try { workspace.build(IncrementalProjectBuilder.FULL_BUILD, getMonitor()); workspace.getRoot().refreshLocal(IResource.DEPTH_INFINITE, getMonitor()); } catch (CoreException e) { return false; } return true; } /** * Get the default monitor. * @return The current monitor */ public static IProgressMonitor getMonitor() { return monitor; } /** * Get the workspace. * @return The workspace */ public static IWorkspaceRoot getWorkspaceRoot() { return root; } /** * Mark a specified file in a project as executable. * @param project The project that the file is found in * @param filePath The relative path to the file * @return true if the change was successful, false otherwise */ public static boolean markExecutable(IProject project, String filePath) { // Get a launcher for the config command CommandLauncher launcher = new CommandLauncher(); OutputStream stdout = new ByteArrayOutputStream(); OutputStream stderr = new ByteArrayOutputStream(); launcher.showCommand(true); IPath commandPath = new Path("chmod"); IPath runPath = project.getLocation().append(filePath).removeLastSegments(1); // if the path points to an actual object, use its resource to get its run path location // which will handle any linked directories if (project.findMember(filePath) != null) runPath = project.findMember(filePath).getLocation().removeLastSegments(1); String[] args = new String[2]; args[0] = "+x"; // if the path points to an actual object, use its resource to get its location // which will handle any linked directories if (project.findMember(filePath) != null) args[1] = project.findMember(filePath).getLocation().toOSString(); else // otherwise, just append to project location args[1] = project.getLocation().append(filePath).toOSString(); try { Process proc = launcher.execute(commandPath, args, new String[0], runPath, new NullProgressMonitor()); if (proc != null) { try { // Close the input of the process since we will never write to // it proc.getOutputStream().close(); } catch (IOException e) { } if (launcher.waitAndRead(stdout, stderr, SubMonitor.convert(monitor, IProgressMonitor.UNKNOWN)) != CommandLauncher.OK) { return false; } } else return false; } catch (CoreException e) { return false; } return true; } // Inner class to allow us to fake a project wizard without starting up // the UI for it. protected static class ConvertToAutotoolsProjectWizardTest extends ConvertToAutotoolsProjectWizard { ConvertToAutotoolsProjectWizardTest() { super(); } // The following is a kludge to allow testing to occur for the // wizard code. The regular applyOptions() method would also attempt // to call performApply() for the optionPage. This doesn't work in // the test scenario because the UI display logic is needed to // initialize some things. The performApply() call is only needed // to check out referenced projects. In our test scenario, this is // not required. @Override public void applyOptions(IProject project, IProgressMonitor monitor) { setCurrentProject(project); } @Override public IConfiguration[] getSelectedConfigurations() { IProjectType projectType = ManagedBuildManager.getExtensionProjectType("org.eclipse.linuxtools.cdt.autotools.core.projectType"); //$NON-NLS-1$ return projectType.getConfigurations(); } } /** * Creates an empty Autotools project. * @param name The name of the new project * @return The newly created project or null */ public static IProject createProject(String name) { IProject testProject = root.getProject(name); if (testProject == null) { return null; } IProjectDescription description = workspace.newProjectDescription(name); try { testProject.create(monitor); testProject.open(monitor); IProject newProject = CCorePlugin.getDefault().createCDTProject(description, testProject, SubMonitor.convert(monitor,25)); ConvertToAutotoolsProjectWizardTest wizard = new ConvertToAutotoolsProjectWizardTest(); wizard.addPages(); ConvertToAutotoolsProjectWizardPage page = new ConvertToAutotoolsProjectWizardPage("test", wizard); page.convertProject(newProject, monitor, wizard.getProjectID()); } catch (CoreException e) { testProject = null; } return testProject; } /** * Set the configuration source directory for an Autotools project. * @param project The Autotools project to modify * @param dir The relative project directory to use */ public static void setConfigDir(IProject project, String dir) { IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(project); IConfiguration c = info.getDefaultConfiguration(); ICConfigurationDescription cfgd = ManagedBuildManager.getDescriptionForConfiguration(c); String id = cfgd.getId(); IAConfiguration cfg = AutotoolsConfigurationManager.getInstance().getConfiguration(project, id, true); cfg.setConfigToolDirectory(dir); } private static void importFilesFromZip(ZipFile srcZipFile, IPath destPath, IProgressMonitor monitor) throws InvocationTargetException { ZipFileStructureProvider structureProvider= new ZipFileStructureProvider(srcZipFile); try { ImportOperation op= new ImportOperation(destPath, structureProvider.getRoot(), structureProvider, new ImportOverwriteQuery()); op.run(monitor); } catch (InterruptedException e) { // should not happen } } private static boolean generateFiles(IPath destPath) { // Get a launcher for the config command CommandLauncher launcher = new CommandLauncher(); OutputStream stdout = new ByteArrayOutputStream(); OutputStream stderr = new ByteArrayOutputStream(); IPath runPath = root.getLocation().append(destPath); // Run the genfiles.sh shell script which will simulate // running aclocal, autoconf, and automake launcher.showCommand(true); IPath commandPath = new Path("sh"); String[] cmdargs = new String[]{"genfiles.sh"}; try { Process proc = launcher.execute(commandPath, cmdargs, new String[0], runPath, new NullProgressMonitor()); if (proc != null) { try { // Close the input of the process since we will never write to // it proc.getOutputStream().close(); } catch (IOException e) { } if (launcher.waitAndRead(stdout, stderr, SubMonitor.convert( monitor, IProgressMonitor.UNKNOWN)) != CommandLauncher.OK) { return false; } } else return false; } catch (CoreException e) { return false; } return true; } private static void importFilesFromZipAndGenerate(ZipFile srcZipFile, IPath destPath, IProgressMonitor monitor) throws InvocationTargetException { importFilesFromZip(srcZipFile, destPath, monitor); if (!generateFiles(destPath)) throw new InvocationTargetException(new Exception("Unsuccessful test file generation")); } private static class ImportOverwriteQuery implements IOverwriteQuery { @Override public String queryOverwrite(String file) { return ALL; } } /** * Adds a source container to a IProject. * @param jproject The parent project * @param containerName The name of the new source container * @return The handle to the new source container * @throws CoreException Creation failed */ public static IContainer addSourceContainer(IProject jproject, String containerName) throws CoreException { IProject project= jproject.getProject(); IContainer container= null; if (containerName == null || containerName.length() == 0) { container= project; } else { IFolder folder= project.getFolder(containerName); if (!folder.exists()) { createFolder(folder, false, true, null); } container= folder; } return container; } /** * Adds a source container to a IProject and imports all files contained * in the given ZIP file. * @param project The parent project * @param containerName Name of the source container * @param zipFile Archive to import * @param generate true if configuration files need to be pre-generated * @param exclusionFilters Exclusion filters to set * @return The handle to the new source container * @throws InvocationTargetException Creation failed * @throws CoreException Creation failed * @throws IOException Creation failed */ public static IContainer addSourceContainerWithImport(IProject project, String containerName, File zipFile, boolean generate) throws InvocationTargetException, CoreException, IOException { try (ZipFile file= new ZipFile(zipFile)){ IContainer root= addSourceContainer(project, containerName); if (generate) importFilesFromZipAndGenerate(file, root.getFullPath(), null); else importFilesFromZip(file, root.getFullPath(), null); return root; } } /** * Adds a source container to a IProject and imports all files contained * in the given ZIP file and generates configuration files if needed. * @param project The parent project * @param containerName Name of the source container * @param path path of zipFile Archive to import * @param generate true if configuration files need to be pre-generated * @return The handle to the new source container * @throws InvocationTargetException Creation failed * @throws CoreException Creation failed * @throws IOException Creation failed */ public static IContainer addSourceContainerWithImport(IProject project, String containerName, Path zipFilePath, boolean generate) throws InvocationTargetException, CoreException, IOException { File zipFile = new File(FileLocator.toFileURL(FileLocator.find(FrameworkUtil.getBundle(ProjectTools.class), zipFilePath, null)).getFile()); return addSourceContainerWithImport(project, containerName, zipFile, generate); } /** * Adds a source container to a IProject and imports all files contained * in the given ZIP file. * @param project The parent project * @param containerName Name of the source container * @param path path of zipFile Archive to import * @return The handle to the new source container * @throws InvocationTargetException Creation failed * @throws CoreException Creation failed * @throws IOException Creation failed */ public static IContainer addSourceContainerWithImport(IProject project, String containerName, Path zipFilePath) throws InvocationTargetException, CoreException, IOException { return addSourceContainerWithImport(project, containerName, zipFilePath, false); } /** * Create a file for a project and initialize the contents. * @param project The project to create a file for * @param filename Name of the new file * @param contents String containing the initial contents of the file * @return the created file * @throws CoreException */ public IFile createFile(IProject project, String filename, String contents) throws CoreException { IFile file = project.getFile(filename); file.create(null, false, null); file.setContents(new ByteArrayInputStream(contents.getBytes()), false, false, null); return file; } /** * Create a linked folder for a project * @param project The project * @param folderName Name of the linked folder in the project * @param path The URI of the real file/folder * * @return * @throws CoreException */ public static IFolder createLinkedFolder(IProject project, String folderName, final URI linkTarget) throws Exception { final IFolder folderHandle = root.getFolder(project.getFullPath().append(folderName)); WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { @Override public void execute(IProgressMonitor monitor) throws CoreException { try { monitor.beginTask(IDEWorkbenchMessages.NewFolderDialog_progress, 2000); if (monitor.isCanceled()) { throw new OperationCanceledException(); } folderHandle.createLink(linkTarget, IResource.ALLOW_MISSING_LOCAL, monitor); if (monitor.isCanceled()) { throw new OperationCanceledException(); } } finally { monitor.done(); } } }; try { PlatformUI.getWorkbench().getProgressService().busyCursorWhile(operation); } catch (InterruptedException exception) { return null; } return folderHandle; } /** * Creates a folder and all parent folders if not existing. * Project must exist. * <code> org.eclipse.ui.dialogs.ContainerGenerator</code> is too heavy * (creates a runnable) */ public static void createFolder(IFolder folder, boolean force, boolean local, IProgressMonitor monitor) throws CoreException { if (!folder.exists()) { IContainer parent= folder.getParent(); if (parent instanceof IFolder) { createFolder((IFolder)parent, force, local, null); } folder.create(force, local, monitor); } } }