Add a feature to import a specified settings jar.

Change-Id: Idfa2a80d4a57ef5a26228363a7ce7a9286ae3942
diff --git a/google-cloud-tools.iml b/google-cloud-tools.iml
index 9126f4b..6d1ab7c 100644
--- a/google-cloud-tools.iml
+++ b/google-cloud-tools.iml
@@ -54,6 +54,7 @@
       </library>
     </orderEntry>
     <orderEntry type="module" module-name="google-login" />
+    <orderEntry type="module" module-name="bootstrap" />
   </component>
 </module>
 
diff --git a/src/com/google/gct/idea/settings/ImportSettings.java b/src/com/google/gct/idea/settings/ImportSettings.java
new file mode 100644
index 0000000..a509fc6
--- /dev/null
+++ b/src/com/google/gct/idea/settings/ImportSettings.java
@@ -0,0 +1,137 @@
+package com.google.gct.idea.settings;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.actions.ImportSettingsFilenameFilter;
+import com.intellij.ide.plugins.PluginManager;
+import com.intellij.ide.startup.StartupActionScriptManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ApplicationNamesInfo;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.ex.ApplicationEx;
+import com.intellij.openapi.components.ExportableApplicationComponent;
+import com.intellij.openapi.components.ExportableComponent;
+import com.intellij.openapi.components.ServiceBean;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.updateSettings.impl.UpdateSettings;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.io.ZipUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Provides functionality to update IDEA setting from a jar containing new settings
+ */
+public class ImportSettings {
+  private static final String DIALOG_TITLE = "Setting Synchronization";
+  public static final String SETTINGS_JAR_MARKER = "IntelliJ IDEA Global Settings";
+
+  /**
+   * Parse and update the IDEA settings in the jar at <code>path</code>.
+   * Note: This function might require a restart of the application.
+   * @param path The location of the jar with the new IDEA settings.
+   */
+  public static void doImport(String path) {
+    final File saveFile = new File(path);
+    try {
+      if (!saveFile.exists()) {
+        Messages.showErrorDialog(IdeBundle.message("error.cannot.find.file", presentableFileName(saveFile)), DIALOG_TITLE);
+        return;
+      }
+
+      // What is this file used for?
+      final ZipEntry magicEntry = new ZipFile(saveFile).getEntry(SETTINGS_JAR_MARKER);
+      if (magicEntry == null) {
+        Messages.showErrorDialog("The file " + presentableFileName(saveFile) + " contains no settings to import",
+          DIALOG_TITLE);
+        return;
+      }
+
+      final ArrayList<ExportableComponent> registeredComponents = new ArrayList<ExportableComponent>(
+        Arrays.asList(ApplicationManager.getApplication().getComponents(ExportableApplicationComponent.class)));
+      registeredComponents.addAll(ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class));
+
+      List<ExportableComponent> storedComponents = getComponentsStored(saveFile, registeredComponents);
+
+      Set<String> relativeNamesToExtract = new HashSet<String>();
+      for (final ExportableComponent aComponent : storedComponents) {
+        final File[] exportFiles = aComponent.getExportFiles();
+        for (File exportFile : exportFiles) {
+          final File configPath = new File(PathManager.getConfigPath());
+          final String rPath = FileUtil.getRelativePath(configPath, exportFile);
+          assert rPath != null;
+          final String relativePath = FileUtil.toSystemIndependentName(rPath);
+          relativeNamesToExtract.add(relativePath);
+        }
+      }
+
+      relativeNamesToExtract.add(PluginManager.INSTALLED_TXT);
+
+      final File tempFile = new File(PathManager.getPluginTempPath() + "/" + saveFile.getName());
+      FileUtil.copy(saveFile, tempFile);
+      File outDir = new File(PathManager.getConfigPath());
+      final ImportSettingsFilenameFilter filenameFilter = new ImportSettingsFilenameFilter(relativeNamesToExtract);
+      StartupActionScriptManager.ActionCommand unzip = new StartupActionScriptManager.UnzipCommand(tempFile, outDir, filenameFilter);
+      StartupActionScriptManager.addActionCommand(unzip);
+
+      // remove temp file
+      StartupActionScriptManager.ActionCommand deleteTemp = new StartupActionScriptManager.DeleteCommand(tempFile);
+      StartupActionScriptManager.addActionCommand(deleteTemp);
+
+      UpdateSettings.getInstance().forceCheckForUpdateAfterRestart();
+
+      String key = ApplicationManager.getApplication().isRestartCapable()
+                   ? "message.settings.imported.successfully.restart"
+                   : "message.settings.imported.successfully";
+      final int ret = Messages.showOkCancelDialog(IdeBundle.message(key,
+                                                                    ApplicationNamesInfo.getInstance().getProductName(),
+                                                                    ApplicationNamesInfo.getInstance().getFullProductName()),
+                                                  IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon());
+      if (ret == Messages.OK) {
+        ((ApplicationEx)ApplicationManager.getApplication()).restart(true);
+      }
+    }
+    catch (ZipException e1) {
+      Messages.showErrorDialog(
+        "Error reading file " + presentableFileName(saveFile) + ".\\nThere was " + e1.getMessage(),
+        DIALOG_TITLE);
+    }
+    catch (IOException e1) {
+      Messages.showErrorDialog(IdeBundle.message("error.reading.settings.file.2", presentableFileName(saveFile), e1.getMessage()),
+                               DIALOG_TITLE);
+    }
+  }
+
+  private static String presentableFileName(final File file) {
+    return "'" + FileUtil.toSystemDependentName(file.getPath()) + "'";
+  }
+
+  private static List<ExportableComponent> getComponentsStored(File zipFile,
+    ArrayList<ExportableComponent> registeredComponents)
+    throws IOException {
+    final File configPath = new File(PathManager.getConfigPath());
+
+    final ArrayList<ExportableComponent> components = new ArrayList<ExportableComponent>();
+    for (ExportableComponent component : registeredComponents) {
+      final File[] exportFiles = component.getExportFiles();
+      for (File exportFile : exportFiles) {
+        final String rPath = FileUtil.getRelativePath(configPath, exportFile);
+        assert rPath != null;
+        String relativePath = FileUtil.toSystemIndependentName(rPath);
+        if (exportFile.isDirectory()) relativePath += "/";
+        if (ZipUtil.isZipContainsEntry(zipFile, relativePath)) {
+          components.add(component);
+          break;
+        }
+      }
+    }
+    return components;
+  }
+}