#!/usr/bin/python
# vim: set fileencoding=utf-8 :
#
# (C) 2006,2007 Guido Guenther <agx@sigxcpu.org>
#    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; either version 2 of the License, or
#    (at your option) any later version.
#
#    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
#
"""Import a new upstream version"""

import sys
import os
import tempfile
import re
import glob
import subprocess
import gbp.command_wrappers as gbpc
from gbp.git_utils import (GitRepositoryError, GitRepository, build_tag)
from gbp.config import GbpOptionParser
from gbp.errors import GbpError


def cleanup_tmp_tree(tree):
    """remove a tree of temporary files"""
    try:
        gbpc.RemoveTree(tree)()
    except gbpc.CommandExecFailed:
        print >>sys.stderr, "Removal of tmptree %s failed." % tree


def unpack_orig(archive, tmpdir):
    """unpack a .orig.tar.gz"""
    try:
        unpackArchive = gbpc.UnpackTarArchive(archive, tmpdir)
        unpackArchive()
    except gbpc.CommandExecFailed:
        print "Unpacking of %s failed" % archive
        cleanup_tmp_tree(unpackArchive.dir)
        raise GbpError
    return unpackArchive.dir


def import_source_tree(repo, orig_dir, version, filter, verbose):
    """import source tree to the current branch"""
    try:
        old = set(repo.index_files())
        new = set(gbpc.copy_from(orig_dir, filter))
        gbpc.GitAdd()(['.'])
        files = [ obj for obj in old - new if not os.path.isdir(obj)]
        if files:
            gbpc.GitRm()(files)
        if not repo.is_clean()[0]:
            gbpc.GitCommitAll(verbose=verbose)(msg="Imported upstream version %s" % version)
        else:
            raise GbpError, "Nothing to commit, nothing imported."
    except gbpc.CommandExecFailed:
        raise GbpError, "Import of new upstream version failed."


def guess_version(archive, version_regex=r''):
    """
    guess the version from the filename of an upstgream archive
    @archive: filename to guess to version for
    @version_regex: additional version regex to apply, needs a 'version' group
    """
    version_filters = [ # Debian package_<version>.orig.tar.gz:
                        r'^[a-z\d\-]+_(?P<version>[a-z\d\.\~\-]+)\.orig\.tar\.(gz|bz2)',
                        # Upstream package-<version>.tar.gz:
                        r'^[a-z\d\-]+-(?P<version>[a-z\d\.]+)\.tar\.(gz|bz2)' ]
    if version_regex:
        version_filters = version_regex + version_filters
    for filter in version_filters:
        m = re.match(filter, os.path.basename(archive))
        if m:
            return m.group('version')


def main(argv):
    ret = 0
    tmpdir = ''

    parser = GbpOptionParser(command=os.path.basename(argv[0]), prefix='',
                           usage='%prog [-u version] /path/to/upstream-version.tar.gz')

    parser.add_option("-u", "--upstream-version", dest="version",
                      help="Upstream Version")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
                      help="verbose command execution")
    parser.add_option("--no-merge", dest='merge', action="store_false", default=True,
                      help="after import dont do any merging to another branch")
    parser.add_option("--no-dch", dest='run_dch', action="store_false", default=True,
                      help="don't call dch after the import")
    parser.add_config_file_option(option_name="debian-branch", dest='debian_branch',
                      help="branch the debian patch is being developed on, default is '%(debian-branch)s'")
    parser.add_config_file_option(option_name="upstream-branch", dest="upstream_branch",
                      help="upstream branch, default is '%(upstream-branch)s'")
    parser.add_config_file_option(option_name="sign-tags", dest="sign_tags",
                      help="sign git tags", action="store_true")
    parser.add_config_file_option(option_name="keyid", dest="keyid",
                      help="GPG keyid to sign tags with")
    parser.add_config_file_option(option_name="upstream-tag", dest="upstream_tag",
                      help="format string for upstream tags, default is '%(upstream-tag)s'")
    parser.add_config_file_option(option_name="filter", dest="filter",
                      help="files to filter out during import")
    (options, args) = parser.parse_args(argv[1:])

    gitCheckoutMaster = gbpc.GitCheckoutBranch(options.debian_branch)
    gitShowBranch = gbpc.GitShowBranch()
    gitPullUpstream = gbpc.GitPull('.', options.upstream_branch)

    try:
        if options.verbose:
            gbpc.Command.verbose = True

        if len(args) != 1:
            parser.print_help()
            raise GbpError
        else:
            archive = args[0]

        try:
            repo = GitRepository('.')
        except GitRepositoryError:
            raise GbpError, "%s is not a git repository" % (os.path.abspath('.'))

        # an empty repo has now branches:
        if repo.get_branch():
            is_empty = False
        else:
            is_empty = True

        if not repo.has_branch(options.upstream_branch) and not is_empty:
            print >>sys.stderr, """
Repository does not have branch '%s' for upstream sources. If there is none see
file:///usr/share/doc/git-buildpackage/manual-html/gbp.import.html#GBP.IMPORT.CONVERT
on howto create it otherwise use --upstream-branch to specify it.
"""  % options.upstream_branch
            raise GbpError

        if options.version:
            version = options.version
        else:
            version = guess_version(archive)

        if version:
            print "Upstream version is %s" % version
        else:
            print >>sys.stderr, "Cannot determine upstream version from %s - use -u <version>" % archive
            parser.print_help()
            raise GbpError

        (clean, out) = repo.is_clean()
        if not clean and not is_empty:
            print >>sys.stderr, "Repository has uncommitted changes, commit these first: "
            raise GbpError, out

        if os.path.isdir(archive):
            orig_dir = archive
        else:
            tmpdir = tempfile.mkdtemp(dir='../')
            unpack_orig(archive, tmpdir)
            if options.verbose:
                print "Unpacked %s to '%s'" % (archive , tmpdir)
            unpacked = glob.glob(tmpdir+'/*')
            # archive has everything packed up in one subdir:
            if len(unpacked) == 1:
                orig_dir = unpacked[0]
            # archive content not in a subdir
            else:
                orig_dir = tmpdir

        try:
            if not is_empty:
                print "Importing '%s' to branch '%s'..." % (archive, options.upstream_branch)
                gbpc.GitCheckoutBranch(options.upstream_branch)()
            else:
                print "Initial import of '%s'..." % archive

            import_source_tree(repo, orig_dir, version, options.filter, verbose=not is_empty)
            gbpc.GitTag(options.sign_tags, options.keyid)(build_tag(options.upstream_tag, version),
                        msg="Upstream version %s" % version)

            if is_empty:
                gbpc.GitBranch()(options.upstream_branch)
            elif options.merge:
                print "Merging to %s" % options.debian_branch
                gitCheckoutMaster()
                gitShowBranch()
                try:
                    gitPullUpstream()
                except gbpc.CommandExecFailed:
                    raise GbpError, """Merge failed, please resolve and run "dch -v %s-1".""" % version
                if options.run_dch:
                    gbpc.Dch("%s-1" % version, 'New Upstream Version')()
        except gbpc.CommandExecFailed:
            raise GbpError, "Import of %s failed" % archive
    except GbpError, err:
        if len(err.__str__()):
            print >>sys.stderr, err
        ret = 1

    if tmpdir:
        cleanup_tmp_tree(tmpdir)

    if not ret:
        print "Succesfully merged version %s of %s into ." % (version, archive)
    return ret

if __name__ == "__main__":
    sys.exit(main(sys.argv))

# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
