Ignore .DS_Store files on macOS

Finder creates these files if you browse a directory there. These files
are really annoying, but it's an incredible pain for users that these
files are created unbeknownst to them, and then they get in the way of
Elasticsearch starting. This commit adds leniency on macOS only to skip
these files.

Relates #27108
This commit is contained in:
Jason Tedor 2017-10-25 11:25:29 -04:00 committed by GitHub
parent 149e558dd5
commit 6722b9c4a2
6 changed files with 85 additions and 0 deletions

View File

@ -21,6 +21,7 @@ package org.elasticsearch.bootstrap;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Platforms;
import org.elasticsearch.plugins.PluginInfo;
@ -73,6 +74,9 @@ final class Spawner implements Closeable {
*/
try (DirectoryStream<Path> stream = Files.newDirectoryStream(pluginsFile)) {
for (final Path plugin : stream) {
if (FileSystemUtils.isDesktopServicesStore(plugin)) {
continue;
}
final PluginInfo info = PluginInfo.readFromProperties(plugin);
final Path spawnPath = Platforms.nativeControllerPath(plugin);
if (!Files.isRegularFile(spawnPath)) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.common.io;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.IOUtils;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
@ -65,6 +66,16 @@ public final class FileSystemUtils {
return fileName.toString().startsWith(".");
}
/**
* Check whether the file denoted by the given path is a desktop services store created by Finder on macOS.
*
* @param path the path
* @return true if the current system is macOS and the specified file appears to be a desktop services store file
*/
public static boolean isDesktopServicesStore(final Path path) {
return Constants.MAC_OS_X && Files.isRegularFile(path) && ".DS_Store".equals(path.getFileName().toString());
}
/**
* Appends the path to the given base and strips N elements off the path if strip is &gt; 0.
*/

View File

@ -34,6 +34,7 @@ import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.io.FileSystemUtils;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
@ -326,6 +327,9 @@ public class PluginsService extends AbstractComponent {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(pluginsDirectory)) {
for (Path plugin : stream) {
if (FileSystemUtils.isDesktopServicesStore(plugin)) {
continue;
}
logger.trace("--- adding plugin [{}]", plugin.toAbsolutePath());
final PluginInfo info;
try {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.common.io;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.LuceneTestCase.SuppressFileSystems;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
@ -34,6 +35,8 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import static org.hamcrest.Matchers.equalTo;
/**
* Unit tests for {@link org.elasticsearch.common.io.FileSystemUtils}.
*/
@ -137,4 +140,16 @@ public class FileSystemUtilsTests extends ESTestCase {
assertArrayEquals(expectedBytes, actualBytes);
}
}
public void testIsDesktopServicesStoreFile() throws IOException {
final Path path = createTempDir();
final Path desktopServicesStore = path.resolve(".DS_Store");
Files.createFile(desktopServicesStore);
assertThat(FileSystemUtils.isDesktopServicesStore(desktopServicesStore), equalTo(Constants.MAC_OS_X));
Files.delete(desktopServicesStore);
Files.createDirectory(desktopServicesStore);
assertFalse(FileSystemUtils.isDesktopServicesStore(desktopServicesStore));
}
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.plugins;
import org.apache.lucene.util.Constants;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.Version;
import org.elasticsearch.common.settings.Settings;
@ -27,6 +28,7 @@ import org.elasticsearch.index.IndexModule;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.nio.file.FileSystemException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
@ -36,6 +38,7 @@ import java.util.Locale;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasToString;
import static org.hamcrest.Matchers.instanceOf;
@LuceneTestCase.SuppressFileSystems(value = "ExtrasFS")
public class PluginsServiceTests extends ESTestCase {
@ -124,6 +127,28 @@ public class PluginsServiceTests extends ESTestCase {
assertThat(e, hasToString(containsString(expected)));
}
public void testDesktopServicesStoreFiles() throws IOException {
final Path home = createTempDir();
final Settings settings =
Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), home)
.build();
final Path plugins = home.resolve("plugins");
Files.createDirectories(plugins);
final Path desktopServicesStore = plugins.resolve(".DS_Store");
Files.createFile(desktopServicesStore);
if (Constants.MAC_OS_X) {
@SuppressWarnings("unchecked") final PluginsService pluginsService = newPluginsService(settings);
assertNotNull(pluginsService);
} else {
final IllegalStateException e = expectThrows(IllegalStateException.class, () -> newPluginsService(settings));
assertThat(e, hasToString(containsString("Could not load plugin descriptor for existing plugin [.DS_Store]")));
assertNotNull(e.getCause());
assertThat(e.getCause(), instanceOf(FileSystemException.class));
assertThat(e.getCause(), hasToString(containsString("Not a directory")));
}
}
public void testStartupWithRemovingMarker() throws IOException {
final Path home = createTempDir();
final Settings settings =

View File

@ -31,6 +31,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystemException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFileAttributeView;
@ -40,8 +41,10 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.hasToString;
/**
* Create a simple "daemon controller", put it in the right place and check that it runs.
@ -189,6 +192,29 @@ public class SpawnerNoBootstrapTests extends LuceneTestCase {
equalTo("plugin [test_plugin] does not have permission to fork native controller"));
}
public void testSpawnerHandlingOfDesktopServicesStoreFiles() throws IOException {
final Path esHome = createTempDir().resolve("home");
final Settings settings = Settings.builder().put(Environment.PATH_HOME_SETTING.getKey(), esHome.toString()).build();
final Environment environment = new Environment(settings);
Files.createDirectories(environment.pluginsFile());
final Path desktopServicesStore = environment.pluginsFile().resolve(".DS_Store");
Files.createFile(desktopServicesStore);
final Spawner spawner = new Spawner();
if (Constants.MAC_OS_X) {
// if the spawner were not skipping the Desktop Services Store files on macOS this would explode
spawner.spawnNativePluginControllers(environment);
} else {
// we do not ignore these files on non-macOS systems
final FileSystemException e =
expectThrows(FileSystemException.class, () -> spawner.spawnNativePluginControllers(environment));
assertThat(e, hasToString(containsString("Not a directory")));
}
}
private void createControllerProgram(final Path outputFile) throws IOException {
final Path outputDir = outputFile.getParent();
Files.createDirectories(outputDir);