1
 ¤    #!/usr/bin/python3

import re
import argparse
import os
import gi
import json
import subprocess

gi.require_version('Flatpak', '1.0')
from gi.repository import Flatpak
from gi.repository import GLib

def get_bisection_data():
        return {'ref': None, 'good': None, 'bad': None,
                'refs': None, 'log': None, 'messages': None}

class Bisector():
    def load_cache(self):
        try:
            os.makedirs(os.path.join(GLib.get_user_cache_dir(), 'flatpak'))
        except FileExistsError:
            pass

        self.cache_path = os.path.join(GLib.get_user_cache_dir(),
                                       'flatpak', '%s-%s-bisect.status' % (
                                       self.name, self.branch))
        try:
            with open(self.cache_path, 'rb') as f:
                self.data = json.load(f)
        except FileNotFoundError:
            self.data = None

    def dump_data(self):
        with open(self.cache_path, 'w') as f:
            json.dump(self.data, f)

    def setup_flatpak_app(self):
        self.installation = Flatpak.Installation.new_user()
        kind = Flatpak.RefKind.APP
        if self.runtime:
            kind = Flatpak.RefKind.RUNTIME
        try:
            self.cref = self.installation.get_installed_ref(kind, self.name, None, self.branch, None)
        except GLib.Error as e:
            print("%s\n\nMake sure %s is installed as a "
                  "user (flatpak install --user) and specify `--runtime`"
                  " if it is a runtime." % (e, self.name))
            return -1
        return 0

    def run(self):
        self.name = self.name[0]
        self.load_cache()
        res = self.setup_flatpak_app()
        if res:
            return res

        try:
            func = getattr(self, self.subparser_name)
        except AttributeError:
            print('No action called %s' % self.subparser_name)

            return -1

        res = func()

        if self.data:
            self.dump_data()

        return res

    def set_reference_commits(self, set_name, check_name):
        if not self.data:
            print("You need to first start the bisection")
            return -1
        ref = self.cref.get_latest_commit()

        if self.data[check_name] == ref:
            print('Commit %s is already set as %s...' % (
                ref, check_name))
            return 1

        if ref not in self.data['refs']:
            print("%s is not a known commit." % ref)
            return -1

        print("Setting %s as %s commit" % (ref, set_name))
        self.data[set_name] = ref

        if self.data[set_name] and self.data[check_name]:
            x1 = self.data['refs'].index(self.data['good'])
            x2 = self.data['refs'].index(self.data['bad'])

            refs = self.data['refs'][x1:x2]
            if not refs:
                print("=========================="
                      "First bad commit is:\n%s"
                      "==========================" % self.data['message'][self.data['bad']])
                exit(0)
            ref = refs[int(len(refs) / 2)]
            if self.data['good'] == ref:
                print("\n==========================\n"
                      "First bad commit is:\n\n%s"
                      "==========================" % self.data['messages'][self.data['bad']])
                exit(0)

            return self.checkout(ref)

        return -1

    def load_refs(self):
        repodir, refname = self.download_history()
        history = subprocess.check_output(['ostree', 'log', '--repo', repodir, refname]).decode()

        refs = []
        messages = {}
        message = ""
        _hash = ''
        for l in history.split('\n'):
            rehash = re.search('(?<=^commit )\w+', l)
            if rehash:
                if message:
                    messages[_hash] = message
                _hash = rehash.group(0)
                refs.insert(0, _hash)
                message = ""
            message += l + '\n'

        if message:
            messages[_hash] = message

        self.d