diff --git a/projector_installer/actions.py b/projector_installer/actions.py index bf6814b..cf5b428 100644 --- a/projector_installer/actions.py +++ b/projector_installer/actions.py @@ -22,7 +22,7 @@ find_apps, edit_config, list_apps, select_installed_app, select_run_config, make_run_config, \ get_user_install_input, make_config_from_input -from .global_config import get_download_cache_dir, RunConfig, is_secure, is_password_protected +from .global_config import get_download_cache_dir, RunConfig from .ide_configuration import forbid_updates_for from .run_config import get_run_configs, get_run_script_path, validate_run_config, \ @@ -53,10 +53,10 @@ def do_show_config(pattern: Optional[str] = None) -> None: if run_config.toolbox: print('Toolbox config = yes') - if is_secure(run_config): + if run_config.is_secure(): print('Secure config = yes') - if is_password_protected(run_config): + if run_config.is_password_protected(): print(f'RW Password: = {run_config.password}') print(f'RO Password: = {run_config.ro_password}') @@ -84,7 +84,7 @@ def get_access_urls(run_config: RunConfig) -> List[str]: schema = 'http' - if is_secure(run_config): + if run_config.is_secure(): schema = 'https' urls = [] @@ -170,7 +170,7 @@ def signal_handler(*args): # type: ignore print('To see Projector logs in realtime run\n\t' f'tail -f "{get_path_to_log(run_config.name)}"\n') - if is_secure(run_config): + if run_config.is_secure(): print('If browser warns on unsecure connection, install projector certificate:') print(get_ca_crt_file()) print('Refer to: ') diff --git a/projector_installer/apps.py b/projector_installer/apps.py index c3bc835..33cee94 100644 --- a/projector_installer/apps.py +++ b/projector_installer/apps.py @@ -13,8 +13,7 @@ from . import global_config from .global_config import get_apps_dir, get_projector_server_dir, \ - InstallableApp, RunConfig, is_password_protected, init_compatible_apps, is_secure, \ - get_ssl_properties_file + InstallableApp, RunConfig, init_compatible_apps, get_ssl_properties_file from .utils import unpack_tar_file @@ -75,10 +74,10 @@ def write_run_script(run_config: RunConfig, src: TextIO, dst: TextIO) -> None: line = f' -Dorg.jetbrains.projector.server.port={run_config.projector_port} \\\n' line += f' -Dorg.jetbrains.projector.server.classToLaunch={IDEA_RUN_CLASS} \\\n' - if is_secure(run_config): + if run_config.is_secure(): line += f' -D{SSL_ENV_NAME}=\"{get_ssl_properties_file(run_config.name)}\" \\\n' - if is_password_protected(run_config): + if run_config.is_password_protected(): line += f' -D{TOKEN_ENV_NAME}=\"{run_config.password}\" \\\n' line += f' -D{RO_TOKEN_ENV_NAME}=\"{run_config.ro_password}\" \\\n' diff --git a/projector_installer/dialogs.py b/projector_installer/dialogs.py index 525097a..8b32285 100644 --- a/projector_installer/dialogs.py +++ b/projector_installer/dialogs.py @@ -11,10 +11,9 @@ import click +from .run_config import get_run_configs, RunConfig, get_run_config_names, get_used_projector_ports from .apps import get_installed_apps, get_app_path, get_compatible_app_names, \ is_path_to_app, is_toolbox_path -from .run_config import get_run_configs, RunConfig, get_run_config_names, \ - get_used_projector_ports, is_password_protected from .global_config import DEF_PROJECTOR_PORT from .secure_config import generate_token @@ -315,7 +314,7 @@ def select_custom_fqdns() -> str: type=bool) fqdns: str = click.prompt('Please specify the comma-separated list of custom fqdns', - type=str) if need_fqdn else '' + type=str) if need_fqdn else '' return fqdns @@ -328,7 +327,7 @@ def edit_config(config: RunConfig) -> RunConfig: prompt = 'Enter a Projector port (press ENTER for default)' config.projector_port = click.prompt(prompt, default=str(config.projector_port)) - if is_password_protected(config): + if config.is_password_protected(): password = select_password("Choose password", config.password) ro_password = password diff --git a/projector_installer/global_config.py b/projector_installer/global_config.py index 4d4733a..3daee4b 100644 --- a/projector_installer/global_config.py +++ b/projector_installer/global_config.py @@ -7,20 +7,18 @@ Global configuration constants, variables and functions. """ -import socket import sys from typing import List from shutil import rmtree -from urllib.error import URLError from os.path import dirname, join, expanduser, abspath -from .installable_app import InstallableApp, load_installable_apps -from .utils import create_dir_if_not_exist, download_file, get_file_name_from_url +from .installable_app import InstallableApp, load_compatible_apps +from .utils import create_dir_if_not_exist USER_HOME: str = expanduser('~') INSTALL_DIR: str = dirname(abspath(__file__)) DEF_PROJECTOR_PORT: int = 9999 -COMPATIBLE_IDE_FILE: str = 'compatible_ide.json' +COMPATIBLE_IDE_FILE: str = join(INSTALL_DIR, 'compatible_ide.json') DEF_CONFIG_DIR: str = '.projector' SSL_PROPERTIES_FILE = 'ssl.properties' BUNDLED_DIR: str = 'bundled' @@ -70,11 +68,6 @@ def get_ssl_dir() -> str: return join(config_dir, 'ssl') -def get_compatible_ide_file() -> str: - """Returns full path to compatible ide file.""" - return join(INSTALL_DIR, COMPATIBLE_IDE_FILE) - - COMPATIBLE_APPS: List[InstallableApp] = [] @@ -94,50 +87,19 @@ def __init__(self, own_name: str, path_to_app: str, projector_port: int, self.toolbox = toolbox self.fqdns = custom_fqdns + def is_secure(self) -> bool: + """Checks if secure configuration""" + return self.token != '' -def is_secure(run_config: RunConfig) -> bool: - """Checks if secure configuration""" - return run_config.token != '' - - -def is_password_protected(run_config: RunConfig) -> bool: - """Checks if run config is password protected""" - return run_config.password != '' - - -COMPATIBLE_IDE_FILE_URL: str = \ - 'https://raw.githubusercontent.com/JetBrains/projector-installer/master/' \ - 'projector_installer/compatible_ide.json' - - -def download_compatible_apps() -> str: - """Downloads compatible ide json file from github repository.""" - try: - download_file(COMPATIBLE_IDE_FILE_URL, get_download_cache_dir(), timeout=3, silent=True) - name = get_file_name_from_url(COMPATIBLE_IDE_FILE_URL) - file_name = join(get_download_cache_dir(), name) - - return file_name - except (URLError, socket.timeout): - return '' - - -def load_compatible_apps() -> List[InstallableApp]: - """Loads compatible apps dictionary from bundled file and github-stored Json""" - file_name = get_compatible_ide_file() - local_list = load_installable_apps(file_name) - github_file = download_compatible_apps() - - if github_file: - github_list = load_installable_apps(github_file) - - return list(set(local_list) | set(github_list)) + def is_password_protected(self) -> bool: + """Checks if run config is password protected""" + return self.password != '' def init_compatible_apps() -> List[InstallableApp]: """Initializes compatible apps list.""" try: - return load_compatible_apps() + return load_compatible_apps(COMPATIBLE_IDE_FILE) except IOError as error: print(f'Cannot load compatible ide file: {str(error)}. Exiting...') sys.exit(2) diff --git a/projector_installer/installable_app.py b/projector_installer/installable_app.py index d0c8349..9d2b897 100644 --- a/projector_installer/installable_app.py +++ b/projector_installer/installable_app.py @@ -4,8 +4,19 @@ """InstallableApp class and related stuff""" import json +import socket +from os import remove +from os.path import join +from tempfile import gettempdir from typing import List, Tuple, Any from enum import Enum, auto +from urllib.error import URLError + +from .utils import download_file, get_file_name_from_url + +COMPATIBLE_IDE_FILE_URL: str = \ + 'https://raw.githubusercontent.com/JetBrains/projector-installer/master/' \ + 'projector_installer/compatible_ide.json' class IDEKind(Enum): @@ -55,9 +66,41 @@ def _parse_entry(entry: Any) -> InstallableApp: return InstallableApp(entry['name'], entry['url'], kind) -def load_installable_apps(file_name: str) -> List[InstallableApp]: +def load_installable_apps_from_file(file_name: str) -> List[InstallableApp]: """Loads installable app list from json file.""" with open(file_name, 'r') as file: data = json.load(file) return [_parse_entry(entry) for entry in data] + + +def download_compatible_apps() -> str: + """Downloads compatible ide json file from github repository.""" + + try: + download_file(COMPATIBLE_IDE_FILE_URL, gettempdir(), timeout=3, silent=True) + name = get_file_name_from_url(COMPATIBLE_IDE_FILE_URL) + file_name = join(gettempdir(), name) + + return file_name + except (URLError, socket.timeout): + return '' + + +def load_compatible_apps_from_github() -> List[InstallableApp]: + """Loads compatible app list from github repo""" + file_name = download_compatible_apps() + res = load_installable_apps_from_file(file_name) if file_name else [] + remove(file_name) + return res + + +def load_compatible_apps(file_name: str) -> List[InstallableApp]: + """Loads from file and from github and merges results""" + local_list = load_installable_apps_from_file(file_name) + github_list = load_compatible_apps_from_github() + + return list(set(local_list) | set(github_list)) + +# # https://data.services.jetbrains.com/products?code=IIU%2CIIC&release.type=release +# PRODUCTS_URL = 'https://data.services.jetbrains.com/products' diff --git a/projector_installer/run_config.py b/projector_installer/run_config.py index 483cb8a..c3384e2 100644 --- a/projector_installer/run_config.py +++ b/projector_installer/run_config.py @@ -14,7 +14,7 @@ import configparser from .apps import get_app_path, make_run_script, check_run_script -from .global_config import get_run_configs_dir, RunConfig, is_password_protected, is_secure +from .global_config import get_run_configs_dir, RunConfig from .secure_config import generate_server_secrets CONFIG_INI_NAME = 'config.ini' @@ -58,11 +58,11 @@ def save_config(run_config: RunConfig) -> None: config['PROJECTOR'] = {} config['PROJECTOR']['PORT'] = str(run_config.projector_port) - if is_secure(run_config): + if run_config.is_secure(): config['SSL'] = {} config['SSL']['TOKEN'] = run_config.token - if is_password_protected(run_config): + if run_config.is_password_protected(): config['PASSWORDS'] = {} config['PASSWORDS']['PASSWORD'] = run_config.password # type: ignore config['PASSWORDS']['RO_PASSWORD'] = run_config.ro_password # type: ignore @@ -87,7 +87,7 @@ def save_config(run_config: RunConfig) -> None: generate_run_script(run_config) - if is_secure(run_config): + if run_config.is_secure(): generate_server_secrets(run_config)