[PATCH 2 of 2 V2] commands: add --browser argument to `hg serve`
Gregory Szorc
gregory.szorc at gmail.com
Sun Jul 17 16:01:16 EDT 2016
# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1468785660 25200
# Sun Jul 17 13:01:00 2016 -0700
# Node ID 61e63f5a6922f693c7ca4e7ed8c5c8e8a45aba2a
# Parent a6ed7328eac4500637021b9afa065225fe1b90ed
commands: add --browser argument to `hg serve`
When D. Richard Hipp visited the Mozilla office several months ago
and was showing me all the awesomeness in his Fossil VCS, one of the
features that stood out to me was `fossil ui` starting a fully-featured
HTTP/HTML server including the web browser. It was so... elegant
to just type a command and get a web browser pointed to a local
HTTP server where you could interact with your VCS.
>From my own experience, when I run `hg serve` I frequently open a web
browser to navigate the started server. Today, I have to click on the
printed URL or copy and paste it into my browser to open it. While it
only takes a few seconds, this wastes my precious time.
This patch adds a --browser argument to `hg serve` to streamline the
process of opening a browser when starting a local HTTP/HTML server.
The argument only works when starting servers that run the HTTP/HTML
server.
I wish "--browser" could exist as a boolean with an optional value so
bareword "--browser" would open the default browser (instead of
requiring an argument). However, it doesn't appear our option parser
allows this. This does undermine the utility of the argument a bit
(now you have to type extra characters). But, users can always install
an [alias] entry to type fewer characters, so this is only a minor
issue.
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -6439,16 +6439,17 @@ def root(ui, repo):
Returns 0 on success.
"""
ui.write(repo.root + "\n")
@command('^serve',
[('A', 'accesslog', '', _('name of access log file to write to'),
_('FILE')),
+ ('', 'browser', '', _('web browser to run')),
('d', 'daemon', None, _('run server in background')),
('', 'daemon-postexec', [], _('used internally by daemon mode')),
('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
# use string type, then we can check if something was passed
('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
('a', 'address', '', _('address to listen on (default: all interfaces)'),
_('ADDR')),
('', 'prefix', '', _('prefix path to serve from (default: server root)'),
@@ -6485,22 +6486,31 @@ def serve(ui, repo, **opts):
By default, the server logs accesses to stdout and errors to
stderr. Use the -A/--accesslog and -E/--errorlog options to log to
files.
To have the server choose a free port number to listen on, specify
a port number of 0; in this case, the server will print the port
number it uses.
+ A web browser will be opened at the started server if the ``--browser``
+ argument contains the name of a browser to start. The special value
+ ``default`` will open the default browser as configured by your
+ operating system.
+
Returns 0 on success.
"""
if opts["stdio"] and opts["cmdserver"]:
raise error.Abort(_("cannot use --stdio with --cmdserver"))
+ if (opts['stdio'] or opts['cmdserver']) and opts['browser']:
+ raise error.Abort(_('cannot use --browser with --cmdserver or '
+ '--stdio'))
+
if opts["stdio"]:
if repo is None:
raise error.RepoError(_("there is no Mercurial repository here"
" (.hg not found)"))
s = sshserver.sshserver(ui, repo)
s.serve_forever()
if opts["cmdserver"]:
diff --git a/mercurial/hgweb/__init__.py b/mercurial/hgweb/__init__.py
--- a/mercurial/hgweb/__init__.py
+++ b/mercurial/hgweb/__init__.py
@@ -4,16 +4,17 @@
# Copyright 2005 Matt Mackall <mpm at selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import os
+import webbrowser
from ..i18n import _
from .. import (
error,
util,
)
@@ -79,18 +80,41 @@ class httpservice(object):
else:
write = self.ui.write
self.url = 'http://%s%s/%s' % (fqaddr, port, prefix)
write(_('listening at %s (bound to %s:%d)\n') %
(self.url, bindaddr, self.httpd.port))
self.ui.flush() # avoid buffering of status message
def run(self):
+ self._maybestartbrowser()
self.httpd.serve_forever()
+ def _maybestartbrowser(self):
+ browser = self.opts.get('browser')
+ if not browser:
+ return
+
+ # webbrowser.get() accepts empty value to indicate default browser.
+ if browser == 'default':
+ browser = None
+
+ try:
+ browser = webbrowser.get(browser)
+ # Text-mode browsers block the calling process, which interferes
+ # with our server.
+ if (not isinstance(browser, webbrowser.BackgroundBrowser) and
+ not getattr(browser, 'background', None)):
+ self.ui.warn(_('(cannot start text-mode browsers; '
+ 'continuing to start server)\n'))
+ return
+ browser.open_new_tab(self.url)
+ except webbrowser.Error as e:
+ self.ui.warn(_('(unable to start web browser: %s)\n') % e.args[0])
+
def createservice(ui, repo, opts):
# this way we can check if something was given in the command-line
if opts.get('port'):
opts['port'] = util.getport(opts.get('port'))
alluis = set([ui])
if repo:
baseui = repo.baseui
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -149,16 +149,17 @@ Show the global options
-q
-v
-y
Show the options for the "serve" command
$ hg debugcomplete --options serve | sort
--accesslog
--address
+ --browser
--certificate
--cmdserver
--config
--cwd
--daemon
--daemon-postexec
--debug
--debugger
@@ -214,17 +215,17 @@ Show all commands + options
export: output, switch-parent, rev, text, git, nodates
forget: include, exclude
init: ssh, remotecmd, insecure
log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
merge: force, rev, preview, tool
pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
remove: after, force, subrepos, include, exclude
- serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
+ serve: accesslog, browser, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
summary: remote
update: clean, check, date, rev, tool
addremove: similarity, subrepos, include, exclude, dry-run
archive: no-decode, prefix, rev, type, subrepos, include, exclude
backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
bisect: reset, good, bad, skip, extend, command, noupdate
bookmarks: force, rev, delete, rename, inactive, template
More information about the Mercurial-devel
mailing list