diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -2290,6 +2290,15 @@ def add(ui, repo, match, prefix, explici bad.extend(f for f in rejected if f in match.files()) return bad +def addwebdirpath(repo, serverpath, webconf): + webconf[serverpath] = repo.root + repo.ui.debug('adding %s = %s\n' % (serverpath, repo.root)) + + for r in repo.revs('filelog("path:.hgsub")'): + ctx = repo[r] + for subpath in ctx.substate: + ctx.sub(subpath).addwebdirpath(serverpath, webconf) + def forget(ui, repo, match, prefix, explicitonly): join = lambda f: os.path.join(prefix, f) bad = [] diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -4619,7 +4619,8 @@ def root(ui, repo): ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')), ('', 'style', '', _('template style to use'), _('STYLE')), ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')), - ('', 'certificate', '', _('SSL certificate file'), _('FILE'))], + ('', 'certificate', '', _('SSL certificate file'), _('FILE'))] + + subrepoopts, _('[OPTION]...'), optionalrepo=True) def serve(ui, repo, **opts): diff --git a/mercurial/help/subrepos.txt b/mercurial/help/subrepos.txt --- a/mercurial/help/subrepos.txt +++ b/mercurial/help/subrepos.txt @@ -136,6 +136,10 @@ Interaction with Mercurial Commands subrepository changes are available when referenced by top-level repositories. Push is a no-op for Subversion subrepositories. +:serve: serve does not recurse into subrepositories unless + -S/--subrepos is specified. Git and Subversion subrepositories + are currently silently ignored. + :status: status does not recurse into subrepositories unless -S/--subrepos is specified. Subrepository changes are displayed as regular Mercurial changes on the subrepository diff --git a/mercurial/server.py b/mercurial/server.py --- a/mercurial/server.py +++ b/mercurial/server.py @@ -15,6 +15,7 @@ from .i18n import _ from . import ( chgserver, + cmdutil, commandserver, error, hgweb, @@ -130,11 +131,22 @@ def _createhgwebservice(ui, repo, opts): baseui = ui webconf = opts.get('web_conf') or opts.get('webdir_conf') if webconf: + if opts.get('subrepos'): + raise error.Abort(_('--web-conf cannot be used with --subrepos')) + # load server settings (e.g. web.port) to "copied" ui, which allows # hgwebdir to reload webconf cleanly servui = ui.copy() servui.readconfig(webconf, sections=['web']) alluis.add(servui) + elif opts.get('subrepos'): + servui = ui + + # If repo is None, hgweb.createapp() already raises a proper abort + # message as long as webconf is None. + if repo: + webconf = dict() + cmdutil.addwebdirpath(repo, "", webconf) else: servui = ui diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -444,6 +444,15 @@ class abstractsubrepo(object): self._ctx = ctx self._path = path + def addwebdirpath(self, serverpath, webconf): + """Add the hgwebdir entries for this subrepo, and any of its subrepos. + + ``serverpath`` is the path component of the URL for this repo. + + ``webconf`` is the dictionary of hgwebdir entries. + """ + pass + def storeclean(self, path): """ returns true if the repository has not changed since it was last @@ -651,6 +660,10 @@ class hgsubrepo(abstractsubrepo): self.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo') self._initrepo(r, state[0], create) + @annotatesubrepoerror + def addwebdirpath(self, serverpath, webconf): + cmdutil.addwebdirpath(self._repo, subrelpath(self), webconf) + def storeclean(self, path): with self._repo.lock(): return self._storeclean(path) diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -184,6 +184,7 @@ Show the options for the "serve" command --repository --stdio --style + --subrepos --templates --time --traceback @@ -194,6 +195,7 @@ Show the options for the "serve" command -A -E -R + -S -a -d -h @@ -225,7 +227,7 @@ Show all commands + options 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, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, subrepos status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template summary: remote update: clean, check, merge, date, rev, tool diff --git a/tests/test-subrepo-deep-nested-change.t b/tests/test-subrepo-deep-nested-change.t --- a/tests/test-subrepo-deep-nested-change.t +++ b/tests/test-subrepo-deep-nested-change.t @@ -73,6 +73,43 @@ Preparing the 'main' repo which depends adding main/main (glob) $ hg commit -R main -m "main import" +#if serve + +Unfortunately, subrepos not at their nominal location cannot be cloned. But +they are still served from their location within the local repository. The only +reason why 'main' can be cloned via the filesystem is because 'sub1' and 'sub2' +are also available as siblings of 'main'. + + $ hg serve -R main --debug -S -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log + adding = $TESTTMP/main (glob) + adding sub1 = $TESTTMP/main/sub1 (glob) + adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob) + listening at http://*:$HGPORT/ (bound to *:$HGPORT) (glob) (?) + adding = $TESTTMP/main (glob) (?) + adding sub1 = $TESTTMP/main/sub1 (glob) (?) + adding sub1/sub2 = $TESTTMP/main/sub1/sub2 (glob) (?) + $ cat hg1.pid >> $DAEMON_PIDS + + $ hg clone http://localhost:$HGPORT httpclone --config progress.disable=True + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 3 changes to 3 files + updating to branch default + abort: HTTP Error 404: Not Found + [255] + + $ cat access.log + * "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * "GET /?cmd=batch HTTP/1.1" 200 - * (glob) + * "GET /?cmd=getbundle HTTP/1.1" 200 - * (glob) + * "GET /../sub1?cmd=capabilities HTTP/1.1" 404 - (glob) + + $ killdaemons.py + $ rm hg1.pid error.log access.log +#endif + Cleaning both repositories, just as a clone -U $ hg up -C -R sub2 null diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t --- a/tests/test-subrepo-recursion.t +++ b/tests/test-subrepo-recursion.t @@ -251,6 +251,60 @@ Status between revisions: z1 +z2 +#if serve + $ cd .. + $ hg serve -R repo --debug -S -p $HGPORT -d --pid-file=hg1.pid -E error.log -A access.log + adding = $TESTTMP/repo (glob) + adding foo = $TESTTMP/repo/foo (glob) + adding foo/bar = $TESTTMP/repo/foo/bar (glob) + listening at http://*:$HGPORT/ (bound to *:$HGPORT) (glob) (?) + adding = $TESTTMP/repo (glob) (?) + adding foo = $TESTTMP/repo/foo (glob) (?) + adding foo/bar = $TESTTMP/repo/foo/bar (glob) (?) + $ cat hg1.pid >> $DAEMON_PIDS + + $ hg clone http://localhost:$HGPORT clone --config progress.disable=True + requesting all changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 5 changes to 3 files + updating to branch default + cloning subrepo foo from http://localhost:$HGPORT/foo + requesting all changes + adding changesets + adding manifests + adding file changes + added 4 changesets with 7 changes to 3 files + cloning subrepo foo/bar from http://localhost:$HGPORT/foo/bar (glob) + requesting all changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 3 changes to 1 files + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ cat clone/foo/bar/z.txt + z1 + z2 + z3 + + $ cat access.log + * "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) + * "GET /?cmd=batch HTTP/1.1" 200 - * (glob) + * "GET /?cmd=getbundle HTTP/1.1" 200 - * (glob) + * "GET /foo?cmd=capabilities HTTP/1.1" 200 - (glob) + * "GET /foo?cmd=batch HTTP/1.1" 200 - * (glob) + * "GET /foo?cmd=getbundle HTTP/1.1" 200 - * (glob) + * "GET /foo/bar?cmd=capabilities HTTP/1.1" 200 - (glob) + * "GET /foo/bar?cmd=batch HTTP/1.1" 200 - * (glob) + * "GET /foo/bar?cmd=getbundle HTTP/1.1" 200 - * (glob) + + $ killdaemons.py + $ rm hg1.pid error.log access.log + $ cd repo +#endif + Enable progress extension for archive tests: $ cp $HGRCPATH $HGRCPATH.no-progress