Ejemplo n.º 1
0
 def test_extract_no_file(self, client):
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.download() is True
     with ChDir(update.update_folder):
         files = os.listdir(os.getcwd())
         for f in files:
             remove_any(f)
     if get_system() != 'win':
         assert update.extract() is False
Ejemplo n.º 2
0
def main(use_custom_dir, port, windowed):
    scripts = [('app_restart_onedir.py', '4.1',
                '--windowed' if windowed else ''),
               ('app_restart_02.py', '4.2',
                '--windowed' if windowed else '')]

    # We use this flag to untar & move our binary to the
    # current working directory
    first = True
    # patch config_file for custom port number
    config_file = open('client_config.py', 'rt').read()
    config_file = re.sub(
        'localhost:\d+', 'localhost:%s' % port, config_file)
    # patch config_file for use_custom_dir
    if use_custom_dir:
        config_file += '\n    USE_CUSTOM_DIR = True\n'
    open('client_config.py', 'wt').write(config_file)
    for s in scripts:
        build(s)
        if first:
            if sys.platform == 'win32':
                ext = '.zip'
            else:
                ext = '.tar.gz'

            # Build path to archive
            archive_path = os.path.join('pyu-data', 'new',
                                        'Acme-{}-4.1{}'.format(get_system(),
                                                               ext))

            if not os.path.exists(archive_path):
                print("Archive did not build!")
                sys.exit(1)

            # We extract the Acme binary here. When we call pyupdater pkg -P
            # the Acme binary will be moved to the deploy folder. In our test
            # (test_pyupdater.TestExecution.test_execution_update_*) we
            # move all of the files from the deploy directory to the cwd
            # of the test runner.
            extract(archive_path)

            first = False

        os.system(cmd1)

    os.system(cmd2)
Ejemplo n.º 3
0
    def _restart(self):
        log.debug('Restarting')
        current_app = os.path.join(self._current_app_dir, self.name)
        if get_system() == 'mac':
            # Must be dealing with Mac .app application
            if not os.path.exists(current_app):
                log.debug('Must be a .app bundle')
                current_app += '.app'
                mac_app_binary_dir = os.path.join(current_app, 'Contents',
                                                  'MacOS')
                _file = os.listdir(mac_app_binary_dir)

                # We are making an assumption here that only 1
                # executable will be in the MacOS folder.
                current_app = os.path.join(mac_app_binary_dir, sys.executable)

        r = Restarter(current_app, name=self.name)
        r.process()
Ejemplo n.º 4
0
    def extract(self):
        """Will extract the update from its archive to the update folder.
        If updating a lib you can take over from there. If updating
        an app this call should be followed by method "restart" to
        complete update.

        ######Returns:

            (bool) True - Extract successful. False - Extract failed.
        """
        if get_system() == 'win':  # Tested elsewhere
            log.debug('Only supported on Unix like systems')
            return False
        try:
            self._extract_update()
        except ClientError as err:
            log.debug(err, exc_info=True)
            return False
        return True
Ejemplo n.º 5
0
def main(use_custom_dir, port, windowed):
    scripts = [('app_restart_01.py', '4.1', '--windowed' if windowed else ''),
               ('app_restart_02.py', '4.2', '--windowed' if windowed else '')]

    # We use this flag to untar & move our binary to the
    # current working directory
    first = True
    # patch config_file for custom port number
    config_file = open('client_config.py', 'rt').read()
    config_file = re.sub('localhost:\d+', 'localhost:%s' % port, config_file)
    # patch config_file for use_custom_dir
    if use_custom_dir:
        config_file += '\n    USE_CUSTOM_DIR = True\n'
    open('client_config.py', 'wt').write(config_file)
    for s in scripts:
        build(s)
        if first:
            if sys.platform == 'win32':
                ext = '.zip'
            else:
                ext = '.tar.gz'

            # Build path to archive
            archive_path = os.path.join(
                'pyu-data', 'new', 'Acme-{}-4.1{}'.format(get_system(), ext))

            if not os.path.exists(archive_path):
                print("Archive did not build!")
                sys.exit(1)

            # We extract the Acme binary here. When we call pyupdater pkg -P
            # the Acme binary will be moved to the deploy folder. In our test
            # (test_pyupdater.TestExecution.test_execution_update_*) we
            # move all of the files from the deploy directory to the cwd
            # of the test runner.
            extract(archive_path)

            first = False

        os.system(cmd1)

    os.system(cmd2)
Ejemplo n.º 6
0
    def build(self):
        start = time.time()
        temp_name = get_system()
        # Check for spec file or python script
        self._setup()
        spec_file_path = os.path.join(self.spec_dir, temp_name + '.spec')

        # Spec file used instead of python script
        if self.app_info['type'] == 'spec':
            spec_file_path = self.app_info['name']
        else:
            # Creating spec file from script
            self._make_spec(self.pyi_args, temp_name, self.app_info)

        # Build executable
        self._build(self.args, spec_file_path)
        # Archive executable
        self._archive(self.args, temp_name)
        finished = time.time() - start
        msg = 'Build finished in {:.2f} seconds.'.format(finished)
        log.info(msg)
Ejemplo n.º 7
0
    def _overwrite(self):
        # Unix: Overwrites the running applications binary
        if get_system() == 'mac':
            if self._current_app_dir.endswith('MacOS') is True:
                log.debug('Looks like we\'re dealing with a Mac Gui')
                temp_dir = get_mac_dot_app_dir(self._current_app_dir)
                self._current_app_dir = temp_dir

        app_update = os.path.join(self.update_folder, self.name)

        # Must be dealing with Mac .app application
        if not os.path.exists(app_update) and sys.platform == "darwin":
            app_update += '.app'

        log.debug('Update Location:\n%s', os.path.dirname(app_update))
        log.debug('Update Name: %s', os.path.basename(app_update))

        current_app = os.path.join(self._current_app_dir, self.name)

        # Must be dealing with Mac .app application
        if not os.path.exists(current_app):
            current_app += '.app'

        log.debug('Current App location:\n\n%s', current_app)

        # Remove current app to prevent errors when moving
        # update to new location
        # if update_app is a directory, then we are updating a directory
        if os.path.isdir(app_update):
            if (os.path.isdir(current_app)):
                shutil.rmtree(current_app)
            else:
                shutil.rmtree(os.path.dirname(current_app))

        if os.path.exists(current_app):
            remove_any(current_app)

        log.debug('Moving app to new location:\n\n%s', self._current_app_dir)
        shutil.move(app_update, self._current_app_dir)
Ejemplo n.º 8
0
    def _overwrite(self):
        # Unix: Overwrites the running applications binary
        if get_system() == 'mac':
            if self._current_app_dir.endswith('MacOS') is True:
                log.debug('Looks like we\'re dealing with a Mac Gui')
                temp_dir = get_mac_dot_app_dir(self._current_app_dir)
                self._current_app_dir = temp_dir

        app_update = os.path.join(self.update_folder, self.name)

        # Must be dealing with Mac .app application
        if not os.path.exists(app_update) and sys.platform == "darwin":
            app_update += '.app'

        log.debug('Update Location:\n%s', os.path.dirname(app_update))
        log.debug('Update Name: %s', os.path.basename(app_update))

        current_app = os.path.join(self._current_app_dir, self.name)

        # Must be dealing with Mac .app application
        if not os.path.exists(current_app):
            current_app += '.app'

        log.debug('Current App location:\n\n%s', current_app)

        # Remove current app to prevent errors when moving
        # update to new location
        # if update_app is a directory, then we are updating a directory
        if os.path.isdir(app_update):
            if (os.path.isdir(current_app)):
                shutil.rmtree(current_app)
            else:
                shutil.rmtree(os.path.dirname(current_app))

        if os.path.exists(current_app):
            remove_any(current_app)

        log.debug('Moving app to new location:\n\n%s', self._current_app_dir)
        shutil.move(app_update, self._current_app_dir)
Ejemplo n.º 9
0
    def build(self):
        start = time.time()

        # Check for spec file or python script
        self._setup()

        temp_name = get_system()
        spec_file_path = os.path.join(self.spec_dir, temp_name + ".spec")

        # Spec file used instead of python script
        if self.app_info["type"] == "spec":
            spec_file_path = self.app_info["name"]
        else:
            # Creating spec file from script
            self._make_spec(temp_name)

        # Build executable
        self._build(spec_file_path)

        # Archive executable
        self._archive(temp_name)
        finished = time.time() - start
        log.info("Build finished in {:.2f} seconds.".format(finished))
Ejemplo n.º 10
0
    def extract(self):
        """Will extract the update from its archive to the update folder.
        If updating a lib you can take over from there. If updating
        an app this call should be followed by method "restart" to
        complete update.

        Returns:

            (bool) Meanings:

                True - Extract successful

                False - Extract failed
        """
        if get_system() == 'win':  # Tested elsewhere
            log.debug('Only supported on Unix like systems')
            return False
        try:
            self._extract_update()
        except ClientError as err:
            log.debug(err, exc_info=True)
            return False
        return True
Ejemplo n.º 11
0
 def test_archive(self):
     with io.open('test', 'w', encoding='utf-8') as f:
         f.write('this is a test')
     ex = ExternalLib('test', '0.1')
     ex.archive()
     assert os.path.exists('test-{}-0.1{}'.format(get_system(), EXT))
Ejemplo n.º 12
0
 def make_spec(self):
     temp_name = get_system()
     self._make_spec(temp_name, spec_only=True)
Ejemplo n.º 13
0
 def test_extract(self, client):
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.download() is True
     if get_system() != 'win':
         assert update.extract() is True
Ejemplo n.º 14
0
import os
import tempfile

import bsdiff4
from dsdev_utils.crypto import get_package_hashes
from dsdev_utils.helpers import EasyAccessDict, Version
from dsdev_utils.paths import ChDir, remove_any
from dsdev_utils.system import get_system

from pyupdater.client.downloader import FileDownloader
from pyupdater import settings
from pyupdater.utils.exceptions import PatcherError

log = logging.getLogger(__name__)

_PLATFORM = get_system()


class Patcher(object):
    """Downloads, verifies, and patches binaries

    Kwargs:

        name (str): Name of binary to patch

        json_data (dict): Info dict with all package meta data

        current_version (str): Version number of currently installed binary

        latest_version (str): Newest version available
Ejemplo n.º 15
0
 def test_archive(self):
     with io.open('test', 'w', encoding='utf-8') as f:
         f.write('this is a test')
     ex = ExternalLib('test', '0.1')
     ex.archive()
     assert os.path.exists('test-{}-0.1{}'.format(get_system(), EXT))
Ejemplo n.º 16
0
 def test_archive(self):
     with io.open("test", "w", encoding="utf-8") as f:
         f.write("this is a test")
     ex = ExternalLib("test", "0.1")
     ex.archive()
     assert os.path.exists("test-{}-0.1{}".format(get_system(), EXT))
Ejemplo n.º 17
0
    def test_freeze_update_available(self):
        """
        Test ability to freeze and run app with an update available.
        """
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements

        # PyUpdater uses PyInstaller under the hood.  We will customize
        # the command-line arguments PyUpdater sends to PyInstaller.

        # The SocketServer module (used by werkzeug, which is used by Flask)
        # doesn't seem to get detected automatically by PyInstaller (observed
        # on Windows), so we add this as a hidden import.

        pyiArgs = ['--hidden-import=SocketServer', 'run.py']

        if get_system() == 'mac':
            # On Mac, we need to use PyInstaller's --windowed option to create
            # an app bundle, otherwise attempting to run the frozen application
            # gives this error:
            #
            #     This program needs access to the screen.
            #     Please run with a Framework build of python, and only when
            #     you are logged in on the main display of your Mac.
            #
            # On other platforms, we will build a console application for the
            # purposes of testing, so that we can easily interact with its
            # STDOUT and STDERR:
            pyiArgs = ['--windowed'] + pyiArgs
        else:
            pyiArgs = ['--console'] + pyiArgs
        wxupdatedemo.__version__ = CURRENT_VERSION
        args = Namespace(app_version=CURRENT_VERSION,
                         clean=False,
                         command='build',
                         distpath=None,
                         keep=False,
                         name=None,
                         onedir=False,
                         onefile=False,
                         specpath=None,
                         workpath=None)
        builder = Builder(args, pyiArgs)
        builder.build()
        if get_system() == 'win':
            ext = '.zip'
        else:
            ext = '.tar.gz'
        buildFilename = \
            '%s-%s-%s%s' % (APP_NAME, get_system(), CURRENT_VERSION, ext)
        newDir = os.path.join(settings.USER_DATA_FOLDER, 'new')
        self.assertEqual(os.listdir(newDir), [buildFilename])
        os.chdir(newDir)
        if get_system() == 'win':
            with zipfile.ZipFile(buildFilename, 'r') as zipFile:
                zipFile.extractall()
            pathToExe = '%s.exe' % APP_NAME
            self.assertEqual(sorted(os.listdir('.')),
                             [buildFilename, pathToExe])
        elif get_system() == 'mac':
            tar = tarfile.open(buildFilename, "r:gz")
            tar.extractall()
            tar.close()
            appBundleName = '%s.app' % APP_NAME
            self.assertEqual(sorted(os.listdir('.')),
                             [buildFilename, appBundleName])
            pathToExe = os.path.join(newDir, '%s.app' % APP_NAME, 'Contents',
                                     'MacOS', APP_NAME)
        else:  # Linux / Unix
            tar = tarfile.open(buildFilename, "r:gz")
            tar.extractall()
            tar.close()
            pathToExe = os.path.join(newDir, APP_NAME)

        sys.stderr.write("\n\nTesting ability to apply patch update...\n")

        cmdList = [pathToExe, '--debug']
        runExeProc = subprocess.Popen(cmdList,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      env=os.environ.copy())
        runExeStdout, _ = runExeProc.communicate()
        logger.debug(runExeStdout)
        self.assertEqual(runExeProc.returncode, 0)
        appliedPatchSuccessfully = False
        statusPrefix = "Exiting with status: "
        for line in runExeStdout.splitlines():
            if "Applied patch successfully" in line:
                sys.stderr.write("\t%s\n" % line)
                appliedPatchSuccessfully = True
            if line.startswith("Exiting with status: "):
                sys.stderr.write("\t%s\n" % line)
                status = line.split(statusPrefix)[1]
                self.assertEqual(status, "Extracting update and restarting.")
        self.assertTrue(appliedPatchSuccessfully)

        # Remove all local data from previous PyUpdater downloads:
        if os.path.exists(appdirs.user_data_dir(APP_NAME, COMPANY_NAME)):
            shutil.rmtree(appdirs.user_data_dir(APP_NAME, COMPANY_NAME))
        # Now we can't patch because there's no base binary to patch from:
        sys.stderr.write("\nTesting ability to download full update...\n")
        runExeProc = subprocess.Popen(cmdList,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      env=os.environ.copy())
        runExeStdout, _ = runExeProc.communicate()
        logger.debug(runExeStdout)
        self.assertEqual(runExeProc.returncode, 0)
        fullDownloadSuccessful = False
        statusPrefix = "Exiting with status: "
        for line in runExeStdout.splitlines():
            if "Full download successful" in line:
                sys.stderr.write("\t%s\n" % line)
                fullDownloadSuccessful = True
            if line.startswith("Exiting with status: "):
                sys.stderr.write("\t%s\n" % line)
                status = line.split(statusPrefix)[1]
                self.assertEqual(status, "Extracting update and restarting.")
        self.assertTrue(fullDownloadSuccessful)

        # Remove all local data from previous PyUpdater downloads:
        if os.path.exists(appdirs.user_data_dir(APP_NAME, COMPANY_NAME)):
            shutil.rmtree(appdirs.user_data_dir(APP_NAME, COMPANY_NAME))
        # Remove update archive from file server:
        os.remove(os.path.join(self.fileServerDir, self.updateFilename))
        # Now attempting to update should fail - can't download update.
        sys.stderr.write(
            "\nTesting ability to report failed download of update...\n")
        runExeProc = subprocess.Popen(cmdList,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      env=os.environ.copy())
        runExeStdout, _ = runExeProc.communicate()
        logger.debug(runExeStdout)
        self.assertEqual(runExeProc.returncode, 0)
        statusPrefix = "Exiting with status: "
        fullDownloadFailed = False
        for line in runExeStdout.splitlines():
            if "Full download failed" in line:
                sys.stderr.write("\t%s\n" % line)
                fullDownloadFailed = True
            if line.startswith("Exiting with status: "):
                sys.stderr.write("\t%s\n" % line)
                status = line.split(statusPrefix)[1]
                self.assertEqual(status, "Update download failed.")
        self.assertTrue(fullDownloadFailed)
Ejemplo n.º 18
0
 def make_spec(self):
     temp_name = get_system()
     self._make_spec(self.pyi_args, temp_name,
                     self.app_info, spec_only=True)
Ejemplo n.º 19
0
import os

import pytest
from dsdev_utils.system import get_system

from pyupdater import PyUpdater
from pyupdater.utils.config import Config
from tconfig import TConfig


def create_build_cmd(version):
    cmd = ['build', '--app-name', 'myapp', '--app-version',
           '0.1.{}'.format(version), 'app.py', '-F']
    return cmd

if get_system() == 'win':
    ext = '.zip'
else:
    ext = '.tar.gz'


@pytest.mark.usefixtures('cleandir', 'create_keypack', 'pyu')
class TestUtils(object):

    def test_setup(self):
        data_dir = os.getcwd()
        pyu_data_dir = os.path.join(data_dir, 'pyu-data')
        t_config = TConfig()
        t_config.DATA_DIR = data_dir
        pyu = PyUpdater(t_config)
        pyu.setup()
Ejemplo n.º 20
0
 def __init__(self, data):
     self._is_win = get_system() == 'win'
     super(AppUpdate, self).__init__(data)
Ejemplo n.º 21
0
 def gen_archive_name(version):
     archive_name = 'myapp-{}-0.1.{}{}'.format(get_system(),
                                               version, ext)
     return archive_name
Ejemplo n.º 22
0
__version__ = "0.0.3"
__app__ = "PyQt-Updater"
__author__ = "liuzixuan"
__develop__ = True
__asset_update_log__ = "updatelog"
__download_folder_win__ = "/Users/chihuen/PycharmProjects/PyQt-Updater/download"
__download_folder_mac__ = "/Users/chihuen/PycharmProjects/PyQt-Updater/download"
__download_folder__ = ''

__develop_server_host__ = '127.0.0.1'
__develop_update_url__ = ['http://127.0.0.1:2664/Update/']
__develop_server_root__ = 'root'
__develop_server_password__ = ''

__release_server_host__ = '127.0.0.1'
__release_update_url__ = ['http://127.0.0.1:2664/Update/']
__release_server_root__ = 'root'
__release_server_password__ = ''

from dsdev_utils.system import get_system
if get_system() == 'win':
    __download_folder__ = __download_folder_win__
else:
    __download_folder__ = __download_folder_mac__
Ejemplo n.º 23
0
 def __init__(self, data):
     self._is_win = get_system() == 'win'
     super(AppUpdate, self).__init__(data)
Ejemplo n.º 24
0
 def test_extract(self, client):
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.download() is True
     if get_system() != 'win':
         assert update.extract() is True
Ejemplo n.º 25
0
CONFIG_DB_KEY_APP_CONFIG = "app_config"
CONFIG_DB_KEY_KEYPACK = "keypack"
CONFIG_DB_KEY_VERSION_META = "version_meta"
CONFIG_DB_KEY_PY_REPO_CONFIG = "py_repo_config"

DEFAULT_CLIENT_CONFIG = ["client_config.py"]

GENERIC_APP_NAME = "PyUpdater App"
GENERIC_COMPANY_NAME = "PyUpdater"

# Log filename
LOG_FILENAME_DEBUG = "pyu-debug.log"

# KeyFile
KEYPACK_FILENAME = "keypack.pyu"

# Main user visible data folder
USER_DATA_FOLDER = "pyu-data"

# Key in version file where value are update meta data
UPDATES_KEY = "updates"

# Folder on client system where updates are stored
UPDATE_FOLDER = "update"

# Name of version file in online repo
VERSION_FILE_FILENAME = "versions-{}.gz".format(system.get_system())
VERSION_FILE_FILENAME_COMPAT = "versions.gz"
KEY_FILE_FILENAME = "keys.gz"
Ejemplo n.º 26
0
def make_archive(name, target, version, archive_format):
    """Used to make archives of file or dir. Zip on windows and tar.gz
    on all other platforms

    Args:
        name - Name to rename binary.

        version - Version of app. Used to create archive filename

        target - Name of file to archive.

    Returns:
         (str) - name of archive
    """
    log.debug('starting archive')
    ext = os.path.splitext(target)[1]
    temp_file = name + ext
    log.debug('Temp file: %s', temp_file)
    # Remove file if it exists. Found during testing...
    if os.path.exists(temp_file):
        paths.remove_any(temp_file)

    if os.path.isfile(target):
        shutil.copy(target, temp_file)
    else:
        shutil.copytree(target, temp_file, symlinks=True)
        # renames the entry-point executable
        file_ext = '.exe' if system.get_system() == 'win' else ''
        src_executable = temp_file + os.sep + target + file_ext
        dst_executable = temp_file + os.sep + name + file_ext
        # is an osx bundle app so does not need to fix the executable name
        if ext != '.app':
            shutil.move(src_executable, dst_executable)

        # is a win folder so the manifest need to be renamed too
        if system.get_system() == 'win':
            src_manifest = src_executable + '.manifest'
            dst_manifest = dst_executable + '.manifest'
            shutil.move(src_manifest, dst_manifest)

    file_dir = os.path.dirname(os.path.abspath(target))
    filename = '{}-{}-{}'.format(
        os.path.splitext(name)[0], system.get_system(), version)
    # Only use zip on windows.
    # Zip does not preserve file permissions on nix & mac
    # tar.gz creates full file path
    with paths.ChDir(file_dir):
        ext = 'gztar'
        if archive_format == 'default':
            if system.get_system() == 'win':
                ext = 'zip'
        else:
            ext = archive_format
        output_filename = shutil.make_archive(filename, ext, file_dir,
                                              temp_file)

    if os.path.exists(temp_file):
        paths.remove_any(temp_file)

    log.debug('Archive output filename: %s', output_filename)
    return output_filename
Ejemplo n.º 27
0
import os
import tempfile

import bsdiff4
from dsdev_utils.crypto import get_package_hashes
from dsdev_utils.helpers import EasyAccessDict, Version
from dsdev_utils.paths import ChDir, remove_any
from dsdev_utils.system import get_system

from pyupdater.client.downloader import FileDownloader
from pyupdater import settings
from pyupdater.utils.exceptions import PatcherError

log = logging.getLogger(__name__)

_PLATFORM = get_system()


class Patcher(object):
    """Downloads, verifies, and patches binaries

    Kwargs:

        name (str): Name of binary to patch

        json_data (dict): Info dict with all package meta data

        current_version (str): Version number of currently installed binary

        latest_version (str): Newest version available
Ejemplo n.º 28
0
    def setUp(self):
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-locals
        self.initialWorkingDir = os.getcwd()

        userDataDir = appdirs.user_data_dir(APP_NAME, COMPANY_NAME)
        if os.path.exists(userDataDir):
            shutil.rmtree(userDataDir)
        os.makedirs(userDataDir)
        versionsUserDataFilePath = os.path.join(userDataDir, 'versions.gz')
        userDataUpdateDir = os.path.join(userDataDir, "update")
        os.mkdir(userDataUpdateDir)
        system = get_system()
        self.currentFilename = \
            VERSIONS['updates'][APP_NAME][CURRENT_VERSION_PYU_FORMAT]\
            [system]['filename']
        currentFilePath = os.path.join(userDataUpdateDir, self.currentFilename)
        with open(currentFilePath, "wb") as currentFile:
            currentFile.write("%s" % CURRENT_VERSION)
            currentFile.seek(FILE_SIZE - 1)
            currentFile.write("\0")
        fileHash = get_package_hashes(currentFilePath)
        VERSIONS['updates'][APP_NAME][CURRENT_VERSION_PYU_FORMAT]\
            [system]['file_hash'] = fileHash

        tempFile = tempfile.NamedTemporaryFile()
        self.fileServerDir = tempFile.name
        tempFile.close()
        os.mkdir(self.fileServerDir)
        os.chdir(self.fileServerDir)

        self.updateFilename = \
            VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\
            [system]['filename']
        with open(self.updateFilename, "wb") as updateFile:
            updateFile.write("%s" % UPDATE_VERSION)
            updateFile.seek(FILE_SIZE - 1)
            updateFile.write("\0")
        os.chdir(self.fileServerDir)
        fileHash = get_package_hashes(self.updateFilename)
        VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\
            [system]['file_hash'] = fileHash
        self.patchFilename = \
            VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\
            [system]['patch_name']
        bsdiff4.file_diff(currentFilePath, self.updateFilename,
                          self.patchFilename)
        os.chdir(self.fileServerDir)
        fileHash = get_package_hashes(self.patchFilename)
        VERSIONS['updates'][APP_NAME][UPDATE_VERSION_PYU_FORMAT]\
            [system]['patch_hash'] = fileHash
        os.chdir(self.initialWorkingDir)
        privateKey = ed25519.SigningKey(PRIVATE_KEY.encode('utf-8'),
                                        encoding='base64')
        signature = privateKey.sign(six.b(json.dumps(VERSIONS,
                                                     sort_keys=True)),
                                    encoding='base64').decode()
        VERSIONS['signature'] = signature
        keysFilePath = os.path.join(self.fileServerDir, 'keys.gz')
        with gzip.open(keysFilePath, 'wb') as keysFile:
            keysFile.write(json.dumps(KEYS, sort_keys=True))
        versionsFilePath = os.path.join(self.fileServerDir, 'versions.gz')
        with gzip.open(versionsFilePath, 'wb') as versionsFile:
            versionsFile.write(json.dumps(VERSIONS, sort_keys=True))
        with gzip.open(versionsUserDataFilePath, 'wb') as versionsFile:
            versionsFile.write(json.dumps(VERSIONS, sort_keys=True))

        tempFile = tempfile.NamedTemporaryFile()
        self.tempDir = tempFile.name
        tempFile.close()
        settings.CONFIG_DATA_FOLDER = os.path.join(self.tempDir, '.pyupdater')
        settings.USER_DATA_FOLDER = os.path.join(self.tempDir, 'pyu-data')
        os.mkdir(self.tempDir)
        os.mkdir(settings.USER_DATA_FOLDER)
        os.mkdir(settings.CONFIG_DATA_FOLDER)
        # The way we set the App name below avoids having to
        # create .pyupdater/config.pyu:
        settings.GENERIC_APP_NAME = APP_NAME
        settings.GENERIC_COMPANY_NAME = COMPANY_NAME
        os.environ['PYUPDATER_FILESERVER_DIR'] = self.fileServerDir
        os.environ['WXUPDATEDEMO_TESTING'] = 'True'
        os.environ['WXUPDATEDEMO_TESTING_FROZEN'] = 'True'
        os.environ['WXUPDATEDEMO_TESTING_APP_NAME'] = APP_NAME
        os.environ['WXUPDATEDEMO_TESTING_COMPANY_NAME'] = COMPANY_NAME
        os.environ['WXUPDATEDEMO_TESTING_APP_VERSION'] = CURRENT_VERSION
        os.environ['WXUPDATEDEMO_TESTING_PUBLIC_KEY'] = PUBLIC_KEY