Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commands.py @ 4545:aea8fd7fb5e2
dispatch: move signal and exception handling to its own function
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 11 Jun 2007 21:09:23 -0500 |
parents | 930ed513c864 |
children | 5c8130691692 |
comparison
equal
deleted
inserted
replaced
4544:930ed513c864 | 4545:aea8fd7fb5e2 |
---|---|
3032 norepo = ("clone init version help debugancestor debugcomplete debugdata" | 3032 norepo = ("clone init version help debugancestor debugcomplete debugdata" |
3033 " debugindex debugindexdot debugdate debuginstall") | 3033 " debugindex debugindexdot debugdate debuginstall") |
3034 optionalrepo = ("paths serve showconfig") | 3034 optionalrepo = ("paths serve showconfig") |
3035 | 3035 |
3036 def run(): | 3036 def run(): |
3037 sys.exit(dispatch(sys.argv[1:])) | |
3038 | |
3039 def findpossible(ui, cmd): | |
3040 """ | |
3041 Return cmd -> (aliases, command table entry) | |
3042 for each matching command. | |
3043 Return debug commands (or their aliases) only if no normal command matches. | |
3044 """ | |
3045 choice = {} | |
3046 debugchoice = {} | |
3047 for e in table.keys(): | |
3048 aliases = e.lstrip("^").split("|") | |
3049 found = None | |
3050 if cmd in aliases: | |
3051 found = cmd | |
3052 elif not ui.config("ui", "strict"): | |
3053 for a in aliases: | |
3054 if a.startswith(cmd): | |
3055 found = a | |
3056 break | |
3057 if found is not None: | |
3058 if aliases[0].startswith("debug") or found.startswith("debug"): | |
3059 debugchoice[found] = (aliases, table[e]) | |
3060 else: | |
3061 choice[found] = (aliases, table[e]) | |
3062 | |
3063 if not choice and debugchoice: | |
3064 choice = debugchoice | |
3065 | |
3066 return choice | |
3067 | |
3068 def findcmd(ui, cmd): | |
3069 """Return (aliases, command table entry) for command string.""" | |
3070 choice = findpossible(ui, cmd) | |
3071 | |
3072 if choice.has_key(cmd): | |
3073 return choice[cmd] | |
3074 | |
3075 if len(choice) > 1: | |
3076 clist = choice.keys() | |
3077 clist.sort() | |
3078 raise AmbiguousCommand(cmd, clist) | |
3079 | |
3080 if choice: | |
3081 return choice.values()[0] | |
3082 | |
3083 raise UnknownCommand(cmd) | |
3084 | |
3085 class ParseError(Exception): | |
3086 """Exception raised on errors in parsing the command line.""" | |
3087 | |
3088 def parse(ui, args): | |
3089 options = {} | |
3090 cmdoptions = {} | |
3091 | |
3092 try: | |
3093 args = fancyopts.fancyopts(args, globalopts, options) | |
3094 except fancyopts.getopt.GetoptError, inst: | |
3095 raise ParseError(None, inst) | |
3096 | |
3097 if args: | |
3098 cmd, args = args[0], args[1:] | |
3099 aliases, i = findcmd(ui, cmd) | |
3100 cmd = aliases[0] | |
3101 defaults = ui.config("defaults", cmd) | |
3102 if defaults: | |
3103 args = shlex.split(defaults) + args | |
3104 c = list(i[1]) | |
3105 else: | |
3106 cmd = None | |
3107 c = [] | |
3108 | |
3109 # combine global options into local | |
3110 for o in globalopts: | |
3111 c.append((o[0], o[1], options[o[1]], o[3])) | |
3112 | |
3113 try: | |
3114 args = fancyopts.fancyopts(args, c, cmdoptions) | |
3115 except fancyopts.getopt.GetoptError, inst: | |
3116 raise ParseError(cmd, inst) | |
3117 | |
3118 # separate global options back out | |
3119 for o in globalopts: | |
3120 n = o[1] | |
3121 options[n] = cmdoptions[n] | |
3122 del cmdoptions[n] | |
3123 | |
3124 return (cmd, cmd and i[0] or None, args, options, cmdoptions) | |
3125 | |
3126 def parseconfig(config): | |
3127 """parse the --config options from the command line""" | |
3128 parsed = [] | |
3129 for cfg in config: | |
3130 try: | |
3131 name, value = cfg.split('=', 1) | |
3132 section, name = name.split('.', 1) | |
3133 if not section or not name: | |
3134 raise IndexError | |
3135 parsed.append((section, name, value)) | |
3136 except (IndexError, ValueError): | |
3137 raise util.Abort(_('malformed --config option: %s') % cfg) | |
3138 return parsed | |
3139 | |
3140 def catchterm(*args): | |
3141 raise util.SignalInterrupt | |
3142 | |
3143 def dispatch(args): | |
3144 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |
3145 num = getattr(signal, name, None) | |
3146 if num: signal.signal(num, catchterm) | |
3147 | |
3148 try: | 3037 try: |
3149 u = ui.ui(traceback='--traceback' in sys.argv[1:]) | 3038 u = ui.ui(traceback='--traceback' in sys.argv[1:]) |
3150 except util.Abort, inst: | 3039 except util.Abort, inst: |
3151 sys.stderr.write(_("abort: %s\n") % inst) | 3040 sys.stderr.write(_("abort: %s\n") % inst) |
3152 return -1 | 3041 return -1 |
3153 | 3042 sys.exit(runcatch(u, sys.argv[1:])) |
3154 extensions.loadall(u) | 3043 |
3155 u.addreadhook(extensions.loadall) | 3044 def runcatch(u, args): |
3045 def catchterm(*args): | |
3046 raise util.SignalInterrupt | |
3047 | |
3048 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |
3049 num = getattr(signal, name, None) | |
3050 if num: signal.signal(num, catchterm) | |
3156 | 3051 |
3157 try: | 3052 try: |
3158 cmd, func, args, options, cmdoptions = parse(u, args) | 3053 return dispatch(u, args) |
3159 if options["encoding"]: | |
3160 util._encoding = options["encoding"] | |
3161 if options["encodingmode"]: | |
3162 util._encodingmode = options["encodingmode"] | |
3163 if options["time"]: | |
3164 def get_times(): | |
3165 t = os.times() | |
3166 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock() | |
3167 t = (t[0], t[1], t[2], t[3], time.clock()) | |
3168 return t | |
3169 s = get_times() | |
3170 def print_time(): | |
3171 t = get_times() | |
3172 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") % | |
3173 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3])) | |
3174 atexit.register(print_time) | |
3175 | |
3176 # enter the debugger before command execution | |
3177 if options['debugger']: | |
3178 pdb.set_trace() | |
3179 | |
3180 try: | |
3181 if options['cwd']: | |
3182 os.chdir(options['cwd']) | |
3183 | |
3184 u.updateopts(options["verbose"], options["debug"], options["quiet"], | |
3185 not options["noninteractive"], options["traceback"], | |
3186 parseconfig(options["config"])) | |
3187 | |
3188 path = u.expandpath(options["repository"]) or "" | |
3189 repo = path and hg.repository(u, path=path) or None | |
3190 if repo and not repo.local(): | |
3191 raise util.Abort(_("repository '%s' is not local") % path) | |
3192 | |
3193 if options['help']: | |
3194 return help_(u, cmd, options['version']) | |
3195 elif options['version']: | |
3196 return version_(u) | |
3197 elif not cmd: | |
3198 return help_(u, 'shortlist') | |
3199 | |
3200 if cmd not in norepo.split(): | |
3201 try: | |
3202 if not repo: | |
3203 repo = hg.repository(u, path=path) | |
3204 u = repo.ui | |
3205 except hg.RepoError: | |
3206 if cmd not in optionalrepo.split(): | |
3207 raise | |
3208 d = lambda: func(u, repo, *args, **cmdoptions) | |
3209 else: | |
3210 d = lambda: func(u, *args, **cmdoptions) | |
3211 | |
3212 try: | |
3213 if options['profile']: | |
3214 import hotshot, hotshot.stats | |
3215 prof = hotshot.Profile("hg.prof") | |
3216 try: | |
3217 try: | |
3218 return prof.runcall(d) | |
3219 except: | |
3220 try: | |
3221 u.warn(_('exception raised - generating ' | |
3222 'profile anyway\n')) | |
3223 except: | |
3224 pass | |
3225 raise | |
3226 finally: | |
3227 prof.close() | |
3228 stats = hotshot.stats.load("hg.prof") | |
3229 stats.strip_dirs() | |
3230 stats.sort_stats('time', 'calls') | |
3231 stats.print_stats(40) | |
3232 elif options['lsprof']: | |
3233 try: | |
3234 from mercurial import lsprof | |
3235 except ImportError: | |
3236 raise util.Abort(_( | |
3237 'lsprof not available - install from ' | |
3238 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/')) | |
3239 p = lsprof.Profiler() | |
3240 p.enable(subcalls=True) | |
3241 try: | |
3242 return d() | |
3243 finally: | |
3244 p.disable() | |
3245 stats = lsprof.Stats(p.getstats()) | |
3246 stats.sort() | |
3247 stats.pprint(top=10, file=sys.stderr, climit=5) | |
3248 else: | |
3249 return d() | |
3250 finally: | |
3251 u.flush() | |
3252 except: | |
3253 # enter the debugger when we hit an exception | |
3254 if options['debugger']: | |
3255 pdb.post_mortem(sys.exc_info()[2]) | |
3256 u.print_exc() | |
3257 raise | |
3258 except ParseError, inst: | |
3259 if inst.args[0]: | |
3260 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1])) | |
3261 help_(u, inst.args[0]) | |
3262 else: | |
3263 u.warn(_("hg: %s\n") % inst.args[1]) | |
3264 help_(u, 'shortlist') | |
3265 except AmbiguousCommand, inst: | |
3266 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") % | |
3267 (inst.args[0], " ".join(inst.args[1]))) | |
3268 except UnknownCommand, inst: | |
3269 u.warn(_("hg: unknown command '%s'\n") % inst.args[0]) | |
3270 help_(u, 'shortlist') | |
3271 except hg.RepoError, inst: | 3054 except hg.RepoError, inst: |
3272 u.warn(_("abort: %s!\n") % inst) | 3055 u.warn(_("abort: %s!\n") % inst) |
3273 except lock.LockHeld, inst: | 3056 except lock.LockHeld, inst: |
3274 if inst.errno == errno.ETIMEDOUT: | 3057 if inst.errno == errno.ETIMEDOUT: |
3275 reason = _('timed out waiting for lock held by %s') % inst.locker | 3058 reason = _('timed out waiting for lock held by %s') % inst.locker |
3348 u.warn(_("** Mercurial Distributed SCM (version %s)\n") | 3131 u.warn(_("** Mercurial Distributed SCM (version %s)\n") |
3349 % version.get_version()) | 3132 % version.get_version()) |
3350 raise | 3133 raise |
3351 | 3134 |
3352 return -1 | 3135 return -1 |
3136 | |
3137 def findpossible(ui, cmd): | |
3138 """ | |
3139 Return cmd -> (aliases, command table entry) | |
3140 for each matching command. | |
3141 Return debug commands (or their aliases) only if no normal command matches. | |
3142 """ | |
3143 choice = {} | |
3144 debugchoice = {} | |
3145 for e in table.keys(): | |
3146 aliases = e.lstrip("^").split("|") | |
3147 found = None | |
3148 if cmd in aliases: | |
3149 found = cmd | |
3150 elif not ui.config("ui", "strict"): | |
3151 for a in aliases: | |
3152 if a.startswith(cmd): | |
3153 found = a | |
3154 break | |
3155 if found is not None: | |
3156 if aliases[0].startswith("debug") or found.startswith("debug"): | |
3157 debugchoice[found] = (aliases, table[e]) | |
3158 else: | |
3159 choice[found] = (aliases, table[e]) | |
3160 | |
3161 if not choice and debugchoice: | |
3162 choice = debugchoice | |
3163 | |
3164 return choice | |
3165 | |
3166 def findcmd(ui, cmd): | |
3167 """Return (aliases, command table entry) for command string.""" | |
3168 choice = findpossible(ui, cmd) | |
3169 | |
3170 if choice.has_key(cmd): | |
3171 return choice[cmd] | |
3172 | |
3173 if len(choice) > 1: | |
3174 clist = choice.keys() | |
3175 clist.sort() | |
3176 raise AmbiguousCommand(cmd, clist) | |
3177 | |
3178 if choice: | |
3179 return choice.values()[0] | |
3180 | |
3181 raise UnknownCommand(cmd) | |
3182 | |
3183 class ParseError(Exception): | |
3184 """Exception raised on errors in parsing the command line.""" | |
3185 | |
3186 def parse(ui, args): | |
3187 options = {} | |
3188 cmdoptions = {} | |
3189 | |
3190 try: | |
3191 args = fancyopts.fancyopts(args, globalopts, options) | |
3192 except fancyopts.getopt.GetoptError, inst: | |
3193 raise ParseError(None, inst) | |
3194 | |
3195 if args: | |
3196 cmd, args = args[0], args[1:] | |
3197 aliases, i = findcmd(ui, cmd) | |
3198 cmd = aliases[0] | |
3199 defaults = ui.config("defaults", cmd) | |
3200 if defaults: | |
3201 args = shlex.split(defaults) + args | |
3202 c = list(i[1]) | |
3203 else: | |
3204 cmd = None | |
3205 c = [] | |
3206 | |
3207 # combine global options into local | |
3208 for o in globalopts: | |
3209 c.append((o[0], o[1], options[o[1]], o[3])) | |
3210 | |
3211 try: | |
3212 args = fancyopts.fancyopts(args, c, cmdoptions) | |
3213 except fancyopts.getopt.GetoptError, inst: | |
3214 raise ParseError(cmd, inst) | |
3215 | |
3216 # separate global options back out | |
3217 for o in globalopts: | |
3218 n = o[1] | |
3219 options[n] = cmdoptions[n] | |
3220 del cmdoptions[n] | |
3221 | |
3222 return (cmd, cmd and i[0] or None, args, options, cmdoptions) | |
3223 | |
3224 def parseconfig(config): | |
3225 """parse the --config options from the command line""" | |
3226 parsed = [] | |
3227 for cfg in config: | |
3228 try: | |
3229 name, value = cfg.split('=', 1) | |
3230 section, name = name.split('.', 1) | |
3231 if not section or not name: | |
3232 raise IndexError | |
3233 parsed.append((section, name, value)) | |
3234 except (IndexError, ValueError): | |
3235 raise util.Abort(_('malformed --config option: %s') % cfg) | |
3236 return parsed | |
3237 | |
3238 def dispatch(u, args): | |
3239 extensions.loadall(u) | |
3240 u.addreadhook(extensions.loadall) | |
3241 | |
3242 try: | |
3243 cmd, func, args, options, cmdoptions = parse(u, args) | |
3244 if options["encoding"]: | |
3245 util._encoding = options["encoding"] | |
3246 if options["encodingmode"]: | |
3247 util._encodingmode = options["encodingmode"] | |
3248 if options["time"]: | |
3249 def get_times(): | |
3250 t = os.times() | |
3251 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock() | |
3252 t = (t[0], t[1], t[2], t[3], time.clock()) | |
3253 return t | |
3254 s = get_times() | |
3255 def print_time(): | |
3256 t = get_times() | |
3257 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") % | |
3258 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3])) | |
3259 atexit.register(print_time) | |
3260 | |
3261 # enter the debugger before command execution | |
3262 if options['debugger']: | |
3263 pdb.set_trace() | |
3264 | |
3265 try: | |
3266 if options['cwd']: | |
3267 os.chdir(options['cwd']) | |
3268 | |
3269 u.updateopts(options["verbose"], options["debug"], options["quiet"], | |
3270 not options["noninteractive"], options["traceback"], | |
3271 parseconfig(options["config"])) | |
3272 | |
3273 path = u.expandpath(options["repository"]) or "" | |
3274 repo = path and hg.repository(u, path=path) or None | |
3275 if repo and not repo.local(): | |
3276 raise util.Abort(_("repository '%s' is not local") % path) | |
3277 | |
3278 if options['help']: | |
3279 return help_(u, cmd, options['version']) | |
3280 elif options['version']: | |
3281 return version_(u) | |
3282 elif not cmd: | |
3283 return help_(u, 'shortlist') | |
3284 | |
3285 if cmd not in norepo.split(): | |
3286 try: | |
3287 if not repo: | |
3288 repo = hg.repository(u, path=path) | |
3289 u = repo.ui | |
3290 except hg.RepoError: | |
3291 if cmd not in optionalrepo.split(): | |
3292 raise | |
3293 d = lambda: func(u, repo, *args, **cmdoptions) | |
3294 else: | |
3295 d = lambda: func(u, *args, **cmdoptions) | |
3296 | |
3297 try: | |
3298 if options['profile']: | |
3299 import hotshot, hotshot.stats | |
3300 prof = hotshot.Profile("hg.prof") | |
3301 try: | |
3302 try: | |
3303 return prof.runcall(d) | |
3304 except: | |
3305 try: | |
3306 u.warn(_('exception raised - generating ' | |
3307 'profile anyway\n')) | |
3308 except: | |
3309 pass | |
3310 raise | |
3311 finally: | |
3312 prof.close() | |
3313 stats = hotshot.stats.load("hg.prof") | |
3314 stats.strip_dirs() | |
3315 stats.sort_stats('time', 'calls') | |
3316 stats.print_stats(40) | |
3317 elif options['lsprof']: | |
3318 try: | |
3319 from mercurial import lsprof | |
3320 except ImportError: | |
3321 raise util.Abort(_( | |
3322 'lsprof not available - install from ' | |
3323 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/')) | |
3324 p = lsprof.Profiler() | |
3325 p.enable(subcalls=True) | |
3326 try: | |
3327 return d() | |
3328 finally: | |
3329 p.disable() | |
3330 stats = lsprof.Stats(p.getstats()) | |
3331 stats.sort() | |
3332 stats.pprint(top=10, file=sys.stderr, climit=5) | |
3333 else: | |
3334 return d() | |
3335 finally: | |
3336 u.flush() | |
3337 except: | |
3338 # enter the debugger when we hit an exception | |
3339 if options['debugger']: | |
3340 pdb.post_mortem(sys.exc_info()[2]) | |
3341 u.print_exc() | |
3342 raise | |
3343 except ParseError, inst: | |
3344 if inst.args[0]: | |
3345 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1])) | |
3346 help_(u, inst.args[0]) | |
3347 else: | |
3348 u.warn(_("hg: %s\n") % inst.args[1]) | |
3349 help_(u, 'shortlist') | |
3350 except AmbiguousCommand, inst: | |
3351 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") % | |
3352 (inst.args[0], " ".join(inst.args[1]))) | |
3353 except UnknownCommand, inst: | |
3354 u.warn(_("hg: unknown command '%s'\n") % inst.args[0]) | |
3355 help_(u, 'shortlist') |