import os
from subprocess import Popen, PIPE


def ilen(it):
    return sum(1 for i in it)


def mercurial(path, ignore_set, **options):
    """Get statuses of a Mercurial repository."""
    ignore_untracked = options['ignore_untracked']

    process = Popen(('hg', 'st'), stdout=PIPE, cwd=path)
    output = process.stdout.read()
    lines = output.splitlines()
    untracked_count = ilen((line for line in lines if line.startswith('?')))
    untracked_only = untracked_count == len(lines)

    touched = bool(lines)
    if ignore_untracked and untracked_only:
        touched = False
    if touched:
        if untracked_only:
            status = 'untracked'
        else:
            status = 'uncommitted'
    else:
        status = 'OK'

    yield dict(
        touched=touched,
        path=path,
        status=status,
        output=output,
    )

    process = Popen(('hg', 'out'), stdout=PIPE, cwd=path)
    output = process.stdout.read()
    lines = []
    for line in output.splitlines():
        if not line.strip():
            continue
        if line.startswith('comparing with'):
            continue
        if line.startswith('searching for changes'):
            continue
        if line.startswith('no changes found'):
            continue
        lines.append(line)
    output = '\n'.join(lines)+'\n'

    touched = bool(lines)
    if touched:
        yield dict(
            touched=touched,
            path=path,
            status='unpushed' if touched else 'OK',
            output=output,
        )


def git(path, ignore_set, **options):
    """Get statuses of a Git repository."""
    ignore_untracked = options['ignore_untracked']

    process = Popen(('git', 'status', '--porcelain'), stdout=PIPE, cwd=path)
    output = process.stdout.read()
    lines = output.splitlines()
    untracked_count = ilen((line for line in lines if line.startswith('?')))
    untracked_only = untracked_count == len(lines)

    touched = bool(lines)
    if ignore_untracked and untracked_only:
        touched = False
    if touched:
        if untracked_only:
            status = 'untracked'
        else:
            status = 'uncommitted'
    else:
        status = 'OK'

    yield dict(
        touched=touched,
        path=path,
        status=status,
        output=output,
    )

    # Related commands:
    # git log --branches --not --remotes --simplify-by-decoration --decorate --oneline
    # git branch -v
    # git for-each-ref --format='%(refname)' refs/heads
    process = Popen(('git', 'branch'), stdout=PIPE, cwd=path)
    branches = [br[2:] for br in process.stdout.read().splitlines()]
    for branch in branches:
        process = Popen(('git', 'log', branch, '--not', '--remotes',
                         '--simplify-by-decoration',
                         '--decorate', '--oneline', '--'), stdout=PIPE, cwd=path)
        output = process.stdout.read()
        touched = bool(output)
        yield dict(
            touched=touched,
            path='%s:%s' % (path, branch),
            status='unpushed' if touched else 'OK',
            output=output,
        )


def subversion(path, ignore_set, **options):
    """Get statuses of a Subversion repository."""
    ignore_untracked = options['ignore_untracked']

    process = Popen(('svn', 'st', '-v'), stdout=PIPE, cwd=path)
    output = process.stdout.read()
    lines = []
    for line in output.splitlines():
        if not line.strip():
            continue
        if line.startswith('Performing'):
            continue
        status = line[:8]
        filename = line[8:].split(None, 3)[-1]
        ignore_set.add(os.path.join(path, filename))
        if status.strip():
            lines.append(status + filename)
    output = '\n'.join(lines)+'\n'

    untracked_count = ilen((line for line in lines if line.startswith('?')))
    untracked_only = untracked_count == len(lines)

    touched = bool(lines)
    if ignore_untracked and untracked_only:
        touched = False
    if touched:
        if untracked_only:
            status = 'untracked'
        else:
            status = 'uncommitted'
    else:
        status = 'OK'

    yield dict(
        touched=touched,
        path=path,
        status=status,
        output=output,
    )

@@ -418,32 +418,33 @@
 line.startswith(
+b
 '?')))%0A    untra
@@ -1073,16 +1073,17 @@
 rtswith(
+b
 'compari
@@ -1141,16 +1141,17 @@
 rtswith(
+b
 'searchi
@@ -1216,16 +1216,17 @@
 rtswith(
+b
 'no chan
@@ -1867,32 +1867,33 @@
 line.startswith(
+b
 '?')))%0A    untra
@@ -3479,16 +3479,17 @@
 rtswith(
+b
 'Perform
@@ -3819,16 +3819,17 @@
 rtswith(
+b
 '?')))%0A 

Fix binary type on python 3