# HG changeset patch # User Frank Kingswood # Date 1213541993 -3600 # Node ID d2ac53fe216e70dac6b6e1251d0e6d3a5ea8d7f7 # Parent 5cd7a8433cd44487be357f98cbb7d9b9e886c59e convert: cvsps - User interface to CVS changeset code in cvsps.py diff -r 5cd7a8433cd4 -r d2ac53fe216e hgext/convert/cvsps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/convert/cvsps Sun Jun 15 15:59:53 2008 +0100 @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# +# Commandline front-end for cvsps.py +# +# Copyright 2008, Frank Kingswood +# +# 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()