mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Import/Export SettingsAction in kotlin
This commit is contained in:
@@ -13,320 +13,255 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.actions
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
package com.intellij.ide.actions;
|
||||
import com.intellij.AbstractBundle
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.ide.IdeBundle
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.components.impl.ServiceManagerImpl
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager
|
||||
import com.intellij.openapi.components.impl.stores.StoreUtil
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.options.OptionsBundle
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.util.PairProcessor
|
||||
import com.intellij.util.PlatformUtils
|
||||
import com.intellij.util.ReflectionUtil
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.containers.MultiMap
|
||||
import com.intellij.util.io.ZipUtil
|
||||
import gnu.trove.THashSet
|
||||
|
||||
import com.intellij.AbstractBundle;
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor;
|
||||
import com.intellij.ide.plugins.PluginManager;
|
||||
import com.intellij.ide.plugins.PluginManagerCore;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl;
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.components.impl.ServiceManagerImpl;
|
||||
import com.intellij.openapi.components.impl.stores.StateStorageManager;
|
||||
import com.intellij.openapi.components.impl.stores.StoreUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.PluginDescriptor;
|
||||
import com.intellij.openapi.options.OptionsBundle;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.CharsetToolkit;
|
||||
import com.intellij.util.PairProcessor;
|
||||
import com.intellij.util.PlatformUtils;
|
||||
import com.intellij.util.ReflectionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.io.ZipUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
private class ExportSettingsAction : AnAction(), DumbAware {
|
||||
override fun actionPerformed(e: AnActionEvent?) {
|
||||
ApplicationManager.getApplication().saveSettings()
|
||||
|
||||
public class ExportSettingsAction extends AnAction implements DumbAware {
|
||||
private static final Logger LOG = Logger.getInstance(ExportSettingsAction.class);
|
||||
|
||||
@Override
|
||||
public void actionPerformed(@Nullable AnActionEvent e) {
|
||||
ApplicationManager.getApplication().saveSettings();
|
||||
|
||||
ChooseComponentsToExportDialog dialog = new ChooseComponentsToExportDialog(getExportableComponentsMap(true, true), true,
|
||||
IdeBundle.message("title.select.components.to.export"),
|
||||
IdeBundle.message(
|
||||
"prompt.please.check.all.components.to.export"));
|
||||
val dialog = ChooseComponentsToExportDialog(getExportableComponentsMap(true, true), true,
|
||||
IdeBundle.message("title.select.components.to.export"),
|
||||
IdeBundle.message(
|
||||
"prompt.please.check.all.components.to.export"))
|
||||
if (!dialog.showAndGet()) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
Set<ExportableComponent> markedComponents = dialog.getExportableComponents();
|
||||
val markedComponents = dialog.exportableComponents
|
||||
if (markedComponents.isEmpty()) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
Set<File> exportFiles = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
|
||||
for (ExportableComponent markedComponent : markedComponents) {
|
||||
ContainerUtil.addAll(exportFiles, markedComponent.getExportFiles());
|
||||
val exportFiles = THashSet(FileUtil.FILE_HASHING_STRATEGY)
|
||||
for (markedComponent in markedComponents) {
|
||||
ContainerUtil.addAll<File, File, Set<File>>(exportFiles, *markedComponent.exportFiles)
|
||||
}
|
||||
|
||||
final File saveFile = dialog.getExportFile();
|
||||
val saveFile = dialog.exportFile
|
||||
try {
|
||||
if (saveFile.exists() && Messages.showOkCancelDialog(
|
||||
IdeBundle.message("prompt.overwrite.settings.file", FileUtil.toSystemDependentName(saveFile.getPath())),
|
||||
IdeBundle.message("prompt.overwrite.settings.file", FileUtil.toSystemDependentName(saveFile.path)),
|
||||
IdeBundle.message("title.file.already.exists"), Messages.getWarningIcon()) != Messages.OK) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
MyZipOutputStream zipOut = new MyZipOutputStream(new BufferedOutputStream(new FileOutputStream(saveFile)));
|
||||
val zipOut = MyZipOutputStream(BufferedOutputStream(FileOutputStream(saveFile)))
|
||||
try {
|
||||
Set<String> writtenItemRelativePaths = new THashSet<String>();
|
||||
String configRoot = FileUtilRt.toSystemIndependentName(PathManager.getConfigPath());
|
||||
for (File file : exportFiles) {
|
||||
val writtenItemRelativePaths = THashSet<String>()
|
||||
val configRoot = FileUtilRt.toSystemIndependentName(PathManager.getConfigPath())
|
||||
for (file in exportFiles) {
|
||||
if (file.exists()) {
|
||||
String relativePath = FileUtilRt.getRelativePath(configRoot, FileUtilRt.toSystemIndependentName(file.getAbsolutePath()), '/');
|
||||
assert relativePath != null;
|
||||
ZipUtil.addFileOrDirRecursively(zipOut, null, file, relativePath, null, writtenItemRelativePaths);
|
||||
val relativePath = FileUtilRt.getRelativePath(configRoot, FileUtilRt.toSystemIndependentName(file.absolutePath), '/')!!
|
||||
ZipUtil.addFileOrDirRecursively(zipOut, null, file, relativePath, null, writtenItemRelativePaths)
|
||||
}
|
||||
}
|
||||
|
||||
exportInstalledPlugins(zipOut);
|
||||
exportInstalledPlugins(zipOut)
|
||||
|
||||
ZipEntry zipEntry = new ZipEntry(ImportSettingsFilenameFilter.SETTINGS_JAR_MARKER);
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
zipOut.closeEntry();
|
||||
val zipEntry = ZipEntry(ImportSettingsFilenameFilter.SETTINGS_JAR_MARKER)
|
||||
zipOut.putNextEntry(zipEntry)
|
||||
zipOut.closeEntry()
|
||||
}
|
||||
finally {
|
||||
zipOut.doClose();
|
||||
zipOut.doClose()
|
||||
}
|
||||
ShowFilePathAction.showDialog(getEventProject(e), IdeBundle.message("message.settings.exported.successfully"),
|
||||
IdeBundle.message("title.export.successful"), saveFile, null);
|
||||
ShowFilePathAction.showDialog(AnAction.getEventProject(e), IdeBundle.message("message.settings.exported.successfully"),
|
||||
IdeBundle.message("title.export.successful"), saveFile, null)
|
||||
}
|
||||
catch (IOException e1) {
|
||||
Messages.showErrorDialog(IdeBundle.message("error.writing.settings", e1.toString()), IdeBundle.message("title.error.writing.file"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void exportInstalledPlugins(@NotNull MyZipOutputStream zipOut) throws IOException {
|
||||
List<String> plugins = new ArrayList<String>();
|
||||
for (IdeaPluginDescriptor descriptor : PluginManagerCore.getPlugins()) {
|
||||
if (!descriptor.isBundled() && descriptor.isEnabled()) {
|
||||
plugins.add(descriptor.getPluginId().getIdString());
|
||||
}
|
||||
}
|
||||
if (plugins.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZipEntry e = new ZipEntry(PluginManager.INSTALLED_TXT);
|
||||
zipOut.putNextEntry(e);
|
||||
try {
|
||||
PluginManagerCore.writePluginsList(plugins, new OutputStreamWriter(zipOut, CharsetToolkit.UTF8_CHARSET));
|
||||
}
|
||||
finally {
|
||||
zipOut.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyZipOutputStream extends ZipOutputStream {
|
||||
private boolean ignoreClose = true;
|
||||
|
||||
public MyZipOutputStream(@NotNull OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (!ignoreClose) {
|
||||
doClose();
|
||||
}
|
||||
}
|
||||
|
||||
public void doClose() throws IOException {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MultiMap<File, ExportableComponent> getExportableComponentsMap(boolean onlyExisting, boolean computePresentableNames) {
|
||||
ApplicationImpl application = (ApplicationImpl)ApplicationManager.getApplication();
|
||||
StateStorageManager storageManager = ComponentsPackage.getStateStore(application).getStateStorageManager();
|
||||
return getExportableComponentsMap(onlyExisting, computePresentableNames, storageManager);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static MultiMap<File, ExportableComponent> getExportableComponentsMap(final boolean onlyExisting, final boolean computePresentableNames, final @NotNull StateStorageManager storageManager) {
|
||||
@SuppressWarnings("deprecation")
|
||||
List<ExportableApplicationComponent> components1 = ComponentsPackage.getComponents(ApplicationManager.getApplication(), ExportableApplicationComponent.class);
|
||||
List<ExportableComponent> components2 = ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent.class);
|
||||
final MultiMap<File, ExportableComponent> result = MultiMap.createLinkedSet();
|
||||
for (ExportableComponent component : ContainerUtil.concat(components1, components2)) {
|
||||
for (File exportFile : component.getExportFiles()) {
|
||||
result.putValue(exportFile, component);
|
||||
}
|
||||
}
|
||||
|
||||
if (onlyExisting) {
|
||||
for (Iterator<File> it = result.keySet().iterator(); it.hasNext(); ) {
|
||||
if (!it.next().exists()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServiceManagerImpl.processAllImplementationClasses((ApplicationImpl)ApplicationManager.getApplication(), new PairProcessor<Class<?>, PluginDescriptor>() {
|
||||
@Override
|
||||
public boolean process(@NotNull Class<?> aClass, @Nullable PluginDescriptor pluginDescriptor) {
|
||||
State stateAnnotation = StoreUtil.getStateSpec(aClass);
|
||||
if (stateAnnotation != null && !StringUtil.isEmpty(stateAnnotation.name())) {
|
||||
if (ExportableComponent.class.isAssignableFrom(aClass)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int storageIndex;
|
||||
Storage[] storages = stateAnnotation.storages();
|
||||
if (storages.length == 1) {
|
||||
storageIndex = 0;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
|
||||
Storage storage = storages[storageIndex];
|
||||
if (storage.roamingType() != RoamingType.DISABLED &&
|
||||
storage.storageClass().equals(StateStorage.class) &&
|
||||
storage.scheme() == StorageScheme.DEFAULT &&
|
||||
!StringUtil.isEmpty(storage.file()) &&
|
||||
storage.file().startsWith(StoragePathMacros.APP_CONFIG)) {
|
||||
|
||||
File additionalExportFile = null;
|
||||
if (!StringUtil.isEmpty(stateAnnotation.additionalExportFile())) {
|
||||
String expandedPath = storageManager.expandMacros(stateAnnotation.additionalExportFile());
|
||||
additionalExportFile = new File(expandedPath);
|
||||
if (!additionalExportFile.exists()) {
|
||||
//noinspection deprecation
|
||||
additionalExportFile = new File(storageManager.expandMacros(StoragePathMacros.ROOT_CONFIG) + '/' + expandedPath);
|
||||
}
|
||||
|
||||
if (onlyExisting && !additionalExportFile.exists()) {
|
||||
additionalExportFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
File file = new File(storageManager.expandMacros(storage.file()));
|
||||
boolean fileExists = !onlyExisting || file.exists();
|
||||
if (fileExists || additionalExportFile != null) {
|
||||
File[] files;
|
||||
if (additionalExportFile == null) {
|
||||
files = new File[]{file};
|
||||
}
|
||||
else {
|
||||
files = fileExists ? new File[]{file, additionalExportFile} : new File[]{additionalExportFile};
|
||||
}
|
||||
ExportableComponentItem item = new ExportableComponentItem(files,
|
||||
computePresentableNames
|
||||
? getComponentPresentableName(stateAnnotation, aClass, pluginDescriptor)
|
||||
: "",
|
||||
storage.roamingType());
|
||||
result.putValue(file, item);
|
||||
if (additionalExportFile != null) {
|
||||
result.putValue(additionalExportFile, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String getComponentPresentableName(@NotNull State state, @NotNull Class<?> aClass, @Nullable PluginDescriptor pluginDescriptor) {
|
||||
if (state.presentableName() != State.NameGetter.class) {
|
||||
try {
|
||||
return ReflectionUtil.newInstance(state.presentableName()).get();
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
String defaultName = state.name();
|
||||
String resourceBundleName;
|
||||
if (pluginDescriptor != null && pluginDescriptor instanceof IdeaPluginDescriptor && !"com.intellij".equals(pluginDescriptor.getPluginId().getIdString())) {
|
||||
resourceBundleName = ((IdeaPluginDescriptor)pluginDescriptor).getResourceBundleBaseName();
|
||||
}
|
||||
else {
|
||||
resourceBundleName = OptionsBundle.PATH_TO_BUNDLE;
|
||||
}
|
||||
|
||||
if (resourceBundleName == null) {
|
||||
return defaultName;
|
||||
}
|
||||
|
||||
ClassLoader classLoader = pluginDescriptor == null ? null : pluginDescriptor.getPluginClassLoader();
|
||||
classLoader = classLoader == null ? aClass.getClassLoader() : classLoader;
|
||||
if (classLoader != null) {
|
||||
String message = messageOrDefault(classLoader, resourceBundleName, defaultName);
|
||||
if (message != defaultName) {
|
||||
return message;
|
||||
}
|
||||
|
||||
if (PlatformUtils.isRubyMine()) {
|
||||
// ruby plugin in RubyMine has id "com.intellij", so, we cannot set "resource-bundle" in plugin.xml
|
||||
return messageOrDefault(classLoader, "org.jetbrains.plugins.ruby.RBundle", defaultName);
|
||||
}
|
||||
}
|
||||
return defaultName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String messageOrDefault(@NotNull ClassLoader classLoader, @NotNull String bundleName, @NotNull String defaultName) {
|
||||
ResourceBundle bundle = AbstractBundle.getResourceBundle(bundleName, classLoader);
|
||||
return bundle == null ? defaultName : CommonBundle.messageOrDefault(bundle, "exportable." + defaultName + ".presentable.name", defaultName);
|
||||
}
|
||||
|
||||
public static final class ExportableComponentItem implements ExportableComponent {
|
||||
private final File[] files;
|
||||
private final String name;
|
||||
private final RoamingType roamingType;
|
||||
|
||||
public ExportableComponentItem(@NotNull File[] files, @NotNull String name, @NotNull RoamingType roamingType) {
|
||||
this.files = files;
|
||||
this.name = name;
|
||||
this.roamingType = roamingType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public File[] getExportFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public RoamingType getRoamingType() {
|
||||
return roamingType;
|
||||
catch (e1: IOException) {
|
||||
Messages.showErrorDialog(IdeBundle.message("error.writing.settings", e1.toString()), IdeBundle.message("title.error.writing.file"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MyZipOutputStream(out: OutputStream) : ZipOutputStream(out) {
|
||||
override fun close() {
|
||||
}
|
||||
|
||||
fun doClose() {
|
||||
super.close()
|
||||
}
|
||||
}
|
||||
|
||||
class ExportableComponentItem(private val files: Array<File>, private val name: String, val roamingType: RoamingType) : ExportableComponent {
|
||||
override fun getExportFiles() = files
|
||||
|
||||
override fun getPresentableName() = name
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance(ExportSettingsAction::class.java)
|
||||
|
||||
private fun exportInstalledPlugins(zipOut: MyZipOutputStream) {
|
||||
val plugins = ArrayList<String>()
|
||||
for (descriptor in PluginManagerCore.getPlugins()) {
|
||||
if (!descriptor.isBundled && descriptor.isEnabled) {
|
||||
plugins.add(descriptor.pluginId.idString)
|
||||
}
|
||||
}
|
||||
if (plugins.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val e = ZipEntry(PluginManager.INSTALLED_TXT)
|
||||
zipOut.putNextEntry(e)
|
||||
try {
|
||||
PluginManagerCore.writePluginsList(plugins, OutputStreamWriter(zipOut, CharsetToolkit.UTF8_CHARSET))
|
||||
}
|
||||
finally {
|
||||
zipOut.closeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
fun getExportableComponentsMap(onlyExisting: Boolean, computePresentableNames: Boolean, storageManager: StateStorageManager = ApplicationManager.getApplication().stateStore.stateStorageManager): MultiMap<File, ExportableComponent> {
|
||||
val result = MultiMap.createLinkedSet<File, ExportableComponent>()
|
||||
val processor = { component: ExportableComponent ->
|
||||
for (exportFile in component.exportFiles) {
|
||||
result.putValue(exportFile, component)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATED_SYMBOL_WITH_MESSAGE")
|
||||
ApplicationManager.getApplication().getComponents(ExportableApplicationComponent::class.java).forEach(processor)
|
||||
ServiceBean.loadServicesFromBeans(ExportableComponent.EXTENSION_POINT, ExportableComponent::class.java).forEach(processor)
|
||||
|
||||
if (onlyExisting) {
|
||||
val it = result.keySet().iterator()
|
||||
while (it.hasNext()) {
|
||||
if (!it.next().exists()) {
|
||||
it.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServiceManagerImpl.processAllImplementationClasses(ApplicationManager.getApplication() as ApplicationImpl, object : PairProcessor<Class<*>, PluginDescriptor> {
|
||||
override fun process(aClass: Class<*>, pluginDescriptor: PluginDescriptor?): Boolean {
|
||||
val stateAnnotation = StoreUtil.getStateSpec(aClass)
|
||||
if (stateAnnotation != null && !StringUtil.isEmpty(stateAnnotation.name)) {
|
||||
if (ExportableComponent::class.java.isAssignableFrom(aClass)) {
|
||||
return true
|
||||
}
|
||||
|
||||
val storageIndex: Int
|
||||
val storages = stateAnnotation.storages
|
||||
if (storages.size() == 1) {
|
||||
storageIndex = 0
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
|
||||
val storage = storages[storageIndex]
|
||||
if (storage.roamingType != RoamingType.DISABLED && storage.storageClass == StateStorage::class.java && storage.scheme == StorageScheme.DEFAULT && !StringUtil.isEmpty(storage.file) && storage.file.startsWith(StoragePathMacros.APP_CONFIG)) {
|
||||
var additionalExportFile: File? = null
|
||||
if (!StringUtil.isEmpty(stateAnnotation.additionalExportFile)) {
|
||||
val expandedPath = storageManager.expandMacros(stateAnnotation.additionalExportFile)
|
||||
additionalExportFile = File(expandedPath)
|
||||
if (!additionalExportFile.exists()) {
|
||||
//noinspection deprecation
|
||||
additionalExportFile = File(storageManager.expandMacros(StoragePathMacros.ROOT_CONFIG) + '/' + expandedPath)
|
||||
}
|
||||
|
||||
if (onlyExisting && !additionalExportFile.exists()) {
|
||||
additionalExportFile = null
|
||||
}
|
||||
}
|
||||
|
||||
val file = File(storageManager.expandMacros(storage.file))
|
||||
val fileExists = !onlyExisting || file.exists()
|
||||
if (fileExists || additionalExportFile != null) {
|
||||
val files = if (additionalExportFile == null) {
|
||||
arrayOf(file)
|
||||
}
|
||||
else {
|
||||
if (fileExists) arrayOf(file, additionalExportFile) else arrayOf(additionalExportFile)
|
||||
}
|
||||
val item = ExportableComponentItem(files, if (computePresentableNames) getComponentPresentableName(stateAnnotation, aClass, pluginDescriptor) else "", storage.roamingType)
|
||||
result.putValue(file, item)
|
||||
if (additionalExportFile != null) {
|
||||
result.putValue(additionalExportFile, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getComponentPresentableName(state: State, aClass: Class<*>, pluginDescriptor: PluginDescriptor?): String {
|
||||
val presentableName = state.presentableName.java
|
||||
if (presentableName != State.NameGetter::class.java) {
|
||||
try {
|
||||
return ReflectionUtil.newInstance(presentableName).get()
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
val defaultName = state.name
|
||||
val resourceBundleName = (if (pluginDescriptor is IdeaPluginDescriptor && "com.intellij" != pluginDescriptor.pluginId.idString) {
|
||||
pluginDescriptor.resourceBundleBaseName
|
||||
}
|
||||
else {
|
||||
OptionsBundle.PATH_TO_BUNDLE
|
||||
}) ?: return defaultName
|
||||
|
||||
var classLoader = pluginDescriptor?.pluginClassLoader ?: aClass.classLoader
|
||||
if (classLoader != null) {
|
||||
val message = messageOrDefault(classLoader, resourceBundleName, defaultName)
|
||||
if (message !== defaultName) {
|
||||
return message
|
||||
}
|
||||
|
||||
if (PlatformUtils.isRubyMine()) {
|
||||
// ruby plugin in RubyMine has id "com.intellij", so, we cannot set "resource-bundle" in plugin.xml
|
||||
return messageOrDefault(classLoader, "org.jetbrains.plugins.ruby.RBundle", defaultName)
|
||||
}
|
||||
}
|
||||
return defaultName
|
||||
}
|
||||
|
||||
private fun messageOrDefault(classLoader: ClassLoader, bundleName: String, defaultName: String): String {
|
||||
val bundle = AbstractBundle.getResourceBundle(bundleName, classLoader) ?: return defaultName
|
||||
return CommonBundle.messageOrDefault(bundle, "exportable.$defaultName.presentable.name", defaultName)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,168 +13,141 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.actions
|
||||
|
||||
/**
|
||||
* @author cdr
|
||||
*/
|
||||
package com.intellij.ide.actions;
|
||||
import com.intellij.ide.IdeBundle
|
||||
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.actionSystem.PlatformDataKeys
|
||||
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.ExportableComponent
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.util.Consumer
|
||||
import gnu.trove.THashSet
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.zip.ZipException
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
import com.intellij.ide.IdeBundle;
|
||||
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.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
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.ExportableComponent;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class ImportSettingsAction extends AnAction implements DumbAware {
|
||||
@Override
|
||||
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||
final DataContext dataContext = e.getDataContext();
|
||||
final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext);
|
||||
ChooseComponentsToExportDialog.chooseSettingsFile(PathManager.getConfigPath(), component, IdeBundle.message("title.import.file.location"), IdeBundle.message("prompt.choose.import.file.path")).doWhenDone(new Consumer<String>() {
|
||||
@Override
|
||||
public void consume(String path) {
|
||||
File saveFile = new File(path);
|
||||
private class ImportSettingsAction : AnAction(), DumbAware {
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val dataContext = e.dataContext
|
||||
val component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext)
|
||||
ChooseComponentsToExportDialog.chooseSettingsFile(PathManager.getConfigPath(), component, IdeBundle.message("title.import.file.location"), IdeBundle.message("prompt.choose.import.file.path")).doWhenDone(object : Consumer<String> {
|
||||
override fun consume(path: String) {
|
||||
val saveFile = File(path)
|
||||
try {
|
||||
doImport(saveFile);
|
||||
doImport(saveFile)
|
||||
}
|
||||
catch (ZipException e1) {
|
||||
catch (e1: ZipException) {
|
||||
Messages.showErrorDialog(
|
||||
IdeBundle.message("error.reading.settings.file", presentableFileName(saveFile), e1.getMessage(), promptLocationMessage()),
|
||||
IdeBundle.message("title.invalid.file"));
|
||||
IdeBundle.message("title.invalid.file"))
|
||||
}
|
||||
catch (IOException e1) {
|
||||
catch (e1: IOException) {
|
||||
Messages.showErrorDialog(IdeBundle.message("error.reading.settings.file.2", presentableFileName(saveFile), e1.getMessage()),
|
||||
IdeBundle.message("title.error.reading.file"));
|
||||
IdeBundle.message("title.error.reading.file"))
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
private static void doImport(@NotNull File saveFile) throws IOException {
|
||||
private fun doImport(saveFile: File) {
|
||||
if (!saveFile.exists()) {
|
||||
Messages.showErrorDialog(IdeBundle.message("error.cannot.find.file", presentableFileName(saveFile)),
|
||||
IdeBundle.message("title.file.not.found"));
|
||||
return;
|
||||
IdeBundle.message("title.file.not.found"))
|
||||
return
|
||||
}
|
||||
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
final ZipEntry magicEntry = new ZipFile(saveFile).getEntry(ImportSettingsFilenameFilter.SETTINGS_JAR_MARKER);
|
||||
val magicEntry = ZipFile(saveFile).getEntry(ImportSettingsFilenameFilter.SETTINGS_JAR_MARKER)
|
||||
if (magicEntry == null) {
|
||||
Messages.showErrorDialog(
|
||||
IdeBundle.message("error.file.contains.no.settings.to.import", presentableFileName(saveFile), promptLocationMessage()),
|
||||
IdeBundle.message("title.invalid.file"));
|
||||
return;
|
||||
IdeBundle.message("title.invalid.file"))
|
||||
return
|
||||
}
|
||||
|
||||
MultiMap<File, ExportableComponent> fileToComponents = ExportSettingsAction.getExportableComponentsMap(false, true);
|
||||
List<ExportableComponent> components = getComponentsStored(saveFile, fileToComponents.values());
|
||||
fileToComponents.values().retainAll(components);
|
||||
final ChooseComponentsToExportDialog dialog = new ChooseComponentsToExportDialog(fileToComponents, false,
|
||||
IdeBundle.message("title.select.components.to.import"),
|
||||
IdeBundle.message("prompt.check.components.to.import"));
|
||||
val fileToComponents = getExportableComponentsMap(false, true)
|
||||
val components = getComponentsStored(saveFile, fileToComponents.values())
|
||||
fileToComponents.values().retainAll(components)
|
||||
val dialog = ChooseComponentsToExportDialog(fileToComponents, false,
|
||||
IdeBundle.message("title.select.components.to.import"),
|
||||
IdeBundle.message("prompt.check.components.to.import"))
|
||||
if (!dialog.showAndGet()) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
final Set<ExportableComponent> chosenComponents = dialog.getExportableComponents();
|
||||
Set<String> relativeNamesToExtract = new THashSet<String>();
|
||||
for (ExportableComponent chosenComponent : chosenComponents) {
|
||||
for (File exportFile : chosenComponent.getExportFiles()) {
|
||||
String rPath = FileUtilRt.getRelativePath(new File(PathManager.getConfigPath()), exportFile);
|
||||
assert rPath != null;
|
||||
relativeNamesToExtract.add(FileUtil.toSystemIndependentName(rPath));
|
||||
val chosenComponents = dialog.exportableComponents
|
||||
val relativeNamesToExtract = THashSet<String>()
|
||||
for (chosenComponent in chosenComponents) {
|
||||
for (exportFile in chosenComponent.exportFiles) {
|
||||
relativeNamesToExtract.add(FileUtil.toSystemIndependentName(FileUtilRt.getRelativePath(File(PathManager.getConfigPath()), exportFile)!!))
|
||||
}
|
||||
}
|
||||
|
||||
relativeNamesToExtract.add(PluginManager.INSTALLED_TXT);
|
||||
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.addActionCommand(new StartupActionScriptManager.UnzipCommand(tempFile, outDir, filenameFilter));
|
||||
val tempFile = File(PathManager.getPluginTempPath(), saveFile.name)
|
||||
FileUtil.copy(saveFile, tempFile)
|
||||
val outDir = File(PathManager.getConfigPath())
|
||||
val filenameFilter = ImportSettingsFilenameFilter(relativeNamesToExtract)
|
||||
StartupActionScriptManager.addActionCommand(StartupActionScriptManager.UnzipCommand(tempFile, outDir, filenameFilter))
|
||||
// remove temp file
|
||||
StartupActionScriptManager.addActionCommand(new StartupActionScriptManager.DeleteCommand(tempFile));
|
||||
StartupActionScriptManager.addActionCommand(StartupActionScriptManager.DeleteCommand(tempFile))
|
||||
|
||||
UpdateSettings.getInstance().forceCheckForUpdateAfterRestart();
|
||||
UpdateSettings.getInstance().forceCheckForUpdateAfterRestart()
|
||||
|
||||
String key = ApplicationManager.getApplication().isRestartCapable()
|
||||
? "message.settings.imported.successfully.restart"
|
||||
: "message.settings.imported.successfully";
|
||||
val key = if (ApplicationManager.getApplication().isRestartCapable)
|
||||
"message.settings.imported.successfully.restart"
|
||||
else
|
||||
"message.settings.imported.successfully"
|
||||
if (Messages.showOkCancelDialog(IdeBundle.message(key,
|
||||
ApplicationNamesInfo.getInstance().getProductName(),
|
||||
ApplicationNamesInfo.getInstance().getFullProductName()),
|
||||
IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon()) == Messages.OK) {
|
||||
((ApplicationEx)ApplicationManager.getApplication()).restart(true);
|
||||
ApplicationNamesInfo.getInstance().productName,
|
||||
ApplicationNamesInfo.getInstance().fullProductName),
|
||||
IdeBundle.message("title.restart.needed"), Messages.getQuestionIcon()) == Messages.OK) {
|
||||
(ApplicationManager.getApplication() as ApplicationEx).restart(true)
|
||||
}
|
||||
}
|
||||
|
||||
private static String presentableFileName(@NotNull File file) {
|
||||
return "'" + FileUtil.toSystemDependentName(file.getPath()) + "'";
|
||||
}
|
||||
private fun presentableFileName(file: File) = "'" + FileUtil.toSystemDependentName(file.path) + "'"
|
||||
|
||||
private static String promptLocationMessage() {
|
||||
return IdeBundle.message("message.please.ensure.correct.settings");
|
||||
}
|
||||
private fun promptLocationMessage() = IdeBundle.message("message.please.ensure.correct.settings")
|
||||
|
||||
@NotNull
|
||||
private static List<ExportableComponent> getComponentsStored(@NotNull File settings,
|
||||
@NotNull Collection<? extends ExportableComponent> registeredComponents) throws IOException {
|
||||
THashSet<String> zipEntries = new THashSet<String>();
|
||||
ZipFile zip = new ZipFile(settings);
|
||||
try {
|
||||
Enumeration enumeration = zip.entries();
|
||||
private fun getComponentsStored(settings: File, registeredComponents: Collection<ExportableComponent>): List<ExportableComponent> {
|
||||
val zipEntries = THashSet<String>()
|
||||
ZipFile(settings).use {
|
||||
val enumeration = it.entries()
|
||||
while (enumeration.hasMoreElements()) {
|
||||
ZipEntry zipEntry = (ZipEntry)enumeration.nextElement();
|
||||
zipEntries.add(zipEntry.getName());
|
||||
zipEntries.add(enumeration.nextElement().name)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
zip.close();
|
||||
}
|
||||
|
||||
File configPath = new File(PathManager.getConfigPath());
|
||||
List<ExportableComponent> components = new ArrayList<ExportableComponent>();
|
||||
|
||||
for (ExportableComponent component : registeredComponents) {
|
||||
for (File exportFile : component.getExportFiles()) {
|
||||
String relativePath = FileUtilRt.getRelativePath(configPath, exportFile);
|
||||
assert relativePath != null;
|
||||
relativePath = FileUtilRt.toSystemIndependentName(relativePath);
|
||||
if (exportFile.getName().indexOf('.') == -1 && !exportFile.isFile()) {
|
||||
relativePath += '/';
|
||||
val configPath = File(PathManager.getConfigPath())
|
||||
val components = ArrayList<ExportableComponent>()
|
||||
for (component in registeredComponents) {
|
||||
for (exportFile in component.exportFiles) {
|
||||
var relativePath = FileUtilRt.getRelativePath(configPath, exportFile)!!
|
||||
relativePath = FileUtilRt.toSystemIndependentName(relativePath)
|
||||
if (exportFile.name.indexOf('.') == -1 && !exportFile.isFile) {
|
||||
relativePath += '/'
|
||||
}
|
||||
if (zipEntries.contains(relativePath)) {
|
||||
components.add(component);
|
||||
break;
|
||||
components.add(component)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return components;
|
||||
return components
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ package org.jetbrains.settingsRepository
|
||||
|
||||
import com.intellij.configurationStore.ROOT_CONFIG
|
||||
import com.intellij.configurationStore.StateStorageManagerImpl
|
||||
import com.intellij.ide.actions.ExportSettingsAction
|
||||
import com.intellij.ide.actions.ExportableComponentItem
|
||||
import com.intellij.ide.actions.getExportableComponentsMap
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
@@ -27,7 +28,7 @@ import java.io.File
|
||||
fun copyLocalConfig(storageManager: StateStorageManagerImpl = ApplicationManager.getApplication()!!.stateStore.stateStorageManager as StateStorageManagerImpl) {
|
||||
val streamProvider = storageManager.streamProvider!! as IcsManager.IcsStreamProvider
|
||||
|
||||
val fileToComponents = ExportSettingsAction.getExportableComponentsMap(true, false, storageManager)
|
||||
val fileToComponents = getExportableComponentsMap(true, false, storageManager)
|
||||
for (file in fileToComponents.keySet()) {
|
||||
val absolutePath = FileUtilRt.toSystemIndependentName(file.absolutePath)
|
||||
var fileSpec = storageManager.collapseMacros(absolutePath)
|
||||
@@ -69,7 +70,7 @@ private fun saveDirectory(parent: File, parentFileSpec: String, roamingType: Roa
|
||||
|
||||
private fun getRoamingType(components: Collection<ExportableComponent>): RoamingType {
|
||||
for (component in components) {
|
||||
if (component is ExportSettingsAction.ExportableComponentItem) {
|
||||
if (component is ExportableComponentItem) {
|
||||
return component.roamingType
|
||||
}
|
||||
else if (component is PersistentStateComponent<*>) {
|
||||
|
||||
Reference in New Issue
Block a user