IDEA-135257 (detect FS case-sensitivity mismatch)
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Thu, 22 Jan 2015 19:19:33 +0000 (20:19 +0100)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Thu, 22 Jan 2015 19:19:33 +0000 (20:19 +0100)
platform/platform-impl/src/com/intellij/ide/startup/impl/StartupManagerImpl.java
platform/platform-resources-en/src/messages/ApplicationBundle.properties
platform/util/src/com/intellij/openapi/util/io/FileUtil.java
platform/util/testSrc/com/intellij/openapi/util/io/FileUtilHeavyTest.java

index 58959c36d01b9eadd22595c59eae40153938438a..48c7df89a3adf34e71ced3b0d9a710eee2e99613 100644 (file)
@@ -17,6 +17,10 @@ package com.intellij.ide.startup.impl;
 
 import com.intellij.ide.caches.CacheUpdater;
 import com.intellij.ide.startup.StartupManagerEx;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
 import com.intellij.openapi.application.AccessToken;
 import com.intellij.openapi.application.Application;
 import com.intellij.openapi.application.ApplicationBundle;
@@ -30,6 +34,7 @@ import com.intellij.openapi.project.*;
 import com.intellij.openapi.project.impl.ProjectLifecycleListener;
 import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.startup.StartupActivity;
+import com.intellij.openapi.util.SystemInfo;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.vfs.LocalFileSystem;
@@ -46,6 +51,7 @@ import com.intellij.util.ui.UIUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.TestOnly;
 
+import java.io.FileNotFoundException;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
@@ -220,6 +226,7 @@ public class StartupManagerImpl extends StartupManagerEx {
 
         Application app = ApplicationManager.getApplication();
         if (!app.isHeadlessEnvironment()) {
+          checkFsSanity();
           checkProjectRoots();
           final long sessionId = VirtualFileManager.getInstance().asyncRefresh(null);
           final MessageBusConnection connection = app.getMessageBus().connect();
@@ -238,6 +245,25 @@ public class StartupManagerImpl extends StartupManagerEx {
     });
   }
 
+  private void checkFsSanity() {
+    try {
+      String path = myProject.getProjectFilePath();
+      boolean actual = FileUtil.isFileSystemCaseSensitive(path);
+      LOG.info(path + " case-sensitivity: " + actual);
+      if (actual != SystemInfo.isFileSystemCaseSensitive) {
+        int prefix = SystemInfo.isFileSystemCaseSensitive ? 1 : 0;  // IDE=true -> FS=false -> prefix='in'
+        String title = ApplicationBundle.message("fs.case.sensitivity.mismatch.title");
+        String text = ApplicationBundle.message("fs.case.sensitivity.mismatch.message", prefix);
+        Notifications.Bus.notify(
+          new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, title, text, NotificationType.WARNING, NotificationListener.URL_OPENING_LISTENER),
+          myProject);
+      }
+    }
+    catch (FileNotFoundException e) {
+      LOG.warn(e);
+    }
+  }
+
   private void checkProjectRoots() {
     LocalFileSystem fs = LocalFileSystem.getInstance();
     if (!(fs instanceof LocalFileSystemImpl)) return;
index adc5d40cd4f6d358da497e9f8b08a1d002210d80..c6d34afc36dfa8c3a387ab5c3ef864fc5c056dee 100644 (file)
@@ -597,6 +597,12 @@ watcher.failed.to.start=File watcher failed to start
 watcher.gave.up=File watcher gave up to operate
 watcher.non.watchable.project=Project files cannot be watched (are they under network mount?)
 
+fs.case.sensitivity.mismatch.title=Filesystem Case-Sensitivity Mismatch
+fs.case.sensitivity.mismatch.message=\
+  The project seems to be located on a case-{0,choice,0#|1#in}sensitive file system.<br> \
+  This doesn't match IDE settings. \
+  <a href="https://confluence.jetbrains.com/display/IDEADEV/Filesystem+Case-Sensitivity+Mismatch">More details.</a>
+
 arrangement.title.settings.tab=Arrangement
 arrangement.text.empty.rule=<empty rule>
 arrangement.text.type=Type
index 419c1bbfe14c30f95cb371fd6db1a82f2e75ec41..57e86a9fe3a4c7a3a98f38443b27b90b7c28ffb5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1545,7 +1545,7 @@ public class FileUtil extends FileUtilRt {
   }
 
   /**
-   * Like {@link Properties#load(java.io.Reader)}, but preserves the order of key/value pairs.
+   * Like {@link Properties#load(Reader)}, but preserves the order of key/value pairs.
    */
   @NotNull
   public static Map<String, String> loadProperties(@NotNull Reader reader) throws IOException {
@@ -1576,4 +1576,15 @@ public class FileUtil extends FileUtilRt {
     boolean success = file.renameTo(tempFileNameForDeletion);
     return delete(success ? tempFileNameForDeletion:file);
   }
+
+  public static boolean isFileSystemCaseSensitive(@NotNull String path) throws FileNotFoundException {
+    FileAttributes attributes = FileSystemUtil.getAttributes(path);
+    if (attributes == null) {
+      throw new FileNotFoundException(path);
+    }
+
+    FileAttributes upper = FileSystemUtil.getAttributes(path.toUpperCase(Locale.ENGLISH));
+    FileAttributes lower = FileSystemUtil.getAttributes(path.toLowerCase(Locale.ENGLISH));
+    return !(attributes.equals(upper) && attributes.equals(lower));
+  }
 }
index 0f667ad43f945cfda47f49d5c6eb0486cc419849..bd6c32bfb57e1327102ed5eb86e4650fb857897b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2015 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -227,4 +227,10 @@ public class FileUtilHeavyTest {
     FileUtil.delete(linkDir);
     assertEquals(1, targetDir.list().length);
   }
+
+  @Test
+  public void testCaseSensitivityDetection() throws IOException {
+    String path = myFindTestFirstFile.getPath();
+    assertEquals(SystemInfo.isFileSystemCaseSensitive, FileUtil.isFileSystemCaseSensitive(path));
+  }
 }