# Copyright (C) 2008 Canonical Ltd
#
# 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

"""Fast, stream-based importing of data into Bazaar."""


from bzrlib.commands import Command, register_command
from bzrlib.option import Option, ListOption


def test_suite():
    import tests
    return tests.test_suite()


def _run(source, processor_factory, control, params, verbose):
    """Create and run a processor.
    
    :param source: a filename or '-' for standard input
    :param processor_factory: a callable for creating a processor
    :param control: the BzrDir of the destination or None if no
      destination is expected
    """
    import parser
    if source == '-':
        import sys
        stream = sys.stdin
    else:
        stream = open(source)
    proc = processor_factory(control, params=params, verbose=verbose)
    p = parser.ImportParser(stream, verbose=verbose)
    return proc.process(p.iter_commands)


class cmd_fast_import(Command):
    """Backend for fast Bazaar data importers.

    This command reads a mixed command/data stream and
    creates branches in the current repository accordingly.
    To specify standard input as the input stream, use a
    source name of '-'.
    
    The usual recipe is::

      bzr init-repo .
      front-end | bzr fast-import -

    If run inside a branch using a shared repository, then
    the current branch is made the trunk and other branches,
    if any, are created in sister directories. If run inside
    a standalone tree, the current branch is also made the
    trunk, but warnings are output about other branches found.
    
    The stream format is upwardly compatible with git-fast-import
    so existing front-ends for that tool can typically be reused
    without changes. See http://bazaar-vcs.org/BzrFastImport for
    links to matching exporters from Subversion, CVS, Git,
    Mercurial, Darcs, Perforce and SCCS.
 
    While reusing an existing format with existing frontends is
    great, it does mean a slightly more complex recipe when
    importing large projects, namely::

      bzr init-repo .
      front-end > xxx.fi
      bzr fast-export-info -v xxx.fi > xxx.cfg
      bzr fast-export xxx.fi --info xxx.cfg

    In this scenario, the xxx.cfg file generated by the first pass
    holds caching hints that the second pass uses to lower memory
    usage.
    
    If you wish to write a custom exporter for your project, see
    http://bazaar-vcs.org/BzrFastImport for the detailed protocol
    specification. In many cases, exporters can be written quite
    quickly using whatever scripting/programming language you like.

    Examples::

     cd /git/repo/path
     git-fast-export --signed-tags=warn | bzr fast-import -

        Import a Git repository into Bazaar.

     svn-fast-export.py /svn/repo/path | bzr fast-import -

        Import a Subversion repository into Bazaar.

     hg-fast-export.py -r /hg/repo/path | bzr fast-import -

        Import a Mercurial repository into Bazaar.
    """
    hidden = True
    _see_also = ['fast-import-info', 'fast-import-filter']
    takes_args = ['source']
    takes_options = ['verbose',
                    Option('info', type=str,
                        help="Path to file containing caching hints.",
                        ),
                    Option('trees',
                        help="Update working trees.",
                        ),
                    Option('checkpoint', type=int,
                        help="Checkpoint automatically every N revisions.",
                        ),
                    Option('count', type=int,
                        help="Import this many revisions then exit.",
                        ),
                    Option('inv-cache', type=int,
                        help="Number of inventories to cache.",
                        ),
                    Option('experimental',
                        help="Enable experimental features.",
                        ),
                     ]
    aliases = []
    def run(self, source, verbose=False, info=None, trees=False,
        checkpoint=10000, count=-1, inv_cache=10, experimental=False):
        from bzrlib import bzrdir
        from bzrlib.plugins.fastimport.processors import generic_processor
        control, relpath = bzrdir.BzrDir.open_containing('.')
        params = {
            'info': info,
            'trees': trees,
            'checkpoint': checkpoint,
            'count': count,
            'inv-cache': inv_cache,
            'experimental': experimental,
            }
        return _run(source, generic_processor.GenericProcessor, control,
            params, verbose)


class cmd_fast_import_info(Command):
    """Output information about a fast-import stream.

    This command reads a fast-import stream and outputs
    statistics and interesting properties about what it finds.
    When run in verbose mode, the information is output as a
    configuration file that can be passed to fast-import to
    assist it in intelligently caching objects.

    To specify standard input as the input stream, use a source
    name of '-'.

    Examples::

     front-end | bzr fast-import-info -

        Display statistics about the import stream produced by front-end.

     front-end | bzr fast-import-info -v - > front-end.cfg

       Create a hints file for running fast-import on a large repository.
    """
    hidden = True
    _see_also = ['fast-import']
    takes_args = ['source']
    takes_options = ['verbose']
    aliases = []
    def run(self, source, verbose=False):
        from bzrlib.plugins.fastimport.processors import info_processor
        return _run(source, info_processor.InfoProcessor, None, {}, verbose)


class cmd_fast_import_filter(Command):
    """Filter a fast-import stream displaying selected commands.

    To specify standard input as the input stream, use a source
    name of '-'. To specify the commands to display, use the -C
    option one or more times. To specify just some fields for
    a command, use the syntax::

      command=field1,...

    By default, the nominated fields for the nominated commands
    are displayed tab separated. To see the information in
    a name:value format, use verbose mode.

    Note: Binary fields (e.g. data for blobs) are masked out
    so it is generally safe to view the output in a terminal.

    Examples::

      front-end > xxx.fi
      bzr fast-import-filter xxx.fi -Creset -Ctag

        Show all the fields of the reset and tag commands.

      bzr fast-import-filter xxx.fi -Ccommit=mark,merge

        Show the mark and merge fields of the commit commands.
    """
    hidden = True
    _see_also = ['fast-import']
    takes_args = ['source']
    takes_options = ['verbose',
                    ListOption('commands', short_name='C', type=str,
                        help="Display fields for these commands."
                        ),
                     ]
    aliases = []
    def run(self, source, verbose=False, commands=None):
        from bzrlib.plugins.fastimport.processors import filter_processor
        from bzrlib.plugins.fastimport import helpers
        params = helpers.defines_to_dict(commands)
        return _run(source, filter_processor.FilterProcessor, None, params,
            verbose)


register_command(cmd_fast_import)
register_command(cmd_fast_import_info)
register_command(cmd_fast_import_filter)
