# HG changeset patch # User Frank Kingswood # Date 2008-12-10 14:02:54 # Node ID 16905fc2690f744eeb009b872ca7cd6bf2f93027 # Parent 732c54abd592d31e3e9cea8ba043321518c52c88 Add debugcvsps command, replacing cvsps script diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py --- a/hgext/convert/__init__.py +++ b/hgext/convert/__init__.py @@ -7,6 +7,7 @@ '''converting foreign VCS repositories to Mercurial''' import convcmd +import cvsps from mercurial import commands from mercurial.i18n import _ @@ -183,7 +184,18 @@ def convert(ui, src, dest=None, revmapfi def debugsvnlog(ui, **opts): return convcmd.debugsvnlog(ui, **opts) -commands.norepo += " convert debugsvnlog" +def debugcvsps(ui, *args, **opts): + '''Create changeset information from CVS + + This command is intended as a debugging tool for the CVS to Mercurial + converter, and can be used as a direct replacement for cvsps. + + Hg debugcvsps reads the CVS rlog for current directory (or any named + directory) in the CVS repository, and converts the log to a series of + changesets based on matching commit log entries and dates.''' + return cvsps.debugcvsps(ui, *args, **opts) + +commands.norepo += " convert debugsvnlog debugcvsps" cmdtable = { "convert": @@ -200,4 +212,22 @@ cmdtable = { (debugsvnlog, [], 'hg debugsvnlog'), + "debugcvsps": + (debugcvsps, + [ + # Main options shared with cvsps-2.1 + ('b', 'branches', [], _('Only return changes on specified branches')), + ('p', 'prefix', '', _('Prefix to remove from file names')), + ('r', 'revisions', [], _('Only return changes after or between specified tags')), + ('u', 'update-cache', None, _("Update cvs log cache")), + ('x', 'new-cache', None, _("Create new cvs log cache")), + ('z', 'fuzz', 60, _('Set commit time fuzz in seconds')), + ('', 'root', '', _('Specify cvsroot')), + # Options specific to builtin cvsps + ('', 'parents', '', _('Show parent changesets')), + ('', 'ancestors', '', _('Show current changeset in ancestor branches')), + # Options that are ignored for compatibility with cvsps-2.1 + ('A', 'cvs-direct', None, 'Ignored for compatibility'), + ], + 'hg debugcvsps [OPTION]... [PATH]...'), } diff --git a/hgext/convert/cvsps b/hgext/convert/cvsps deleted file mode 100644 --- a/hgext/convert/cvsps +++ /dev/null @@ -1,154 +0,0 @@ -#!/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() diff --git a/hgext/convert/cvsps.py b/hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py +++ b/hgext/convert/cvsps.py @@ -584,3 +584,95 @@ def createchangeset(ui, log, fuzz=60, me ui.status(_('%d changeset entries\n') % len(changesets)) return changesets + + +def debugcvsps(ui, *args, **opts): + '''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.''' + + if opts["new_cache"]: + cache = "write" + elif opts["update_cache"]: + cache = "update" + else: + cache = None + + revisions = opts["revisions"] + + try: + if args: + log = [] + for d in args: + log += createlog(ui, d, root=opts["root"], cache=cache) + else: + log = createlog(ui, root=opts["root"], cache=cache) + except logerror, e: + ui.write("%r\n"%e) + return + + changesets = createchangeset(ui, log, opts["fuzz"]) + del log + + # Print changesets (optionally filtered) + + off = len(revisions) + branches = {} # latest version number in each branch + ancestors = {} # parent branch + for cs in changesets: + + if opts["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 opts["branches"] and (cs.branch or 'HEAD') not in opts["branches"]: + continue + + if not off: + # Note: trailing spaces on several lines here are needed to have + # bug-for-bug compatibility with cvsps. + ui.write('---------------------\n') + ui.write('PatchSet %d \n' % cs.id) + ui.write('Date: %s\n' % util.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2')) + ui.write('Author: %s\n' % cs.author) + ui.write('Branch: %s\n' % (cs.branch or 'HEAD')) + ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags)>1], + ','.join(cs.tags) or '(none)')) + if opts["parents"] and cs.parents: + if len(cs.parents)>1: + ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents]))) + else: + ui.write('Parent: %d\n' % cs.parents[0].id) + + if opts["ancestors"]: + b = cs.branch + r = [] + while b: + b, c = ancestors[b] + r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) + if r: + ui.write('Ancestors: %s\n' % (','.join(r))) + + ui.write('Log:\n') + ui.write('%s\n\n' % cs.comment) + ui.write('Members: \n') + for f in cs.entries: + fn = f.file + if fn.startswith(opts["prefix"]): + fn = fn[len(opts["prefix"]):] + ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', + '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead])) + ui.write('\n') + + # have we seen the start tag? + if revisions and off: + if revisions[0] == str(cs.id) or \ + revisions[0] in cs.tags: + off = False + + # see if we reached the end tag + if len(revisions)>1 and not off: + if revisions[1] == str(cs.id) or \ + revisions[1] in cs.tags: + break