-
-
Save bytefluxio/9bd84cb780966a6091cf01fd8f92f1f6 to your computer and use it in GitHub Desktop.
Install JetBrains PlugIns via CLI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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