def _display(self, contentType):
     # print depending on the content type
     while True:
         try:
             if isinstance(contentType, InputText):
                 contentType.run_callback(result=rlinput(contentType.content, contentType.default_input))
             elif isinstance(contentType, LicenseAgreement):
                 print(contentType.content)
                 contentType.choose(answer=input(contentType.input))
             elif isinstance(contentType, TextWithChoices):
                 contentType.choose(answer=input(contentType.prompt))
             elif isinstance(contentType, DisplayMessage):
                 print(contentType.text)
             elif isinstance(contentType, UnknownProgress):
                 if not contentType.bar:
                     contentType.bar = ProgressBar(widgets=[BouncingBar()])
                 with suppress(StopIteration):
                     # pulse and add a timeout callback
                     contentType.bar(contentType._iterator()).next()
                     UI.delayed_display(contentType)
                 # don't recall the callback
                 return False
             else:
                 logger.error("Unexcepted content type to display to CLI UI: {}".format(contentType))
                 MainLoop().quit(status_code=1)
             break
         except InputError as e:
             logger.error(str(e))
             continue
    def setup(self, arg_install_path=None):
        self.arg_install_path = arg_install_path
        super().setup()

        # first step, check if installed
        if self.is_installed:
            UI.display(YesNo("{} is already installed on your system, do you want to reinstall "
                             "it anyway?".format(self.name), self.reinstall, UI.return_main_screen))
        else:
            self.confirm_path(arg_install_path)
    def test_call_display(self, mocksys):
        """We call the display method from the UIPlug"""
        UI.display(self.contentType)
        self.start_glib_mainloop()
        self.wait_for_mainloop_shutdown()

        self.assertTrue(self.mockUIPlug._display.called)
        self.assertIsNotNone(self.mainloop_thread)
        self.assertIsNotNone(self.display_thread)
        self.assertEquals(self.mainloop_thread, self.display_thread)
    def decompress_and_install(self, fd):
        UI.display(DisplayMessage("Installing {}".format(self.name)))
        # empty destination directory if reinstall
        for dir_to_remove in self._paths_to_clean:
            with suppress(FileNotFoundError):
                shutil.rmtree(dir_to_remove)

        Decompressor({fd: Decompressor.DecompressOrder(dir=self.dir_to_decompress_in_tarball, dest=self.install_path)},
                     self.decompress_and_install_done)
        UI.display(UnknownProgress(self.iterate_until_install_done))
 def run_for(self, args):
     """Running commands from args namespace"""
     # try to call default framework if any
     if not args.framework:
         if not self.default_framework:
             message = "A default framework for category {} was requested where there is none".format(self.name)
             logger.error(message)
             UI.return_main_screen(status_code=1)
         self.default_framework.run_for(args)
         return
     self.frameworks[args.framework].run_for(args)
    def test_call_delayed_display(self, mocksys):
        """We call the display method from the UIPlug in delayed_display with 50ms waiting"""
        UI.delayed_display(self.contentType)
        now = time()
        self.start_glib_mainloop()
        self.wait_for_mainloop_shutdown()

        self.assertTrue(self.mockUIPlug._display.called)
        self.assertIsNotNone(self.mainloop_thread)
        self.assertIsNotNone(self.display_thread)
        self.assertEquals(self.mainloop_thread, self.display_thread)
        self.assertTrue(self.time_display_call - now > 0.05)
 def start_download_and_install(self):
     self.last_progress_download = None
     self.last_progress_requirement = None
     self.balance_requirement_download = None
     self.pkg_size_download = 0
     self.result_requirement = None
     self.result_download = None
     self._download_done_callback_called = False
     UI.display(DisplayMessage("Downloading and installing requirements"))
     self.pbar = ProgressBar().start()
     self.pkg_to_install = RequirementsHandler().install_bucket(self.packages_requirements,
                                                                self.get_progress_requirement,
                                                                self.requirement_done)
     DownloadCenter(urls=self.download_requests, on_done=self.download_done, report=self.get_progress_download)
 def run_for(self, args):
     """Running commands from args namespace"""
     logger.debug("Call run_for on {}".format(self.name))
     if args.remove:
         if args.destdir:
             message = "You can't specify a destination dir while removing a framework"
             logger.error(message)
             UI.return_main_screen()
         self.remove()
     else:
         install_path = None
         if args.destdir:
             install_path = os.path.abspath(os.path.expanduser(args.destdir))
         self.setup(install_path)
    def setup(self):
        """Method call to setup the Framework"""
        if not self.is_installable:
            logger.error("You can't install that framework on that machine")
            UI.return_main_screen()
            return

        if self.need_root_access and os.geteuid() != 0:
            logger.debug("Requesting root access")
            cmd = ["sudo", "-E", "env", "PATH={}".format(os.getenv("PATH"))]
            cmd.extend(sys.argv)
            MainLoop().quit(subprocess.call(cmd))

        # be a normal, kind user as we don't want normal files to be written as root
        switch_to_current_user()
        def done(download_result):
            res = download_result[md5_url]

            if res.error:
                logger.error(res.error)
                UI.return_main_screen()
                return

            # Should be ASCII anyway.
            md5 = res.buffer.getvalue().decode('utf-8').split()[0]
            logger.debug("Downloaded MD5 is {}".format(md5))

            logger.debug("Preparing to download the main archive.")

            download_url = self.DOWNLOAD_URL_PAT.format(release=RELEASE, suf='')

            self.download_requests.append((download_url, md5))
            self.start_download_and_install()
    def download_and_requirements_done(self):
        # wait for both side to be done
        if self._download_done_callback_called or (not self.result_download or not self.result_requirement):
            return
        self._download_done_callback_called = True

        self.pbar.finish()
        # display eventual errors
        error_detected = False
        fd = None
        if self.result_requirement.error:
            logger.error(self.result_requirement.error)
            error_detected = True
        for url in self.result_download:
            if self.result_download[url].error:
                logger.error(self.result_download[url].error)
                error_detected = True
            fd = self.result_download[url].fd
        if error_detected:
            UI.return_main_screen()
            return
        self.decompress_and_install(fd)
    def confirm_path(self, path_dir=""):
        """Confirm path dir"""

        if not path_dir:
            logger.debug("No installation path provided. Requesting one.")
            UI.display(InputText("Choose installation path:", self.confirm_path, self.install_path))
            return

        logger.debug("Installation path provided. Checking if exists.")
        with suppress(FileNotFoundError):
            if os.listdir(path_dir):
                # we already told we were ok to overwrite as it was the previous install path
                if path_dir not in self._paths_to_clean:
                    if path_dir == "/":
                        logger.error("This doesn't seem wise. We won't let you shoot in your feet.")
                        self.confirm_path()
                        return
                    self.install_path = path_dir  # we don't set it before to not repropose / as installation path
                    UI.display(YesNo("{} isn't an empty directory, do you want to remove its content and install "
                                     "there?".format(path_dir), self.set_installdir_to_clean, UI.return_main_screen))
                    return
        self.install_path = path_dir
        self.download_provider_page()
    def confirm_path(self, path_dir=""):
        """Confirm path dir"""

        if not path_dir:
            logger.debug("No installation path provided. Requesting one.")
            UI.display(InputText("Choose installation path:", self.confirm_path, self.install_path))
            return

        logger.debug("Installation path provided. Checking if exists.")
        with suppress(FileNotFoundError):
            if os.listdir(path_dir):
                if self._reinstall:
                    self.set_dir_to_clean()
                else:
                    if path_dir == "/":
                        logger.error("This doesn't seem wise. We won't let you shoot in your feet.")
                        self.confirm_path()
                        return
                    UI.display(YesNo("{} isn't an empty directory, do you want to remove its content and install "
                                     "there?".format(path_dir), self.set_dir_to_clean, UI.return_main_screen))
                self.install_path = path_dir
                return
        self.install_path = path_dir
        self.download_provider_page()
    def get_metadata_and_check_license(self, result):
        """Download files to download + license and check it"""
        logger.debug("Parse download metadata")

        error_msg = result[self.download_page].error
        if error_msg:
            logger.error("An error occurred while downloading {}: {}".format(self.download_page, error_msg))
            UI.return_main_screen()

        url, md5sum = (None, None)
        with StringIO() as license_txt:
            in_license = False
            in_download = False
            for line in result[self.download_page].buffer:
                line_content = line.decode()

                if self.expect_license:
                    in_license = self.parse_license(line_content, license_txt, in_license)

                (download, in_download) = self.parse_download_link(line_content, in_download)
                if download is not None:
                    (newurl, newmd5sum) = download
                    url = newurl if newurl is not None else url
                    md5sum = newmd5sum if newmd5sum is not None else md5sum
                    logger.debug("Found download link for {}, md5sum: {}".format(url, md5sum))

            if url is None or (self.require_md5 and md5sum is None):
                logger.error("Download page changed its syntax or is not parsable")
                UI.return_main_screen()
            self.download_requests.append((url, md5sum))

            if license_txt.getvalue() != "":
                logger.debug("Check license agreement.")
                UI.display(LicenseAgreement(strip_tags(license_txt.getvalue()).strip(),
                                            self.start_download_and_install,
                                            UI.return_main_screen))
            elif self.expect_license:
                logger.error("We were expecting to find a license on the download page, we didn't.")
                UI.return_main_screen()
            else:
                self.start_download_and_install()
        return
    def decompress_and_install_done(self, result):
        self._install_done = True
        error_detected = False
        for fd in result:
            if result[fd].error:
                logger.error(result[fd].error)
                error_detected = True
            fd.close()
        if error_detected:
            UI.return_main_screen()
            return

        # install desktop file
        if self.desktop_file_name:
            self.create_launcher()

        UI.delayed_display(DisplayMessage("Installation done"))
        UI.return_main_screen()
    def remove(self):
        """Remove current framework if installed

        Not that we only remove desktop file, launcher icon and dir content, we do not remove
        packages as they might be in used for other framework"""
        # check if it's installed and so on.
        super().remove()

        UI.display(DisplayMessage("Removing {}".format(self.name)))
        if self.desktop_filename:
            with suppress(FileNotFoundError):
                os.remove(get_launcher_path(self.desktop_filename))
        if self.icon_filename:
            with suppress(FileNotFoundError):
                os.remove(get_icon_path(self.icon_filename))
        with suppress(FileNotFoundError):
            shutil.rmtree(self.install_path)
        self.remove_from_config()

        UI.delayed_display(DisplayMessage("Suppression done"))
        UI.return_main_screen()
 def test_return_to_mainscreen(self):
     """We call the return to main screen on the UIPlug"""
     UI.return_main_screen()
     self.assertTrue(self.mockUIPlug._return_main_screen.called)
 def run_display(future):
     nonlocal now
     self.function_thread = threading.current_thread().ident
     now = time()
     UI.delayed_display(self.contentType)
 def run_display(future):
     self.function_thread = threading.current_thread().ident
     UI.display(self.contentType)
 def remove(self):
     """Method call to remove the current framework"""
     if not self.is_installed:
         logger.error(_("You can't remove {} as it isn't installed".format(self.name)))
         UI.return_main_screen(status_code=1)
         return