From 354af8b041c60fd6cc070dc20289d010e9a26c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Moreira?= Date: Tue, 10 Dec 2019 13:03:03 -0300 Subject: [PATCH] downloading and installing node --- bauh/gems/web/__init__.py | 8 +++- bauh/gems/web/controller.py | 9 +++- bauh/gems/web/environment.py | 90 ++++++++++++++++++++++++++++++++++++ bauh/view/core/downloader.py | 4 +- 4 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 bauh/gems/web/environment.py diff --git a/bauh/gems/web/__init__.py b/bauh/gems/web/__init__.py index 81c0edfd..c5008b25 100644 --- a/bauh/gems/web/__init__.py +++ b/bauh/gems/web/__init__.py @@ -1,3 +1,9 @@ import os -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) \ No newline at end of file +from bauh.api.constants import HOME_PATH + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +BIN_PATH = '{}/.local/share/bauh/web'.format(HOME_PATH) +NODE_DIR_PATH = '{}/node'.format(BIN_PATH) +NODE_BIN_PATH = '{}/bin/node'.format(NODE_DIR_PATH) +NPM_BIN_PATH = '{}/bin/npm'.format(NODE_DIR_PATH) diff --git a/bauh/gems/web/controller.py b/bauh/gems/web/controller.py index 97f7ab0a..82e47429 100644 --- a/bauh/gems/web/controller.py +++ b/bauh/gems/web/controller.py @@ -1,3 +1,5 @@ +import os +from threading import Thread from typing import List, Type, Set from bauh.api.abstract.context import ApplicationContext @@ -6,6 +8,7 @@ from bauh.api.abstract.disk import DiskCacheLoader from bauh.api.abstract.handler import ProcessWatcher from bauh.api.abstract.model import SoftwarePackage, PackageAction, PackageSuggestion, PackageUpdate, PackageHistory from bauh.gems.web import npm +from bauh.gems.web.environment import NodeUpdater from bauh.gems.web.model import WebApplication try: @@ -27,6 +30,7 @@ class WebApplicationManager(SoftwareManager): def __init__(self, context: ApplicationContext): super(WebApplicationManager, self).__init__(context=context) self.http_client = context.http_client + self.node_updater = NodeUpdater(logger=context.logger, file_downloader=context.file_downloader, i18n=context.i18n) self.enabled = True def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult: @@ -87,13 +91,14 @@ class WebApplicationManager(SoftwareManager): self.enabled = enabled def can_work(self) -> bool: - return BS4_AVAILABLE and LXML_AVAILABLE and npm.is_available() + return BS4_AVAILABLE and LXML_AVAILABLE def requires_root(self, action: str, pkg: SoftwarePackage): return False def prepare(self): - pass + if bool(int(os.getenv('BAUH_WEB_UPDATE_NODE', 1))): + Thread(daemon=True, target=self.node_updater.update_node).start() def list_updates(self, internet_available: bool) -> List[PackageUpdate]: pass diff --git a/bauh/gems/web/environment.py b/bauh/gems/web/environment.py new file mode 100644 index 00000000..a76172de --- /dev/null +++ b/bauh/gems/web/environment.py @@ -0,0 +1,90 @@ +import logging +import os +import shutil +import tarfile +from pathlib import Path + +from bauh.api.abstract.download import FileDownloader +from bauh.api.abstract.handler import ProcessWatcher +from bauh.api.exception import NoInternetException +from bauh.commons import system +from bauh.gems.web import BIN_PATH, NODE_DIR_PATH, NODE_BIN_PATH +from bauh.view.util.translation import I18n + + +class NodeUpdater: + + def __init__(self, logger: logging.Logger, file_downloader: FileDownloader, i18n: I18n): + self.logger = logger + self.file_downloader = file_downloader + self.i18n = i18n + + def _is_internet_available(self) -> bool: + self.logger.info('Checking internet connection') + # TODO + return True + + def _download_and_install(self, cloud_version: str, watcher: ProcessWatcher ) -> bool: + npm_dlink = 'https://nodejs.org/dist/v12.13.1/node-v12.13.1-linux-x64.tar.xz' + self.logger.info("Downloading NodeJS {}: {}".format(cloud_version, npm_dlink)) + + tarf_path = '{}/{}'.format(BIN_PATH, npm_dlink.split('/')[-1]) + downloaded = self.file_downloader.download(npm_dlink, watcher=watcher, output_path=tarf_path, cwd=BIN_PATH) + + if not downloaded: + self.logger.error("Could not download '{}'. Aborting...".format(npm_dlink)) + return False + else: + try: + tf = tarfile.open(tarf_path) + tf.extractall(path=BIN_PATH) + + extracted_file = '{}/{}'.format(BIN_PATH, tf.getnames()[0]) + + os.rename(extracted_file, NODE_DIR_PATH) + + except: + self.logger.error('Could not extract {}'.format(tarf_path)) + return False + finally: + if os.path.exists(tarf_path): + try: + os.remove(tarf_path) + except: + self.logger.error('Could not delete file {}'.format(tarf_path)) + + def update_node(self, watcher: ProcessWatcher = None) -> bool: + if not self._is_internet_available(): + raise NoInternetException() + + self.logger.info('Checking Node version from bauh-files') + # TODO + cloud_version = 'v12.13.1' + + Path(BIN_PATH).mkdir(parents=True, exist_ok=True) + + if not os.path.exists(NODE_DIR_PATH): + if not self._download_and_install(cloud_version, watcher): + return False + else: + installed_version = system.run_cmd('{} --version'.format(NODE_BIN_PATH)) + + if installed_version: + installed_version = installed_version.strip() + + self.logger.info('Node -> installed: {}. cloud: {}.'.format(installed_version, cloud_version)) + + if cloud_version != installed_version: + return self._download_and_install(cloud_version, watcher) + else: + self.logger.info("Node is already up to date") + return True + else: + self.logger.warning("Could not determine the current NodeJS installed version") + self.logger.info("Removing {}".format(NODE_DIR_PATH)) + try: + shutil.rmtree(NODE_DIR_PATH) + return self._download_and_install(cloud_version, watcher) + except: + self.logger.error('Could not delete the dir {}'.format(NODE_DIR_PATH)) + return False diff --git a/bauh/view/core/downloader.py b/bauh/view/core/downloader.py index d29231fb..fc5f45d1 100644 --- a/bauh/view/core/downloader.py +++ b/bauh/view/core/downloader.py @@ -91,7 +91,9 @@ class AdaptableFileDownloader(FileDownloader): file_size = self.http_client.get_content_length(file_url) msg = bold('[{}] ').format(downloader) + self.i18n['downloading'] + ' ' + bold(file_url.split('/')[-1]) + (' ( {} )'.format(file_size) if file_size else '') - watcher.change_substatus(msg) + + if watcher: + watcher.change_substatus(msg) if isinstance(process, SimpleProcess): success = handler.handle_simple(process)