##// END OF EJS Templates
extensions: remove the inotify extension (BC)...
Matt Mackall -
r20622:352abbb0 default
parent child Browse files
Show More
@@ -1,369 +1,369 b''
1 # extensions.py - extension handling for mercurial
1 # extensions.py - extension handling for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import imp, os
8 import imp, os
9 import util, cmdutil, error
9 import util, cmdutil, error
10 from i18n import _, gettext
10 from i18n import _, gettext
11
11
12 _extensions = {}
12 _extensions = {}
13 _order = []
13 _order = []
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg']
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify']
15
15
16 def extensions(ui=None):
16 def extensions(ui=None):
17 if ui:
17 if ui:
18 def enabled(name):
18 def enabled(name):
19 for format in ['%s', 'hgext.%s']:
19 for format in ['%s', 'hgext.%s']:
20 conf = ui.config('extensions', format % name)
20 conf = ui.config('extensions', format % name)
21 if conf is not None and not conf.startswith('!'):
21 if conf is not None and not conf.startswith('!'):
22 return True
22 return True
23 else:
23 else:
24 enabled = lambda name: True
24 enabled = lambda name: True
25 for name in _order:
25 for name in _order:
26 module = _extensions[name]
26 module = _extensions[name]
27 if module and enabled(name):
27 if module and enabled(name):
28 yield name, module
28 yield name, module
29
29
30 def find(name):
30 def find(name):
31 '''return module with given extension name'''
31 '''return module with given extension name'''
32 mod = None
32 mod = None
33 try:
33 try:
34 mod = _extensions[name]
34 mod = _extensions[name]
35 except KeyError:
35 except KeyError:
36 for k, v in _extensions.iteritems():
36 for k, v in _extensions.iteritems():
37 if k.endswith('.' + name) or k.endswith('/' + name):
37 if k.endswith('.' + name) or k.endswith('/' + name):
38 mod = v
38 mod = v
39 break
39 break
40 if not mod:
40 if not mod:
41 raise KeyError(name)
41 raise KeyError(name)
42 return mod
42 return mod
43
43
44 def loadpath(path, module_name):
44 def loadpath(path, module_name):
45 module_name = module_name.replace('.', '_')
45 module_name = module_name.replace('.', '_')
46 path = util.expandpath(path)
46 path = util.expandpath(path)
47 if os.path.isdir(path):
47 if os.path.isdir(path):
48 # module/__init__.py style
48 # module/__init__.py style
49 d, f = os.path.split(path.rstrip('/'))
49 d, f = os.path.split(path.rstrip('/'))
50 fd, fpath, desc = imp.find_module(f, [d])
50 fd, fpath, desc = imp.find_module(f, [d])
51 return imp.load_module(module_name, fd, fpath, desc)
51 return imp.load_module(module_name, fd, fpath, desc)
52 else:
52 else:
53 try:
53 try:
54 return imp.load_source(module_name, path)
54 return imp.load_source(module_name, path)
55 except IOError, exc:
55 except IOError, exc:
56 if not exc.filename:
56 if not exc.filename:
57 exc.filename = path # python does not fill this
57 exc.filename = path # python does not fill this
58 raise
58 raise
59
59
60 def load(ui, name, path):
60 def load(ui, name, path):
61 if name.startswith('hgext.') or name.startswith('hgext/'):
61 if name.startswith('hgext.') or name.startswith('hgext/'):
62 shortname = name[6:]
62 shortname = name[6:]
63 else:
63 else:
64 shortname = name
64 shortname = name
65 if shortname in _ignore:
65 if shortname in _ignore:
66 return None
66 return None
67 if shortname in _extensions:
67 if shortname in _extensions:
68 return _extensions[shortname]
68 return _extensions[shortname]
69 _extensions[shortname] = None
69 _extensions[shortname] = None
70 if path:
70 if path:
71 # the module will be loaded in sys.modules
71 # the module will be loaded in sys.modules
72 # choose an unique name so that it doesn't
72 # choose an unique name so that it doesn't
73 # conflicts with other modules
73 # conflicts with other modules
74 mod = loadpath(path, 'hgext.%s' % name)
74 mod = loadpath(path, 'hgext.%s' % name)
75 else:
75 else:
76 def importh(name):
76 def importh(name):
77 mod = __import__(name)
77 mod = __import__(name)
78 components = name.split('.')
78 components = name.split('.')
79 for comp in components[1:]:
79 for comp in components[1:]:
80 mod = getattr(mod, comp)
80 mod = getattr(mod, comp)
81 return mod
81 return mod
82 try:
82 try:
83 mod = importh("hgext.%s" % name)
83 mod = importh("hgext.%s" % name)
84 except ImportError, err:
84 except ImportError, err:
85 ui.debug('could not import hgext.%s (%s): trying %s\n'
85 ui.debug('could not import hgext.%s (%s): trying %s\n'
86 % (name, err, name))
86 % (name, err, name))
87 mod = importh(name)
87 mod = importh(name)
88 _extensions[shortname] = mod
88 _extensions[shortname] = mod
89 _order.append(shortname)
89 _order.append(shortname)
90 return mod
90 return mod
91
91
92 def loadall(ui):
92 def loadall(ui):
93 result = ui.configitems("extensions")
93 result = ui.configitems("extensions")
94 newindex = len(_order)
94 newindex = len(_order)
95 for (name, path) in result:
95 for (name, path) in result:
96 if path:
96 if path:
97 if path[0] == '!':
97 if path[0] == '!':
98 continue
98 continue
99 try:
99 try:
100 load(ui, name, path)
100 load(ui, name, path)
101 except KeyboardInterrupt:
101 except KeyboardInterrupt:
102 raise
102 raise
103 except Exception, inst:
103 except Exception, inst:
104 if path:
104 if path:
105 ui.warn(_("*** failed to import extension %s from %s: %s\n")
105 ui.warn(_("*** failed to import extension %s from %s: %s\n")
106 % (name, path, inst))
106 % (name, path, inst))
107 else:
107 else:
108 ui.warn(_("*** failed to import extension %s: %s\n")
108 ui.warn(_("*** failed to import extension %s: %s\n")
109 % (name, inst))
109 % (name, inst))
110 if ui.traceback():
110 if ui.traceback():
111 return 1
111 return 1
112
112
113 for name in _order[newindex:]:
113 for name in _order[newindex:]:
114 uisetup = getattr(_extensions[name], 'uisetup', None)
114 uisetup = getattr(_extensions[name], 'uisetup', None)
115 if uisetup:
115 if uisetup:
116 uisetup(ui)
116 uisetup(ui)
117
117
118 for name in _order[newindex:]:
118 for name in _order[newindex:]:
119 extsetup = getattr(_extensions[name], 'extsetup', None)
119 extsetup = getattr(_extensions[name], 'extsetup', None)
120 if extsetup:
120 if extsetup:
121 try:
121 try:
122 extsetup(ui)
122 extsetup(ui)
123 except TypeError:
123 except TypeError:
124 if extsetup.func_code.co_argcount != 0:
124 if extsetup.func_code.co_argcount != 0:
125 raise
125 raise
126 extsetup() # old extsetup with no ui argument
126 extsetup() # old extsetup with no ui argument
127
127
128 def wrapcommand(table, command, wrapper):
128 def wrapcommand(table, command, wrapper):
129 '''Wrap the command named `command' in table
129 '''Wrap the command named `command' in table
130
130
131 Replace command in the command table with wrapper. The wrapped command will
131 Replace command in the command table with wrapper. The wrapped command will
132 be inserted into the command table specified by the table argument.
132 be inserted into the command table specified by the table argument.
133
133
134 The wrapper will be called like
134 The wrapper will be called like
135
135
136 wrapper(orig, *args, **kwargs)
136 wrapper(orig, *args, **kwargs)
137
137
138 where orig is the original (wrapped) function, and *args, **kwargs
138 where orig is the original (wrapped) function, and *args, **kwargs
139 are the arguments passed to it.
139 are the arguments passed to it.
140 '''
140 '''
141 assert util.safehasattr(wrapper, '__call__')
141 assert util.safehasattr(wrapper, '__call__')
142 aliases, entry = cmdutil.findcmd(command, table)
142 aliases, entry = cmdutil.findcmd(command, table)
143 for alias, e in table.iteritems():
143 for alias, e in table.iteritems():
144 if e is entry:
144 if e is entry:
145 key = alias
145 key = alias
146 break
146 break
147
147
148 origfn = entry[0]
148 origfn = entry[0]
149 def wrap(*args, **kwargs):
149 def wrap(*args, **kwargs):
150 return util.checksignature(wrapper)(
150 return util.checksignature(wrapper)(
151 util.checksignature(origfn), *args, **kwargs)
151 util.checksignature(origfn), *args, **kwargs)
152
152
153 wrap.__doc__ = getattr(origfn, '__doc__')
153 wrap.__doc__ = getattr(origfn, '__doc__')
154 wrap.__module__ = getattr(origfn, '__module__')
154 wrap.__module__ = getattr(origfn, '__module__')
155
155
156 newentry = list(entry)
156 newentry = list(entry)
157 newentry[0] = wrap
157 newentry[0] = wrap
158 table[key] = tuple(newentry)
158 table[key] = tuple(newentry)
159 return entry
159 return entry
160
160
161 def wrapfunction(container, funcname, wrapper):
161 def wrapfunction(container, funcname, wrapper):
162 '''Wrap the function named funcname in container
162 '''Wrap the function named funcname in container
163
163
164 Replace the funcname member in the given container with the specified
164 Replace the funcname member in the given container with the specified
165 wrapper. The container is typically a module, class, or instance.
165 wrapper. The container is typically a module, class, or instance.
166
166
167 The wrapper will be called like
167 The wrapper will be called like
168
168
169 wrapper(orig, *args, **kwargs)
169 wrapper(orig, *args, **kwargs)
170
170
171 where orig is the original (wrapped) function, and *args, **kwargs
171 where orig is the original (wrapped) function, and *args, **kwargs
172 are the arguments passed to it.
172 are the arguments passed to it.
173
173
174 Wrapping methods of the repository object is not recommended since
174 Wrapping methods of the repository object is not recommended since
175 it conflicts with extensions that extend the repository by
175 it conflicts with extensions that extend the repository by
176 subclassing. All extensions that need to extend methods of
176 subclassing. All extensions that need to extend methods of
177 localrepository should use this subclassing trick: namely,
177 localrepository should use this subclassing trick: namely,
178 reposetup() should look like
178 reposetup() should look like
179
179
180 def reposetup(ui, repo):
180 def reposetup(ui, repo):
181 class myrepo(repo.__class__):
181 class myrepo(repo.__class__):
182 def whatever(self, *args, **kwargs):
182 def whatever(self, *args, **kwargs):
183 [...extension stuff...]
183 [...extension stuff...]
184 super(myrepo, self).whatever(*args, **kwargs)
184 super(myrepo, self).whatever(*args, **kwargs)
185 [...extension stuff...]
185 [...extension stuff...]
186
186
187 repo.__class__ = myrepo
187 repo.__class__ = myrepo
188
188
189 In general, combining wrapfunction() with subclassing does not
189 In general, combining wrapfunction() with subclassing does not
190 work. Since you cannot control what other extensions are loaded by
190 work. Since you cannot control what other extensions are loaded by
191 your end users, you should play nicely with others by using the
191 your end users, you should play nicely with others by using the
192 subclass trick.
192 subclass trick.
193 '''
193 '''
194 assert util.safehasattr(wrapper, '__call__')
194 assert util.safehasattr(wrapper, '__call__')
195 def wrap(*args, **kwargs):
195 def wrap(*args, **kwargs):
196 return wrapper(origfn, *args, **kwargs)
196 return wrapper(origfn, *args, **kwargs)
197
197
198 origfn = getattr(container, funcname)
198 origfn = getattr(container, funcname)
199 assert util.safehasattr(origfn, '__call__')
199 assert util.safehasattr(origfn, '__call__')
200 setattr(container, funcname, wrap)
200 setattr(container, funcname, wrap)
201 return origfn
201 return origfn
202
202
203 def _disabledpaths(strip_init=False):
203 def _disabledpaths(strip_init=False):
204 '''find paths of disabled extensions. returns a dict of {name: path}
204 '''find paths of disabled extensions. returns a dict of {name: path}
205 removes /__init__.py from packages if strip_init is True'''
205 removes /__init__.py from packages if strip_init is True'''
206 import hgext
206 import hgext
207 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
207 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
208 try: # might not be a filesystem path
208 try: # might not be a filesystem path
209 files = os.listdir(extpath)
209 files = os.listdir(extpath)
210 except OSError:
210 except OSError:
211 return {}
211 return {}
212
212
213 exts = {}
213 exts = {}
214 for e in files:
214 for e in files:
215 if e.endswith('.py'):
215 if e.endswith('.py'):
216 name = e.rsplit('.', 1)[0]
216 name = e.rsplit('.', 1)[0]
217 path = os.path.join(extpath, e)
217 path = os.path.join(extpath, e)
218 else:
218 else:
219 name = e
219 name = e
220 path = os.path.join(extpath, e, '__init__.py')
220 path = os.path.join(extpath, e, '__init__.py')
221 if not os.path.exists(path):
221 if not os.path.exists(path):
222 continue
222 continue
223 if strip_init:
223 if strip_init:
224 path = os.path.dirname(path)
224 path = os.path.dirname(path)
225 if name in exts or name in _order or name == '__init__':
225 if name in exts or name in _order or name == '__init__':
226 continue
226 continue
227 exts[name] = path
227 exts[name] = path
228 return exts
228 return exts
229
229
230 def _moduledoc(file):
230 def _moduledoc(file):
231 '''return the top-level python documentation for the given file
231 '''return the top-level python documentation for the given file
232
232
233 Loosely inspired by pydoc.source_synopsis(), but rewritten to
233 Loosely inspired by pydoc.source_synopsis(), but rewritten to
234 handle triple quotes and to return the whole text instead of just
234 handle triple quotes and to return the whole text instead of just
235 the synopsis'''
235 the synopsis'''
236 result = []
236 result = []
237
237
238 line = file.readline()
238 line = file.readline()
239 while line[:1] == '#' or not line.strip():
239 while line[:1] == '#' or not line.strip():
240 line = file.readline()
240 line = file.readline()
241 if not line:
241 if not line:
242 break
242 break
243
243
244 start = line[:3]
244 start = line[:3]
245 if start == '"""' or start == "'''":
245 if start == '"""' or start == "'''":
246 line = line[3:]
246 line = line[3:]
247 while line:
247 while line:
248 if line.rstrip().endswith(start):
248 if line.rstrip().endswith(start):
249 line = line.split(start)[0]
249 line = line.split(start)[0]
250 if line:
250 if line:
251 result.append(line)
251 result.append(line)
252 break
252 break
253 elif not line:
253 elif not line:
254 return None # unmatched delimiter
254 return None # unmatched delimiter
255 result.append(line)
255 result.append(line)
256 line = file.readline()
256 line = file.readline()
257 else:
257 else:
258 return None
258 return None
259
259
260 return ''.join(result)
260 return ''.join(result)
261
261
262 def _disabledhelp(path):
262 def _disabledhelp(path):
263 '''retrieve help synopsis of a disabled extension (without importing)'''
263 '''retrieve help synopsis of a disabled extension (without importing)'''
264 try:
264 try:
265 file = open(path)
265 file = open(path)
266 except IOError:
266 except IOError:
267 return
267 return
268 else:
268 else:
269 doc = _moduledoc(file)
269 doc = _moduledoc(file)
270 file.close()
270 file.close()
271
271
272 if doc: # extracting localized synopsis
272 if doc: # extracting localized synopsis
273 return gettext(doc).splitlines()[0]
273 return gettext(doc).splitlines()[0]
274 else:
274 else:
275 return _('(no help text available)')
275 return _('(no help text available)')
276
276
277 def disabled():
277 def disabled():
278 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
278 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
279 try:
279 try:
280 from hgext import __index__
280 from hgext import __index__
281 return dict((name, gettext(desc))
281 return dict((name, gettext(desc))
282 for name, desc in __index__.docs.iteritems()
282 for name, desc in __index__.docs.iteritems()
283 if name not in _order)
283 if name not in _order)
284 except ImportError:
284 except ImportError:
285 pass
285 pass
286
286
287 paths = _disabledpaths()
287 paths = _disabledpaths()
288 if not paths:
288 if not paths:
289 return {}
289 return {}
290
290
291 exts = {}
291 exts = {}
292 for name, path in paths.iteritems():
292 for name, path in paths.iteritems():
293 doc = _disabledhelp(path)
293 doc = _disabledhelp(path)
294 if doc:
294 if doc:
295 exts[name] = doc
295 exts[name] = doc
296
296
297 return exts
297 return exts
298
298
299 def disabledext(name):
299 def disabledext(name):
300 '''find a specific disabled extension from hgext. returns desc'''
300 '''find a specific disabled extension from hgext. returns desc'''
301 try:
301 try:
302 from hgext import __index__
302 from hgext import __index__
303 if name in _order: # enabled
303 if name in _order: # enabled
304 return
304 return
305 else:
305 else:
306 return gettext(__index__.docs.get(name))
306 return gettext(__index__.docs.get(name))
307 except ImportError:
307 except ImportError:
308 pass
308 pass
309
309
310 paths = _disabledpaths()
310 paths = _disabledpaths()
311 if name in paths:
311 if name in paths:
312 return _disabledhelp(paths[name])
312 return _disabledhelp(paths[name])
313
313
314 def disabledcmd(ui, cmd, strict=False):
314 def disabledcmd(ui, cmd, strict=False):
315 '''import disabled extensions until cmd is found.
315 '''import disabled extensions until cmd is found.
316 returns (cmdname, extname, module)'''
316 returns (cmdname, extname, module)'''
317
317
318 paths = _disabledpaths(strip_init=True)
318 paths = _disabledpaths(strip_init=True)
319 if not paths:
319 if not paths:
320 raise error.UnknownCommand(cmd)
320 raise error.UnknownCommand(cmd)
321
321
322 def findcmd(cmd, name, path):
322 def findcmd(cmd, name, path):
323 try:
323 try:
324 mod = loadpath(path, 'hgext.%s' % name)
324 mod = loadpath(path, 'hgext.%s' % name)
325 except Exception:
325 except Exception:
326 return
326 return
327 try:
327 try:
328 aliases, entry = cmdutil.findcmd(cmd,
328 aliases, entry = cmdutil.findcmd(cmd,
329 getattr(mod, 'cmdtable', {}), strict)
329 getattr(mod, 'cmdtable', {}), strict)
330 except (error.AmbiguousCommand, error.UnknownCommand):
330 except (error.AmbiguousCommand, error.UnknownCommand):
331 return
331 return
332 except Exception:
332 except Exception:
333 ui.warn(_('warning: error finding commands in %s\n') % path)
333 ui.warn(_('warning: error finding commands in %s\n') % path)
334 ui.traceback()
334 ui.traceback()
335 return
335 return
336 for c in aliases:
336 for c in aliases:
337 if c.startswith(cmd):
337 if c.startswith(cmd):
338 cmd = c
338 cmd = c
339 break
339 break
340 else:
340 else:
341 cmd = aliases[0]
341 cmd = aliases[0]
342 return (cmd, name, mod)
342 return (cmd, name, mod)
343
343
344 ext = None
344 ext = None
345 # first, search for an extension with the same name as the command
345 # first, search for an extension with the same name as the command
346 path = paths.pop(cmd, None)
346 path = paths.pop(cmd, None)
347 if path:
347 if path:
348 ext = findcmd(cmd, cmd, path)
348 ext = findcmd(cmd, cmd, path)
349 if not ext:
349 if not ext:
350 # otherwise, interrogate each extension until there's a match
350 # otherwise, interrogate each extension until there's a match
351 for name, path in paths.iteritems():
351 for name, path in paths.iteritems():
352 ext = findcmd(cmd, name, path)
352 ext = findcmd(cmd, name, path)
353 if ext:
353 if ext:
354 break
354 break
355 if ext and 'DEPRECATED' not in ext.__doc__:
355 if ext and 'DEPRECATED' not in ext.__doc__:
356 return ext
356 return ext
357
357
358 raise error.UnknownCommand(cmd)
358 raise error.UnknownCommand(cmd)
359
359
360 def enabled(shortname=True):
360 def enabled(shortname=True):
361 '''return a dict of {name: desc} of extensions'''
361 '''return a dict of {name: desc} of extensions'''
362 exts = {}
362 exts = {}
363 for ename, ext in extensions():
363 for ename, ext in extensions():
364 doc = (gettext(ext.__doc__) or _('(no help text available)'))
364 doc = (gettext(ext.__doc__) or _('(no help text available)'))
365 if shortname:
365 if shortname:
366 ename = ename.split('.')[-1]
366 ename = ename.split('.')[-1]
367 exts[ename] = doc.splitlines()[0].strip()
367 exts[ename] = doc.splitlines()[0].strip()
368
368
369 return exts
369 return exts
@@ -1,577 +1,563 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 def b(s):
12 def b(s):
13 '''A helper function to emulate 2.6+ bytes literals using string
13 '''A helper function to emulate 2.6+ bytes literals using string
14 literals.'''
14 literals.'''
15 return s.encode('latin1')
15 return s.encode('latin1')
16 else:
16 else:
17 def b(s):
17 def b(s):
18 '''A helper function to emulate 2.6+ bytes literals using string
18 '''A helper function to emulate 2.6+ bytes literals using string
19 literals.'''
19 literals.'''
20 return s
20 return s
21
21
22 # Solaris Python packaging brain damage
22 # Solaris Python packaging brain damage
23 try:
23 try:
24 import hashlib
24 import hashlib
25 sha = hashlib.sha1()
25 sha = hashlib.sha1()
26 except ImportError:
26 except ImportError:
27 try:
27 try:
28 import sha
28 import sha
29 except ImportError:
29 except ImportError:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 except ImportError:
35 except ImportError:
36 raise SystemExit(
36 raise SystemExit(
37 "Couldn't import standard zlib (incomplete Python install).")
37 "Couldn't import standard zlib (incomplete Python install).")
38
38
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 isironpython = False
40 isironpython = False
41 try:
41 try:
42 isironpython = (platform.python_implementation()
42 isironpython = (platform.python_implementation()
43 .lower().find("ironpython") != -1)
43 .lower().find("ironpython") != -1)
44 except AttributeError:
44 except AttributeError:
45 pass
45 pass
46
46
47 if isironpython:
47 if isironpython:
48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
48 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
49 else:
49 else:
50 try:
50 try:
51 import bz2
51 import bz2
52 except ImportError:
52 except ImportError:
53 raise SystemExit(
53 raise SystemExit(
54 "Couldn't import standard bz2 (incomplete Python install).")
54 "Couldn't import standard bz2 (incomplete Python install).")
55
55
56 import os, subprocess, time
56 import os, subprocess, time
57 import shutil
57 import shutil
58 import tempfile
58 import tempfile
59 from distutils import log
59 from distutils import log
60 from distutils.core import setup, Command, Extension
60 from distutils.core import setup, Command, Extension
61 from distutils.dist import Distribution
61 from distutils.dist import Distribution
62 from distutils.command.build import build
62 from distutils.command.build import build
63 from distutils.command.build_ext import build_ext
63 from distutils.command.build_ext import build_ext
64 from distutils.command.build_py import build_py
64 from distutils.command.build_py import build_py
65 from distutils.command.install_scripts import install_scripts
65 from distutils.command.install_scripts import install_scripts
66 from distutils.spawn import spawn, find_executable
66 from distutils.spawn import spawn, find_executable
67 from distutils.ccompiler import new_compiler
67 from distutils.ccompiler import new_compiler
68 from distutils import cygwinccompiler
68 from distutils import cygwinccompiler
69 from distutils.errors import CCompilerError, DistutilsExecError
69 from distutils.errors import CCompilerError, DistutilsExecError
70 from distutils.sysconfig import get_python_inc
70 from distutils.sysconfig import get_python_inc
71 from distutils.version import StrictVersion
71 from distutils.version import StrictVersion
72
72
73 convert2to3 = '--c2to3' in sys.argv
73 convert2to3 = '--c2to3' in sys.argv
74 if convert2to3:
74 if convert2to3:
75 try:
75 try:
76 from distutils.command.build_py import build_py_2to3 as build_py
76 from distutils.command.build_py import build_py_2to3 as build_py
77 from lib2to3.refactor import get_fixers_from_package as getfixers
77 from lib2to3.refactor import get_fixers_from_package as getfixers
78 except ImportError:
78 except ImportError:
79 if sys.version_info[0] < 3:
79 if sys.version_info[0] < 3:
80 raise SystemExit("--c2to3 is only compatible with python3.")
80 raise SystemExit("--c2to3 is only compatible with python3.")
81 raise
81 raise
82 sys.path.append('contrib')
82 sys.path.append('contrib')
83 elif sys.version_info[0] >= 3:
83 elif sys.version_info[0] >= 3:
84 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
84 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
85
85
86 scripts = ['hg']
86 scripts = ['hg']
87 if os.name == 'nt':
87 if os.name == 'nt':
88 scripts.append('contrib/win32/hg.bat')
88 scripts.append('contrib/win32/hg.bat')
89
89
90 # simplified version of distutils.ccompiler.CCompiler.has_function
90 # simplified version of distutils.ccompiler.CCompiler.has_function
91 # that actually removes its temporary files.
91 # that actually removes its temporary files.
92 def hasfunction(cc, funcname):
92 def hasfunction(cc, funcname):
93 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
93 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
94 devnull = oldstderr = None
94 devnull = oldstderr = None
95 try:
95 try:
96 try:
96 try:
97 fname = os.path.join(tmpdir, 'funcname.c')
97 fname = os.path.join(tmpdir, 'funcname.c')
98 f = open(fname, 'w')
98 f = open(fname, 'w')
99 f.write('int main(void) {\n')
99 f.write('int main(void) {\n')
100 f.write(' %s();\n' % funcname)
100 f.write(' %s();\n' % funcname)
101 f.write('}\n')
101 f.write('}\n')
102 f.close()
102 f.close()
103 # Redirect stderr to /dev/null to hide any error messages
103 # Redirect stderr to /dev/null to hide any error messages
104 # from the compiler.
104 # from the compiler.
105 # This will have to be changed if we ever have to check
105 # This will have to be changed if we ever have to check
106 # for a function on Windows.
106 # for a function on Windows.
107 devnull = open('/dev/null', 'w')
107 devnull = open('/dev/null', 'w')
108 oldstderr = os.dup(sys.stderr.fileno())
108 oldstderr = os.dup(sys.stderr.fileno())
109 os.dup2(devnull.fileno(), sys.stderr.fileno())
109 os.dup2(devnull.fileno(), sys.stderr.fileno())
110 objects = cc.compile([fname], output_dir=tmpdir)
110 objects = cc.compile([fname], output_dir=tmpdir)
111 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
111 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
112 except Exception:
112 except Exception:
113 return False
113 return False
114 return True
114 return True
115 finally:
115 finally:
116 if oldstderr is not None:
116 if oldstderr is not None:
117 os.dup2(oldstderr, sys.stderr.fileno())
117 os.dup2(oldstderr, sys.stderr.fileno())
118 if devnull is not None:
118 if devnull is not None:
119 devnull.close()
119 devnull.close()
120 shutil.rmtree(tmpdir)
120 shutil.rmtree(tmpdir)
121
121
122 # py2exe needs to be installed to work
122 # py2exe needs to be installed to work
123 try:
123 try:
124 import py2exe
124 import py2exe
125 py2exeloaded = True
125 py2exeloaded = True
126 # import py2exe's patched Distribution class
126 # import py2exe's patched Distribution class
127 from distutils.core import Distribution
127 from distutils.core import Distribution
128 except ImportError:
128 except ImportError:
129 py2exeloaded = False
129 py2exeloaded = False
130
130
131 def runcmd(cmd, env):
131 def runcmd(cmd, env):
132 if sys.platform == 'plan9':
132 if sys.platform == 'plan9':
133 # subprocess kludge to work around issues in half-baked Python
133 # subprocess kludge to work around issues in half-baked Python
134 # ports, notably bichued/python:
134 # ports, notably bichued/python:
135 _, out, err = os.popen3(cmd)
135 _, out, err = os.popen3(cmd)
136 return str(out), str(err)
136 return str(out), str(err)
137 else:
137 else:
138 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
138 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
139 stderr=subprocess.PIPE, env=env)
139 stderr=subprocess.PIPE, env=env)
140 out, err = p.communicate()
140 out, err = p.communicate()
141 return out, err
141 return out, err
142
142
143 def runhg(cmd, env):
143 def runhg(cmd, env):
144 out, err = runcmd(cmd, env)
144 out, err = runcmd(cmd, env)
145 # If root is executing setup.py, but the repository is owned by
145 # If root is executing setup.py, but the repository is owned by
146 # another user (as in "sudo python setup.py install") we will get
146 # another user (as in "sudo python setup.py install") we will get
147 # trust warnings since the .hg/hgrc file is untrusted. That is
147 # trust warnings since the .hg/hgrc file is untrusted. That is
148 # fine, we don't want to load it anyway. Python may warn about
148 # fine, we don't want to load it anyway. Python may warn about
149 # a missing __init__.py in mercurial/locale, we also ignore that.
149 # a missing __init__.py in mercurial/locale, we also ignore that.
150 err = [e for e in err.splitlines()
150 err = [e for e in err.splitlines()
151 if not e.startswith(b('not trusting file')) \
151 if not e.startswith(b('not trusting file')) \
152 and not e.startswith(b('warning: Not importing')) \
152 and not e.startswith(b('warning: Not importing')) \
153 and not e.startswith(b('obsolete feature not enabled'))]
153 and not e.startswith(b('obsolete feature not enabled'))]
154 if err:
154 if err:
155 print >> sys.stderr, "stderr from '%s':" % (' '.join(cmd))
155 print >> sys.stderr, "stderr from '%s':" % (' '.join(cmd))
156 print >> sys.stderr, '\n'.join([' ' + e for e in err])
156 print >> sys.stderr, '\n'.join([' ' + e for e in err])
157 return ''
157 return ''
158 return out
158 return out
159
159
160 version = ''
160 version = ''
161
161
162 # Execute hg out of this directory with a custom environment which
162 # Execute hg out of this directory with a custom environment which
163 # includes the pure Python modules in mercurial/pure. We also take
163 # includes the pure Python modules in mercurial/pure. We also take
164 # care to not use any hgrc files and do no localization.
164 # care to not use any hgrc files and do no localization.
165 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
165 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
166 env = {'PYTHONPATH': os.pathsep.join(pypath),
166 env = {'PYTHONPATH': os.pathsep.join(pypath),
167 'HGRCPATH': '',
167 'HGRCPATH': '',
168 'LANGUAGE': 'C'}
168 'LANGUAGE': 'C'}
169 if 'LD_LIBRARY_PATH' in os.environ:
169 if 'LD_LIBRARY_PATH' in os.environ:
170 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
170 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
171 if 'SystemRoot' in os.environ:
171 if 'SystemRoot' in os.environ:
172 # Copy SystemRoot into the custom environment for Python 2.6
172 # Copy SystemRoot into the custom environment for Python 2.6
173 # under Windows. Otherwise, the subprocess will fail with
173 # under Windows. Otherwise, the subprocess will fail with
174 # error 0xc0150004. See: http://bugs.python.org/issue3440
174 # error 0xc0150004. See: http://bugs.python.org/issue3440
175 env['SystemRoot'] = os.environ['SystemRoot']
175 env['SystemRoot'] = os.environ['SystemRoot']
176
176
177 if os.path.isdir('.hg'):
177 if os.path.isdir('.hg'):
178 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
178 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
179 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
179 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
180 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
180 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
181 if numerictags: # tag(s) found
181 if numerictags: # tag(s) found
182 version = numerictags[-1]
182 version = numerictags[-1]
183 if hgid.endswith('+'): # propagate the dirty status to the tag
183 if hgid.endswith('+'): # propagate the dirty status to the tag
184 version += '+'
184 version += '+'
185 else: # no tag found
185 else: # no tag found
186 cmd = [sys.executable, 'hg', 'parents', '--template',
186 cmd = [sys.executable, 'hg', 'parents', '--template',
187 '{latesttag}+{latesttagdistance}-']
187 '{latesttag}+{latesttagdistance}-']
188 version = runhg(cmd, env) + hgid
188 version = runhg(cmd, env) + hgid
189 if version.endswith('+'):
189 if version.endswith('+'):
190 version += time.strftime('%Y%m%d')
190 version += time.strftime('%Y%m%d')
191 elif os.path.exists('.hg_archival.txt'):
191 elif os.path.exists('.hg_archival.txt'):
192 kw = dict([[t.strip() for t in l.split(':', 1)]
192 kw = dict([[t.strip() for t in l.split(':', 1)]
193 for l in open('.hg_archival.txt')])
193 for l in open('.hg_archival.txt')])
194 if 'tag' in kw:
194 if 'tag' in kw:
195 version = kw['tag']
195 version = kw['tag']
196 elif 'latesttag' in kw:
196 elif 'latesttag' in kw:
197 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
197 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
198 else:
198 else:
199 version = kw.get('node', '')[:12]
199 version = kw.get('node', '')[:12]
200
200
201 if version:
201 if version:
202 f = open("mercurial/__version__.py", "w")
202 f = open("mercurial/__version__.py", "w")
203 f.write('# this file is autogenerated by setup.py\n')
203 f.write('# this file is autogenerated by setup.py\n')
204 f.write('version = "%s"\n' % version)
204 f.write('version = "%s"\n' % version)
205 f.close()
205 f.close()
206
206
207
207
208 try:
208 try:
209 from mercurial import __version__
209 from mercurial import __version__
210 version = __version__.version
210 version = __version__.version
211 except ImportError:
211 except ImportError:
212 version = 'unknown'
212 version = 'unknown'
213
213
214 class hgbuild(build):
214 class hgbuild(build):
215 # Insert hgbuildmo first so that files in mercurial/locale/ are found
215 # Insert hgbuildmo first so that files in mercurial/locale/ are found
216 # when build_py is run next.
216 # when build_py is run next.
217 sub_commands = [('build_mo', None),
217 sub_commands = [('build_mo', None),
218
218
219 # We also need build_ext before build_py. Otherwise, when 2to3 is
219 # We also need build_ext before build_py. Otherwise, when 2to3 is
220 # called (in build_py), it will not find osutil & friends,
220 # called (in build_py), it will not find osutil & friends,
221 # thinking that those modules are global and, consequently, making
221 # thinking that those modules are global and, consequently, making
222 # a mess, now that all module imports are global.
222 # a mess, now that all module imports are global.
223
223
224 ('build_ext', build.has_ext_modules),
224 ('build_ext', build.has_ext_modules),
225 ] + build.sub_commands
225 ] + build.sub_commands
226
226
227 class hgbuildmo(build):
227 class hgbuildmo(build):
228
228
229 description = "build translations (.mo files)"
229 description = "build translations (.mo files)"
230
230
231 def run(self):
231 def run(self):
232 if not find_executable('msgfmt'):
232 if not find_executable('msgfmt'):
233 self.warn("could not find msgfmt executable, no translations "
233 self.warn("could not find msgfmt executable, no translations "
234 "will be built")
234 "will be built")
235 return
235 return
236
236
237 podir = 'i18n'
237 podir = 'i18n'
238 if not os.path.isdir(podir):
238 if not os.path.isdir(podir):
239 self.warn("could not find %s/ directory" % podir)
239 self.warn("could not find %s/ directory" % podir)
240 return
240 return
241
241
242 join = os.path.join
242 join = os.path.join
243 for po in os.listdir(podir):
243 for po in os.listdir(podir):
244 if not po.endswith('.po'):
244 if not po.endswith('.po'):
245 continue
245 continue
246 pofile = join(podir, po)
246 pofile = join(podir, po)
247 modir = join('locale', po[:-3], 'LC_MESSAGES')
247 modir = join('locale', po[:-3], 'LC_MESSAGES')
248 mofile = join(modir, 'hg.mo')
248 mofile = join(modir, 'hg.mo')
249 mobuildfile = join('mercurial', mofile)
249 mobuildfile = join('mercurial', mofile)
250 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
250 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
251 if sys.platform != 'sunos5':
251 if sys.platform != 'sunos5':
252 # msgfmt on Solaris does not know about -c
252 # msgfmt on Solaris does not know about -c
253 cmd.append('-c')
253 cmd.append('-c')
254 self.mkpath(join('mercurial', modir))
254 self.mkpath(join('mercurial', modir))
255 self.make_file([pofile], mobuildfile, spawn, (cmd,))
255 self.make_file([pofile], mobuildfile, spawn, (cmd,))
256
256
257
257
258 class hgdist(Distribution):
258 class hgdist(Distribution):
259 pure = 0
259 pure = 0
260
260
261 global_options = Distribution.global_options + \
261 global_options = Distribution.global_options + \
262 [('pure', None, "use pure (slow) Python "
262 [('pure', None, "use pure (slow) Python "
263 "code instead of C extensions"),
263 "code instead of C extensions"),
264 ('c2to3', None, "(experimental!) convert "
264 ('c2to3', None, "(experimental!) convert "
265 "code with 2to3"),
265 "code with 2to3"),
266 ]
266 ]
267
267
268 def has_ext_modules(self):
268 def has_ext_modules(self):
269 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
269 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
270 # too late for some cases
270 # too late for some cases
271 return not self.pure and Distribution.has_ext_modules(self)
271 return not self.pure and Distribution.has_ext_modules(self)
272
272
273 class hgbuildext(build_ext):
273 class hgbuildext(build_ext):
274
274
275 def build_extension(self, ext):
275 def build_extension(self, ext):
276 try:
276 try:
277 build_ext.build_extension(self, ext)
277 build_ext.build_extension(self, ext)
278 except CCompilerError:
278 except CCompilerError:
279 if not getattr(ext, 'optional', False):
279 if not getattr(ext, 'optional', False):
280 raise
280 raise
281 log.warn("Failed to build optional extension '%s' (skipping)",
281 log.warn("Failed to build optional extension '%s' (skipping)",
282 ext.name)
282 ext.name)
283
283
284 class hgbuildpy(build_py):
284 class hgbuildpy(build_py):
285 if convert2to3:
285 if convert2to3:
286 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
286 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
287 getfixers("hgfixes")))
287 getfixers("hgfixes")))
288
288
289 def finalize_options(self):
289 def finalize_options(self):
290 build_py.finalize_options(self)
290 build_py.finalize_options(self)
291
291
292 if self.distribution.pure:
292 if self.distribution.pure:
293 if self.py_modules is None:
293 if self.py_modules is None:
294 self.py_modules = []
294 self.py_modules = []
295 for ext in self.distribution.ext_modules:
295 for ext in self.distribution.ext_modules:
296 if ext.name.startswith("mercurial."):
296 if ext.name.startswith("mercurial."):
297 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
297 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
298 self.distribution.ext_modules = []
298 self.distribution.ext_modules = []
299 else:
299 else:
300 h = os.path.join(get_python_inc(), 'Python.h')
300 h = os.path.join(get_python_inc(), 'Python.h')
301 if not os.path.exists(h):
301 if not os.path.exists(h):
302 raise SystemExit('Python headers are required to build '
302 raise SystemExit('Python headers are required to build '
303 'Mercurial but weren\'t found in %s' % h)
303 'Mercurial but weren\'t found in %s' % h)
304
304
305 def find_modules(self):
305 def find_modules(self):
306 modules = build_py.find_modules(self)
306 modules = build_py.find_modules(self)
307 for module in modules:
307 for module in modules:
308 if module[0] == "mercurial.pure":
308 if module[0] == "mercurial.pure":
309 if module[1] != "__init__":
309 if module[1] != "__init__":
310 yield ("mercurial", module[1], module[2])
310 yield ("mercurial", module[1], module[2])
311 else:
311 else:
312 yield module
312 yield module
313
313
314 class buildhgextindex(Command):
314 class buildhgextindex(Command):
315 description = 'generate prebuilt index of hgext (for frozen package)'
315 description = 'generate prebuilt index of hgext (for frozen package)'
316 user_options = []
316 user_options = []
317 _indexfilename = 'hgext/__index__.py'
317 _indexfilename = 'hgext/__index__.py'
318
318
319 def initialize_options(self):
319 def initialize_options(self):
320 pass
320 pass
321
321
322 def finalize_options(self):
322 def finalize_options(self):
323 pass
323 pass
324
324
325 def run(self):
325 def run(self):
326 if os.path.exists(self._indexfilename):
326 if os.path.exists(self._indexfilename):
327 os.unlink(self._indexfilename)
327 os.unlink(self._indexfilename)
328
328
329 # here no extension enabled, disabled() lists up everything
329 # here no extension enabled, disabled() lists up everything
330 code = ('import pprint; from mercurial import extensions; '
330 code = ('import pprint; from mercurial import extensions; '
331 'pprint.pprint(extensions.disabled())')
331 'pprint.pprint(extensions.disabled())')
332 out, err = runcmd([sys.executable, '-c', code], env)
332 out, err = runcmd([sys.executable, '-c', code], env)
333 if err:
333 if err:
334 raise DistutilsExecError(err)
334 raise DistutilsExecError(err)
335
335
336 f = open(self._indexfilename, 'w')
336 f = open(self._indexfilename, 'w')
337 f.write('# this file is autogenerated by setup.py\n')
337 f.write('# this file is autogenerated by setup.py\n')
338 f.write('docs = ')
338 f.write('docs = ')
339 f.write(out)
339 f.write(out)
340 f.close()
340 f.close()
341
341
342 class buildhgexe(build_ext):
342 class buildhgexe(build_ext):
343 description = 'compile hg.exe from mercurial/exewrapper.c'
343 description = 'compile hg.exe from mercurial/exewrapper.c'
344
344
345 def build_extensions(self):
345 def build_extensions(self):
346 if os.name != 'nt':
346 if os.name != 'nt':
347 return
347 return
348 if isinstance(self.compiler, HackedMingw32CCompiler):
348 if isinstance(self.compiler, HackedMingw32CCompiler):
349 self.compiler.compiler_so = self.compiler.compiler # no -mdll
349 self.compiler.compiler_so = self.compiler.compiler # no -mdll
350 self.compiler.dll_libraries = [] # no -lmsrvc90
350 self.compiler.dll_libraries = [] # no -lmsrvc90
351 hv = sys.hexversion
351 hv = sys.hexversion
352 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
352 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
353 f = open('mercurial/hgpythonlib.h', 'wb')
353 f = open('mercurial/hgpythonlib.h', 'wb')
354 f.write('/* this file is autogenerated by setup.py */\n')
354 f.write('/* this file is autogenerated by setup.py */\n')
355 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
355 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
356 f.close()
356 f.close()
357 objects = self.compiler.compile(['mercurial/exewrapper.c'],
357 objects = self.compiler.compile(['mercurial/exewrapper.c'],
358 output_dir=self.build_temp)
358 output_dir=self.build_temp)
359 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
359 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
360 target = os.path.join(dir, 'hg')
360 target = os.path.join(dir, 'hg')
361 self.compiler.link_executable(objects, target,
361 self.compiler.link_executable(objects, target,
362 libraries=[],
362 libraries=[],
363 output_dir=self.build_temp)
363 output_dir=self.build_temp)
364
364
365 class hginstallscripts(install_scripts):
365 class hginstallscripts(install_scripts):
366 '''
366 '''
367 This is a specialization of install_scripts that replaces the @LIBDIR@ with
367 This is a specialization of install_scripts that replaces the @LIBDIR@ with
368 the configured directory for modules. If possible, the path is made relative
368 the configured directory for modules. If possible, the path is made relative
369 to the directory for scripts.
369 to the directory for scripts.
370 '''
370 '''
371
371
372 def initialize_options(self):
372 def initialize_options(self):
373 install_scripts.initialize_options(self)
373 install_scripts.initialize_options(self)
374
374
375 self.install_lib = None
375 self.install_lib = None
376
376
377 def finalize_options(self):
377 def finalize_options(self):
378 install_scripts.finalize_options(self)
378 install_scripts.finalize_options(self)
379 self.set_undefined_options('install',
379 self.set_undefined_options('install',
380 ('install_lib', 'install_lib'))
380 ('install_lib', 'install_lib'))
381
381
382 def run(self):
382 def run(self):
383 install_scripts.run(self)
383 install_scripts.run(self)
384
384
385 if (os.path.splitdrive(self.install_dir)[0] !=
385 if (os.path.splitdrive(self.install_dir)[0] !=
386 os.path.splitdrive(self.install_lib)[0]):
386 os.path.splitdrive(self.install_lib)[0]):
387 # can't make relative paths from one drive to another, so use an
387 # can't make relative paths from one drive to another, so use an
388 # absolute path instead
388 # absolute path instead
389 libdir = self.install_lib
389 libdir = self.install_lib
390 else:
390 else:
391 common = os.path.commonprefix((self.install_dir, self.install_lib))
391 common = os.path.commonprefix((self.install_dir, self.install_lib))
392 rest = self.install_dir[len(common):]
392 rest = self.install_dir[len(common):]
393 uplevel = len([n for n in os.path.split(rest) if n])
393 uplevel = len([n for n in os.path.split(rest) if n])
394
394
395 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
395 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
396
396
397 for outfile in self.outfiles:
397 for outfile in self.outfiles:
398 fp = open(outfile, 'rb')
398 fp = open(outfile, 'rb')
399 data = fp.read()
399 data = fp.read()
400 fp.close()
400 fp.close()
401
401
402 # skip binary files
402 # skip binary files
403 if b('\0') in data:
403 if b('\0') in data:
404 continue
404 continue
405
405
406 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
406 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
407 fp = open(outfile, 'wb')
407 fp = open(outfile, 'wb')
408 fp.write(data)
408 fp.write(data)
409 fp.close()
409 fp.close()
410
410
411 cmdclass = {'build': hgbuild,
411 cmdclass = {'build': hgbuild,
412 'build_mo': hgbuildmo,
412 'build_mo': hgbuildmo,
413 'build_ext': hgbuildext,
413 'build_ext': hgbuildext,
414 'build_py': hgbuildpy,
414 'build_py': hgbuildpy,
415 'build_hgextindex': buildhgextindex,
415 'build_hgextindex': buildhgextindex,
416 'install_scripts': hginstallscripts,
416 'install_scripts': hginstallscripts,
417 'build_hgexe': buildhgexe,
417 'build_hgexe': buildhgexe,
418 }
418 }
419
419
420 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
420 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
421 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
421 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
422 'hgext.largefiles']
422 'hgext.largefiles']
423
423
424 pymodules = []
424 pymodules = []
425
425
426 common_depends = ['mercurial/util.h']
426 common_depends = ['mercurial/util.h']
427
427
428 extmodules = [
428 extmodules = [
429 Extension('mercurial.base85', ['mercurial/base85.c'],
429 Extension('mercurial.base85', ['mercurial/base85.c'],
430 depends=common_depends),
430 depends=common_depends),
431 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
431 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
432 depends=common_depends),
432 depends=common_depends),
433 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
433 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
434 depends=common_depends),
434 depends=common_depends),
435 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
435 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
436 depends=common_depends),
436 depends=common_depends),
437 Extension('mercurial.parsers', ['mercurial/dirs.c',
437 Extension('mercurial.parsers', ['mercurial/dirs.c',
438 'mercurial/parsers.c',
438 'mercurial/parsers.c',
439 'mercurial/pathencode.c'],
439 'mercurial/pathencode.c'],
440 depends=common_depends),
440 depends=common_depends),
441 ]
441 ]
442
442
443 osutil_ldflags = []
443 osutil_ldflags = []
444
444
445 if sys.platform == 'darwin':
445 if sys.platform == 'darwin':
446 osutil_ldflags += ['-framework', 'ApplicationServices']
446 osutil_ldflags += ['-framework', 'ApplicationServices']
447
447
448 # disable osutil.c under windows + python 2.4 (issue1364)
448 # disable osutil.c under windows + python 2.4 (issue1364)
449 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
449 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
450 pymodules.append('mercurial.pure.osutil')
450 pymodules.append('mercurial.pure.osutil')
451 else:
451 else:
452 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
452 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
453 extra_link_args=osutil_ldflags,
453 extra_link_args=osutil_ldflags,
454 depends=common_depends))
454 depends=common_depends))
455
455
456 # the -mno-cygwin option has been deprecated for years
456 # the -mno-cygwin option has been deprecated for years
457 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
457 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
458
458
459 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
459 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
460 def __init__(self, *args, **kwargs):
460 def __init__(self, *args, **kwargs):
461 Mingw32CCompiler.__init__(self, *args, **kwargs)
461 Mingw32CCompiler.__init__(self, *args, **kwargs)
462 for i in 'compiler compiler_so linker_exe linker_so'.split():
462 for i in 'compiler compiler_so linker_exe linker_so'.split():
463 try:
463 try:
464 getattr(self, i).remove('-mno-cygwin')
464 getattr(self, i).remove('-mno-cygwin')
465 except ValueError:
465 except ValueError:
466 pass
466 pass
467
467
468 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
468 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
469
469
470 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
471 # The inotify extension is only usable with Linux 2.6 kernels.
472 # You also need a reasonably recent C library.
473 # In any case, if it fails to build the error will be skipped ('optional').
474 cc = new_compiler()
475 if hasfunction(cc, 'inotify_add_watch'):
476 inotify = Extension('hgext.inotify.linux._inotify',
477 ['hgext/inotify/linux/_inotify.c'],
478 ['mercurial'],
479 depends=common_depends)
480 inotify.optional = True
481 extmodules.append(inotify)
482 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
483
484 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
470 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
485 'help/*.txt']}
471 'help/*.txt']}
486
472
487 def ordinarypath(p):
473 def ordinarypath(p):
488 return p and p[0] != '.' and p[-1] != '~'
474 return p and p[0] != '.' and p[-1] != '~'
489
475
490 for root in ('templates',):
476 for root in ('templates',):
491 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
477 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
492 curdir = curdir.split(os.sep, 1)[1]
478 curdir = curdir.split(os.sep, 1)[1]
493 dirs[:] = filter(ordinarypath, dirs)
479 dirs[:] = filter(ordinarypath, dirs)
494 for f in filter(ordinarypath, files):
480 for f in filter(ordinarypath, files):
495 f = os.path.join(curdir, f)
481 f = os.path.join(curdir, f)
496 packagedata['mercurial'].append(f)
482 packagedata['mercurial'].append(f)
497
483
498 datafiles = []
484 datafiles = []
499 setupversion = version
485 setupversion = version
500 extra = {}
486 extra = {}
501
487
502 if py2exeloaded:
488 if py2exeloaded:
503 extra['console'] = [
489 extra['console'] = [
504 {'script':'hg',
490 {'script':'hg',
505 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
491 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
506 'product_version':version}]
492 'product_version':version}]
507 # sub command of 'build' because 'py2exe' does not handle sub_commands
493 # sub command of 'build' because 'py2exe' does not handle sub_commands
508 build.sub_commands.insert(0, ('build_hgextindex', None))
494 build.sub_commands.insert(0, ('build_hgextindex', None))
509
495
510 if os.name == 'nt':
496 if os.name == 'nt':
511 # Windows binary file versions for exe/dll files must have the
497 # Windows binary file versions for exe/dll files must have the
512 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
498 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
513 setupversion = version.split('+', 1)[0]
499 setupversion = version.split('+', 1)[0]
514
500
515 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
501 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
516 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
502 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
517 # distutils.sysconfig
503 # distutils.sysconfig
518 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
504 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
519 if version:
505 if version:
520 version = version[0]
506 version = version[0]
521 xcode4 = (version.startswith('Xcode') and
507 xcode4 = (version.startswith('Xcode') and
522 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
508 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
523 else:
509 else:
524 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
510 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
525 # installed, but instead with only command-line tools. Assume
511 # installed, but instead with only command-line tools. Assume
526 # that only happens on >= Lion, thus no PPC support.
512 # that only happens on >= Lion, thus no PPC support.
527 xcode4 = True
513 xcode4 = True
528
514
529 if xcode4:
515 if xcode4:
530 os.environ['ARCHFLAGS'] = ''
516 os.environ['ARCHFLAGS'] = ''
531
517
532 setup(name='mercurial',
518 setup(name='mercurial',
533 version=setupversion,
519 version=setupversion,
534 author='Matt Mackall and many others',
520 author='Matt Mackall and many others',
535 author_email='mercurial@selenic.com',
521 author_email='mercurial@selenic.com',
536 url='http://mercurial.selenic.com/',
522 url='http://mercurial.selenic.com/',
537 download_url='http://mercurial.selenic.com/release/',
523 download_url='http://mercurial.selenic.com/release/',
538 description=('Fast scalable distributed SCM (revision control, version '
524 description=('Fast scalable distributed SCM (revision control, version '
539 'control) system'),
525 'control) system'),
540 long_description=('Mercurial is a distributed SCM tool written in Python.'
526 long_description=('Mercurial is a distributed SCM tool written in Python.'
541 ' It is used by a number of large projects that require'
527 ' It is used by a number of large projects that require'
542 ' fast, reliable distributed revision control, such as '
528 ' fast, reliable distributed revision control, such as '
543 'Mozilla.'),
529 'Mozilla.'),
544 license='GNU GPLv2 or any later version',
530 license='GNU GPLv2 or any later version',
545 classifiers=[
531 classifiers=[
546 'Development Status :: 6 - Mature',
532 'Development Status :: 6 - Mature',
547 'Environment :: Console',
533 'Environment :: Console',
548 'Intended Audience :: Developers',
534 'Intended Audience :: Developers',
549 'Intended Audience :: System Administrators',
535 'Intended Audience :: System Administrators',
550 'License :: OSI Approved :: GNU General Public License (GPL)',
536 'License :: OSI Approved :: GNU General Public License (GPL)',
551 'Natural Language :: Danish',
537 'Natural Language :: Danish',
552 'Natural Language :: English',
538 'Natural Language :: English',
553 'Natural Language :: German',
539 'Natural Language :: German',
554 'Natural Language :: Italian',
540 'Natural Language :: Italian',
555 'Natural Language :: Japanese',
541 'Natural Language :: Japanese',
556 'Natural Language :: Portuguese (Brazilian)',
542 'Natural Language :: Portuguese (Brazilian)',
557 'Operating System :: Microsoft :: Windows',
543 'Operating System :: Microsoft :: Windows',
558 'Operating System :: OS Independent',
544 'Operating System :: OS Independent',
559 'Operating System :: POSIX',
545 'Operating System :: POSIX',
560 'Programming Language :: C',
546 'Programming Language :: C',
561 'Programming Language :: Python',
547 'Programming Language :: Python',
562 'Topic :: Software Development :: Version Control',
548 'Topic :: Software Development :: Version Control',
563 ],
549 ],
564 scripts=scripts,
550 scripts=scripts,
565 packages=packages,
551 packages=packages,
566 py_modules=pymodules,
552 py_modules=pymodules,
567 ext_modules=extmodules,
553 ext_modules=extmodules,
568 data_files=datafiles,
554 data_files=datafiles,
569 package_data=packagedata,
555 package_data=packagedata,
570 cmdclass=cmdclass,
556 cmdclass=cmdclass,
571 distclass=hgdist,
557 distclass=hgdist,
572 options=dict(py2exe=dict(packages=['hgext', 'email']),
558 options=dict(py2exe=dict(packages=['hgext', 'email']),
573 bdist_mpkg=dict(zipdist=True,
559 bdist_mpkg=dict(zipdist=True,
574 license='COPYING',
560 license='COPYING',
575 readme='contrib/macosx/Readme.html',
561 readme='contrib/macosx/Readme.html',
576 welcome='contrib/macosx/Welcome.html')),
562 welcome='contrib/macosx/Welcome.html')),
577 **extra)
563 **extra)
@@ -1,35 +1,27 b''
1 # invalid filenames
1 # invalid filenames
2 test-add.t
2 test-add.t
3 test-init.t
3 test-init.t
4 test-clone.t
4 test-clone.t
5 test-contrib.t
5 test-contrib.t
6 test-hgweb-raw.t
6 test-hgweb-raw.t
7 test-walk.t
7 test-walk.t
8
8
9 # no sockets or fifos
9 # no sockets or fifos
10 test-hup.t
10 test-hup.t
11 test-inotify-debuginotify.t
12 test-inotify-dirty-dirstate.t
13 test-inotify-issue1208.t
14 test-inotify-issue1371.t
15 test-inotify-issue1542.t
16 test-inotify-lookup.t
17 test-inotify.t
18 test-inotify-issue1556.t
19
11
20 # no hardlinks
12 # no hardlinks
21 test-hardlinks.t
13 test-hardlinks.t
22 test-relink.t
14 test-relink.t
23
15
24 # exec bit problems
16 # exec bit problems
25 test-convert-bzr-114.t
17 test-convert-bzr-114.t
26 test-convert-bzr-directories.t
18 test-convert-bzr-directories.t
27 test-convert-bzr-merges.t
19 test-convert-bzr-merges.t
28 test-convert-bzr-treeroot.t
20 test-convert-bzr-treeroot.t
29 test-convert-darcs.t
21 test-convert-darcs.t
30 test-merge-tools.t
22 test-merge-tools.t
31
23
32 # debugstate exec bit false positives
24 # debugstate exec bit false positives
33 test-dirstate.t
25 test-dirstate.t
34 test-filebranch.t
26 test-filebranch.t
35 test-merge-remove.t
27 test-merge-remove.t
@@ -1,344 +1,328 b''
1 import os, stat, socket
1 import os, stat, socket
2 import re
2 import re
3 import sys
3 import sys
4 import tempfile
4 import tempfile
5
5
6 tempprefix = 'hg-hghave-'
6 tempprefix = 'hg-hghave-'
7
7
8 def matchoutput(cmd, regexp, ignorestatus=False):
8 def matchoutput(cmd, regexp, ignorestatus=False):
9 """Return True if cmd executes successfully and its output
9 """Return True if cmd executes successfully and its output
10 is matched by the supplied regular expression.
10 is matched by the supplied regular expression.
11 """
11 """
12 r = re.compile(regexp)
12 r = re.compile(regexp)
13 fh = os.popen(cmd)
13 fh = os.popen(cmd)
14 s = fh.read()
14 s = fh.read()
15 try:
15 try:
16 ret = fh.close()
16 ret = fh.close()
17 except IOError:
17 except IOError:
18 # Happen in Windows test environment
18 # Happen in Windows test environment
19 ret = 1
19 ret = 1
20 return (ignorestatus or ret is None) and r.search(s)
20 return (ignorestatus or ret is None) and r.search(s)
21
21
22 def has_baz():
22 def has_baz():
23 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
23 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
24
24
25 def has_bzr():
25 def has_bzr():
26 try:
26 try:
27 import bzrlib
27 import bzrlib
28 return bzrlib.__doc__ is not None
28 return bzrlib.__doc__ is not None
29 except ImportError:
29 except ImportError:
30 return False
30 return False
31
31
32 def has_bzr114():
32 def has_bzr114():
33 try:
33 try:
34 import bzrlib
34 import bzrlib
35 return (bzrlib.__doc__ is not None
35 return (bzrlib.__doc__ is not None
36 and bzrlib.version_info[:2] >= (1, 14))
36 and bzrlib.version_info[:2] >= (1, 14))
37 except ImportError:
37 except ImportError:
38 return False
38 return False
39
39
40 def has_cvs():
40 def has_cvs():
41 re = r'Concurrent Versions System.*?server'
41 re = r'Concurrent Versions System.*?server'
42 return matchoutput('cvs --version 2>&1', re) and not has_msys()
42 return matchoutput('cvs --version 2>&1', re) and not has_msys()
43
43
44 def has_cvs112():
44 def has_cvs112():
45 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
45 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
46 return matchoutput('cvs --version 2>&1', re) and not has_msys()
46 return matchoutput('cvs --version 2>&1', re) and not has_msys()
47
47
48 def has_darcs():
48 def has_darcs():
49 return matchoutput('darcs --version', r'2\.[2-9]', True)
49 return matchoutput('darcs --version', r'2\.[2-9]', True)
50
50
51 def has_mtn():
51 def has_mtn():
52 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
52 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
53 'mtn --version', r'monotone 0\.', True)
53 'mtn --version', r'monotone 0\.', True)
54
54
55 def has_eol_in_paths():
55 def has_eol_in_paths():
56 try:
56 try:
57 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
57 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
58 os.close(fd)
58 os.close(fd)
59 os.remove(path)
59 os.remove(path)
60 return True
60 return True
61 except (IOError, OSError):
61 except (IOError, OSError):
62 return False
62 return False
63
63
64 def has_executablebit():
64 def has_executablebit():
65 try:
65 try:
66 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
66 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
67 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
67 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
68 try:
68 try:
69 os.close(fh)
69 os.close(fh)
70 m = os.stat(fn).st_mode & 0777
70 m = os.stat(fn).st_mode & 0777
71 new_file_has_exec = m & EXECFLAGS
71 new_file_has_exec = m & EXECFLAGS
72 os.chmod(fn, m ^ EXECFLAGS)
72 os.chmod(fn, m ^ EXECFLAGS)
73 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
73 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
74 finally:
74 finally:
75 os.unlink(fn)
75 os.unlink(fn)
76 except (IOError, OSError):
76 except (IOError, OSError):
77 # we don't care, the user probably won't be able to commit anyway
77 # we don't care, the user probably won't be able to commit anyway
78 return False
78 return False
79 return not (new_file_has_exec or exec_flags_cannot_flip)
79 return not (new_file_has_exec or exec_flags_cannot_flip)
80
80
81 def has_icasefs():
81 def has_icasefs():
82 # Stolen from mercurial.util
82 # Stolen from mercurial.util
83 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
83 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
84 os.close(fd)
84 os.close(fd)
85 try:
85 try:
86 s1 = os.stat(path)
86 s1 = os.stat(path)
87 d, b = os.path.split(path)
87 d, b = os.path.split(path)
88 p2 = os.path.join(d, b.upper())
88 p2 = os.path.join(d, b.upper())
89 if path == p2:
89 if path == p2:
90 p2 = os.path.join(d, b.lower())
90 p2 = os.path.join(d, b.lower())
91 try:
91 try:
92 s2 = os.stat(p2)
92 s2 = os.stat(p2)
93 return s2 == s1
93 return s2 == s1
94 except OSError:
94 except OSError:
95 return False
95 return False
96 finally:
96 finally:
97 os.remove(path)
97 os.remove(path)
98
98
99 def has_inotify():
100 try:
101 import hgext.inotify.linux.watcher
102 except ImportError:
103 return False
104 name = tempfile.mktemp(dir='.', prefix=tempprefix)
105 sock = socket.socket(socket.AF_UNIX)
106 try:
107 sock.bind(name)
108 except socket.error:
109 return False
110 sock.close()
111 os.unlink(name)
112 return True
113
114 def has_fifo():
99 def has_fifo():
115 if getattr(os, "mkfifo", None) is None:
100 if getattr(os, "mkfifo", None) is None:
116 return False
101 return False
117 name = tempfile.mktemp(dir='.', prefix=tempprefix)
102 name = tempfile.mktemp(dir='.', prefix=tempprefix)
118 try:
103 try:
119 os.mkfifo(name)
104 os.mkfifo(name)
120 os.unlink(name)
105 os.unlink(name)
121 return True
106 return True
122 except OSError:
107 except OSError:
123 return False
108 return False
124
109
125 def has_killdaemons():
110 def has_killdaemons():
126 return True
111 return True
127
112
128 def has_cacheable_fs():
113 def has_cacheable_fs():
129 from mercurial import util
114 from mercurial import util
130
115
131 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
116 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
132 os.close(fd)
117 os.close(fd)
133 try:
118 try:
134 return util.cachestat(path).cacheable()
119 return util.cachestat(path).cacheable()
135 finally:
120 finally:
136 os.remove(path)
121 os.remove(path)
137
122
138 def has_lsprof():
123 def has_lsprof():
139 try:
124 try:
140 import _lsprof
125 import _lsprof
141 return True
126 return True
142 except ImportError:
127 except ImportError:
143 return False
128 return False
144
129
145 def has_gettext():
130 def has_gettext():
146 return matchoutput('msgfmt --version', 'GNU gettext-tools')
131 return matchoutput('msgfmt --version', 'GNU gettext-tools')
147
132
148 def has_git():
133 def has_git():
149 return matchoutput('git --version 2>&1', r'^git version')
134 return matchoutput('git --version 2>&1', r'^git version')
150
135
151 def has_docutils():
136 def has_docutils():
152 try:
137 try:
153 from docutils.core import publish_cmdline
138 from docutils.core import publish_cmdline
154 return True
139 return True
155 except ImportError:
140 except ImportError:
156 return False
141 return False
157
142
158 def getsvnversion():
143 def getsvnversion():
159 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
144 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
160 if not m:
145 if not m:
161 return (0, 0)
146 return (0, 0)
162 return (int(m.group(1)), int(m.group(2)))
147 return (int(m.group(1)), int(m.group(2)))
163
148
164 def has_svn15():
149 def has_svn15():
165 return getsvnversion() >= (1, 5)
150 return getsvnversion() >= (1, 5)
166
151
167 def has_svn13():
152 def has_svn13():
168 return getsvnversion() >= (1, 3)
153 return getsvnversion() >= (1, 3)
169
154
170 def has_svn():
155 def has_svn():
171 return matchoutput('svn --version 2>&1', r'^svn, version') and \
156 return matchoutput('svn --version 2>&1', r'^svn, version') and \
172 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
157 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
173
158
174 def has_svn_bindings():
159 def has_svn_bindings():
175 try:
160 try:
176 import svn.core
161 import svn.core
177 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
162 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
178 if version < (1, 4):
163 if version < (1, 4):
179 return False
164 return False
180 return True
165 return True
181 except ImportError:
166 except ImportError:
182 return False
167 return False
183
168
184 def has_p4():
169 def has_p4():
185 return (matchoutput('p4 -V', r'Rev\. P4/') and
170 return (matchoutput('p4 -V', r'Rev\. P4/') and
186 matchoutput('p4d -V', r'Rev\. P4D/'))
171 matchoutput('p4d -V', r'Rev\. P4D/'))
187
172
188 def has_symlink():
173 def has_symlink():
189 if getattr(os, "symlink", None) is None:
174 if getattr(os, "symlink", None) is None:
190 return False
175 return False
191 name = tempfile.mktemp(dir='.', prefix=tempprefix)
176 name = tempfile.mktemp(dir='.', prefix=tempprefix)
192 try:
177 try:
193 os.symlink(".", name)
178 os.symlink(".", name)
194 os.unlink(name)
179 os.unlink(name)
195 return True
180 return True
196 except (OSError, AttributeError):
181 except (OSError, AttributeError):
197 return False
182 return False
198
183
199 def has_hardlink():
184 def has_hardlink():
200 from mercurial import util
185 from mercurial import util
201 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
186 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
202 os.close(fh)
187 os.close(fh)
203 name = tempfile.mktemp(dir='.', prefix=tempprefix)
188 name = tempfile.mktemp(dir='.', prefix=tempprefix)
204 try:
189 try:
205 try:
190 try:
206 util.oslink(fn, name)
191 util.oslink(fn, name)
207 os.unlink(name)
192 os.unlink(name)
208 return True
193 return True
209 except OSError:
194 except OSError:
210 return False
195 return False
211 finally:
196 finally:
212 os.unlink(fn)
197 os.unlink(fn)
213
198
214 def has_tla():
199 def has_tla():
215 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
200 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
216
201
217 def has_gpg():
202 def has_gpg():
218 return matchoutput('gpg --version 2>&1', r'GnuPG')
203 return matchoutput('gpg --version 2>&1', r'GnuPG')
219
204
220 def has_unix_permissions():
205 def has_unix_permissions():
221 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
206 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
222 try:
207 try:
223 fname = os.path.join(d, 'foo')
208 fname = os.path.join(d, 'foo')
224 for umask in (077, 007, 022):
209 for umask in (077, 007, 022):
225 os.umask(umask)
210 os.umask(umask)
226 f = open(fname, 'w')
211 f = open(fname, 'w')
227 f.close()
212 f.close()
228 mode = os.stat(fname).st_mode
213 mode = os.stat(fname).st_mode
229 os.unlink(fname)
214 os.unlink(fname)
230 if mode & 0777 != ~umask & 0666:
215 if mode & 0777 != ~umask & 0666:
231 return False
216 return False
232 return True
217 return True
233 finally:
218 finally:
234 os.rmdir(d)
219 os.rmdir(d)
235
220
236 def has_root():
221 def has_root():
237 return getattr(os, 'geteuid', None) and os.geteuid() == 0
222 return getattr(os, 'geteuid', None) and os.geteuid() == 0
238
223
239 def has_pyflakes():
224 def has_pyflakes():
240 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
225 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
241 r"<stdin>:1: 're' imported but unused",
226 r"<stdin>:1: 're' imported but unused",
242 True)
227 True)
243
228
244 def has_pygments():
229 def has_pygments():
245 try:
230 try:
246 import pygments
231 import pygments
247 return True
232 return True
248 except ImportError:
233 except ImportError:
249 return False
234 return False
250
235
251 def has_python243():
236 def has_python243():
252 return sys.version_info >= (2, 4, 3)
237 return sys.version_info >= (2, 4, 3)
253
238
254 def has_outer_repo():
239 def has_outer_repo():
255 # failing for other reasons than 'no repo' imply that there is a repo
240 # failing for other reasons than 'no repo' imply that there is a repo
256 return not matchoutput('hg root 2>&1',
241 return not matchoutput('hg root 2>&1',
257 r'abort: no repository found', True)
242 r'abort: no repository found', True)
258
243
259 def has_ssl():
244 def has_ssl():
260 try:
245 try:
261 import ssl
246 import ssl
262 import OpenSSL
247 import OpenSSL
263 OpenSSL.SSL.Context
248 OpenSSL.SSL.Context
264 return True
249 return True
265 except ImportError:
250 except ImportError:
266 return False
251 return False
267
252
268 def has_windows():
253 def has_windows():
269 return os.name == 'nt'
254 return os.name == 'nt'
270
255
271 def has_system_sh():
256 def has_system_sh():
272 return os.name != 'nt'
257 return os.name != 'nt'
273
258
274 def has_serve():
259 def has_serve():
275 return os.name != 'nt' # gross approximation
260 return os.name != 'nt' # gross approximation
276
261
277 def has_tic():
262 def has_tic():
278 try:
263 try:
279 import curses
264 import curses
280 curses.COLOR_BLUE
265 curses.COLOR_BLUE
281 return matchoutput('test -x "`which tic`"', '')
266 return matchoutput('test -x "`which tic`"', '')
282 except ImportError:
267 except ImportError:
283 return False
268 return False
284
269
285 def has_msys():
270 def has_msys():
286 return os.getenv('MSYSTEM')
271 return os.getenv('MSYSTEM')
287
272
288 def has_aix():
273 def has_aix():
289 return sys.platform.startswith("aix")
274 return sys.platform.startswith("aix")
290
275
291 def has_absimport():
276 def has_absimport():
292 import __future__
277 import __future__
293 from mercurial import util
278 from mercurial import util
294 return util.safehasattr(__future__, "absolute_import")
279 return util.safehasattr(__future__, "absolute_import")
295
280
296 def has_py3k():
281 def has_py3k():
297 return 3 == sys.version_info[0]
282 return 3 == sys.version_info[0]
298
283
299 checks = {
284 checks = {
300 "true": (lambda: True, "yak shaving"),
285 "true": (lambda: True, "yak shaving"),
301 "false": (lambda: False, "nail clipper"),
286 "false": (lambda: False, "nail clipper"),
302 "baz": (has_baz, "GNU Arch baz client"),
287 "baz": (has_baz, "GNU Arch baz client"),
303 "bzr": (has_bzr, "Canonical's Bazaar client"),
288 "bzr": (has_bzr, "Canonical's Bazaar client"),
304 "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
289 "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"),
305 "cacheable": (has_cacheable_fs, "cacheable filesystem"),
290 "cacheable": (has_cacheable_fs, "cacheable filesystem"),
306 "cvs": (has_cvs, "cvs client/server"),
291 "cvs": (has_cvs, "cvs client/server"),
307 "cvs112": (has_cvs112, "cvs client/server >= 1.12"),
292 "cvs112": (has_cvs112, "cvs client/server >= 1.12"),
308 "darcs": (has_darcs, "darcs client"),
293 "darcs": (has_darcs, "darcs client"),
309 "docutils": (has_docutils, "Docutils text processing library"),
294 "docutils": (has_docutils, "Docutils text processing library"),
310 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
295 "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"),
311 "execbit": (has_executablebit, "executable bit"),
296 "execbit": (has_executablebit, "executable bit"),
312 "fifo": (has_fifo, "named pipes"),
297 "fifo": (has_fifo, "named pipes"),
313 "gettext": (has_gettext, "GNU Gettext (msgfmt)"),
298 "gettext": (has_gettext, "GNU Gettext (msgfmt)"),
314 "git": (has_git, "git command line client"),
299 "git": (has_git, "git command line client"),
315 "gpg": (has_gpg, "gpg client"),
300 "gpg": (has_gpg, "gpg client"),
316 "hardlink": (has_hardlink, "hardlinks"),
301 "hardlink": (has_hardlink, "hardlinks"),
317 "icasefs": (has_icasefs, "case insensitive file system"),
302 "icasefs": (has_icasefs, "case insensitive file system"),
318 "inotify": (has_inotify, "inotify extension support"),
319 "killdaemons": (has_killdaemons, 'killdaemons.py support'),
303 "killdaemons": (has_killdaemons, 'killdaemons.py support'),
320 "lsprof": (has_lsprof, "python lsprof module"),
304 "lsprof": (has_lsprof, "python lsprof module"),
321 "mtn": (has_mtn, "monotone client (>= 1.0)"),
305 "mtn": (has_mtn, "monotone client (>= 1.0)"),
322 "outer-repo": (has_outer_repo, "outer repo"),
306 "outer-repo": (has_outer_repo, "outer repo"),
323 "p4": (has_p4, "Perforce server and client"),
307 "p4": (has_p4, "Perforce server and client"),
324 "pyflakes": (has_pyflakes, "Pyflakes python linter"),
308 "pyflakes": (has_pyflakes, "Pyflakes python linter"),
325 "pygments": (has_pygments, "Pygments source highlighting library"),
309 "pygments": (has_pygments, "Pygments source highlighting library"),
326 "python243": (has_python243, "python >= 2.4.3"),
310 "python243": (has_python243, "python >= 2.4.3"),
327 "root": (has_root, "root permissions"),
311 "root": (has_root, "root permissions"),
328 "serve": (has_serve, "platform and python can manage 'hg serve -d'"),
312 "serve": (has_serve, "platform and python can manage 'hg serve -d'"),
329 "ssl": (has_ssl, "python >= 2.6 ssl module and python OpenSSL"),
313 "ssl": (has_ssl, "python >= 2.6 ssl module and python OpenSSL"),
330 "svn": (has_svn, "subversion client and admin tools"),
314 "svn": (has_svn, "subversion client and admin tools"),
331 "svn13": (has_svn13, "subversion client and admin tools >= 1.3"),
315 "svn13": (has_svn13, "subversion client and admin tools >= 1.3"),
332 "svn15": (has_svn15, "subversion client and admin tools >= 1.5"),
316 "svn15": (has_svn15, "subversion client and admin tools >= 1.5"),
333 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
317 "svn-bindings": (has_svn_bindings, "subversion python bindings"),
334 "symlink": (has_symlink, "symbolic links"),
318 "symlink": (has_symlink, "symbolic links"),
335 "system-sh": (has_system_sh, "system() uses sh"),
319 "system-sh": (has_system_sh, "system() uses sh"),
336 "tic": (has_tic, "terminfo compiler and curses module"),
320 "tic": (has_tic, "terminfo compiler and curses module"),
337 "tla": (has_tla, "GNU Arch tla client"),
321 "tla": (has_tla, "GNU Arch tla client"),
338 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
322 "unix-permissions": (has_unix_permissions, "unix-style permissions"),
339 "windows": (has_windows, "Windows"),
323 "windows": (has_windows, "Windows"),
340 "msys": (has_msys, "Windows with MSYS"),
324 "msys": (has_msys, "Windows with MSYS"),
341 "aix": (has_aix, "AIX"),
325 "aix": (has_aix, "AIX"),
342 "absimport": (has_absimport, "absolute_import in __future__"),
326 "absimport": (has_absimport, "absolute_import in __future__"),
343 "py3k": (has_py3k, "running with Python 3.x"),
327 "py3k": (has_py3k, "running with Python 3.x"),
344 }
328 }
@@ -1,1302 +1,1294 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 # Modifying this script is tricky because it has many modes:
10 # Modifying this script is tricky because it has many modes:
11 # - serial (default) vs parallel (-jN, N > 1)
11 # - serial (default) vs parallel (-jN, N > 1)
12 # - no coverage (default) vs coverage (-c, -C, -s)
12 # - no coverage (default) vs coverage (-c, -C, -s)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
14 # - tests are a mix of shell scripts and Python scripts
14 # - tests are a mix of shell scripts and Python scripts
15 #
15 #
16 # If you change this script, it is recommended that you ensure you
16 # If you change this script, it is recommended that you ensure you
17 # haven't broken it by running it in various modes with a representative
17 # haven't broken it by running it in various modes with a representative
18 # sample of test scripts. For example:
18 # sample of test scripts. For example:
19 #
19 #
20 # 1) serial, no coverage, temp install:
20 # 1) serial, no coverage, temp install:
21 # ./run-tests.py test-s*
21 # ./run-tests.py test-s*
22 # 2) serial, no coverage, local hg:
22 # 2) serial, no coverage, local hg:
23 # ./run-tests.py --local test-s*
23 # ./run-tests.py --local test-s*
24 # 3) serial, coverage, temp install:
24 # 3) serial, coverage, temp install:
25 # ./run-tests.py -c test-s*
25 # ./run-tests.py -c test-s*
26 # 4) serial, coverage, local hg:
26 # 4) serial, coverage, local hg:
27 # ./run-tests.py -c --local test-s* # unsupported
27 # ./run-tests.py -c --local test-s* # unsupported
28 # 5) parallel, no coverage, temp install:
28 # 5) parallel, no coverage, temp install:
29 # ./run-tests.py -j2 test-s*
29 # ./run-tests.py -j2 test-s*
30 # 6) parallel, no coverage, local hg:
30 # 6) parallel, no coverage, local hg:
31 # ./run-tests.py -j2 --local test-s*
31 # ./run-tests.py -j2 --local test-s*
32 # 7) parallel, coverage, temp install:
32 # 7) parallel, coverage, temp install:
33 # ./run-tests.py -j2 -c test-s* # currently broken
33 # ./run-tests.py -j2 -c test-s* # currently broken
34 # 8) parallel, coverage, local install:
34 # 8) parallel, coverage, local install:
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
36 # 9) parallel, custom tmp dir:
36 # 9) parallel, custom tmp dir:
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
38 #
38 #
39 # (You could use any subset of the tests: test-s* happens to match
39 # (You could use any subset of the tests: test-s* happens to match
40 # enough that it's worth doing parallel runs, few enough that it
40 # enough that it's worth doing parallel runs, few enough that it
41 # completes fairly quickly, includes both shell and Python scripts, and
41 # completes fairly quickly, includes both shell and Python scripts, and
42 # includes some scripts that run daemon processes.)
42 # includes some scripts that run daemon processes.)
43
43
44 from distutils import version
44 from distutils import version
45 import difflib
45 import difflib
46 import errno
46 import errno
47 import optparse
47 import optparse
48 import os
48 import os
49 import shutil
49 import shutil
50 import subprocess
50 import subprocess
51 import signal
51 import signal
52 import sys
52 import sys
53 import tempfile
53 import tempfile
54 import time
54 import time
55 import random
55 import random
56 import re
56 import re
57 import threading
57 import threading
58 import killdaemons as killmod
58 import killdaemons as killmod
59 import Queue as queue
59 import Queue as queue
60
60
61 processlock = threading.Lock()
61 processlock = threading.Lock()
62
62
63 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
63 # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
64 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing
64 # http://bugs.python.org/issue1731717 for details. We shouldn't be producing
65 # zombies but it's pretty harmless even if we do.
65 # zombies but it's pretty harmless even if we do.
66 if sys.version_info < (2, 5):
66 if sys.version_info < (2, 5):
67 subprocess._cleanup = lambda: None
67 subprocess._cleanup = lambda: None
68
68
69 closefds = os.name == 'posix'
69 closefds = os.name == 'posix'
70 def Popen4(cmd, wd, timeout, env=None):
70 def Popen4(cmd, wd, timeout, env=None):
71 processlock.acquire()
71 processlock.acquire()
72 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
72 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
73 close_fds=closefds,
73 close_fds=closefds,
74 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
74 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
75 stderr=subprocess.STDOUT)
75 stderr=subprocess.STDOUT)
76 processlock.release()
76 processlock.release()
77
77
78 p.fromchild = p.stdout
78 p.fromchild = p.stdout
79 p.tochild = p.stdin
79 p.tochild = p.stdin
80 p.childerr = p.stderr
80 p.childerr = p.stderr
81
81
82 p.timeout = False
82 p.timeout = False
83 if timeout:
83 if timeout:
84 def t():
84 def t():
85 start = time.time()
85 start = time.time()
86 while time.time() - start < timeout and p.returncode is None:
86 while time.time() - start < timeout and p.returncode is None:
87 time.sleep(.1)
87 time.sleep(.1)
88 p.timeout = True
88 p.timeout = True
89 if p.returncode is None:
89 if p.returncode is None:
90 terminate(p)
90 terminate(p)
91 threading.Thread(target=t).start()
91 threading.Thread(target=t).start()
92
92
93 return p
93 return p
94
94
95 # reserved exit code to skip test (used by hghave)
95 # reserved exit code to skip test (used by hghave)
96 SKIPPED_STATUS = 80
96 SKIPPED_STATUS = 80
97 SKIPPED_PREFIX = 'skipped: '
97 SKIPPED_PREFIX = 'skipped: '
98 FAILED_PREFIX = 'hghave check failed: '
98 FAILED_PREFIX = 'hghave check failed: '
99 PYTHON = sys.executable.replace('\\', '/')
99 PYTHON = sys.executable.replace('\\', '/')
100 IMPL_PATH = 'PYTHONPATH'
100 IMPL_PATH = 'PYTHONPATH'
101 if 'java' in sys.platform:
101 if 'java' in sys.platform:
102 IMPL_PATH = 'JYTHONPATH'
102 IMPL_PATH = 'JYTHONPATH'
103
103
104 requiredtools = [os.path.basename(sys.executable), "diff", "grep", "unzip",
104 requiredtools = [os.path.basename(sys.executable), "diff", "grep", "unzip",
105 "gunzip", "bunzip2", "sed"]
105 "gunzip", "bunzip2", "sed"]
106 createdfiles = []
106 createdfiles = []
107
107
108 defaults = {
108 defaults = {
109 'jobs': ('HGTEST_JOBS', 1),
109 'jobs': ('HGTEST_JOBS', 1),
110 'timeout': ('HGTEST_TIMEOUT', 180),
110 'timeout': ('HGTEST_TIMEOUT', 180),
111 'port': ('HGTEST_PORT', 20059),
111 'port': ('HGTEST_PORT', 20059),
112 'shell': ('HGTEST_SHELL', 'sh'),
112 'shell': ('HGTEST_SHELL', 'sh'),
113 }
113 }
114
114
115 def parselistfiles(files, listtype, warn=True):
115 def parselistfiles(files, listtype, warn=True):
116 entries = dict()
116 entries = dict()
117 for filename in files:
117 for filename in files:
118 try:
118 try:
119 path = os.path.expanduser(os.path.expandvars(filename))
119 path = os.path.expanduser(os.path.expandvars(filename))
120 f = open(path, "r")
120 f = open(path, "r")
121 except IOError, err:
121 except IOError, err:
122 if err.errno != errno.ENOENT:
122 if err.errno != errno.ENOENT:
123 raise
123 raise
124 if warn:
124 if warn:
125 print "warning: no such %s file: %s" % (listtype, filename)
125 print "warning: no such %s file: %s" % (listtype, filename)
126 continue
126 continue
127
127
128 for line in f.readlines():
128 for line in f.readlines():
129 line = line.split('#', 1)[0].strip()
129 line = line.split('#', 1)[0].strip()
130 if line:
130 if line:
131 entries[line] = filename
131 entries[line] = filename
132
132
133 f.close()
133 f.close()
134 return entries
134 return entries
135
135
136 def parseargs():
136 def parseargs():
137 parser = optparse.OptionParser("%prog [options] [tests]")
137 parser = optparse.OptionParser("%prog [options] [tests]")
138
138
139 # keep these sorted
139 # keep these sorted
140 parser.add_option("--blacklist", action="append",
140 parser.add_option("--blacklist", action="append",
141 help="skip tests listed in the specified blacklist file")
141 help="skip tests listed in the specified blacklist file")
142 parser.add_option("--whitelist", action="append",
142 parser.add_option("--whitelist", action="append",
143 help="always run tests listed in the specified whitelist file")
143 help="always run tests listed in the specified whitelist file")
144 parser.add_option("-C", "--annotate", action="store_true",
144 parser.add_option("-C", "--annotate", action="store_true",
145 help="output files annotated with coverage")
145 help="output files annotated with coverage")
146 parser.add_option("-c", "--cover", action="store_true",
146 parser.add_option("-c", "--cover", action="store_true",
147 help="print a test coverage report")
147 help="print a test coverage report")
148 parser.add_option("-d", "--debug", action="store_true",
148 parser.add_option("-d", "--debug", action="store_true",
149 help="debug mode: write output of test scripts to console"
149 help="debug mode: write output of test scripts to console"
150 " rather than capturing and diff'ing it (disables timeout)")
150 " rather than capturing and diff'ing it (disables timeout)")
151 parser.add_option("-f", "--first", action="store_true",
151 parser.add_option("-f", "--first", action="store_true",
152 help="exit on the first test failure")
152 help="exit on the first test failure")
153 parser.add_option("-H", "--htmlcov", action="store_true",
153 parser.add_option("-H", "--htmlcov", action="store_true",
154 help="create an HTML report of the coverage of the files")
154 help="create an HTML report of the coverage of the files")
155 parser.add_option("--inotify", action="store_true",
156 help="enable inotify extension when running tests")
157 parser.add_option("-i", "--interactive", action="store_true",
155 parser.add_option("-i", "--interactive", action="store_true",
158 help="prompt to accept changed output")
156 help="prompt to accept changed output")
159 parser.add_option("-j", "--jobs", type="int",
157 parser.add_option("-j", "--jobs", type="int",
160 help="number of jobs to run in parallel"
158 help="number of jobs to run in parallel"
161 " (default: $%s or %d)" % defaults['jobs'])
159 " (default: $%s or %d)" % defaults['jobs'])
162 parser.add_option("--keep-tmpdir", action="store_true",
160 parser.add_option("--keep-tmpdir", action="store_true",
163 help="keep temporary directory after running tests")
161 help="keep temporary directory after running tests")
164 parser.add_option("-k", "--keywords",
162 parser.add_option("-k", "--keywords",
165 help="run tests matching keywords")
163 help="run tests matching keywords")
166 parser.add_option("-l", "--local", action="store_true",
164 parser.add_option("-l", "--local", action="store_true",
167 help="shortcut for --with-hg=<testdir>/../hg")
165 help="shortcut for --with-hg=<testdir>/../hg")
168 parser.add_option("--loop", action="store_true",
166 parser.add_option("--loop", action="store_true",
169 help="loop tests repeatedly")
167 help="loop tests repeatedly")
170 parser.add_option("-n", "--nodiff", action="store_true",
168 parser.add_option("-n", "--nodiff", action="store_true",
171 help="skip showing test changes")
169 help="skip showing test changes")
172 parser.add_option("-p", "--port", type="int",
170 parser.add_option("-p", "--port", type="int",
173 help="port on which servers should listen"
171 help="port on which servers should listen"
174 " (default: $%s or %d)" % defaults['port'])
172 " (default: $%s or %d)" % defaults['port'])
175 parser.add_option("--compiler", type="string",
173 parser.add_option("--compiler", type="string",
176 help="compiler to build with")
174 help="compiler to build with")
177 parser.add_option("--pure", action="store_true",
175 parser.add_option("--pure", action="store_true",
178 help="use pure Python code instead of C extensions")
176 help="use pure Python code instead of C extensions")
179 parser.add_option("-R", "--restart", action="store_true",
177 parser.add_option("-R", "--restart", action="store_true",
180 help="restart at last error")
178 help="restart at last error")
181 parser.add_option("-r", "--retest", action="store_true",
179 parser.add_option("-r", "--retest", action="store_true",
182 help="retest failed tests")
180 help="retest failed tests")
183 parser.add_option("-S", "--noskips", action="store_true",
181 parser.add_option("-S", "--noskips", action="store_true",
184 help="don't report skip tests verbosely")
182 help="don't report skip tests verbosely")
185 parser.add_option("--shell", type="string",
183 parser.add_option("--shell", type="string",
186 help="shell to use (default: $%s or %s)" % defaults['shell'])
184 help="shell to use (default: $%s or %s)" % defaults['shell'])
187 parser.add_option("-t", "--timeout", type="int",
185 parser.add_option("-t", "--timeout", type="int",
188 help="kill errant tests after TIMEOUT seconds"
186 help="kill errant tests after TIMEOUT seconds"
189 " (default: $%s or %d)" % defaults['timeout'])
187 " (default: $%s or %d)" % defaults['timeout'])
190 parser.add_option("--time", action="store_true",
188 parser.add_option("--time", action="store_true",
191 help="time how long each test takes")
189 help="time how long each test takes")
192 parser.add_option("--tmpdir", type="string",
190 parser.add_option("--tmpdir", type="string",
193 help="run tests in the given temporary directory"
191 help="run tests in the given temporary directory"
194 " (implies --keep-tmpdir)")
192 " (implies --keep-tmpdir)")
195 parser.add_option("-v", "--verbose", action="store_true",
193 parser.add_option("-v", "--verbose", action="store_true",
196 help="output verbose messages")
194 help="output verbose messages")
197 parser.add_option("--view", type="string",
195 parser.add_option("--view", type="string",
198 help="external diff viewer")
196 help="external diff viewer")
199 parser.add_option("--with-hg", type="string",
197 parser.add_option("--with-hg", type="string",
200 metavar="HG",
198 metavar="HG",
201 help="test using specified hg script rather than a "
199 help="test using specified hg script rather than a "
202 "temporary installation")
200 "temporary installation")
203 parser.add_option("-3", "--py3k-warnings", action="store_true",
201 parser.add_option("-3", "--py3k-warnings", action="store_true",
204 help="enable Py3k warnings on Python 2.6+")
202 help="enable Py3k warnings on Python 2.6+")
205 parser.add_option('--extra-config-opt', action="append",
203 parser.add_option('--extra-config-opt', action="append",
206 help='set the given config opt in the test hgrc')
204 help='set the given config opt in the test hgrc')
207 parser.add_option('--random', action="store_true",
205 parser.add_option('--random', action="store_true",
208 help='run tests in random order')
206 help='run tests in random order')
209
207
210 for option, (envvar, default) in defaults.items():
208 for option, (envvar, default) in defaults.items():
211 defaults[option] = type(default)(os.environ.get(envvar, default))
209 defaults[option] = type(default)(os.environ.get(envvar, default))
212 parser.set_defaults(**defaults)
210 parser.set_defaults(**defaults)
213 (options, args) = parser.parse_args()
211 (options, args) = parser.parse_args()
214
212
215 # jython is always pure
213 # jython is always pure
216 if 'java' in sys.platform or '__pypy__' in sys.modules:
214 if 'java' in sys.platform or '__pypy__' in sys.modules:
217 options.pure = True
215 options.pure = True
218
216
219 if options.with_hg:
217 if options.with_hg:
220 options.with_hg = os.path.expanduser(options.with_hg)
218 options.with_hg = os.path.expanduser(options.with_hg)
221 if not (os.path.isfile(options.with_hg) and
219 if not (os.path.isfile(options.with_hg) and
222 os.access(options.with_hg, os.X_OK)):
220 os.access(options.with_hg, os.X_OK)):
223 parser.error('--with-hg must specify an executable hg script')
221 parser.error('--with-hg must specify an executable hg script')
224 if not os.path.basename(options.with_hg) == 'hg':
222 if not os.path.basename(options.with_hg) == 'hg':
225 sys.stderr.write('warning: --with-hg should specify an hg script\n')
223 sys.stderr.write('warning: --with-hg should specify an hg script\n')
226 if options.local:
224 if options.local:
227 testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
225 testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
228 hgbin = os.path.join(os.path.dirname(testdir), 'hg')
226 hgbin = os.path.join(os.path.dirname(testdir), 'hg')
229 if os.name != 'nt' and not os.access(hgbin, os.X_OK):
227 if os.name != 'nt' and not os.access(hgbin, os.X_OK):
230 parser.error('--local specified, but %r not found or not executable'
228 parser.error('--local specified, but %r not found or not executable'
231 % hgbin)
229 % hgbin)
232 options.with_hg = hgbin
230 options.with_hg = hgbin
233
231
234 options.anycoverage = options.cover or options.annotate or options.htmlcov
232 options.anycoverage = options.cover or options.annotate or options.htmlcov
235 if options.anycoverage:
233 if options.anycoverage:
236 try:
234 try:
237 import coverage
235 import coverage
238 covver = version.StrictVersion(coverage.__version__).version
236 covver = version.StrictVersion(coverage.__version__).version
239 if covver < (3, 3):
237 if covver < (3, 3):
240 parser.error('coverage options require coverage 3.3 or later')
238 parser.error('coverage options require coverage 3.3 or later')
241 except ImportError:
239 except ImportError:
242 parser.error('coverage options now require the coverage package')
240 parser.error('coverage options now require the coverage package')
243
241
244 if options.anycoverage and options.local:
242 if options.anycoverage and options.local:
245 # this needs some path mangling somewhere, I guess
243 # this needs some path mangling somewhere, I guess
246 parser.error("sorry, coverage options do not work when --local "
244 parser.error("sorry, coverage options do not work when --local "
247 "is specified")
245 "is specified")
248
246
249 global verbose
247 global verbose
250 if options.verbose:
248 if options.verbose:
251 verbose = ''
249 verbose = ''
252
250
253 if options.tmpdir:
251 if options.tmpdir:
254 options.tmpdir = os.path.expanduser(options.tmpdir)
252 options.tmpdir = os.path.expanduser(options.tmpdir)
255
253
256 if options.jobs < 1:
254 if options.jobs < 1:
257 parser.error('--jobs must be positive')
255 parser.error('--jobs must be positive')
258 if options.interactive and options.debug:
256 if options.interactive and options.debug:
259 parser.error("-i/--interactive and -d/--debug are incompatible")
257 parser.error("-i/--interactive and -d/--debug are incompatible")
260 if options.debug:
258 if options.debug:
261 if options.timeout != defaults['timeout']:
259 if options.timeout != defaults['timeout']:
262 sys.stderr.write(
260 sys.stderr.write(
263 'warning: --timeout option ignored with --debug\n')
261 'warning: --timeout option ignored with --debug\n')
264 options.timeout = 0
262 options.timeout = 0
265 if options.py3k_warnings:
263 if options.py3k_warnings:
266 if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
264 if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
267 parser.error('--py3k-warnings can only be used on Python 2.6+')
265 parser.error('--py3k-warnings can only be used on Python 2.6+')
268 if options.blacklist:
266 if options.blacklist:
269 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
267 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
270 if options.whitelist:
268 if options.whitelist:
271 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
269 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
272 else:
270 else:
273 options.whitelisted = {}
271 options.whitelisted = {}
274
272
275 return (options, args)
273 return (options, args)
276
274
277 def rename(src, dst):
275 def rename(src, dst):
278 """Like os.rename(), trade atomicity and opened files friendliness
276 """Like os.rename(), trade atomicity and opened files friendliness
279 for existing destination support.
277 for existing destination support.
280 """
278 """
281 shutil.copy(src, dst)
279 shutil.copy(src, dst)
282 os.remove(src)
280 os.remove(src)
283
281
284 def parsehghaveoutput(lines):
282 def parsehghaveoutput(lines):
285 '''Parse hghave log lines.
283 '''Parse hghave log lines.
286 Return tuple of lists (missing, failed):
284 Return tuple of lists (missing, failed):
287 * the missing/unknown features
285 * the missing/unknown features
288 * the features for which existence check failed'''
286 * the features for which existence check failed'''
289 missing = []
287 missing = []
290 failed = []
288 failed = []
291 for line in lines:
289 for line in lines:
292 if line.startswith(SKIPPED_PREFIX):
290 if line.startswith(SKIPPED_PREFIX):
293 line = line.splitlines()[0]
291 line = line.splitlines()[0]
294 missing.append(line[len(SKIPPED_PREFIX):])
292 missing.append(line[len(SKIPPED_PREFIX):])
295 elif line.startswith(FAILED_PREFIX):
293 elif line.startswith(FAILED_PREFIX):
296 line = line.splitlines()[0]
294 line = line.splitlines()[0]
297 failed.append(line[len(FAILED_PREFIX):])
295 failed.append(line[len(FAILED_PREFIX):])
298
296
299 return missing, failed
297 return missing, failed
300
298
301 def showdiff(expected, output, ref, err):
299 def showdiff(expected, output, ref, err):
302 print
300 print
303 for line in difflib.unified_diff(expected, output, ref, err):
301 for line in difflib.unified_diff(expected, output, ref, err):
304 sys.stdout.write(line)
302 sys.stdout.write(line)
305
303
306 verbose = False
304 verbose = False
307 def vlog(*msg):
305 def vlog(*msg):
308 if verbose is not False:
306 if verbose is not False:
309 iolock.acquire()
307 iolock.acquire()
310 if verbose:
308 if verbose:
311 print verbose,
309 print verbose,
312 for m in msg:
310 for m in msg:
313 print m,
311 print m,
314 print
312 print
315 sys.stdout.flush()
313 sys.stdout.flush()
316 iolock.release()
314 iolock.release()
317
315
318 def log(*msg):
316 def log(*msg):
319 iolock.acquire()
317 iolock.acquire()
320 if verbose:
318 if verbose:
321 print verbose,
319 print verbose,
322 for m in msg:
320 for m in msg:
323 print m,
321 print m,
324 print
322 print
325 sys.stdout.flush()
323 sys.stdout.flush()
326 iolock.release()
324 iolock.release()
327
325
328 def findprogram(program):
326 def findprogram(program):
329 """Search PATH for a executable program"""
327 """Search PATH for a executable program"""
330 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
328 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
331 name = os.path.join(p, program)
329 name = os.path.join(p, program)
332 if os.name == 'nt' or os.access(name, os.X_OK):
330 if os.name == 'nt' or os.access(name, os.X_OK):
333 return name
331 return name
334 return None
332 return None
335
333
336 def createhgrc(path, options):
334 def createhgrc(path, options):
337 # create a fresh hgrc
335 # create a fresh hgrc
338 hgrc = open(path, 'w')
336 hgrc = open(path, 'w')
339 hgrc.write('[ui]\n')
337 hgrc.write('[ui]\n')
340 hgrc.write('slash = True\n')
338 hgrc.write('slash = True\n')
341 hgrc.write('interactive = False\n')
339 hgrc.write('interactive = False\n')
342 hgrc.write('[defaults]\n')
340 hgrc.write('[defaults]\n')
343 hgrc.write('backout = -d "0 0"\n')
341 hgrc.write('backout = -d "0 0"\n')
344 hgrc.write('commit = -d "0 0"\n')
342 hgrc.write('commit = -d "0 0"\n')
345 hgrc.write('shelve = --date "0 0"\n')
343 hgrc.write('shelve = --date "0 0"\n')
346 hgrc.write('tag = -d "0 0"\n')
344 hgrc.write('tag = -d "0 0"\n')
347 if options.inotify:
348 hgrc.write('[extensions]\n')
349 hgrc.write('inotify=\n')
350 hgrc.write('[inotify]\n')
351 hgrc.write('pidfile=daemon.pids')
352 hgrc.write('appendpid=True\n')
353 if options.extra_config_opt:
345 if options.extra_config_opt:
354 for opt in options.extra_config_opt:
346 for opt in options.extra_config_opt:
355 section, key = opt.split('.', 1)
347 section, key = opt.split('.', 1)
356 assert '=' in key, ('extra config opt %s must '
348 assert '=' in key, ('extra config opt %s must '
357 'have an = for assignment' % opt)
349 'have an = for assignment' % opt)
358 hgrc.write('[%s]\n%s\n' % (section, key))
350 hgrc.write('[%s]\n%s\n' % (section, key))
359 hgrc.close()
351 hgrc.close()
360
352
361 def createenv(options, testtmp, threadtmp, port):
353 def createenv(options, testtmp, threadtmp, port):
362 env = os.environ.copy()
354 env = os.environ.copy()
363 env['TESTTMP'] = testtmp
355 env['TESTTMP'] = testtmp
364 env['HOME'] = testtmp
356 env['HOME'] = testtmp
365 env["HGPORT"] = str(port)
357 env["HGPORT"] = str(port)
366 env["HGPORT1"] = str(port + 1)
358 env["HGPORT1"] = str(port + 1)
367 env["HGPORT2"] = str(port + 2)
359 env["HGPORT2"] = str(port + 2)
368 env["HGRCPATH"] = os.path.join(threadtmp, '.hgrc')
360 env["HGRCPATH"] = os.path.join(threadtmp, '.hgrc')
369 env["DAEMON_PIDS"] = os.path.join(threadtmp, 'daemon.pids')
361 env["DAEMON_PIDS"] = os.path.join(threadtmp, 'daemon.pids')
370 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
362 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
371 env["HGMERGE"] = "internal:merge"
363 env["HGMERGE"] = "internal:merge"
372 env["HGUSER"] = "test"
364 env["HGUSER"] = "test"
373 env["HGENCODING"] = "ascii"
365 env["HGENCODING"] = "ascii"
374 env["HGENCODINGMODE"] = "strict"
366 env["HGENCODINGMODE"] = "strict"
375
367
376 # Reset some environment variables to well-known values so that
368 # Reset some environment variables to well-known values so that
377 # the tests produce repeatable output.
369 # the tests produce repeatable output.
378 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
370 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
379 env['TZ'] = 'GMT'
371 env['TZ'] = 'GMT'
380 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
372 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
381 env['COLUMNS'] = '80'
373 env['COLUMNS'] = '80'
382 env['TERM'] = 'xterm'
374 env['TERM'] = 'xterm'
383
375
384 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
376 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
385 'NO_PROXY').split():
377 'NO_PROXY').split():
386 if k in env:
378 if k in env:
387 del env[k]
379 del env[k]
388
380
389 # unset env related to hooks
381 # unset env related to hooks
390 for k in env.keys():
382 for k in env.keys():
391 if k.startswith('HG_'):
383 if k.startswith('HG_'):
392 del env[k]
384 del env[k]
393
385
394 return env
386 return env
395
387
396 def checktools():
388 def checktools():
397 # Before we go any further, check for pre-requisite tools
389 # Before we go any further, check for pre-requisite tools
398 # stuff from coreutils (cat, rm, etc) are not tested
390 # stuff from coreutils (cat, rm, etc) are not tested
399 for p in requiredtools:
391 for p in requiredtools:
400 if os.name == 'nt' and not p.endswith('.exe'):
392 if os.name == 'nt' and not p.endswith('.exe'):
401 p += '.exe'
393 p += '.exe'
402 found = findprogram(p)
394 found = findprogram(p)
403 if found:
395 if found:
404 vlog("# Found prerequisite", p, "at", found)
396 vlog("# Found prerequisite", p, "at", found)
405 else:
397 else:
406 print "WARNING: Did not find prerequisite tool: "+p
398 print "WARNING: Did not find prerequisite tool: "+p
407
399
408 def terminate(proc):
400 def terminate(proc):
409 """Terminate subprocess (with fallback for Python versions < 2.6)"""
401 """Terminate subprocess (with fallback for Python versions < 2.6)"""
410 vlog('# Terminating process %d' % proc.pid)
402 vlog('# Terminating process %d' % proc.pid)
411 try:
403 try:
412 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
404 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
413 except OSError:
405 except OSError:
414 pass
406 pass
415
407
416 def killdaemons(pidfile):
408 def killdaemons(pidfile):
417 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
409 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
418 logfn=vlog)
410 logfn=vlog)
419
411
420 def cleanup(options):
412 def cleanup(options):
421 if not options.keep_tmpdir:
413 if not options.keep_tmpdir:
422 vlog("# Cleaning up HGTMP", HGTMP)
414 vlog("# Cleaning up HGTMP", HGTMP)
423 shutil.rmtree(HGTMP, True)
415 shutil.rmtree(HGTMP, True)
424 for f in createdfiles:
416 for f in createdfiles:
425 try:
417 try:
426 os.remove(f)
418 os.remove(f)
427 except OSError:
419 except OSError:
428 pass
420 pass
429
421
430 def usecorrectpython():
422 def usecorrectpython():
431 # some tests run python interpreter. they must use same
423 # some tests run python interpreter. they must use same
432 # interpreter we use or bad things will happen.
424 # interpreter we use or bad things will happen.
433 pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
425 pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
434 if getattr(os, 'symlink', None):
426 if getattr(os, 'symlink', None):
435 vlog("# Making python executable in test path a symlink to '%s'" %
427 vlog("# Making python executable in test path a symlink to '%s'" %
436 sys.executable)
428 sys.executable)
437 mypython = os.path.join(TMPBINDIR, pyexename)
429 mypython = os.path.join(TMPBINDIR, pyexename)
438 try:
430 try:
439 if os.readlink(mypython) == sys.executable:
431 if os.readlink(mypython) == sys.executable:
440 return
432 return
441 os.unlink(mypython)
433 os.unlink(mypython)
442 except OSError, err:
434 except OSError, err:
443 if err.errno != errno.ENOENT:
435 if err.errno != errno.ENOENT:
444 raise
436 raise
445 if findprogram(pyexename) != sys.executable:
437 if findprogram(pyexename) != sys.executable:
446 try:
438 try:
447 os.symlink(sys.executable, mypython)
439 os.symlink(sys.executable, mypython)
448 createdfiles.append(mypython)
440 createdfiles.append(mypython)
449 except OSError, err:
441 except OSError, err:
450 # child processes may race, which is harmless
442 # child processes may race, which is harmless
451 if err.errno != errno.EEXIST:
443 if err.errno != errno.EEXIST:
452 raise
444 raise
453 else:
445 else:
454 exedir, exename = os.path.split(sys.executable)
446 exedir, exename = os.path.split(sys.executable)
455 vlog("# Modifying search path to find %s as %s in '%s'" %
447 vlog("# Modifying search path to find %s as %s in '%s'" %
456 (exename, pyexename, exedir))
448 (exename, pyexename, exedir))
457 path = os.environ['PATH'].split(os.pathsep)
449 path = os.environ['PATH'].split(os.pathsep)
458 while exedir in path:
450 while exedir in path:
459 path.remove(exedir)
451 path.remove(exedir)
460 os.environ['PATH'] = os.pathsep.join([exedir] + path)
452 os.environ['PATH'] = os.pathsep.join([exedir] + path)
461 if not findprogram(pyexename):
453 if not findprogram(pyexename):
462 print "WARNING: Cannot find %s in search path" % pyexename
454 print "WARNING: Cannot find %s in search path" % pyexename
463
455
464 def installhg(options):
456 def installhg(options):
465 vlog("# Performing temporary installation of HG")
457 vlog("# Performing temporary installation of HG")
466 installerrs = os.path.join("tests", "install.err")
458 installerrs = os.path.join("tests", "install.err")
467 compiler = ''
459 compiler = ''
468 if options.compiler:
460 if options.compiler:
469 compiler = '--compiler ' + options.compiler
461 compiler = '--compiler ' + options.compiler
470 pure = options.pure and "--pure" or ""
462 pure = options.pure and "--pure" or ""
471 py3 = ''
463 py3 = ''
472 if sys.version_info[0] == 3:
464 if sys.version_info[0] == 3:
473 py3 = '--c2to3'
465 py3 = '--c2to3'
474
466
475 # Run installer in hg root
467 # Run installer in hg root
476 script = os.path.realpath(sys.argv[0])
468 script = os.path.realpath(sys.argv[0])
477 hgroot = os.path.dirname(os.path.dirname(script))
469 hgroot = os.path.dirname(os.path.dirname(script))
478 os.chdir(hgroot)
470 os.chdir(hgroot)
479 nohome = '--home=""'
471 nohome = '--home=""'
480 if os.name == 'nt':
472 if os.name == 'nt':
481 # The --home="" trick works only on OS where os.sep == '/'
473 # The --home="" trick works only on OS where os.sep == '/'
482 # because of a distutils convert_path() fast-path. Avoid it at
474 # because of a distutils convert_path() fast-path. Avoid it at
483 # least on Windows for now, deal with .pydistutils.cfg bugs
475 # least on Windows for now, deal with .pydistutils.cfg bugs
484 # when they happen.
476 # when they happen.
485 nohome = ''
477 nohome = ''
486 cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
478 cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
487 ' build %(compiler)s --build-base="%(base)s"'
479 ' build %(compiler)s --build-base="%(base)s"'
488 ' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"'
480 ' install --force --prefix="%(prefix)s" --install-lib="%(libdir)s"'
489 ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
481 ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
490 % dict(exe=sys.executable, py3=py3, pure=pure, compiler=compiler,
482 % dict(exe=sys.executable, py3=py3, pure=pure, compiler=compiler,
491 base=os.path.join(HGTMP, "build"),
483 base=os.path.join(HGTMP, "build"),
492 prefix=INST, libdir=PYTHONDIR, bindir=BINDIR,
484 prefix=INST, libdir=PYTHONDIR, bindir=BINDIR,
493 nohome=nohome, logfile=installerrs))
485 nohome=nohome, logfile=installerrs))
494 vlog("# Running", cmd)
486 vlog("# Running", cmd)
495 if os.system(cmd) == 0:
487 if os.system(cmd) == 0:
496 if not options.verbose:
488 if not options.verbose:
497 os.remove(installerrs)
489 os.remove(installerrs)
498 else:
490 else:
499 f = open(installerrs)
491 f = open(installerrs)
500 for line in f:
492 for line in f:
501 print line,
493 print line,
502 f.close()
494 f.close()
503 sys.exit(1)
495 sys.exit(1)
504 os.chdir(TESTDIR)
496 os.chdir(TESTDIR)
505
497
506 usecorrectpython()
498 usecorrectpython()
507
499
508 if options.py3k_warnings and not options.anycoverage:
500 if options.py3k_warnings and not options.anycoverage:
509 vlog("# Updating hg command to enable Py3k Warnings switch")
501 vlog("# Updating hg command to enable Py3k Warnings switch")
510 f = open(os.path.join(BINDIR, 'hg'), 'r')
502 f = open(os.path.join(BINDIR, 'hg'), 'r')
511 lines = [line.rstrip() for line in f]
503 lines = [line.rstrip() for line in f]
512 lines[0] += ' -3'
504 lines[0] += ' -3'
513 f.close()
505 f.close()
514 f = open(os.path.join(BINDIR, 'hg'), 'w')
506 f = open(os.path.join(BINDIR, 'hg'), 'w')
515 for line in lines:
507 for line in lines:
516 f.write(line + '\n')
508 f.write(line + '\n')
517 f.close()
509 f.close()
518
510
519 hgbat = os.path.join(BINDIR, 'hg.bat')
511 hgbat = os.path.join(BINDIR, 'hg.bat')
520 if os.path.isfile(hgbat):
512 if os.path.isfile(hgbat):
521 # hg.bat expects to be put in bin/scripts while run-tests.py
513 # hg.bat expects to be put in bin/scripts while run-tests.py
522 # installation layout put it in bin/ directly. Fix it
514 # installation layout put it in bin/ directly. Fix it
523 f = open(hgbat, 'rb')
515 f = open(hgbat, 'rb')
524 data = f.read()
516 data = f.read()
525 f.close()
517 f.close()
526 if '"%~dp0..\python" "%~dp0hg" %*' in data:
518 if '"%~dp0..\python" "%~dp0hg" %*' in data:
527 data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
519 data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
528 '"%~dp0python" "%~dp0hg" %*')
520 '"%~dp0python" "%~dp0hg" %*')
529 f = open(hgbat, 'wb')
521 f = open(hgbat, 'wb')
530 f.write(data)
522 f.write(data)
531 f.close()
523 f.close()
532 else:
524 else:
533 print 'WARNING: cannot fix hg.bat reference to python.exe'
525 print 'WARNING: cannot fix hg.bat reference to python.exe'
534
526
535 if options.anycoverage:
527 if options.anycoverage:
536 custom = os.path.join(TESTDIR, 'sitecustomize.py')
528 custom = os.path.join(TESTDIR, 'sitecustomize.py')
537 target = os.path.join(PYTHONDIR, 'sitecustomize.py')
529 target = os.path.join(PYTHONDIR, 'sitecustomize.py')
538 vlog('# Installing coverage trigger to %s' % target)
530 vlog('# Installing coverage trigger to %s' % target)
539 shutil.copyfile(custom, target)
531 shutil.copyfile(custom, target)
540 rc = os.path.join(TESTDIR, '.coveragerc')
532 rc = os.path.join(TESTDIR, '.coveragerc')
541 vlog('# Installing coverage rc to %s' % rc)
533 vlog('# Installing coverage rc to %s' % rc)
542 os.environ['COVERAGE_PROCESS_START'] = rc
534 os.environ['COVERAGE_PROCESS_START'] = rc
543 fn = os.path.join(INST, '..', '.coverage')
535 fn = os.path.join(INST, '..', '.coverage')
544 os.environ['COVERAGE_FILE'] = fn
536 os.environ['COVERAGE_FILE'] = fn
545
537
546 def outputtimes(options):
538 def outputtimes(options):
547 vlog('# Producing time report')
539 vlog('# Producing time report')
548 times.sort(key=lambda t: (t[1], t[0]), reverse=True)
540 times.sort(key=lambda t: (t[1], t[0]), reverse=True)
549 cols = '%7.3f %s'
541 cols = '%7.3f %s'
550 print '\n%-7s %s' % ('Time', 'Test')
542 print '\n%-7s %s' % ('Time', 'Test')
551 for test, timetaken in times:
543 for test, timetaken in times:
552 print cols % (timetaken, test)
544 print cols % (timetaken, test)
553
545
554 def outputcoverage(options):
546 def outputcoverage(options):
555
547
556 vlog('# Producing coverage report')
548 vlog('# Producing coverage report')
557 os.chdir(PYTHONDIR)
549 os.chdir(PYTHONDIR)
558
550
559 def covrun(*args):
551 def covrun(*args):
560 cmd = 'coverage %s' % ' '.join(args)
552 cmd = 'coverage %s' % ' '.join(args)
561 vlog('# Running: %s' % cmd)
553 vlog('# Running: %s' % cmd)
562 os.system(cmd)
554 os.system(cmd)
563
555
564 covrun('-c')
556 covrun('-c')
565 omit = ','.join(os.path.join(x, '*') for x in [BINDIR, TESTDIR])
557 omit = ','.join(os.path.join(x, '*') for x in [BINDIR, TESTDIR])
566 covrun('-i', '-r', '"--omit=%s"' % omit) # report
558 covrun('-i', '-r', '"--omit=%s"' % omit) # report
567 if options.htmlcov:
559 if options.htmlcov:
568 htmldir = os.path.join(TESTDIR, 'htmlcov')
560 htmldir = os.path.join(TESTDIR, 'htmlcov')
569 covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
561 covrun('-i', '-b', '"--directory=%s"' % htmldir, '"--omit=%s"' % omit)
570 if options.annotate:
562 if options.annotate:
571 adir = os.path.join(TESTDIR, 'annotated')
563 adir = os.path.join(TESTDIR, 'annotated')
572 if not os.path.isdir(adir):
564 if not os.path.isdir(adir):
573 os.mkdir(adir)
565 os.mkdir(adir)
574 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
566 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
575
567
576 def pytest(test, wd, options, replacements, env):
568 def pytest(test, wd, options, replacements, env):
577 py3kswitch = options.py3k_warnings and ' -3' or ''
569 py3kswitch = options.py3k_warnings and ' -3' or ''
578 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
570 cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test)
579 vlog("# Running", cmd)
571 vlog("# Running", cmd)
580 if os.name == 'nt':
572 if os.name == 'nt':
581 replacements.append((r'\r\n', '\n'))
573 replacements.append((r'\r\n', '\n'))
582 return run(cmd, wd, options, replacements, env)
574 return run(cmd, wd, options, replacements, env)
583
575
584 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
576 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
585 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
577 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
586 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256))
578 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256))
587 escapemap.update({'\\': '\\\\', '\r': r'\r'})
579 escapemap.update({'\\': '\\\\', '\r': r'\r'})
588 def escapef(m):
580 def escapef(m):
589 return escapemap[m.group(0)]
581 return escapemap[m.group(0)]
590 def stringescape(s):
582 def stringescape(s):
591 return escapesub(escapef, s)
583 return escapesub(escapef, s)
592
584
593 def rematch(el, l):
585 def rematch(el, l):
594 try:
586 try:
595 # use \Z to ensure that the regex matches to the end of the string
587 # use \Z to ensure that the regex matches to the end of the string
596 if os.name == 'nt':
588 if os.name == 'nt':
597 return re.match(el + r'\r?\n\Z', l)
589 return re.match(el + r'\r?\n\Z', l)
598 return re.match(el + r'\n\Z', l)
590 return re.match(el + r'\n\Z', l)
599 except re.error:
591 except re.error:
600 # el is an invalid regex
592 # el is an invalid regex
601 return False
593 return False
602
594
603 def globmatch(el, l):
595 def globmatch(el, l):
604 # The only supported special characters are * and ? plus / which also
596 # The only supported special characters are * and ? plus / which also
605 # matches \ on windows. Escaping of these caracters is supported.
597 # matches \ on windows. Escaping of these caracters is supported.
606 if el + '\n' == l:
598 if el + '\n' == l:
607 if os.altsep:
599 if os.altsep:
608 # matching on "/" is not needed for this line
600 # matching on "/" is not needed for this line
609 return '-glob'
601 return '-glob'
610 return True
602 return True
611 i, n = 0, len(el)
603 i, n = 0, len(el)
612 res = ''
604 res = ''
613 while i < n:
605 while i < n:
614 c = el[i]
606 c = el[i]
615 i += 1
607 i += 1
616 if c == '\\' and el[i] in '*?\\/':
608 if c == '\\' and el[i] in '*?\\/':
617 res += el[i - 1:i + 1]
609 res += el[i - 1:i + 1]
618 i += 1
610 i += 1
619 elif c == '*':
611 elif c == '*':
620 res += '.*'
612 res += '.*'
621 elif c == '?':
613 elif c == '?':
622 res += '.'
614 res += '.'
623 elif c == '/' and os.altsep:
615 elif c == '/' and os.altsep:
624 res += '[/\\\\]'
616 res += '[/\\\\]'
625 else:
617 else:
626 res += re.escape(c)
618 res += re.escape(c)
627 return rematch(res, l)
619 return rematch(res, l)
628
620
629 def linematch(el, l):
621 def linematch(el, l):
630 if el == l: # perfect match (fast)
622 if el == l: # perfect match (fast)
631 return True
623 return True
632 if el:
624 if el:
633 if el.endswith(" (esc)\n"):
625 if el.endswith(" (esc)\n"):
634 el = el[:-7].decode('string-escape') + '\n'
626 el = el[:-7].decode('string-escape') + '\n'
635 if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
627 if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
636 return True
628 return True
637 if el.endswith(" (re)\n"):
629 if el.endswith(" (re)\n"):
638 return rematch(el[:-6], l)
630 return rematch(el[:-6], l)
639 if el.endswith(" (glob)\n"):
631 if el.endswith(" (glob)\n"):
640 return globmatch(el[:-8], l)
632 return globmatch(el[:-8], l)
641 if os.altsep and l.replace('\\', '/') == el:
633 if os.altsep and l.replace('\\', '/') == el:
642 return '+glob'
634 return '+glob'
643 return False
635 return False
644
636
645 def tsttest(test, wd, options, replacements, env):
637 def tsttest(test, wd, options, replacements, env):
646 # We generate a shell script which outputs unique markers to line
638 # We generate a shell script which outputs unique markers to line
647 # up script results with our source. These markers include input
639 # up script results with our source. These markers include input
648 # line number and the last return code
640 # line number and the last return code
649 salt = "SALT" + str(time.time())
641 salt = "SALT" + str(time.time())
650 def addsalt(line, inpython):
642 def addsalt(line, inpython):
651 if inpython:
643 if inpython:
652 script.append('%s %d 0\n' % (salt, line))
644 script.append('%s %d 0\n' % (salt, line))
653 else:
645 else:
654 script.append('echo %s %s $?\n' % (salt, line))
646 script.append('echo %s %s $?\n' % (salt, line))
655
647
656 # After we run the shell script, we re-unify the script output
648 # After we run the shell script, we re-unify the script output
657 # with non-active parts of the source, with synchronization by our
649 # with non-active parts of the source, with synchronization by our
658 # SALT line number markers. The after table contains the
650 # SALT line number markers. The after table contains the
659 # non-active components, ordered by line number
651 # non-active components, ordered by line number
660 after = {}
652 after = {}
661 pos = prepos = -1
653 pos = prepos = -1
662
654
663 # Expected shellscript output
655 # Expected shellscript output
664 expected = {}
656 expected = {}
665
657
666 # We keep track of whether or not we're in a Python block so we
658 # We keep track of whether or not we're in a Python block so we
667 # can generate the surrounding doctest magic
659 # can generate the surrounding doctest magic
668 inpython = False
660 inpython = False
669
661
670 # True or False when in a true or false conditional section
662 # True or False when in a true or false conditional section
671 skipping = None
663 skipping = None
672
664
673 def hghave(reqs):
665 def hghave(reqs):
674 # TODO: do something smarter when all other uses of hghave is gone
666 # TODO: do something smarter when all other uses of hghave is gone
675 tdir = TESTDIR.replace('\\', '/')
667 tdir = TESTDIR.replace('\\', '/')
676 proc = Popen4('%s -c "%s/hghave %s"' %
668 proc = Popen4('%s -c "%s/hghave %s"' %
677 (options.shell, tdir, ' '.join(reqs)), wd, 0)
669 (options.shell, tdir, ' '.join(reqs)), wd, 0)
678 stdout, stderr = proc.communicate()
670 stdout, stderr = proc.communicate()
679 ret = proc.wait()
671 ret = proc.wait()
680 if wifexited(ret):
672 if wifexited(ret):
681 ret = os.WEXITSTATUS(ret)
673 ret = os.WEXITSTATUS(ret)
682 if ret == 2:
674 if ret == 2:
683 print stdout
675 print stdout
684 sys.exit(1)
676 sys.exit(1)
685 return ret == 0
677 return ret == 0
686
678
687 f = open(test)
679 f = open(test)
688 t = f.readlines()
680 t = f.readlines()
689 f.close()
681 f.close()
690
682
691 script = []
683 script = []
692 if options.debug:
684 if options.debug:
693 script.append('set -x\n')
685 script.append('set -x\n')
694 if os.getenv('MSYSTEM'):
686 if os.getenv('MSYSTEM'):
695 script.append('alias pwd="pwd -W"\n')
687 script.append('alias pwd="pwd -W"\n')
696 n = 0
688 n = 0
697 for n, l in enumerate(t):
689 for n, l in enumerate(t):
698 if not l.endswith('\n'):
690 if not l.endswith('\n'):
699 l += '\n'
691 l += '\n'
700 if l.startswith('#if'):
692 if l.startswith('#if'):
701 if skipping is not None:
693 if skipping is not None:
702 after.setdefault(pos, []).append(' !!! nested #if\n')
694 after.setdefault(pos, []).append(' !!! nested #if\n')
703 skipping = not hghave(l.split()[1:])
695 skipping = not hghave(l.split()[1:])
704 after.setdefault(pos, []).append(l)
696 after.setdefault(pos, []).append(l)
705 elif l.startswith('#else'):
697 elif l.startswith('#else'):
706 if skipping is None:
698 if skipping is None:
707 after.setdefault(pos, []).append(' !!! missing #if\n')
699 after.setdefault(pos, []).append(' !!! missing #if\n')
708 skipping = not skipping
700 skipping = not skipping
709 after.setdefault(pos, []).append(l)
701 after.setdefault(pos, []).append(l)
710 elif l.startswith('#endif'):
702 elif l.startswith('#endif'):
711 if skipping is None:
703 if skipping is None:
712 after.setdefault(pos, []).append(' !!! missing #if\n')
704 after.setdefault(pos, []).append(' !!! missing #if\n')
713 skipping = None
705 skipping = None
714 after.setdefault(pos, []).append(l)
706 after.setdefault(pos, []).append(l)
715 elif skipping:
707 elif skipping:
716 after.setdefault(pos, []).append(l)
708 after.setdefault(pos, []).append(l)
717 elif l.startswith(' >>> '): # python inlines
709 elif l.startswith(' >>> '): # python inlines
718 after.setdefault(pos, []).append(l)
710 after.setdefault(pos, []).append(l)
719 prepos = pos
711 prepos = pos
720 pos = n
712 pos = n
721 if not inpython:
713 if not inpython:
722 # we've just entered a Python block, add the header
714 # we've just entered a Python block, add the header
723 inpython = True
715 inpython = True
724 addsalt(prepos, False) # make sure we report the exit code
716 addsalt(prepos, False) # make sure we report the exit code
725 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
717 script.append('%s -m heredoctest <<EOF\n' % PYTHON)
726 addsalt(n, True)
718 addsalt(n, True)
727 script.append(l[2:])
719 script.append(l[2:])
728 elif l.startswith(' ... '): # python inlines
720 elif l.startswith(' ... '): # python inlines
729 after.setdefault(prepos, []).append(l)
721 after.setdefault(prepos, []).append(l)
730 script.append(l[2:])
722 script.append(l[2:])
731 elif l.startswith(' $ '): # commands
723 elif l.startswith(' $ '): # commands
732 if inpython:
724 if inpython:
733 script.append("EOF\n")
725 script.append("EOF\n")
734 inpython = False
726 inpython = False
735 after.setdefault(pos, []).append(l)
727 after.setdefault(pos, []).append(l)
736 prepos = pos
728 prepos = pos
737 pos = n
729 pos = n
738 addsalt(n, False)
730 addsalt(n, False)
739 cmd = l[4:].split()
731 cmd = l[4:].split()
740 if len(cmd) == 2 and cmd[0] == 'cd':
732 if len(cmd) == 2 and cmd[0] == 'cd':
741 l = ' $ cd %s || exit 1\n' % cmd[1]
733 l = ' $ cd %s || exit 1\n' % cmd[1]
742 script.append(l[4:])
734 script.append(l[4:])
743 elif l.startswith(' > '): # continuations
735 elif l.startswith(' > '): # continuations
744 after.setdefault(prepos, []).append(l)
736 after.setdefault(prepos, []).append(l)
745 script.append(l[4:])
737 script.append(l[4:])
746 elif l.startswith(' '): # results
738 elif l.startswith(' '): # results
747 # queue up a list of expected results
739 # queue up a list of expected results
748 expected.setdefault(pos, []).append(l[2:])
740 expected.setdefault(pos, []).append(l[2:])
749 else:
741 else:
750 if inpython:
742 if inpython:
751 script.append("EOF\n")
743 script.append("EOF\n")
752 inpython = False
744 inpython = False
753 # non-command/result - queue up for merged output
745 # non-command/result - queue up for merged output
754 after.setdefault(pos, []).append(l)
746 after.setdefault(pos, []).append(l)
755
747
756 if inpython:
748 if inpython:
757 script.append("EOF\n")
749 script.append("EOF\n")
758 if skipping is not None:
750 if skipping is not None:
759 after.setdefault(pos, []).append(' !!! missing #endif\n')
751 after.setdefault(pos, []).append(' !!! missing #endif\n')
760 addsalt(n + 1, False)
752 addsalt(n + 1, False)
761
753
762 # Write out the script and execute it
754 # Write out the script and execute it
763 name = wd + '.sh'
755 name = wd + '.sh'
764 f = open(name, 'w')
756 f = open(name, 'w')
765 for l in script:
757 for l in script:
766 f.write(l)
758 f.write(l)
767 f.close()
759 f.close()
768
760
769 cmd = '%s "%s"' % (options.shell, name)
761 cmd = '%s "%s"' % (options.shell, name)
770 vlog("# Running", cmd)
762 vlog("# Running", cmd)
771 exitcode, output = run(cmd, wd, options, replacements, env)
763 exitcode, output = run(cmd, wd, options, replacements, env)
772 # do not merge output if skipped, return hghave message instead
764 # do not merge output if skipped, return hghave message instead
773 # similarly, with --debug, output is None
765 # similarly, with --debug, output is None
774 if exitcode == SKIPPED_STATUS or output is None:
766 if exitcode == SKIPPED_STATUS or output is None:
775 return exitcode, output
767 return exitcode, output
776
768
777 # Merge the script output back into a unified test
769 # Merge the script output back into a unified test
778
770
779 warnonly = 1 # 1: not yet, 2: yes, 3: for sure not
771 warnonly = 1 # 1: not yet, 2: yes, 3: for sure not
780 if exitcode != 0: # failure has been reported
772 if exitcode != 0: # failure has been reported
781 warnonly = 3 # set to "for sure not"
773 warnonly = 3 # set to "for sure not"
782 pos = -1
774 pos = -1
783 postout = []
775 postout = []
784 for l in output:
776 for l in output:
785 lout, lcmd = l, None
777 lout, lcmd = l, None
786 if salt in l:
778 if salt in l:
787 lout, lcmd = l.split(salt, 1)
779 lout, lcmd = l.split(salt, 1)
788
780
789 if lout:
781 if lout:
790 if not lout.endswith('\n'):
782 if not lout.endswith('\n'):
791 lout += ' (no-eol)\n'
783 lout += ' (no-eol)\n'
792
784
793 # find the expected output at the current position
785 # find the expected output at the current position
794 el = None
786 el = None
795 if pos in expected and expected[pos]:
787 if pos in expected and expected[pos]:
796 el = expected[pos].pop(0)
788 el = expected[pos].pop(0)
797
789
798 r = linematch(el, lout)
790 r = linematch(el, lout)
799 if isinstance(r, str):
791 if isinstance(r, str):
800 if r == '+glob':
792 if r == '+glob':
801 lout = el[:-1] + ' (glob)\n'
793 lout = el[:-1] + ' (glob)\n'
802 r = '' # warn only this line
794 r = '' # warn only this line
803 elif r == '-glob':
795 elif r == '-glob':
804 lout = ''.join(el.rsplit(' (glob)', 1))
796 lout = ''.join(el.rsplit(' (glob)', 1))
805 r = '' # warn only this line
797 r = '' # warn only this line
806 else:
798 else:
807 log('\ninfo, unknown linematch result: %r\n' % r)
799 log('\ninfo, unknown linematch result: %r\n' % r)
808 r = False
800 r = False
809 if r:
801 if r:
810 postout.append(" " + el)
802 postout.append(" " + el)
811 else:
803 else:
812 if needescape(lout):
804 if needescape(lout):
813 lout = stringescape(lout.rstrip('\n')) + " (esc)\n"
805 lout = stringescape(lout.rstrip('\n')) + " (esc)\n"
814 postout.append(" " + lout) # let diff deal with it
806 postout.append(" " + lout) # let diff deal with it
815 if r != '': # if line failed
807 if r != '': # if line failed
816 warnonly = 3 # set to "for sure not"
808 warnonly = 3 # set to "for sure not"
817 elif warnonly == 1: # is "not yet" (and line is warn only)
809 elif warnonly == 1: # is "not yet" (and line is warn only)
818 warnonly = 2 # set to "yes" do warn
810 warnonly = 2 # set to "yes" do warn
819
811
820 if lcmd:
812 if lcmd:
821 # add on last return code
813 # add on last return code
822 ret = int(lcmd.split()[1])
814 ret = int(lcmd.split()[1])
823 if ret != 0:
815 if ret != 0:
824 postout.append(" [%s]\n" % ret)
816 postout.append(" [%s]\n" % ret)
825 if pos in after:
817 if pos in after:
826 # merge in non-active test bits
818 # merge in non-active test bits
827 postout += after.pop(pos)
819 postout += after.pop(pos)
828 pos = int(lcmd.split()[0])
820 pos = int(lcmd.split()[0])
829
821
830 if pos in after:
822 if pos in after:
831 postout += after.pop(pos)
823 postout += after.pop(pos)
832
824
833 if warnonly == 2:
825 if warnonly == 2:
834 exitcode = False # set exitcode to warned
826 exitcode = False # set exitcode to warned
835 return exitcode, postout
827 return exitcode, postout
836
828
837 wifexited = getattr(os, "WIFEXITED", lambda x: False)
829 wifexited = getattr(os, "WIFEXITED", lambda x: False)
838 def run(cmd, wd, options, replacements, env):
830 def run(cmd, wd, options, replacements, env):
839 """Run command in a sub-process, capturing the output (stdout and stderr).
831 """Run command in a sub-process, capturing the output (stdout and stderr).
840 Return a tuple (exitcode, output). output is None in debug mode."""
832 Return a tuple (exitcode, output). output is None in debug mode."""
841 # TODO: Use subprocess.Popen if we're running on Python 2.4
833 # TODO: Use subprocess.Popen if we're running on Python 2.4
842 if options.debug:
834 if options.debug:
843 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
835 proc = subprocess.Popen(cmd, shell=True, cwd=wd, env=env)
844 ret = proc.wait()
836 ret = proc.wait()
845 return (ret, None)
837 return (ret, None)
846
838
847 proc = Popen4(cmd, wd, options.timeout, env)
839 proc = Popen4(cmd, wd, options.timeout, env)
848 def cleanup():
840 def cleanup():
849 terminate(proc)
841 terminate(proc)
850 ret = proc.wait()
842 ret = proc.wait()
851 if ret == 0:
843 if ret == 0:
852 ret = signal.SIGTERM << 8
844 ret = signal.SIGTERM << 8
853 killdaemons(env['DAEMON_PIDS'])
845 killdaemons(env['DAEMON_PIDS'])
854 return ret
846 return ret
855
847
856 output = ''
848 output = ''
857 proc.tochild.close()
849 proc.tochild.close()
858
850
859 try:
851 try:
860 output = proc.fromchild.read()
852 output = proc.fromchild.read()
861 except KeyboardInterrupt:
853 except KeyboardInterrupt:
862 vlog('# Handling keyboard interrupt')
854 vlog('# Handling keyboard interrupt')
863 cleanup()
855 cleanup()
864 raise
856 raise
865
857
866 ret = proc.wait()
858 ret = proc.wait()
867 if wifexited(ret):
859 if wifexited(ret):
868 ret = os.WEXITSTATUS(ret)
860 ret = os.WEXITSTATUS(ret)
869
861
870 if proc.timeout:
862 if proc.timeout:
871 ret = 'timeout'
863 ret = 'timeout'
872
864
873 if ret:
865 if ret:
874 killdaemons(env['DAEMON_PIDS'])
866 killdaemons(env['DAEMON_PIDS'])
875
867
876 if abort:
868 if abort:
877 raise KeyboardInterrupt()
869 raise KeyboardInterrupt()
878
870
879 for s, r in replacements:
871 for s, r in replacements:
880 output = re.sub(s, r, output)
872 output = re.sub(s, r, output)
881 return ret, output.splitlines(True)
873 return ret, output.splitlines(True)
882
874
883 def runone(options, test, count):
875 def runone(options, test, count):
884 '''returns a result element: (code, test, msg)'''
876 '''returns a result element: (code, test, msg)'''
885
877
886 def skip(msg):
878 def skip(msg):
887 if options.verbose:
879 if options.verbose:
888 log("\nSkipping %s: %s" % (testpath, msg))
880 log("\nSkipping %s: %s" % (testpath, msg))
889 return 's', test, msg
881 return 's', test, msg
890
882
891 def fail(msg, ret):
883 def fail(msg, ret):
892 warned = ret is False
884 warned = ret is False
893 if not options.nodiff:
885 if not options.nodiff:
894 log("\n%s: %s %s" % (warned and 'Warning' or 'ERROR', test, msg))
886 log("\n%s: %s %s" % (warned and 'Warning' or 'ERROR', test, msg))
895 if (not ret and options.interactive
887 if (not ret and options.interactive
896 and os.path.exists(testpath + ".err")):
888 and os.path.exists(testpath + ".err")):
897 iolock.acquire()
889 iolock.acquire()
898 print "Accept this change? [n] ",
890 print "Accept this change? [n] ",
899 answer = sys.stdin.readline().strip()
891 answer = sys.stdin.readline().strip()
900 iolock.release()
892 iolock.release()
901 if answer.lower() in "y yes".split():
893 if answer.lower() in "y yes".split():
902 if test.endswith(".t"):
894 if test.endswith(".t"):
903 rename(testpath + ".err", testpath)
895 rename(testpath + ".err", testpath)
904 else:
896 else:
905 rename(testpath + ".err", testpath + ".out")
897 rename(testpath + ".err", testpath + ".out")
906 return '.', test, ''
898 return '.', test, ''
907 return warned and '~' or '!', test, msg
899 return warned and '~' or '!', test, msg
908
900
909 def success():
901 def success():
910 return '.', test, ''
902 return '.', test, ''
911
903
912 def ignore(msg):
904 def ignore(msg):
913 return 'i', test, msg
905 return 'i', test, msg
914
906
915 def describe(ret):
907 def describe(ret):
916 if ret < 0:
908 if ret < 0:
917 return 'killed by signal %d' % -ret
909 return 'killed by signal %d' % -ret
918 return 'returned error code %d' % ret
910 return 'returned error code %d' % ret
919
911
920 testpath = os.path.join(TESTDIR, test)
912 testpath = os.path.join(TESTDIR, test)
921 err = os.path.join(TESTDIR, test + ".err")
913 err = os.path.join(TESTDIR, test + ".err")
922 lctest = test.lower()
914 lctest = test.lower()
923
915
924 if not os.path.exists(testpath):
916 if not os.path.exists(testpath):
925 return skip("doesn't exist")
917 return skip("doesn't exist")
926
918
927 if not (options.whitelisted and test in options.whitelisted):
919 if not (options.whitelisted and test in options.whitelisted):
928 if options.blacklist and test in options.blacklist:
920 if options.blacklist and test in options.blacklist:
929 return skip("blacklisted")
921 return skip("blacklisted")
930
922
931 if options.retest and not os.path.exists(test + ".err"):
923 if options.retest and not os.path.exists(test + ".err"):
932 return ignore("not retesting")
924 return ignore("not retesting")
933
925
934 if options.keywords:
926 if options.keywords:
935 fp = open(test)
927 fp = open(test)
936 t = fp.read().lower() + test.lower()
928 t = fp.read().lower() + test.lower()
937 fp.close()
929 fp.close()
938 for k in options.keywords.lower().split():
930 for k in options.keywords.lower().split():
939 if k in t:
931 if k in t:
940 break
932 break
941 else:
933 else:
942 return ignore("doesn't match keyword")
934 return ignore("doesn't match keyword")
943
935
944 if not lctest.startswith("test-"):
936 if not lctest.startswith("test-"):
945 return skip("not a test file")
937 return skip("not a test file")
946 for ext, func, out in testtypes:
938 for ext, func, out in testtypes:
947 if lctest.endswith(ext):
939 if lctest.endswith(ext):
948 runner = func
940 runner = func
949 ref = os.path.join(TESTDIR, test + out)
941 ref = os.path.join(TESTDIR, test + out)
950 break
942 break
951 else:
943 else:
952 return skip("unknown test type")
944 return skip("unknown test type")
953
945
954 vlog("# Test", test)
946 vlog("# Test", test)
955
947
956 if os.path.exists(err):
948 if os.path.exists(err):
957 os.remove(err) # Remove any previous output files
949 os.remove(err) # Remove any previous output files
958
950
959 # Make a tmp subdirectory to work in
951 # Make a tmp subdirectory to work in
960 threadtmp = os.path.join(HGTMP, "child%d" % count)
952 threadtmp = os.path.join(HGTMP, "child%d" % count)
961 testtmp = os.path.join(threadtmp, os.path.basename(test))
953 testtmp = os.path.join(threadtmp, os.path.basename(test))
962 os.mkdir(threadtmp)
954 os.mkdir(threadtmp)
963 os.mkdir(testtmp)
955 os.mkdir(testtmp)
964
956
965 port = options.port + count * 3
957 port = options.port + count * 3
966 replacements = [
958 replacements = [
967 (r':%s\b' % port, ':$HGPORT'),
959 (r':%s\b' % port, ':$HGPORT'),
968 (r':%s\b' % (port + 1), ':$HGPORT1'),
960 (r':%s\b' % (port + 1), ':$HGPORT1'),
969 (r':%s\b' % (port + 2), ':$HGPORT2'),
961 (r':%s\b' % (port + 2), ':$HGPORT2'),
970 ]
962 ]
971 if os.name == 'nt':
963 if os.name == 'nt':
972 replacements.append(
964 replacements.append(
973 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
965 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
974 c in '/\\' and r'[/\\]' or
966 c in '/\\' and r'[/\\]' or
975 c.isdigit() and c or
967 c.isdigit() and c or
976 '\\' + c
968 '\\' + c
977 for c in testtmp), '$TESTTMP'))
969 for c in testtmp), '$TESTTMP'))
978 else:
970 else:
979 replacements.append((re.escape(testtmp), '$TESTTMP'))
971 replacements.append((re.escape(testtmp), '$TESTTMP'))
980
972
981 env = createenv(options, testtmp, threadtmp, port)
973 env = createenv(options, testtmp, threadtmp, port)
982 createhgrc(env['HGRCPATH'], options)
974 createhgrc(env['HGRCPATH'], options)
983
975
984 starttime = time.time()
976 starttime = time.time()
985 try:
977 try:
986 ret, out = runner(testpath, testtmp, options, replacements, env)
978 ret, out = runner(testpath, testtmp, options, replacements, env)
987 except KeyboardInterrupt:
979 except KeyboardInterrupt:
988 endtime = time.time()
980 endtime = time.time()
989 log('INTERRUPTED: %s (after %d seconds)' % (test, endtime - starttime))
981 log('INTERRUPTED: %s (after %d seconds)' % (test, endtime - starttime))
990 raise
982 raise
991 endtime = time.time()
983 endtime = time.time()
992 times.append((test, endtime - starttime))
984 times.append((test, endtime - starttime))
993 vlog("# Ret was:", ret)
985 vlog("# Ret was:", ret)
994
986
995 killdaemons(env['DAEMON_PIDS'])
987 killdaemons(env['DAEMON_PIDS'])
996
988
997 skipped = (ret == SKIPPED_STATUS)
989 skipped = (ret == SKIPPED_STATUS)
998
990
999 # If we're not in --debug mode and reference output file exists,
991 # If we're not in --debug mode and reference output file exists,
1000 # check test output against it.
992 # check test output against it.
1001 if options.debug:
993 if options.debug:
1002 refout = None # to match "out is None"
994 refout = None # to match "out is None"
1003 elif os.path.exists(ref):
995 elif os.path.exists(ref):
1004 f = open(ref, "r")
996 f = open(ref, "r")
1005 refout = f.read().splitlines(True)
997 refout = f.read().splitlines(True)
1006 f.close()
998 f.close()
1007 else:
999 else:
1008 refout = []
1000 refout = []
1009
1001
1010 if (ret != 0 or out != refout) and not skipped and not options.debug:
1002 if (ret != 0 or out != refout) and not skipped and not options.debug:
1011 # Save errors to a file for diagnosis
1003 # Save errors to a file for diagnosis
1012 f = open(err, "wb")
1004 f = open(err, "wb")
1013 for line in out:
1005 for line in out:
1014 f.write(line)
1006 f.write(line)
1015 f.close()
1007 f.close()
1016
1008
1017 if skipped:
1009 if skipped:
1018 if out is None: # debug mode: nothing to parse
1010 if out is None: # debug mode: nothing to parse
1019 missing = ['unknown']
1011 missing = ['unknown']
1020 failed = None
1012 failed = None
1021 else:
1013 else:
1022 missing, failed = parsehghaveoutput(out)
1014 missing, failed = parsehghaveoutput(out)
1023 if not missing:
1015 if not missing:
1024 missing = ['irrelevant']
1016 missing = ['irrelevant']
1025 if failed:
1017 if failed:
1026 result = fail("hghave failed checking for %s" % failed[-1], ret)
1018 result = fail("hghave failed checking for %s" % failed[-1], ret)
1027 skipped = False
1019 skipped = False
1028 else:
1020 else:
1029 result = skip(missing[-1])
1021 result = skip(missing[-1])
1030 elif ret == 'timeout':
1022 elif ret == 'timeout':
1031 result = fail("timed out", ret)
1023 result = fail("timed out", ret)
1032 elif out != refout:
1024 elif out != refout:
1033 if not options.nodiff:
1025 if not options.nodiff:
1034 iolock.acquire()
1026 iolock.acquire()
1035 if options.view:
1027 if options.view:
1036 os.system("%s %s %s" % (options.view, ref, err))
1028 os.system("%s %s %s" % (options.view, ref, err))
1037 else:
1029 else:
1038 showdiff(refout, out, ref, err)
1030 showdiff(refout, out, ref, err)
1039 iolock.release()
1031 iolock.release()
1040 if ret:
1032 if ret:
1041 result = fail("output changed and " + describe(ret), ret)
1033 result = fail("output changed and " + describe(ret), ret)
1042 else:
1034 else:
1043 result = fail("output changed", ret)
1035 result = fail("output changed", ret)
1044 elif ret:
1036 elif ret:
1045 result = fail(describe(ret), ret)
1037 result = fail(describe(ret), ret)
1046 else:
1038 else:
1047 result = success()
1039 result = success()
1048
1040
1049 if not options.verbose:
1041 if not options.verbose:
1050 iolock.acquire()
1042 iolock.acquire()
1051 sys.stdout.write(result[0])
1043 sys.stdout.write(result[0])
1052 sys.stdout.flush()
1044 sys.stdout.flush()
1053 iolock.release()
1045 iolock.release()
1054
1046
1055 if not options.keep_tmpdir:
1047 if not options.keep_tmpdir:
1056 shutil.rmtree(threadtmp, True)
1048 shutil.rmtree(threadtmp, True)
1057 return result
1049 return result
1058
1050
1059 _hgpath = None
1051 _hgpath = None
1060
1052
1061 def _gethgpath():
1053 def _gethgpath():
1062 """Return the path to the mercurial package that is actually found by
1054 """Return the path to the mercurial package that is actually found by
1063 the current Python interpreter."""
1055 the current Python interpreter."""
1064 global _hgpath
1056 global _hgpath
1065 if _hgpath is not None:
1057 if _hgpath is not None:
1066 return _hgpath
1058 return _hgpath
1067
1059
1068 cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
1060 cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
1069 pipe = os.popen(cmd % PYTHON)
1061 pipe = os.popen(cmd % PYTHON)
1070 try:
1062 try:
1071 _hgpath = pipe.read().strip()
1063 _hgpath = pipe.read().strip()
1072 finally:
1064 finally:
1073 pipe.close()
1065 pipe.close()
1074 return _hgpath
1066 return _hgpath
1075
1067
1076 def _checkhglib(verb):
1068 def _checkhglib(verb):
1077 """Ensure that the 'mercurial' package imported by python is
1069 """Ensure that the 'mercurial' package imported by python is
1078 the one we expect it to be. If not, print a warning to stderr."""
1070 the one we expect it to be. If not, print a warning to stderr."""
1079 expecthg = os.path.join(PYTHONDIR, 'mercurial')
1071 expecthg = os.path.join(PYTHONDIR, 'mercurial')
1080 actualhg = _gethgpath()
1072 actualhg = _gethgpath()
1081 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
1073 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
1082 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
1074 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
1083 ' (expected %s)\n'
1075 ' (expected %s)\n'
1084 % (verb, actualhg, expecthg))
1076 % (verb, actualhg, expecthg))
1085
1077
1086 results = {'.':[], '!':[], '~': [], 's':[], 'i':[]}
1078 results = {'.':[], '!':[], '~': [], 's':[], 'i':[]}
1087 times = []
1079 times = []
1088 iolock = threading.Lock()
1080 iolock = threading.Lock()
1089 abort = False
1081 abort = False
1090
1082
1091 def scheduletests(options, tests):
1083 def scheduletests(options, tests):
1092 jobs = options.jobs
1084 jobs = options.jobs
1093 done = queue.Queue()
1085 done = queue.Queue()
1094 running = 0
1086 running = 0
1095 count = 0
1087 count = 0
1096 global abort
1088 global abort
1097
1089
1098 def job(test, count):
1090 def job(test, count):
1099 try:
1091 try:
1100 done.put(runone(options, test, count))
1092 done.put(runone(options, test, count))
1101 except KeyboardInterrupt:
1093 except KeyboardInterrupt:
1102 pass
1094 pass
1103 except: # re-raises
1095 except: # re-raises
1104 done.put(('!', test, 'run-test raised an error, see traceback'))
1096 done.put(('!', test, 'run-test raised an error, see traceback'))
1105 raise
1097 raise
1106
1098
1107 try:
1099 try:
1108 while tests or running:
1100 while tests or running:
1109 if not done.empty() or running == jobs or not tests:
1101 if not done.empty() or running == jobs or not tests:
1110 try:
1102 try:
1111 code, test, msg = done.get(True, 1)
1103 code, test, msg = done.get(True, 1)
1112 results[code].append((test, msg))
1104 results[code].append((test, msg))
1113 if options.first and code not in '.si':
1105 if options.first and code not in '.si':
1114 break
1106 break
1115 except queue.Empty:
1107 except queue.Empty:
1116 continue
1108 continue
1117 running -= 1
1109 running -= 1
1118 if tests and not running == jobs:
1110 if tests and not running == jobs:
1119 test = tests.pop(0)
1111 test = tests.pop(0)
1120 if options.loop:
1112 if options.loop:
1121 tests.append(test)
1113 tests.append(test)
1122 t = threading.Thread(target=job, name=test, args=(test, count))
1114 t = threading.Thread(target=job, name=test, args=(test, count))
1123 t.start()
1115 t.start()
1124 running += 1
1116 running += 1
1125 count += 1
1117 count += 1
1126 except KeyboardInterrupt:
1118 except KeyboardInterrupt:
1127 abort = True
1119 abort = True
1128
1120
1129 def runtests(options, tests):
1121 def runtests(options, tests):
1130 try:
1122 try:
1131 if INST:
1123 if INST:
1132 installhg(options)
1124 installhg(options)
1133 _checkhglib("Testing")
1125 _checkhglib("Testing")
1134 else:
1126 else:
1135 usecorrectpython()
1127 usecorrectpython()
1136
1128
1137 if options.restart:
1129 if options.restart:
1138 orig = list(tests)
1130 orig = list(tests)
1139 while tests:
1131 while tests:
1140 if os.path.exists(tests[0] + ".err"):
1132 if os.path.exists(tests[0] + ".err"):
1141 break
1133 break
1142 tests.pop(0)
1134 tests.pop(0)
1143 if not tests:
1135 if not tests:
1144 print "running all tests"
1136 print "running all tests"
1145 tests = orig
1137 tests = orig
1146
1138
1147 scheduletests(options, tests)
1139 scheduletests(options, tests)
1148
1140
1149 failed = len(results['!'])
1141 failed = len(results['!'])
1150 warned = len(results['~'])
1142 warned = len(results['~'])
1151 tested = len(results['.']) + failed + warned
1143 tested = len(results['.']) + failed + warned
1152 skipped = len(results['s'])
1144 skipped = len(results['s'])
1153 ignored = len(results['i'])
1145 ignored = len(results['i'])
1154
1146
1155 print
1147 print
1156 if not options.noskips:
1148 if not options.noskips:
1157 for s in results['s']:
1149 for s in results['s']:
1158 print "Skipped %s: %s" % s
1150 print "Skipped %s: %s" % s
1159 for s in results['~']:
1151 for s in results['~']:
1160 print "Warned %s: %s" % s
1152 print "Warned %s: %s" % s
1161 for s in results['!']:
1153 for s in results['!']:
1162 print "Failed %s: %s" % s
1154 print "Failed %s: %s" % s
1163 _checkhglib("Tested")
1155 _checkhglib("Tested")
1164 print "# Ran %d tests, %d skipped, %d warned, %d failed." % (
1156 print "# Ran %d tests, %d skipped, %d warned, %d failed." % (
1165 tested, skipped + ignored, warned, failed)
1157 tested, skipped + ignored, warned, failed)
1166 if results['!']:
1158 if results['!']:
1167 print 'python hash seed:', os.environ['PYTHONHASHSEED']
1159 print 'python hash seed:', os.environ['PYTHONHASHSEED']
1168 if options.time:
1160 if options.time:
1169 outputtimes(options)
1161 outputtimes(options)
1170
1162
1171 if options.anycoverage:
1163 if options.anycoverage:
1172 outputcoverage(options)
1164 outputcoverage(options)
1173 except KeyboardInterrupt:
1165 except KeyboardInterrupt:
1174 failed = True
1166 failed = True
1175 print "\ninterrupted!"
1167 print "\ninterrupted!"
1176
1168
1177 if failed:
1169 if failed:
1178 return 1
1170 return 1
1179 if warned:
1171 if warned:
1180 return 80
1172 return 80
1181
1173
1182 testtypes = [('.py', pytest, '.out'),
1174 testtypes = [('.py', pytest, '.out'),
1183 ('.t', tsttest, '')]
1175 ('.t', tsttest, '')]
1184
1176
1185 def main():
1177 def main():
1186 (options, args) = parseargs()
1178 (options, args) = parseargs()
1187 os.umask(022)
1179 os.umask(022)
1188
1180
1189 checktools()
1181 checktools()
1190
1182
1191 if len(args) == 0:
1183 if len(args) == 0:
1192 args = [t for t in os.listdir(".")
1184 args = [t for t in os.listdir(".")
1193 if t.startswith("test-")
1185 if t.startswith("test-")
1194 and (t.endswith(".py") or t.endswith(".t"))]
1186 and (t.endswith(".py") or t.endswith(".t"))]
1195
1187
1196 tests = args
1188 tests = args
1197
1189
1198 if options.random:
1190 if options.random:
1199 random.shuffle(tests)
1191 random.shuffle(tests)
1200 else:
1192 else:
1201 # keywords for slow tests
1193 # keywords for slow tests
1202 slow = 'svn gendoc check-code-hg'.split()
1194 slow = 'svn gendoc check-code-hg'.split()
1203 def sortkey(f):
1195 def sortkey(f):
1204 # run largest tests first, as they tend to take the longest
1196 # run largest tests first, as they tend to take the longest
1205 try:
1197 try:
1206 val = -os.stat(f).st_size
1198 val = -os.stat(f).st_size
1207 except OSError, e:
1199 except OSError, e:
1208 if e.errno != errno.ENOENT:
1200 if e.errno != errno.ENOENT:
1209 raise
1201 raise
1210 return -1e9 # file does not exist, tell early
1202 return -1e9 # file does not exist, tell early
1211 for kw in slow:
1203 for kw in slow:
1212 if kw in f:
1204 if kw in f:
1213 val *= 10
1205 val *= 10
1214 return val
1206 return val
1215 tests.sort(key=sortkey)
1207 tests.sort(key=sortkey)
1216
1208
1217 if 'PYTHONHASHSEED' not in os.environ:
1209 if 'PYTHONHASHSEED' not in os.environ:
1218 # use a random python hash seed all the time
1210 # use a random python hash seed all the time
1219 # we do the randomness ourself to know what seed is used
1211 # we do the randomness ourself to know what seed is used
1220 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
1212 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
1221
1213
1222 global TESTDIR, HGTMP, INST, BINDIR, TMPBINDIR, PYTHONDIR, COVERAGE_FILE
1214 global TESTDIR, HGTMP, INST, BINDIR, TMPBINDIR, PYTHONDIR, COVERAGE_FILE
1223 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
1215 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
1224 if options.tmpdir:
1216 if options.tmpdir:
1225 options.keep_tmpdir = True
1217 options.keep_tmpdir = True
1226 tmpdir = options.tmpdir
1218 tmpdir = options.tmpdir
1227 if os.path.exists(tmpdir):
1219 if os.path.exists(tmpdir):
1228 # Meaning of tmpdir has changed since 1.3: we used to create
1220 # Meaning of tmpdir has changed since 1.3: we used to create
1229 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
1221 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
1230 # tmpdir already exists.
1222 # tmpdir already exists.
1231 sys.exit("error: temp dir %r already exists" % tmpdir)
1223 sys.exit("error: temp dir %r already exists" % tmpdir)
1232
1224
1233 # Automatically removing tmpdir sounds convenient, but could
1225 # Automatically removing tmpdir sounds convenient, but could
1234 # really annoy anyone in the habit of using "--tmpdir=/tmp"
1226 # really annoy anyone in the habit of using "--tmpdir=/tmp"
1235 # or "--tmpdir=$HOME".
1227 # or "--tmpdir=$HOME".
1236 #vlog("# Removing temp dir", tmpdir)
1228 #vlog("# Removing temp dir", tmpdir)
1237 #shutil.rmtree(tmpdir)
1229 #shutil.rmtree(tmpdir)
1238 os.makedirs(tmpdir)
1230 os.makedirs(tmpdir)
1239 else:
1231 else:
1240 d = None
1232 d = None
1241 if os.name == 'nt':
1233 if os.name == 'nt':
1242 # without this, we get the default temp dir location, but
1234 # without this, we get the default temp dir location, but
1243 # in all lowercase, which causes troubles with paths (issue3490)
1235 # in all lowercase, which causes troubles with paths (issue3490)
1244 d = os.getenv('TMP')
1236 d = os.getenv('TMP')
1245 tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
1237 tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
1246 HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
1238 HGTMP = os.environ['HGTMP'] = os.path.realpath(tmpdir)
1247
1239
1248 if options.with_hg:
1240 if options.with_hg:
1249 INST = None
1241 INST = None
1250 BINDIR = os.path.dirname(os.path.realpath(options.with_hg))
1242 BINDIR = os.path.dirname(os.path.realpath(options.with_hg))
1251 TMPBINDIR = os.path.join(HGTMP, 'install', 'bin')
1243 TMPBINDIR = os.path.join(HGTMP, 'install', 'bin')
1252 os.makedirs(TMPBINDIR)
1244 os.makedirs(TMPBINDIR)
1253
1245
1254 # This looks redundant with how Python initializes sys.path from
1246 # This looks redundant with how Python initializes sys.path from
1255 # the location of the script being executed. Needed because the
1247 # the location of the script being executed. Needed because the
1256 # "hg" specified by --with-hg is not the only Python script
1248 # "hg" specified by --with-hg is not the only Python script
1257 # executed in the test suite that needs to import 'mercurial'
1249 # executed in the test suite that needs to import 'mercurial'
1258 # ... which means it's not really redundant at all.
1250 # ... which means it's not really redundant at all.
1259 PYTHONDIR = BINDIR
1251 PYTHONDIR = BINDIR
1260 else:
1252 else:
1261 INST = os.path.join(HGTMP, "install")
1253 INST = os.path.join(HGTMP, "install")
1262 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
1254 BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
1263 TMPBINDIR = BINDIR
1255 TMPBINDIR = BINDIR
1264 PYTHONDIR = os.path.join(INST, "lib", "python")
1256 PYTHONDIR = os.path.join(INST, "lib", "python")
1265
1257
1266 os.environ["BINDIR"] = BINDIR
1258 os.environ["BINDIR"] = BINDIR
1267 os.environ["PYTHON"] = PYTHON
1259 os.environ["PYTHON"] = PYTHON
1268
1260
1269 path = [BINDIR] + os.environ["PATH"].split(os.pathsep)
1261 path = [BINDIR] + os.environ["PATH"].split(os.pathsep)
1270 if TMPBINDIR != BINDIR:
1262 if TMPBINDIR != BINDIR:
1271 path = [TMPBINDIR] + path
1263 path = [TMPBINDIR] + path
1272 os.environ["PATH"] = os.pathsep.join(path)
1264 os.environ["PATH"] = os.pathsep.join(path)
1273
1265
1274 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
1266 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
1275 # can run .../tests/run-tests.py test-foo where test-foo
1267 # can run .../tests/run-tests.py test-foo where test-foo
1276 # adds an extension to HGRC. Also include run-test.py directory to import
1268 # adds an extension to HGRC. Also include run-test.py directory to import
1277 # modules like heredoctest.
1269 # modules like heredoctest.
1278 pypath = [PYTHONDIR, TESTDIR, os.path.abspath(os.path.dirname(__file__))]
1270 pypath = [PYTHONDIR, TESTDIR, os.path.abspath(os.path.dirname(__file__))]
1279 # We have to augment PYTHONPATH, rather than simply replacing
1271 # We have to augment PYTHONPATH, rather than simply replacing
1280 # it, in case external libraries are only available via current
1272 # it, in case external libraries are only available via current
1281 # PYTHONPATH. (In particular, the Subversion bindings on OS X
1273 # PYTHONPATH. (In particular, the Subversion bindings on OS X
1282 # are in /opt/subversion.)
1274 # are in /opt/subversion.)
1283 oldpypath = os.environ.get(IMPL_PATH)
1275 oldpypath = os.environ.get(IMPL_PATH)
1284 if oldpypath:
1276 if oldpypath:
1285 pypath.append(oldpypath)
1277 pypath.append(oldpypath)
1286 os.environ[IMPL_PATH] = os.pathsep.join(pypath)
1278 os.environ[IMPL_PATH] = os.pathsep.join(pypath)
1287
1279
1288 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
1280 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
1289
1281
1290 vlog("# Using TESTDIR", TESTDIR)
1282 vlog("# Using TESTDIR", TESTDIR)
1291 vlog("# Using HGTMP", HGTMP)
1283 vlog("# Using HGTMP", HGTMP)
1292 vlog("# Using PATH", os.environ["PATH"])
1284 vlog("# Using PATH", os.environ["PATH"])
1293 vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
1285 vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
1294
1286
1295 try:
1287 try:
1296 sys.exit(runtests(options, tests) or 0)
1288 sys.exit(runtests(options, tests) or 0)
1297 finally:
1289 finally:
1298 time.sleep(.1)
1290 time.sleep(.1)
1299 cleanup(options)
1291 cleanup(options)
1300
1292
1301 if __name__ == '__main__':
1293 if __name__ == '__main__':
1302 main()
1294 main()
@@ -1,21 +1,20 b''
1 $ "$TESTDIR/hghave" pyflakes || exit 80
1 $ "$TESTDIR/hghave" pyflakes || exit 80
2 $ cd "`dirname "$TESTDIR"`"
2 $ cd "`dirname "$TESTDIR"`"
3
3
4 run pyflakes on all tracked files ending in .py or without a file ending
4 run pyflakes on all tracked files ending in .py or without a file ending
5 (skipping binary file random-seed)
5 (skipping binary file random-seed)
6 $ hg manifest 2>/dev/null | egrep "\.py$|^[^.]*$" | grep -v /random_seed$ \
6 $ hg manifest 2>/dev/null | egrep "\.py$|^[^.]*$" | grep -v /random_seed$ \
7 > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
7 > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
8 contrib/win32/hgwebdir_wsgi.py:*: 'win32traceutil' imported but unused (glob)
8 contrib/win32/hgwebdir_wsgi.py:*: 'win32traceutil' imported but unused (glob)
9 setup.py:*: 'sha' imported but unused (glob)
9 setup.py:*: 'sha' imported but unused (glob)
10 setup.py:*: 'zlib' imported but unused (glob)
10 setup.py:*: 'zlib' imported but unused (glob)
11 setup.py:*: 'bz2' imported but unused (glob)
11 setup.py:*: 'bz2' imported but unused (glob)
12 setup.py:*: 'py2exe' imported but unused (glob)
12 setup.py:*: 'py2exe' imported but unused (glob)
13 tests/hghave.py:*: 'hgext' imported but unused (glob)
13 tests/hghave.py:*: 'hgext' imported but unused (glob)
14 tests/hghave.py:*: '_lsprof' imported but unused (glob)
14 tests/hghave.py:*: '_lsprof' imported but unused (glob)
15 tests/hghave.py:*: 'publish_cmdline' imported but unused (glob)
15 tests/hghave.py:*: 'publish_cmdline' imported but unused (glob)
16 tests/hghave.py:*: 'pygments' imported but unused (glob)
16 tests/hghave.py:*: 'pygments' imported but unused (glob)
17 tests/hghave.py:*: 'ssl' imported but unused (glob)
17 tests/hghave.py:*: 'ssl' imported but unused (glob)
18 contrib/win32/hgwebdir_wsgi.py:*: 'from isapi.install import *' used; unable to detect undefined names (glob)
18 contrib/win32/hgwebdir_wsgi.py:*: 'from isapi.install import *' used; unable to detect undefined names (glob)
19 hgext/inotify/linux/__init__.py:*: 'from _inotify import *' used; unable to detect undefined names (glob)
20
19
21
20
@@ -1,36 +1,36 b''
1 import os
1 import os
2 from mercurial import ui, commands, extensions
2 from mercurial import ui, commands, extensions
3
3
4 ignore = set(['highlight', 'inotify', 'win32text', 'factotum'])
4 ignore = set(['highlight', 'win32text', 'factotum'])
5
5
6 if os.name != 'nt':
6 if os.name != 'nt':
7 ignore.add('win32mbcs')
7 ignore.add('win32mbcs')
8
8
9 disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
9 disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
10
10
11 hgrc = open(os.environ["HGRCPATH"], 'w')
11 hgrc = open(os.environ["HGRCPATH"], 'w')
12 hgrc.write('[extensions]\n')
12 hgrc.write('[extensions]\n')
13
13
14 for ext in disabled:
14 for ext in disabled:
15 hgrc.write(ext + '=\n')
15 hgrc.write(ext + '=\n')
16
16
17 hgrc.close()
17 hgrc.close()
18
18
19 u = ui.ui()
19 u = ui.ui()
20 extensions.loadall(u)
20 extensions.loadall(u)
21
21
22 globalshort = set()
22 globalshort = set()
23 globallong = set()
23 globallong = set()
24 for option in commands.globalopts:
24 for option in commands.globalopts:
25 option[0] and globalshort.add(option[0])
25 option[0] and globalshort.add(option[0])
26 option[1] and globallong.add(option[1])
26 option[1] and globallong.add(option[1])
27
27
28 for cmd, entry in commands.table.iteritems():
28 for cmd, entry in commands.table.iteritems():
29 seenshort = globalshort.copy()
29 seenshort = globalshort.copy()
30 seenlong = globallong.copy()
30 seenlong = globallong.copy()
31 for option in entry[1]:
31 for option in entry[1]:
32 if (option[0] and option[0] in seenshort) or \
32 if (option[0] and option[0] in seenshort) or \
33 (option[1] and option[1] in seenlong):
33 (option[1] and option[1] in seenlong):
34 print "command '" + cmd + "' has duplicate option " + str(option)
34 print "command '" + cmd + "' has duplicate option " + str(option)
35 seenshort.add(option[0])
35 seenshort.add(option[0])
36 seenlong.add(option[1])
36 seenlong.add(option[1])
@@ -1,1995 +1,1995 b''
1 Short help:
1 Short help:
2
2
3 $ hg
3 $ hg
4 Mercurial Distributed SCM
4 Mercurial Distributed SCM
5
5
6 basic commands:
6 basic commands:
7
7
8 add add the specified files on the next commit
8 add add the specified files on the next commit
9 annotate show changeset information by line for each file
9 annotate show changeset information by line for each file
10 clone make a copy of an existing repository
10 clone make a copy of an existing repository
11 commit commit the specified files or all outstanding changes
11 commit commit the specified files or all outstanding changes
12 diff diff repository (or selected files)
12 diff diff repository (or selected files)
13 export dump the header and diffs for one or more changesets
13 export dump the header and diffs for one or more changesets
14 forget forget the specified files on the next commit
14 forget forget the specified files on the next commit
15 init create a new repository in the given directory
15 init create a new repository in the given directory
16 log show revision history of entire repository or files
16 log show revision history of entire repository or files
17 merge merge working directory with another revision
17 merge merge working directory with another revision
18 pull pull changes from the specified source
18 pull pull changes from the specified source
19 push push changes to the specified destination
19 push push changes to the specified destination
20 remove remove the specified files on the next commit
20 remove remove the specified files on the next commit
21 serve start stand-alone webserver
21 serve start stand-alone webserver
22 status show changed files in the working directory
22 status show changed files in the working directory
23 summary summarize working directory state
23 summary summarize working directory state
24 update update working directory (or switch revisions)
24 update update working directory (or switch revisions)
25
25
26 use "hg help" for the full list of commands or "hg -v" for details
26 use "hg help" for the full list of commands or "hg -v" for details
27
27
28 $ hg -q
28 $ hg -q
29 add add the specified files on the next commit
29 add add the specified files on the next commit
30 annotate show changeset information by line for each file
30 annotate show changeset information by line for each file
31 clone make a copy of an existing repository
31 clone make a copy of an existing repository
32 commit commit the specified files or all outstanding changes
32 commit commit the specified files or all outstanding changes
33 diff diff repository (or selected files)
33 diff diff repository (or selected files)
34 export dump the header and diffs for one or more changesets
34 export dump the header and diffs for one or more changesets
35 forget forget the specified files on the next commit
35 forget forget the specified files on the next commit
36 init create a new repository in the given directory
36 init create a new repository in the given directory
37 log show revision history of entire repository or files
37 log show revision history of entire repository or files
38 merge merge working directory with another revision
38 merge merge working directory with another revision
39 pull pull changes from the specified source
39 pull pull changes from the specified source
40 push push changes to the specified destination
40 push push changes to the specified destination
41 remove remove the specified files on the next commit
41 remove remove the specified files on the next commit
42 serve start stand-alone webserver
42 serve start stand-alone webserver
43 status show changed files in the working directory
43 status show changed files in the working directory
44 summary summarize working directory state
44 summary summarize working directory state
45 update update working directory (or switch revisions)
45 update update working directory (or switch revisions)
46
46
47 $ hg help
47 $ hg help
48 Mercurial Distributed SCM
48 Mercurial Distributed SCM
49
49
50 list of commands:
50 list of commands:
51
51
52 add add the specified files on the next commit
52 add add the specified files on the next commit
53 addremove add all new files, delete all missing files
53 addremove add all new files, delete all missing files
54 annotate show changeset information by line for each file
54 annotate show changeset information by line for each file
55 archive create an unversioned archive of a repository revision
55 archive create an unversioned archive of a repository revision
56 backout reverse effect of earlier changeset
56 backout reverse effect of earlier changeset
57 bisect subdivision search of changesets
57 bisect subdivision search of changesets
58 bookmarks track a line of development with movable markers
58 bookmarks track a line of development with movable markers
59 branch set or show the current branch name
59 branch set or show the current branch name
60 branches list repository named branches
60 branches list repository named branches
61 bundle create a changegroup file
61 bundle create a changegroup file
62 cat output the current or given revision of files
62 cat output the current or given revision of files
63 clone make a copy of an existing repository
63 clone make a copy of an existing repository
64 commit commit the specified files or all outstanding changes
64 commit commit the specified files or all outstanding changes
65 config show combined config settings from all hgrc files
65 config show combined config settings from all hgrc files
66 copy mark files as copied for the next commit
66 copy mark files as copied for the next commit
67 diff diff repository (or selected files)
67 diff diff repository (or selected files)
68 export dump the header and diffs for one or more changesets
68 export dump the header and diffs for one or more changesets
69 forget forget the specified files on the next commit
69 forget forget the specified files on the next commit
70 graft copy changes from other branches onto the current branch
70 graft copy changes from other branches onto the current branch
71 grep search for a pattern in specified files and revisions
71 grep search for a pattern in specified files and revisions
72 heads show branch heads
72 heads show branch heads
73 help show help for a given topic or a help overview
73 help show help for a given topic or a help overview
74 identify identify the working copy or specified revision
74 identify identify the working copy or specified revision
75 import import an ordered set of patches
75 import import an ordered set of patches
76 incoming show new changesets found in source
76 incoming show new changesets found in source
77 init create a new repository in the given directory
77 init create a new repository in the given directory
78 locate locate files matching specific patterns
78 locate locate files matching specific patterns
79 log show revision history of entire repository or files
79 log show revision history of entire repository or files
80 manifest output the current or given revision of the project manifest
80 manifest output the current or given revision of the project manifest
81 merge merge working directory with another revision
81 merge merge working directory with another revision
82 outgoing show changesets not found in the destination
82 outgoing show changesets not found in the destination
83 parents show the parents of the working directory or revision
83 parents show the parents of the working directory or revision
84 paths show aliases for remote repositories
84 paths show aliases for remote repositories
85 phase set or show the current phase name
85 phase set or show the current phase name
86 pull pull changes from the specified source
86 pull pull changes from the specified source
87 push push changes to the specified destination
87 push push changes to the specified destination
88 recover roll back an interrupted transaction
88 recover roll back an interrupted transaction
89 remove remove the specified files on the next commit
89 remove remove the specified files on the next commit
90 rename rename files; equivalent of copy + remove
90 rename rename files; equivalent of copy + remove
91 resolve redo merges or set/view the merge status of files
91 resolve redo merges or set/view the merge status of files
92 revert restore files to their checkout state
92 revert restore files to their checkout state
93 root print the root (top) of the current working directory
93 root print the root (top) of the current working directory
94 serve start stand-alone webserver
94 serve start stand-alone webserver
95 status show changed files in the working directory
95 status show changed files in the working directory
96 summary summarize working directory state
96 summary summarize working directory state
97 tag add one or more tags for the current or given revision
97 tag add one or more tags for the current or given revision
98 tags list repository tags
98 tags list repository tags
99 unbundle apply one or more changegroup files
99 unbundle apply one or more changegroup files
100 update update working directory (or switch revisions)
100 update update working directory (or switch revisions)
101 verify verify the integrity of the repository
101 verify verify the integrity of the repository
102 version output version and copyright information
102 version output version and copyright information
103
103
104 additional help topics:
104 additional help topics:
105
105
106 config Configuration Files
106 config Configuration Files
107 dates Date Formats
107 dates Date Formats
108 diffs Diff Formats
108 diffs Diff Formats
109 environment Environment Variables
109 environment Environment Variables
110 extensions Using Additional Features
110 extensions Using Additional Features
111 filesets Specifying File Sets
111 filesets Specifying File Sets
112 glossary Glossary
112 glossary Glossary
113 hgignore Syntax for Mercurial Ignore Files
113 hgignore Syntax for Mercurial Ignore Files
114 hgweb Configuring hgweb
114 hgweb Configuring hgweb
115 merge-tools Merge Tools
115 merge-tools Merge Tools
116 multirevs Specifying Multiple Revisions
116 multirevs Specifying Multiple Revisions
117 patterns File Name Patterns
117 patterns File Name Patterns
118 phases Working with Phases
118 phases Working with Phases
119 revisions Specifying Single Revisions
119 revisions Specifying Single Revisions
120 revsets Specifying Revision Sets
120 revsets Specifying Revision Sets
121 subrepos Subrepositories
121 subrepos Subrepositories
122 templating Template Usage
122 templating Template Usage
123 urls URL Paths
123 urls URL Paths
124
124
125 use "hg -v help" to show builtin aliases and global options
125 use "hg -v help" to show builtin aliases and global options
126
126
127 $ hg -q help
127 $ hg -q help
128 add add the specified files on the next commit
128 add add the specified files on the next commit
129 addremove add all new files, delete all missing files
129 addremove add all new files, delete all missing files
130 annotate show changeset information by line for each file
130 annotate show changeset information by line for each file
131 archive create an unversioned archive of a repository revision
131 archive create an unversioned archive of a repository revision
132 backout reverse effect of earlier changeset
132 backout reverse effect of earlier changeset
133 bisect subdivision search of changesets
133 bisect subdivision search of changesets
134 bookmarks track a line of development with movable markers
134 bookmarks track a line of development with movable markers
135 branch set or show the current branch name
135 branch set or show the current branch name
136 branches list repository named branches
136 branches list repository named branches
137 bundle create a changegroup file
137 bundle create a changegroup file
138 cat output the current or given revision of files
138 cat output the current or given revision of files
139 clone make a copy of an existing repository
139 clone make a copy of an existing repository
140 commit commit the specified files or all outstanding changes
140 commit commit the specified files or all outstanding changes
141 config show combined config settings from all hgrc files
141 config show combined config settings from all hgrc files
142 copy mark files as copied for the next commit
142 copy mark files as copied for the next commit
143 diff diff repository (or selected files)
143 diff diff repository (or selected files)
144 export dump the header and diffs for one or more changesets
144 export dump the header and diffs for one or more changesets
145 forget forget the specified files on the next commit
145 forget forget the specified files on the next commit
146 graft copy changes from other branches onto the current branch
146 graft copy changes from other branches onto the current branch
147 grep search for a pattern in specified files and revisions
147 grep search for a pattern in specified files and revisions
148 heads show branch heads
148 heads show branch heads
149 help show help for a given topic or a help overview
149 help show help for a given topic or a help overview
150 identify identify the working copy or specified revision
150 identify identify the working copy or specified revision
151 import import an ordered set of patches
151 import import an ordered set of patches
152 incoming show new changesets found in source
152 incoming show new changesets found in source
153 init create a new repository in the given directory
153 init create a new repository in the given directory
154 locate locate files matching specific patterns
154 locate locate files matching specific patterns
155 log show revision history of entire repository or files
155 log show revision history of entire repository or files
156 manifest output the current or given revision of the project manifest
156 manifest output the current or given revision of the project manifest
157 merge merge working directory with another revision
157 merge merge working directory with another revision
158 outgoing show changesets not found in the destination
158 outgoing show changesets not found in the destination
159 parents show the parents of the working directory or revision
159 parents show the parents of the working directory or revision
160 paths show aliases for remote repositories
160 paths show aliases for remote repositories
161 phase set or show the current phase name
161 phase set or show the current phase name
162 pull pull changes from the specified source
162 pull pull changes from the specified source
163 push push changes to the specified destination
163 push push changes to the specified destination
164 recover roll back an interrupted transaction
164 recover roll back an interrupted transaction
165 remove remove the specified files on the next commit
165 remove remove the specified files on the next commit
166 rename rename files; equivalent of copy + remove
166 rename rename files; equivalent of copy + remove
167 resolve redo merges or set/view the merge status of files
167 resolve redo merges or set/view the merge status of files
168 revert restore files to their checkout state
168 revert restore files to their checkout state
169 root print the root (top) of the current working directory
169 root print the root (top) of the current working directory
170 serve start stand-alone webserver
170 serve start stand-alone webserver
171 status show changed files in the working directory
171 status show changed files in the working directory
172 summary summarize working directory state
172 summary summarize working directory state
173 tag add one or more tags for the current or given revision
173 tag add one or more tags for the current or given revision
174 tags list repository tags
174 tags list repository tags
175 unbundle apply one or more changegroup files
175 unbundle apply one or more changegroup files
176 update update working directory (or switch revisions)
176 update update working directory (or switch revisions)
177 verify verify the integrity of the repository
177 verify verify the integrity of the repository
178 version output version and copyright information
178 version output version and copyright information
179
179
180 additional help topics:
180 additional help topics:
181
181
182 config Configuration Files
182 config Configuration Files
183 dates Date Formats
183 dates Date Formats
184 diffs Diff Formats
184 diffs Diff Formats
185 environment Environment Variables
185 environment Environment Variables
186 extensions Using Additional Features
186 extensions Using Additional Features
187 filesets Specifying File Sets
187 filesets Specifying File Sets
188 glossary Glossary
188 glossary Glossary
189 hgignore Syntax for Mercurial Ignore Files
189 hgignore Syntax for Mercurial Ignore Files
190 hgweb Configuring hgweb
190 hgweb Configuring hgweb
191 merge-tools Merge Tools
191 merge-tools Merge Tools
192 multirevs Specifying Multiple Revisions
192 multirevs Specifying Multiple Revisions
193 patterns File Name Patterns
193 patterns File Name Patterns
194 phases Working with Phases
194 phases Working with Phases
195 revisions Specifying Single Revisions
195 revisions Specifying Single Revisions
196 revsets Specifying Revision Sets
196 revsets Specifying Revision Sets
197 subrepos Subrepositories
197 subrepos Subrepositories
198 templating Template Usage
198 templating Template Usage
199 urls URL Paths
199 urls URL Paths
200
200
201 Test extension help:
201 Test extension help:
202 $ hg help extensions --config extensions.rebase= --config extensions.children= | grep -v inotify
202 $ hg help extensions --config extensions.rebase= --config extensions.children=
203 Using Additional Features
203 Using Additional Features
204 """""""""""""""""""""""""
204 """""""""""""""""""""""""
205
205
206 Mercurial has the ability to add new features through the use of
206 Mercurial has the ability to add new features through the use of
207 extensions. Extensions may add new commands, add options to existing
207 extensions. Extensions may add new commands, add options to existing
208 commands, change the default behavior of commands, or implement hooks.
208 commands, change the default behavior of commands, or implement hooks.
209
209
210 To enable the "foo" extension, either shipped with Mercurial or in the
210 To enable the "foo" extension, either shipped with Mercurial or in the
211 Python search path, create an entry for it in your configuration file,
211 Python search path, create an entry for it in your configuration file,
212 like this:
212 like this:
213
213
214 [extensions]
214 [extensions]
215 foo =
215 foo =
216
216
217 You may also specify the full path to an extension:
217 You may also specify the full path to an extension:
218
218
219 [extensions]
219 [extensions]
220 myfeature = ~/.hgext/myfeature.py
220 myfeature = ~/.hgext/myfeature.py
221
221
222 See "hg help config" for more information on configuration files.
222 See "hg help config" for more information on configuration files.
223
223
224 Extensions are not loaded by default for a variety of reasons: they can
224 Extensions are not loaded by default for a variety of reasons: they can
225 increase startup overhead; they may be meant for advanced usage only; they
225 increase startup overhead; they may be meant for advanced usage only; they
226 may provide potentially dangerous abilities (such as letting you destroy
226 may provide potentially dangerous abilities (such as letting you destroy
227 or modify history); they might not be ready for prime time; or they may
227 or modify history); they might not be ready for prime time; or they may
228 alter some usual behaviors of stock Mercurial. It is thus up to the user
228 alter some usual behaviors of stock Mercurial. It is thus up to the user
229 to activate extensions as needed.
229 to activate extensions as needed.
230
230
231 To explicitly disable an extension enabled in a configuration file of
231 To explicitly disable an extension enabled in a configuration file of
232 broader scope, prepend its path with !:
232 broader scope, prepend its path with !:
233
233
234 [extensions]
234 [extensions]
235 # disabling extension bar residing in /path/to/extension/bar.py
235 # disabling extension bar residing in /path/to/extension/bar.py
236 bar = !/path/to/extension/bar.py
236 bar = !/path/to/extension/bar.py
237 # ditto, but no path was supplied for extension baz
237 # ditto, but no path was supplied for extension baz
238 baz = !
238 baz = !
239
239
240 enabled extensions:
240 enabled extensions:
241
241
242 children command to display child changesets (DEPRECATED)
242 children command to display child changesets (DEPRECATED)
243 rebase command to move sets of revisions to a different ancestor
243 rebase command to move sets of revisions to a different ancestor
244
244
245 disabled extensions:
245 disabled extensions:
246
246
247 acl hooks for controlling repository access
247 acl hooks for controlling repository access
248 blackbox log repository events to a blackbox for debugging
248 blackbox log repository events to a blackbox for debugging
249 bugzilla hooks for integrating with the Bugzilla bug tracker
249 bugzilla hooks for integrating with the Bugzilla bug tracker
250 churn command to display statistics about repository history
250 churn command to display statistics about repository history
251 color colorize output from some commands
251 color colorize output from some commands
252 convert import revisions from foreign VCS repositories into
252 convert import revisions from foreign VCS repositories into
253 Mercurial
253 Mercurial
254 eol automatically manage newlines in repository files
254 eol automatically manage newlines in repository files
255 extdiff command to allow external programs to compare revisions
255 extdiff command to allow external programs to compare revisions
256 factotum http authentication with factotum
256 factotum http authentication with factotum
257 gpg commands to sign and verify changesets
257 gpg commands to sign and verify changesets
258 hgcia hooks for integrating with the CIA.vc notification service
258 hgcia hooks for integrating with the CIA.vc notification service
259 hgk browse the repository in a graphical way
259 hgk browse the repository in a graphical way
260 highlight syntax highlighting for hgweb (requires Pygments)
260 highlight syntax highlighting for hgweb (requires Pygments)
261 histedit interactive history editing
261 histedit interactive history editing
262 interhg expand expressions into changelog and summaries
262 interhg expand expressions into changelog and summaries
263 keyword expand keywords in tracked files
263 keyword expand keywords in tracked files
264 largefiles track large binary files
264 largefiles track large binary files
265 mq manage a stack of patches
265 mq manage a stack of patches
266 notify hooks for sending email push notifications
266 notify hooks for sending email push notifications
267 pager browse command output with an external pager
267 pager browse command output with an external pager
268 patchbomb command to send changesets as (a series of) patch emails
268 patchbomb command to send changesets as (a series of) patch emails
269 progress show progress bars for some actions
269 progress show progress bars for some actions
270 purge command to delete untracked files from the working
270 purge command to delete untracked files from the working
271 directory
271 directory
272 record commands to interactively select changes for
272 record commands to interactively select changes for
273 commit/qrefresh
273 commit/qrefresh
274 relink recreates hardlinks between repository clones
274 relink recreates hardlinks between repository clones
275 schemes extend schemes with shortcuts to repository swarms
275 schemes extend schemes with shortcuts to repository swarms
276 share share a common history between several working directories
276 share share a common history between several working directories
277 shelve save and restore changes to the working directory
277 shelve save and restore changes to the working directory
278 strip strip changesets and their descendents from history
278 strip strip changesets and their descendents from history
279 transplant command to transplant changesets from another branch
279 transplant command to transplant changesets from another branch
280 win32mbcs allow the use of MBCS paths with problematic encodings
280 win32mbcs allow the use of MBCS paths with problematic encodings
281 win32text perform automatic newline conversion
281 win32text perform automatic newline conversion
282 zeroconf discover and advertise repositories on the local network
282 zeroconf discover and advertise repositories on the local network
283 Test short command list with verbose option
283 Test short command list with verbose option
284
284
285 $ hg -v help shortlist
285 $ hg -v help shortlist
286 Mercurial Distributed SCM
286 Mercurial Distributed SCM
287
287
288 basic commands:
288 basic commands:
289
289
290 add add the specified files on the next commit
290 add add the specified files on the next commit
291 annotate, blame
291 annotate, blame
292 show changeset information by line for each file
292 show changeset information by line for each file
293 clone make a copy of an existing repository
293 clone make a copy of an existing repository
294 commit, ci commit the specified files or all outstanding changes
294 commit, ci commit the specified files or all outstanding changes
295 diff diff repository (or selected files)
295 diff diff repository (or selected files)
296 export dump the header and diffs for one or more changesets
296 export dump the header and diffs for one or more changesets
297 forget forget the specified files on the next commit
297 forget forget the specified files on the next commit
298 init create a new repository in the given directory
298 init create a new repository in the given directory
299 log, history show revision history of entire repository or files
299 log, history show revision history of entire repository or files
300 merge merge working directory with another revision
300 merge merge working directory with another revision
301 pull pull changes from the specified source
301 pull pull changes from the specified source
302 push push changes to the specified destination
302 push push changes to the specified destination
303 remove, rm remove the specified files on the next commit
303 remove, rm remove the specified files on the next commit
304 serve start stand-alone webserver
304 serve start stand-alone webserver
305 status, st show changed files in the working directory
305 status, st show changed files in the working directory
306 summary, sum summarize working directory state
306 summary, sum summarize working directory state
307 update, up, checkout, co
307 update, up, checkout, co
308 update working directory (or switch revisions)
308 update working directory (or switch revisions)
309
309
310 global options:
310 global options:
311
311
312 -R --repository REPO repository root directory or name of overlay bundle
312 -R --repository REPO repository root directory or name of overlay bundle
313 file
313 file
314 --cwd DIR change working directory
314 --cwd DIR change working directory
315 -y --noninteractive do not prompt, automatically pick the first choice for
315 -y --noninteractive do not prompt, automatically pick the first choice for
316 all prompts
316 all prompts
317 -q --quiet suppress output
317 -q --quiet suppress output
318 -v --verbose enable additional output
318 -v --verbose enable additional output
319 --config CONFIG [+] set/override config option (use 'section.name=value')
319 --config CONFIG [+] set/override config option (use 'section.name=value')
320 --debug enable debugging output
320 --debug enable debugging output
321 --debugger start debugger
321 --debugger start debugger
322 --encoding ENCODE set the charset encoding (default: ascii)
322 --encoding ENCODE set the charset encoding (default: ascii)
323 --encodingmode MODE set the charset encoding mode (default: strict)
323 --encodingmode MODE set the charset encoding mode (default: strict)
324 --traceback always print a traceback on exception
324 --traceback always print a traceback on exception
325 --time time how long the command takes
325 --time time how long the command takes
326 --profile print command execution profile
326 --profile print command execution profile
327 --version output version information and exit
327 --version output version information and exit
328 -h --help display help and exit
328 -h --help display help and exit
329 --hidden consider hidden changesets
329 --hidden consider hidden changesets
330
330
331 [+] marked option can be specified multiple times
331 [+] marked option can be specified multiple times
332
332
333 use "hg help" for the full list of commands
333 use "hg help" for the full list of commands
334
334
335 $ hg add -h
335 $ hg add -h
336 hg add [OPTION]... [FILE]...
336 hg add [OPTION]... [FILE]...
337
337
338 add the specified files on the next commit
338 add the specified files on the next commit
339
339
340 Schedule files to be version controlled and added to the repository.
340 Schedule files to be version controlled and added to the repository.
341
341
342 The files will be added to the repository at the next commit. To undo an
342 The files will be added to the repository at the next commit. To undo an
343 add before that, see "hg forget".
343 add before that, see "hg forget".
344
344
345 If no names are given, add all files to the repository.
345 If no names are given, add all files to the repository.
346
346
347 Returns 0 if all files are successfully added.
347 Returns 0 if all files are successfully added.
348
348
349 options:
349 options:
350
350
351 -I --include PATTERN [+] include names matching the given patterns
351 -I --include PATTERN [+] include names matching the given patterns
352 -X --exclude PATTERN [+] exclude names matching the given patterns
352 -X --exclude PATTERN [+] exclude names matching the given patterns
353 -S --subrepos recurse into subrepositories
353 -S --subrepos recurse into subrepositories
354 -n --dry-run do not perform actions, just print output
354 -n --dry-run do not perform actions, just print output
355
355
356 [+] marked option can be specified multiple times
356 [+] marked option can be specified multiple times
357
357
358 use "hg -v help add" to show more complete help and the global options
358 use "hg -v help add" to show more complete help and the global options
359
359
360 Verbose help for add
360 Verbose help for add
361
361
362 $ hg add -hv
362 $ hg add -hv
363 hg add [OPTION]... [FILE]...
363 hg add [OPTION]... [FILE]...
364
364
365 add the specified files on the next commit
365 add the specified files on the next commit
366
366
367 Schedule files to be version controlled and added to the repository.
367 Schedule files to be version controlled and added to the repository.
368
368
369 The files will be added to the repository at the next commit. To undo an
369 The files will be added to the repository at the next commit. To undo an
370 add before that, see "hg forget".
370 add before that, see "hg forget".
371
371
372 If no names are given, add all files to the repository.
372 If no names are given, add all files to the repository.
373
373
374 An example showing how new (unknown) files are added automatically by "hg
374 An example showing how new (unknown) files are added automatically by "hg
375 add":
375 add":
376
376
377 $ ls
377 $ ls
378 foo.c
378 foo.c
379 $ hg status
379 $ hg status
380 ? foo.c
380 ? foo.c
381 $ hg add
381 $ hg add
382 adding foo.c
382 adding foo.c
383 $ hg status
383 $ hg status
384 A foo.c
384 A foo.c
385
385
386 Returns 0 if all files are successfully added.
386 Returns 0 if all files are successfully added.
387
387
388 options:
388 options:
389
389
390 -I --include PATTERN [+] include names matching the given patterns
390 -I --include PATTERN [+] include names matching the given patterns
391 -X --exclude PATTERN [+] exclude names matching the given patterns
391 -X --exclude PATTERN [+] exclude names matching the given patterns
392 -S --subrepos recurse into subrepositories
392 -S --subrepos recurse into subrepositories
393 -n --dry-run do not perform actions, just print output
393 -n --dry-run do not perform actions, just print output
394
394
395 [+] marked option can be specified multiple times
395 [+] marked option can be specified multiple times
396
396
397 global options:
397 global options:
398
398
399 -R --repository REPO repository root directory or name of overlay bundle
399 -R --repository REPO repository root directory or name of overlay bundle
400 file
400 file
401 --cwd DIR change working directory
401 --cwd DIR change working directory
402 -y --noninteractive do not prompt, automatically pick the first choice for
402 -y --noninteractive do not prompt, automatically pick the first choice for
403 all prompts
403 all prompts
404 -q --quiet suppress output
404 -q --quiet suppress output
405 -v --verbose enable additional output
405 -v --verbose enable additional output
406 --config CONFIG [+] set/override config option (use 'section.name=value')
406 --config CONFIG [+] set/override config option (use 'section.name=value')
407 --debug enable debugging output
407 --debug enable debugging output
408 --debugger start debugger
408 --debugger start debugger
409 --encoding ENCODE set the charset encoding (default: ascii)
409 --encoding ENCODE set the charset encoding (default: ascii)
410 --encodingmode MODE set the charset encoding mode (default: strict)
410 --encodingmode MODE set the charset encoding mode (default: strict)
411 --traceback always print a traceback on exception
411 --traceback always print a traceback on exception
412 --time time how long the command takes
412 --time time how long the command takes
413 --profile print command execution profile
413 --profile print command execution profile
414 --version output version information and exit
414 --version output version information and exit
415 -h --help display help and exit
415 -h --help display help and exit
416 --hidden consider hidden changesets
416 --hidden consider hidden changesets
417
417
418 [+] marked option can be specified multiple times
418 [+] marked option can be specified multiple times
419
419
420 Test help option with version option
420 Test help option with version option
421
421
422 $ hg add -h --version
422 $ hg add -h --version
423 Mercurial Distributed SCM (version *) (glob)
423 Mercurial Distributed SCM (version *) (glob)
424 (see http://mercurial.selenic.com for more information)
424 (see http://mercurial.selenic.com for more information)
425
425
426 Copyright (C) 2005-2014 Matt Mackall and others
426 Copyright (C) 2005-2014 Matt Mackall and others
427 This is free software; see the source for copying conditions. There is NO
427 This is free software; see the source for copying conditions. There is NO
428 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
428 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
429
429
430 $ hg add --skjdfks
430 $ hg add --skjdfks
431 hg add: option --skjdfks not recognized
431 hg add: option --skjdfks not recognized
432 hg add [OPTION]... [FILE]...
432 hg add [OPTION]... [FILE]...
433
433
434 add the specified files on the next commit
434 add the specified files on the next commit
435
435
436 options:
436 options:
437
437
438 -I --include PATTERN [+] include names matching the given patterns
438 -I --include PATTERN [+] include names matching the given patterns
439 -X --exclude PATTERN [+] exclude names matching the given patterns
439 -X --exclude PATTERN [+] exclude names matching the given patterns
440 -S --subrepos recurse into subrepositories
440 -S --subrepos recurse into subrepositories
441 -n --dry-run do not perform actions, just print output
441 -n --dry-run do not perform actions, just print output
442
442
443 [+] marked option can be specified multiple times
443 [+] marked option can be specified multiple times
444
444
445 use "hg help add" to show the full help text
445 use "hg help add" to show the full help text
446 [255]
446 [255]
447
447
448 Test ambiguous command help
448 Test ambiguous command help
449
449
450 $ hg help ad
450 $ hg help ad
451 list of commands:
451 list of commands:
452
452
453 add add the specified files on the next commit
453 add add the specified files on the next commit
454 addremove add all new files, delete all missing files
454 addremove add all new files, delete all missing files
455
455
456 use "hg -v help ad" to show builtin aliases and global options
456 use "hg -v help ad" to show builtin aliases and global options
457
457
458 Test command without options
458 Test command without options
459
459
460 $ hg help verify
460 $ hg help verify
461 hg verify
461 hg verify
462
462
463 verify the integrity of the repository
463 verify the integrity of the repository
464
464
465 Verify the integrity of the current repository.
465 Verify the integrity of the current repository.
466
466
467 This will perform an extensive check of the repository's integrity,
467 This will perform an extensive check of the repository's integrity,
468 validating the hashes and checksums of each entry in the changelog,
468 validating the hashes and checksums of each entry in the changelog,
469 manifest, and tracked files, as well as the integrity of their crosslinks
469 manifest, and tracked files, as well as the integrity of their crosslinks
470 and indices.
470 and indices.
471
471
472 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
472 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption for more
473 information about recovery from corruption of the repository.
473 information about recovery from corruption of the repository.
474
474
475 Returns 0 on success, 1 if errors are encountered.
475 Returns 0 on success, 1 if errors are encountered.
476
476
477 use "hg -v help verify" to show the global options
477 use "hg -v help verify" to show the global options
478
478
479 $ hg help diff
479 $ hg help diff
480 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
480 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
481
481
482 diff repository (or selected files)
482 diff repository (or selected files)
483
483
484 Show differences between revisions for the specified files.
484 Show differences between revisions for the specified files.
485
485
486 Differences between files are shown using the unified diff format.
486 Differences between files are shown using the unified diff format.
487
487
488 Note:
488 Note:
489 diff may generate unexpected results for merges, as it will default to
489 diff may generate unexpected results for merges, as it will default to
490 comparing against the working directory's first parent changeset if no
490 comparing against the working directory's first parent changeset if no
491 revisions are specified.
491 revisions are specified.
492
492
493 When two revision arguments are given, then changes are shown between
493 When two revision arguments are given, then changes are shown between
494 those revisions. If only one revision is specified then that revision is
494 those revisions. If only one revision is specified then that revision is
495 compared to the working directory, and, when no revisions are specified,
495 compared to the working directory, and, when no revisions are specified,
496 the working directory files are compared to its parent.
496 the working directory files are compared to its parent.
497
497
498 Alternatively you can specify -c/--change with a revision to see the
498 Alternatively you can specify -c/--change with a revision to see the
499 changes in that changeset relative to its first parent.
499 changes in that changeset relative to its first parent.
500
500
501 Without the -a/--text option, diff will avoid generating diffs of files it
501 Without the -a/--text option, diff will avoid generating diffs of files it
502 detects as binary. With -a, diff will generate a diff anyway, probably
502 detects as binary. With -a, diff will generate a diff anyway, probably
503 with undesirable results.
503 with undesirable results.
504
504
505 Use the -g/--git option to generate diffs in the git extended diff format.
505 Use the -g/--git option to generate diffs in the git extended diff format.
506 For more information, read "hg help diffs".
506 For more information, read "hg help diffs".
507
507
508 Returns 0 on success.
508 Returns 0 on success.
509
509
510 options:
510 options:
511
511
512 -r --rev REV [+] revision
512 -r --rev REV [+] revision
513 -c --change REV change made by revision
513 -c --change REV change made by revision
514 -a --text treat all files as text
514 -a --text treat all files as text
515 -g --git use git extended diff format
515 -g --git use git extended diff format
516 --nodates omit dates from diff headers
516 --nodates omit dates from diff headers
517 -p --show-function show which function each change is in
517 -p --show-function show which function each change is in
518 --reverse produce a diff that undoes the changes
518 --reverse produce a diff that undoes the changes
519 -w --ignore-all-space ignore white space when comparing lines
519 -w --ignore-all-space ignore white space when comparing lines
520 -b --ignore-space-change ignore changes in the amount of white space
520 -b --ignore-space-change ignore changes in the amount of white space
521 -B --ignore-blank-lines ignore changes whose lines are all blank
521 -B --ignore-blank-lines ignore changes whose lines are all blank
522 -U --unified NUM number of lines of context to show
522 -U --unified NUM number of lines of context to show
523 --stat output diffstat-style summary of changes
523 --stat output diffstat-style summary of changes
524 -I --include PATTERN [+] include names matching the given patterns
524 -I --include PATTERN [+] include names matching the given patterns
525 -X --exclude PATTERN [+] exclude names matching the given patterns
525 -X --exclude PATTERN [+] exclude names matching the given patterns
526 -S --subrepos recurse into subrepositories
526 -S --subrepos recurse into subrepositories
527
527
528 [+] marked option can be specified multiple times
528 [+] marked option can be specified multiple times
529
529
530 use "hg -v help diff" to show more complete help and the global options
530 use "hg -v help diff" to show more complete help and the global options
531
531
532 $ hg help status
532 $ hg help status
533 hg status [OPTION]... [FILE]...
533 hg status [OPTION]... [FILE]...
534
534
535 aliases: st
535 aliases: st
536
536
537 show changed files in the working directory
537 show changed files in the working directory
538
538
539 Show status of files in the repository. If names are given, only files
539 Show status of files in the repository. If names are given, only files
540 that match are shown. Files that are clean or ignored or the source of a
540 that match are shown. Files that are clean or ignored or the source of a
541 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
541 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
542 -C/--copies or -A/--all are given. Unless options described with "show
542 -C/--copies or -A/--all are given. Unless options described with "show
543 only ..." are given, the options -mardu are used.
543 only ..." are given, the options -mardu are used.
544
544
545 Option -q/--quiet hides untracked (unknown and ignored) files unless
545 Option -q/--quiet hides untracked (unknown and ignored) files unless
546 explicitly requested with -u/--unknown or -i/--ignored.
546 explicitly requested with -u/--unknown or -i/--ignored.
547
547
548 Note:
548 Note:
549 status may appear to disagree with diff if permissions have changed or
549 status may appear to disagree with diff if permissions have changed or
550 a merge has occurred. The standard diff format does not report
550 a merge has occurred. The standard diff format does not report
551 permission changes and diff only reports changes relative to one merge
551 permission changes and diff only reports changes relative to one merge
552 parent.
552 parent.
553
553
554 If one revision is given, it is used as the base revision. If two
554 If one revision is given, it is used as the base revision. If two
555 revisions are given, the differences between them are shown. The --change
555 revisions are given, the differences between them are shown. The --change
556 option can also be used as a shortcut to list the changed files of a
556 option can also be used as a shortcut to list the changed files of a
557 revision from its first parent.
557 revision from its first parent.
558
558
559 The codes used to show the status of files are:
559 The codes used to show the status of files are:
560
560
561 M = modified
561 M = modified
562 A = added
562 A = added
563 R = removed
563 R = removed
564 C = clean
564 C = clean
565 ! = missing (deleted by non-hg command, but still tracked)
565 ! = missing (deleted by non-hg command, but still tracked)
566 ? = not tracked
566 ? = not tracked
567 I = ignored
567 I = ignored
568 = origin of the previous file listed as A (added)
568 = origin of the previous file listed as A (added)
569
569
570 Returns 0 on success.
570 Returns 0 on success.
571
571
572 options:
572 options:
573
573
574 -A --all show status of all files
574 -A --all show status of all files
575 -m --modified show only modified files
575 -m --modified show only modified files
576 -a --added show only added files
576 -a --added show only added files
577 -r --removed show only removed files
577 -r --removed show only removed files
578 -d --deleted show only deleted (but tracked) files
578 -d --deleted show only deleted (but tracked) files
579 -c --clean show only files without changes
579 -c --clean show only files without changes
580 -u --unknown show only unknown (not tracked) files
580 -u --unknown show only unknown (not tracked) files
581 -i --ignored show only ignored files
581 -i --ignored show only ignored files
582 -n --no-status hide status prefix
582 -n --no-status hide status prefix
583 -C --copies show source of copied files
583 -C --copies show source of copied files
584 -0 --print0 end filenames with NUL, for use with xargs
584 -0 --print0 end filenames with NUL, for use with xargs
585 --rev REV [+] show difference from revision
585 --rev REV [+] show difference from revision
586 --change REV list the changed files of a revision
586 --change REV list the changed files of a revision
587 -I --include PATTERN [+] include names matching the given patterns
587 -I --include PATTERN [+] include names matching the given patterns
588 -X --exclude PATTERN [+] exclude names matching the given patterns
588 -X --exclude PATTERN [+] exclude names matching the given patterns
589 -S --subrepos recurse into subrepositories
589 -S --subrepos recurse into subrepositories
590
590
591 [+] marked option can be specified multiple times
591 [+] marked option can be specified multiple times
592
592
593 use "hg -v help status" to show more complete help and the global options
593 use "hg -v help status" to show more complete help and the global options
594
594
595 $ hg -q help status
595 $ hg -q help status
596 hg status [OPTION]... [FILE]...
596 hg status [OPTION]... [FILE]...
597
597
598 show changed files in the working directory
598 show changed files in the working directory
599
599
600 $ hg help foo
600 $ hg help foo
601 hg: unknown command 'foo'
601 hg: unknown command 'foo'
602 Mercurial Distributed SCM
602 Mercurial Distributed SCM
603
603
604 basic commands:
604 basic commands:
605
605
606 add add the specified files on the next commit
606 add add the specified files on the next commit
607 annotate show changeset information by line for each file
607 annotate show changeset information by line for each file
608 clone make a copy of an existing repository
608 clone make a copy of an existing repository
609 commit commit the specified files or all outstanding changes
609 commit commit the specified files or all outstanding changes
610 diff diff repository (or selected files)
610 diff diff repository (or selected files)
611 export dump the header and diffs for one or more changesets
611 export dump the header and diffs for one or more changesets
612 forget forget the specified files on the next commit
612 forget forget the specified files on the next commit
613 init create a new repository in the given directory
613 init create a new repository in the given directory
614 log show revision history of entire repository or files
614 log show revision history of entire repository or files
615 merge merge working directory with another revision
615 merge merge working directory with another revision
616 pull pull changes from the specified source
616 pull pull changes from the specified source
617 push push changes to the specified destination
617 push push changes to the specified destination
618 remove remove the specified files on the next commit
618 remove remove the specified files on the next commit
619 serve start stand-alone webserver
619 serve start stand-alone webserver
620 status show changed files in the working directory
620 status show changed files in the working directory
621 summary summarize working directory state
621 summary summarize working directory state
622 update update working directory (or switch revisions)
622 update update working directory (or switch revisions)
623
623
624 use "hg help" for the full list of commands or "hg -v" for details
624 use "hg help" for the full list of commands or "hg -v" for details
625 [255]
625 [255]
626
626
627 $ hg skjdfks
627 $ hg skjdfks
628 hg: unknown command 'skjdfks'
628 hg: unknown command 'skjdfks'
629 Mercurial Distributed SCM
629 Mercurial Distributed SCM
630
630
631 basic commands:
631 basic commands:
632
632
633 add add the specified files on the next commit
633 add add the specified files on the next commit
634 annotate show changeset information by line for each file
634 annotate show changeset information by line for each file
635 clone make a copy of an existing repository
635 clone make a copy of an existing repository
636 commit commit the specified files or all outstanding changes
636 commit commit the specified files or all outstanding changes
637 diff diff repository (or selected files)
637 diff diff repository (or selected files)
638 export dump the header and diffs for one or more changesets
638 export dump the header and diffs for one or more changesets
639 forget forget the specified files on the next commit
639 forget forget the specified files on the next commit
640 init create a new repository in the given directory
640 init create a new repository in the given directory
641 log show revision history of entire repository or files
641 log show revision history of entire repository or files
642 merge merge working directory with another revision
642 merge merge working directory with another revision
643 pull pull changes from the specified source
643 pull pull changes from the specified source
644 push push changes to the specified destination
644 push push changes to the specified destination
645 remove remove the specified files on the next commit
645 remove remove the specified files on the next commit
646 serve start stand-alone webserver
646 serve start stand-alone webserver
647 status show changed files in the working directory
647 status show changed files in the working directory
648 summary summarize working directory state
648 summary summarize working directory state
649 update update working directory (or switch revisions)
649 update update working directory (or switch revisions)
650
650
651 use "hg help" for the full list of commands or "hg -v" for details
651 use "hg help" for the full list of commands or "hg -v" for details
652 [255]
652 [255]
653
653
654 $ cat > helpext.py <<EOF
654 $ cat > helpext.py <<EOF
655 > import os
655 > import os
656 > from mercurial import commands
656 > from mercurial import commands
657 >
657 >
658 > def nohelp(ui, *args, **kwargs):
658 > def nohelp(ui, *args, **kwargs):
659 > pass
659 > pass
660 >
660 >
661 > cmdtable = {
661 > cmdtable = {
662 > "nohelp": (nohelp, [], "hg nohelp"),
662 > "nohelp": (nohelp, [], "hg nohelp"),
663 > }
663 > }
664 >
664 >
665 > commands.norepo += ' nohelp'
665 > commands.norepo += ' nohelp'
666 > EOF
666 > EOF
667 $ echo '[extensions]' >> $HGRCPATH
667 $ echo '[extensions]' >> $HGRCPATH
668 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
668 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
669
669
670 Test command with no help text
670 Test command with no help text
671
671
672 $ hg help nohelp
672 $ hg help nohelp
673 hg nohelp
673 hg nohelp
674
674
675 (no help text available)
675 (no help text available)
676
676
677 use "hg -v help nohelp" to show the global options
677 use "hg -v help nohelp" to show the global options
678
678
679 $ hg help -k nohelp
679 $ hg help -k nohelp
680 Commands:
680 Commands:
681
681
682 nohelp hg nohelp
682 nohelp hg nohelp
683
683
684 Extension Commands:
684 Extension Commands:
685
685
686 nohelp (no help text available)
686 nohelp (no help text available)
687
687
688 Test that default list of commands omits extension commands
688 Test that default list of commands omits extension commands
689
689
690 $ hg help
690 $ hg help
691 Mercurial Distributed SCM
691 Mercurial Distributed SCM
692
692
693 list of commands:
693 list of commands:
694
694
695 add add the specified files on the next commit
695 add add the specified files on the next commit
696 addremove add all new files, delete all missing files
696 addremove add all new files, delete all missing files
697 annotate show changeset information by line for each file
697 annotate show changeset information by line for each file
698 archive create an unversioned archive of a repository revision
698 archive create an unversioned archive of a repository revision
699 backout reverse effect of earlier changeset
699 backout reverse effect of earlier changeset
700 bisect subdivision search of changesets
700 bisect subdivision search of changesets
701 bookmarks track a line of development with movable markers
701 bookmarks track a line of development with movable markers
702 branch set or show the current branch name
702 branch set or show the current branch name
703 branches list repository named branches
703 branches list repository named branches
704 bundle create a changegroup file
704 bundle create a changegroup file
705 cat output the current or given revision of files
705 cat output the current or given revision of files
706 clone make a copy of an existing repository
706 clone make a copy of an existing repository
707 commit commit the specified files or all outstanding changes
707 commit commit the specified files or all outstanding changes
708 config show combined config settings from all hgrc files
708 config show combined config settings from all hgrc files
709 copy mark files as copied for the next commit
709 copy mark files as copied for the next commit
710 diff diff repository (or selected files)
710 diff diff repository (or selected files)
711 export dump the header and diffs for one or more changesets
711 export dump the header and diffs for one or more changesets
712 forget forget the specified files on the next commit
712 forget forget the specified files on the next commit
713 graft copy changes from other branches onto the current branch
713 graft copy changes from other branches onto the current branch
714 grep search for a pattern in specified files and revisions
714 grep search for a pattern in specified files and revisions
715 heads show branch heads
715 heads show branch heads
716 help show help for a given topic or a help overview
716 help show help for a given topic or a help overview
717 identify identify the working copy or specified revision
717 identify identify the working copy or specified revision
718 import import an ordered set of patches
718 import import an ordered set of patches
719 incoming show new changesets found in source
719 incoming show new changesets found in source
720 init create a new repository in the given directory
720 init create a new repository in the given directory
721 locate locate files matching specific patterns
721 locate locate files matching specific patterns
722 log show revision history of entire repository or files
722 log show revision history of entire repository or files
723 manifest output the current or given revision of the project manifest
723 manifest output the current or given revision of the project manifest
724 merge merge working directory with another revision
724 merge merge working directory with another revision
725 outgoing show changesets not found in the destination
725 outgoing show changesets not found in the destination
726 parents show the parents of the working directory or revision
726 parents show the parents of the working directory or revision
727 paths show aliases for remote repositories
727 paths show aliases for remote repositories
728 phase set or show the current phase name
728 phase set or show the current phase name
729 pull pull changes from the specified source
729 pull pull changes from the specified source
730 push push changes to the specified destination
730 push push changes to the specified destination
731 recover roll back an interrupted transaction
731 recover roll back an interrupted transaction
732 remove remove the specified files on the next commit
732 remove remove the specified files on the next commit
733 rename rename files; equivalent of copy + remove
733 rename rename files; equivalent of copy + remove
734 resolve redo merges or set/view the merge status of files
734 resolve redo merges or set/view the merge status of files
735 revert restore files to their checkout state
735 revert restore files to their checkout state
736 root print the root (top) of the current working directory
736 root print the root (top) of the current working directory
737 serve start stand-alone webserver
737 serve start stand-alone webserver
738 status show changed files in the working directory
738 status show changed files in the working directory
739 summary summarize working directory state
739 summary summarize working directory state
740 tag add one or more tags for the current or given revision
740 tag add one or more tags for the current or given revision
741 tags list repository tags
741 tags list repository tags
742 unbundle apply one or more changegroup files
742 unbundle apply one or more changegroup files
743 update update working directory (or switch revisions)
743 update update working directory (or switch revisions)
744 verify verify the integrity of the repository
744 verify verify the integrity of the repository
745 version output version and copyright information
745 version output version and copyright information
746
746
747 enabled extensions:
747 enabled extensions:
748
748
749 helpext (no help text available)
749 helpext (no help text available)
750
750
751 additional help topics:
751 additional help topics:
752
752
753 config Configuration Files
753 config Configuration Files
754 dates Date Formats
754 dates Date Formats
755 diffs Diff Formats
755 diffs Diff Formats
756 environment Environment Variables
756 environment Environment Variables
757 extensions Using Additional Features
757 extensions Using Additional Features
758 filesets Specifying File Sets
758 filesets Specifying File Sets
759 glossary Glossary
759 glossary Glossary
760 hgignore Syntax for Mercurial Ignore Files
760 hgignore Syntax for Mercurial Ignore Files
761 hgweb Configuring hgweb
761 hgweb Configuring hgweb
762 merge-tools Merge Tools
762 merge-tools Merge Tools
763 multirevs Specifying Multiple Revisions
763 multirevs Specifying Multiple Revisions
764 patterns File Name Patterns
764 patterns File Name Patterns
765 phases Working with Phases
765 phases Working with Phases
766 revisions Specifying Single Revisions
766 revisions Specifying Single Revisions
767 revsets Specifying Revision Sets
767 revsets Specifying Revision Sets
768 subrepos Subrepositories
768 subrepos Subrepositories
769 templating Template Usage
769 templating Template Usage
770 urls URL Paths
770 urls URL Paths
771
771
772 use "hg -v help" to show builtin aliases and global options
772 use "hg -v help" to show builtin aliases and global options
773
773
774
774
775
775
776 Test list of commands with command with no help text
776 Test list of commands with command with no help text
777
777
778 $ hg help helpext
778 $ hg help helpext
779 helpext extension - no help text available
779 helpext extension - no help text available
780
780
781 list of commands:
781 list of commands:
782
782
783 nohelp (no help text available)
783 nohelp (no help text available)
784
784
785 use "hg -v help helpext" to show builtin aliases and global options
785 use "hg -v help helpext" to show builtin aliases and global options
786
786
787 Test a help topic
787 Test a help topic
788
788
789 $ hg help revs
789 $ hg help revs
790 Specifying Single Revisions
790 Specifying Single Revisions
791 """""""""""""""""""""""""""
791 """""""""""""""""""""""""""
792
792
793 Mercurial supports several ways to specify individual revisions.
793 Mercurial supports several ways to specify individual revisions.
794
794
795 A plain integer is treated as a revision number. Negative integers are
795 A plain integer is treated as a revision number. Negative integers are
796 treated as sequential offsets from the tip, with -1 denoting the tip, -2
796 treated as sequential offsets from the tip, with -1 denoting the tip, -2
797 denoting the revision prior to the tip, and so forth.
797 denoting the revision prior to the tip, and so forth.
798
798
799 A 40-digit hexadecimal string is treated as a unique revision identifier.
799 A 40-digit hexadecimal string is treated as a unique revision identifier.
800
800
801 A hexadecimal string less than 40 characters long is treated as a unique
801 A hexadecimal string less than 40 characters long is treated as a unique
802 revision identifier and is referred to as a short-form identifier. A
802 revision identifier and is referred to as a short-form identifier. A
803 short-form identifier is only valid if it is the prefix of exactly one
803 short-form identifier is only valid if it is the prefix of exactly one
804 full-length identifier.
804 full-length identifier.
805
805
806 Any other string is treated as a bookmark, tag, or branch name. A bookmark
806 Any other string is treated as a bookmark, tag, or branch name. A bookmark
807 is a movable pointer to a revision. A tag is a permanent name associated
807 is a movable pointer to a revision. A tag is a permanent name associated
808 with a revision. A branch name denotes the tipmost open branch head of
808 with a revision. A branch name denotes the tipmost open branch head of
809 that branch - or if they are all closed, the tipmost closed head of the
809 that branch - or if they are all closed, the tipmost closed head of the
810 branch. Bookmark, tag, and branch names must not contain the ":"
810 branch. Bookmark, tag, and branch names must not contain the ":"
811 character.
811 character.
812
812
813 The reserved name "tip" always identifies the most recent revision.
813 The reserved name "tip" always identifies the most recent revision.
814
814
815 The reserved name "null" indicates the null revision. This is the revision
815 The reserved name "null" indicates the null revision. This is the revision
816 of an empty repository, and the parent of revision 0.
816 of an empty repository, and the parent of revision 0.
817
817
818 The reserved name "." indicates the working directory parent. If no
818 The reserved name "." indicates the working directory parent. If no
819 working directory is checked out, it is equivalent to null. If an
819 working directory is checked out, it is equivalent to null. If an
820 uncommitted merge is in progress, "." is the revision of the first parent.
820 uncommitted merge is in progress, "." is the revision of the first parent.
821
821
822 Test templating help
822 Test templating help
823
823
824 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
824 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
825 desc String. The text of the changeset description.
825 desc String. The text of the changeset description.
826 diffstat String. Statistics of changes with the following format:
826 diffstat String. Statistics of changes with the following format:
827 firstline Any text. Returns the first line of text.
827 firstline Any text. Returns the first line of text.
828 nonempty Any text. Returns '(none)' if the string is empty.
828 nonempty Any text. Returns '(none)' if the string is empty.
829
829
830 Test help hooks
830 Test help hooks
831
831
832 $ cat > helphook1.py <<EOF
832 $ cat > helphook1.py <<EOF
833 > from mercurial import help
833 > from mercurial import help
834 >
834 >
835 > def rewrite(topic, doc):
835 > def rewrite(topic, doc):
836 > return doc + '\nhelphook1\n'
836 > return doc + '\nhelphook1\n'
837 >
837 >
838 > def extsetup(ui):
838 > def extsetup(ui):
839 > help.addtopichook('revsets', rewrite)
839 > help.addtopichook('revsets', rewrite)
840 > EOF
840 > EOF
841 $ cat > helphook2.py <<EOF
841 $ cat > helphook2.py <<EOF
842 > from mercurial import help
842 > from mercurial import help
843 >
843 >
844 > def rewrite(topic, doc):
844 > def rewrite(topic, doc):
845 > return doc + '\nhelphook2\n'
845 > return doc + '\nhelphook2\n'
846 >
846 >
847 > def extsetup(ui):
847 > def extsetup(ui):
848 > help.addtopichook('revsets', rewrite)
848 > help.addtopichook('revsets', rewrite)
849 > EOF
849 > EOF
850 $ echo '[extensions]' >> $HGRCPATH
850 $ echo '[extensions]' >> $HGRCPATH
851 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
851 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
852 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
852 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
853 $ hg help revsets | grep helphook
853 $ hg help revsets | grep helphook
854 helphook1
854 helphook1
855 helphook2
855 helphook2
856
856
857 Test keyword search help
857 Test keyword search help
858
858
859 $ cat > prefixedname.py <<EOF
859 $ cat > prefixedname.py <<EOF
860 > '''matched against word "clone"
860 > '''matched against word "clone"
861 > '''
861 > '''
862 > EOF
862 > EOF
863 $ echo '[extensions]' >> $HGRCPATH
863 $ echo '[extensions]' >> $HGRCPATH
864 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
864 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
865 $ hg help -k clone
865 $ hg help -k clone
866 Topics:
866 Topics:
867
867
868 config Configuration Files
868 config Configuration Files
869 extensions Using Additional Features
869 extensions Using Additional Features
870 glossary Glossary
870 glossary Glossary
871 phases Working with Phases
871 phases Working with Phases
872 subrepos Subrepositories
872 subrepos Subrepositories
873 urls URL Paths
873 urls URL Paths
874
874
875 Commands:
875 Commands:
876
876
877 bookmarks track a line of development with movable markers
877 bookmarks track a line of development with movable markers
878 clone make a copy of an existing repository
878 clone make a copy of an existing repository
879 paths show aliases for remote repositories
879 paths show aliases for remote repositories
880 update update working directory (or switch revisions)
880 update update working directory (or switch revisions)
881
881
882 Extensions:
882 Extensions:
883
883
884 prefixedname matched against word "clone"
884 prefixedname matched against word "clone"
885 relink recreates hardlinks between repository clones
885 relink recreates hardlinks between repository clones
886
886
887 Extension Commands:
887 Extension Commands:
888
888
889 qclone clone main and patch repository at same time
889 qclone clone main and patch repository at same time
890
890
891 Test omit indicating for help
891 Test omit indicating for help
892
892
893 $ cat > addverboseitems.py <<EOF
893 $ cat > addverboseitems.py <<EOF
894 > '''extension to test omit indicating.
894 > '''extension to test omit indicating.
895 >
895 >
896 > This paragraph is never omitted (for extension)
896 > This paragraph is never omitted (for extension)
897 >
897 >
898 > .. container:: verbose
898 > .. container:: verbose
899 >
899 >
900 > This paragraph is omitted,
900 > This paragraph is omitted,
901 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
901 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for extension)
902 >
902 >
903 > This paragraph is never omitted, too (for extension)
903 > This paragraph is never omitted, too (for extension)
904 > '''
904 > '''
905 >
905 >
906 > from mercurial import help, commands
906 > from mercurial import help, commands
907 > testtopic = """This paragraph is never omitted (for topic).
907 > testtopic = """This paragraph is never omitted (for topic).
908 >
908 >
909 > .. container:: verbose
909 > .. container:: verbose
910 >
910 >
911 > This paragraph is omitted,
911 > This paragraph is omitted,
912 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
912 > if :hg:\`help\` is invoked witout \`\`-v\`\` (for topic)
913 >
913 >
914 > This paragraph is never omitted, too (for topic)
914 > This paragraph is never omitted, too (for topic)
915 > """
915 > """
916 > def extsetup(ui):
916 > def extsetup(ui):
917 > help.helptable.append((["topic-containing-verbose"],
917 > help.helptable.append((["topic-containing-verbose"],
918 > "This is the topic to test omit indicating.",
918 > "This is the topic to test omit indicating.",
919 > lambda : testtopic))
919 > lambda : testtopic))
920 > EOF
920 > EOF
921 $ echo '[extensions]' >> $HGRCPATH
921 $ echo '[extensions]' >> $HGRCPATH
922 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
922 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
923 $ hg help addverboseitems
923 $ hg help addverboseitems
924 addverboseitems extension - extension to test omit indicating.
924 addverboseitems extension - extension to test omit indicating.
925
925
926 This paragraph is never omitted (for extension)
926 This paragraph is never omitted (for extension)
927
927
928 This paragraph is never omitted, too (for extension)
928 This paragraph is never omitted, too (for extension)
929
929
930 use "hg help -v addverboseitems" to show more complete help
930 use "hg help -v addverboseitems" to show more complete help
931
931
932 no commands defined
932 no commands defined
933 $ hg help -v addverboseitems
933 $ hg help -v addverboseitems
934 addverboseitems extension - extension to test omit indicating.
934 addverboseitems extension - extension to test omit indicating.
935
935
936 This paragraph is never omitted (for extension)
936 This paragraph is never omitted (for extension)
937
937
938 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
938 This paragraph is omitted, if "hg help" is invoked witout "-v" (for extension)
939
939
940 This paragraph is never omitted, too (for extension)
940 This paragraph is never omitted, too (for extension)
941
941
942 no commands defined
942 no commands defined
943 $ hg help topic-containing-verbose
943 $ hg help topic-containing-verbose
944 This is the topic to test omit indicating.
944 This is the topic to test omit indicating.
945 """"""""""""""""""""""""""""""""""""""""""
945 """"""""""""""""""""""""""""""""""""""""""
946
946
947 This paragraph is never omitted (for topic).
947 This paragraph is never omitted (for topic).
948
948
949 This paragraph is never omitted, too (for topic)
949 This paragraph is never omitted, too (for topic)
950
950
951 use "hg help -v topic-containing-verbose" to show more complete help
951 use "hg help -v topic-containing-verbose" to show more complete help
952 $ hg help -v topic-containing-verbose
952 $ hg help -v topic-containing-verbose
953 This is the topic to test omit indicating.
953 This is the topic to test omit indicating.
954 """"""""""""""""""""""""""""""""""""""""""
954 """"""""""""""""""""""""""""""""""""""""""
955
955
956 This paragraph is never omitted (for topic).
956 This paragraph is never omitted (for topic).
957
957
958 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
958 This paragraph is omitted, if "hg help" is invoked witout "-v" (for topic)
959
959
960 This paragraph is never omitted, too (for topic)
960 This paragraph is never omitted, too (for topic)
961
961
962 Test usage of section marks in help documents
962 Test usage of section marks in help documents
963
963
964 $ cd "$TESTDIR"/../doc
964 $ cd "$TESTDIR"/../doc
965 $ python check-seclevel.py
965 $ python check-seclevel.py
966 $ cd $TESTTMP
966 $ cd $TESTTMP
967
967
968 #if serve
968 #if serve
969
969
970 Test the help pages in hgweb.
970 Test the help pages in hgweb.
971
971
972 Dish up an empty repo; serve it cold.
972 Dish up an empty repo; serve it cold.
973
973
974 $ hg init "$TESTTMP/test"
974 $ hg init "$TESTTMP/test"
975 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
975 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
976 $ cat hg.pid >> $DAEMON_PIDS
976 $ cat hg.pid >> $DAEMON_PIDS
977
977
978 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help"
978 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help"
979 200 Script output follows
979 200 Script output follows
980
980
981 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
981 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
982 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
982 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
983 <head>
983 <head>
984 <link rel="icon" href="/static/hgicon.png" type="image/png" />
984 <link rel="icon" href="/static/hgicon.png" type="image/png" />
985 <meta name="robots" content="index, nofollow" />
985 <meta name="robots" content="index, nofollow" />
986 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
986 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
987 <script type="text/javascript" src="/static/mercurial.js"></script>
987 <script type="text/javascript" src="/static/mercurial.js"></script>
988
988
989 <title>Help: Index</title>
989 <title>Help: Index</title>
990 </head>
990 </head>
991 <body>
991 <body>
992
992
993 <div class="container">
993 <div class="container">
994 <div class="menu">
994 <div class="menu">
995 <div class="logo">
995 <div class="logo">
996 <a href="http://mercurial.selenic.com/">
996 <a href="http://mercurial.selenic.com/">
997 <img src="/static/hglogo.png" alt="mercurial" /></a>
997 <img src="/static/hglogo.png" alt="mercurial" /></a>
998 </div>
998 </div>
999 <ul>
999 <ul>
1000 <li><a href="/shortlog">log</a></li>
1000 <li><a href="/shortlog">log</a></li>
1001 <li><a href="/graph">graph</a></li>
1001 <li><a href="/graph">graph</a></li>
1002 <li><a href="/tags">tags</a></li>
1002 <li><a href="/tags">tags</a></li>
1003 <li><a href="/bookmarks">bookmarks</a></li>
1003 <li><a href="/bookmarks">bookmarks</a></li>
1004 <li><a href="/branches">branches</a></li>
1004 <li><a href="/branches">branches</a></li>
1005 </ul>
1005 </ul>
1006 <ul>
1006 <ul>
1007 <li class="active">help</li>
1007 <li class="active">help</li>
1008 </ul>
1008 </ul>
1009 </div>
1009 </div>
1010
1010
1011 <div class="main">
1011 <div class="main">
1012 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1012 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1013 <form class="search" action="/log">
1013 <form class="search" action="/log">
1014
1014
1015 <p><input name="rev" id="search1" type="text" size="30" /></p>
1015 <p><input name="rev" id="search1" type="text" size="30" /></p>
1016 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1016 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1017 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1017 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1018 </form>
1018 </form>
1019 <table class="bigtable">
1019 <table class="bigtable">
1020 <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr>
1020 <tr><td colspan="2"><h2><a name="main" href="#topics">Topics</a></h2></td></tr>
1021
1021
1022 <tr><td>
1022 <tr><td>
1023 <a href="/help/config">
1023 <a href="/help/config">
1024 config
1024 config
1025 </a>
1025 </a>
1026 </td><td>
1026 </td><td>
1027 Configuration Files
1027 Configuration Files
1028 </td></tr>
1028 </td></tr>
1029 <tr><td>
1029 <tr><td>
1030 <a href="/help/dates">
1030 <a href="/help/dates">
1031 dates
1031 dates
1032 </a>
1032 </a>
1033 </td><td>
1033 </td><td>
1034 Date Formats
1034 Date Formats
1035 </td></tr>
1035 </td></tr>
1036 <tr><td>
1036 <tr><td>
1037 <a href="/help/diffs">
1037 <a href="/help/diffs">
1038 diffs
1038 diffs
1039 </a>
1039 </a>
1040 </td><td>
1040 </td><td>
1041 Diff Formats
1041 Diff Formats
1042 </td></tr>
1042 </td></tr>
1043 <tr><td>
1043 <tr><td>
1044 <a href="/help/environment">
1044 <a href="/help/environment">
1045 environment
1045 environment
1046 </a>
1046 </a>
1047 </td><td>
1047 </td><td>
1048 Environment Variables
1048 Environment Variables
1049 </td></tr>
1049 </td></tr>
1050 <tr><td>
1050 <tr><td>
1051 <a href="/help/extensions">
1051 <a href="/help/extensions">
1052 extensions
1052 extensions
1053 </a>
1053 </a>
1054 </td><td>
1054 </td><td>
1055 Using Additional Features
1055 Using Additional Features
1056 </td></tr>
1056 </td></tr>
1057 <tr><td>
1057 <tr><td>
1058 <a href="/help/filesets">
1058 <a href="/help/filesets">
1059 filesets
1059 filesets
1060 </a>
1060 </a>
1061 </td><td>
1061 </td><td>
1062 Specifying File Sets
1062 Specifying File Sets
1063 </td></tr>
1063 </td></tr>
1064 <tr><td>
1064 <tr><td>
1065 <a href="/help/glossary">
1065 <a href="/help/glossary">
1066 glossary
1066 glossary
1067 </a>
1067 </a>
1068 </td><td>
1068 </td><td>
1069 Glossary
1069 Glossary
1070 </td></tr>
1070 </td></tr>
1071 <tr><td>
1071 <tr><td>
1072 <a href="/help/hgignore">
1072 <a href="/help/hgignore">
1073 hgignore
1073 hgignore
1074 </a>
1074 </a>
1075 </td><td>
1075 </td><td>
1076 Syntax for Mercurial Ignore Files
1076 Syntax for Mercurial Ignore Files
1077 </td></tr>
1077 </td></tr>
1078 <tr><td>
1078 <tr><td>
1079 <a href="/help/hgweb">
1079 <a href="/help/hgweb">
1080 hgweb
1080 hgweb
1081 </a>
1081 </a>
1082 </td><td>
1082 </td><td>
1083 Configuring hgweb
1083 Configuring hgweb
1084 </td></tr>
1084 </td></tr>
1085 <tr><td>
1085 <tr><td>
1086 <a href="/help/merge-tools">
1086 <a href="/help/merge-tools">
1087 merge-tools
1087 merge-tools
1088 </a>
1088 </a>
1089 </td><td>
1089 </td><td>
1090 Merge Tools
1090 Merge Tools
1091 </td></tr>
1091 </td></tr>
1092 <tr><td>
1092 <tr><td>
1093 <a href="/help/multirevs">
1093 <a href="/help/multirevs">
1094 multirevs
1094 multirevs
1095 </a>
1095 </a>
1096 </td><td>
1096 </td><td>
1097 Specifying Multiple Revisions
1097 Specifying Multiple Revisions
1098 </td></tr>
1098 </td></tr>
1099 <tr><td>
1099 <tr><td>
1100 <a href="/help/patterns">
1100 <a href="/help/patterns">
1101 patterns
1101 patterns
1102 </a>
1102 </a>
1103 </td><td>
1103 </td><td>
1104 File Name Patterns
1104 File Name Patterns
1105 </td></tr>
1105 </td></tr>
1106 <tr><td>
1106 <tr><td>
1107 <a href="/help/phases">
1107 <a href="/help/phases">
1108 phases
1108 phases
1109 </a>
1109 </a>
1110 </td><td>
1110 </td><td>
1111 Working with Phases
1111 Working with Phases
1112 </td></tr>
1112 </td></tr>
1113 <tr><td>
1113 <tr><td>
1114 <a href="/help/revisions">
1114 <a href="/help/revisions">
1115 revisions
1115 revisions
1116 </a>
1116 </a>
1117 </td><td>
1117 </td><td>
1118 Specifying Single Revisions
1118 Specifying Single Revisions
1119 </td></tr>
1119 </td></tr>
1120 <tr><td>
1120 <tr><td>
1121 <a href="/help/revsets">
1121 <a href="/help/revsets">
1122 revsets
1122 revsets
1123 </a>
1123 </a>
1124 </td><td>
1124 </td><td>
1125 Specifying Revision Sets
1125 Specifying Revision Sets
1126 </td></tr>
1126 </td></tr>
1127 <tr><td>
1127 <tr><td>
1128 <a href="/help/subrepos">
1128 <a href="/help/subrepos">
1129 subrepos
1129 subrepos
1130 </a>
1130 </a>
1131 </td><td>
1131 </td><td>
1132 Subrepositories
1132 Subrepositories
1133 </td></tr>
1133 </td></tr>
1134 <tr><td>
1134 <tr><td>
1135 <a href="/help/templating">
1135 <a href="/help/templating">
1136 templating
1136 templating
1137 </a>
1137 </a>
1138 </td><td>
1138 </td><td>
1139 Template Usage
1139 Template Usage
1140 </td></tr>
1140 </td></tr>
1141 <tr><td>
1141 <tr><td>
1142 <a href="/help/urls">
1142 <a href="/help/urls">
1143 urls
1143 urls
1144 </a>
1144 </a>
1145 </td><td>
1145 </td><td>
1146 URL Paths
1146 URL Paths
1147 </td></tr>
1147 </td></tr>
1148 <tr><td>
1148 <tr><td>
1149 <a href="/help/topic-containing-verbose">
1149 <a href="/help/topic-containing-verbose">
1150 topic-containing-verbose
1150 topic-containing-verbose
1151 </a>
1151 </a>
1152 </td><td>
1152 </td><td>
1153 This is the topic to test omit indicating.
1153 This is the topic to test omit indicating.
1154 </td></tr>
1154 </td></tr>
1155
1155
1156 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
1156 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
1157
1157
1158 <tr><td>
1158 <tr><td>
1159 <a href="/help/add">
1159 <a href="/help/add">
1160 add
1160 add
1161 </a>
1161 </a>
1162 </td><td>
1162 </td><td>
1163 add the specified files on the next commit
1163 add the specified files on the next commit
1164 </td></tr>
1164 </td></tr>
1165 <tr><td>
1165 <tr><td>
1166 <a href="/help/annotate">
1166 <a href="/help/annotate">
1167 annotate
1167 annotate
1168 </a>
1168 </a>
1169 </td><td>
1169 </td><td>
1170 show changeset information by line for each file
1170 show changeset information by line for each file
1171 </td></tr>
1171 </td></tr>
1172 <tr><td>
1172 <tr><td>
1173 <a href="/help/clone">
1173 <a href="/help/clone">
1174 clone
1174 clone
1175 </a>
1175 </a>
1176 </td><td>
1176 </td><td>
1177 make a copy of an existing repository
1177 make a copy of an existing repository
1178 </td></tr>
1178 </td></tr>
1179 <tr><td>
1179 <tr><td>
1180 <a href="/help/commit">
1180 <a href="/help/commit">
1181 commit
1181 commit
1182 </a>
1182 </a>
1183 </td><td>
1183 </td><td>
1184 commit the specified files or all outstanding changes
1184 commit the specified files or all outstanding changes
1185 </td></tr>
1185 </td></tr>
1186 <tr><td>
1186 <tr><td>
1187 <a href="/help/diff">
1187 <a href="/help/diff">
1188 diff
1188 diff
1189 </a>
1189 </a>
1190 </td><td>
1190 </td><td>
1191 diff repository (or selected files)
1191 diff repository (or selected files)
1192 </td></tr>
1192 </td></tr>
1193 <tr><td>
1193 <tr><td>
1194 <a href="/help/export">
1194 <a href="/help/export">
1195 export
1195 export
1196 </a>
1196 </a>
1197 </td><td>
1197 </td><td>
1198 dump the header and diffs for one or more changesets
1198 dump the header and diffs for one or more changesets
1199 </td></tr>
1199 </td></tr>
1200 <tr><td>
1200 <tr><td>
1201 <a href="/help/forget">
1201 <a href="/help/forget">
1202 forget
1202 forget
1203 </a>
1203 </a>
1204 </td><td>
1204 </td><td>
1205 forget the specified files on the next commit
1205 forget the specified files on the next commit
1206 </td></tr>
1206 </td></tr>
1207 <tr><td>
1207 <tr><td>
1208 <a href="/help/init">
1208 <a href="/help/init">
1209 init
1209 init
1210 </a>
1210 </a>
1211 </td><td>
1211 </td><td>
1212 create a new repository in the given directory
1212 create a new repository in the given directory
1213 </td></tr>
1213 </td></tr>
1214 <tr><td>
1214 <tr><td>
1215 <a href="/help/log">
1215 <a href="/help/log">
1216 log
1216 log
1217 </a>
1217 </a>
1218 </td><td>
1218 </td><td>
1219 show revision history of entire repository or files
1219 show revision history of entire repository or files
1220 </td></tr>
1220 </td></tr>
1221 <tr><td>
1221 <tr><td>
1222 <a href="/help/merge">
1222 <a href="/help/merge">
1223 merge
1223 merge
1224 </a>
1224 </a>
1225 </td><td>
1225 </td><td>
1226 merge working directory with another revision
1226 merge working directory with another revision
1227 </td></tr>
1227 </td></tr>
1228 <tr><td>
1228 <tr><td>
1229 <a href="/help/pull">
1229 <a href="/help/pull">
1230 pull
1230 pull
1231 </a>
1231 </a>
1232 </td><td>
1232 </td><td>
1233 pull changes from the specified source
1233 pull changes from the specified source
1234 </td></tr>
1234 </td></tr>
1235 <tr><td>
1235 <tr><td>
1236 <a href="/help/push">
1236 <a href="/help/push">
1237 push
1237 push
1238 </a>
1238 </a>
1239 </td><td>
1239 </td><td>
1240 push changes to the specified destination
1240 push changes to the specified destination
1241 </td></tr>
1241 </td></tr>
1242 <tr><td>
1242 <tr><td>
1243 <a href="/help/remove">
1243 <a href="/help/remove">
1244 remove
1244 remove
1245 </a>
1245 </a>
1246 </td><td>
1246 </td><td>
1247 remove the specified files on the next commit
1247 remove the specified files on the next commit
1248 </td></tr>
1248 </td></tr>
1249 <tr><td>
1249 <tr><td>
1250 <a href="/help/serve">
1250 <a href="/help/serve">
1251 serve
1251 serve
1252 </a>
1252 </a>
1253 </td><td>
1253 </td><td>
1254 start stand-alone webserver
1254 start stand-alone webserver
1255 </td></tr>
1255 </td></tr>
1256 <tr><td>
1256 <tr><td>
1257 <a href="/help/status">
1257 <a href="/help/status">
1258 status
1258 status
1259 </a>
1259 </a>
1260 </td><td>
1260 </td><td>
1261 show changed files in the working directory
1261 show changed files in the working directory
1262 </td></tr>
1262 </td></tr>
1263 <tr><td>
1263 <tr><td>
1264 <a href="/help/summary">
1264 <a href="/help/summary">
1265 summary
1265 summary
1266 </a>
1266 </a>
1267 </td><td>
1267 </td><td>
1268 summarize working directory state
1268 summarize working directory state
1269 </td></tr>
1269 </td></tr>
1270 <tr><td>
1270 <tr><td>
1271 <a href="/help/update">
1271 <a href="/help/update">
1272 update
1272 update
1273 </a>
1273 </a>
1274 </td><td>
1274 </td><td>
1275 update working directory (or switch revisions)
1275 update working directory (or switch revisions)
1276 </td></tr>
1276 </td></tr>
1277
1277
1278 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
1278 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
1279
1279
1280 <tr><td>
1280 <tr><td>
1281 <a href="/help/addremove">
1281 <a href="/help/addremove">
1282 addremove
1282 addremove
1283 </a>
1283 </a>
1284 </td><td>
1284 </td><td>
1285 add all new files, delete all missing files
1285 add all new files, delete all missing files
1286 </td></tr>
1286 </td></tr>
1287 <tr><td>
1287 <tr><td>
1288 <a href="/help/archive">
1288 <a href="/help/archive">
1289 archive
1289 archive
1290 </a>
1290 </a>
1291 </td><td>
1291 </td><td>
1292 create an unversioned archive of a repository revision
1292 create an unversioned archive of a repository revision
1293 </td></tr>
1293 </td></tr>
1294 <tr><td>
1294 <tr><td>
1295 <a href="/help/backout">
1295 <a href="/help/backout">
1296 backout
1296 backout
1297 </a>
1297 </a>
1298 </td><td>
1298 </td><td>
1299 reverse effect of earlier changeset
1299 reverse effect of earlier changeset
1300 </td></tr>
1300 </td></tr>
1301 <tr><td>
1301 <tr><td>
1302 <a href="/help/bisect">
1302 <a href="/help/bisect">
1303 bisect
1303 bisect
1304 </a>
1304 </a>
1305 </td><td>
1305 </td><td>
1306 subdivision search of changesets
1306 subdivision search of changesets
1307 </td></tr>
1307 </td></tr>
1308 <tr><td>
1308 <tr><td>
1309 <a href="/help/bookmarks">
1309 <a href="/help/bookmarks">
1310 bookmarks
1310 bookmarks
1311 </a>
1311 </a>
1312 </td><td>
1312 </td><td>
1313 track a line of development with movable markers
1313 track a line of development with movable markers
1314 </td></tr>
1314 </td></tr>
1315 <tr><td>
1315 <tr><td>
1316 <a href="/help/branch">
1316 <a href="/help/branch">
1317 branch
1317 branch
1318 </a>
1318 </a>
1319 </td><td>
1319 </td><td>
1320 set or show the current branch name
1320 set or show the current branch name
1321 </td></tr>
1321 </td></tr>
1322 <tr><td>
1322 <tr><td>
1323 <a href="/help/branches">
1323 <a href="/help/branches">
1324 branches
1324 branches
1325 </a>
1325 </a>
1326 </td><td>
1326 </td><td>
1327 list repository named branches
1327 list repository named branches
1328 </td></tr>
1328 </td></tr>
1329 <tr><td>
1329 <tr><td>
1330 <a href="/help/bundle">
1330 <a href="/help/bundle">
1331 bundle
1331 bundle
1332 </a>
1332 </a>
1333 </td><td>
1333 </td><td>
1334 create a changegroup file
1334 create a changegroup file
1335 </td></tr>
1335 </td></tr>
1336 <tr><td>
1336 <tr><td>
1337 <a href="/help/cat">
1337 <a href="/help/cat">
1338 cat
1338 cat
1339 </a>
1339 </a>
1340 </td><td>
1340 </td><td>
1341 output the current or given revision of files
1341 output the current or given revision of files
1342 </td></tr>
1342 </td></tr>
1343 <tr><td>
1343 <tr><td>
1344 <a href="/help/config">
1344 <a href="/help/config">
1345 config
1345 config
1346 </a>
1346 </a>
1347 </td><td>
1347 </td><td>
1348 show combined config settings from all hgrc files
1348 show combined config settings from all hgrc files
1349 </td></tr>
1349 </td></tr>
1350 <tr><td>
1350 <tr><td>
1351 <a href="/help/copy">
1351 <a href="/help/copy">
1352 copy
1352 copy
1353 </a>
1353 </a>
1354 </td><td>
1354 </td><td>
1355 mark files as copied for the next commit
1355 mark files as copied for the next commit
1356 </td></tr>
1356 </td></tr>
1357 <tr><td>
1357 <tr><td>
1358 <a href="/help/graft">
1358 <a href="/help/graft">
1359 graft
1359 graft
1360 </a>
1360 </a>
1361 </td><td>
1361 </td><td>
1362 copy changes from other branches onto the current branch
1362 copy changes from other branches onto the current branch
1363 </td></tr>
1363 </td></tr>
1364 <tr><td>
1364 <tr><td>
1365 <a href="/help/grep">
1365 <a href="/help/grep">
1366 grep
1366 grep
1367 </a>
1367 </a>
1368 </td><td>
1368 </td><td>
1369 search for a pattern in specified files and revisions
1369 search for a pattern in specified files and revisions
1370 </td></tr>
1370 </td></tr>
1371 <tr><td>
1371 <tr><td>
1372 <a href="/help/heads">
1372 <a href="/help/heads">
1373 heads
1373 heads
1374 </a>
1374 </a>
1375 </td><td>
1375 </td><td>
1376 show branch heads
1376 show branch heads
1377 </td></tr>
1377 </td></tr>
1378 <tr><td>
1378 <tr><td>
1379 <a href="/help/help">
1379 <a href="/help/help">
1380 help
1380 help
1381 </a>
1381 </a>
1382 </td><td>
1382 </td><td>
1383 show help for a given topic or a help overview
1383 show help for a given topic or a help overview
1384 </td></tr>
1384 </td></tr>
1385 <tr><td>
1385 <tr><td>
1386 <a href="/help/identify">
1386 <a href="/help/identify">
1387 identify
1387 identify
1388 </a>
1388 </a>
1389 </td><td>
1389 </td><td>
1390 identify the working copy or specified revision
1390 identify the working copy or specified revision
1391 </td></tr>
1391 </td></tr>
1392 <tr><td>
1392 <tr><td>
1393 <a href="/help/import">
1393 <a href="/help/import">
1394 import
1394 import
1395 </a>
1395 </a>
1396 </td><td>
1396 </td><td>
1397 import an ordered set of patches
1397 import an ordered set of patches
1398 </td></tr>
1398 </td></tr>
1399 <tr><td>
1399 <tr><td>
1400 <a href="/help/incoming">
1400 <a href="/help/incoming">
1401 incoming
1401 incoming
1402 </a>
1402 </a>
1403 </td><td>
1403 </td><td>
1404 show new changesets found in source
1404 show new changesets found in source
1405 </td></tr>
1405 </td></tr>
1406 <tr><td>
1406 <tr><td>
1407 <a href="/help/locate">
1407 <a href="/help/locate">
1408 locate
1408 locate
1409 </a>
1409 </a>
1410 </td><td>
1410 </td><td>
1411 locate files matching specific patterns
1411 locate files matching specific patterns
1412 </td></tr>
1412 </td></tr>
1413 <tr><td>
1413 <tr><td>
1414 <a href="/help/manifest">
1414 <a href="/help/manifest">
1415 manifest
1415 manifest
1416 </a>
1416 </a>
1417 </td><td>
1417 </td><td>
1418 output the current or given revision of the project manifest
1418 output the current or given revision of the project manifest
1419 </td></tr>
1419 </td></tr>
1420 <tr><td>
1420 <tr><td>
1421 <a href="/help/nohelp">
1421 <a href="/help/nohelp">
1422 nohelp
1422 nohelp
1423 </a>
1423 </a>
1424 </td><td>
1424 </td><td>
1425 (no help text available)
1425 (no help text available)
1426 </td></tr>
1426 </td></tr>
1427 <tr><td>
1427 <tr><td>
1428 <a href="/help/outgoing">
1428 <a href="/help/outgoing">
1429 outgoing
1429 outgoing
1430 </a>
1430 </a>
1431 </td><td>
1431 </td><td>
1432 show changesets not found in the destination
1432 show changesets not found in the destination
1433 </td></tr>
1433 </td></tr>
1434 <tr><td>
1434 <tr><td>
1435 <a href="/help/parents">
1435 <a href="/help/parents">
1436 parents
1436 parents
1437 </a>
1437 </a>
1438 </td><td>
1438 </td><td>
1439 show the parents of the working directory or revision
1439 show the parents of the working directory or revision
1440 </td></tr>
1440 </td></tr>
1441 <tr><td>
1441 <tr><td>
1442 <a href="/help/paths">
1442 <a href="/help/paths">
1443 paths
1443 paths
1444 </a>
1444 </a>
1445 </td><td>
1445 </td><td>
1446 show aliases for remote repositories
1446 show aliases for remote repositories
1447 </td></tr>
1447 </td></tr>
1448 <tr><td>
1448 <tr><td>
1449 <a href="/help/phase">
1449 <a href="/help/phase">
1450 phase
1450 phase
1451 </a>
1451 </a>
1452 </td><td>
1452 </td><td>
1453 set or show the current phase name
1453 set or show the current phase name
1454 </td></tr>
1454 </td></tr>
1455 <tr><td>
1455 <tr><td>
1456 <a href="/help/recover">
1456 <a href="/help/recover">
1457 recover
1457 recover
1458 </a>
1458 </a>
1459 </td><td>
1459 </td><td>
1460 roll back an interrupted transaction
1460 roll back an interrupted transaction
1461 </td></tr>
1461 </td></tr>
1462 <tr><td>
1462 <tr><td>
1463 <a href="/help/rename">
1463 <a href="/help/rename">
1464 rename
1464 rename
1465 </a>
1465 </a>
1466 </td><td>
1466 </td><td>
1467 rename files; equivalent of copy + remove
1467 rename files; equivalent of copy + remove
1468 </td></tr>
1468 </td></tr>
1469 <tr><td>
1469 <tr><td>
1470 <a href="/help/resolve">
1470 <a href="/help/resolve">
1471 resolve
1471 resolve
1472 </a>
1472 </a>
1473 </td><td>
1473 </td><td>
1474 redo merges or set/view the merge status of files
1474 redo merges or set/view the merge status of files
1475 </td></tr>
1475 </td></tr>
1476 <tr><td>
1476 <tr><td>
1477 <a href="/help/revert">
1477 <a href="/help/revert">
1478 revert
1478 revert
1479 </a>
1479 </a>
1480 </td><td>
1480 </td><td>
1481 restore files to their checkout state
1481 restore files to their checkout state
1482 </td></tr>
1482 </td></tr>
1483 <tr><td>
1483 <tr><td>
1484 <a href="/help/root">
1484 <a href="/help/root">
1485 root
1485 root
1486 </a>
1486 </a>
1487 </td><td>
1487 </td><td>
1488 print the root (top) of the current working directory
1488 print the root (top) of the current working directory
1489 </td></tr>
1489 </td></tr>
1490 <tr><td>
1490 <tr><td>
1491 <a href="/help/tag">
1491 <a href="/help/tag">
1492 tag
1492 tag
1493 </a>
1493 </a>
1494 </td><td>
1494 </td><td>
1495 add one or more tags for the current or given revision
1495 add one or more tags for the current or given revision
1496 </td></tr>
1496 </td></tr>
1497 <tr><td>
1497 <tr><td>
1498 <a href="/help/tags">
1498 <a href="/help/tags">
1499 tags
1499 tags
1500 </a>
1500 </a>
1501 </td><td>
1501 </td><td>
1502 list repository tags
1502 list repository tags
1503 </td></tr>
1503 </td></tr>
1504 <tr><td>
1504 <tr><td>
1505 <a href="/help/unbundle">
1505 <a href="/help/unbundle">
1506 unbundle
1506 unbundle
1507 </a>
1507 </a>
1508 </td><td>
1508 </td><td>
1509 apply one or more changegroup files
1509 apply one or more changegroup files
1510 </td></tr>
1510 </td></tr>
1511 <tr><td>
1511 <tr><td>
1512 <a href="/help/verify">
1512 <a href="/help/verify">
1513 verify
1513 verify
1514 </a>
1514 </a>
1515 </td><td>
1515 </td><td>
1516 verify the integrity of the repository
1516 verify the integrity of the repository
1517 </td></tr>
1517 </td></tr>
1518 <tr><td>
1518 <tr><td>
1519 <a href="/help/version">
1519 <a href="/help/version">
1520 version
1520 version
1521 </a>
1521 </a>
1522 </td><td>
1522 </td><td>
1523 output version and copyright information
1523 output version and copyright information
1524 </td></tr>
1524 </td></tr>
1525 </table>
1525 </table>
1526 </div>
1526 </div>
1527 </div>
1527 </div>
1528
1528
1529 <script type="text/javascript">process_dates()</script>
1529 <script type="text/javascript">process_dates()</script>
1530
1530
1531
1531
1532 </body>
1532 </body>
1533 </html>
1533 </html>
1534
1534
1535
1535
1536 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/add"
1536 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/add"
1537 200 Script output follows
1537 200 Script output follows
1538
1538
1539 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1539 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1540 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1540 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1541 <head>
1541 <head>
1542 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1542 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1543 <meta name="robots" content="index, nofollow" />
1543 <meta name="robots" content="index, nofollow" />
1544 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1544 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1545 <script type="text/javascript" src="/static/mercurial.js"></script>
1545 <script type="text/javascript" src="/static/mercurial.js"></script>
1546
1546
1547 <title>Help: add</title>
1547 <title>Help: add</title>
1548 </head>
1548 </head>
1549 <body>
1549 <body>
1550
1550
1551 <div class="container">
1551 <div class="container">
1552 <div class="menu">
1552 <div class="menu">
1553 <div class="logo">
1553 <div class="logo">
1554 <a href="http://mercurial.selenic.com/">
1554 <a href="http://mercurial.selenic.com/">
1555 <img src="/static/hglogo.png" alt="mercurial" /></a>
1555 <img src="/static/hglogo.png" alt="mercurial" /></a>
1556 </div>
1556 </div>
1557 <ul>
1557 <ul>
1558 <li><a href="/shortlog">log</a></li>
1558 <li><a href="/shortlog">log</a></li>
1559 <li><a href="/graph">graph</a></li>
1559 <li><a href="/graph">graph</a></li>
1560 <li><a href="/tags">tags</a></li>
1560 <li><a href="/tags">tags</a></li>
1561 <li><a href="/bookmarks">bookmarks</a></li>
1561 <li><a href="/bookmarks">bookmarks</a></li>
1562 <li><a href="/branches">branches</a></li>
1562 <li><a href="/branches">branches</a></li>
1563 </ul>
1563 </ul>
1564 <ul>
1564 <ul>
1565 <li class="active"><a href="/help">help</a></li>
1565 <li class="active"><a href="/help">help</a></li>
1566 </ul>
1566 </ul>
1567 </div>
1567 </div>
1568
1568
1569 <div class="main">
1569 <div class="main">
1570 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1570 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1571 <h3>Help: add</h3>
1571 <h3>Help: add</h3>
1572
1572
1573 <form class="search" action="/log">
1573 <form class="search" action="/log">
1574
1574
1575 <p><input name="rev" id="search1" type="text" size="30" /></p>
1575 <p><input name="rev" id="search1" type="text" size="30" /></p>
1576 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1576 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1577 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1577 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1578 </form>
1578 </form>
1579 <div id="doc">
1579 <div id="doc">
1580 <p>
1580 <p>
1581 hg add [OPTION]... [FILE]...
1581 hg add [OPTION]... [FILE]...
1582 </p>
1582 </p>
1583 <p>
1583 <p>
1584 add the specified files on the next commit
1584 add the specified files on the next commit
1585 </p>
1585 </p>
1586 <p>
1586 <p>
1587 Schedule files to be version controlled and added to the
1587 Schedule files to be version controlled and added to the
1588 repository.
1588 repository.
1589 </p>
1589 </p>
1590 <p>
1590 <p>
1591 The files will be added to the repository at the next commit. To
1591 The files will be added to the repository at the next commit. To
1592 undo an add before that, see &quot;hg forget&quot;.
1592 undo an add before that, see &quot;hg forget&quot;.
1593 </p>
1593 </p>
1594 <p>
1594 <p>
1595 If no names are given, add all files to the repository.
1595 If no names are given, add all files to the repository.
1596 </p>
1596 </p>
1597 <p>
1597 <p>
1598 An example showing how new (unknown) files are added
1598 An example showing how new (unknown) files are added
1599 automatically by &quot;hg add&quot;:
1599 automatically by &quot;hg add&quot;:
1600 </p>
1600 </p>
1601 <pre>
1601 <pre>
1602 \$ ls (re)
1602 \$ ls (re)
1603 foo.c
1603 foo.c
1604 \$ hg status (re)
1604 \$ hg status (re)
1605 ? foo.c
1605 ? foo.c
1606 \$ hg add (re)
1606 \$ hg add (re)
1607 adding foo.c
1607 adding foo.c
1608 \$ hg status (re)
1608 \$ hg status (re)
1609 A foo.c
1609 A foo.c
1610 </pre>
1610 </pre>
1611 <p>
1611 <p>
1612 Returns 0 if all files are successfully added.
1612 Returns 0 if all files are successfully added.
1613 </p>
1613 </p>
1614 <p>
1614 <p>
1615 options:
1615 options:
1616 </p>
1616 </p>
1617 <table>
1617 <table>
1618 <tr><td>-I</td>
1618 <tr><td>-I</td>
1619 <td>--include PATTERN [+]</td>
1619 <td>--include PATTERN [+]</td>
1620 <td>include names matching the given patterns</td></tr>
1620 <td>include names matching the given patterns</td></tr>
1621 <tr><td>-X</td>
1621 <tr><td>-X</td>
1622 <td>--exclude PATTERN [+]</td>
1622 <td>--exclude PATTERN [+]</td>
1623 <td>exclude names matching the given patterns</td></tr>
1623 <td>exclude names matching the given patterns</td></tr>
1624 <tr><td>-S</td>
1624 <tr><td>-S</td>
1625 <td>--subrepos</td>
1625 <td>--subrepos</td>
1626 <td>recurse into subrepositories</td></tr>
1626 <td>recurse into subrepositories</td></tr>
1627 <tr><td>-n</td>
1627 <tr><td>-n</td>
1628 <td>--dry-run</td>
1628 <td>--dry-run</td>
1629 <td>do not perform actions, just print output</td></tr>
1629 <td>do not perform actions, just print output</td></tr>
1630 </table>
1630 </table>
1631 <p>
1631 <p>
1632 [+] marked option can be specified multiple times
1632 [+] marked option can be specified multiple times
1633 </p>
1633 </p>
1634 <p>
1634 <p>
1635 global options:
1635 global options:
1636 </p>
1636 </p>
1637 <table>
1637 <table>
1638 <tr><td>-R</td>
1638 <tr><td>-R</td>
1639 <td>--repository REPO</td>
1639 <td>--repository REPO</td>
1640 <td>repository root directory or name of overlay bundle file</td></tr>
1640 <td>repository root directory or name of overlay bundle file</td></tr>
1641 <tr><td></td>
1641 <tr><td></td>
1642 <td>--cwd DIR</td>
1642 <td>--cwd DIR</td>
1643 <td>change working directory</td></tr>
1643 <td>change working directory</td></tr>
1644 <tr><td>-y</td>
1644 <tr><td>-y</td>
1645 <td>--noninteractive</td>
1645 <td>--noninteractive</td>
1646 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1646 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1647 <tr><td>-q</td>
1647 <tr><td>-q</td>
1648 <td>--quiet</td>
1648 <td>--quiet</td>
1649 <td>suppress output</td></tr>
1649 <td>suppress output</td></tr>
1650 <tr><td>-v</td>
1650 <tr><td>-v</td>
1651 <td>--verbose</td>
1651 <td>--verbose</td>
1652 <td>enable additional output</td></tr>
1652 <td>enable additional output</td></tr>
1653 <tr><td></td>
1653 <tr><td></td>
1654 <td>--config CONFIG [+]</td>
1654 <td>--config CONFIG [+]</td>
1655 <td>set/override config option (use 'section.name=value')</td></tr>
1655 <td>set/override config option (use 'section.name=value')</td></tr>
1656 <tr><td></td>
1656 <tr><td></td>
1657 <td>--debug</td>
1657 <td>--debug</td>
1658 <td>enable debugging output</td></tr>
1658 <td>enable debugging output</td></tr>
1659 <tr><td></td>
1659 <tr><td></td>
1660 <td>--debugger</td>
1660 <td>--debugger</td>
1661 <td>start debugger</td></tr>
1661 <td>start debugger</td></tr>
1662 <tr><td></td>
1662 <tr><td></td>
1663 <td>--encoding ENCODE</td>
1663 <td>--encoding ENCODE</td>
1664 <td>set the charset encoding (default: ascii)</td></tr>
1664 <td>set the charset encoding (default: ascii)</td></tr>
1665 <tr><td></td>
1665 <tr><td></td>
1666 <td>--encodingmode MODE</td>
1666 <td>--encodingmode MODE</td>
1667 <td>set the charset encoding mode (default: strict)</td></tr>
1667 <td>set the charset encoding mode (default: strict)</td></tr>
1668 <tr><td></td>
1668 <tr><td></td>
1669 <td>--traceback</td>
1669 <td>--traceback</td>
1670 <td>always print a traceback on exception</td></tr>
1670 <td>always print a traceback on exception</td></tr>
1671 <tr><td></td>
1671 <tr><td></td>
1672 <td>--time</td>
1672 <td>--time</td>
1673 <td>time how long the command takes</td></tr>
1673 <td>time how long the command takes</td></tr>
1674 <tr><td></td>
1674 <tr><td></td>
1675 <td>--profile</td>
1675 <td>--profile</td>
1676 <td>print command execution profile</td></tr>
1676 <td>print command execution profile</td></tr>
1677 <tr><td></td>
1677 <tr><td></td>
1678 <td>--version</td>
1678 <td>--version</td>
1679 <td>output version information and exit</td></tr>
1679 <td>output version information and exit</td></tr>
1680 <tr><td>-h</td>
1680 <tr><td>-h</td>
1681 <td>--help</td>
1681 <td>--help</td>
1682 <td>display help and exit</td></tr>
1682 <td>display help and exit</td></tr>
1683 <tr><td></td>
1683 <tr><td></td>
1684 <td>--hidden</td>
1684 <td>--hidden</td>
1685 <td>consider hidden changesets</td></tr>
1685 <td>consider hidden changesets</td></tr>
1686 </table>
1686 </table>
1687 <p>
1687 <p>
1688 [+] marked option can be specified multiple times
1688 [+] marked option can be specified multiple times
1689 </p>
1689 </p>
1690
1690
1691 </div>
1691 </div>
1692 </div>
1692 </div>
1693 </div>
1693 </div>
1694
1694
1695 <script type="text/javascript">process_dates()</script>
1695 <script type="text/javascript">process_dates()</script>
1696
1696
1697
1697
1698 </body>
1698 </body>
1699 </html>
1699 </html>
1700
1700
1701
1701
1702 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/remove"
1702 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/remove"
1703 200 Script output follows
1703 200 Script output follows
1704
1704
1705 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1705 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1706 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1706 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1707 <head>
1707 <head>
1708 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1708 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1709 <meta name="robots" content="index, nofollow" />
1709 <meta name="robots" content="index, nofollow" />
1710 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1710 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1711 <script type="text/javascript" src="/static/mercurial.js"></script>
1711 <script type="text/javascript" src="/static/mercurial.js"></script>
1712
1712
1713 <title>Help: remove</title>
1713 <title>Help: remove</title>
1714 </head>
1714 </head>
1715 <body>
1715 <body>
1716
1716
1717 <div class="container">
1717 <div class="container">
1718 <div class="menu">
1718 <div class="menu">
1719 <div class="logo">
1719 <div class="logo">
1720 <a href="http://mercurial.selenic.com/">
1720 <a href="http://mercurial.selenic.com/">
1721 <img src="/static/hglogo.png" alt="mercurial" /></a>
1721 <img src="/static/hglogo.png" alt="mercurial" /></a>
1722 </div>
1722 </div>
1723 <ul>
1723 <ul>
1724 <li><a href="/shortlog">log</a></li>
1724 <li><a href="/shortlog">log</a></li>
1725 <li><a href="/graph">graph</a></li>
1725 <li><a href="/graph">graph</a></li>
1726 <li><a href="/tags">tags</a></li>
1726 <li><a href="/tags">tags</a></li>
1727 <li><a href="/bookmarks">bookmarks</a></li>
1727 <li><a href="/bookmarks">bookmarks</a></li>
1728 <li><a href="/branches">branches</a></li>
1728 <li><a href="/branches">branches</a></li>
1729 </ul>
1729 </ul>
1730 <ul>
1730 <ul>
1731 <li class="active"><a href="/help">help</a></li>
1731 <li class="active"><a href="/help">help</a></li>
1732 </ul>
1732 </ul>
1733 </div>
1733 </div>
1734
1734
1735 <div class="main">
1735 <div class="main">
1736 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1736 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1737 <h3>Help: remove</h3>
1737 <h3>Help: remove</h3>
1738
1738
1739 <form class="search" action="/log">
1739 <form class="search" action="/log">
1740
1740
1741 <p><input name="rev" id="search1" type="text" size="30" /></p>
1741 <p><input name="rev" id="search1" type="text" size="30" /></p>
1742 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1742 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1743 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1743 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1744 </form>
1744 </form>
1745 <div id="doc">
1745 <div id="doc">
1746 <p>
1746 <p>
1747 hg remove [OPTION]... FILE...
1747 hg remove [OPTION]... FILE...
1748 </p>
1748 </p>
1749 <p>
1749 <p>
1750 aliases: rm
1750 aliases: rm
1751 </p>
1751 </p>
1752 <p>
1752 <p>
1753 remove the specified files on the next commit
1753 remove the specified files on the next commit
1754 </p>
1754 </p>
1755 <p>
1755 <p>
1756 Schedule the indicated files for removal from the current branch.
1756 Schedule the indicated files for removal from the current branch.
1757 </p>
1757 </p>
1758 <p>
1758 <p>
1759 This command schedules the files to be removed at the next commit.
1759 This command schedules the files to be removed at the next commit.
1760 To undo a remove before that, see &quot;hg revert&quot;. To undo added
1760 To undo a remove before that, see &quot;hg revert&quot;. To undo added
1761 files, see &quot;hg forget&quot;.
1761 files, see &quot;hg forget&quot;.
1762 </p>
1762 </p>
1763 <p>
1763 <p>
1764 -A/--after can be used to remove only files that have already
1764 -A/--after can be used to remove only files that have already
1765 been deleted, -f/--force can be used to force deletion, and -Af
1765 been deleted, -f/--force can be used to force deletion, and -Af
1766 can be used to remove files from the next revision without
1766 can be used to remove files from the next revision without
1767 deleting them from the working directory.
1767 deleting them from the working directory.
1768 </p>
1768 </p>
1769 <p>
1769 <p>
1770 The following table details the behavior of remove for different
1770 The following table details the behavior of remove for different
1771 file states (columns) and option combinations (rows). The file
1771 file states (columns) and option combinations (rows). The file
1772 states are Added [A], Clean [C], Modified [M] and Missing [!]
1772 states are Added [A], Clean [C], Modified [M] and Missing [!]
1773 (as reported by &quot;hg status&quot;). The actions are Warn, Remove
1773 (as reported by &quot;hg status&quot;). The actions are Warn, Remove
1774 (from branch) and Delete (from disk):
1774 (from branch) and Delete (from disk):
1775 </p>
1775 </p>
1776 <table>
1776 <table>
1777 <tr><td>opt/state</td>
1777 <tr><td>opt/state</td>
1778 <td>A</td>
1778 <td>A</td>
1779 <td>C</td>
1779 <td>C</td>
1780 <td>M</td>
1780 <td>M</td>
1781 <td>!</td></tr>
1781 <td>!</td></tr>
1782 <tr><td>none</td>
1782 <tr><td>none</td>
1783 <td>W</td>
1783 <td>W</td>
1784 <td>RD</td>
1784 <td>RD</td>
1785 <td>W</td>
1785 <td>W</td>
1786 <td>R</td></tr>
1786 <td>R</td></tr>
1787 <tr><td>-f</td>
1787 <tr><td>-f</td>
1788 <td>R</td>
1788 <td>R</td>
1789 <td>RD</td>
1789 <td>RD</td>
1790 <td>RD</td>
1790 <td>RD</td>
1791 <td>R</td></tr>
1791 <td>R</td></tr>
1792 <tr><td>-A</td>
1792 <tr><td>-A</td>
1793 <td>W</td>
1793 <td>W</td>
1794 <td>W</td>
1794 <td>W</td>
1795 <td>W</td>
1795 <td>W</td>
1796 <td>R</td></tr>
1796 <td>R</td></tr>
1797 <tr><td>-Af</td>
1797 <tr><td>-Af</td>
1798 <td>R</td>
1798 <td>R</td>
1799 <td>R</td>
1799 <td>R</td>
1800 <td>R</td>
1800 <td>R</td>
1801 <td>R</td></tr>
1801 <td>R</td></tr>
1802 </table>
1802 </table>
1803 <p>
1803 <p>
1804 Note that remove never deletes files in Added [A] state from the
1804 Note that remove never deletes files in Added [A] state from the
1805 working directory, not even if option --force is specified.
1805 working directory, not even if option --force is specified.
1806 </p>
1806 </p>
1807 <p>
1807 <p>
1808 Returns 0 on success, 1 if any warnings encountered.
1808 Returns 0 on success, 1 if any warnings encountered.
1809 </p>
1809 </p>
1810 <p>
1810 <p>
1811 options:
1811 options:
1812 </p>
1812 </p>
1813 <table>
1813 <table>
1814 <tr><td>-A</td>
1814 <tr><td>-A</td>
1815 <td>--after</td>
1815 <td>--after</td>
1816 <td>record delete for missing files</td></tr>
1816 <td>record delete for missing files</td></tr>
1817 <tr><td>-f</td>
1817 <tr><td>-f</td>
1818 <td>--force</td>
1818 <td>--force</td>
1819 <td>remove (and delete) file even if added or modified</td></tr>
1819 <td>remove (and delete) file even if added or modified</td></tr>
1820 <tr><td>-I</td>
1820 <tr><td>-I</td>
1821 <td>--include PATTERN [+]</td>
1821 <td>--include PATTERN [+]</td>
1822 <td>include names matching the given patterns</td></tr>
1822 <td>include names matching the given patterns</td></tr>
1823 <tr><td>-X</td>
1823 <tr><td>-X</td>
1824 <td>--exclude PATTERN [+]</td>
1824 <td>--exclude PATTERN [+]</td>
1825 <td>exclude names matching the given patterns</td></tr>
1825 <td>exclude names matching the given patterns</td></tr>
1826 </table>
1826 </table>
1827 <p>
1827 <p>
1828 [+] marked option can be specified multiple times
1828 [+] marked option can be specified multiple times
1829 </p>
1829 </p>
1830 <p>
1830 <p>
1831 global options:
1831 global options:
1832 </p>
1832 </p>
1833 <table>
1833 <table>
1834 <tr><td>-R</td>
1834 <tr><td>-R</td>
1835 <td>--repository REPO</td>
1835 <td>--repository REPO</td>
1836 <td>repository root directory or name of overlay bundle file</td></tr>
1836 <td>repository root directory or name of overlay bundle file</td></tr>
1837 <tr><td></td>
1837 <tr><td></td>
1838 <td>--cwd DIR</td>
1838 <td>--cwd DIR</td>
1839 <td>change working directory</td></tr>
1839 <td>change working directory</td></tr>
1840 <tr><td>-y</td>
1840 <tr><td>-y</td>
1841 <td>--noninteractive</td>
1841 <td>--noninteractive</td>
1842 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1842 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
1843 <tr><td>-q</td>
1843 <tr><td>-q</td>
1844 <td>--quiet</td>
1844 <td>--quiet</td>
1845 <td>suppress output</td></tr>
1845 <td>suppress output</td></tr>
1846 <tr><td>-v</td>
1846 <tr><td>-v</td>
1847 <td>--verbose</td>
1847 <td>--verbose</td>
1848 <td>enable additional output</td></tr>
1848 <td>enable additional output</td></tr>
1849 <tr><td></td>
1849 <tr><td></td>
1850 <td>--config CONFIG [+]</td>
1850 <td>--config CONFIG [+]</td>
1851 <td>set/override config option (use 'section.name=value')</td></tr>
1851 <td>set/override config option (use 'section.name=value')</td></tr>
1852 <tr><td></td>
1852 <tr><td></td>
1853 <td>--debug</td>
1853 <td>--debug</td>
1854 <td>enable debugging output</td></tr>
1854 <td>enable debugging output</td></tr>
1855 <tr><td></td>
1855 <tr><td></td>
1856 <td>--debugger</td>
1856 <td>--debugger</td>
1857 <td>start debugger</td></tr>
1857 <td>start debugger</td></tr>
1858 <tr><td></td>
1858 <tr><td></td>
1859 <td>--encoding ENCODE</td>
1859 <td>--encoding ENCODE</td>
1860 <td>set the charset encoding (default: ascii)</td></tr>
1860 <td>set the charset encoding (default: ascii)</td></tr>
1861 <tr><td></td>
1861 <tr><td></td>
1862 <td>--encodingmode MODE</td>
1862 <td>--encodingmode MODE</td>
1863 <td>set the charset encoding mode (default: strict)</td></tr>
1863 <td>set the charset encoding mode (default: strict)</td></tr>
1864 <tr><td></td>
1864 <tr><td></td>
1865 <td>--traceback</td>
1865 <td>--traceback</td>
1866 <td>always print a traceback on exception</td></tr>
1866 <td>always print a traceback on exception</td></tr>
1867 <tr><td></td>
1867 <tr><td></td>
1868 <td>--time</td>
1868 <td>--time</td>
1869 <td>time how long the command takes</td></tr>
1869 <td>time how long the command takes</td></tr>
1870 <tr><td></td>
1870 <tr><td></td>
1871 <td>--profile</td>
1871 <td>--profile</td>
1872 <td>print command execution profile</td></tr>
1872 <td>print command execution profile</td></tr>
1873 <tr><td></td>
1873 <tr><td></td>
1874 <td>--version</td>
1874 <td>--version</td>
1875 <td>output version information and exit</td></tr>
1875 <td>output version information and exit</td></tr>
1876 <tr><td>-h</td>
1876 <tr><td>-h</td>
1877 <td>--help</td>
1877 <td>--help</td>
1878 <td>display help and exit</td></tr>
1878 <td>display help and exit</td></tr>
1879 <tr><td></td>
1879 <tr><td></td>
1880 <td>--hidden</td>
1880 <td>--hidden</td>
1881 <td>consider hidden changesets</td></tr>
1881 <td>consider hidden changesets</td></tr>
1882 </table>
1882 </table>
1883 <p>
1883 <p>
1884 [+] marked option can be specified multiple times
1884 [+] marked option can be specified multiple times
1885 </p>
1885 </p>
1886
1886
1887 </div>
1887 </div>
1888 </div>
1888 </div>
1889 </div>
1889 </div>
1890
1890
1891 <script type="text/javascript">process_dates()</script>
1891 <script type="text/javascript">process_dates()</script>
1892
1892
1893
1893
1894 </body>
1894 </body>
1895 </html>
1895 </html>
1896
1896
1897
1897
1898 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/revisions"
1898 $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/revisions"
1899 200 Script output follows
1899 200 Script output follows
1900
1900
1901 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1901 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1902 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1902 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1903 <head>
1903 <head>
1904 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1904 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1905 <meta name="robots" content="index, nofollow" />
1905 <meta name="robots" content="index, nofollow" />
1906 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1906 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1907 <script type="text/javascript" src="/static/mercurial.js"></script>
1907 <script type="text/javascript" src="/static/mercurial.js"></script>
1908
1908
1909 <title>Help: revisions</title>
1909 <title>Help: revisions</title>
1910 </head>
1910 </head>
1911 <body>
1911 <body>
1912
1912
1913 <div class="container">
1913 <div class="container">
1914 <div class="menu">
1914 <div class="menu">
1915 <div class="logo">
1915 <div class="logo">
1916 <a href="http://mercurial.selenic.com/">
1916 <a href="http://mercurial.selenic.com/">
1917 <img src="/static/hglogo.png" alt="mercurial" /></a>
1917 <img src="/static/hglogo.png" alt="mercurial" /></a>
1918 </div>
1918 </div>
1919 <ul>
1919 <ul>
1920 <li><a href="/shortlog">log</a></li>
1920 <li><a href="/shortlog">log</a></li>
1921 <li><a href="/graph">graph</a></li>
1921 <li><a href="/graph">graph</a></li>
1922 <li><a href="/tags">tags</a></li>
1922 <li><a href="/tags">tags</a></li>
1923 <li><a href="/bookmarks">bookmarks</a></li>
1923 <li><a href="/bookmarks">bookmarks</a></li>
1924 <li><a href="/branches">branches</a></li>
1924 <li><a href="/branches">branches</a></li>
1925 </ul>
1925 </ul>
1926 <ul>
1926 <ul>
1927 <li class="active"><a href="/help">help</a></li>
1927 <li class="active"><a href="/help">help</a></li>
1928 </ul>
1928 </ul>
1929 </div>
1929 </div>
1930
1930
1931 <div class="main">
1931 <div class="main">
1932 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1932 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1933 <h3>Help: revisions</h3>
1933 <h3>Help: revisions</h3>
1934
1934
1935 <form class="search" action="/log">
1935 <form class="search" action="/log">
1936
1936
1937 <p><input name="rev" id="search1" type="text" size="30" /></p>
1937 <p><input name="rev" id="search1" type="text" size="30" /></p>
1938 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1938 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1939 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1939 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1940 </form>
1940 </form>
1941 <div id="doc">
1941 <div id="doc">
1942 <h1>Specifying Single Revisions</h1>
1942 <h1>Specifying Single Revisions</h1>
1943 <p>
1943 <p>
1944 Mercurial supports several ways to specify individual revisions.
1944 Mercurial supports several ways to specify individual revisions.
1945 </p>
1945 </p>
1946 <p>
1946 <p>
1947 A plain integer is treated as a revision number. Negative integers are
1947 A plain integer is treated as a revision number. Negative integers are
1948 treated as sequential offsets from the tip, with -1 denoting the tip,
1948 treated as sequential offsets from the tip, with -1 denoting the tip,
1949 -2 denoting the revision prior to the tip, and so forth.
1949 -2 denoting the revision prior to the tip, and so forth.
1950 </p>
1950 </p>
1951 <p>
1951 <p>
1952 A 40-digit hexadecimal string is treated as a unique revision
1952 A 40-digit hexadecimal string is treated as a unique revision
1953 identifier.
1953 identifier.
1954 </p>
1954 </p>
1955 <p>
1955 <p>
1956 A hexadecimal string less than 40 characters long is treated as a
1956 A hexadecimal string less than 40 characters long is treated as a
1957 unique revision identifier and is referred to as a short-form
1957 unique revision identifier and is referred to as a short-form
1958 identifier. A short-form identifier is only valid if it is the prefix
1958 identifier. A short-form identifier is only valid if it is the prefix
1959 of exactly one full-length identifier.
1959 of exactly one full-length identifier.
1960 </p>
1960 </p>
1961 <p>
1961 <p>
1962 Any other string is treated as a bookmark, tag, or branch name. A
1962 Any other string is treated as a bookmark, tag, or branch name. A
1963 bookmark is a movable pointer to a revision. A tag is a permanent name
1963 bookmark is a movable pointer to a revision. A tag is a permanent name
1964 associated with a revision. A branch name denotes the tipmost open branch head
1964 associated with a revision. A branch name denotes the tipmost open branch head
1965 of that branch - or if they are all closed, the tipmost closed head of the
1965 of that branch - or if they are all closed, the tipmost closed head of the
1966 branch. Bookmark, tag, and branch names must not contain the &quot;:&quot; character.
1966 branch. Bookmark, tag, and branch names must not contain the &quot;:&quot; character.
1967 </p>
1967 </p>
1968 <p>
1968 <p>
1969 The reserved name &quot;tip&quot; always identifies the most recent revision.
1969 The reserved name &quot;tip&quot; always identifies the most recent revision.
1970 </p>
1970 </p>
1971 <p>
1971 <p>
1972 The reserved name &quot;null&quot; indicates the null revision. This is the
1972 The reserved name &quot;null&quot; indicates the null revision. This is the
1973 revision of an empty repository, and the parent of revision 0.
1973 revision of an empty repository, and the parent of revision 0.
1974 </p>
1974 </p>
1975 <p>
1975 <p>
1976 The reserved name &quot;.&quot; indicates the working directory parent. If no
1976 The reserved name &quot;.&quot; indicates the working directory parent. If no
1977 working directory is checked out, it is equivalent to null. If an
1977 working directory is checked out, it is equivalent to null. If an
1978 uncommitted merge is in progress, &quot;.&quot; is the revision of the first
1978 uncommitted merge is in progress, &quot;.&quot; is the revision of the first
1979 parent.
1979 parent.
1980 </p>
1980 </p>
1981
1981
1982 </div>
1982 </div>
1983 </div>
1983 </div>
1984 </div>
1984 </div>
1985
1985
1986 <script type="text/javascript">process_dates()</script>
1986 <script type="text/javascript">process_dates()</script>
1987
1987
1988
1988
1989 </body>
1989 </body>
1990 </html>
1990 </html>
1991
1991
1992
1992
1993 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1993 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1994
1994
1995 #endif
1995 #endif
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (649 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now