From 60811de15df70cd5fa0a1d18acc7577c673e9484 Mon Sep 17 00:00:00 2001 From: Sébastien Lesaint Date: Thu, 11 Feb 2016 13:42:30 +0100 Subject: SONAR-7125 use efficient delete dir method in sonar-process --- .../java/org/sonar/process/ConfigurationUtils.java | 10 +- .../src/main/java/org/sonar/process/FileUtils.java | 180 +++++++++++++++ .../org/sonar/process/MinimumViableSystem.java | 4 +- .../test/java/org/sonar/process/FileUtilsTest.java | 245 +++++++++++++++++++++ 4 files changed, 432 insertions(+), 7 deletions(-) create mode 100644 server/sonar-process/src/main/java/org/sonar/process/FileUtils.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/FileUtilsTest.java (limited to 'server') diff --git a/server/sonar-process/src/main/java/org/sonar/process/ConfigurationUtils.java b/server/sonar-process/src/main/java/org/sonar/process/ConfigurationUtils.java index 045b4e581ca..734a57f8adb 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ConfigurationUtils.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ConfigurationUtils.java @@ -19,10 +19,6 @@ */ package org.sonar.process; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.text.StrSubstitutor; - import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; @@ -31,6 +27,10 @@ import java.nio.charset.StandardCharsets; import java.util.Enumeration; import java.util.Map; import java.util.Properties; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.text.StrSubstitutor; + +import static org.apache.commons.io.FileUtils.deleteQuietly; public final class ConfigurationUtils { @@ -66,7 +66,7 @@ public final class ConfigurationUtils { throw new IllegalStateException("Could not read properties from file: " + args[0], e); } finally { IOUtils.closeQuietly(reader); - FileUtils.deleteQuietly(propertyFile); + deleteQuietly(propertyFile); } return new Props(properties); } diff --git a/server/sonar-process/src/main/java/org/sonar/process/FileUtils.java b/server/sonar-process/src/main/java/org/sonar/process/FileUtils.java new file mode 100644 index 00000000000..f25ac1f101a --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/FileUtils.java @@ -0,0 +1,180 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT 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.sonar.process; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.EnumSet; +import javax.annotation.Nullable; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; + +/** + * This utility class provides Java NIO based replacement for some methods of + * {@link org.apache.commons.io.FileUtils Common IO FileUtils} class. + */ +public final class FileUtils { + private static final String DIRECTORY_CAN_NOT_BE_NULL = "Directory can not be null"; + private static final EnumSet FOLLOW_LINKS = EnumSet.of(FileVisitOption.FOLLOW_LINKS); + + private FileUtils() { + // prevents instantiation + } + + /** + * Cleans a directory recursively. + * + * @param directory directory to delete + * @throws IOException in case deletion is unsuccessful + */ + public static void cleanDirectory(File directory) throws IOException { + requireNonNull(directory, DIRECTORY_CAN_NOT_BE_NULL); + if (!directory.exists()) { + return; + } + + cleanDirectoryImpl(directory.toPath()); + } + + /** + * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. + *

+ * The difference between File.delete() and this method are: + *

+ * + * @param file file or directory to delete, can be {@code null} + * @return {@code true} if the file or directory was deleted, otherwise {@code false} + */ + public static boolean deleteQuietly(@Nullable File file) { + if (file == null) { + return false; + } + + try { + if (file.isDirectory()) { + deleteDirectory(file); + } else { + Files.delete(file.toPath()); + } + return true; + } catch (IOException | SecurityException ignored) { + return false; + } + } + + /** + * Deletes a directory recursively. Does not support symbolic link to directories. + * + * @param directory directory to delete + * @throws IOException in case deletion is unsuccessful + */ + public static void deleteDirectory(File directory) throws IOException { + requireNonNull(directory, DIRECTORY_CAN_NOT_BE_NULL); + + Path path = directory.toPath(); + if (!Files.exists(path)) { + return; + } + + if (Files.isSymbolicLink(path)) { + throw new IOException(format("Directory '%s' is a symbolic link", directory)); + } + if (Files.isRegularFile(path)) { + throw new IOException(format("Directory '%s' is a file", directory)); + } + deleteDirectoryImpl(path); + + if (Files.exists(path)) { + throw new IOException(format("Unable to delete directory '%s'", directory)); + } + } + + private static void cleanDirectoryImpl(Path path) throws IOException { + if (!Files.isDirectory(path)) { + throw new IllegalArgumentException(format("'%s' is not a directory", path)); + } + Files.walkFileTree(path, FOLLOW_LINKS, CleanDirectoryFileVisitor.VISIT_MAX_DEPTH, new CleanDirectoryFileVisitor(path)); + } + + private static void deleteDirectoryImpl(Path path) throws IOException { + Files.walkFileTree(path, DeleteRecursivelyFileVisitor.INSTANCE); + } + + /** + * This visitor is intended to be used to visit direct children of directory or a symLink to a directory, + * so, with a max depth of {@link #VISIT_MAX_DEPTH 1}. Each direct children will either be directly deleted (if file) + * or recursively deleted (if directory). + */ + private static class CleanDirectoryFileVisitor extends SimpleFileVisitor { + public static final int VISIT_MAX_DEPTH = 1; + + private final Path path; + private final boolean symLink; + + public CleanDirectoryFileVisitor(Path path) { + this.path = path; + this.symLink = Files.isSymbolicLink(path); + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (Files.isDirectory(file)) { + deleteDirectoryImpl(file); + } else if (!symLink || !file.equals(path)) { + Files.delete(file); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (!dir.equals(path)) { + deleteDirectoryImpl(dir); + } + return FileVisitResult.CONTINUE; + } + } + + private static final class DeleteRecursivelyFileVisitor extends SimpleFileVisitor { + public static final DeleteRecursivelyFileVisitor INSTANCE = new DeleteRecursivelyFileVisitor(); + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/MinimumViableSystem.java b/server/sonar-process/src/main/java/org/sonar/process/MinimumViableSystem.java index 320bb133cee..3b20d57c5dc 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/MinimumViableSystem.java +++ b/server/sonar-process/src/main/java/org/sonar/process/MinimumViableSystem.java @@ -19,7 +19,6 @@ */ package org.sonar.process; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import java.io.File; @@ -27,6 +26,7 @@ import java.io.IOException; import java.util.Map; import static java.lang.String.format; +import static org.sonar.process.FileUtils.deleteQuietly; public class MinimumViableSystem { @@ -42,7 +42,7 @@ public class MinimumViableSystem { void checkWritableDir(String tempPath) { try { File tempFile = File.createTempFile("check", "tmp", new File(tempPath)); - FileUtils.deleteQuietly(tempFile); + deleteQuietly(tempFile); } catch (IOException e) { throw new IllegalStateException(format("Temp directory is not writable: %s", tempPath), e); } diff --git a/server/sonar-process/src/test/java/org/sonar/process/FileUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/FileUtilsTest.java new file mode 100644 index 00000000000..9b1b0ce6d12 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/FileUtilsTest.java @@ -0,0 +1,245 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT 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.sonar.process; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import javax.annotation.CheckForNull; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FileUtilsTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void cleanDirectory_throws_NPE_if_file_is_null() throws IOException { + expectDirectoryCanNotBeNullNPE(); + + FileUtils.cleanDirectory(null); + } + + @Test + public void cleanDirectory_does_nothing_if_argument_does_not_exist() throws IOException { + FileUtils.cleanDirectory(new File("/a/b/ToDoSSS")); + } + + @Test + public void cleanDirectory_throws_IAE_if_argument_is_a_file() throws IOException { + File file = temporaryFolder.newFile(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("'" + file.getAbsolutePath() + "' is not a directory"); + + FileUtils.cleanDirectory(file); + } + + @Test + public void cleanDirectory_removes_directories_and_files_in_target_directory_but_not_target_directory() throws IOException { + Path target = temporaryFolder.newFolder().toPath(); + Path childFile1 = Files.createFile(target.resolve("file1.txt")); + Path childDir1 = Files.createDirectory(target.resolve("subDir1")); + Path childFile2 = Files.createFile(childDir1.resolve("file2.txt")); + Path childDir2 = Files.createDirectory(childDir1.resolve("subDir2")); + + assertThat(target).isDirectory(); + assertThat(childFile1).isRegularFile(); + assertThat(childDir1).isDirectory(); + assertThat(childFile2).isRegularFile(); + assertThat(childDir2).isDirectory(); + + // on supporting FileSystem, target will change if directory is recreated + Object targetKey = getFileKey(target); + + FileUtils.cleanDirectory(target.toFile()); + + assertThat(target).isDirectory(); + assertThat(childFile1).doesNotExist(); + assertThat(childDir1).doesNotExist(); + assertThat(childFile2).doesNotExist(); + assertThat(childDir2).doesNotExist(); + assertThat(getFileKey(target)).isEqualTo(targetKey); + } + + @Test + public void cleanDirectory_follows_symlink_to_target_directory() throws IOException { + Path target = temporaryFolder.newFolder().toPath(); + Path symToDir = Files.createSymbolicLink(temporaryFolder.newFolder().toPath().resolve("sym_to_dir"), target); + Path childFile1 = Files.createFile(target.resolve("file1.txt")); + Path childDir1 = Files.createDirectory(target.resolve("subDir1")); + Path childFile2 = Files.createFile(childDir1.resolve("file2.txt")); + Path childDir2 = Files.createDirectory(childDir1.resolve("subDir2")); + + assertThat(target).isDirectory(); + assertThat(symToDir).isSymbolicLink(); + assertThat(childFile1).isRegularFile(); + assertThat(childDir1).isDirectory(); + assertThat(childFile2).isRegularFile(); + assertThat(childDir2).isDirectory(); + + // on supporting FileSystem, target will change if directory is recreated + Object targetKey = getFileKey(target); + Object symLinkKey = getFileKey(symToDir); + + FileUtils.cleanDirectory(symToDir.toFile()); + + assertThat(target).isDirectory(); + assertThat(symToDir).isSymbolicLink(); + assertThat(childFile1).doesNotExist(); + assertThat(childDir1).doesNotExist(); + assertThat(childFile2).doesNotExist(); + assertThat(childDir2).doesNotExist(); + assertThat(getFileKey(target)).isEqualTo(targetKey); + assertThat(getFileKey(symToDir)).isEqualTo(symLinkKey); + } + + @Test + public void deleteQuietly_does_not_fail_if_argument_is_null() { + FileUtils.deleteQuietly(null); + } + + @Test + public void deleteQuietly_does_not_fail_if_file_does_not_exist() throws IOException { + File file = new File(temporaryFolder.newFolder(), "blablabl"); + assertThat(file).doesNotExist(); + + FileUtils.deleteQuietly(file); + } + + @Test + public void deleteQuietly_deletes_directory_and_content() throws IOException { + Path target = temporaryFolder.newFolder().toPath(); + Path childFile1 = Files.createFile(target.resolve("file1.txt")); + Path childDir1 = Files.createDirectory(target.resolve("subDir1")); + Path childFile2 = Files.createFile(childDir1.resolve("file2.txt")); + Path childDir2 = Files.createDirectory(childDir1.resolve("subDir2")); + + assertThat(target).isDirectory(); + assertThat(childFile1).isRegularFile(); + assertThat(childDir1).isDirectory(); + assertThat(childFile2).isRegularFile(); + assertThat(childDir2).isDirectory(); + + FileUtils.deleteQuietly(target.toFile()); + + assertThat(target).doesNotExist(); + assertThat(childFile1).doesNotExist(); + assertThat(childDir1).doesNotExist(); + assertThat(childFile2).doesNotExist(); + assertThat(childDir2).doesNotExist(); + } + + @Test + public void deleteQuietly_deletes_symbolicLink() throws IOException { + Path folder = temporaryFolder.newFolder().toPath(); + Path file1 = Files.createFile(folder.resolve("file1.txt")); + Path symLink = Files.createSymbolicLink(folder.resolve("link1"), file1); + + assertThat(file1).isRegularFile(); + assertThat(symLink).isSymbolicLink(); + + FileUtils.deleteQuietly(symLink.toFile()); + + assertThat(symLink).doesNotExist(); + assertThat(file1).isRegularFile(); + } + + @Test + public void deleteDirectory_throws_NPE_if_argument_is_null() throws IOException { + expectDirectoryCanNotBeNullNPE(); + + FileUtils.deleteDirectory(null); + } + + @Test + public void deleteDirectory_does_not_fail_if_file_does_not_exist() throws IOException { + File file = new File(temporaryFolder.newFolder(), "foo.d"); + + FileUtils.deleteDirectory(file); + } + + @Test + public void deleteDirectory_throws_IOE_if_argument_is_a_file() throws IOException { + File file = temporaryFolder.newFile(); + + expectedException.expect(IOException.class); + expectedException.expectMessage("Directory '" + file.getAbsolutePath() + "' is a file"); + + FileUtils.deleteDirectory(file); + } + + @Test + public void deleteDirectory_throws_IOE_if_file_is_symbolicLink() throws IOException { + Path folder = temporaryFolder.newFolder().toPath(); + Path file1 = Files.createFile(folder.resolve("file1.txt")); + Path symLink = Files.createSymbolicLink(folder.resolve("link1"), file1); + + assertThat(file1).isRegularFile(); + assertThat(symLink).isSymbolicLink(); + + expectedException.expect(IOException.class); + expectedException.expectMessage("Directory '" + symLink.toFile().getAbsolutePath() + "' is a symbolic link"); + + FileUtils.deleteDirectory(symLink.toFile()); + } + + @Test + public void deleteDirectory_deletes_directory_and_content() throws IOException { + Path target = temporaryFolder.newFolder().toPath(); + Path childFile1 = Files.createFile(target.resolve("file1.txt")); + Path childDir1 = Files.createDirectory(target.resolve("subDir1")); + Path childFile2 = Files.createFile(childDir1.resolve("file2.txt")); + Path childDir2 = Files.createDirectory(childDir1.resolve("subDir2")); + + assertThat(target).isDirectory(); + assertThat(childFile1).isRegularFile(); + assertThat(childDir1).isDirectory(); + assertThat(childFile2).isRegularFile(); + assertThat(childDir2).isDirectory(); + + FileUtils.deleteQuietly(target.toFile()); + + assertThat(target).doesNotExist(); + assertThat(childFile1).doesNotExist(); + assertThat(childDir1).doesNotExist(); + assertThat(childFile2).doesNotExist(); + assertThat(childDir2).doesNotExist(); + } + + private void expectDirectoryCanNotBeNullNPE() { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("Directory can not be null"); + } + + @CheckForNull + private static Object getFileKey(Path path) throws IOException { + BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); + return attrs.fileKey(); + } +} -- cgit v1.2.3 From 8b36b92c75be2da2d16e9d14e3fe2254f6dc4368 Mon Sep 17 00:00:00 2001 From: Sébastien Lesaint Date: Thu, 11 Feb 2016 14:07:01 +0100 Subject: SONAR-7125 use efficient delete dir code in core, batch and server use Java NIO rather than Common IO FileUtils --- .../java/org/sonar/server/app/EmbeddedTomcat.java | 5 ++-- .../java/org/sonar/server/app/TomcatContexts.java | 2 +- .../computation/queue/report/ReportFiles.java | 6 ++--- .../server/platform/DefaultServerFileSystem.java | 2 +- .../sonar/server/platform/RailsAppsDeployer.java | 2 +- .../org/sonar/server/plugins/PluginDownloader.java | 5 ++-- .../server/plugins/ServerPluginJarExploder.java | 8 +++---- .../server/plugins/ServerPluginRepository.java | 4 ++-- .../server/qualityprofile/QProfileCopier.java | 19 ++++++++------- .../batch/bootstrap/BatchPluginJarExploder.java | 4 +++- .../batch/bootstrap/GlobalTempFolderProvider.java | 27 +++++++++++----------- .../batch/cache/DefaultProjectCacheStatus.java | 11 ++++----- .../java/org/sonar/batch/index/CachesManager.java | 11 ++++----- .../org/sonar/batch/report/ReportPublisher.java | 25 ++++++++++---------- .../batch/scan/MutableProjectReactorProvider.java | 11 ++++----- .../org/sonar/core/util/DefaultHttpDownloader.java | 8 +++---- 16 files changed, 71 insertions(+), 79 deletions(-) (limited to 'server') diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java b/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java index 39b5d5c1e0a..432dbae8ff9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java +++ b/server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java @@ -24,11 +24,12 @@ import java.io.File; import org.apache.catalina.LifecycleException; import org.apache.catalina.core.StandardContext; import org.apache.catalina.startup.Tomcat; -import org.apache.commons.io.FileUtils; import org.sonar.api.utils.log.Loggers; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; +import static org.sonar.core.util.FileUtils.deleteQuietly; + class EmbeddedTomcat { private final Props props; @@ -97,7 +98,7 @@ class EmbeddedTomcat { Loggers.get(EmbeddedTomcat.class).error("Fail to stop web server", e); } } - FileUtils.deleteQuietly(tomcatBasedir()); + deleteQuietly(tomcatBasedir()); } void awaitTermination() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java index deece74787a..7ed8a009486 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java +++ b/server/sonar-server/src/main/java/org/sonar/server/app/TomcatContexts.java @@ -136,7 +136,7 @@ public class TomcatContexts { static class Fs { void createOrCleanupDir(File dir) throws IOException { FileUtils.forceMkdir(dir); - FileUtils.cleanDirectory(dir); + org.sonar.core.util.FileUtils.cleanDirectory(dir); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java index 255f1d61cbb..1bc74abf973 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/report/ReportFiles.java @@ -49,21 +49,21 @@ public class ReportFiles { try { FileUtils.copyInputStreamToFile(reportInput, file); } catch (Exception e) { - FileUtils.deleteQuietly(file); + org.sonar.core.util.FileUtils.deleteQuietly(file); IOUtils.closeQuietly(reportInput); throw new IllegalStateException(format("Fail to copy report to file: %s", file.getAbsolutePath()), e); } } public void deleteIfExists(String taskUuid) { - FileUtils.deleteQuietly(fileForUuid(taskUuid)); + org.sonar.core.util.FileUtils.deleteQuietly(fileForUuid(taskUuid)); } public void deleteAll() { File dir = reportDir(); if (dir.exists()) { try { - FileUtils.cleanDirectory(dir); + org.sonar.core.util.FileUtils.cleanDirectory(dir); } catch (Exception e) { throw new IllegalStateException(format("Fail to clean directory: %s", dir.getAbsolutePath()), e); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java index dc41d224733..176f533dbe3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java @@ -74,7 +74,7 @@ public class DefaultServerFileSystem implements ServerFileSystem, Startable { File deprecated = getDeprecatedPluginsDir(); try { FileUtils.forceMkdir(deprecated); - FileUtils.cleanDirectory(deprecated); + org.sonar.core.util.FileUtils.cleanDirectory(deprecated); } catch (IOException e) { throw new IllegalStateException("The following directory can not be created: " + deprecated.getAbsolutePath(), e); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java b/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java index b4f6391b30f..ee56ab6226d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/RailsAppsDeployer.java @@ -111,7 +111,7 @@ public class RailsAppsDeployer implements Startable { private void prepareDir(File appsDir) { if (appsDir.exists() && appsDir.isDirectory()) { try { - FileUtils.deleteDirectory(appsDir); + org.sonar.core.util.FileUtils.deleteDirectory(appsDir); } catch (IOException e) { throw new IllegalStateException("Fail to delete temp directory: " + appsDir, e); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java index c85905a927f..436e657efa4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/PluginDownloader.java @@ -42,14 +42,13 @@ import org.sonar.updatecenter.common.Version; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; -import static org.apache.commons.io.FileUtils.cleanDirectory; import static org.apache.commons.io.FileUtils.copyFile; import static org.apache.commons.io.FileUtils.copyFileToDirectory; -import static org.apache.commons.io.FileUtils.deleteQuietly; import static org.apache.commons.io.FileUtils.forceMkdir; import static org.apache.commons.io.FileUtils.toFile; import static org.apache.commons.lang.StringUtils.substringAfterLast; import static org.sonar.core.platform.PluginInfo.jarToPluginInfo; +import static org.sonar.core.util.FileUtils.deleteQuietly; /** * Downloads plugins from update center. Files are copied in the directory extensions/downloads and then @@ -95,7 +94,7 @@ public class PluginDownloader implements Startable { public void cancelDownloads() { try { if (downloadDir.exists()) { - cleanDirectory(downloadDir); + org.sonar.core.util.FileUtils.cleanDirectory(downloadDir); } } catch (IOException e) { throw new IllegalStateException("Fail to clean the plugin downloads directory: " + downloadDir, e); diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java index e29e063a6aa..db74246c80f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginJarExploder.java @@ -19,17 +19,15 @@ */ package org.sonar.server.plugins; +import java.io.File; import org.apache.commons.io.FileUtils; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.ZipUtils; import org.sonar.core.platform.ExplodedPlugin; -import org.sonar.core.platform.PluginJarExploder; import org.sonar.core.platform.PluginInfo; +import org.sonar.core.platform.PluginJarExploder; import org.sonar.server.platform.DefaultServerFileSystem; -import java.io.File; - -import static org.apache.commons.io.FileUtils.cleanDirectory; import static org.apache.commons.io.FileUtils.forceMkdir; @ServerSide @@ -51,7 +49,7 @@ public class ServerPluginJarExploder extends PluginJarExploder { File toDir = new File(fs.getDeployedPluginsDir(), pluginInfo.getKey()); try { forceMkdir(toDir); - cleanDirectory(toDir); + org.sonar.core.util.FileUtils.cleanDirectory(toDir); File jarSource = pluginInfo.getNonNullJarFile(); File jarTarget = new File(toDir, jarSource.getName()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java index 90f5d726e92..40bcc6b20dc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java +++ b/server/sonar-server/src/main/java/org/sonar/server/plugins/ServerPluginRepository.java @@ -53,7 +53,7 @@ import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Lists.newArrayList; import static java.lang.String.format; import static org.apache.commons.io.FileUtils.copyFile; -import static org.apache.commons.io.FileUtils.deleteQuietly; +import static org.sonar.core.util.FileUtils.deleteQuietly; import static org.apache.commons.io.FileUtils.moveFile; import static org.apache.commons.io.FileUtils.moveFileToDirectory; import static org.sonar.core.platform.PluginInfo.jarToPluginInfo; @@ -159,7 +159,7 @@ public class ServerPluginRepository implements PluginRepository, Startable { private void registerPluginInfo(PluginInfo info) { if (blacklistedPluginKeys.contains(info.getKey())) { LOG.warn("Plugin {} [{}] is blacklisted and is being uninstalled.", info.getName(), info.getKey()); - deleteQuietly(info.getNonNullJarFile()); + org.sonar.core.util.FileUtils.deleteQuietly(info.getNonNullJarFile()); return; } PluginInfo existing = pluginInfosByKeys.put(info.getKey(), info); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java index 8844f597751..621717a2d6c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileCopier.java @@ -19,15 +19,6 @@ */ package org.sonar.server.qualityprofile; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.server.ServerSide; -import org.sonar.api.utils.TempFolder; -import org.sonar.db.DbSession; -import org.sonar.db.qualityprofile.QualityProfileDto; -import org.sonar.db.DbClient; - import java.io.File; import java.io.IOException; import java.io.InputStreamReader; @@ -35,6 +26,14 @@ import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.nio.charset.StandardCharsets; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.server.ServerSide; +import org.sonar.api.utils.TempFolder; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.qualityprofile.QualityProfileDto; @ServerSide public class QProfileCopier { @@ -59,7 +58,7 @@ public class QProfileCopier { restore(backupFile, QProfileName.createFor(to.getLanguage(), to.getName())); return to; } finally { - FileUtils.deleteQuietly(backupFile); + org.sonar.core.util.FileUtils.deleteQuietly(backupFile); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarExploder.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarExploder.java index 3e8a4b3f6f4..a91a6b38cbc 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarExploder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchPluginJarExploder.java @@ -31,6 +31,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import static org.sonar.core.util.FileUtils.deleteQuietly; + @BatchSide public class BatchPluginJarExploder extends PluginJarExploder { @@ -70,7 +72,7 @@ public class BatchPluginJarExploder extends PluginJarExploder { } } finally { out.close(); - FileUtils.deleteQuietly(lockFile); + deleteQuietly(lockFile); } } return destDir; diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java index 78de896f011..2ea3bff55a3 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/GlobalTempFolderProvider.java @@ -19,19 +19,6 @@ */ package org.sonar.batch.bootstrap; -import org.picocontainer.ComponentLifecycle; - -import org.picocontainer.PicoContainer; -import org.picocontainer.injectors.ProviderAdapter; -import org.sonar.api.utils.System2; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.apache.commons.io.FileUtils; -import org.sonar.api.utils.TempFolder; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.CoreProperties; -import org.sonar.api.utils.internal.DefaultTempFolder; - import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -39,6 +26,18 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.util.concurrent.TimeUnit; +import org.apache.commons.lang.StringUtils; +import org.picocontainer.ComponentLifecycle; +import org.picocontainer.PicoContainer; +import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.api.CoreProperties; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.TempFolder; +import org.sonar.api.utils.internal.DefaultTempFolder; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +import static org.sonar.core.util.FileUtils.deleteQuietly; public class GlobalTempFolderProvider extends ProviderAdapter implements ComponentLifecycle { private static final Logger LOG = Loggers.get(GlobalTempFolderProvider.class); @@ -113,7 +112,7 @@ public class GlobalTempFolderProvider extends ProviderAdapter implements Compone if (Files.exists(path)) { try (DirectoryStream stream = Files.newDirectoryStream(path, new CleanFilter())) { for (Path p : stream) { - FileUtils.deleteQuietly(p.toFile()); + deleteQuietly(p.toFile()); } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/cache/DefaultProjectCacheStatus.java b/sonar-batch/src/main/java/org/sonar/batch/cache/DefaultProjectCacheStatus.java index 80aa01cde17..45baaecacc8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/cache/DefaultProjectCacheStatus.java +++ b/sonar-batch/src/main/java/org/sonar/batch/cache/DefaultProjectCacheStatus.java @@ -19,10 +19,6 @@ */ package org.sonar.batch.cache; -import org.apache.commons.io.FileUtils; - -import org.sonar.home.cache.PersistentCache; - import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -31,6 +27,9 @@ import java.io.ObjectOutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Date; +import org.sonar.home.cache.PersistentCache; + +import static org.sonar.core.util.FileUtils.deleteQuietly; public class DefaultProjectCacheStatus implements ProjectCacheStatus { private static final String STATUS_FILENAME = "cache-sync-status"; @@ -56,7 +55,7 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { @Override public void delete() { cache.clear(); - FileUtils.deleteQuietly(getStatusFilePath().toFile()); + deleteQuietly(getStatusFilePath().toFile()); } @Override @@ -70,7 +69,7 @@ public class DefaultProjectCacheStatus implements ProjectCacheStatus { return (Date) objInput.readObject(); } } catch (IOException | ClassNotFoundException e) { - FileUtils.deleteQuietly(p.toFile()); + deleteQuietly(p.toFile()); throw new IllegalStateException("Failed to read cache sync status", e); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java b/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java index 6700f8c0832..010375a84eb 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/CachesManager.java @@ -19,18 +19,17 @@ */ package org.sonar.batch.index; -import org.sonar.api.utils.TempFolder; - import com.persistit.Persistit; import com.persistit.exception.PersistitException; import com.persistit.logging.Slf4jAdapter; -import org.apache.commons.io.FileUtils; +import java.io.File; +import java.util.Properties; import org.picocontainer.Startable; import org.slf4j.LoggerFactory; import org.sonar.api.batch.BatchSide; +import org.sonar.api.utils.TempFolder; -import java.io.File; -import java.util.Properties; +import static org.sonar.core.util.FileUtils.deleteQuietly; /** * Factory of caches @@ -85,7 +84,7 @@ public class CachesManager implements Startable { throw new IllegalStateException("Fail to close caches", e); } } - FileUtils.deleteQuietly(tempDir); + deleteQuietly(tempDir); tempDir = null; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java index 35c747d11d3..5ab75c42f2a 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java +++ b/sonar-batch/src/main/java/org/sonar/batch/report/ReportPublisher.java @@ -23,6 +23,15 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Throwables; import com.google.common.io.Files; import com.squareup.okhttp.HttpUrl; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +import javax.annotation.Nullable; import org.apache.commons.io.FileUtils; import org.picocontainer.Startable; import org.sonar.api.CoreProperties; @@ -42,15 +51,7 @@ import org.sonarqube.ws.WsCe; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsResponse; -import javax.annotation.Nullable; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; -import java.util.Map; +import static org.sonar.core.util.FileUtils.deleteQuietly; @BatchSide public class ReportPublisher implements Startable { @@ -73,7 +74,7 @@ public class ReportPublisher implements Startable { private BatchReportWriter writer; public ReportPublisher(Settings settings, BatchWsClient wsClient, AnalysisContextReportPublisher contextPublisher, - ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) { + ImmutableProjectReactor projectReactor, DefaultAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers) { this.settings = settings; this.wsClient = wsClient; this.contextPublisher = contextPublisher; @@ -93,7 +94,7 @@ public class ReportPublisher implements Startable { @Override public void stop() { if (!settings.getBoolean(KEEP_REPORT_PROP_KEY) && !settings.getBoolean(VERBOSE_KEY)) { - FileUtils.deleteQuietly(reportDir); + deleteQuietly(reportDir); } else { LOG.info("Analysis report generated in " + reportDir); } @@ -174,7 +175,7 @@ public class ReportPublisher implements Startable { String effectiveKey = projectReactor.getRoot().getKeyWithBranch(); metadata.put("projectKey", effectiveKey); metadata.put("serverUrl", publicUrl()); - + URL dashboardUrl = HttpUrl.parse(publicUrl()).newBuilder() .addPathSegment("dashboard").addPathSegment("index").addPathSegment(effectiveKey) .build() diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java b/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java index ac101e62822..c3d34a23a30 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/MutableProjectReactorProvider.java @@ -19,13 +19,11 @@ */ package org.sonar.batch.scan; -import org.apache.commons.io.FileUtils; -import org.picocontainer.injectors.ProviderAdapter; -import org.sonar.api.batch.bootstrap.ProjectReactor; - import java.io.File; import java.io.IOException; -import java.nio.file.Files; +import org.picocontainer.injectors.ProviderAdapter; +import org.sonar.api.batch.bootstrap.ProjectReactor; +import org.sonar.core.util.FileUtils; public class MutableProjectReactorProvider extends ProviderAdapter { private ProjectReactor reactor = null; @@ -40,8 +38,7 @@ public class MutableProjectReactorProvider extends ProviderAdapter { private static void cleanDirectory(File dir) { try { - FileUtils.deleteDirectory(dir); - Files.createDirectories(dir.toPath()); + FileUtils.cleanDirectory(dir); } catch (IOException e) { throw new IllegalStateException("Failed to recreate working directory: " + dir.getAbsolutePath(), e); } diff --git a/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java b/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java index 5f6f9820844..a1572554d86 100644 --- a/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java +++ b/sonar-core/src/main/java/org/sonar/core/util/DefaultHttpDownloader.java @@ -29,7 +29,6 @@ import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import com.google.common.io.Files; import com.google.common.io.InputSupplier; - import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -44,11 +43,8 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.zip.GZIPInputStream; - import javax.annotation.Nullable; - import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.sonar.api.config.Settings; import org.sonar.api.platform.Server; @@ -56,6 +52,8 @@ import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.SonarException; import org.sonar.api.utils.log.Loggers; +import static org.sonar.core.util.FileUtils.deleteQuietly; + /** * This component downloads HTTP files * @@ -150,7 +148,7 @@ public class DefaultHttpDownloader extends HttpDownloader { try { Files.copy(downloader.newInputSupplier(uri, this.connectTimeout, this.readTimeout), toFile); } catch (IOException e) { - FileUtils.deleteQuietly(toFile); + deleteQuietly(toFile); throw failToDownload(uri, e); } } -- cgit v1.2.3 From 9e5166d40483c1dd7815edc76f91468c144ebbe3 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Fri, 12 Feb 2016 12:36:32 +0100 Subject: stabilize ProjectDrilldownTest --- .../ProjectDrilldownTest/should_display_measure_drilldown.html | 5 +++++ server/sonar-web/src/main/js/apps/drilldown/app.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'server') diff --git a/it/it-tests/src/test/resources/projectServices/ProjectDrilldownTest/should_display_measure_drilldown.html b/it/it-tests/src/test/resources/projectServices/ProjectDrilldownTest/should_display_measure_drilldown.html index 192440c454c..f39d6888a7f 100644 --- a/it/it-tests/src/test/resources/projectServices/ProjectDrilldownTest/should_display_measure_drilldown.html +++ b/it/it-tests/src/test/resources/projectServices/ProjectDrilldownTest/should_display_measure_drilldown.html @@ -18,6 +18,11 @@ css=a[data-key="project-drilldown-test-project:src/main/xoo/sample/Sample.xoo"] + + waitForElementPresent + css=a.js-drilldown-link.js-ready + + click css=a[data-key="project-drilldown-test-project:src/main/xoo/sample/Sample.xoo"] diff --git a/server/sonar-web/src/main/js/apps/drilldown/app.js b/server/sonar-web/src/main/js/apps/drilldown/app.js index fb8c35d9b99..f3262566647 100644 --- a/server/sonar-web/src/main/js/apps/drilldown/app.js +++ b/server/sonar-web/src/main/js/apps/drilldown/app.js @@ -38,7 +38,7 @@ var App = new Marionette.Application(), viewer.filterLinesByDate(window.drilldown.period, window.drilldown.periodName); }); } - }); + }).addClass('js-ready'); }; App.on('start', function (options) { -- cgit v1.2.3