#!/usr/bin/python
# vim: ai ts=4 sts=4 et sw=4
#
# Copyright (c) 2011 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.

import sys
import re

from gitbuildsys.__version__ import VERSION
from gitbuildsys import msger, cmdln, errors

def handle_repository(option, opt_str, value, parser):
    if not value:
        raise errors.Usage("option %s: need value" % opt_str)
    if value[0] == '-':
        raise errors.Usage("option %s: invalid value %s" % (opt_str, value))
    if getattr(parser.values, option.dest) is None:
        setattr(parser.values, option.dest, [])
    getattr(parser.values, option.dest).append(value)

def handle_project(option, opt_str, value, parser):
    if not value:
        raise errors.Usage("option %s: need value" % opt_str)
    if value[0] == '-':
        raise errors.Usage("option %s: invalid project name %s, cannot " \
                           "start with '-'" % (opt_str, value))
    if not re.match(r'^(\w|:|\.|-)+$', value):
        raise errors.Usage("option %s: invalid project name %s, only word " \
                           "character, ':', '.' and '-' are supported" \
                           % (opt_str, value))
    setattr(parser.values, option.dest, value)

class Gbs(cmdln.Cmdln):
    """
    Usage: gbs [GLOBAL-OPTS] SUBCOMMAND [OPTS] [ARGS...]

    gbs - the command line tool for Tizen package developers
    Try 'gbs help SUBCOMAND' for help on a specific subcommand.

    ${command_list}
    global ${option_list}
    ${help_list}
    """

    name = 'gbs'
    version = VERSION

    def get_optparser(self):
        optparser = cmdln.CmdlnOptionParser(self, version=self.version)
        optparser.add_option('-d', '--debug', action='store_true',
                                              dest='debug',
                                              help='print debug message')
        optparser.add_option('-v', '--verbose', action='store_true',
                                                dest='verbose',
                                                help='verbose information')
        optparser.add_option('-c', '--conf', dest='conf',
                                             help='specify config file for gbs')
        return optparser

    def postoptparse(self):
        from gitbuildsys.conf import configmgr
        if self.options.verbose:
            msger.set_loglevel('verbose')

        if self.options.debug:
            msger.set_loglevel('debug')

        if self.options.conf:
            configmgr.reset_from_conf(self.options.conf)
    @cmdln.alias('sr')
    @cmdln.option('-m', '--msg',
                  default=None,
                  dest='msg',
                  help='specify tag message info')
    @cmdln.option('-c', '--commit',
                  default='HEAD',
                  dest='commit',
                  help='specify a commit ID to submit')
    @cmdln.option('-s', '--sign',
                  action='store_true',
                  default=False,
                  dest='sign',
                  help='make a GPG-signed tag')
    @cmdln.option('-u', '--user-key',
                  default=None,
                  dest='user_key',
                  help='using the given key to make a GPG-signed tag')
    @cmdln.option('-t', '--target',
                  default=None,
                  dest='target',
                  help='specify target version to submit, eg: trunk.')
    @cmdln.option('-r', '--remote',
                  default='origin',
                  dest='remote',
                  help='specify gerrit project server, default value is '\
                  'origin for example:\nssh://user@review.tizen.org:29418'\
                  '/public/base/gcc')
    def do_submit(self, _subcmd, opts, *args):
        """${cmd_name}: submit tag to gerrit and trigger building in OBS

        Usage:
            gbs submit -m <message for tag> [options]

        Examples:
            gbs submit -m 'release for 0.1'
            gbs submit -c <commit_ID> -m 'release for 0.2'
            gbs submit -m 'release for 0.3' -s
            gbs submit -r ssh://user@review.tizen.org:29418/public/base/gcc\
 -m 'release for 0.4'

        ${cmd_option_list}
        """

        from gitbuildsys import cmd_submit as cmd
        cmd.do(opts, args)

    @cmdln.alias('ex')
    @cmdln.option('-o', '--outdir',
                  default=None,
                  dest='outdir',
                  help='output directory')
    @cmdln.option('--spec',
                  default=None,
                  dest='spec',
                  help='specify a spec file to use')
    @cmdln.option('-c', '--commit',
                  default=None,
                  dest='commit',
                  help='specify a commit ID to export')
    @cmdln.option('--include-all',
                  action='store_true',
                  default=False,
                  dest='include_all',
                  help='uncommitted changes and untracked files would be '\
                       'included while generating tar ball')
    @cmdln.option('--source-rpm',
                  action='store_true',
                  default=False,
                  dest='source_rpm',
                  help='generate source rpm')
    def do_export(self, _subcmd, opts, *args):
        """${cmd_name}: export files and prepare for build

        Usage:
            gbs export

        Note:

        ${cmd_option_list}
        """

        from gitbuildsys import cmd_export as cmd
        cmd.do(opts, args)

    @cmdln.alias('lb')
    @cmdln.option('-D', '--dist',
                  default=None,
                  dest='dist',
                  help='specify distribution configuration file, which should ' \
                       'be a full path')
    @cmdln.option('-R', '--repository',
                  action="callback",
                  default=None,
                  type='string',
                  dest='repositories',
                  callback=handle_repository,
                  help='specify package repositories, only rpm-md format ' \
                       'is supported')
    @cmdln.option('-B', '--buildroot',
                  default=None,
                  dest='buildroot',
                  help='specify build root to setup chroot environment')
    @cmdln.option('-A', '--arch',
                  default=None,
                  dest='arch',
                  help='build target arch ')
    @cmdln.option('-C', '--clean',
                  action='store_true',
                  default=False,
                  dest='clean',
                  help='delete old build root before initialization')
    @cmdln.option('--noinit',
                  action='store_true',
                  default=False,
                  dest='noinit',
                  help='skip initialization of build root and start ' \
                       'with build immediately')
    @cmdln.option('--ccache',
                  action="store_true",
                  default=False,
                  dest='ccache',
                  help='use ccache to speed up rebuilds')
    @cmdln.option('--skip-conf-repos',
                  action="store_true",
                  default=False,
                  dest='skip_conf_repos',
                  help='skip repositories mentioned in config file')
    @cmdln.option('-c', '--commit',
                  default=None,
                  dest='commit',
                  help='specify a commit ID to build')
    @cmdln.option('--spec',
                  default=None,
                  dest='spec',
                  help='specify a spec file to use')
    @cmdln.option('--extra-packs',
                  default=None,
                  dest='extra_packs',
                  help='specify extra packages to install to build root '\
                       'multiple packages can be separated by comma')
    @cmdln.option('--include-all',
                  action='store_true',
                  default=False,
                  dest='include_all',
                  help='uncommitted changes and untracked files would be '\
                       'included while generating tar ball')
    @cmdln.option('--out',
                  default=None,
                  dest='out',
                  help='output directory for RPMs')
    def do_build(self, _subcmd, opts, *args):
        """${cmd_name}: local build package

        Usage:
            gbs build -R repository -A ARCH [options] [package git dir]

            [package git dir] is optional, if not specified, current dir would
            be used.

        Examples:
            gbs build -R http://example1.org/packages/ \\
                      -R http://example2.org/packages/ \\
                      -A i586                          \\
                      -D /usr/share/gbs/tizen-1.0.conf

        Note:

        If -D not specified, distconf key in ~/.gbs.conf would be used.
        If distconf key is None, dist conf file would be got from OBS
        project (Tizen:Main by default).

        ${cmd_option_list}
        """

        from gitbuildsys import cmd_build as cmd
        cmd.do(opts, args)

    @cmdln.alias('ch')
    @cmdln.option('-r', '--root',
                  action='store_true',
                  default=False,
                  dest='root',
                  help='chroot as root instead of abuild by default')
    @cmdln.option('-A', '--arch',
                  default='i586',
                  dest='arch',
                  help='specify the build root arch')
    def do_chroot(self, subcmd, opts, *args):
        """${cmd_name}: chroot to build root

        Usage:
            gbs chroot [options]

        ${cmd_option_list}
        """

        from gitbuildsys import cmd_chroot as cmd
        cmd.do(opts, args)

    @cmdln.alias('rb')
    @cmdln.option('-T', '--target-obsprj',
                  action='callback',
                  default=None,
                  dest='target_obsprj',
                  type='string',
                  callback=handle_project,
                  help='OBS project where package will be checked in' \
                       '(default: home:<userid>:gbs:Tizen:Main)')
    @cmdln.option('-B', '--base-obsprj',
                  action='callback',
                  default=None,
                  dest='base_obsprj',
                  type='string',
                  callback=handle_project,
                  help='OBS project to branch from (default: Tizen:Main)')
    @cmdln.option('--spec',
                  default=None,
                  dest='spec',
                  help='specify a spec file to use')
    @cmdln.option('-c', '--commit',
                  default=None,
                  dest='commit',
                  help='specify a commit ID to build')
    @cmdln.option('--buildlog',
                  action='store_true',
                  default=False,
                  dest='buildlog',
                  help='get buildlog from build sever')
    @cmdln.option('--status',
                  action='store_true',
                  default=False,
                  dest='status',
                  help='get build status from build server')
    @cmdln.option('--include-all',
                  action='store_true',
                  default=False,
                  dest='include_all',
                  help='uncommitted changes and untracked files will be '\
                       'included while generating tar ball')
    def do_remotebuild(self, subcmd, opts, *args):
        """${cmd_name}: remote build package

        Usage:
            gbs remotebuild [options] [package git dir] \
    [--buildlog repo arch] [--status]

            [package git dir] is optional, if not specified, current dir would
            be used.

        Examples:
          $ gbs remotebuild
          $ gbs remotebuild -B Test
          $ gbs remotebuild -B Test -T home:<userid>:gbs
          $ gbs remotebuild <package git directory>
        ${cmd_option_list}
        """

        from gitbuildsys import cmd_remotebuild as cmd
        cmd.do(opts, args)


    @cmdln.alias('im')
    @cmdln.option('--author-name',
                  default=None,
                  dest='author_name',
                  help='author name of git commit')
    @cmdln.option('--author-email',
                  default=None,
                  dest='author_email',
                  help='author email of git commit')
    @cmdln.option('--upstream_branch',
                  default='upstream',
                  dest='upstream_branch',
                  help='specify upstream branch for new version of package')
    @cmdln.option('--no-merge',
                  action='store_true',
                  default=False,
                  dest='no_merge',
                  help='don\'t merge new upstream branch to master')
    def do_import(self, subcmd, opts, *args):
        """${cmd_name}: import spec file/source rpm/tar ball to git repository

        Usage:
            gbs import [options] specfile | source rpm | tar ball


        Examples:
          $ gbs import /path/to/specfile/
          $ gbs import /path/to/src.rpm
          $ gbs import /path/to/tarball
        ${cmd_option_list}
        """

        from gitbuildsys import cmd_import as cmd
        cmd.do(opts, args)


    @cmdln.alias('ch')
    @cmdln.option('-s', '--since',
                  default=None,
                  dest='since',
                  help='commit to start from')
    @cmdln.option('-m', '--message',
                  default=None,
                  dest='message',
                  help='use given message as the changelog entry')
    def do_changelog(self, _subcmd, opts, *args):
        """${cmd_name}: update the changelog file with the git commit messages

        Usage:
            gbs changelog [options]

        Examples:
          $ gbs changelog
          $ gbs changelog --since=COMMIT_ID
          $ gbs changelog -m 'new upstream release 0.0.1'
        ${cmd_option_list}
        """

        from gitbuildsys import cmd_changelog as cmd
        cmd.do(opts, args)


if __name__ == '__main__':
    try:
        sys.exit(Gbs().main())

    except KeyboardInterrupt:
        msger.error('\n^C caught, program aborted.')

    except errors.Usage, usage:
        msger.error(str(usage))

    except errors.Abort, msg:
        msger.info(str(msg))

    except errors.CmdError, err:
        if msger.get_loglevel() == 'debug':
            import traceback
            msger.error(traceback.format_exc())
        else:
            msger.error('\n'+str(err))

    except Exception:
        import traceback
        msger.error(traceback.format_exc())
