[PATCH 2 of 2 V2] commands: add --browser argument to `hg serve`

Augie Fackler raf at durin42.com
Mon Jul 18 09:33:00 EDT 2016


On Sun, Jul 17, 2016 at 01:01:16PM -0700, Gregory Szorc wrote:
> # 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`

Seems fine. I suspect there will be some weirdness around showing the
address we bound to, since we're showing the (IIRC) reverse-DNS
hostname, which might not forward resolve back to the user's machine
(I think that might be true on most home networks?). I'd like someone
else to look at it though, and I'd love to know your thoughts on my
question below.

>
> 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.

So, I've been thinking about this some, and I've been meaning to see
if I can hack together some sort of true-or-value flag that'd work
thus:

[not set]: false
--flag: true
--flag=value: value

Which would then let us do things like have:

hg diff --git=no

as a quick (and mostly obvious) way to disable git-diffs. What do you
think? Even if you like that idea (I'll admit it's a bit wonky), I
think we can still land this patch and then at a later date we can
change --browser to work with no argument.

>
> 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
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list