/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonarlint.eclipse.tests.common; import java.io.File; import java.io.IOException; import java.nio.file.CopyOption; import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileSystemLoopException; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; 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.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.junit.AfterClass; import org.junit.BeforeClass; import static java.nio.file.FileVisitResult.CONTINUE; import static java.nio.file.FileVisitResult.SKIP_SUBTREE; import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.junit.Assert.assertTrue; /** * Common test case for sonar-ide/eclipse projects. */ public abstract class SonarTestCase { protected static final IProgressMonitor MONITOR = new NullProgressMonitor(); protected static IWorkspace workspace; protected static File projectsSource; protected static File projectsWorkdir; private static final ReadWriteLock COPY_PROJECT_LOCK = new ReentrantReadWriteLock(); protected static File getProject(String projectName) throws IOException { File destDir = new File(projectsWorkdir, projectName); return getProject(projectName, destDir); } /** * Installs specified project to specified directory. * * @param projectName * name of project * @param destDir * destination directory * @return project directory * @throws IOException * if unable to prepare project directory */ protected static File getProject(String projectName, File destDir) throws IOException { COPY_PROJECT_LOCK.writeLock().lock(); try { File projectFolder = new File(projectsSource, projectName); assertTrue("Project " + projectName + " folder not found.\n" + projectFolder.getAbsolutePath(), projectFolder.isDirectory()); if (destDir.isDirectory()) { System.out.println("Directory for project already exists: " + destDir); } Files.copy(projectFolder.toPath(), destDir.toPath()); EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); TreeCopier tc = new TreeCopier(projectFolder.toPath(), destDir.toPath(), true, true); Files.walkFileTree(projectFolder.toPath(), opts, Integer.MAX_VALUE, tc); return destDir; } finally { COPY_PROJECT_LOCK.writeLock().unlock(); } } /** * A {@code FileVisitor} that copies a file-tree ("cp -r") */ static class TreeCopier implements FileVisitor<Path> { private final Path source; private final Path target; private final boolean force; private final boolean preserve; TreeCopier(Path source, Path target, boolean force, boolean preserve) { this.source = source; this.target = target; this.force = force; this.preserve = preserve; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { // before visiting entries in a directory we copy the directory // (okay if directory already exists). CopyOption[] options = (preserve) ? new CopyOption[] {COPY_ATTRIBUTES} : new CopyOption[0]; Path newdir = target.resolve(source.relativize(dir)); try { Files.copy(dir, newdir, options); } catch (FileAlreadyExistsException x) { // ignore } catch (IOException x) { System.err.format("Unable to create: %s: %s%n", newdir, x); return SKIP_SUBTREE; } return CONTINUE; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { copyFile(file, target.resolve(source.relativize(file)), force, preserve); return CONTINUE; } @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { // fix up modification time of directory when done if (exc == null && preserve) { Path newdir = target.resolve(source.relativize(dir)); try { FileTime time = Files.getLastModifiedTime(dir); Files.setLastModifiedTime(newdir, time); } catch (IOException x) { System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x); } } return CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { if (exc instanceof FileSystemLoopException) { System.err.println("cycle detected: " + file); } else { System.err.format("Unable to copy: %s: %s%n", file, exc); } return CONTINUE; } } /** * Copy source file to target location. If {@code prompt} is true then * prompt user to overwrite target if it exists. The {@code preserve} * parameter determines if file attributes should be copied/preserved. */ static void copyFile(Path source, Path target, boolean force, boolean preserve) { CopyOption[] options = (preserve) ? new CopyOption[] {COPY_ATTRIBUTES, REPLACE_EXISTING} : new CopyOption[] {REPLACE_EXISTING}; if (force || Files.notExists(target)) { try { Files.copy(source, target, options); } catch (IOException x) { System.err.format("Unable to copy: %s: %s%n", source, x); } } } @BeforeClass final static public void prepareWorkspace() throws Exception { // Override default location "target/projects-source" projectsSource = new File("testdata"); projectsWorkdir = new File("target/projects-target"); workspace = ResourcesPlugin.getWorkspace(); final IWorkspaceDescription description = workspace.getDescription(); description.setAutoBuilding(false); workspace.setDescription(description); cleanWorkspace(); } @AfterClass final static public void end() throws Exception { final IWorkspaceDescription description = workspace.getDescription(); description.setAutoBuilding(true); workspace.setDescription(description); } private static void cleanWorkspace() throws Exception { final IWorkspaceRoot root = workspace.getRoot(); for (final IProject project : root.getProjects()) { project.delete(true, true, MONITOR); } } /** * Import test project into the Eclipse workspace * * @return created projects */ public static IProject importEclipseProject(final String projectdir) throws IOException, CoreException { final IWorkspaceRoot root = workspace.getRoot(); final String projectName = projectdir; File dst = new File(root.getLocation().toFile(), projectName); getProject(projectName, dst); final IProject project = workspace.getRoot().getProject(projectName); final List<IProject> addedProjectList = new ArrayList<IProject>(); workspace.run(new IWorkspaceRunnable() { @Override public void run(final IProgressMonitor monitor) throws CoreException { // create project as java project if (!project.exists()) { final IProjectDescription projectDescription = workspace.newProjectDescription(project.getName()); projectDescription.setLocation(null); project.create(projectDescription, monitor); project.open(IResource.NONE, monitor); } else { project.refreshLocal(IResource.DEPTH_INFINITE, monitor); } addedProjectList.add(project); } }, workspace.getRoot(), IWorkspace.AVOID_UPDATE, MONITOR); JobHelpers.waitForJobsToComplete(); return addedProjectList.get(0); } }