/tortoisehg/hgtk/hgtk.py

https://bitbucket.org/tortoisehg/hgtk/ · Python · 832 lines · 761 code · 49 blank · 22 comment · 106 complexity · ecb6846f382e24ae5e8e3e013cf0da5d MD5 · raw file

  1. # hgtk.py - front-end script for TortoiseHg dialogs
  2. #
  3. # Copyright 2008 Steve Borho <steve@borho.org>
  4. # Copyright 2008 TK Soh <teekaysoh@gmail.com>
  5. #
  6. # This software may be used and distributed according to the terms of the
  7. # GNU General Public License version 2, incorporated herein by reference.
  8. shortlicense = '''
  9. Copyright (C) 2008-2010 Steve Borho <steve@borho.org> and others.
  10. This is free software; see the source for copying conditions. There is NO
  11. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. '''
  13. import os
  14. import pdb
  15. import sys
  16. import subprocess
  17. import traceback
  18. import gtk
  19. import gobject
  20. import mercurial.ui as _ui
  21. from mercurial import hg, util, fancyopts, cmdutil, extensions, error
  22. from tortoisehg.util.i18n import agettext as _
  23. from tortoisehg.util import hglib, paths, shlib, i18n
  24. from tortoisehg.util import version as thgversion
  25. try:
  26. from tortoisehg.util.config import nofork as config_nofork
  27. except ImportError:
  28. config_nofork = None
  29. from tortoisehg.hgtk import textview
  30. try:
  31. import win32con
  32. openflags = win32con.CREATE_NO_WINDOW
  33. except ImportError:
  34. openflags = 0
  35. nonrepo_commands = '''userconfig shellconfig clone debugcomplete init
  36. about help version thgstatus serve'''
  37. # Add TortoiseHg signals, hooked to key accelerators in gtklib
  38. for sig in ('copy-clipboard', 'thg-diff', 'thg-parent', 'thg-rename',
  39. 'thg-revision', 'mq-move-up', 'mq-move-down', 'mq-move-top',
  40. 'mq-move-bottom', 'mq-pop', 'mq-push'):
  41. gobject.signal_new(sig, gtk.TreeView,
  42. gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ())
  43. for sig in ('thg-exit', 'thg-close', 'thg-refresh', 'thg-accept',
  44. 'thg-reflow', 'status-scroll-down', 'status-scroll-up',
  45. 'status-next-file', 'status-previous-file',
  46. 'status-select-all', 'status-next-page',
  47. 'status-previous-page'):
  48. gobject.signal_new(sig, gtk.Window,
  49. gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ())
  50. for sig in ('thg-close', 'thg-new'):
  51. gobject.signal_new(sig, gtk.Notebook,
  52. gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ())
  53. for sig in ('thg-undo', 'thg-redo'):
  54. gobject.signal_new(sig, textview.UndoableTextView,
  55. gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ())
  56. gtkmainalive = False
  57. def dispatch(args):
  58. "run the command specified in args"
  59. try:
  60. u = _ui.ui()
  61. if '--traceback' in args:
  62. u.setconfig('ui', 'traceback', 'on')
  63. if '--debugger' in args:
  64. pdb.set_trace()
  65. return _runcatch(u, args)
  66. except SystemExit:
  67. pass
  68. except KeyboardInterrupt:
  69. print _('\nCaught keyboard interrupt, aborting.\n')
  70. except:
  71. from tortoisehg.hgtk.bugreport import run
  72. if '--debugger' in args:
  73. pdb.post_mortem(sys.exc_info()[2])
  74. error = traceback.format_exc()
  75. opts = {}
  76. opts['cmd'] = ' '.join(sys.argv[1:])
  77. opts['error'] = error
  78. opts['nofork'] = True
  79. if gtkmainalive:
  80. dlg = run(u, **opts)
  81. dlg.display()
  82. dlg.show_all()
  83. else:
  84. gtkrun(run, u, **opts)
  85. origwdir = os.getcwd()
  86. def portable_fork(ui, opts):
  87. if 'THG_HGTK_SPAWN' in os.environ or (
  88. not opts.get('fork') and opts.get('nofork')):
  89. return
  90. elif ui.configbool('tortoisehg', 'hgtkfork', None) is not None:
  91. if not ui.configbool('tortoisehg', 'hgtkfork'):
  92. return
  93. elif config_nofork:
  94. return
  95. # Spawn background process and exit
  96. if hasattr(sys, "frozen"):
  97. args = sys.argv
  98. else:
  99. args = [sys.executable] + sys.argv
  100. os.environ['THG_HGTK_SPAWN'] = '1'
  101. cmdline = subprocess.list2cmdline(args)
  102. os.chdir(origwdir)
  103. subprocess.Popen(cmdline,
  104. creationflags=openflags,
  105. shell=True)
  106. sys.exit(0)
  107. def get_list_from_file(filename):
  108. try:
  109. if filename == '-':
  110. lines = [ x.replace("\n", "") for x in sys.stdin.readlines() ]
  111. else:
  112. fd = open(filename, "r")
  113. lines = [ x.replace("\n", "") for x in fd.readlines() ]
  114. fd.close()
  115. os.unlink(filename)
  116. except IOError, e:
  117. sys.stderr.write(_('can not read file "%s". Ignored.\n') % filename)
  118. return []
  119. # Convert absolute file paths to repo/cwd canonical
  120. cwd = os.getcwd()
  121. root = paths.find_root(cwd)
  122. if not root:
  123. return lines
  124. if cwd == root:
  125. cwd_rel = ''
  126. else:
  127. cwd_rel = cwd[len(root+os.sep):] + os.sep
  128. files = []
  129. for f in lines:
  130. try:
  131. cpath = util.canonpath(root, cwd, f)
  132. # canonpath will abort on .hg/ paths
  133. except util.Abort:
  134. continue
  135. if cpath.startswith(cwd_rel):
  136. cpath = cpath[len(cwd_rel):]
  137. files.append(cpath)
  138. else:
  139. files.append(f)
  140. return files
  141. def _parse(ui, args):
  142. options = {}
  143. cmdoptions = {}
  144. try:
  145. args = fancyopts.fancyopts(args, globalopts, options)
  146. except fancyopts.getopt.GetoptError, inst:
  147. raise error.ParseError(None, inst)
  148. if args:
  149. alias, args = args[0], args[1:]
  150. aliases, i = cmdutil.findcmd(alias, table, ui.config("ui", "strict"))
  151. for a in aliases:
  152. if a.startswith(alias):
  153. alias = a
  154. break
  155. cmd = aliases[0]
  156. c = list(i[1])
  157. else:
  158. alias = None
  159. cmd = None
  160. c = []
  161. # combine global options into local
  162. for o in globalopts:
  163. c.append((o[0], o[1], options[o[1]], o[3]))
  164. try:
  165. args = fancyopts.fancyopts(args, c, cmdoptions)
  166. except fancyopts.getopt.GetoptError, inst:
  167. raise error.ParseError(cmd, inst)
  168. # separate global options back out
  169. for o in globalopts:
  170. n = o[1]
  171. options[n] = cmdoptions[n]
  172. del cmdoptions[n]
  173. listfile = options.get('listfile')
  174. if listfile:
  175. del options['listfile']
  176. args += get_list_from_file(listfile)
  177. return (cmd, cmd and i[0] or None, args, options, cmdoptions, alias)
  178. def _runcatch(ui, args):
  179. try:
  180. try:
  181. return runcommand(ui, args)
  182. finally:
  183. ui.flush()
  184. except error.ParseError, inst:
  185. if inst.args[0]:
  186. ui.status(_("hgtk %s: %s\n") % (inst.args[0], inst.args[1]))
  187. help_(ui, inst.args[0])
  188. else:
  189. ui.status(_("hgtk: %s\n") % inst.args[1])
  190. help_(ui, 'shortlist')
  191. except error.AmbiguousCommand, inst:
  192. ui.status(_("hgtk: command '%s' is ambiguous:\n %s\n") %
  193. (inst.args[0], " ".join(inst.args[1])))
  194. except error.UnknownCommand, inst:
  195. ui.status(_("hgtk: unknown command '%s'\n") % inst.args[0])
  196. help_(ui, 'shortlist')
  197. except error.RepoError, inst:
  198. ui.status(_("abort: %s!\n") % inst)
  199. return -1
  200. def runcommand(ui, args):
  201. cmd, func, args, options, cmdoptions, alias = _parse(ui, args)
  202. cmdoptions['alias'] = alias
  203. ui.setconfig("ui", "verbose", str(bool(options["verbose"])))
  204. i18n.setlanguage(ui.config('tortoisehg', 'ui.language'))
  205. if options['help']:
  206. return help_(ui, cmd)
  207. elif not cmd:
  208. return help_(ui, 'shortlist')
  209. path = options['repository']
  210. if path:
  211. if path.startswith('bundle:'):
  212. s = path[7:].split('+', 1)
  213. if len(s) == 1:
  214. path, bundle = os.getcwd(), s[0]
  215. else:
  216. path, bundle = s
  217. cmdoptions['bundle'] = os.path.abspath(bundle)
  218. path = ui.expandpath(path)
  219. cmdoptions['repository'] = path
  220. os.chdir(path)
  221. if options['fork']:
  222. cmdoptions['fork'] = True
  223. if options['nofork'] or options['profile']:
  224. cmdoptions['nofork'] = True
  225. path = paths.find_root(os.getcwd())
  226. if path:
  227. try:
  228. lui = ui.copy()
  229. lui.readconfig(os.path.join(path, ".hg", "hgrc"))
  230. except IOError:
  231. pass
  232. else:
  233. lui = ui
  234. hglib.wrapextensionsloader() # enable blacklist of extensions
  235. extensions.loadall(ui)
  236. if options['quiet']:
  237. ui.quiet = True
  238. if cmd not in nonrepo_commands.split() and not path:
  239. raise error.RepoError(_("There is no Mercurial repository here"
  240. " (.hg not found)"))
  241. cmdoptions['mainapp'] = True
  242. d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
  243. return _runcommand(lui, options, cmd, d)
  244. def _runcommand(ui, options, cmd, cmdfunc):
  245. def checkargs():
  246. try:
  247. return cmdfunc()
  248. except error.SignatureError:
  249. raise error.ParseError(cmd, _("invalid arguments"))
  250. if options['profile']:
  251. format = ui.config('profiling', 'format', default='text')
  252. if not format in ['text', 'kcachegrind']:
  253. ui.warn(_("unrecognized profiling format '%s'"
  254. " - Ignored\n") % format)
  255. format = 'text'
  256. output = ui.config('profiling', 'output')
  257. if output:
  258. path = ui.expandpath(output)
  259. ostream = open(path, 'wb')
  260. else:
  261. ostream = sys.stderr
  262. try:
  263. from mercurial import lsprof
  264. except ImportError:
  265. raise util.Abort(_(
  266. 'lsprof not available - install from '
  267. 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
  268. p = lsprof.Profiler()
  269. p.enable(subcalls=True)
  270. try:
  271. return checkargs()
  272. finally:
  273. p.disable()
  274. if format == 'kcachegrind':
  275. import lsprofcalltree
  276. calltree = lsprofcalltree.KCacheGrind(p)
  277. calltree.output(ostream)
  278. else:
  279. # format == 'text'
  280. stats = lsprof.Stats(p.getstats())
  281. stats.sort()
  282. stats.pprint(top=10, file=ostream, climit=5)
  283. if output:
  284. ostream.close()
  285. else:
  286. return checkargs()
  287. mainwindow = None
  288. def thgexit(win):
  289. if hasattr(mainwindow, 'should_live'):
  290. if mainwindow.should_live(): return
  291. mainwindow.destroy()
  292. def gtkrun(dlgfunc, ui, *args, **opts):
  293. portable_fork(ui, opts)
  294. win = dlgfunc(ui, *args, **opts)
  295. if not win:
  296. return
  297. global mainwindow, gtkmainalive
  298. mainwindow = win
  299. if hasattr(win, 'display'):
  300. win.display()
  301. win.show_all()
  302. if 'response' in gobject.signal_list_names(win):
  303. win.connect('response', gtk.main_quit)
  304. win.connect('destroy', gtk.main_quit)
  305. gtk.gdk.threads_init()
  306. gtk.gdk.threads_enter()
  307. gtkmainalive = True
  308. gtk.main()
  309. gtkmainalive = False
  310. gtk.gdk.threads_leave()
  311. def about(ui, *pats, **opts):
  312. """about TortoiseHg"""
  313. from tortoisehg.hgtk.about import run
  314. gtkrun(run, ui, *pats, **opts)
  315. def add(ui, *pats, **opts):
  316. """add files"""
  317. from tortoisehg.hgtk.quickop import run
  318. gtkrun(run, ui, *pats, **opts)
  319. def thgstatus(ui, *pats, **opts):
  320. """update TortoiseHg status cache"""
  321. from tortoisehg.util.thgstatus import run
  322. run(ui, *pats, **opts)
  323. def clone(ui, *pats, **opts):
  324. """clone tool"""
  325. from tortoisehg.hgtk.clone import run
  326. gtkrun(run, ui, *pats, **opts)
  327. def commit(ui, *pats, **opts):
  328. """commit tool"""
  329. # move cwd to repo root if repo is merged, so we can show
  330. # all the changed files
  331. repo = hg.repository(ui, path=paths.find_root())
  332. if len(repo.parents()) > 1:
  333. os.chdir(repo.root)
  334. pats = []
  335. from tortoisehg.hgtk.commit import run
  336. gtkrun(run, ui, *pats, **opts)
  337. def shelve(ui, *pats, **opts):
  338. """shelve/unshelve tool"""
  339. from tortoisehg.hgtk.thgshelve import run
  340. gtkrun(run, ui, *pats, **opts)
  341. def userconfig(ui, *pats, **opts):
  342. """user configuration editor"""
  343. from tortoisehg.hgtk.thgconfig import run
  344. gtkrun(run, ui, *pats, **opts)
  345. def repoconfig(ui, *pats, **opts):
  346. """repository configuration editor"""
  347. from tortoisehg.hgtk.thgconfig import run
  348. gtkrun(run, ui, *pats, **opts)
  349. def shellconfig(ui, *pats, **opts):
  350. """Explorer extension configuration editor"""
  351. from tortoisehg.hgtk.shellconf import run
  352. gtkrun(run, ui, *pats, **opts)
  353. def rename(ui, *pats, **opts):
  354. """rename a single file or directory"""
  355. if not pats or len(pats) > 2:
  356. from tortoisehg.hgtk import gdialog
  357. gdialog.Prompt(_('Rename error'),
  358. _('rename takes one or two path arguments'), None).run()
  359. return
  360. from tortoisehg.hgtk.rename import run
  361. gtkrun(run, ui, *pats, **opts)
  362. def guess(ui, *pats, **opts):
  363. """guess previous renames or copies"""
  364. from tortoisehg.hgtk.guess import run
  365. gtkrun(run, ui, *pats, **opts)
  366. def datamine(ui, *pats, **opts):
  367. """repository search and annotate tool"""
  368. from tortoisehg.hgtk.datamine import run
  369. gtkrun(run, ui, *pats, **opts)
  370. def hgignore(ui, *pats, **opts):
  371. """ignore filter editor"""
  372. from tortoisehg.hgtk.hgignore import run
  373. gtkrun(run, ui, *pats, **opts)
  374. def hginit(ui, *pats, **opts):
  375. """repository initialization tool"""
  376. from tortoisehg.hgtk.hginit import run
  377. gtkrun(run, ui, *pats, **opts)
  378. def log(ui, *pats, **opts):
  379. """Repository Explorer (changelog viewer)"""
  380. from tortoisehg.hgtk.history import run
  381. gtkrun(run, ui, *pats, **opts)
  382. def merge(ui, *pats, **opts):
  383. """merge tool"""
  384. from tortoisehg.hgtk.merge import run
  385. gtkrun(run, ui, *pats, **opts)
  386. def recovery(ui, *pats, **opts):
  387. """recover, rollback & verify"""
  388. from tortoisehg.hgtk.recovery import run
  389. gtkrun(run, ui, *pats, **opts)
  390. def remove(ui, *pats, **opts):
  391. """file status viewer in remove mode"""
  392. from tortoisehg.hgtk.quickop import run
  393. gtkrun(run, ui, *pats, **opts)
  394. def revert(ui, *pats, **opts):
  395. """file status viewer in revert mode"""
  396. from tortoisehg.hgtk.quickop import run
  397. gtkrun(run, ui, *pats, **opts)
  398. def forget(ui, *pats, **opts):
  399. """file status viewer in forget mode"""
  400. from tortoisehg.hgtk.quickop import run
  401. gtkrun(run, ui, *pats, **opts)
  402. def serve(ui, *pats, **opts):
  403. """web server"""
  404. from tortoisehg.hgtk.serve import run
  405. if paths.find_root() == None and not (opts['web_conf'] or opts['webdir_conf']):
  406. raise error.RepoError(_("There is no Mercurial repository here"
  407. " (.hg not found)"))
  408. gtkrun(run, ui, *pats, **opts)
  409. def status(ui, *pats, **opts):
  410. """file status & diff viewer"""
  411. from tortoisehg.hgtk.status import run
  412. gtkrun(run, ui, *pats, **opts)
  413. def strip(ui, *pats, **opts):
  414. """strip changesets"""
  415. from tortoisehg.hgtk.thgstrip import run
  416. gtkrun(run, ui, *pats, **opts)
  417. def synch(ui, *pats, **opts):
  418. """repository synchronization tool"""
  419. from tortoisehg.hgtk.synch import run
  420. cmd = opts['alias']
  421. if cmd in ('push', 'outgoing', 'email'):
  422. opts['pushmode'] = True
  423. else:
  424. opts['pushmode'] = False
  425. gtkrun(run, ui, *pats, **opts)
  426. def update(ui, *pats, **opts):
  427. """update/checkout tool"""
  428. from tortoisehg.hgtk.update import run
  429. gtkrun(run, ui, *pats, **opts)
  430. def browse(ui, *pats, **opts):
  431. """browse repository state"""
  432. from tortoisehg.hgtk.browse import run
  433. gtkrun(run, ui, *pats, **opts)
  434. def vdiff(ui, *pats, **opts):
  435. """launch configured visual diff tool"""
  436. from tortoisehg.hgtk.visdiff import run
  437. gtkrun(run, ui, *pats, **opts)
  438. def thgimport(ui, *pats, **opts):
  439. """import patches to repository/patch queue"""
  440. from tortoisehg.hgtk.thgimport import run
  441. gtkrun(run, ui, *pats, **opts)
  442. def mpatch(ui, rejfile, *pats, **opts):
  443. """Attempt to resolve conflicts in a .rej file"""
  444. def abort(err):
  445. from tortoisehg.hgtk import gdialog
  446. gdialog.Prompt(_('mpatch error'), err, None).run()
  447. return None
  448. if not rejfile or pats or not rejfile.endswith('.rej'):
  449. return abort(_('mpatch expects *.rej file argument\n'))
  450. if not os.path.exists(rejfile):
  451. return abort(_('%s does not exist\n') % rejfile)
  452. # Assume patch was made from repo root, and arrange ourselves thusly
  453. repo = hg.repository(ui, path=paths.find_root())
  454. rejfile = util.canonpath(repo.root, repo.getcwd(), rejfile)
  455. os.chdir(repo.root)
  456. source = rejfile[:-4]
  457. if not os.path.exists(source):
  458. return abort(_('%s does not exist\n') % source)
  459. from tortoisehg.util import prej
  460. from tortoisehg.hgtk import visdiff
  461. prej.run(ui, rejfile, source, visdiff.filemerge)
  462. ### help management, adapted from mercurial.commands.help_()
  463. def help_(ui, name=None, with_version=False, **opts):
  464. """show help for a command, extension, or list of commands
  465. With no arguments, print a list of commands and short help.
  466. Given a command name, print help for that command.
  467. Given an extension name, print help for that extension, and the
  468. commands it provides."""
  469. option_lists = []
  470. textwidth = ui.termwidth() - 2
  471. def addglobalopts(aliases):
  472. if ui.verbose:
  473. option_lists.append((_("global options:"), globalopts))
  474. if name == 'shortlist':
  475. option_lists.append((_('use "hgtk help" for the full list '
  476. 'of commands'), ()))
  477. else:
  478. if name == 'shortlist':
  479. msg = _('use "hgtk help" for the full list of commands '
  480. 'or "hgtk -v" for details')
  481. elif aliases:
  482. msg = _('use "hgtk -v help%s" to show aliases and '
  483. 'global options') % (name and " " + name or "")
  484. else:
  485. msg = _('use "hgtk -v help %s" to show global options') % name
  486. option_lists.append((msg, ()))
  487. def helpcmd(name):
  488. if with_version:
  489. version(ui)
  490. ui.write('\n')
  491. try:
  492. aliases, i = cmdutil.findcmd(name, table, False)
  493. except error.AmbiguousCommand, inst:
  494. select = lambda c: c.lstrip('^').startswith(inst.args[0])
  495. helplist(_('list of commands:\n\n'), select)
  496. return
  497. # synopsis
  498. ui.write("%s\n" % i[2])
  499. # aliases
  500. if not ui.quiet and len(aliases) > 1:
  501. ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
  502. # description
  503. doc = i[0].__doc__
  504. if not doc:
  505. doc = _("(No help text available)")
  506. if ui.quiet:
  507. doc = doc.splitlines(0)[0]
  508. ui.write("\n%s\n" % doc.rstrip())
  509. if not ui.quiet:
  510. # options
  511. if i[1]:
  512. option_lists.append((_("options:\n"), i[1]))
  513. addglobalopts(False)
  514. def helplist(header, select=None):
  515. h = {}
  516. cmds = {}
  517. for c, e in table.iteritems():
  518. f = c.split("|", 1)[0]
  519. if select and not select(f):
  520. continue
  521. if (not select and name != 'shortlist' and
  522. e[0].__module__ != __name__):
  523. continue
  524. if name == "shortlist" and not f.startswith("^"):
  525. continue
  526. f = f.lstrip("^")
  527. if not ui.debugflag and f.startswith("debug"):
  528. continue
  529. doc = e[0].__doc__
  530. if doc and 'DEPRECATED' in doc and not ui.verbose:
  531. continue
  532. #doc = gettext(doc)
  533. if not doc:
  534. doc = _("(no help text available)")
  535. h[f] = doc.splitlines()[0].rstrip()
  536. cmds[f] = c.lstrip("^")
  537. if not h:
  538. ui.status(_('no commands defined\n'))
  539. return
  540. ui.status(header)
  541. fns = sorted(h)
  542. m = max(map(len, fns))
  543. for f in fns:
  544. if ui.verbose:
  545. commands = cmds[f].replace("|",", ")
  546. ui.write(" %s:\n %s\n"%(commands, h[f]))
  547. else:
  548. ui.write('%s\n' % (util.wrap(h[f], textwidth,
  549. initindent=' %-*s ' % (m, f),
  550. hangindent=' ' * (m + 4))))
  551. if not ui.quiet:
  552. addglobalopts(True)
  553. def helptopic(name):
  554. from mercurial import help
  555. for names, header, doc in help.helptable:
  556. if name in names:
  557. break
  558. else:
  559. raise error.UnknownCommand(name)
  560. # description
  561. if not doc:
  562. doc = _("(No help text available)")
  563. if hasattr(doc, '__call__'):
  564. doc = doc()
  565. ui.write("%s\n" % header)
  566. ui.write("%s\n" % doc.rstrip())
  567. if name and name != 'shortlist':
  568. i = None
  569. for f in (helpcmd, helptopic):
  570. try:
  571. f(name)
  572. i = None
  573. break
  574. except error.UnknownCommand, inst:
  575. i = inst
  576. if i:
  577. raise i
  578. else:
  579. # program name
  580. if ui.verbose or with_version:
  581. version(ui)
  582. else:
  583. ui.status(_("Hgtk - TortoiseHg's GUI tools for Mercurial SCM (Hg)\n"))
  584. ui.status('\n')
  585. # list of commands
  586. if name == "shortlist":
  587. header = _('basic commands:\n\n')
  588. else:
  589. header = _('list of commands:\n\n')
  590. helplist(header)
  591. # list all option lists
  592. opt_output = []
  593. for title, options in option_lists:
  594. opt_output.append(("\n%s" % title, None))
  595. for shortopt, longopt, default, desc in options:
  596. if "DEPRECATED" in desc and not ui.verbose: continue
  597. opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
  598. longopt and " --%s" % longopt),
  599. "%s%s" % (desc,
  600. default
  601. and _(" (default: %s)") % default
  602. or "")))
  603. if opt_output:
  604. opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
  605. for first, second in opt_output:
  606. if second:
  607. initindent = ' %-*s ' % (opts_len, first)
  608. hangindent = ' ' * (opts_len + 3)
  609. ui.write('%s\n' % (util.wrap(second, textwidth,
  610. initindent=initindent,
  611. hangindent=hangindent)))
  612. else:
  613. ui.write("%s\n" % first)
  614. def version(ui, **opts):
  615. """output version and copyright information"""
  616. ui.write(_('TortoiseHg Dialogs (version %s), '
  617. 'Mercurial (version %s)\n') %
  618. (hglib.fromutf(thgversion.version()), hglib.hgversion))
  619. if not ui.quiet:
  620. ui.write(shortlicense)
  621. def debugcomplete(ui, cmd='', **opts):
  622. """output list of possible commands"""
  623. if opts.get('options'):
  624. options = []
  625. otables = [globalopts]
  626. if cmd:
  627. aliases, entry = cmdutil.findcmd(cmd, table, False)
  628. otables.append(entry[1])
  629. for t in otables:
  630. for o in t:
  631. if o[0]:
  632. options.append('-%s' % o[0])
  633. options.append('--%s' % o[1])
  634. ui.write("%s\n" % "\n".join(options))
  635. return
  636. cmdlist = cmdutil.findpossible(cmd, table)
  637. if ui.verbose:
  638. cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
  639. ui.write("%s\n" % "\n".join(sorted(cmdlist)))
  640. def archive(ui, *pats, **opts):
  641. """create an unversioned archive of a repository revision"""
  642. from tortoisehg.hgtk.archive import run
  643. gtkrun(run, ui, *pats, **opts)
  644. globalopts = [
  645. ('R', 'repository', '',
  646. _('repository root directory or symbolic path name')),
  647. ('v', 'verbose', None, _('enable additional output')),
  648. ('q', 'quiet', None, _('suppress output')),
  649. ('h', 'help', None, _('display help and exit')),
  650. ('', 'debugger', None, _('start debugger')),
  651. ('', 'profile', None, _('print command execution profile')),
  652. ('', 'nofork', None, _('do not fork GUI process')),
  653. ('', 'fork', None, _('always fork GUI process')),
  654. ('', 'listfile', '', _('read file list from file')),
  655. ]
  656. table = {
  657. "about": (about, [], _('hgtk about')),
  658. "add": (add, [], _('hgtk add [FILE]...')),
  659. "^clone": (clone, [], _('hgtk clone SOURCE [DEST]')),
  660. "^commit|ci": (commit,
  661. [('u', 'user', '', _('record user as committer')),
  662. ('d', 'date', '', _('record datecode as commit date'))],
  663. _('hgtk commit [OPTIONS] [FILE]...')),
  664. "^datamine|annotate|blame|grep": (datamine, [], _('hgtk datamine')),
  665. "^hgignore|ignore|filter": (hgignore, [], _('hgtk hgignore [FILE]')),
  666. "^init": (hginit, [], _('hgtk init [DEST]')),
  667. "^log|history|explorer": (log,
  668. [('l', 'limit', '', _('limit number of changes displayed'))],
  669. _('hgtk log [OPTIONS] [FILE]')),
  670. "merge": (merge,
  671. [('r', 'rev', '', _('revision to merge with'))],
  672. _('hgtk merge')),
  673. "^recovery|rollback|verify": (recovery, [], _('hgtk recovery')),
  674. "^shelve|unshelve": (shelve, [], _('hgtk shelve')),
  675. "synch|pull|push|incoming|outgoing|email": (synch, [], _('hgtk synch')),
  676. "^status|st|diff": (status,
  677. [('r', 'rev', [], _('revisions to compare'))],
  678. _('hgtk status [FILE]...')),
  679. "^userconfig": (userconfig,
  680. [('', 'focus', '', _('field to give initial focus'))],
  681. _('hgtk userconfig')),
  682. "^repoconfig": (repoconfig,
  683. [('', 'focus', '', _('field to give initial focus'))],
  684. _('hgtk repoconfig')),
  685. "^guess": (guess, [], _('hgtk guess')),
  686. "remove|rm": (revert, [], _('hgtk remove [FILE]...')),
  687. "rename|mv": (rename, [], _('hgtk rename SOURCE [DEST]')),
  688. "revert": (revert, [], _('hgtk revert [FILE]...')),
  689. "forget": (forget, [], _('hgtk forget [FILE]...')),
  690. "^serve":
  691. (serve,
  692. [('', 'web-conf', '',
  693. _('name of the hgweb config file (serve more than one repository)')),
  694. ('', 'webdir-conf', '',
  695. _('name of the hgweb config file (DEPRECATED)'))],
  696. _('hgtk serve [OPTION]...')),
  697. "thgstatus": (thgstatus,
  698. [('', 'delay', None, _('wait until the second ticks over')),
  699. ('n', 'notify', [], _('notify the shell for paths given')),
  700. ('', 'remove', None, _('remove the status cache')),
  701. ('s', 'show', None, _('show the contents of the'
  702. ' status cache (no update)')),
  703. ('', 'all', None, _('udpate all repos in current dir')) ],
  704. _('hgtk thgstatus [OPTION]')),
  705. "^update|checkout|co": (update,
  706. [('r', 'rev', [], _('revision to update'))],
  707. ('hgtk update')),
  708. "^vdiff": (vdiff,
  709. [('c', 'change', '', _('changeset to view in diff tool')),
  710. ('r', 'rev', [], _('revisions to view in diff tool')),
  711. ('b', 'bundle', '', _('bundle file to preview'))],
  712. _('launch visual diff tool')),
  713. "^version": (version,
  714. [('v', 'verbose', None, _('print license'))],
  715. _('hgtk version [OPTION]')),
  716. "debugcomplete": (debugcomplete,
  717. [('o', 'options', None, _('show the command options'))],
  718. _('[-o] CMD')),
  719. "help": (help_, [], _('hgtk help [COMMAND]')),
  720. "archive": (archive,
  721. [('r', 'rev', '', _('revision to update'))],
  722. ('hgtk archive')),
  723. "strip": (strip, [], ('hgtk strip [REV]')),
  724. "^mpatch": (mpatch, [], ('hgtk mpatch file.rej')),
  725. "import": (thgimport,
  726. [('', 'repo', False, _('import to the repository')),
  727. ('', 'mq', False, _('import to the patch queue (MQ)'))],
  728. _('hgtk import [OPTION] [SOURCE]...')),
  729. }
  730. if os.name == 'nt':
  731. # TODO: extra detection to determine if shell extension is installed
  732. table['shellconfig'] = (shellconfig, [], _('hgtk shellconfig'))