Beispiel #1
0
    def install_onedir(self, install_path: str, latest_version: str, platform: str):
        old_path = f'{install_path}.OLD'
        zip_path = f"{HOME}/.figgy/figgy.zip"
        install_dir = f'{HOME}/.figgy/installations/{latest_version}/{str(uuid.uuid4())[:4]}'
        url = f'http://www.figgy.dev/releases/cli/{latest_version}/{platform.lower()}/figgy.zip'
        os.makedirs(os.path.dirname(install_dir), exist_ok=True)
        suffix = ".exe" if Utils.is_windows() else ""
        self._cleanup_file(zip_path)

        self.download_with_progress(url, zip_path)

        with ZipFile(zip_path, 'r') as zipObj:
            zipObj.extractall(install_dir)

        if self._utils.file_exists(old_path):
            os.remove(old_path)

        executable_path = f'{install_dir}/figgy/{CLI_NAME}{suffix}'
        st = os.stat(executable_path)
        os.chmod(executable_path, st.st_mode | stat.S_IEXEC)

        if self._utils.file_exists(install_path):
            os.rename(install_path, old_path)

        os.symlink(executable_path, install_path)
Beispiel #2
0
class UpgradeManager:
    def __init__(self, colors_enabled: bool):
        self._utils = Utils(colors_enabled=colors_enabled)
        self.c = Utils.default_colors(enabled=colors_enabled)
        self.current_version: FiggyVersionDetails = VersionTracker.get_version()

    def download(self, url: str, local_path: str):
        with requests.get(url, stream=True) as r:
            r.raise_for_status()
            with open(local_path, 'wb+') as f:
                for chunk in r.iter_content(chunk_size=1024):
                    f.write(chunk)

    def download_with_progress(self, url: str, local_path: str):
        resp = requests.get(url, stream=True)
        total = int(resp.headers.get('content-length', 0))
        with open(local_path, 'wb+') as file, tqdm(
                desc='Downloading',
                total=total,
                unit='iB',
                miniters=1,
                unit_scale=True,
                unit_divisor=1024,
        ) as bar:
            for data in resp.iter_content(chunk_size=1024):
                size = file.write(data)
                bar.update(size)

        return True

    def is_symlink(self, install_path: str):
        return os.path.islink(install_path)

    def is_pip_install(self) -> bool:
        install_path = self.install_path
        try:
            if install_path:
                with open(install_path, 'r') as file:
                    contents = file.read()

                return 'EASY-INSTALL' in contents or 'console_scripts' in contents
            else:
                return False
        except UnicodeDecodeError as e:
            log.info(f"Error decoding {install_path}, file must be binary.")
            return False

    def is_brew_install(self) -> bool:
        return "Cellar" in self.install_path

    def install_onedir(self, install_path: str, latest_version: str, platform: str):
        old_path = f'{install_path}.OLD'
        zip_path = f"{HOME}/.figgy/figgy.zip"
        install_dir = f'{HOME}/.figgy/installations/{latest_version}/{str(uuid.uuid4())[:4]}'
        url = f'http://www.figgy.dev/releases/cli/{latest_version}/{platform.lower()}/figgy.zip'
        os.makedirs(os.path.dirname(install_dir), exist_ok=True)
        suffix = ".exe" if Utils.is_windows() else ""
        self._cleanup_file(zip_path)

        self.download_with_progress(url, zip_path)

        with ZipFile(zip_path, 'r') as zipObj:
            zipObj.extractall(install_dir)

        if self._utils.file_exists(old_path):
            os.remove(old_path)

        executable_path = f'{install_dir}/figgy/{CLI_NAME}{suffix}'
        st = os.stat(executable_path)
        os.chmod(executable_path, st.st_mode | stat.S_IEXEC)

        if self._utils.file_exists(install_path):
            os.rename(install_path, old_path)

        os.symlink(executable_path, install_path)

    def _get_executable_path(self):
        return

    def _cleanup_file(self, file_path: str):
        try:
            os.remove(file_path)
        except Exception as e:
            log.error(f"Received error when attempting to prune install.")
            pass

    @property
    def install_path(self) -> Optional[str]:
        """
        Prompts the user to get their local installation path.
        """
        binary_path = sys.executable
        suffix = ".exe" if self._utils.is_windows() and not binary_path.endswith(".exe") else ""
        binary_path = f'{binary_path}{suffix}'

        if not os.path.exists(binary_path):
            return None

        return binary_path
Beispiel #3
0
class Upgrade(MaintenanceCommand):
    """
    Drives the --version command
    """
    def __init__(self, maintenance_context: MaintenanceContext,
                 config_service: Optional[ConfigService]):
        super().__init__(version, maintenance_context.defaults.colors_enabled,
                         maintenance_context)
        self.tracker = VersionTracker(self.context.defaults, config_service)
        self.upgrade_mgr = UpgradeManager(
            maintenance_context.defaults.colors_enabled)
        self._utils = Utils(
            colors_enabled=maintenance_context.defaults.colors_enabled)
        self._out = Output(
            colors_enabled=maintenance_context.defaults.colors_enabled)

    def upgrade(self):
        latest_version: FiggyVersionDetails = self.tracker.get_version()
        install_success, upgrade_it = False, True

        if self.upgrade_mgr.is_pip_install():
            self._out.error(
                f"Figgy appears to have been installed with pip. Please upgrade [[{CLI_NAME}]] with "
                f"`pip` instead.")
            self._out.print(
                f"\n\n[[Try this command]]: pip install figgy-cli --upgrade")

            self._out.print(
                f"\n\nPip based [[{CLI_NAME}]] installations do not support automatic upgrades and "
                f"instead require pip-managed upgrades; however,  Homebrew, one-line, and manual "
                f"installations support auto-upgrade. Please consider installing figgy through one "
                f"of these other methods to take advantage of this feature. "
                f"It will save you time, help keep you up-to-date, and enable important features like "
                f"release-rollbacks and canary releases! "
                f"[[https://www.figgy.dev/docs/getting-started/install/]]")
            sys.exit(0)

        install_path = self.upgrade_mgr.install_path

        if not install_path:
            self._utils.error_exit(
                f"Unable to detect local figgy installation. Please reinstall figgy and follow one "
                f"of the recommended installation procedures.")

        if latest_version.version == VERSION:
            self._out.success(
                f'You are currently using the latest version of [[{CLI_NAME}]]: [[{VERSION}]]'
            )
            upgrade_it = False
        elif self.tracker.upgrade_available():
            self._out.notify_h2(
                f"New version: [[{latest_version.version}]] is more recent than your version: [[{VERSION}]]"
            )
            upgrade_it = True
        elif not self.tracker.cloud_version_compatible_with_upgrade():
            self._out.notify_h2(
                f"Version [[{self.tracker.get_version().version}]] of the Figgy CLI is available but your "
                f"current version of Figgy Cloud ([[{self.tracker.current_cloud_version()}]]) is not compatible."
                f" Your administrator must first update FiggyCloud to at least version: "
                f"[[{self.tracker.required_cloud_version()}]] before you can upgrade Figgy."
            )
            upgrade_it = False
        else:
            self._out.notify_h2(
                f"Your version: [[{VERSION}]] is more recent then the current recommended version "
                f"of {CLI_NAME}: [[{latest_version.version}]]")
            upgrade_it = Input.y_n_input(
                f'Would you like to revert to the current recommended version '
                f'of {CLI_NAME}?')

        if upgrade_it:
            if self._utils.is_mac():
                self._out.print(
                    f"\nMacOS auto-upgrade is supported. Performing auto-upgrade."
                )
                install_success = self.install_mac(latest_version)
            elif self._utils.is_linux():
                self._out.print(
                    f"\nLinux auto-upgrade is supported. Performing auto-upgrade."
                )
                install_success = self.install_linux(latest_version)
            elif self._utils.is_windows():
                self._out.print(
                    f"\nWindows auto-upgrade is supported. Performing auto-upgrade."
                )
                install_success = self.install_windows(latest_version)

            if install_success:
                self._out.success(
                    f"Installation successful! Exiting. Rerun `[[{CLI_NAME}]]` "
                    f"to use the latest version!")
            else:
                self._out.warn(
                    f"\nUpgrade may not have been successful. Check by re-running "
                    f"[[`{CLI_NAME}` --version]] to see if it was. If it wasn't, please reinstall [[`{CLI_NAME}`]]. "
                    f"See {INSTALL_URL}.")

    def install_mac(self, latest_version: FiggyVersionDetails) -> bool:
        install_path = '/usr/local/bin/figgy'

        if self.upgrade_mgr.is_brew_install():
            self._out.notify_h2(f"Homebrew installation detected!")

            print(
                f"This upgrade process will not remove your brew installation but will instead unlink it. "
                f"Going forward you will no longer need homebrew to manage {CLI_NAME}. Continuing is recommended.\n"
            )

            selection = Input.y_n_input(f"Continue? ", default_yes=True)
        else:
            selection = True

        if selection:
            self.upgrade_mgr.install_onedir(install_path,
                                            latest_version.version, MAC)
            return True
        else:
            self._out.print(
                f'\n[[Auto-upgrade aborted. To upgrade through brew run:]] \n'
                f'-> brew upgrade figtools/figgy/figgy')
            self._out.warn(
                f"\n\nYou may continue to manage [[{CLI_NAME}]] through Homebrew, but doing so will "
                f"limit some upcoming functionality around canary releases, rollbacks, and dynamic "
                f"version-swapping.")
            return False

    def install_linux(self, latest_version: FiggyVersionDetails) -> bool:
        install_path = self.upgrade_mgr.install_path
        self.upgrade_mgr.install_onedir(install_path, latest_version.version,
                                        LINUX)
        return True

    def install_windows(self, latest_version: FiggyVersionDetails) -> bool:
        install_path = self.upgrade_mgr.install_path
        self.upgrade_mgr.install_onedir(install_path, latest_version.version,
                                        WINDOWS)
        return True

    @AnonymousUsageTracker.track_command_usage
    def execute(self):
        self.upgrade()