Skip to content

Instantly share code, notes, and snippets.

@bytefluxio
Created June 19, 2021 12:42
Show Gist options
  • Save bytefluxio/9bd84cb780966a6091cf01fd8f92f1f6 to your computer and use it in GitHub Desktop.
Save bytefluxio/9bd84cb780966a6091cf01fd8f92f1f6 to your computer and use it in GitHub Desktop.
Install JetBrains PlugIns via CLI
import argparse
import http.client
import json
import os
import glob
import re
import urllib.request
import zipfile
def main():
config = __parse_args()
products = map(Product, config.products)
plugins = map(PlugIn, config.plugins)
for product in products:
for plugin in plugins:
version = plugin.get_compatible_version(product)
if version:
version.download_and_extract_to(product.plugin_path)
pass
class Product:
def __init__(self, product_name):
pycharm_wildcard_path = os.path.join(os.environ.get('APPDATA'), 'JetBrains', f'{product_name}*')
pycharm_paths = glob.glob(pycharm_wildcard_path)
if len(pycharm_paths) != 1:
raise EnvironmentError(f"Path for {product_name} couldn't be determined.")
pycharm_path = pycharm_paths[0]
self.name = product_name
self.version = pycharm_path.split('PyCharm')[-1]
self.path = pycharm_path
self.plugin_path = os.path.join(pycharm_path, 'plugins')
class PlugIn:
def __init__(self, plugin_name):
connection = http.client.HTTPSConnection("plugins.jetbrains.com")
plugin_json = self.__get_plugin(connection, plugin_name)
self.name = plugin_json.get('value')
self.id = re.findall(r'\d+', plugin_json.get('url'))[0]
self.versions = self.__get_versions(connection)
def __get_plugin(self, connection, plugin_name):
search_term = plugin_name
plugins_json = self.__get_plugins(connection, search_term)
while len(plugins_json) == 0 and len(search_term) > 5:
search_term = search_term[:-1]
plugins_json = self.__get_plugins(connection, search_term)
# Filter for only plugins that match the search term completely
filtered_plugins = list(filter(lambda x: x.get('value').lower() == plugin_name.lower(), plugins_json))
# If more or less than one plugin was found, something went wrong
if not filtered_plugins or len(filtered_plugins) == 0:
raise ValueError(f"Couldn't find any plugin using the search term {search_term}")
elif len(filtered_plugins) == 1:
return filtered_plugins[0]
else:
raise ValueError(f"Found more than one plugin for search term {search_term}")
def __get_versions(self, connection):
connection.request("GET", f"/api/plugins/{self.id}/updates?channel=&size=8")
versions_json = json.loads(connection.getresponse().read().decode('UTF-8'))
return list(map(PlugInVersion, versions_json))
@staticmethod
def __get_plugins(connection, search_term):
headers = {'accept': "application/json"}
products = [
"idea", "idea_ce", "idea_edu", "phpstorm", "webstorm",
"pycharm", "pycharm_ce", "pycharm_edu", "ruby", "objc",
"clion", "go", "dbe", "rider", "androidstudio", "mps"
]
url = f"/api/searchSuggest?isIDERequest=false" \
f"{''.join(map(lambda x: '&product=' + x, products))}" \
f"&term={search_term}"
connection.request("GET", url, headers=headers)
result = connection.getresponse()
data = result.read()
return json.loads(data.decode('UTF-8'))
def get_compatible_version(self, product):
sorted_versions = sorted(self.versions, key=lambda x: x.version, reverse=True)
for version in sorted_versions:
minimum_version = version.compatible_versions.get(product.name.upper())
if minimum_version[-1] == '+':
minimum_version = minimum_version[:-1]
if product.version >= minimum_version:
return version
return None
class PlugInVersion:
def __init__(self, version_json):
self.id = version_json.get('id')
self.version = version_json.get('version')
self.file = version_json.get('file')
self.compatible_versions = version_json.get('compatibleVersions')
def download_and_extract_to(self, plugin_path):
remote_url = "https://plugins.jetbrains.com/files/" + self.file
zip_file = f"{plugin_path}/{self.id}.zip"
urllib.request.urlretrieve(remote_url, zip_file)
with zipfile.ZipFile(zip_file, 'r') as zip_ref:
zip_ref.extractall(plugin_path)
os.remove(zip_file)
pass
def __parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'--products', '-pr',
type=str.lower,
choices=['idea', 'idea_ce', 'idea_edu', 'phpstorm', 'webstorm', 'pycharm', 'pycharm_ce', 'pycharm_edu',
'ruby', 'objc', 'clion', 'go', 'dbe', 'rider', 'androidstudio', 'mps'],
required=True,
nargs='+'
)
parser.add_argument(
'--plugins', '-p',
type=str.lower,
required=True,
nargs='+'
)
return parser.parse_args()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment