Upload application with its environment (directory) into the storage.

    Application directory or its subdirectories must contain valid manifest file
    named `manifest.json` or `manifest` otherwise you must specify it explicitly by
    setting `--manifest` option.

    You can specify application name. By default, leaf directory name is treated as application
    name.

    If you have already prepared application archive (*.tar.gz), you can explicitly specify path to
    it by setting `--package` option.

    Additional output can be turned on by passing `-vvvv` option.

def app_upload(path, name, manifest, package, docker_address, registry, manifest_only, **kwargs):
    """
    Upload application with its environment (directory) into the storage.

    Application directory or its subdirectories must contain valid manifest file
    named `manifest.json` or `manifest` otherwise you must specify it explicitly by
    setting `--manifest` option.

    You can specify application name. By default, leaf directory name is treated as application
    name.

    If you have already prepared application archive (*.tar.gz), you can explicitly specify path to
    it by setting `--package` option.

    Additional output can be turned on by passing `-vvvv` option.
    """
    lower_limit = 120.0

    ctx = Context(**kwargs)
    if ctx.timeout < lower_limit:
        ctx.timeout = lower_limit
        log.info('shifted timeout to the %.2fs', ctx.timeout)

    mutex_record = collections.namedtuple('mutex_record', 'value, name')
    mutex = [
        (mutex_record(path, 'PATH'), mutex_record(package, '--package')),
        (mutex_record(package, '--package'), mutex_record(docker_address, '--docker')),
        (mutex_record(package, '--package'), mutex_record(registry, '--registry')),
    ]
    for (f, s) in mutex:
        if f.value and s.value:
            click.echo('Wrong usage: option {} and {} are mutual exclusive, you can only use one'.
                       format(f.name, s.name))
            exit(os.EX_USAGE)

    if manifest_only:
        ctx.execute_action('app:upload-manual', **{
            'storage': ctx.repo.create_secure_service('storage'),
            'name': name,
            'manifest': manifest,
            'package': None,
            'manifest_only': manifest_only,
        })
    elif package:
        ctx.execute_action('app:upload-manual', **{
            'storage': ctx.repo.create_secure_service('storage'),
            'name': name,
            'manifest': manifest,
            'package': package
        })
    elif docker_address:
        ctx.execute_action('app:upload-docker', **{
            'storage': ctx.repo.create_secure_service('storage'),
            'path': path,
            'name': name,
            'manifest': manifest,
            'address': docker_address,
            'registry': registry
        })
    else:
        ctx.execute_action('app:upload', **{
            'storage': ctx.repo.create_secure_service('storage'),
            'path': path,
            'name': name,
            'manifest': manifest
        })