# git_filter_branch_process.py
# Copyright (C) 2011 Julien Miotte <miotte.julien@gmail.com>
#
# This module is part of gfbi_core and is released under the GPLv3
# License: http://www.gnu.org/licenses/gpl-3.0.txt
#
# -*- coding: utf-8 -*-

from subprocess import Popen, PIPE
from threading import Thread
import os
import fcntl

class git_filter_branch_process(Thread):
    """
        Thread meant to execute and follow the progress of the git command
        process.
    """

    def __init__(self, parent, args, oldest_commit_modified_parent,
                 log, script):
        """
            Initialization of the GitFilterBranchProcess thread.

            :param parent:
                GitModel object, parent of this thread.
            :param args:
                List of arguments that will be passed on to git filter-branch.
            :param oldest_commit_modified_parent:
                The oldest modified commit's parent.
            :param log:
                If set to True, the git filter-branch command will be logged.
            :param script:
                If set to True, the git filter-branch command will be written in
                a script that can be distributed to other developpers of the
                project.
        """
        Thread.__init__(self)

        self._args = args
        if oldest_commit_modified_parent is None:
            self._oldest_commit = "HEAD"
        else:
            self._oldest_commit = oldest_commit_modified_parent + ".."

        self._log = log
        self._script = script
        self._parent = parent

        self._output = []
        self._errors = []
        self._progress = None
        self._finished = False


    def run(self):
        """
            Main method of the script. Launches the git command and
            logs/generate scripts if the options are set.
        """
        clean_pipe = "|tr '\r' '\n'"
        command = "git filter-branch "
        command += self._args + self._oldest_commit

        process = Popen(command + clean_pipe, shell=True,
                        stdout=PIPE, stderr=PIPE)

        # Setting the stdout file descriptor to non blocking.
        fcntl.fcntl(
                process.stdout.fileno(),
                fcntl.F_SETFL,
                fcntl.fcntl(process.stdout.fileno(),
                            fcntl.F_GETFL) | os.O_NONBLOCK,
            )

        while True:
            try:
                line = process.stdout.readline()
            except IOError, error:
                continue

            if not line:
                break

            clean_line = line.replace('\r', '\n')
            self._output.append(clean_line)
            if "Rewrite" in clean_line:
                progress = float(line.split('(')[1].split('/')[0])
                total = float(line.split('/')[1].split(')')[0])
                self._progress = progress/total

        process.wait()
        self._finished = True

        self._errors = process.stderr.readlines()
        if self._log:
            log_file = "./gitbuster.log"
            handle = open(log_file, "a")
            handle.write("=======================\n")
            handle.write("Operation date :" +
                         datetime.now().strftime("%a %b %d %H:%M:%S %Y") +
                        "\n")
            handle.write("===== Command: ========\n")
            handle.write(command + "\n")
            handle.write("===== git output: =====\n")
            for line in self._output:
                handle.write(line.rstrip() + "\n")
            handle.write("===== git errors: =====\n")
            for line in self._errors:
                handle.write(line + "\n")
            handle.close()

        if self._script:
            # Generate migration script
            handle = open("migration.sh", "w")
            handle.write("#/bin/sh\n# Generated by gitbuster on " +
                         datetime.now().strftime("%a %b %d %H:%M:%S %Y") +
                         "\n")
            handle.write(command + "\n")
            handle.close()

        if self._errors:
            for line in self._errors:
                print line
        else:
            self._parent.erase_modifications()

    def progress(self):
        """
            Returns the progress percentage
        """
        return self._progress

    def output(self):
        """
            Returns the output as a list of lines
        """
        return list(self._output)

    def errors(self):
        """
            Returns the errors as a list of lines
        """
        return list(self._errors)

    def is_finished(self):
        """
            Returns self._finished
        """
        return self._finished
