repoman / repoman /

# Copyright 2009-2012 Edlund A/S
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Command dispatch handling.

import sys
import os
import getopt
import pdb
import urllib2
import datetime

from mercurial import fancyopts
from mercurial.util import checksignature
from mercurial.cmdutil import findrepo as _findrepo
from mercurial.dispatch import _parseconfig, _earlygetopt
import mercurial.extensions
import mercurial.hg
import hgext.color

from repoman import ui
from repoman import forest
from repoman import util
from repoman import commands
from repoman import cmdutil
from repoman import extensions

blocking_dependencies = {
        'merge': ['branch', 'push', 'pull', 'rebase', 'uncommit'],

def colorcmd(ui, opts):
    if ui.plain():
    mode = opts.get('color', ui.config('color', 'mode', 'auto'))
    if not mode:
        mode = ui.config('color', 'mode', 'auto')
    omode = mode
    if mode == 'auto' or mode == 'always':
        if == 'nt' and 'TERM' not in os.environ:
            # looks line a cmd.exe console, use win32 API or nothing
            mode = hgext.color.w32effects and 'win32' or 'none'
            mode = 'ansi'
    if mode == 'win32':
        if hgext.color.w32effects is None:
            # only warn if color.mode is explicitly set to win32
            ui.warn(_('win32console not found, please install pywin32\n'))
    elif mode != 'ansi':
    if (omode == 'always' or
        (omode == 'auto' and (os.environ.get('TERM') != 'dumb'
                                      and ui.formatted()))):
        hgext.color.colorui._colormode = mode
        if not issubclass(ui.__class__, hgext.color.colorui):
            hgext.color.colorui.__bases__ = (ui.__class__,)
            ui.__class__ = hgext.color.colorui

def is_blocked(ui, cmd, f=None, **options):
    if f is None:
        f = forest.Forest(ui, **options)
    if f.state is None:
        return None

    blocked = blocking_dependencies.get(
    if cmd in blocked:
    return None

def load_extensions(myui):
    # load required hg extensions
    for ext in ['mq', 'rebase']:
        myui.setconfig('extensions', ext, '')
    # load repoman extensions
    cmd_dict = dict(commands.commands)
    for name, ext in extensions.extensions():
    return cmd_dict

def _handle_exc(myui, options, err_text, extra_text=None):
    if myui:
        err_output = lambda x: myui.write_err(x, label='repoman.error')
        output = myui.write_stderr if myui else sys.stderr.write
        err_output = sys.stderr.write
        output = sys.stderr.write

    if extra_text:

    if '--debugger' in sys.argv:
    if myui is not None:

def run(argv):
        with open(os.path.expanduser(os.path.join('~', '.repolog')), 'a') as fh:
            fh.write('%s: %s: %s\n' % (datetime.datetime.utcnow().isoformat(), os.getcwd(), argv))
    except IOError:
        pass # ignore logging if writing to the file fails

    if '--version' in argv:
        argv = ['version']

    repoextpath = [x for x in os.environ.get('REPOPYTHONPATH', '').split(';' if == 'nt' else ':') if x]

    myui = None
    start_time = None
    options = None
        if '--simpleui' in argv:
            ui.ui = ui.SimpleUi

        myui = ui.ui()
        configopts = _earlygetopt(['--config'], argv)
        coloropts = _earlygetopt(['--color'], argv)
        coloropts = coloropts[0] if coloropts else ''
        _parseconfig(myui, configopts)
        colorcmd(myui, {'color': coloropts})
        cmd_dict = load_extensions(myui)
        cmd, options, cmdoptions, args = parse_commandline(myui, cmd_dict, argv)
        if options.get('debugger'):
        if options.get('time'):
            start_time = util.get_times()
        myui2 = ui.ui(**options)
        myui2.__class__ = myui.__class__
        myui = myui2
        _parseconfig(myui, configopts)
        colorcmd(myui, {'color': coloropts})
        myui.debugflag = bool(options.get('debug'))
        myui.verbose = myui.debugflag or bool(options.get('verbose'))
        myui.quiet = not myui.debugflag and bool(options.get('quiet'))
        myui.silent = not myui.debugflag and bool(options.get('silent'))
        myui._traceback = myui.tracebackflag = bool(options.get('traceback'))
        myui.filter = options.get('filter')
        myui._buffered = options.get('buffered')
        if not cmd:
            raise mercurial.error.UnknownCommand(args)

        if options.get('help'):
  , cmd)

        cmd_fnc = cmd_dict[cmd][0]

        # Non-forest commands.
        if cmd_fnc.__name__ in commands.nonforest_commands:
            checksignature(cmd_fnc)(myui, *args, **cmdoptions)

        # Module commands.
        elif cmd_fnc.__name__ in commands.module_commands:
            repo_path = options['repository'] or _findrepo(os.getcwd())
            if not repo_path or not os.path.isdir(os.path.join(repo_path, '.hg')):
                raise util.Abort('module %s not found' % repo_path)
            forest_path = os.path.join(repo_path, '..')
            if forest.is_forest(forest_path):
                f = forest.Forest(myui, forest_path=forest_path, **options)
                blocking = is_blocked(myui, cmd_fnc.__name__, f, **options)
                if blocking:
                    raise util.Abort('there is an outstanding %s operation that is blocking %s' % (blocking, cmd_fnc.__name__))
            repo = mercurial.hg.repository(myui, repo_path)
            checksignature(cmd_fnc)(myui, repo, *args, **cmdoptions)

        # Forest commands.
            forest_path = options['repository'] or forest.find_forest(os.getcwd())
            f = forest.Forest(myui, forest_path=forest_path, **options)
            blocking = is_blocked(myui, cmd_fnc.__name__, f, **options)
            if blocking:
                raise util.Abort('there is an outstanding %s operation that is blocking %s' % (blocking, cmd_fnc.__name__))
            checksignature(cmd_fnc)(myui, f, *args, **cmdoptions)

    except mercurial.error.AmbiguousCommand, inst:
        _handle_exc(myui, options,
                'ambiguous command\npossible commands: %s\n' %
                ', '.join(sorted([x[0] for x in inst.args[1]])))
    except util.SignatureError:
        _handle_exc(myui, options,
                'repo %s: invalid arguments\n' % (cmd,),
                'usage: repo %s %s\n' % (cmd, cmd_dict[cmd][3]))
    except (util.Abort, urllib2.HTTPError, SystemError, 
            util.UnrelatedSolutionError), inst:
        _handle_exc(myui, options,
                'abort: %s\n' % inst)
    except util.ModulesMissingError, inst:
        _handle_exc(myui, options,
                'abort: the following modules are missing: %s\n' %
                (', '.join(sorted(inst.args[0]))))
    except mercurial.error.UnknownCommand, inst:
        _handle_exc(myui, options,
                'unknown command: %s\n' % inst)
    except urllib2.URLError, inst:
        _handle_exc(myui, options,
                'abort: error communicating with remote host: %s\n' %
    except mercurial.error.RepoError, inst:
        _handle_exc(myui, options,
                'abort: %s!\n' % inst)

        if myui and start_time:
            util.print_times(myui, start_time)
        del myui

def parse_commandline(ui, cmd_dict, cmd_args):
    aliases = cmdutil.build_alias_map(cmd_dict)

    cmd = None
        # Parse global options.
        options = {}
        args = fancyopts.fancyopts(cmd_args, commands.globaloptions, options)
        cmd, args = args[0], args[1:]

        # Find command and parse command options.
            cmd, cmdinfo = cmdutil.findcmd(cmd, cmd_dict, aliases)
        except mercurial.error.UnknownCommand:
            # command may be defined using --config, return options early
            # handle error elsewhere
            return None, options, None, cmd

        cmdoptions = {}

        # combine global options into command options
        commandinfo = list(cmdinfo[2])
        option_names = [x[1] for x in commandinfo]
        for opt in commands.globaloptions:
            if opt[1] in option_names:

            commandinfo.append((opt[0], opt[1], options[opt[1]], opt[3]))

        args = fancyopts.fancyopts(args, commandinfo, cmdoptions, True)

        # separate global options back out
        for opt in commands.globaloptions:
            name = opt[1]

            if name in option_names:

            options[name] = cmdoptions[name]
            del cmdoptions[name]

        return cmd, options, cmdoptions, args

    except IndexError:
        return 'help', {}, {}, []

    except getopt.GetoptError, error:
        err_output = ui.write_err if ui else sys.stderr.write
        output = ui.write_stderr if ui else sys.stderr.write

        old_style = [arg for arg in cmd_args if len(arg) > 3 and arg[0] == '-' and arg[1] != '-']
        if old_style:
            err_output('\nwarning: did you forget to use gnu-style option names?\n')
            err_output('the following options look suspect: %s\n\n' % ', '.join(old_style))
        err_output('abort: %s\n' % error.msg)
        if cmd:
            output('usage: repo %s %s \n' % (cmd, cmd_dict[cmd][3]))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.