Show More
@@ -0,0 +1,71 | |||
|
1 | ======== | |
|
2 | hg-ssh | |
|
3 | ======== | |
|
4 | ||
|
5 | ---------------------------------------- | |
|
6 | restricted ssh login shell for Mercurial | |
|
7 | ---------------------------------------- | |
|
8 | ||
|
9 | :Author: Thomas Arendsen Hein <thomas@intevation.de> | |
|
10 | :Organization: Mercurial | |
|
11 | :Manual section: 8 | |
|
12 | :Manual group: Mercurial Manual | |
|
13 | ||
|
14 | .. contents:: | |
|
15 | :backlinks: top | |
|
16 | :class: htmlonly | |
|
17 | :depth: 1 | |
|
18 | ||
|
19 | Synopsis | |
|
20 | """""""" | |
|
21 | **hg-ssh** repositories... | |
|
22 | ||
|
23 | Description | |
|
24 | """"""""""" | |
|
25 | **hg-ssh** is a wrapper for ssh access to a limited set of mercurial repos. | |
|
26 | ||
|
27 | To be used in ~/.ssh/authorized_keys with the "command" option, see sshd(8): | |
|
28 | command="hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4" ssh-dss ... | |
|
29 | (probably together with these other useful options: | |
|
30 | no-port-forwarding,no-X11-forwarding,no-agent-forwarding) | |
|
31 | ||
|
32 | This allows pull/push over ssh from/to the repositories given as arguments. | |
|
33 | ||
|
34 | If all your repositories are subdirectories of a common directory, you can | |
|
35 | allow shorter paths with: | |
|
36 | command="cd path/to/my/repositories && hg-ssh repo1 subdir/repo2" | |
|
37 | ||
|
38 | You can use pattern matching of your normal shell, e.g.: | |
|
39 | command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}" | |
|
40 | ||
|
41 | You can also add a --read-only flag to allow read-only access to a key, e.g.: | |
|
42 | command="hg-ssh --read-only repos/\*" | |
|
43 | ||
|
44 | Bugs | |
|
45 | """" | |
|
46 | Probably lots, please post them to the mailing list (see Resources_ | |
|
47 | below) when you find them. | |
|
48 | ||
|
49 | See Also | |
|
50 | """""""" | |
|
51 | |hg(1)|_ | |
|
52 | ||
|
53 | Author | |
|
54 | """""" | |
|
55 | Written by Matt Mackall <mpm@selenic.com> | |
|
56 | ||
|
57 | Resources | |
|
58 | """"""""" | |
|
59 | Main Web Site: https://mercurial-scm.org/ | |
|
60 | ||
|
61 | Source code repository: http://selenic.com/hg | |
|
62 | ||
|
63 | Mailing list: http://selenic.com/mailman/listinfo/mercurial | |
|
64 | ||
|
65 | Copying | |
|
66 | """"""" | |
|
67 | Copyright (C) 2005-2016 Matt Mackall. | |
|
68 | Free use of this software is granted under the terms of the GNU General | |
|
69 | Public License version 2 or any later version. | |
|
70 | ||
|
71 | .. include:: common.txt |
@@ -1,223 +1,224 | |||
|
1 | 1 | #!/usr/bin/env python |
|
2 | 2 | """usage: %s DOC ... |
|
3 | 3 | |
|
4 | 4 | where DOC is the name of a document |
|
5 | 5 | """ |
|
6 | 6 | |
|
7 | 7 | from __future__ import absolute_import |
|
8 | 8 | |
|
9 | 9 | import os |
|
10 | 10 | import sys |
|
11 | 11 | import textwrap |
|
12 | 12 | |
|
13 | 13 | # This script is executed during installs and may not have C extensions |
|
14 | 14 | # available. Relax C module requirements. |
|
15 | 15 | os.environ['HGMODULEPOLICY'] = 'allow' |
|
16 | 16 | # import from the live mercurial repo |
|
17 | 17 | sys.path.insert(0, "..") |
|
18 | 18 | from mercurial import demandimport; demandimport.enable() |
|
19 | 19 | from mercurial import ( |
|
20 | 20 | commands, |
|
21 | 21 | extensions, |
|
22 | 22 | help, |
|
23 | 23 | minirst, |
|
24 | 24 | ui as uimod, |
|
25 | 25 | ) |
|
26 | 26 | from mercurial.i18n import ( |
|
27 | 27 | gettext, |
|
28 | 28 | _, |
|
29 | 29 | ) |
|
30 | 30 | |
|
31 | 31 | table = commands.table |
|
32 | 32 | globalopts = commands.globalopts |
|
33 | 33 | helptable = help.helptable |
|
34 | 34 | loaddoc = help.loaddoc |
|
35 | 35 | |
|
36 | 36 | def get_desc(docstr): |
|
37 | 37 | if not docstr: |
|
38 | 38 | return "", "" |
|
39 | 39 | # sanitize |
|
40 | 40 | docstr = docstr.strip("\n") |
|
41 | 41 | docstr = docstr.rstrip() |
|
42 | 42 | shortdesc = docstr.splitlines()[0].strip() |
|
43 | 43 | |
|
44 | 44 | i = docstr.find("\n") |
|
45 | 45 | if i != -1: |
|
46 | 46 | desc = docstr[i + 2:] |
|
47 | 47 | else: |
|
48 | 48 | desc = shortdesc |
|
49 | 49 | |
|
50 | 50 | desc = textwrap.dedent(desc) |
|
51 | 51 | |
|
52 | 52 | return (shortdesc, desc) |
|
53 | 53 | |
|
54 | 54 | def get_opts(opts): |
|
55 | 55 | for opt in opts: |
|
56 | 56 | if len(opt) == 5: |
|
57 | 57 | shortopt, longopt, default, desc, optlabel = opt |
|
58 | 58 | else: |
|
59 | 59 | shortopt, longopt, default, desc = opt |
|
60 | 60 | optlabel = _("VALUE") |
|
61 | 61 | allopts = [] |
|
62 | 62 | if shortopt: |
|
63 | 63 | allopts.append("-%s" % shortopt) |
|
64 | 64 | if longopt: |
|
65 | 65 | allopts.append("--%s" % longopt) |
|
66 | 66 | if isinstance(default, list): |
|
67 | 67 | allopts[-1] += " <%s[+]>" % optlabel |
|
68 | 68 | elif (default is not None) and not isinstance(default, bool): |
|
69 | 69 | allopts[-1] += " <%s>" % optlabel |
|
70 | 70 | if '\n' in desc: |
|
71 | 71 | # only remove line breaks and indentation |
|
72 | 72 | desc = ' '.join(l.lstrip() for l in desc.split('\n')) |
|
73 | 73 | desc += default and _(" (default: %s)") % default or "" |
|
74 | 74 | yield (", ".join(allopts), desc) |
|
75 | 75 | |
|
76 | 76 | def get_cmd(cmd, cmdtable): |
|
77 | 77 | d = {} |
|
78 | 78 | attr = cmdtable[cmd] |
|
79 | 79 | cmds = cmd.lstrip("^").split("|") |
|
80 | 80 | |
|
81 | 81 | d['cmd'] = cmds[0] |
|
82 | 82 | d['aliases'] = cmd.split("|")[1:] |
|
83 | 83 | d['desc'] = get_desc(gettext(attr[0].__doc__)) |
|
84 | 84 | d['opts'] = list(get_opts(attr[1])) |
|
85 | 85 | |
|
86 | 86 | s = 'hg ' + cmds[0] |
|
87 | 87 | if len(attr) > 2: |
|
88 | 88 | if not attr[2].startswith('hg'): |
|
89 | 89 | s += ' ' + attr[2] |
|
90 | 90 | else: |
|
91 | 91 | s = attr[2] |
|
92 | 92 | d['synopsis'] = s.strip() |
|
93 | 93 | |
|
94 | 94 | return d |
|
95 | 95 | |
|
96 | 96 | def showdoc(ui): |
|
97 | 97 | # print options |
|
98 | 98 | ui.write(minirst.section(_("Options"))) |
|
99 | 99 | multioccur = False |
|
100 | 100 | for optstr, desc in get_opts(globalopts): |
|
101 | 101 | ui.write("%s\n %s\n\n" % (optstr, desc)) |
|
102 | 102 | if optstr.endswith("[+]>"): |
|
103 | 103 | multioccur = True |
|
104 | 104 | if multioccur: |
|
105 | 105 | ui.write(_("\n[+] marked option can be specified multiple times\n")) |
|
106 | 106 | ui.write("\n") |
|
107 | 107 | |
|
108 | 108 | # print cmds |
|
109 | 109 | ui.write(minirst.section(_("Commands"))) |
|
110 | 110 | commandprinter(ui, table, minirst.subsection) |
|
111 | 111 | |
|
112 | 112 | # print help topics |
|
113 | 113 | # The config help topic is included in the hgrc.5 man page. |
|
114 | 114 | helpprinter(ui, helptable, minirst.section, exclude=['config']) |
|
115 | 115 | |
|
116 | 116 | ui.write(minirst.section(_("Extensions"))) |
|
117 | 117 | ui.write(_("This section contains help for extensions that are " |
|
118 | 118 | "distributed together with Mercurial. Help for other " |
|
119 | 119 | "extensions is available in the help system.")) |
|
120 | 120 | ui.write("\n\n" |
|
121 | 121 | ".. contents::\n" |
|
122 | 122 | " :class: htmlonly\n" |
|
123 | 123 | " :local:\n" |
|
124 | 124 | " :depth: 1\n\n") |
|
125 | 125 | |
|
126 | 126 | for extensionname in sorted(allextensionnames()): |
|
127 | 127 | mod = extensions.load(ui, extensionname, None) |
|
128 | 128 | ui.write(minirst.subsection(extensionname)) |
|
129 | 129 | ui.write("%s\n\n" % gettext(mod.__doc__)) |
|
130 | 130 | cmdtable = getattr(mod, 'cmdtable', None) |
|
131 | 131 | if cmdtable: |
|
132 | 132 | ui.write(minirst.subsubsection(_('Commands'))) |
|
133 | 133 | commandprinter(ui, cmdtable, minirst.subsubsubsection) |
|
134 | 134 | |
|
135 | 135 | def showtopic(ui, topic): |
|
136 | 136 | extrahelptable = [ |
|
137 | 137 | (["common"], '', loaddoc('common')), |
|
138 | 138 | (["hg.1"], '', loaddoc('hg.1')), |
|
139 | (["hg-ssh.8"], '', loaddoc('hg-ssh.8')), | |
|
139 | 140 | (["hgignore.5"], '', loaddoc('hgignore.5')), |
|
140 | 141 | (["hgrc.5"], '', loaddoc('hgrc.5')), |
|
141 | 142 | (["hgignore.5.gendoc"], '', loaddoc('hgignore')), |
|
142 | 143 | (["hgrc.5.gendoc"], '', loaddoc('config')), |
|
143 | 144 | ] |
|
144 | 145 | helpprinter(ui, helptable + extrahelptable, None, include=[topic]) |
|
145 | 146 | |
|
146 | 147 | def helpprinter(ui, helptable, sectionfunc, include=[], exclude=[]): |
|
147 | 148 | for names, sec, doc in helptable: |
|
148 | 149 | if exclude and names[0] in exclude: |
|
149 | 150 | continue |
|
150 | 151 | if include and names[0] not in include: |
|
151 | 152 | continue |
|
152 | 153 | for name in names: |
|
153 | 154 | ui.write(".. _%s:\n" % name) |
|
154 | 155 | ui.write("\n") |
|
155 | 156 | if sectionfunc: |
|
156 | 157 | ui.write(sectionfunc(sec)) |
|
157 | 158 | if callable(doc): |
|
158 | 159 | doc = doc(ui) |
|
159 | 160 | ui.write(doc) |
|
160 | 161 | ui.write("\n") |
|
161 | 162 | |
|
162 | 163 | def commandprinter(ui, cmdtable, sectionfunc): |
|
163 | 164 | h = {} |
|
164 | 165 | for c, attr in cmdtable.items(): |
|
165 | 166 | f = c.split("|")[0] |
|
166 | 167 | f = f.lstrip("^") |
|
167 | 168 | h[f] = c |
|
168 | 169 | cmds = h.keys() |
|
169 | 170 | cmds.sort() |
|
170 | 171 | |
|
171 | 172 | for f in cmds: |
|
172 | 173 | if f.startswith("debug"): |
|
173 | 174 | continue |
|
174 | 175 | d = get_cmd(h[f], cmdtable) |
|
175 | 176 | ui.write(sectionfunc(d['cmd'])) |
|
176 | 177 | # short description |
|
177 | 178 | ui.write(d['desc'][0]) |
|
178 | 179 | # synopsis |
|
179 | 180 | ui.write("::\n\n") |
|
180 | 181 | synopsislines = d['synopsis'].splitlines() |
|
181 | 182 | for line in synopsislines: |
|
182 | 183 | # some commands (such as rebase) have a multi-line |
|
183 | 184 | # synopsis |
|
184 | 185 | ui.write(" %s\n" % line) |
|
185 | 186 | ui.write('\n') |
|
186 | 187 | # description |
|
187 | 188 | ui.write("%s\n\n" % d['desc'][1]) |
|
188 | 189 | # options |
|
189 | 190 | opt_output = list(d['opts']) |
|
190 | 191 | if opt_output: |
|
191 | 192 | opts_len = max([len(line[0]) for line in opt_output]) |
|
192 | 193 | ui.write(_("Options:\n\n")) |
|
193 | 194 | multioccur = False |
|
194 | 195 | for optstr, desc in opt_output: |
|
195 | 196 | if desc: |
|
196 | 197 | s = "%-*s %s" % (opts_len, optstr, desc) |
|
197 | 198 | else: |
|
198 | 199 | s = optstr |
|
199 | 200 | ui.write("%s\n" % s) |
|
200 | 201 | if optstr.endswith("[+]>"): |
|
201 | 202 | multioccur = True |
|
202 | 203 | if multioccur: |
|
203 | 204 | ui.write(_("\n[+] marked option can be specified" |
|
204 | 205 | " multiple times\n")) |
|
205 | 206 | ui.write("\n") |
|
206 | 207 | # aliases |
|
207 | 208 | if d['aliases']: |
|
208 | 209 | ui.write(_(" aliases: %s\n\n") % " ".join(d['aliases'])) |
|
209 | 210 | |
|
210 | 211 | |
|
211 | 212 | def allextensionnames(): |
|
212 | 213 | return extensions.enabled().keys() + extensions.disabled().keys() |
|
213 | 214 | |
|
214 | 215 | if __name__ == "__main__": |
|
215 | 216 | doc = 'hg.1.gendoc' |
|
216 | 217 | if len(sys.argv) > 1: |
|
217 | 218 | doc = sys.argv[1] |
|
218 | 219 | |
|
219 | 220 | ui = uimod.ui() |
|
220 | 221 | if doc == 'hg.1.gendoc': |
|
221 | 222 | showdoc(ui) |
|
222 | 223 | else: |
|
223 | 224 | showtopic(ui, sys.argv[1]) |
@@ -1,138 +1,139 | |||
|
1 | 1 | hg debuginstall |
|
2 | 2 | $ hg debuginstall |
|
3 | 3 | checking encoding (ascii)... |
|
4 | 4 | checking Python executable (*) (glob) |
|
5 | 5 | checking Python version (2.*) (glob) |
|
6 | 6 | checking Python lib (*lib*)... (glob) |
|
7 | 7 | checking installed modules (*mercurial)... (glob) |
|
8 | 8 | checking templates (*mercurial?templates)... (glob) |
|
9 | 9 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
10 | 10 | checking commit editor... (* -c "import sys; sys.exit(0)") (glob) |
|
11 | 11 | checking username (test) |
|
12 | 12 | no problems detected |
|
13 | 13 | |
|
14 | 14 | hg debuginstall JSON |
|
15 | 15 | $ hg debuginstall -Tjson | sed 's|\\\\|\\|g' |
|
16 | 16 | [ |
|
17 | 17 | { |
|
18 | 18 | "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob) |
|
19 | 19 | "defaulttemplateerror": null, |
|
20 | 20 | "defaulttemplatenotfound": "default", |
|
21 | 21 | "editor": "* -c \"import sys; sys.exit(0)\"", (glob) |
|
22 | 22 | "editornotfound": false, |
|
23 | 23 | "encoding": "ascii", |
|
24 | 24 | "encodingerror": null, |
|
25 | 25 | "extensionserror": null, |
|
26 | 26 | "hgmodules": "*mercurial", (glob) |
|
27 | 27 | "problems": 0, |
|
28 | 28 | "pythonexe": "*", (glob) |
|
29 | 29 | "pythonlib": "*", (glob) |
|
30 | 30 | "pythonver": "*.*.*", (glob) |
|
31 | 31 | "templatedirs": "*mercurial?templates", (glob) |
|
32 | 32 | "username": "test", |
|
33 | 33 | "usernameerror": null, |
|
34 | 34 | "vinotfound": false |
|
35 | 35 | } |
|
36 | 36 | ] |
|
37 | 37 | |
|
38 | 38 | hg debuginstall with no username |
|
39 | 39 | $ HGUSER= hg debuginstall |
|
40 | 40 | checking encoding (ascii)... |
|
41 | 41 | checking Python executable (*) (glob) |
|
42 | 42 | checking Python version (2.*) (glob) |
|
43 | 43 | checking Python lib (*lib*)... (glob) |
|
44 | 44 | checking installed modules (*mercurial)... (glob) |
|
45 | 45 | checking templates (*mercurial?templates)... (glob) |
|
46 | 46 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
47 | 47 | checking commit editor... (* -c "import sys; sys.exit(0)") (glob) |
|
48 | 48 | checking username... |
|
49 | 49 | no username supplied |
|
50 | 50 | (specify a username in your configuration file) |
|
51 | 51 | 1 problems detected, please check your install! |
|
52 | 52 | [1] |
|
53 | 53 | |
|
54 | 54 | path variables are expanded (~ is the same as $TESTTMP) |
|
55 | 55 | $ mkdir tools |
|
56 | 56 | $ touch tools/testeditor.exe |
|
57 | 57 | #if execbit |
|
58 | 58 | $ chmod 755 tools/testeditor.exe |
|
59 | 59 | #endif |
|
60 | 60 | $ hg debuginstall --config ui.editor=~/tools/testeditor.exe |
|
61 | 61 | checking encoding (ascii)... |
|
62 | 62 | checking Python executable (*) (glob) |
|
63 | 63 | checking Python version (*) (glob) |
|
64 | 64 | checking Python lib (*lib*)... (glob) |
|
65 | 65 | checking installed modules (*mercurial)... (glob) |
|
66 | 66 | checking templates (*mercurial?templates)... (glob) |
|
67 | 67 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
68 | 68 | checking commit editor... (* -c "import sys; sys.exit(0)") (glob) |
|
69 | 69 | checking username (test) |
|
70 | 70 | no problems detected |
|
71 | 71 | |
|
72 | 72 | #if test-repo |
|
73 | 73 | $ cat >> wixxml.py << EOF |
|
74 | 74 | > import os, subprocess, sys |
|
75 | 75 | > import xml.etree.ElementTree as ET |
|
76 | 76 | > |
|
77 | 77 | > # MSYS mangles the path if it expands $TESTDIR |
|
78 | 78 | > testdir = os.environ['TESTDIR'] |
|
79 | 79 | > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'} |
|
80 | 80 | > |
|
81 | 81 | > def directory(node, relpath): |
|
82 | 82 | > '''generator of files in the xml node, rooted at relpath''' |
|
83 | 83 | > dirs = node.findall('./{%(wix)s}Directory' % ns) |
|
84 | 84 | > |
|
85 | 85 | > for d in dirs: |
|
86 | 86 | > for subfile in directory(d, relpath + d.attrib['Name'] + '/'): |
|
87 | 87 | > yield subfile |
|
88 | 88 | > |
|
89 | 89 | > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns) |
|
90 | 90 | > |
|
91 | 91 | > for f in files: |
|
92 | 92 | > yield relpath + f.attrib['Name'] |
|
93 | 93 | > |
|
94 | 94 | > def hgdirectory(relpath): |
|
95 | 95 | > '''generator of tracked files, rooted at relpath''' |
|
96 | 96 | > hgdir = "%s/../mercurial" % (testdir) |
|
97 | 97 | > args = ['hg', '--cwd', hgdir, 'files', relpath] |
|
98 | 98 | > proc = subprocess.Popen(args, stdout=subprocess.PIPE, |
|
99 | 99 | > stderr=subprocess.PIPE) |
|
100 | 100 | > output = proc.communicate()[0] |
|
101 | 101 | > |
|
102 | 102 | > slash = '/' |
|
103 | 103 | > for line in output.splitlines(): |
|
104 | 104 | > if os.name == 'nt': |
|
105 | 105 | > yield line.replace(os.sep, slash) |
|
106 | 106 | > else: |
|
107 | 107 | > yield line |
|
108 | 108 | > |
|
109 | 109 | > tracked = [f for f in hgdirectory(sys.argv[1])] |
|
110 | 110 | > |
|
111 | 111 | > xml = ET.parse("%s/../contrib/wix/%s.wxs" % (testdir, sys.argv[1])) |
|
112 | 112 | > root = xml.getroot() |
|
113 | 113 | > dir = root.find('.//{%(wix)s}DirectoryRef' % ns) |
|
114 | 114 | > |
|
115 | 115 | > installed = [f for f in directory(dir, '')] |
|
116 | 116 | > |
|
117 | 117 | > print('Not installed:') |
|
118 | 118 | > for f in sorted(set(tracked) - set(installed)): |
|
119 | 119 | > print(' %s' % f) |
|
120 | 120 | > |
|
121 | 121 | > print('Not tracked:') |
|
122 | 122 | > for f in sorted(set(installed) - set(tracked)): |
|
123 | 123 | > print(' %s' % f) |
|
124 | 124 | > EOF |
|
125 | 125 | |
|
126 | 126 | $ python wixxml.py help |
|
127 | 127 | Not installed: |
|
128 | 128 | help/common.txt |
|
129 | help/hg-ssh.8.txt | |
|
129 | 130 | help/hg.1.txt |
|
130 | 131 | help/hgignore.5.txt |
|
131 | 132 | help/hgrc.5.txt |
|
132 | 133 | Not tracked: |
|
133 | 134 | |
|
134 | 135 | $ python wixxml.py templates |
|
135 | 136 | Not installed: |
|
136 | 137 | Not tracked: |
|
137 | 138 | |
|
138 | 139 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now