Skip to content

Instantly share code, notes, and snippets.

@tansautn
Created November 27, 2024 01:17
Show Gist options
  • Save tansautn/f492582b50cf176862635a2b05e7ebfd to your computer and use it in GitHub Desktop.
Save tansautn/f492582b50cf176862635a2b05e7ebfd to your computer and use it in GitHub Desktop.
Jet Brains IDEA plugins list exporter/importer

JetBrains IDEA Plugins Export/Import

These scripts can help you on export installed plugins. Or Install list of exported plugins to target IDEA.

Author: Zuko

Exporter

// Get non-bundled plugins
        import com.intellij.ide.plugins.PluginManagerCore
        def plugins = PluginManagerCore.getPlugins()
            .findAll {{ !it.isBundled }}
            .collect {{ plugin ->
                [
                    id: plugin.pluginId.idString,
                    name: plugin.name,
                    version: plugin.version,
                    description: plugin.description,
                    isEnabled: !plugin.isEnabled
                ]
            }}

        // Get product info
        def appInfo = com.intellij.openapi.application.ApplicationInfo.getInstance()
        def outputFile = new File("{output_file.replace(backslash_char, '/')}")
        println("Writing to: ${{outputFile.absolutePath}}")

        // Write the JSON
        import groovy.json.JsonBuilder
        outputFile.text = new JsonBuilder([
            metadata: [
                product: "{installation['name']}",
                version: appInfo.fullVersion,
                buildNumber: appInfo.build.toString(),
                exportDate: new Date().toString()
            ],
            plugins: plugins
        ]).toPrettyString()

        println("Export completed to: ${{outputFile.absolutePath}}")

How to use

  • Open your IDE.
  • Press double Shift (Search Everywhere)
  • Typing console then select the IDE Scripting Console
  • Paste code above
  • Select All
  • Press Ctrl + Enter
  • Check console to get output file name

Importer

I also created a python helper to install plugins to target IDEA from list exported plugins

Script content:

import os
import json
import subprocess
import argparse
from datetime import datetime
from pathlib import Path
import re


class JetBrainsPluginManager:
    def __init__(self):
        self.program_files = os.environ.get('PROGRAMFILES', 'C:\\Program Files')
        self.jetbrains_dir = os.path.join(self.program_files, 'JetBrains')
        self.desktop = os.path.join(os.path.expanduser('~'), 'Desktop')
    
    def find_product_installations(self, product_name = None):
        """Find all JetBrains product installations or specific product if name provided"""
        installations = []
        
        if not os.path.exists(self.jetbrains_dir):
            return installations
        
        for item in os.listdir(self.jetbrains_dir):
            item_path = os.path.join(self.jetbrains_dir, item)
            if os.path.isdir(item_path):
                # Extract product info from directory name
                match = re.match(r'(.*?)\s*(\d{4}\.\d+)', item)
                if match:
                    prod_name, version = match.groups()
                    if product_name is None or product_name.lower() in prod_name.lower():
                        bin_dir = os.path.join(item_path, 'bin')
                        if os.path.exists(bin_dir):
                            installations.append({
                                'name': prod_name.strip(),
                                'version': version,
                                'path': item_path,
                                'bin': bin_dir
                            })
        
        return sorted(installations, key=lambda x: x['version'], reverse=True)
    
    def get_exe_path(self, installation):
        """Get the appropriate executable path based on product"""
        exe_mappings = {
            'IntelliJ IDEA': 'idea64.exe',
            'PyCharm': 'pycharm64.exe',
            'WebStorm': 'webstorm64.exe',
            'PhpStorm': 'phpstorm64.exe',
            'Rider': 'rider64.exe',
            'CLion': 'clion64.exe',
            'GoLand': 'goland64.exe',
            'RubyMine': 'rubymine64.exe'
        }
        
        exe_name = exe_mappings.get(installation['name'], 'idea64.exe')
        return os.path.join(installation['bin'], exe_name)
    
    def export_plugins(self, installation, output_file = None):
        """Export plugins from specified installation"""
        if output_file is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            product_name = installation['name'].replace(' ', '-').lower()
            output_file = os.path.join(self.desktop,
                                       f"{product_name}_{installation['version']}_{timestamp}_exported-plugin-list.json")
        
        exe_path = self.get_exe_path(installation)
        backslash_char = '\\'
        # Create a temporary script file with absolute path
        script_path = os.path.join(self.desktop, 'temp_export_script.groovy')
        script = f'''
        // Get non-bundled plugins
        import com.intellij.ide.plugins.PluginManagerCore
        def plugins = PluginManagerCore.getPlugins()
            .findAll {{ !it.isBundled }}
            .collect {{ plugin ->
                [
                    id: plugin.pluginId.idString,
                    name: plugin.name,
                    version: plugin.version,
                    description: plugin.description,
                    isEnabled: !plugin.isEnabled
                ]
            }}

        // Get product info
        def appInfo = com.intellij.openapi.application.ApplicationInfo.getInstance()
        def outputFile = new File("{output_file.replace(backslash_char, '/')}")
        println("Writing to: ${{outputFile.absolutePath}}")

        // Write the JSON
        import groovy.json.JsonBuilder
        outputFile.text = new JsonBuilder([
            metadata: [
                product: "{installation['name']}",
                version: appInfo.fullVersion,
                buildNumber: appInfo.build.toString(),
                exportDate: new Date().toString()
            ],
            plugins: plugins
        ]).toPrettyString()

        println("Export completed to: ${{outputFile.absolutePath}}")
        '''
        print(script)
        try:
            with open(script_path, 'w') as f:
                f.write(script)
            
            # Run the IDE with the script
            exe_path = exe_path.replace('\\\\', '\\')
            script_path = script_path.replace('\\\\', '\\')
            print([
                exe_path,
                'evaluate', script_path
            ])
            process = subprocess.Popen([
                exe_path,
                'evaluate', script_path
            ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            
            # Wait for the process to complete or timeout after 30 seconds
            try:
                stdout, stderr = process.communicate(timeout=30)
                if process.returncode != 0:
                    print(f"Error: {stderr.decode()}")
                    return None
            except subprocess.TimeoutExpired:
                process.kill()
                print("Timeout waiting for IDE to respond")
                return None
            
            if os.path.exists(output_file):
                print(f"Plugins exported to: {output_file}")
                return output_file
            else:
                print(f"Export file not found at: {output_file}")
                return None
        finally:
            if os.path.exists(script_path):
                os.remove(script_path)
    
    def import_plugins(self, installation, plugin_list_file):
        """Import plugins into specified installation"""
        exe_path = self.get_exe_path(installation)
        
        with open(plugin_list_file, 'r') as f:
            data = json.load(f)
        
        plugins = data['plugins']
        enabled_plugins = [p['id'] for p in plugins if not p.get('isEnabled', False)]
        
        for plugin in enabled_plugins:
            print(f"Installing plugin: {plugin}")
            try:
                subprocess.run([
                    exe_path,
                    'installPlugins',
                    plugin
                ], check=True)
            except subprocess.CalledProcessError as e:
                print(f"Error installing plugin {plugin}: {str(e)}")


def main():
    parser = argparse.ArgumentParser(description='JetBrains Plugin Migration Tool')
    parser.add_argument('action', choices=['export', 'import', 'bridge'],
                        help='Action to perform: export plugins, import plugins, or bridge (export+import)')
    parser.add_argument('--source-product', help='Source product name (e.g., "PyCharm")')
    parser.add_argument('--target-product', help='Target product name for import/bridge')
    parser.add_argument('--plugin-file', help='Plugin list file for import')
    parser.add_argument('--output-dir', help='Output directory for export (default: Desktop)')
    
    args = parser.parse_args()
    
    manager = JetBrainsPluginManager()
    
    if args.output_dir:
        manager.desktop = args.output_dir
    
    if args.action == 'export':
        installations = manager.find_product_installations(args.source_product)
        if not installations:
            print(f"No installations found{f' for {args.source_product}' if args.source_product else ''}")
            return
        
        print("\nAvailable installations:")
        for i, inst in enumerate(installations):
            print(f"{i + 1}. {inst['name']} {inst['version']}")
        
        choice = int(input("\nChoose installation number: ")) - 1
        if 0 <= choice < len(installations):
            manager.export_plugins(installations[choice])
        else:
            print("Invalid choice")
    
    elif args.action == 'import':
        if not args.plugin_file:
            print("Please specify plugin list file with --plugin-file")
            return
        
        installations = manager.find_product_installations(args.target_product)
        if not installations:
            print(f"No installations found{f' for {args.target_product}' if args.target_product else ''}")
            return
        
        print("\nAvailable installations:")
        for i, inst in enumerate(installations):
            print(f"{i + 1}. {inst['name']} {inst['version']}")
        
        choice = int(input("\nChoose installation number: ")) - 1
        if 0 <= choice < len(installations):
            manager.import_plugins(installations[choice], args.plugin_file)
        else:
            print("Invalid choice")
    
    elif args.action == 'bridge':
        # Export from source
        source_installations = manager.find_product_installations(args.source_product)
        if not source_installations:
            print(f"No source installations found{f' for {args.source_product}' if args.source_product else ''}")
            return
        
        print("\nAvailable source installations:")
        for i, inst in enumerate(source_installations):
            print(f"{i + 1}. {inst['name']} {inst['version']}")
        
        source_choice = int(input("\nChoose source installation number: ")) - 1
        if 0 <= source_choice < len(source_installations):
            plugin_file = manager.export_plugins(source_installations[source_choice])
            
            if plugin_file:
                # Import to target
                target_installations = manager.find_product_installations(args.target_product)
                if not target_installations:
                    print(
                        f"No target installations found{f' for {args.target_product}' if args.target_product else ''}")
                    return
                
                print("\nAvailable target installations:")
                for i, inst in enumerate(target_installations):
                    print(f"{i + 1}. {inst['name']} {inst['version']}")
                
                target_choice = int(input("\nChoose target installation number: ")) - 1
                if 0 <= target_choice < len(target_installations):
                    manager.import_plugins(target_installations[target_choice], plugin_file)
                else:
                    print("Invalid choice")
        else:
            print("Invalid choice")


if __name__ == "__main__":
    main()

How to use

  • Install python
  • Add python binary to your PATH enviroment
  • create new file named plugin_migrator.py
  • Paste above content into this file, save it
  • Open terminal/powershell/cmd/bash. What ever but just shell is okay
  • Run python plugin_migrator.py import --plugin-file <exported_list_file_path>
  • Folow instruction in console.

Author : Zuko @tansautn

import com.intellij.ide.plugins.PluginManagerCore
import java.io.File
import java.time.LocalDateTime
val plugins = PluginManagerCore.getPlugins()
.filterNot { it.isBundled }
.map { plugin ->
mapOf(
"id" to plugin.pluginId.idString,
"name" to plugin.name,
"version" to plugin.version,
"description" to plugin.description,
"isEnabled" to !plugin.isEnabled
)
}
File("${args[0]}").writeText(
com.fasterxml.jackson.databind.ObjectMapper()
.writerWithDefaultPrettyPrinter()
.writeValueAsString(mapOf(
"metadata" to mapOf(
"product" to "${args[1]}",
"version" to "${args[2]}",
"exportDate" to LocalDateTime.now().toString()
),
"plugins" to plugins
))
)
import os
import json
import subprocess
import argparse
from datetime import datetime
from pathlib import Path
import re
class JetBrainsPluginManager:
def __init__(self):
self.program_files = os.environ.get('PROGRAMFILES', 'C:\\Program Files')
self.jetbrains_dir = os.path.join(self.program_files, 'JetBrains')
self.desktop = os.path.join(os.path.expanduser('~'), 'Desktop')
def find_product_installations(self, product_name = None):
"""Find all JetBrains product installations or specific product if name provided"""
installations = []
if not os.path.exists(self.jetbrains_dir):
return installations
for item in os.listdir(self.jetbrains_dir):
item_path = os.path.join(self.jetbrains_dir, item)
if os.path.isdir(item_path):
# Extract product info from directory name
match = re.match(r'(.*?)\s*(\d{4}\.\d+)', item)
if match:
prod_name, version = match.groups()
if product_name is None or product_name.lower() in prod_name.lower():
bin_dir = os.path.join(item_path, 'bin')
if os.path.exists(bin_dir):
installations.append({
'name': prod_name.strip(),
'version': version,
'path': item_path,
'bin': bin_dir
})
return sorted(installations, key=lambda x: x['version'], reverse=True)
def get_exe_path(self, installation):
"""Get the appropriate executable path based on product"""
exe_mappings = {
'IntelliJ IDEA': 'idea64.exe',
'PyCharm': 'pycharm64.exe',
'WebStorm': 'webstorm64.exe',
'PhpStorm': 'phpstorm64.exe',
'Rider': 'rider64.exe',
'CLion': 'clion64.exe',
'GoLand': 'goland64.exe',
'RubyMine': 'rubymine64.exe'
}
exe_name = exe_mappings.get(installation['name'], 'idea64.exe')
return os.path.join(installation['bin'], exe_name)
def export_plugins(self, installation, output_file = None):
"""Export plugins from specified installation"""
if output_file is None:
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
product_name = installation['name'].replace(' ', '-').lower()
output_file = os.path.join(self.desktop,
f"{product_name}_{installation['version']}_{timestamp}_exported-plugin-list.json")
exe_path = self.get_exe_path(installation)
backslash_char = '\\'
# Create a temporary script file with absolute path
script_path = os.path.join(self.desktop, 'temp_export_script.groovy')
script = f'''
// Get non-bundled plugins
import com.intellij.ide.plugins.PluginManagerCore
def plugins = PluginManagerCore.getPlugins()
.findAll {{ !it.isBundled }}
.collect {{ plugin ->
[
id: plugin.pluginId.idString,
name: plugin.name,
version: plugin.version,
description: plugin.description,
isEnabled: !plugin.isEnabled
]
}}
// Get product info
def appInfo = com.intellij.openapi.application.ApplicationInfo.getInstance()
def outputFile = new File("{output_file.replace(backslash_char, '/')}")
println("Writing to: ${{outputFile.absolutePath}}")
// Write the JSON
import groovy.json.JsonBuilder
outputFile.text = new JsonBuilder([
metadata: [
product: "{installation['name']}",
version: appInfo.fullVersion,
buildNumber: appInfo.build.toString(),
exportDate: new Date().toString()
],
plugins: plugins
]).toPrettyString()
println("Export completed to: ${{outputFile.absolutePath}}")
'''
print(script)
try:
with open(script_path, 'w') as f:
f.write(script)
# Run the IDE with the script
exe_path = exe_path.replace('\\\\', '\\')
script_path = script_path.replace('\\\\', '\\')
print([
exe_path,
'evaluate', script_path
])
process = subprocess.Popen([
exe_path,
'evaluate', script_path
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# Wait for the process to complete or timeout after 30 seconds
try:
stdout, stderr = process.communicate(timeout=30)
if process.returncode != 0:
print(f"Error: {stderr.decode()}")
return None
except subprocess.TimeoutExpired:
process.kill()
print("Timeout waiting for IDE to respond")
return None
if os.path.exists(output_file):
print(f"Plugins exported to: {output_file}")
return output_file
else:
print(f"Export file not found at: {output_file}")
return None
finally:
if os.path.exists(script_path):
os.remove(script_path)
def import_plugins(self, installation, plugin_list_file):
"""Import plugins into specified installation"""
exe_path = self.get_exe_path(installation)
with open(plugin_list_file, 'r') as f:
data = json.load(f)
plugins = data['plugins']
enabled_plugins = [p['id'] for p in plugins if not p.get('isEnabled', False)]
for plugin in enabled_plugins:
print(f"Installing plugin: {plugin}")
try:
subprocess.run([
exe_path,
'installPlugins',
plugin
], check=True)
except subprocess.CalledProcessError as e:
print(f"Error installing plugin {plugin}: {str(e)}")
def main():
parser = argparse.ArgumentParser(description='JetBrains Plugin Migration Tool')
parser.add_argument('action', choices=['export', 'import', 'bridge'],
help='Action to perform: export plugins, import plugins, or bridge (export+import)')
parser.add_argument('--source-product', help='Source product name (e.g., "PyCharm")')
parser.add_argument('--target-product', help='Target product name for import/bridge')
parser.add_argument('--plugin-file', help='Plugin list file for import')
parser.add_argument('--output-dir', help='Output directory for export (default: Desktop)')
args = parser.parse_args()
manager = JetBrainsPluginManager()
if args.output_dir:
manager.desktop = args.output_dir
if args.action == 'export':
installations = manager.find_product_installations(args.source_product)
if not installations:
print(f"No installations found{f' for {args.source_product}' if args.source_product else ''}")
return
print("\nAvailable installations:")
for i, inst in enumerate(installations):
print(f"{i + 1}. {inst['name']} {inst['version']}")
choice = int(input("\nChoose installation number: ")) - 1
if 0 <= choice < len(installations):
manager.export_plugins(installations[choice])
else:
print("Invalid choice")
elif args.action == 'import':
if not args.plugin_file:
print("Please specify plugin list file with --plugin-file")
return
installations = manager.find_product_installations(args.target_product)
if not installations:
print(f"No installations found{f' for {args.target_product}' if args.target_product else ''}")
return
print("\nAvailable installations:")
for i, inst in enumerate(installations):
print(f"{i + 1}. {inst['name']} {inst['version']}")
choice = int(input("\nChoose installation number: ")) - 1
if 0 <= choice < len(installations):
manager.import_plugins(installations[choice], args.plugin_file)
else:
print("Invalid choice")
elif args.action == 'bridge':
# Export from source
source_installations = manager.find_product_installations(args.source_product)
if not source_installations:
print(f"No source installations found{f' for {args.source_product}' if args.source_product else ''}")
return
print("\nAvailable source installations:")
for i, inst in enumerate(source_installations):
print(f"{i + 1}. {inst['name']} {inst['version']}")
source_choice = int(input("\nChoose source installation number: ")) - 1
if 0 <= source_choice < len(source_installations):
plugin_file = manager.export_plugins(source_installations[source_choice])
if plugin_file:
# Import to target
target_installations = manager.find_product_installations(args.target_product)
if not target_installations:
print(
f"No target installations found{f' for {args.target_product}' if args.target_product else ''}")
return
print("\nAvailable target installations:")
for i, inst in enumerate(target_installations):
print(f"{i + 1}. {inst['name']} {inst['version']}")
target_choice = int(input("\nChoose target installation number: ")) - 1
if 0 <= target_choice < len(target_installations):
manager.import_plugins(target_installations[target_choice], plugin_file)
else:
print("Invalid choice")
else:
print("Invalid choice")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment