##// END OF EJS Templates
extensions: raise when trying to find an extension that failed to load...
Idan Kamara -
r14415:c238b12a default
parent child Browse files
Show More
@@ -1,334 +1,338 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']
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec']
15
15
16 def extensions():
16 def extensions():
17 for name in _order:
17 for name in _order:
18 module = _extensions[name]
18 module = _extensions[name]
19 if module:
19 if module:
20 yield name, module
20 yield name, module
21
21
22 def find(name):
22 def find(name):
23 '''return module with given extension name'''
23 '''return module with given extension name'''
24 mod = None
24 try:
25 try:
25 return _extensions[name]
26 mod = _extensions[name]
26 except KeyError:
27 except KeyError:
27 for k, v in _extensions.iteritems():
28 for k, v in _extensions.iteritems():
28 if k.endswith('.' + name) or k.endswith('/' + name):
29 if k.endswith('.' + name) or k.endswith('/' + name):
29 return v
30 mod = v
31 break
32 if not mod:
30 raise KeyError(name)
33 raise KeyError(name)
34 return mod
31
35
32 def loadpath(path, module_name):
36 def loadpath(path, module_name):
33 module_name = module_name.replace('.', '_')
37 module_name = module_name.replace('.', '_')
34 path = util.expandpath(path)
38 path = util.expandpath(path)
35 if os.path.isdir(path):
39 if os.path.isdir(path):
36 # module/__init__.py style
40 # module/__init__.py style
37 d, f = os.path.split(path.rstrip('/'))
41 d, f = os.path.split(path.rstrip('/'))
38 fd, fpath, desc = imp.find_module(f, [d])
42 fd, fpath, desc = imp.find_module(f, [d])
39 return imp.load_module(module_name, fd, fpath, desc)
43 return imp.load_module(module_name, fd, fpath, desc)
40 else:
44 else:
41 return imp.load_source(module_name, path)
45 return imp.load_source(module_name, path)
42
46
43 def load(ui, name, path):
47 def load(ui, name, path):
44 # unused ui argument kept for backwards compatibility
48 # unused ui argument kept for backwards compatibility
45 if name.startswith('hgext.') or name.startswith('hgext/'):
49 if name.startswith('hgext.') or name.startswith('hgext/'):
46 shortname = name[6:]
50 shortname = name[6:]
47 else:
51 else:
48 shortname = name
52 shortname = name
49 if shortname in _ignore:
53 if shortname in _ignore:
50 return None
54 return None
51 if shortname in _extensions:
55 if shortname in _extensions:
52 return _extensions[shortname]
56 return _extensions[shortname]
53 _extensions[shortname] = None
57 _extensions[shortname] = None
54 if path:
58 if path:
55 # the module will be loaded in sys.modules
59 # the module will be loaded in sys.modules
56 # choose an unique name so that it doesn't
60 # choose an unique name so that it doesn't
57 # conflicts with other modules
61 # conflicts with other modules
58 mod = loadpath(path, 'hgext.%s' % name)
62 mod = loadpath(path, 'hgext.%s' % name)
59 else:
63 else:
60 def importh(name):
64 def importh(name):
61 mod = __import__(name)
65 mod = __import__(name)
62 components = name.split('.')
66 components = name.split('.')
63 for comp in components[1:]:
67 for comp in components[1:]:
64 mod = getattr(mod, comp)
68 mod = getattr(mod, comp)
65 return mod
69 return mod
66 try:
70 try:
67 mod = importh("hgext.%s" % name)
71 mod = importh("hgext.%s" % name)
68 except ImportError:
72 except ImportError:
69 mod = importh(name)
73 mod = importh(name)
70 _extensions[shortname] = mod
74 _extensions[shortname] = mod
71 _order.append(shortname)
75 _order.append(shortname)
72 return mod
76 return mod
73
77
74 def loadall(ui):
78 def loadall(ui):
75 result = ui.configitems("extensions")
79 result = ui.configitems("extensions")
76 newindex = len(_order)
80 newindex = len(_order)
77 for (name, path) in result:
81 for (name, path) in result:
78 if path:
82 if path:
79 if path[0] == '!':
83 if path[0] == '!':
80 continue
84 continue
81 try:
85 try:
82 load(ui, name, path)
86 load(ui, name, path)
83 except KeyboardInterrupt:
87 except KeyboardInterrupt:
84 raise
88 raise
85 except Exception, inst:
89 except Exception, inst:
86 if path:
90 if path:
87 ui.warn(_("*** failed to import extension %s from %s: %s\n")
91 ui.warn(_("*** failed to import extension %s from %s: %s\n")
88 % (name, path, inst))
92 % (name, path, inst))
89 else:
93 else:
90 ui.warn(_("*** failed to import extension %s: %s\n")
94 ui.warn(_("*** failed to import extension %s: %s\n")
91 % (name, inst))
95 % (name, inst))
92 if ui.traceback():
96 if ui.traceback():
93 return 1
97 return 1
94
98
95 for name in _order[newindex:]:
99 for name in _order[newindex:]:
96 uisetup = getattr(_extensions[name], 'uisetup', None)
100 uisetup = getattr(_extensions[name], 'uisetup', None)
97 if uisetup:
101 if uisetup:
98 uisetup(ui)
102 uisetup(ui)
99
103
100 for name in _order[newindex:]:
104 for name in _order[newindex:]:
101 extsetup = getattr(_extensions[name], 'extsetup', None)
105 extsetup = getattr(_extensions[name], 'extsetup', None)
102 if extsetup:
106 if extsetup:
103 try:
107 try:
104 extsetup(ui)
108 extsetup(ui)
105 except TypeError:
109 except TypeError:
106 if extsetup.func_code.co_argcount != 0:
110 if extsetup.func_code.co_argcount != 0:
107 raise
111 raise
108 extsetup() # old extsetup with no ui argument
112 extsetup() # old extsetup with no ui argument
109
113
110 def wrapcommand(table, command, wrapper):
114 def wrapcommand(table, command, wrapper):
111 '''Wrap the command named `command' in table
115 '''Wrap the command named `command' in table
112
116
113 Replace command in the command table with wrapper. The wrapped command will
117 Replace command in the command table with wrapper. The wrapped command will
114 be inserted into the command table specified by the table argument.
118 be inserted into the command table specified by the table argument.
115
119
116 The wrapper will be called like
120 The wrapper will be called like
117
121
118 wrapper(orig, *args, **kwargs)
122 wrapper(orig, *args, **kwargs)
119
123
120 where orig is the original (wrapped) function, and *args, **kwargs
124 where orig is the original (wrapped) function, and *args, **kwargs
121 are the arguments passed to it.
125 are the arguments passed to it.
122 '''
126 '''
123 assert hasattr(wrapper, '__call__')
127 assert hasattr(wrapper, '__call__')
124 aliases, entry = cmdutil.findcmd(command, table)
128 aliases, entry = cmdutil.findcmd(command, table)
125 for alias, e in table.iteritems():
129 for alias, e in table.iteritems():
126 if e is entry:
130 if e is entry:
127 key = alias
131 key = alias
128 break
132 break
129
133
130 origfn = entry[0]
134 origfn = entry[0]
131 def wrap(*args, **kwargs):
135 def wrap(*args, **kwargs):
132 return util.checksignature(wrapper)(
136 return util.checksignature(wrapper)(
133 util.checksignature(origfn), *args, **kwargs)
137 util.checksignature(origfn), *args, **kwargs)
134
138
135 wrap.__doc__ = getattr(origfn, '__doc__')
139 wrap.__doc__ = getattr(origfn, '__doc__')
136 wrap.__module__ = getattr(origfn, '__module__')
140 wrap.__module__ = getattr(origfn, '__module__')
137
141
138 newentry = list(entry)
142 newentry = list(entry)
139 newentry[0] = wrap
143 newentry[0] = wrap
140 table[key] = tuple(newentry)
144 table[key] = tuple(newentry)
141 return entry
145 return entry
142
146
143 def wrapfunction(container, funcname, wrapper):
147 def wrapfunction(container, funcname, wrapper):
144 '''Wrap the function named funcname in container
148 '''Wrap the function named funcname in container
145
149
146 Replace the funcname member in the given container with the specified
150 Replace the funcname member in the given container with the specified
147 wrapper. The container is typically a module, class, or instance.
151 wrapper. The container is typically a module, class, or instance.
148
152
149 The wrapper will be called like
153 The wrapper will be called like
150
154
151 wrapper(orig, *args, **kwargs)
155 wrapper(orig, *args, **kwargs)
152
156
153 where orig is the original (wrapped) function, and *args, **kwargs
157 where orig is the original (wrapped) function, and *args, **kwargs
154 are the arguments passed to it.
158 are the arguments passed to it.
155
159
156 Wrapping methods of the repository object is not recommended since
160 Wrapping methods of the repository object is not recommended since
157 it conflicts with extensions that extend the repository by
161 it conflicts with extensions that extend the repository by
158 subclassing. All extensions that need to extend methods of
162 subclassing. All extensions that need to extend methods of
159 localrepository should use this subclassing trick: namely,
163 localrepository should use this subclassing trick: namely,
160 reposetup() should look like
164 reposetup() should look like
161
165
162 def reposetup(ui, repo):
166 def reposetup(ui, repo):
163 class myrepo(repo.__class__):
167 class myrepo(repo.__class__):
164 def whatever(self, *args, **kwargs):
168 def whatever(self, *args, **kwargs):
165 [...extension stuff...]
169 [...extension stuff...]
166 super(myrepo, self).whatever(*args, **kwargs)
170 super(myrepo, self).whatever(*args, **kwargs)
167 [...extension stuff...]
171 [...extension stuff...]
168
172
169 repo.__class__ = myrepo
173 repo.__class__ = myrepo
170
174
171 In general, combining wrapfunction() with subclassing does not
175 In general, combining wrapfunction() with subclassing does not
172 work. Since you cannot control what other extensions are loaded by
176 work. Since you cannot control what other extensions are loaded by
173 your end users, you should play nicely with others by using the
177 your end users, you should play nicely with others by using the
174 subclass trick.
178 subclass trick.
175 '''
179 '''
176 assert hasattr(wrapper, '__call__')
180 assert hasattr(wrapper, '__call__')
177 def wrap(*args, **kwargs):
181 def wrap(*args, **kwargs):
178 return wrapper(origfn, *args, **kwargs)
182 return wrapper(origfn, *args, **kwargs)
179
183
180 origfn = getattr(container, funcname)
184 origfn = getattr(container, funcname)
181 assert hasattr(origfn, '__call__')
185 assert hasattr(origfn, '__call__')
182 setattr(container, funcname, wrap)
186 setattr(container, funcname, wrap)
183 return origfn
187 return origfn
184
188
185 def _disabledpaths(strip_init=False):
189 def _disabledpaths(strip_init=False):
186 '''find paths of disabled extensions. returns a dict of {name: path}
190 '''find paths of disabled extensions. returns a dict of {name: path}
187 removes /__init__.py from packages if strip_init is True'''
191 removes /__init__.py from packages if strip_init is True'''
188 import hgext
192 import hgext
189 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
193 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
190 try: # might not be a filesystem path
194 try: # might not be a filesystem path
191 files = os.listdir(extpath)
195 files = os.listdir(extpath)
192 except OSError:
196 except OSError:
193 return {}
197 return {}
194
198
195 exts = {}
199 exts = {}
196 for e in files:
200 for e in files:
197 if e.endswith('.py'):
201 if e.endswith('.py'):
198 name = e.rsplit('.', 1)[0]
202 name = e.rsplit('.', 1)[0]
199 path = os.path.join(extpath, e)
203 path = os.path.join(extpath, e)
200 else:
204 else:
201 name = e
205 name = e
202 path = os.path.join(extpath, e, '__init__.py')
206 path = os.path.join(extpath, e, '__init__.py')
203 if not os.path.exists(path):
207 if not os.path.exists(path):
204 continue
208 continue
205 if strip_init:
209 if strip_init:
206 path = os.path.dirname(path)
210 path = os.path.dirname(path)
207 if name in exts or name in _order or name == '__init__':
211 if name in exts or name in _order or name == '__init__':
208 continue
212 continue
209 exts[name] = path
213 exts[name] = path
210 return exts
214 return exts
211
215
212 def _moduledoc(file):
216 def _moduledoc(file):
213 '''return the top-level python documentation for the given file
217 '''return the top-level python documentation for the given file
214
218
215 Loosely inspired by pydoc.source_synopsis(), but rewritten to
219 Loosely inspired by pydoc.source_synopsis(), but rewritten to
216 handle triple quotes and to return the whole text instead of just
220 handle triple quotes and to return the whole text instead of just
217 the synopsis'''
221 the synopsis'''
218 result = []
222 result = []
219
223
220 line = file.readline()
224 line = file.readline()
221 while line[:1] == '#' or not line.strip():
225 while line[:1] == '#' or not line.strip():
222 line = file.readline()
226 line = file.readline()
223 if not line:
227 if not line:
224 break
228 break
225
229
226 start = line[:3]
230 start = line[:3]
227 if start == '"""' or start == "'''":
231 if start == '"""' or start == "'''":
228 line = line[3:]
232 line = line[3:]
229 while line:
233 while line:
230 if line.rstrip().endswith(start):
234 if line.rstrip().endswith(start):
231 line = line.split(start)[0]
235 line = line.split(start)[0]
232 if line:
236 if line:
233 result.append(line)
237 result.append(line)
234 break
238 break
235 elif not line:
239 elif not line:
236 return None # unmatched delimiter
240 return None # unmatched delimiter
237 result.append(line)
241 result.append(line)
238 line = file.readline()
242 line = file.readline()
239 else:
243 else:
240 return None
244 return None
241
245
242 return ''.join(result)
246 return ''.join(result)
243
247
244 def _disabledhelp(path):
248 def _disabledhelp(path):
245 '''retrieve help synopsis of a disabled extension (without importing)'''
249 '''retrieve help synopsis of a disabled extension (without importing)'''
246 try:
250 try:
247 file = open(path)
251 file = open(path)
248 except IOError:
252 except IOError:
249 return
253 return
250 else:
254 else:
251 doc = _moduledoc(file)
255 doc = _moduledoc(file)
252 file.close()
256 file.close()
253
257
254 if doc: # extracting localized synopsis
258 if doc: # extracting localized synopsis
255 return gettext(doc).splitlines()[0]
259 return gettext(doc).splitlines()[0]
256 else:
260 else:
257 return _('(no help text available)')
261 return _('(no help text available)')
258
262
259 def disabled():
263 def disabled():
260 '''find disabled extensions from hgext
264 '''find disabled extensions from hgext
261 returns a dict of {name: desc}, and the max name length'''
265 returns a dict of {name: desc}, and the max name length'''
262
266
263 paths = _disabledpaths()
267 paths = _disabledpaths()
264 if not paths:
268 if not paths:
265 return None
269 return None
266
270
267 exts = {}
271 exts = {}
268 for name, path in paths.iteritems():
272 for name, path in paths.iteritems():
269 doc = _disabledhelp(path)
273 doc = _disabledhelp(path)
270 if doc:
274 if doc:
271 exts[name] = doc
275 exts[name] = doc
272
276
273 return exts
277 return exts
274
278
275 def disabledext(name):
279 def disabledext(name):
276 '''find a specific disabled extension from hgext. returns desc'''
280 '''find a specific disabled extension from hgext. returns desc'''
277 paths = _disabledpaths()
281 paths = _disabledpaths()
278 if name in paths:
282 if name in paths:
279 return _disabledhelp(paths[name])
283 return _disabledhelp(paths[name])
280
284
281 def disabledcmd(ui, cmd, strict=False):
285 def disabledcmd(ui, cmd, strict=False):
282 '''import disabled extensions until cmd is found.
286 '''import disabled extensions until cmd is found.
283 returns (cmdname, extname, doc)'''
287 returns (cmdname, extname, doc)'''
284
288
285 paths = _disabledpaths(strip_init=True)
289 paths = _disabledpaths(strip_init=True)
286 if not paths:
290 if not paths:
287 raise error.UnknownCommand(cmd)
291 raise error.UnknownCommand(cmd)
288
292
289 def findcmd(cmd, name, path):
293 def findcmd(cmd, name, path):
290 try:
294 try:
291 mod = loadpath(path, 'hgext.%s' % name)
295 mod = loadpath(path, 'hgext.%s' % name)
292 except Exception:
296 except Exception:
293 return
297 return
294 try:
298 try:
295 aliases, entry = cmdutil.findcmd(cmd,
299 aliases, entry = cmdutil.findcmd(cmd,
296 getattr(mod, 'cmdtable', {}), strict)
300 getattr(mod, 'cmdtable', {}), strict)
297 except (error.AmbiguousCommand, error.UnknownCommand):
301 except (error.AmbiguousCommand, error.UnknownCommand):
298 return
302 return
299 except Exception:
303 except Exception:
300 ui.warn(_('warning: error finding commands in %s\n') % path)
304 ui.warn(_('warning: error finding commands in %s\n') % path)
301 ui.traceback()
305 ui.traceback()
302 return
306 return
303 for c in aliases:
307 for c in aliases:
304 if c.startswith(cmd):
308 if c.startswith(cmd):
305 cmd = c
309 cmd = c
306 break
310 break
307 else:
311 else:
308 cmd = aliases[0]
312 cmd = aliases[0]
309 return (cmd, name, mod)
313 return (cmd, name, mod)
310
314
311 # first, search for an extension with the same name as the command
315 # first, search for an extension with the same name as the command
312 path = paths.pop(cmd, None)
316 path = paths.pop(cmd, None)
313 if path:
317 if path:
314 ext = findcmd(cmd, cmd, path)
318 ext = findcmd(cmd, cmd, path)
315 if ext:
319 if ext:
316 return ext
320 return ext
317
321
318 # otherwise, interrogate each extension until there's a match
322 # otherwise, interrogate each extension until there's a match
319 for name, path in paths.iteritems():
323 for name, path in paths.iteritems():
320 ext = findcmd(cmd, name, path)
324 ext = findcmd(cmd, name, path)
321 if ext:
325 if ext:
322 return ext
326 return ext
323
327
324 raise error.UnknownCommand(cmd)
328 raise error.UnknownCommand(cmd)
325
329
326 def enabled():
330 def enabled():
327 '''return a dict of {name: desc} of extensions, and the max name length'''
331 '''return a dict of {name: desc} of extensions, and the max name length'''
328 exts = {}
332 exts = {}
329 for ename, ext in extensions():
333 for ename, ext in extensions():
330 doc = (gettext(ext.__doc__) or _('(no help text available)'))
334 doc = (gettext(ext.__doc__) or _('(no help text available)'))
331 ename = ename.split('.')[-1]
335 ename = ename.split('.')[-1]
332 exts[ename] = doc.splitlines()[0].strip()
336 exts[ename] = doc.splitlines()[0].strip()
333
337
334 return exts
338 return exts
@@ -1,368 +1,383 b''
1 Create configuration
1 Create configuration
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
5
5
6 help record (no record)
6 help record (no record)
7
7
8 $ hg help record
8 $ hg help record
9 record extension - commands to interactively select changes for commit/qrefresh
9 record extension - commands to interactively select changes for commit/qrefresh
10
10
11 use "hg help extensions" for information on enabling extensions
11 use "hg help extensions" for information on enabling extensions
12
12
13 help qrecord (no record)
13 help qrecord (no record)
14
14
15 $ hg help qrecord
15 $ hg help qrecord
16 'qrecord' is provided by the following extension:
16 'qrecord' is provided by the following extension:
17
17
18 record commands to interactively select changes for commit/qrefresh
18 record commands to interactively select changes for commit/qrefresh
19
19
20 use "hg help extensions" for information on enabling extensions
20 use "hg help extensions" for information on enabling extensions
21
21
22 $ echo "[extensions]" >> $HGRCPATH
22 $ echo "[extensions]" >> $HGRCPATH
23 $ echo "record=" >> $HGRCPATH
23 $ echo "record=" >> $HGRCPATH
24
24
25 help record (record)
25 help record (record)
26
26
27 $ hg help record
27 $ hg help record
28 hg record [OPTION]... [FILE]...
28 hg record [OPTION]... [FILE]...
29
29
30 interactively select changes to commit
30 interactively select changes to commit
31
31
32 If a list of files is omitted, all changes reported by "hg status" will be
32 If a list of files is omitted, all changes reported by "hg status" will be
33 candidates for recording.
33 candidates for recording.
34
34
35 See "hg help dates" for a list of formats valid for -d/--date.
35 See "hg help dates" for a list of formats valid for -d/--date.
36
36
37 You will be prompted for whether to record changes to each modified file,
37 You will be prompted for whether to record changes to each modified file,
38 and for files with multiple changes, for each change to use. For each
38 and for files with multiple changes, for each change to use. For each
39 query, the following responses are possible:
39 query, the following responses are possible:
40
40
41 y - record this change
41 y - record this change
42 n - skip this change
42 n - skip this change
43
43
44 s - skip remaining changes to this file
44 s - skip remaining changes to this file
45 f - record remaining changes to this file
45 f - record remaining changes to this file
46
46
47 d - done, skip remaining changes and files
47 d - done, skip remaining changes and files
48 a - record all changes to all remaining files
48 a - record all changes to all remaining files
49 q - quit, recording no changes
49 q - quit, recording no changes
50
50
51 ? - display help
51 ? - display help
52
52
53 This command is not available when committing a merge.
53 This command is not available when committing a merge.
54
54
55 options:
55 options:
56
56
57 -A --addremove mark new/missing files as added/removed before
57 -A --addremove mark new/missing files as added/removed before
58 committing
58 committing
59 --close-branch mark a branch as closed, hiding it from the branch
59 --close-branch mark a branch as closed, hiding it from the branch
60 list
60 list
61 -I --include PATTERN [+] include names matching the given patterns
61 -I --include PATTERN [+] include names matching the given patterns
62 -X --exclude PATTERN [+] exclude names matching the given patterns
62 -X --exclude PATTERN [+] exclude names matching the given patterns
63 -m --message TEXT use text as commit message
63 -m --message TEXT use text as commit message
64 -l --logfile FILE read commit message from file
64 -l --logfile FILE read commit message from file
65 -d --date DATE record the specified date as commit date
65 -d --date DATE record the specified date as commit date
66 -u --user USER record the specified user as committer
66 -u --user USER record the specified user as committer
67
67
68 [+] marked option can be specified multiple times
68 [+] marked option can be specified multiple times
69
69
70 use "hg -v help record" to show global options
70 use "hg -v help record" to show global options
71
71
72 help (no mq, so no qrecord)
72 help (no mq, so no qrecord)
73
73
74 $ hg help qrecord
74 $ hg help qrecord
75 hg qrecord [OPTION]... PATCH [FILE]...
75 hg qrecord [OPTION]... PATCH [FILE]...
76
76
77 interactively record a new patch
77 interactively record a new patch
78
78
79 See "hg help qnew" & "hg help record" for more information and usage.
79 See "hg help qnew" & "hg help record" for more information and usage.
80
80
81 use "hg -v help qrecord" to show global options
81 use "hg -v help qrecord" to show global options
82
82
83 $ hg init a
83 $ hg init a
84
84
85 qrecord (mq not present)
85 qrecord (mq not present)
86
86
87 $ hg -R a qrecord
87 $ hg -R a qrecord
88 hg qrecord: invalid arguments
88 hg qrecord: invalid arguments
89 hg qrecord [OPTION]... PATCH [FILE]...
89 hg qrecord [OPTION]... PATCH [FILE]...
90
90
91 interactively record a new patch
91 interactively record a new patch
92
92
93 use "hg help qrecord" to show the full help text
93 use "hg help qrecord" to show the full help text
94 [255]
94 [255]
95
95
96 qrecord patch (mq not present)
96 qrecord patch (mq not present)
97
97
98 $ hg -R a qrecord patch
98 $ hg -R a qrecord patch
99 abort: 'mq' extension not loaded
99 abort: 'mq' extension not loaded
100 [255]
100 [255]
101
101
102 help (bad mq)
103
104 $ echo "mq=nonexistant" >> $HGRCPATH
105 $ hg help qrecord
106 *** failed to import extension mq from nonexistant: [Errno 2] No such file or directory
107 hg qrecord [OPTION]... PATCH [FILE]...
108
109 interactively record a new patch
110
111 See "hg help qnew" & "hg help record" for more information and usage.
112
113 use "hg -v help qrecord" to show global options
114
102 help (mq present)
115 help (mq present)
103
116
104 $ echo "mq=" >> $HGRCPATH
117 $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
118 $ mv hgrc.tmp $HGRCPATH
119
105 $ hg help qrecord
120 $ hg help qrecord
106 hg qrecord [OPTION]... PATCH [FILE]...
121 hg qrecord [OPTION]... PATCH [FILE]...
107
122
108 interactively record a new patch
123 interactively record a new patch
109
124
110 See "hg help qnew" & "hg help record" for more information and usage.
125 See "hg help qnew" & "hg help record" for more information and usage.
111
126
112 options:
127 options:
113
128
114 -e --edit edit commit message
129 -e --edit edit commit message
115 -g --git use git extended diff format
130 -g --git use git extended diff format
116 -U --currentuser add "From: <current user>" to patch
131 -U --currentuser add "From: <current user>" to patch
117 -u --user USER add "From: <USER>" to patch
132 -u --user USER add "From: <USER>" to patch
118 -D --currentdate add "Date: <current date>" to patch
133 -D --currentdate add "Date: <current date>" to patch
119 -d --date DATE add "Date: <DATE>" to patch
134 -d --date DATE add "Date: <DATE>" to patch
120 -I --include PATTERN [+] include names matching the given patterns
135 -I --include PATTERN [+] include names matching the given patterns
121 -X --exclude PATTERN [+] exclude names matching the given patterns
136 -X --exclude PATTERN [+] exclude names matching the given patterns
122 -m --message TEXT use text as commit message
137 -m --message TEXT use text as commit message
123 -l --logfile FILE read commit message from file
138 -l --logfile FILE read commit message from file
124
139
125 [+] marked option can be specified multiple times
140 [+] marked option can be specified multiple times
126
141
127 use "hg -v help qrecord" to show global options
142 use "hg -v help qrecord" to show global options
128
143
129 $ cd a
144 $ cd a
130
145
131 Base commit
146 Base commit
132
147
133 $ cat > 1.txt <<EOF
148 $ cat > 1.txt <<EOF
134 > 1
149 > 1
135 > 2
150 > 2
136 > 3
151 > 3
137 > 4
152 > 4
138 > 5
153 > 5
139 > EOF
154 > EOF
140 $ cat > 2.txt <<EOF
155 $ cat > 2.txt <<EOF
141 > a
156 > a
142 > b
157 > b
143 > c
158 > c
144 > d
159 > d
145 > e
160 > e
146 > f
161 > f
147 > EOF
162 > EOF
148
163
149 $ mkdir dir
164 $ mkdir dir
150 $ cat > dir/a.txt <<EOF
165 $ cat > dir/a.txt <<EOF
151 > hello world
166 > hello world
152 >
167 >
153 > someone
168 > someone
154 > up
169 > up
155 > there
170 > there
156 > loves
171 > loves
157 > me
172 > me
158 > EOF
173 > EOF
159
174
160 $ hg add 1.txt 2.txt dir/a.txt
175 $ hg add 1.txt 2.txt dir/a.txt
161 $ hg commit -m 'initial checkin'
176 $ hg commit -m 'initial checkin'
162
177
163 Changing files
178 Changing files
164
179
165 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
180 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
166 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
181 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
167 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
182 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
168
183
169 $ mv -f 1.txt.new 1.txt
184 $ mv -f 1.txt.new 1.txt
170 $ mv -f 2.txt.new 2.txt
185 $ mv -f 2.txt.new 2.txt
171 $ mv -f dir/a.txt.new dir/a.txt
186 $ mv -f dir/a.txt.new dir/a.txt
172
187
173 Whole diff
188 Whole diff
174
189
175 $ hg diff --nodates
190 $ hg diff --nodates
176 diff -r 1057167b20ef 1.txt
191 diff -r 1057167b20ef 1.txt
177 --- a/1.txt
192 --- a/1.txt
178 +++ b/1.txt
193 +++ b/1.txt
179 @@ -1,5 +1,5 @@
194 @@ -1,5 +1,5 @@
180 1
195 1
181 -2
196 -2
182 +2 2
197 +2 2
183 3
198 3
184 -4
199 -4
185 +4 4
200 +4 4
186 5
201 5
187 diff -r 1057167b20ef 2.txt
202 diff -r 1057167b20ef 2.txt
188 --- a/2.txt
203 --- a/2.txt
189 +++ b/2.txt
204 +++ b/2.txt
190 @@ -1,5 +1,5 @@
205 @@ -1,5 +1,5 @@
191 a
206 a
192 -b
207 -b
193 +b b
208 +b b
194 c
209 c
195 d
210 d
196 e
211 e
197 diff -r 1057167b20ef dir/a.txt
212 diff -r 1057167b20ef dir/a.txt
198 --- a/dir/a.txt
213 --- a/dir/a.txt
199 +++ b/dir/a.txt
214 +++ b/dir/a.txt
200 @@ -1,4 +1,4 @@
215 @@ -1,4 +1,4 @@
201 -hello world
216 -hello world
202 +hello world!
217 +hello world!
203
218
204 someone
219 someone
205 up
220 up
206
221
207 qrecord a.patch
222 qrecord a.patch
208
223
209 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
224 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
210 > y
225 > y
211 > y
226 > y
212 > n
227 > n
213 > y
228 > y
214 > y
229 > y
215 > n
230 > n
216 > EOF
231 > EOF
217 diff --git a/1.txt b/1.txt
232 diff --git a/1.txt b/1.txt
218 2 hunks, 2 lines changed
233 2 hunks, 2 lines changed
219 examine changes to '1.txt'? [Ynsfdaq?]
234 examine changes to '1.txt'? [Ynsfdaq?]
220 @@ -1,3 +1,3 @@
235 @@ -1,3 +1,3 @@
221 1
236 1
222 -2
237 -2
223 +2 2
238 +2 2
224 3
239 3
225 record change 1/4 to '1.txt'? [Ynsfdaq?]
240 record change 1/4 to '1.txt'? [Ynsfdaq?]
226 @@ -3,3 +3,3 @@
241 @@ -3,3 +3,3 @@
227 3
242 3
228 -4
243 -4
229 +4 4
244 +4 4
230 5
245 5
231 record change 2/4 to '1.txt'? [Ynsfdaq?]
246 record change 2/4 to '1.txt'? [Ynsfdaq?]
232 diff --git a/2.txt b/2.txt
247 diff --git a/2.txt b/2.txt
233 1 hunks, 1 lines changed
248 1 hunks, 1 lines changed
234 examine changes to '2.txt'? [Ynsfdaq?]
249 examine changes to '2.txt'? [Ynsfdaq?]
235 @@ -1,5 +1,5 @@
250 @@ -1,5 +1,5 @@
236 a
251 a
237 -b
252 -b
238 +b b
253 +b b
239 c
254 c
240 d
255 d
241 e
256 e
242 record change 3/4 to '2.txt'? [Ynsfdaq?]
257 record change 3/4 to '2.txt'? [Ynsfdaq?]
243 diff --git a/dir/a.txt b/dir/a.txt
258 diff --git a/dir/a.txt b/dir/a.txt
244 1 hunks, 1 lines changed
259 1 hunks, 1 lines changed
245 examine changes to 'dir/a.txt'? [Ynsfdaq?]
260 examine changes to 'dir/a.txt'? [Ynsfdaq?]
246
261
247 After qrecord a.patch 'tip'"
262 After qrecord a.patch 'tip'"
248
263
249 $ hg tip -p
264 $ hg tip -p
250 changeset: 1:5d1ca63427ee
265 changeset: 1:5d1ca63427ee
251 tag: a.patch
266 tag: a.patch
252 tag: qbase
267 tag: qbase
253 tag: qtip
268 tag: qtip
254 tag: tip
269 tag: tip
255 user: test
270 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
271 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: aaa
272 summary: aaa
258
273
259 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
274 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
260 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
275 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
261 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
276 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
262 @@ -1,5 +1,5 @@
277 @@ -1,5 +1,5 @@
263 1
278 1
264 -2
279 -2
265 +2 2
280 +2 2
266 3
281 3
267 4
282 4
268 5
283 5
269 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
284 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
270 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
285 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
271 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
286 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
272 @@ -1,5 +1,5 @@
287 @@ -1,5 +1,5 @@
273 a
288 a
274 -b
289 -b
275 +b b
290 +b b
276 c
291 c
277 d
292 d
278 e
293 e
279
294
280
295
281 After qrecord a.patch 'diff'"
296 After qrecord a.patch 'diff'"
282
297
283 $ hg diff --nodates
298 $ hg diff --nodates
284 diff -r 5d1ca63427ee 1.txt
299 diff -r 5d1ca63427ee 1.txt
285 --- a/1.txt
300 --- a/1.txt
286 +++ b/1.txt
301 +++ b/1.txt
287 @@ -1,5 +1,5 @@
302 @@ -1,5 +1,5 @@
288 1
303 1
289 2 2
304 2 2
290 3
305 3
291 -4
306 -4
292 +4 4
307 +4 4
293 5
308 5
294 diff -r 5d1ca63427ee dir/a.txt
309 diff -r 5d1ca63427ee dir/a.txt
295 --- a/dir/a.txt
310 --- a/dir/a.txt
296 +++ b/dir/a.txt
311 +++ b/dir/a.txt
297 @@ -1,4 +1,4 @@
312 @@ -1,4 +1,4 @@
298 -hello world
313 -hello world
299 +hello world!
314 +hello world!
300
315
301 someone
316 someone
302 up
317 up
303
318
304 qrecord b.patch
319 qrecord b.patch
305
320
306 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
321 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
307 > y
322 > y
308 > y
323 > y
309 > y
324 > y
310 > y
325 > y
311 > EOF
326 > EOF
312 diff --git a/1.txt b/1.txt
327 diff --git a/1.txt b/1.txt
313 1 hunks, 1 lines changed
328 1 hunks, 1 lines changed
314 examine changes to '1.txt'? [Ynsfdaq?]
329 examine changes to '1.txt'? [Ynsfdaq?]
315 @@ -1,5 +1,5 @@
330 @@ -1,5 +1,5 @@
316 1
331 1
317 2 2
332 2 2
318 3
333 3
319 -4
334 -4
320 +4 4
335 +4 4
321 5
336 5
322 record change 1/2 to '1.txt'? [Ynsfdaq?]
337 record change 1/2 to '1.txt'? [Ynsfdaq?]
323 diff --git a/dir/a.txt b/dir/a.txt
338 diff --git a/dir/a.txt b/dir/a.txt
324 1 hunks, 1 lines changed
339 1 hunks, 1 lines changed
325 examine changes to 'dir/a.txt'? [Ynsfdaq?]
340 examine changes to 'dir/a.txt'? [Ynsfdaq?]
326 @@ -1,4 +1,4 @@
341 @@ -1,4 +1,4 @@
327 -hello world
342 -hello world
328 +hello world!
343 +hello world!
329
344
330 someone
345 someone
331 up
346 up
332 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
347 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
333
348
334 After qrecord b.patch 'tip'
349 After qrecord b.patch 'tip'
335
350
336 $ hg tip -p
351 $ hg tip -p
337 changeset: 2:b056198bf878
352 changeset: 2:b056198bf878
338 tag: b.patch
353 tag: b.patch
339 tag: qtip
354 tag: qtip
340 tag: tip
355 tag: tip
341 user: test
356 user: test
342 date: Thu Jan 01 00:00:00 1970 +0000
357 date: Thu Jan 01 00:00:00 1970 +0000
343 summary: bbb
358 summary: bbb
344
359
345 diff -r 5d1ca63427ee -r b056198bf878 1.txt
360 diff -r 5d1ca63427ee -r b056198bf878 1.txt
346 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
361 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
347 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
362 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
348 @@ -1,5 +1,5 @@
363 @@ -1,5 +1,5 @@
349 1
364 1
350 2 2
365 2 2
351 3
366 3
352 -4
367 -4
353 +4 4
368 +4 4
354 5
369 5
355 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
370 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
356 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
371 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
357 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
372 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
358 @@ -1,4 +1,4 @@
373 @@ -1,4 +1,4 @@
359 -hello world
374 -hello world
360 +hello world!
375 +hello world!
361
376
362 someone
377 someone
363 up
378 up
364
379
365
380
366 After qrecord b.patch 'diff'
381 After qrecord b.patch 'diff'
367
382
368 $ hg diff --nodates
383 $ hg diff --nodates
General Comments 0
You need to be logged in to leave comments. Login now