Skip to content
Snippets Groups Projects
compare-steam-runtime.py 8.56 KiB
Newer Older
#!/usr/bin/python3

# Compare Steam Runtime with official package list
#
# Copyright © 2017 Collabora Ltd.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import argparse
import os
from debian.debian_support import Version
def main(packages, *, manifest=None, steam=None):
    with open('runtimes/com.valvesoftware.SteamRuntime.yaml') as reader:
        source_manifest = yaml.safe_load(reader)

    print('---')

    missing_platform = set()
    missing_sdk = set()
    only_in_flatpak = set()
    only_in_steam = set()
    newer_in_flatpak = set()
    newer_in_steam = set()

    if packages is not None:
        print('comparing_packages_txt:')
        print('  path: ' + packages)

        with open(packages, 'r') as reader:
            for line in reader:
                line = line.strip()

                if not line or line.startswith('#'):
                    continue

                tokens = line.split()

                source = tokens[0]
                binaries = tokens[1:]

                for binary in binaries:
                    if (binary.endswith('-dev') or
                            binary.endswith('-multidev') or
                            binary.endswith('-dbg') or
                            # Probably not intentionally in the user-facing
                            # Runtime?
                            # https://github.com/ValveSoftware/steam-runtime/issues/76
                            binary.endswith('-pic') or
                            # Probably not intentionally in the user-facing
                            # Runtime?
                            # https://github.com/ValveSoftware/steam-runtime/issues/77
                            binary == 'nvidia-cg-toolkit'):
                        if binary in source_manifest['sdk'].get(
                                'add_packages_multiarch', ()):
                            continue

                        if binary in source_manifest['sdk']['add_packages']:
                            continue

                        missing_sdk.add(binary)
                        continue

                    if binary in source_manifest['add_packages_multiarch']:
                        continue
                    if binary in source_manifest['add_packages']:
                    missing_platform.add(binary)

        if missing_platform:
            print('  missing_from_platform:')

            for binary in sorted(missing_platform):
                print('  - ' + binary)

        if missing_sdk:
            print('  missing_from_sdk:')

            for binary in sorted(missing_sdk):
                print('    - ' + binary)

    if steam is None:
        steam = os.path.join(os.path.expanduser('~'), '.steam', 'steam')

        if not os.path.exists(steam):
            steam = None

    steam_runtime = os.path.join(steam, 'ubuntu12_32', 'steam-runtime')

    if not os.path.exists(steam_runtime):
        steam_runtime = None

    if steam_runtime is not None and manifest is not None:
        print('comparing_steam_installation:')
        print('  steam: ' + steam_runtime)
        print('  manifest: ' + manifest)

        records = []

        with open(manifest, 'r') as reader:
            for line in reader:
                if line.strip().startswith('#'):
                if not line.strip():
                    continue

                records.append(line.split('\t'))

        architectures = set()
        flatpak_versions = {}

        for line in records:
            if line[0].startswith('coreutils:'):
                arch = line[0].split(':', 1)[1]
                architectures.add(arch)
            elif line[0].startswith('libc6:'):
                arch = line[0].split(':', 1)[1]
                architectures.add(arch)

            flatpak_versions[line[0].split(':', 1)[0]] = line

        in_steam = set()
        only_in_flatpak = set()
        sources_only_in_flatpak = set()

        for arch in architectures:
            contents = os.listdir(
                os.path.join(steam_runtime, arch, 'installed'))

            for name in contents:
                if name in ('.', '..'):
                if name.endswith('.md5'):
                binary, version, arch_ = name.split('_', 2)
                assert arch_ in (arch, 'all'), (arch, name)
                in_steam.add(binary)

                flatpak_version = flatpak_versions.get(binary)

                if flatpak_version is None:
                    only_in_steam.add(binary)
                else:
                    no_epoch_version = Version(flatpak_version[1])
                    no_epoch_version.epoch = None

                    if no_epoch_version < Version(version):
                        newer_in_steam.add(
                            (binary, flatpak_version[1], version, arch))

                    if no_epoch_version > Version(version):
                        newer_in_flatpak.add(
                            (binary, flatpak_version[1], version, arch))

        for package, line in flatpak_versions.items():
            if package not in in_steam:
                source = line[2] or package

                if '(' in source:
                    source_version = source.split('(', 1)[1].strip(')')
                else:
                    source_version = line[1]

                only_in_flatpak.add(package)
                sources_only_in_flatpak.add((source, source_version))
        if only_in_steam:
            print('  only_in_steam:')
            for binary in sorted(only_in_steam):
                print('    - ' + binary)
        if only_in_flatpak:
            print('  only_in_flatpak:')
            for binary in sorted(only_in_flatpak):
                print('    - ' + binary)
        if sources_only_in_flatpak:
            print('  sources_only_in_flatpak:')

            for source in sorted(sources_only_in_flatpak):
                print('    - source: ' + source[0])
                print('      source_version: ' + source[1])

        if newer_in_flatpak:
            print('  newer_in_flatpak:')

            for binary in sorted(newer_in_flatpak):
                print('    - package: ' + binary[0])
                print('      in_flatpak: ' + binary[1])
                print('      in_steam: ' + binary[2])
                print('      architecture: ' + binary[3])

        if newer_in_steam:
            print('  newer_in_steam:')

            for binary in sorted(newer_in_steam):
                print('    - package: ' + binary[0])
                print('      in_flatpak: ' + binary[1])
                print('      in_steam: ' + binary[2])
                print('      architecture: ' + binary[3])

    print('...')

    if (missing_platform or missing_sdk or only_in_steam or
            newer_in_flatpak or newer_in_steam):
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description='Compare Steam Runtime with official package list')
    parser.add_argument(
        '--steam', metavar='STEAM',
        help='Path to ~/.steam/steam or ~/.local/share/Steam',
    )
    parser.add_argument(
        '--manifest', metavar='MANIFEST',
        help='Path to '
        '~/.local/share/flatpak/runtime/'
        'com.valvesoftware.SteamRuntime.Platform/'
        'x86_64/scout_beta/active/files/manifest.dpkg or similar',
    )
    parser.add_argument(
        'packages', metavar='PACKAGES.TXT',
        help='Path to packages.txt from the Steam Runtime',
    )
    args = parser.parse_args()
    main(args.packages, manifest=args.manifest, steam=args.steam)