#!/usr/bin/python -tt
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (C) 2010, 2011, 2012, 2013, 2014 Intel, Inc.
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; version 2 of the License.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
"""
Git module inherited from GitRepository and self customed
"""

import os
import shutil

from common import runner
from common.utils import retry

from gbp.git.repository import GitRepository
from gbp.git.repository import GitRepositoryError
import gbp.log as log


class GitError(Exception):
    """Local exception."""
    pass

class Git(GitRepository):
    """The Git class wrappered from GitRepository"""
    def __init__(self, path):
        GitRepository.__init__(self, path)
        log.setup('auto', log.DEBUG)

    def get_tag(self, tag_name):
        """Get tag info though tag name"""
        outs, err, ret = self._git_inout('show',
                                         ['-s', '--pretty=format:###',
                                         tag_name])
        if ret:
            raise GitError('Error running git show -s '\
                           '--pretty=format:### %s: %s' % (tag_name, err))
        tag = {}
        msg = ''
        msgstub = False
        for line in outs.splitlines():
            if not line or not line.strip():
                continue
            if msgstub:
                if line.startswith('###') or line.startswith(
                        '-----BEGIN PGP SIGNATURE-----'):
                    tag['message'] = msg.strip()
                    break
                else:
                    msg += '%s\n' % line
            else:
                if line.startswith('Tagger: '):
                    tag['author'] = line[len('Tagger: '):line.index(' <')]
                    tag['email'] = line[line.index(' <')+2:line.index('>')]
                    msgstub = True

        try:
            tag['commitid'] = self.rev_parse('%s^{commit}' % tag_name)
        except GitRepositoryError, err:
            raise GitError('Error running rev parse %s^{commit}: %s' % \
                            (tag_name, str(err)))

        return tag

    def branch_contains(self, cmitid):
        """shows only the branches that contain the named commit(commitid)"""
        outs, _, ret = self._git_inout('branch',
                                       ['-a', '--contains', cmitid])
        if not ret:
            branches = []
            for branch in outs.splitlines():
                if branch.find('remotes/origin/HEAD ->') != -1:
                    continue
                branch = branch.strip().lstrip('* ')
                if branch.startswith('remotes/origin/'):
                    branch = branch[len('remotes/origin/'):]
                if branch not in branches:
                    branches.append(branch)
            print 'git branch contains %s' % branches
            return branches

def _update_gitproject(localdir, gitpath=None):
    """Fetch latest code to local dir"""

    print '\nUpdating local git: %s' % localdir
    try:
        localgit = Git(localdir)

        if gitpath and ((not localgit.get_remote_repos()) \
                or localgit.get_remote_repos().get('origin')[0] != gitpath):
            shutil.rmtree(localdir)
            return False

        if localgit.bare:
            localgit.fetch(all_remotes=True)
        else:
            localgit.fetch(tags=True)
            try:
                localgit.pull()
            except GitRepositoryError, err:
                print('pull exception: ', err)
                return True
    except GitRepositoryError, gre:
        print('git execption: ', gre)
        shutil.rmtree(localdir)
        return False

    return True

@retry()
def _clone_gitproject(giturl, gerritprj, localdir, bare=False, git_cache_dir=None):
    """Clone gerrit project from remote to local dir"""

    result = True

    # fetch latest code if local dir already exists
    if os.path.isdir(localdir) and \
            _update_gitproject(localdir, gitpath="%s/%s" %(giturl, gerritprj)):
        return True

    try:
        if git_cache_dir is None:
            cache_dir = os.path.join(os.getenv('GIT_CACHE_DIR'), gerritprj) + '.git'
        else:
            cache_dir = os.path.join(git_cache_dir, gerritprj) + '.git'

        if os.path.isdir(cache_dir):
            # use local cache repo as reference to clone
            gitcmd = 'git clone %s/%s --reference %s %s %s' % \
                   (giturl, gerritprj, cache_dir,
                    localdir, '--mirror' if bare else '')
        else:
            gitcmd = 'git clone %s/%s %s %s' % \
                   (giturl, gerritprj, localdir,
                    '--mirror' if bare else '')

        if runner.show(gitcmd)[0] != 0:
            result = False
    except (TypeError, AttributeError, OSError), err:
        result = False
        print '\nExcept occur when clone gerrit project'
        print err

    if not result:
        print '\nClone gerrit project Failed.'
        shutil.rmtree(localdir, ignore_errors=True)

    return result

def clone_gitproject(gerritprj, localdir, giturl=None, bare=False, gerrit_hostname=None, gerrit_username=None, gerrit_sshport=None, git_cache_dir=None):
    """Clone gerrit project from remote to local dir"""
    if not giturl:
        if not gerrit_hostname or not gerrit_username or not gerrit_sshport:
            giturl = 'ssh://%s@%s:%s' % (os.getenv('GERRIT_USERNAME'),
                                        os.getenv('GERRIT_HOSTNAME'),
    	                                 os.getenv('GERRIT_SSHPORT'))
        else:
            giturl = 'ssh://%s@%s:%s' % (gerrit_username,gerrit_hostname,gerrit_sshport)


    return _clone_gitproject(giturl, gerritprj, localdir, bare, git_cache_dir)


def fetch_change(gerritprj, localdir, refspec, giturl=None, bare=False, gerrit_hostname=None, gerrit_username=None, gerrit_sshport=None, git_cache_dir=None):
    """Fecth and checkout change to local dir"""

    if not giturl:
        if not gerrit_hostname or not gerrit_username or not gerrit_sshport:
            giturl = 'ssh://%s@%s:%s/%s' % (os.getenv('GERRIT_USERNAME'),
            	                           os.getenv('GERRIT_HOSTNAME'),
                                           os.getenv('GERRIT_SSHPORT'),
                    	                   gerritprj)
        else:
            giturl = 'ssh://%s@%s:%s' % (gerrit_username,gerrit_hostname,gerrit_sshport,gerritprj)

    git = Git.create(localdir, bare)
    git.fetch(repo=giturl, refspec=refspec)
    git.checkout('FETCH_HEAD')

