Example #1
0
    def _extract_update(self):
        with ChDir(self.update_folder):
            if not os.path.exists(self.filename):
                log.debug('File does not exists')
                raise ClientError('File does not exists', expected=True)

            verified = self._verify_file_hash()
            if verified:
                log.debug('Extracting Update')
                archive_ext = os.path.splitext(self.filename)[1].lower()

                if archive_ext == '.gz':
                    try:
                        with tarfile.open(self.filename, 'r:gz') as tfile:
                            # Extract file update to current
                            # directory.
                            tfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError('Error reading gzip file')
                elif archive_ext == '.zip':
                    try:
                        with zipfile.ZipFile(self.filename, 'r') as zfile:
                            # Extract update file to current
                            # directory.
                            zfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError('Error reading zip file')
                else:
                    raise ClientError('Unknown filetype')
            else:
                raise ClientError('Update archive is corrupt')
Example #2
0
    def _extract_update(self):
        with jms_utils.paths.ChDir(self.update_folder):
            if not os.path.exists(self.filename):
                log.error('File does not exists')
                raise ClientError('File does not exists', expected=True)

            log.info('Extracting Update')
            archive_ext = os.path.splitext(self.filename)[1].lower()
            # Handles extracting gzip or zip archives
            if archive_ext == '.gz':
                try:
                    with tarfile.open(self.filename, 'r:gz') as tfile:
                        # Extract file update to current
                        # directory.
                        tfile.extractall()
                except Exception as err:  # pragma: no cover
                    log.error(err)
                    log.debug(err, exc_info=True)
                    raise ClientError('Error reading gzip file')
            elif archive_ext == '.zip':
                try:
                    with zipfile.ZipFile(self.filename, 'r') as zfile:
                        # Extract update file to current
                        # directory.
                        zfile.extractall()
                except Exception as err:  # pragma: no cover
                    log.error(err)
                    log.debug(err, exc_info=True)
                    raise ClientError('Error reading zip file')
            else:
                raise ClientError('Unknown filetype')
Example #3
0
    def _extract_update(self):
        with jms_utils.paths.ChDir(self.update_folder):
            platform_name = self.name
            # Ensuring we only add .exe when applicable
            if sys.platform == 'win32' and \
                    self.name == self.app_name:  # pragma: no cover
                # We only add .exe to app executable.  Not libs or dll
                log.debug('Adding .exe to filename for windows main '
                          'app udpate.')
                platform_name += '.exe'

            # Ensuring we extract the latest version
            latest = get_highest_version(self.name, self.platform,
                                         self.easy_data)
            # Get full filename of latest update archive
            filename = get_filename(self.name, latest, self.platform,
                                    self.easy_data)
            if not os.path.exists(filename):
                log.error('File does not exists')
                raise ClientError('File does not exists')

            log.info('Extracting Update')
            archive_ext = os.path.splitext(filename)[1].lower()
            # Handles extracting gzip or zip archives
            if archive_ext == '.gz':
                try:
                    with tarfile.open(filename, 'r:gz') as tfile:
                        # Extract file update to current
                        # directory.
                        tfile.extractall()
                except Exception as err:  # pragma: no cover
                    log.error(err)
                    log.debug(str(err), exc_info=True)
                    raise ClientError('Error reading gzip file')
            elif archive_ext == '.zip':
                try:
                    with zipfile.ZipFile(filename, 'r') as zfile:
                        # Extract update file to current
                        # directory.
                        zfile.extractall()
                except Exception as err:  # pragma: no cover
                    log.error(str(err))
                    log.debug(str(err), exc_info=True)
                    raise ClientError('Error reading zip file')
            else:
                raise ClientError('Unknown filetype')
Example #4
0
    def __init__(self, obj, **kwargs):

        refresh = kwargs.get('refresh')
        progress_hooks = kwargs.get('progress_hooks')
        test = kwargs.get('test')
        data_dir = kwargs.get('data_dir')
        headers = kwargs.get('headers')

        if headers is not None:
            if not isinstance(headers, dict):
                raise ClientError('headers argument must be a dict',
                                  expected=True)

        # String: Name of binary to update
        self.name = None

        # String: Version of the binary to update
        self.version = None

        # String: Update manifest as json string - set in _get_update_manifest
        self.json_data = None

        # Boolean: Version file verification
        self.verified = False

        # Boolean: Json being loaded to dict
        self.ready = False

        # LIst: Progress hooks to be called
        self.progress_hooks = []
        if progress_hooks is not None:
            if not isinstance(progress_hooks, list):
                raise SyntaxError('progress_hooks must be provided as a list.')
            self.progress_hooks += progress_hooks

        # Client config obj with settings to find & verify updates
        if obj is not None:
            obj.URLLIB3_HEADERS = headers
            self.init_app(obj, refresh, test, data_dir)
Example #5
0
    def _win_rename(self):
        exe_name = self.name + ".exe"
        current_app = os.path.join(self._current_app_dir, exe_name)
        old_exe_name = exe_name + ".old"
        old_app = os.path.join(self._current_app_dir, old_exe_name)
        updated_app = os.path.join(self.update_folder, exe_name)

        # detect if is a folder
        if os.path.exists(os.path.join(self.update_folder, self.name)):
            raise ClientError(
                "The rename strategy is only supported for one file bundled executables"
            )

        # Remove the old app from previous updates
        if os.path.exists(old_app):
            os.unlink(old_app)

        # On Windows, it's possible to rename a currently running exe file
        os.rename(current_app, old_app)

        # Any operation from here forward will require rollback on failure
        try:
            os.rename(updated_app, current_app)
        except OSError as e:
            log.error("Failed to move updated app into position, rolling back")
            # Rollback strategy: move current app back into position
            if os.path.exists(current_app):
                os.unlink(current_app)
            os.rename(old_app, current_app)
            raise e

        try:
            # Hide the old app
            win_hide_file(old_app)
        except WindowsError as e:
            # Failed to hide file, which is fine - we can still continue
            log.error("Failed to hide file")

        return old_app, current_app, updated_app
Example #6
0
    def _extract_update(self):
        with ChDir(self.update_folder):
            if not os.path.exists(self.filename):
                log.debug("File does not exists")
                raise ClientError("File does not exists", expected=True)

            if not os.access(self.filename, os.R_OK):
                raise ClientError("Permissions Error", expected=True)

            if self._verify_file_hash():
                log.debug("Extracting Update")
                archive_ext = os.path.splitext(self.filename)[1].lower()

                if archive_ext in [".gz", ".bz2"]:
                    try:
                        mode = "r:{}".format(archive_ext[1:])
                        with tarfile.open(self.filename, mode) as tfile:
                            # Extract file update to current
                            # directory.
                            tfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError("Error reading gzip file",
                                          expected=True)
                elif archive_ext == ".zip":
                    try:
                        with zipfile.ZipFile(self.filename, "r") as zfile:
                            # Extract update file to current
                            # directory.
                            zfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError("Error reading zip file",
                                          expected=True)
                else:
                    raise ClientError("Unknown file type")
            else:
                raise ClientError("Update archive is corrupt")
Example #7
0
    def _extract_update(self):
        with ChDir(self.update_folder):
            if not os.path.exists(self.filename):
                log.debug('File does not exists')
                raise ClientError('File does not exists', expected=True)

            if not os.access(self.filename, os.R_OK):
                raise ClientError('Permissions Error', expected=True)

            if self._verify_file_hash():
                log.debug('Extracting Update')
                archive_ext = os.path.splitext(self.filename)[1].lower()

                if archive_ext in ['.gz', '.bz2']:
                    try:
                        mode = 'r:{}'.format(archive_ext[1:])
                        with tarfile.open(self.filename, mode) as tfile:
                            # Extract file update to current
                            # directory.
                            tfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError('Error reading gzip file',
                                          expected=True)
                elif archive_ext == '.zip':
                    try:
                        with zipfile.ZipFile(self.filename, 'r') as zfile:
                            # Extract update file to current
                            # directory.
                            zfile.extractall()
                    except Exception as err:  # pragma: no cover
                        log.debug(err, exc_info=True)
                        raise ClientError('Error reading zip file',
                                          expected=True)
                else:
                    raise ClientError('Unknown file type')
            else:
                raise ClientError('Update archive is corrupt')
Example #8
0
    def __init__(self, obj, **kwargs):
        if obj is None:
            obj = DefaultClientConfig()

        refresh = kwargs.get("refresh", False)
        progress_hooks = kwargs.get("progress_hooks")
        test = kwargs.get("test", False)
        data_dir = kwargs.get("data_dir")
        headers = kwargs.get("headers")

        # 3rd Party downloader
        self.downloader = kwargs.get("downloader")

        if headers is not None:
            if not isinstance(headers, dict):
                raise ClientError("headers argument must be a dict", expected=True)

        # String: Name of binary to update
        self.name = None

        # String: Version of the binary to update
        self.version = None

        # String: Update manifest as json string - set in _get_update_manifest
        self.json_data = None

        # Boolean: Version file verification
        self.verified = False

        # Boolean: Json being loaded to dict
        self.ready = False

        # LIst: Progress hooks to be called
        self.progress_hooks = []
        if progress_hooks is not None:
            if not isinstance(progress_hooks, list):
                raise SyntaxError("progress_hooks must be provided as a list.")
            self.progress_hooks += progress_hooks

        obj.URLLIB3_HEADERS = headers

        # A super dict used to save config info & be dot accessed
        config = _Config()
        config.from_object(obj)

        # Boolean: If executing frozen
        self.FROZEN = FROZEN

        # Grabbing config information
        update_urls = config.get("UPDATE_URLS", [])

        # List of URL to check for update data
        self.update_urls = Client._sanitize_update_url(update_urls)

        # Name of the running application
        self.app_name = config.get("APP_NAME", "PyUpdater")

        # Name of the app author
        self.company_name = config.get("COMPANY_NAME", "Digital Sapphire")

        # Used in testing to force use of the mac archive
        if test:
            # Making platform deterministic for tests.
            self.data_dir = obj.DATA_DIR
            self.platform = "mac"
        else:  # pragma: no cover
            if data_dir is None:
                # Getting platform specific user data directory
                self.data_dir = appdirs.user_data_dir(self.app_name, self.company_name)
            else:
                self.data_dir = data_dir

            # Used when parsing the update manifest
            self.platform = _get_system()

        if six.PY2:
            self.data_dir = self.data_dir.decode("utf-8")

        # Folder to house update archives
        self.update_folder = os.path.join(self.data_dir, settings.UPDATE_FOLDER)

        # The root public key to verify the app signing private key
        self.root_key = config.get("PUBLIC_KEY", "")

        # We'll get the app_key later in _get_signing_key
        # That's if we verify the keys manifest
        self.app_key = None

        # Used to disable TLS cert verification
        self.verify = config.get("VERIFY_SERVER_CERT", True)

        # Max number of download retries
        self.max_download_retries = config.get("MAX_DOWNLOAD_RETRIES", 3)

        # HTTP Timeout
        self.http_timeout = config.get("HTTP_TIMEOUT", 30)

        # The name of the version file to download
        self.version_file = settings.VERSION_FILE_FILENAME

        # The name of the original version of the version file.
        # Basically the version.gz vs vesion-<platform>.gz
        self.version_file_compat = settings.VERSION_FILE_FILENAME_COMPAT

        # The name of the key file to download
        self.key_file = settings.KEY_FILE_FILENAME

        # urllib3 headers
        self.urllib3_headers = obj.URLLIB3_HEADERS

        # Creating data & update directories
        self._setup()

        if refresh is True:
            self.refresh()