hgext/convert/cvsps
author Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
Wed, 12 Nov 2008 19:12:26 +0100
changeset 7358 3c2ed7c2dcb4
parent 6689 d2ac53fe216e
permissions -rw-r--r--
patchbomb: add tests for diffstat, inline, and attach options

#!/usr/bin/env python
#
# Commandline front-end for cvsps.py
#
# Copyright 2008, Frank Kingswood <frank@kingswood-consulting.co.uk>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

import sys
from mercurial import util
from mercurial.i18n import _
from optparse import OptionParser, SUPPRESS_HELP
from hgext.convert.cvsps import createlog, createchangeset, logerror

def main():
    '''Main program to mimic cvsps.'''

    op = OptionParser(usage='%prog [-bpruvxz] path',
                      description='Read CVS rlog for current directory or named '
                                  'path in repository, and convert the log to changesets '
                                  'based on matching commit log entries and dates.')

    # Options that are ignored for compatibility with cvsps-2.1
    op.add_option('-A', dest='Ignore', action='store_true', help=SUPPRESS_HELP)
    op.add_option('--cvs-direct', dest='Ignore', action='store_true', help=SUPPRESS_HELP)
    op.add_option('-q', dest='Ignore', action='store_true', help=SUPPRESS_HELP)

    # Main options shared with cvsps-2.1
    op.add_option('-b', dest='Branches', action='append', default=[],
                  help='Only return changes on specified branches')
    op.add_option('-p', dest='Prefix', action='store', default='',
                  help='Prefix to remove from file names')
    op.add_option('-r', dest='Revisions', action='append', default=[],
                  help='Only return changes after or between specified tags')
    op.add_option('-u', dest='Cache', action='store_const', const='update',
                  help="Update cvs log cache")
    op.add_option('-v', dest='Verbose', action='count', default=0,
                  help='Be verbose')
    op.add_option('-x', dest='Cache', action='store_const', const='write',
                  help="Create new cvs log cache")
    op.add_option('-z', dest='Fuzz', action='store', type='int', default=60,
                  help='Set commit time fuzz', metavar='seconds')
    op.add_option('--root', dest='Root', action='store', default='',
                  help='Specify cvsroot', metavar='cvsroot')

    # Options specific to this version
    op.add_option('--parents', dest='Parents', action='store_true',
                  help='Show parent changesets')
    op.add_option('--ancestors', dest='Ancestors', action='store_true',
                  help='Show current changeset in ancestor branches')

    options, args = op.parse_args()

    # Create a ui object for printing progress messages
    class UI:
        def __init__(self, verbose):
            if verbose:
                self.status = self.message
            if verbose>1:
                self.note = self.message
            if verbose>2:
                self.debug = self.message
        def message(self, msg):
            sys.stderr.write(msg)
        def nomessage(self, msg):
            pass
        status = nomessage
        note = nomessage
        debug = nomessage
    ui = UI(options.Verbose)

    try:
        if args:
            log = []
            for d in args:
                log += createlog(ui, d, root=options.Root, cache=options.Cache)
        else:
            log = createlog(ui, root=options.Root, cache=options.Cache)
    except logerror, e:
        print e
        return

    changesets = createchangeset(ui, log, options.Fuzz)
    del log

    # Print changesets (optionally filtered)

    off = len(options.Revisions)
    branches = {}    # latest version number in each branch
    ancestors = {}   # parent branch
    for cs in changesets:

        if options.Ancestors:
            if cs.branch not in branches and cs.parents and cs.parents[0].id:
                ancestors[cs.branch] = changesets[cs.parents[0].id-1].branch, cs.parents[0].id
            branches[cs.branch] = cs.id

        # limit by branches
        if options.Branches and (cs.branch or 'HEAD') not in options.Branches:
            continue

        if not off:
            # Note: trailing spaces on several lines here are needed to have
            #       bug-for-bug compatibility with cvsps.
            print '---------------------'
            print 'PatchSet %d ' % cs.id
            print 'Date: %s' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2')
            print 'Author: %s' % cs.author
            print 'Branch: %s' % (cs.branch or 'HEAD')
            print 'Tag%s: %s ' % (['', 's'][len(cs.tags)>1],
                                  ','.join(cs.tags) or '(none)')
            if options.Parents and cs.parents:
                if len(cs.parents)>1:
                    print 'Parents: %s' % (','.join([str(p.id) for p in cs.parents]))
                else:
                    print 'Parent: %d' % cs.parents[0].id

            if options.Ancestors:
                b = cs.branch
                r = []
                while b:
                    b, c = ancestors[b]
                    r.append('%s:%d:%d' % (b or "HEAD", c, branches[b]))
                if r:
                    print 'Ancestors: %s' % (','.join(r))

            print 'Log:'
            print cs.comment
            print
            print 'Members: '
            for f in cs.entries:
                fn = f.file
                if fn.startswith(options.Prefix):
                    fn = fn[len(options.Prefix):]
                print '\t%s:%s->%s%s ' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL',
                                          '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead])
            print

        # have we seen the start tag?
        if options.Revisions and off:
            if options.Revisions[0] == str(cs.id) or \
                options.Revisions[0] in cs.tags:
                off = False

        # see if we reached the end tag
        if len(options.Revisions)>1 and not off:
            if options.Revisions[1] == str(cs.id) or \
                options.Revisions[1] in cs.tags:
                break


if __name__ == '__main__':
    main()