##// END OF EJS Templates
makes username mandatory
Benoit Boissinot -
r3466:8b55c0ba default
parent child Browse files
Show More
@@ -1,496 +1,495
1 1 HGRC(5)
2 2 =======
3 3 Bryan O'Sullivan <bos@serpentine.com>
4 4
5 5 NAME
6 6 ----
7 7 hgrc - configuration files for Mercurial
8 8
9 9 SYNOPSIS
10 10 --------
11 11
12 12 The Mercurial system uses a set of configuration files to control
13 13 aspects of its behaviour.
14 14
15 15 FILES
16 16 -----
17 17
18 18 Mercurial reads configuration data from several files, if they exist.
19 19 The names of these files depend on the system on which Mercurial is
20 20 installed.
21 21
22 22 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
23 23 (Unix) <install-root>/etc/mercurial/hgrc::
24 24 Per-installation configuration files, searched for in the
25 25 directory where Mercurial is installed. For example, if installed
26 26 in /shared/tools, Mercurial will look in
27 27 /shared/tools/etc/mercurial/hgrc. Options in these files apply to
28 28 all Mercurial commands executed by any user in any directory.
29 29
30 30 (Unix) /etc/mercurial/hgrc.d/*.rc::
31 31 (Unix) /etc/mercurial/hgrc::
32 32 (Windows) C:\Mercurial\Mercurial.ini::
33 33 Per-system configuration files, for the system on which Mercurial
34 34 is running. Options in these files apply to all Mercurial
35 35 commands executed by any user in any directory. Options in these
36 36 files override per-installation options.
37 37
38 38 (Unix) $HOME/.hgrc::
39 39 (Windows) C:\Documents and Settings\USERNAME\Mercurial.ini::
40 40 (Windows) $HOME\Mercurial.ini::
41 41 Per-user configuration file, for the user running Mercurial.
42 42 Options in this file apply to all Mercurial commands executed by
43 43 any user in any directory. Options in this file override
44 44 per-installation and per-system options.
45 45 On Windows system, one of these is chosen exclusively according
46 46 to definition of HOME environment variable.
47 47
48 48 (Unix, Windows) <repo>/.hg/hgrc::
49 49 Per-repository configuration options that only apply in a
50 50 particular repository. This file is not version-controlled, and
51 51 will not get transferred during a "clone" operation. Options in
52 52 this file override options in all other configuration files.
53 53
54 54 SYNTAX
55 55 ------
56 56
57 57 A configuration file consists of sections, led by a "[section]" header
58 58 and followed by "name: value" entries; "name=value" is also accepted.
59 59
60 60 [spam]
61 61 eggs=ham
62 62 green=
63 63 eggs
64 64
65 65 Each line contains one entry. If the lines that follow are indented,
66 66 they are treated as continuations of that entry.
67 67
68 68 Leading whitespace is removed from values. Empty lines are skipped.
69 69
70 70 The optional values can contain format strings which refer to other
71 71 values in the same section, or values in a special DEFAULT section.
72 72
73 73 Lines beginning with "#" or ";" are ignored and may be used to provide
74 74 comments.
75 75
76 76 SECTIONS
77 77 --------
78 78
79 79 This section describes the different sections that may appear in a
80 80 Mercurial "hgrc" file, the purpose of each section, its possible
81 81 keys, and their possible values.
82 82
83 83 decode/encode::
84 84 Filters for transforming files on checkout/checkin. This would
85 85 typically be used for newline processing or other
86 86 localization/canonicalization of files.
87 87
88 88 Filters consist of a filter pattern followed by a filter command.
89 89 Filter patterns are globs by default, rooted at the repository
90 90 root. For example, to match any file ending in ".txt" in the root
91 91 directory only, use the pattern "*.txt". To match any file ending
92 92 in ".c" anywhere in the repository, use the pattern "**.c".
93 93
94 94 The filter command can start with a specifier, either "pipe:" or
95 95 "tempfile:". If no specifier is given, "pipe:" is used by default.
96 96
97 97 A "pipe:" command must accept data on stdin and return the
98 98 transformed data on stdout.
99 99
100 100 Pipe example:
101 101
102 102 [encode]
103 103 # uncompress gzip files on checkin to improve delta compression
104 104 # note: not necessarily a good idea, just an example
105 105 *.gz = pipe: gunzip
106 106
107 107 [decode]
108 108 # recompress gzip files when writing them to the working dir (we
109 109 # can safely omit "pipe:", because it's the default)
110 110 *.gz = gzip
111 111
112 112 A "tempfile:" command is a template. The string INFILE is replaced
113 113 with the name of a temporary file that contains the data to be
114 114 filtered by the command. The string OUTFILE is replaced with the
115 115 name of an empty temporary file, where the filtered data must be
116 116 written by the command.
117 117
118 118 NOTE: the tempfile mechanism is recommended for Windows systems,
119 119 where the standard shell I/O redirection operators often have
120 120 strange effects. In particular, if you are doing line ending
121 121 conversion on Windows using the popular dos2unix and unix2dos
122 122 programs, you *must* use the tempfile mechanism, as using pipes will
123 123 corrupt the contents of your files.
124 124
125 125 Tempfile example:
126 126
127 127 [encode]
128 128 # convert files to unix line ending conventions on checkin
129 129 **.txt = tempfile: dos2unix -n INFILE OUTFILE
130 130
131 131 [decode]
132 132 # convert files to windows line ending conventions when writing
133 133 # them to the working dir
134 134 **.txt = tempfile: unix2dos -n INFILE OUTFILE
135 135
136 136 defaults::
137 137 Use the [defaults] section to define command defaults, i.e. the
138 138 default options/arguments to pass to the specified commands.
139 139
140 140 The following example makes 'hg log' run in verbose mode, and
141 141 'hg status' show only the modified files, by default.
142 142
143 143 [defaults]
144 144 log = -v
145 145 status = -m
146 146
147 147 The actual commands, instead of their aliases, must be used when
148 148 defining command defaults. The command defaults will also be
149 149 applied to the aliases of the commands defined.
150 150
151 151 email::
152 152 Settings for extensions that send email messages.
153 153 from;;
154 154 Optional. Email address to use in "From" header and SMTP envelope
155 155 of outgoing messages.
156 156 to;;
157 157 Optional. Comma-separated list of recipients' email addresses.
158 158 cc;;
159 159 Optional. Comma-separated list of carbon copy recipients'
160 160 email addresses.
161 161 bcc;;
162 162 Optional. Comma-separated list of blind carbon copy
163 163 recipients' email addresses. Cannot be set interactively.
164 164 method;;
165 165 Optional. Method to use to send email messages. If value is
166 166 "smtp" (default), use SMTP (see section "[smtp]" for
167 167 configuration). Otherwise, use as name of program to run that
168 168 acts like sendmail (takes "-f" option for sender, list of
169 169 recipients on command line, message on stdin). Normally, setting
170 170 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
171 171 sendmail to send messages.
172 172
173 173 Email example:
174 174
175 175 [email]
176 176 from = Joseph User <joe.user@example.com>
177 177 method = /usr/sbin/sendmail
178 178
179 179 extensions::
180 180 Mercurial has an extension mechanism for adding new features. To
181 181 enable an extension, create an entry for it in this section.
182 182
183 183 If you know that the extension is already in Python's search path,
184 184 you can give the name of the module, followed by "=", with nothing
185 185 after the "=".
186 186
187 187 Otherwise, give a name that you choose, followed by "=", followed by
188 188 the path to the ".py" file (including the file name extension) that
189 189 defines the extension.
190 190
191 191 Example for ~/.hgrc:
192 192
193 193 [extensions]
194 194 # (the mq extension will get loaded from mercurial's path)
195 195 hgext.mq =
196 196 # (this extension will get loaded from the file specified)
197 197 myfeature = ~/.hgext/myfeature.py
198 198
199 199 hooks::
200 200 Commands or Python functions that get automatically executed by
201 201 various actions such as starting or finishing a commit. Multiple
202 202 hooks can be run for the same action by appending a suffix to the
203 203 action. Overriding a site-wide hook can be done by changing its
204 204 value or setting it to an empty string.
205 205
206 206 Example .hg/hgrc:
207 207
208 208 [hooks]
209 209 # do not use the site-wide hook
210 210 incoming =
211 211 incoming.email = /my/email/hook
212 212 incoming.autobuild = /my/build/hook
213 213
214 214 Most hooks are run with environment variables set that give added
215 215 useful information. For each hook below, the environment variables
216 216 it is passed are listed with names of the form "$HG_foo".
217 217
218 218 changegroup;;
219 219 Run after a changegroup has been added via push, pull or
220 220 unbundle. ID of the first new changeset is in $HG_NODE. URL from
221 221 which changes came is in $HG_URL.
222 222 commit;;
223 223 Run after a changeset has been created in the local repository.
224 224 ID of the newly created changeset is in $HG_NODE. Parent
225 225 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
226 226 incoming;;
227 227 Run after a changeset has been pulled, pushed, or unbundled into
228 228 the local repository. The ID of the newly arrived changeset is in
229 229 $HG_NODE. URL that was source of changes came is in $HG_URL.
230 230 outgoing;;
231 231 Run after sending changes from local repository to another. ID of
232 232 first changeset sent is in $HG_NODE. Source of operation is in
233 233 $HG_SOURCE; see "preoutgoing" hook for description.
234 234 prechangegroup;;
235 235 Run before a changegroup is added via push, pull or unbundle.
236 236 Exit status 0 allows the changegroup to proceed. Non-zero status
237 237 will cause the push, pull or unbundle to fail. URL from which
238 238 changes will come is in $HG_URL.
239 239 precommit;;
240 240 Run before starting a local commit. Exit status 0 allows the
241 241 commit to proceed. Non-zero status will cause the commit to fail.
242 242 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
243 243 preoutgoing;;
244 244 Run before computing changes to send from the local repository to
245 245 another. Non-zero status will cause failure. This lets you
246 246 prevent pull over http or ssh. Also prevents against local pull,
247 247 push (outbound) or bundle commands, but not effective, since you
248 248 can just copy files instead then. Source of operation is in
249 249 $HG_SOURCE. If "serve", operation is happening on behalf of
250 250 remote ssh or http repository. If "push", "pull" or "bundle",
251 251 operation is happening on behalf of repository on same system.
252 252 pretag;;
253 253 Run before creating a tag. Exit status 0 allows the tag to be
254 254 created. Non-zero status will cause the tag to fail. ID of
255 255 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
256 256 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
257 257 pretxnchangegroup;;
258 258 Run after a changegroup has been added via push, pull or unbundle,
259 259 but before the transaction has been committed. Changegroup is
260 260 visible to hook program. This lets you validate incoming changes
261 261 before accepting them. Passed the ID of the first new changeset
262 262 in $HG_NODE. Exit status 0 allows the transaction to commit.
263 263 Non-zero status will cause the transaction to be rolled back and
264 264 the push, pull or unbundle will fail. URL that was source of
265 265 changes is in $HG_URL.
266 266 pretxncommit;;
267 267 Run after a changeset has been created but the transaction not yet
268 268 committed. Changeset is visible to hook program. This lets you
269 269 validate commit message and changes. Exit status 0 allows the
270 270 commit to proceed. Non-zero status will cause the transaction to
271 271 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
272 272 IDs are in $HG_PARENT1 and $HG_PARENT2.
273 273 preupdate;;
274 274 Run before updating the working directory. Exit status 0 allows
275 275 the update to proceed. Non-zero status will prevent the update.
276 276 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
277 277 of second new parent is in $HG_PARENT2.
278 278 tag;;
279 279 Run after a tag is created. ID of tagged changeset is in
280 280 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
281 281 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
282 282 update;;
283 283 Run after updating the working directory. Changeset ID of first
284 284 new parent is in $HG_PARENT1. If merge, ID of second new parent
285 285 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
286 286 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
287 287
288 288 Note: In earlier releases, the names of hook environment variables
289 289 did not have a "HG_" prefix. The old unprefixed names are no longer
290 290 provided in the environment.
291 291
292 292 The syntax for Python hooks is as follows:
293 293
294 294 hookname = python:modulename.submodule.callable
295 295
296 296 Python hooks are run within the Mercurial process. Each hook is
297 297 called with at least three keyword arguments: a ui object (keyword
298 298 "ui"), a repository object (keyword "repo"), and a "hooktype"
299 299 keyword that tells what kind of hook is used. Arguments listed as
300 300 environment variables above are passed as keyword arguments, with no
301 301 "HG_" prefix, and names in lower case.
302 302
303 303 A Python hook must return a "true" value to succeed. Returning a
304 304 "false" value or raising an exception is treated as failure of the
305 305 hook.
306 306
307 307 http_proxy::
308 308 Used to access web-based Mercurial repositories through a HTTP
309 309 proxy.
310 310 host;;
311 311 Host name and (optional) port of the proxy server, for example
312 312 "myproxy:8000".
313 313 no;;
314 314 Optional. Comma-separated list of host names that should bypass
315 315 the proxy.
316 316 passwd;;
317 317 Optional. Password to authenticate with at the proxy server.
318 318 user;;
319 319 Optional. User name to authenticate with at the proxy server.
320 320
321 321 smtp::
322 322 Configuration for extensions that need to send email messages.
323 323 host;;
324 324 Host name of mail server, e.g. "mail.example.com".
325 325 port;;
326 326 Optional. Port to connect to on mail server. Default: 25.
327 327 tls;;
328 328 Optional. Whether to connect to mail server using TLS. True or
329 329 False. Default: False.
330 330 username;;
331 331 Optional. User name to authenticate to SMTP server with.
332 332 If username is specified, password must also be specified.
333 333 Default: none.
334 334 password;;
335 335 Optional. Password to authenticate to SMTP server with.
336 336 If username is specified, password must also be specified.
337 337 Default: none.
338 338 local_hostname;;
339 339 Optional. It's the hostname that the sender can use to identify itself
340 340 to the MTA.
341 341
342 342 paths::
343 343 Assigns symbolic names to repositories. The left side is the
344 344 symbolic name, and the right gives the directory or URL that is the
345 345 location of the repository. Default paths can be declared by
346 346 setting the following entries.
347 347 default;;
348 348 Directory or URL to use when pulling if no source is specified.
349 349 Default is set to repository from which the current repository
350 350 was cloned.
351 351 default-push;;
352 352 Optional. Directory or URL to use when pushing if no destination
353 353 is specified.
354 354
355 355 server::
356 356 Controls generic server settings.
357 357 uncompressed;;
358 358 Whether to allow clients to clone a repo using the uncompressed
359 359 streaming protocol. This transfers about 40% more data than a
360 360 regular clone, but uses less memory and CPU on both server and
361 361 client. Over a LAN (100Mbps or better) or a very fast WAN, an
362 362 uncompressed streaming clone is a lot faster (~10x) than a regular
363 363 clone. Over most WAN connections (anything slower than about
364 364 6Mbps), uncompressed streaming is slower, because of the extra
365 365 data transfer overhead. Default is False.
366 366
367 367 ui::
368 368 User interface controls.
369 369 debug;;
370 370 Print debugging information. True or False. Default is False.
371 371 editor;;
372 372 The editor to use during a commit. Default is $EDITOR or "vi".
373 373 ignore;;
374 374 A file to read per-user ignore patterns from. This file should be in
375 375 the same format as a repository-wide .hgignore file. This option
376 376 supports hook syntax, so if you want to specify multiple ignore
377 377 files, you can do so by setting something like
378 378 "ignore.other = ~/.hgignore2". For details of the ignore file
379 379 format, see the hgignore(5) man page.
380 380 interactive;;
381 381 Allow to prompt the user. True or False. Default is True.
382 382 logtemplate;;
383 383 Template string for commands that print changesets.
384 384 style;;
385 385 Name of style to use for command output.
386 386 merge;;
387 387 The conflict resolution program to use during a manual merge.
388 388 Default is "hgmerge".
389 389 quiet;;
390 390 Reduce the amount of output printed. True or False. Default is False.
391 391 remotecmd;;
392 392 remote command to use for clone/push/pull operations. Default is 'hg'.
393 393 ssh;;
394 394 command to use for SSH connections. Default is 'ssh'.
395 395 strict;;
396 396 Require exact command names, instead of allowing unambiguous
397 397 abbreviations. True or False. Default is False.
398 398 timeout;;
399 399 The timeout used when a lock is held (in seconds), a negative value
400 400 means no timeout. Default is 600.
401 401 username;;
402 402 The committer of a changeset created when running "commit".
403 403 Typically a person's name and email address, e.g. "Fred Widget
404 <fred@example.com>". Default is $EMAIL or username@hostname, unless
405 username is set to an empty string, which enforces specifying the
406 username manually.
404 <fred@example.com>". Default is $EMAIL. If no default is found,
405 the username have to be specified manually.
407 406 verbose;;
408 407 Increase the amount of output printed. True or False. Default is False.
409 408
410 409
411 410 web::
412 411 Web interface configuration.
413 412 accesslog;;
414 413 Where to output the access log. Default is stdout.
415 414 address;;
416 415 Interface address to bind to. Default is all.
417 416 allow_archive;;
418 417 List of archive format (bz2, gz, zip) allowed for downloading.
419 418 Default is empty.
420 419 allowbz2;;
421 420 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
422 421 Default is false.
423 422 allowgz;;
424 423 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
425 424 Default is false.
426 425 allowpull;;
427 426 Whether to allow pulling from the repository. Default is true.
428 427 allow_push;;
429 428 Whether to allow pushing to the repository. If empty or not set,
430 429 push is not allowed. If the special value "*", any remote user
431 430 can push, including unauthenticated users. Otherwise, the remote
432 431 user must have been authenticated, and the authenticated user name
433 432 must be present in this list (separated by whitespace or ",").
434 433 The contents of the allow_push list are examined after the
435 434 deny_push list.
436 435 allowzip;;
437 436 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
438 437 Default is false. This feature creates temporary files.
439 438 baseurl;;
440 439 Base URL to use when publishing URLs in other locations, so
441 440 third-party tools like email notification hooks can construct URLs.
442 441 Example: "http://hgserver/repos/"
443 442 contact;;
444 443 Name or email address of the person in charge of the repository.
445 444 Default is "unknown".
446 445 deny_push;;
447 446 Whether to deny pushing to the repository. If empty or not set,
448 447 push is not denied. If the special value "*", all remote users
449 448 are denied push. Otherwise, unauthenticated users are all denied,
450 449 and any authenticated user name present in this list (separated by
451 450 whitespace or ",") is also denied. The contents of the deny_push
452 451 list are examined before the allow_push list.
453 452 description;;
454 453 Textual description of the repository's purpose or contents.
455 454 Default is "unknown".
456 455 errorlog;;
457 456 Where to output the error log. Default is stderr.
458 457 ipv6;;
459 458 Whether to use IPv6. Default is false.
460 459 name;;
461 460 Repository name to use in the web interface. Default is current
462 461 working directory.
463 462 maxchanges;;
464 463 Maximum number of changes to list on the changelog. Default is 10.
465 464 maxfiles;;
466 465 Maximum number of files to list per changeset. Default is 10.
467 466 port;;
468 467 Port to listen on. Default is 8000.
469 468 push_ssl;;
470 469 Whether to require that inbound pushes be transported over SSL to
471 470 prevent password sniffing. Default is true.
472 471 stripes;;
473 472 How many lines a "zebra stripe" should span in multiline output.
474 473 Default is 1; set to 0 to disable.
475 474 style;;
476 475 Which template map style to use.
477 476 templates;;
478 477 Where to find the HTML templates. Default is install path.
479 478
480 479
481 480 AUTHOR
482 481 ------
483 482 Bryan O'Sullivan <bos@serpentine.com>.
484 483
485 484 Mercurial was written by Matt Mackall <mpm@selenic.com>.
486 485
487 486 SEE ALSO
488 487 --------
489 488 hg(1), hgignore(5)
490 489
491 490 COPYING
492 491 -------
493 492 This manual page is copyright 2005 Bryan O'Sullivan.
494 493 Mercurial is copyright 2005, 2006 Matt Mackall.
495 494 Free use of this software is granted under the terms of the GNU General
496 495 Public License (GPL).
@@ -1,342 +1,337
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import gettext as _
9 9 from demandload import *
10 10 demandload(globals(), "errno getpass os re socket sys tempfile")
11 11 demandload(globals(), "ConfigParser traceback util")
12 12
13 13 def dupconfig(orig):
14 14 new = util.configparser(orig.defaults())
15 15 updateconfig(orig, new)
16 16 return new
17 17
18 18 def updateconfig(source, dest, sections=None):
19 19 if not sections:
20 20 sections = source.sections()
21 21 for section in sections:
22 22 if not dest.has_section(section):
23 23 dest.add_section(section)
24 24 for name, value in source.items(section, raw=True):
25 25 dest.set(section, name, value)
26 26
27 27 class ui(object):
28 28 def __init__(self, verbose=False, debug=False, quiet=False,
29 29 interactive=True, traceback=False, parentui=None):
30 30 self.overlay = None
31 31 self.header = []
32 32 self.prev_header = []
33 33 if parentui is None:
34 34 # this is the parent of all ui children
35 35 self.parentui = None
36 36 self.readhooks = []
37 37 self.quiet = quiet
38 38 self.verbose = verbose
39 39 self.debugflag = debug
40 40 self.interactive = interactive
41 41 self.traceback = traceback
42 42 self.cdata = util.configparser()
43 43 self.readconfig(util.rcpath())
44 44 self.updateopts(verbose, debug, quiet, interactive)
45 45 else:
46 46 # parentui may point to an ui object which is already a child
47 47 self.parentui = parentui.parentui or parentui
48 48 self.readhooks = self.parentui.readhooks[:]
49 49 self.cdata = dupconfig(self.parentui.cdata)
50 50 if self.parentui.overlay:
51 51 self.overlay = dupconfig(self.parentui.overlay)
52 52
53 53 def __getattr__(self, key):
54 54 return getattr(self.parentui, key)
55 55
56 56 def updateopts(self, verbose=False, debug=False, quiet=False,
57 57 interactive=True, traceback=False, config=[]):
58 58 for section, name, value in config:
59 59 self.setconfig(section, name, value)
60 60
61 61 if quiet or verbose or debug:
62 62 self.setconfig('ui', 'quiet', str(bool(quiet)))
63 63 self.setconfig('ui', 'verbose', str(bool(verbose)))
64 64 self.setconfig('ui', 'debug', str(bool(debug)))
65 65
66 66 self.verbosity_constraints()
67 67
68 68 if not interactive:
69 69 self.setconfig('ui', 'interactive', 'False')
70 70 self.interactive = False
71 71
72 72 self.traceback = self.traceback or traceback
73 73
74 74 def verbosity_constraints(self):
75 75 self.quiet = self.configbool('ui', 'quiet')
76 76 self.verbose = self.configbool('ui', 'verbose')
77 77 self.debugflag = self.configbool('ui', 'debug')
78 78
79 79 if self.debugflag:
80 80 self.verbose = True
81 81 self.quiet = False
82 82 elif self.verbose and self.quiet:
83 83 self.quiet = self.verbose = False
84 84
85 85 def readconfig(self, fn, root=None):
86 86 if isinstance(fn, basestring):
87 87 fn = [fn]
88 88 for f in fn:
89 89 try:
90 90 self.cdata.read(f)
91 91 except ConfigParser.ParsingError, inst:
92 92 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
93 93 # override data from config files with data set with ui.setconfig
94 94 if self.overlay:
95 95 updateconfig(self.overlay, self.cdata)
96 96 if root is None:
97 97 root = os.path.expanduser('~')
98 98 self.fixconfig(root=root)
99 99 for hook in self.readhooks:
100 100 hook(self)
101 101
102 102 def addreadhook(self, hook):
103 103 self.readhooks.append(hook)
104 104
105 105 def readsections(self, filename, *sections):
106 106 "read filename and add only the specified sections to the config data"
107 107 if not sections:
108 108 return
109 109
110 110 cdata = util.configparser()
111 111 try:
112 112 cdata.read(filename)
113 113 except ConfigParser.ParsingError, inst:
114 114 raise util.Abort(_("failed to parse %s\n%s") % (f, inst))
115 115
116 116 for section in sections:
117 117 if not cdata.has_section(section):
118 118 cdata.add_section(section)
119 119
120 120 updateconfig(cdata, self.cdata, sections)
121 121
122 122 def fixconfig(self, section=None, name=None, value=None, root=None):
123 123 # translate paths relative to root (or home) into absolute paths
124 124 if section is None or section == 'paths':
125 125 if root is None:
126 126 root = os.getcwd()
127 127 items = section and [(name, value)] or []
128 128 for cdata in self.cdata, self.overlay:
129 129 if not cdata: continue
130 130 if not items and cdata.has_section('paths'):
131 131 pathsitems = cdata.items('paths')
132 132 else:
133 133 pathsitems = items
134 134 for n, path in pathsitems:
135 135 if path and "://" not in path and not os.path.isabs(path):
136 136 cdata.set("paths", n, os.path.join(root, path))
137 137
138 138 # update quiet/verbose/debug and interactive status
139 139 if section is None or section == 'ui':
140 140 if name is None or name in ('quiet', 'verbose', 'debug'):
141 141 self.verbosity_constraints()
142 142
143 143 if name is None or name == 'interactive':
144 144 self.interactive = self.configbool("ui", "interactive", True)
145 145
146 146 def setconfig(self, section, name, value):
147 147 if not self.overlay:
148 148 self.overlay = util.configparser()
149 149 for cdata in (self.overlay, self.cdata):
150 150 if not cdata.has_section(section):
151 151 cdata.add_section(section)
152 152 cdata.set(section, name, value)
153 153 self.fixconfig(section, name, value)
154 154
155 155 def _config(self, section, name, default, funcname):
156 156 if self.cdata.has_option(section, name):
157 157 try:
158 158 func = getattr(self.cdata, funcname)
159 159 return func(section, name)
160 160 except ConfigParser.InterpolationError, inst:
161 161 raise util.Abort(_("Error in configuration section [%s] "
162 162 "parameter '%s':\n%s")
163 163 % (section, name, inst))
164 164 return default
165 165
166 166 def config(self, section, name, default=None):
167 167 return self._config(section, name, default, 'get')
168 168
169 169 def configbool(self, section, name, default=False):
170 170 return self._config(section, name, default, 'getboolean')
171 171
172 172 def configlist(self, section, name, default=None):
173 173 """Return a list of comma/space separated strings"""
174 174 result = self.config(section, name)
175 175 if result is None:
176 176 result = default or []
177 177 if isinstance(result, basestring):
178 178 result = result.replace(",", " ").split()
179 179 return result
180 180
181 181 def has_config(self, section):
182 182 '''tell whether section exists in config.'''
183 183 return self.cdata.has_section(section)
184 184
185 185 def configitems(self, section):
186 186 items = {}
187 187 if self.cdata.has_section(section):
188 188 try:
189 189 items.update(dict(self.cdata.items(section)))
190 190 except ConfigParser.InterpolationError, inst:
191 191 raise util.Abort(_("Error in configuration section [%s]:\n%s")
192 192 % (section, inst))
193 193 x = items.items()
194 194 x.sort()
195 195 return x
196 196
197 197 def walkconfig(self):
198 198 sections = self.cdata.sections()
199 199 sections.sort()
200 200 for section in sections:
201 201 for name, value in self.configitems(section):
202 202 yield section, name, value.replace('\n', '\\n')
203 203
204 204 def extensions(self):
205 205 result = self.configitems("extensions")
206 206 for i, (key, value) in enumerate(result):
207 207 if value:
208 208 result[i] = (key, os.path.expanduser(value))
209 209 return result
210 210
211 211 def hgignorefiles(self):
212 212 result = []
213 213 for key, value in self.configitems("ui"):
214 214 if key == 'ignore' or key.startswith('ignore.'):
215 215 result.append(os.path.expanduser(value))
216 216 return result
217 217
218 218 def configrevlog(self):
219 219 result = {}
220 220 for key, value in self.configitems("revlog"):
221 221 result[key.lower()] = value
222 222 return result
223 223
224 224 def username(self):
225 225 """Return default username to be used in commits.
226 226
227 227 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
228 228 and stop searching if one of these is set.
229 Abort if found username is an empty string to force specifying
230 the commit user elsewhere, e.g. with line option or repo hgrc.
231 If not found, use ($LOGNAME or $USER or $LNAME or
232 $USERNAME) +"@full.hostname".
229 Abort if no username is found, to force specifying the commit user
230 with line option or repo hgrc.
233 231 """
234 232 user = os.environ.get("HGUSER")
235 233 if user is None:
236 234 user = self.config("ui", "username")
237 235 if user is None:
238 236 user = os.environ.get("EMAIL")
239 237 if user is None:
240 try:
241 user = '%s@%s' % (util.getuser(), socket.getfqdn())
242 except KeyError:
243 raise util.Abort(_("Please specify a username."))
238 raise util.Abort(_("No default username available, use -u"))
244 239 return user
245 240
246 241 def shortuser(self, user):
247 242 """Return a short representation of a user name or email address."""
248 243 if not self.verbose: user = util.shortuser(user)
249 244 return user
250 245
251 246 def expandpath(self, loc, default=None):
252 247 """Return repository location relative to cwd or from [paths]"""
253 248 if "://" in loc or os.path.isdir(loc):
254 249 return loc
255 250
256 251 path = self.config("paths", loc)
257 252 if not path and default is not None:
258 253 path = self.config("paths", default)
259 254 return path or loc
260 255
261 256 def write(self, *args):
262 257 if self.header:
263 258 if self.header != self.prev_header:
264 259 self.prev_header = self.header
265 260 self.write(*self.header)
266 261 self.header = []
267 262 for a in args:
268 263 sys.stdout.write(str(a))
269 264
270 265 def write_header(self, *args):
271 266 for a in args:
272 267 self.header.append(str(a))
273 268
274 269 def write_err(self, *args):
275 270 try:
276 271 if not sys.stdout.closed: sys.stdout.flush()
277 272 for a in args:
278 273 sys.stderr.write(str(a))
279 274 except IOError, inst:
280 275 if inst.errno != errno.EPIPE:
281 276 raise
282 277
283 278 def flush(self):
284 279 try: sys.stdout.flush()
285 280 except: pass
286 281 try: sys.stderr.flush()
287 282 except: pass
288 283
289 284 def readline(self):
290 285 return sys.stdin.readline()[:-1]
291 286 def prompt(self, msg, pat=None, default="y"):
292 287 if not self.interactive: return default
293 288 while 1:
294 289 self.write(msg, " ")
295 290 r = self.readline()
296 291 if not pat or re.match(pat, r):
297 292 return r
298 293 else:
299 294 self.write(_("unrecognized response\n"))
300 295 def getpass(self, prompt=None, default=None):
301 296 if not self.interactive: return default
302 297 return getpass.getpass(prompt or _('password: '))
303 298 def status(self, *msg):
304 299 if not self.quiet: self.write(*msg)
305 300 def warn(self, *msg):
306 301 self.write_err(*msg)
307 302 def note(self, *msg):
308 303 if self.verbose: self.write(*msg)
309 304 def debug(self, *msg):
310 305 if self.debugflag: self.write(*msg)
311 306 def edit(self, text, user):
312 307 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
313 308 text=True)
314 309 try:
315 310 f = os.fdopen(fd, "w")
316 311 f.write(text)
317 312 f.close()
318 313
319 314 editor = (os.environ.get("HGEDITOR") or
320 315 self.config("ui", "editor") or
321 316 os.environ.get("EDITOR", "vi"))
322 317
323 318 util.system("%s \"%s\"" % (editor, name),
324 319 environ={'HGUSER': user},
325 320 onerr=util.Abort, errprefix=_("edit failed"))
326 321
327 322 f = open(name)
328 323 t = f.read()
329 324 f.close()
330 325 t = re.sub("(?m)^HG:.*\n", "", t)
331 326 finally:
332 327 os.unlink(name)
333 328
334 329 return t
335 330
336 331 def print_exc(self):
337 332 '''print exception traceback if traceback printing enabled.
338 333 only to call in exception handler. returns true if traceback
339 334 printed.'''
340 335 if self.traceback:
341 336 traceback.print_exc()
342 337 return self.traceback
@@ -1,1035 +1,1021
1 1 """
2 2 util.py - Mercurial utility functions and platform specfic implementations
3 3
4 4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
7 7
8 8 This software may be used and distributed according to the terms
9 9 of the GNU General Public License, incorporated herein by reference.
10 10
11 11 This contains helper routines that are independent of the SCM core and hide
12 12 platform-specific details from the core.
13 13 """
14 14
15 15 from i18n import gettext as _
16 16 from demandload import *
17 17 demandload(globals(), "cStringIO errno getpass popen2 re shutil sys tempfile")
18 18 demandload(globals(), "os threading time calendar ConfigParser")
19 19
20 20 # used by parsedate
21 21 defaultdateformats = ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M',
22 22 '%a %b %d %H:%M:%S %Y')
23 23
24 24 class SignalInterrupt(Exception):
25 25 """Exception raised on SIGTERM and SIGHUP."""
26 26
27 27 # like SafeConfigParser but with case-sensitive keys
28 28 class configparser(ConfigParser.SafeConfigParser):
29 29 def optionxform(self, optionstr):
30 30 return optionstr
31 31
32 32 def cachefunc(func):
33 33 '''cache the result of function calls'''
34 34 # XXX doesn't handle keywords args
35 35 cache = {}
36 36 if func.func_code.co_argcount == 1:
37 37 # we gain a small amount of time because
38 38 # we don't need to pack/unpack the list
39 39 def f(arg):
40 40 if arg not in cache:
41 41 cache[arg] = func(arg)
42 42 return cache[arg]
43 43 else:
44 44 def f(*args):
45 45 if args not in cache:
46 46 cache[args] = func(*args)
47 47 return cache[args]
48 48
49 49 return f
50 50
51 51 def pipefilter(s, cmd):
52 52 '''filter string S through command CMD, returning its output'''
53 53 (pout, pin) = popen2.popen2(cmd, -1, 'b')
54 54 def writer():
55 55 try:
56 56 pin.write(s)
57 57 pin.close()
58 58 except IOError, inst:
59 59 if inst.errno != errno.EPIPE:
60 60 raise
61 61
62 62 # we should use select instead on UNIX, but this will work on most
63 63 # systems, including Windows
64 64 w = threading.Thread(target=writer)
65 65 w.start()
66 66 f = pout.read()
67 67 pout.close()
68 68 w.join()
69 69 return f
70 70
71 71 def tempfilter(s, cmd):
72 72 '''filter string S through a pair of temporary files with CMD.
73 73 CMD is used as a template to create the real command to be run,
74 74 with the strings INFILE and OUTFILE replaced by the real names of
75 75 the temporary files generated.'''
76 76 inname, outname = None, None
77 77 try:
78 78 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
79 79 fp = os.fdopen(infd, 'wb')
80 80 fp.write(s)
81 81 fp.close()
82 82 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
83 83 os.close(outfd)
84 84 cmd = cmd.replace('INFILE', inname)
85 85 cmd = cmd.replace('OUTFILE', outname)
86 86 code = os.system(cmd)
87 87 if code: raise Abort(_("command '%s' failed: %s") %
88 88 (cmd, explain_exit(code)))
89 89 return open(outname, 'rb').read()
90 90 finally:
91 91 try:
92 92 if inname: os.unlink(inname)
93 93 except: pass
94 94 try:
95 95 if outname: os.unlink(outname)
96 96 except: pass
97 97
98 98 filtertable = {
99 99 'tempfile:': tempfilter,
100 100 'pipe:': pipefilter,
101 101 }
102 102
103 103 def filter(s, cmd):
104 104 "filter a string through a command that transforms its input to its output"
105 105 for name, fn in filtertable.iteritems():
106 106 if cmd.startswith(name):
107 107 return fn(s, cmd[len(name):].lstrip())
108 108 return pipefilter(s, cmd)
109 109
110 110 def find_in_path(name, path, default=None):
111 111 '''find name in search path. path can be string (will be split
112 112 with os.pathsep), or iterable thing that returns strings. if name
113 113 found, return path to name. else return default.'''
114 114 if isinstance(path, str):
115 115 path = path.split(os.pathsep)
116 116 for p in path:
117 117 p_name = os.path.join(p, name)
118 118 if os.path.exists(p_name):
119 119 return p_name
120 120 return default
121 121
122 122 def binary(s):
123 123 """return true if a string is binary data using diff's heuristic"""
124 124 if s and '\0' in s[:4096]:
125 125 return True
126 126 return False
127 127
128 128 def unique(g):
129 129 """return the uniq elements of iterable g"""
130 130 seen = {}
131 131 for f in g:
132 132 if f not in seen:
133 133 seen[f] = 1
134 134 yield f
135 135
136 136 class Abort(Exception):
137 137 """Raised if a command needs to print an error and exit."""
138 138
139 139 def always(fn): return True
140 140 def never(fn): return False
141 141
142 142 def patkind(name, dflt_pat='glob'):
143 143 """Split a string into an optional pattern kind prefix and the
144 144 actual pattern."""
145 145 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
146 146 if name.startswith(prefix + ':'): return name.split(':', 1)
147 147 return dflt_pat, name
148 148
149 149 def globre(pat, head='^', tail='$'):
150 150 "convert a glob pattern into a regexp"
151 151 i, n = 0, len(pat)
152 152 res = ''
153 153 group = False
154 154 def peek(): return i < n and pat[i]
155 155 while i < n:
156 156 c = pat[i]
157 157 i = i+1
158 158 if c == '*':
159 159 if peek() == '*':
160 160 i += 1
161 161 res += '.*'
162 162 else:
163 163 res += '[^/]*'
164 164 elif c == '?':
165 165 res += '.'
166 166 elif c == '[':
167 167 j = i
168 168 if j < n and pat[j] in '!]':
169 169 j += 1
170 170 while j < n and pat[j] != ']':
171 171 j += 1
172 172 if j >= n:
173 173 res += '\\['
174 174 else:
175 175 stuff = pat[i:j].replace('\\','\\\\')
176 176 i = j + 1
177 177 if stuff[0] == '!':
178 178 stuff = '^' + stuff[1:]
179 179 elif stuff[0] == '^':
180 180 stuff = '\\' + stuff
181 181 res = '%s[%s]' % (res, stuff)
182 182 elif c == '{':
183 183 group = True
184 184 res += '(?:'
185 185 elif c == '}' and group:
186 186 res += ')'
187 187 group = False
188 188 elif c == ',' and group:
189 189 res += '|'
190 190 elif c == '\\':
191 191 p = peek()
192 192 if p:
193 193 i += 1
194 194 res += re.escape(p)
195 195 else:
196 196 res += re.escape(c)
197 197 else:
198 198 res += re.escape(c)
199 199 return head + res + tail
200 200
201 201 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
202 202
203 203 def pathto(n1, n2):
204 204 '''return the relative path from one place to another.
205 205 this returns a path in the form used by the local filesystem, not hg.'''
206 206 if not n1: return localpath(n2)
207 207 a, b = n1.split('/'), n2.split('/')
208 208 a.reverse()
209 209 b.reverse()
210 210 while a and b and a[-1] == b[-1]:
211 211 a.pop()
212 212 b.pop()
213 213 b.reverse()
214 214 return os.sep.join((['..'] * len(a)) + b)
215 215
216 216 def canonpath(root, cwd, myname):
217 217 """return the canonical path of myname, given cwd and root"""
218 218 if root == os.sep:
219 219 rootsep = os.sep
220 220 elif root.endswith(os.sep):
221 221 rootsep = root
222 222 else:
223 223 rootsep = root + os.sep
224 224 name = myname
225 225 if not os.path.isabs(name):
226 226 name = os.path.join(root, cwd, name)
227 227 name = os.path.normpath(name)
228 228 if name != rootsep and name.startswith(rootsep):
229 229 name = name[len(rootsep):]
230 230 audit_path(name)
231 231 return pconvert(name)
232 232 elif name == root:
233 233 return ''
234 234 else:
235 235 # Determine whether `name' is in the hierarchy at or beneath `root',
236 236 # by iterating name=dirname(name) until that causes no change (can't
237 237 # check name == '/', because that doesn't work on windows). For each
238 238 # `name', compare dev/inode numbers. If they match, the list `rel'
239 239 # holds the reversed list of components making up the relative file
240 240 # name we want.
241 241 root_st = os.stat(root)
242 242 rel = []
243 243 while True:
244 244 try:
245 245 name_st = os.stat(name)
246 246 except OSError:
247 247 break
248 248 if samestat(name_st, root_st):
249 249 rel.reverse()
250 250 name = os.path.join(*rel)
251 251 audit_path(name)
252 252 return pconvert(name)
253 253 dirname, basename = os.path.split(name)
254 254 rel.append(basename)
255 255 if dirname == name:
256 256 break
257 257 name = dirname
258 258
259 259 raise Abort('%s not under root' % myname)
260 260
261 261 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
262 262 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src)
263 263
264 264 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None):
265 265 if os.name == 'nt':
266 266 dflt_pat = 'glob'
267 267 else:
268 268 dflt_pat = 'relpath'
269 269 return _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src)
270 270
271 271 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src):
272 272 """build a function to match a set of file patterns
273 273
274 274 arguments:
275 275 canonroot - the canonical root of the tree you're matching against
276 276 cwd - the current working directory, if relevant
277 277 names - patterns to find
278 278 inc - patterns to include
279 279 exc - patterns to exclude
280 280 head - a regex to prepend to patterns to control whether a match is rooted
281 281
282 282 a pattern is one of:
283 283 'glob:<rooted glob>'
284 284 're:<rooted regexp>'
285 285 'path:<rooted path>'
286 286 'relglob:<relative glob>'
287 287 'relpath:<relative path>'
288 288 'relre:<relative regexp>'
289 289 '<rooted path or regexp>'
290 290
291 291 returns:
292 292 a 3-tuple containing
293 293 - list of explicit non-pattern names passed in
294 294 - a bool match(filename) function
295 295 - a bool indicating if any patterns were passed in
296 296
297 297 todo:
298 298 make head regex a rooted bool
299 299 """
300 300
301 301 def contains_glob(name):
302 302 for c in name:
303 303 if c in _globchars: return True
304 304 return False
305 305
306 306 def regex(kind, name, tail):
307 307 '''convert a pattern into a regular expression'''
308 308 if kind == 're':
309 309 return name
310 310 elif kind == 'path':
311 311 return '^' + re.escape(name) + '(?:/|$)'
312 312 elif kind == 'relglob':
313 313 return head + globre(name, '(?:|.*/)', tail)
314 314 elif kind == 'relpath':
315 315 return head + re.escape(name) + tail
316 316 elif kind == 'relre':
317 317 if name.startswith('^'):
318 318 return name
319 319 return '.*' + name
320 320 return head + globre(name, '', tail)
321 321
322 322 def matchfn(pats, tail):
323 323 """build a matching function from a set of patterns"""
324 324 if not pats:
325 325 return
326 326 matches = []
327 327 for k, p in pats:
328 328 try:
329 329 pat = '(?:%s)' % regex(k, p, tail)
330 330 matches.append(re.compile(pat).match)
331 331 except re.error:
332 332 if src: raise Abort("%s: invalid pattern (%s): %s" % (src, k, p))
333 333 else: raise Abort("invalid pattern (%s): %s" % (k, p))
334 334
335 335 def buildfn(text):
336 336 for m in matches:
337 337 r = m(text)
338 338 if r:
339 339 return r
340 340
341 341 return buildfn
342 342
343 343 def globprefix(pat):
344 344 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
345 345 root = []
346 346 for p in pat.split(os.sep):
347 347 if contains_glob(p): break
348 348 root.append(p)
349 349 return '/'.join(root)
350 350
351 351 pats = []
352 352 files = []
353 353 roots = []
354 354 for kind, name in [patkind(p, dflt_pat) for p in names]:
355 355 if kind in ('glob', 'relpath'):
356 356 name = canonpath(canonroot, cwd, name)
357 357 if name == '':
358 358 kind, name = 'glob', '**'
359 359 if kind in ('glob', 'path', 're'):
360 360 pats.append((kind, name))
361 361 if kind == 'glob':
362 362 root = globprefix(name)
363 363 if root: roots.append(root)
364 364 elif kind == 'relpath':
365 365 files.append((kind, name))
366 366 roots.append(name)
367 367
368 368 patmatch = matchfn(pats, '$') or always
369 369 filematch = matchfn(files, '(?:/|$)') or always
370 370 incmatch = always
371 371 if inc:
372 372 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc]
373 373 incmatch = matchfn(inckinds, '(?:/|$)')
374 374 excmatch = lambda fn: False
375 375 if exc:
376 376 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc]
377 377 excmatch = matchfn(exckinds, '(?:/|$)')
378 378
379 379 return (roots,
380 380 lambda fn: (incmatch(fn) and not excmatch(fn) and
381 381 (fn.endswith('/') or
382 382 (not pats and not files) or
383 383 (pats and patmatch(fn)) or
384 384 (files and filematch(fn)))),
385 385 (inc or exc or (pats and pats != [('glob', '**')])) and True)
386 386
387 387 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None):
388 388 '''enhanced shell command execution.
389 389 run with environment maybe modified, maybe in different dir.
390 390
391 391 if command fails and onerr is None, return status. if ui object,
392 392 print error message and return status, else raise onerr object as
393 393 exception.'''
394 394 def py2shell(val):
395 395 'convert python object into string that is useful to shell'
396 396 if val in (None, False):
397 397 return '0'
398 398 if val == True:
399 399 return '1'
400 400 return str(val)
401 401 oldenv = {}
402 402 for k in environ:
403 403 oldenv[k] = os.environ.get(k)
404 404 if cwd is not None:
405 405 oldcwd = os.getcwd()
406 406 try:
407 407 for k, v in environ.iteritems():
408 408 os.environ[k] = py2shell(v)
409 409 if cwd is not None and oldcwd != cwd:
410 410 os.chdir(cwd)
411 411 rc = os.system(cmd)
412 412 if rc and onerr:
413 413 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
414 414 explain_exit(rc)[0])
415 415 if errprefix:
416 416 errmsg = '%s: %s' % (errprefix, errmsg)
417 417 try:
418 418 onerr.warn(errmsg + '\n')
419 419 except AttributeError:
420 420 raise onerr(errmsg)
421 421 return rc
422 422 finally:
423 423 for k, v in oldenv.iteritems():
424 424 if v is None:
425 425 del os.environ[k]
426 426 else:
427 427 os.environ[k] = v
428 428 if cwd is not None and oldcwd != cwd:
429 429 os.chdir(oldcwd)
430 430
431 431 def rename(src, dst):
432 432 """forcibly rename a file"""
433 433 try:
434 434 os.rename(src, dst)
435 435 except OSError, err:
436 436 # on windows, rename to existing file is not allowed, so we
437 437 # must delete destination first. but if file is open, unlink
438 438 # schedules it for delete but does not delete it. rename
439 439 # happens immediately even for open files, so we create
440 440 # temporary file, delete it, rename destination to that name,
441 441 # then delete that. then rename is safe to do.
442 442 fd, temp = tempfile.mkstemp(dir=os.path.dirname(dst) or '.')
443 443 os.close(fd)
444 444 os.unlink(temp)
445 445 os.rename(dst, temp)
446 446 os.unlink(temp)
447 447 os.rename(src, dst)
448 448
449 449 def unlink(f):
450 450 """unlink and remove the directory if it is empty"""
451 451 os.unlink(f)
452 452 # try removing directories that might now be empty
453 453 try:
454 454 os.removedirs(os.path.dirname(f))
455 455 except OSError:
456 456 pass
457 457
458 458 def copyfiles(src, dst, hardlink=None):
459 459 """Copy a directory tree using hardlinks if possible"""
460 460
461 461 if hardlink is None:
462 462 hardlink = (os.stat(src).st_dev ==
463 463 os.stat(os.path.dirname(dst)).st_dev)
464 464
465 465 if os.path.isdir(src):
466 466 os.mkdir(dst)
467 467 for name in os.listdir(src):
468 468 srcname = os.path.join(src, name)
469 469 dstname = os.path.join(dst, name)
470 470 copyfiles(srcname, dstname, hardlink)
471 471 else:
472 472 if hardlink:
473 473 try:
474 474 os_link(src, dst)
475 475 except (IOError, OSError):
476 476 hardlink = False
477 477 shutil.copy(src, dst)
478 478 else:
479 479 shutil.copy(src, dst)
480 480
481 481 def audit_path(path):
482 482 """Abort if path contains dangerous components"""
483 483 parts = os.path.normcase(path).split(os.sep)
484 484 if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '')
485 485 or os.pardir in parts):
486 486 raise Abort(_("path contains illegal component: %s\n") % path)
487 487
488 488 def _makelock_file(info, pathname):
489 489 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
490 490 os.write(ld, info)
491 491 os.close(ld)
492 492
493 493 def _readlock_file(pathname):
494 494 return posixfile(pathname).read()
495 495
496 496 def nlinks(pathname):
497 497 """Return number of hardlinks for the given file."""
498 498 return os.lstat(pathname).st_nlink
499 499
500 500 if hasattr(os, 'link'):
501 501 os_link = os.link
502 502 else:
503 503 def os_link(src, dst):
504 504 raise OSError(0, _("Hardlinks not supported"))
505 505
506 506 def fstat(fp):
507 507 '''stat file object that may not have fileno method.'''
508 508 try:
509 509 return os.fstat(fp.fileno())
510 510 except AttributeError:
511 511 return os.stat(fp.name)
512 512
513 513 posixfile = file
514 514
515 515 def is_win_9x():
516 516 '''return true if run on windows 95, 98 or me.'''
517 517 try:
518 518 return sys.getwindowsversion()[3] == 1
519 519 except AttributeError:
520 520 return os.name == 'nt' and 'command' in os.environ.get('comspec', '')
521 521
522 getuser_fallback = None
523
524 def getuser():
525 '''return name of current user'''
526 try:
527 return getpass.getuser()
528 except ImportError:
529 # import of pwd will fail on windows - try fallback
530 if getuser_fallback:
531 return getuser_fallback()
532 # raised if win32api not available
533 raise Abort(_('user name not available - set USERNAME '
534 'environment variable'))
535
536 522 # Platform specific variants
537 523 if os.name == 'nt':
538 524 demandload(globals(), "msvcrt")
539 525 nulldev = 'NUL:'
540 526
541 527 class winstdout:
542 528 '''stdout on windows misbehaves if sent through a pipe'''
543 529
544 530 def __init__(self, fp):
545 531 self.fp = fp
546 532
547 533 def __getattr__(self, key):
548 534 return getattr(self.fp, key)
549 535
550 536 def close(self):
551 537 try:
552 538 self.fp.close()
553 539 except: pass
554 540
555 541 def write(self, s):
556 542 try:
557 543 return self.fp.write(s)
558 544 except IOError, inst:
559 545 if inst.errno != 0: raise
560 546 self.close()
561 547 raise IOError(errno.EPIPE, 'Broken pipe')
562 548
563 549 sys.stdout = winstdout(sys.stdout)
564 550
565 551 def system_rcpath():
566 552 try:
567 553 return system_rcpath_win32()
568 554 except:
569 555 return [r'c:\mercurial\mercurial.ini']
570 556
571 557 def os_rcpath():
572 558 '''return default os-specific hgrc search path'''
573 559 path = system_rcpath()
574 560 path.append(user_rcpath())
575 561 userprofile = os.environ.get('USERPROFILE')
576 562 if userprofile:
577 563 path.append(os.path.join(userprofile, 'mercurial.ini'))
578 564 return path
579 565
580 566 def user_rcpath():
581 567 '''return os-specific hgrc search path to the user dir'''
582 568 return os.path.join(os.path.expanduser('~'), 'mercurial.ini')
583 569
584 570 def parse_patch_output(output_line):
585 571 """parses the output produced by patch and returns the file name"""
586 572 pf = output_line[14:]
587 573 if pf[0] == '`':
588 574 pf = pf[1:-1] # Remove the quotes
589 575 return pf
590 576
591 577 def testpid(pid):
592 578 '''return False if pid dead, True if running or not known'''
593 579 return True
594 580
595 581 def is_exec(f, last):
596 582 return last
597 583
598 584 def set_exec(f, mode):
599 585 pass
600 586
601 587 def set_binary(fd):
602 588 msvcrt.setmode(fd.fileno(), os.O_BINARY)
603 589
604 590 def pconvert(path):
605 591 return path.replace("\\", "/")
606 592
607 593 def localpath(path):
608 594 return path.replace('/', '\\')
609 595
610 596 def normpath(path):
611 597 return pconvert(os.path.normpath(path))
612 598
613 599 makelock = _makelock_file
614 600 readlock = _readlock_file
615 601
616 602 def samestat(s1, s2):
617 603 return False
618 604
619 605 def shellquote(s):
620 606 return '"%s"' % s.replace('"', '\\"')
621 607
622 608 def explain_exit(code):
623 609 return _("exited with status %d") % code, code
624 610
625 611 try:
626 612 # override functions with win32 versions if possible
627 613 from util_win32 import *
628 614 if not is_win_9x():
629 615 posixfile = posixfile_nt
630 616 except ImportError:
631 617 pass
632 618
633 619 else:
634 620 nulldev = '/dev/null'
635 621
636 622 def rcfiles(path):
637 623 rcs = [os.path.join(path, 'hgrc')]
638 624 rcdir = os.path.join(path, 'hgrc.d')
639 625 try:
640 626 rcs.extend([os.path.join(rcdir, f) for f in os.listdir(rcdir)
641 627 if f.endswith(".rc")])
642 628 except OSError:
643 629 pass
644 630 return rcs
645 631
646 632 def os_rcpath():
647 633 '''return default os-specific hgrc search path'''
648 634 path = []
649 635 # old mod_python does not set sys.argv
650 636 if len(getattr(sys, 'argv', [])) > 0:
651 637 path.extend(rcfiles(os.path.dirname(sys.argv[0]) +
652 638 '/../etc/mercurial'))
653 639 path.extend(rcfiles('/etc/mercurial'))
654 640 path.append(os.path.expanduser('~/.hgrc'))
655 641 path = [os.path.normpath(f) for f in path]
656 642 return path
657 643
658 644 def parse_patch_output(output_line):
659 645 """parses the output produced by patch and returns the file name"""
660 646 pf = output_line[14:]
661 647 if pf.startswith("'") and pf.endswith("'") and " " in pf:
662 648 pf = pf[1:-1] # Remove the quotes
663 649 return pf
664 650
665 651 def is_exec(f, last):
666 652 """check whether a file is executable"""
667 653 return (os.lstat(f).st_mode & 0100 != 0)
668 654
669 655 def set_exec(f, mode):
670 656 s = os.lstat(f).st_mode
671 657 if (s & 0100 != 0) == mode:
672 658 return
673 659 if mode:
674 660 # Turn on +x for every +r bit when making a file executable
675 661 # and obey umask.
676 662 umask = os.umask(0)
677 663 os.umask(umask)
678 664 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
679 665 else:
680 666 os.chmod(f, s & 0666)
681 667
682 668 def set_binary(fd):
683 669 pass
684 670
685 671 def pconvert(path):
686 672 return path
687 673
688 674 def localpath(path):
689 675 return path
690 676
691 677 normpath = os.path.normpath
692 678 samestat = os.path.samestat
693 679
694 680 def makelock(info, pathname):
695 681 try:
696 682 os.symlink(info, pathname)
697 683 except OSError, why:
698 684 if why.errno == errno.EEXIST:
699 685 raise
700 686 else:
701 687 _makelock_file(info, pathname)
702 688
703 689 def readlock(pathname):
704 690 try:
705 691 return os.readlink(pathname)
706 692 except OSError, why:
707 693 if why.errno == errno.EINVAL:
708 694 return _readlock_file(pathname)
709 695 else:
710 696 raise
711 697
712 698 def shellquote(s):
713 699 return "'%s'" % s.replace("'", "'\\''")
714 700
715 701 def testpid(pid):
716 702 '''return False if pid dead, True if running or not sure'''
717 703 try:
718 704 os.kill(pid, 0)
719 705 return True
720 706 except OSError, inst:
721 707 return inst.errno != errno.ESRCH
722 708
723 709 def explain_exit(code):
724 710 """return a 2-tuple (desc, code) describing a process's status"""
725 711 if os.WIFEXITED(code):
726 712 val = os.WEXITSTATUS(code)
727 713 return _("exited with status %d") % val, val
728 714 elif os.WIFSIGNALED(code):
729 715 val = os.WTERMSIG(code)
730 716 return _("killed by signal %d") % val, val
731 717 elif os.WIFSTOPPED(code):
732 718 val = os.WSTOPSIG(code)
733 719 return _("stopped by signal %d") % val, val
734 720 raise ValueError(_("invalid exit code"))
735 721
736 722 def opener(base, audit=True):
737 723 """
738 724 return a function that opens files relative to base
739 725
740 726 this function is used to hide the details of COW semantics and
741 727 remote file access from higher level code.
742 728 """
743 729 p = base
744 730 audit_p = audit
745 731
746 732 def mktempcopy(name):
747 733 d, fn = os.path.split(name)
748 734 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
749 735 os.close(fd)
750 736 ofp = posixfile(temp, "wb")
751 737 try:
752 738 try:
753 739 ifp = posixfile(name, "rb")
754 740 except IOError, inst:
755 741 if not getattr(inst, 'filename', None):
756 742 inst.filename = name
757 743 raise
758 744 for chunk in filechunkiter(ifp):
759 745 ofp.write(chunk)
760 746 ifp.close()
761 747 ofp.close()
762 748 except:
763 749 try: os.unlink(temp)
764 750 except: pass
765 751 raise
766 752 st = os.lstat(name)
767 753 os.chmod(temp, st.st_mode)
768 754 return temp
769 755
770 756 class atomictempfile(posixfile):
771 757 """the file will only be copied when rename is called"""
772 758 def __init__(self, name, mode):
773 759 self.__name = name
774 760 self.temp = mktempcopy(name)
775 761 posixfile.__init__(self, self.temp, mode)
776 762 def rename(self):
777 763 if not self.closed:
778 764 posixfile.close(self)
779 765 rename(self.temp, localpath(self.__name))
780 766 def __del__(self):
781 767 if not self.closed:
782 768 try:
783 769 os.unlink(self.temp)
784 770 except: pass
785 771 posixfile.close(self)
786 772
787 773 class atomicfile(atomictempfile):
788 774 """the file will only be copied on close"""
789 775 def __init__(self, name, mode):
790 776 atomictempfile.__init__(self, name, mode)
791 777 def close(self):
792 778 self.rename()
793 779 def __del__(self):
794 780 self.rename()
795 781
796 782 def o(path, mode="r", text=False, atomic=False, atomictemp=False):
797 783 if audit_p:
798 784 audit_path(path)
799 785 f = os.path.join(p, path)
800 786
801 787 if not text:
802 788 mode += "b" # for that other OS
803 789
804 790 if mode[0] != "r":
805 791 try:
806 792 nlink = nlinks(f)
807 793 except OSError:
808 794 d = os.path.dirname(f)
809 795 if not os.path.isdir(d):
810 796 os.makedirs(d)
811 797 else:
812 798 if atomic:
813 799 return atomicfile(f, mode)
814 800 elif atomictemp:
815 801 return atomictempfile(f, mode)
816 802 if nlink > 1:
817 803 rename(mktempcopy(f), f)
818 804 return posixfile(f, mode)
819 805
820 806 return o
821 807
822 808 class chunkbuffer(object):
823 809 """Allow arbitrary sized chunks of data to be efficiently read from an
824 810 iterator over chunks of arbitrary size."""
825 811
826 812 def __init__(self, in_iter, targetsize = 2**16):
827 813 """in_iter is the iterator that's iterating over the input chunks.
828 814 targetsize is how big a buffer to try to maintain."""
829 815 self.in_iter = iter(in_iter)
830 816 self.buf = ''
831 817 self.targetsize = int(targetsize)
832 818 if self.targetsize <= 0:
833 819 raise ValueError(_("targetsize must be greater than 0, was %d") %
834 820 targetsize)
835 821 self.iterempty = False
836 822
837 823 def fillbuf(self):
838 824 """Ignore target size; read every chunk from iterator until empty."""
839 825 if not self.iterempty:
840 826 collector = cStringIO.StringIO()
841 827 collector.write(self.buf)
842 828 for ch in self.in_iter:
843 829 collector.write(ch)
844 830 self.buf = collector.getvalue()
845 831 self.iterempty = True
846 832
847 833 def read(self, l):
848 834 """Read L bytes of data from the iterator of chunks of data.
849 835 Returns less than L bytes if the iterator runs dry."""
850 836 if l > len(self.buf) and not self.iterempty:
851 837 # Clamp to a multiple of self.targetsize
852 838 targetsize = self.targetsize * ((l // self.targetsize) + 1)
853 839 collector = cStringIO.StringIO()
854 840 collector.write(self.buf)
855 841 collected = len(self.buf)
856 842 for chunk in self.in_iter:
857 843 collector.write(chunk)
858 844 collected += len(chunk)
859 845 if collected >= targetsize:
860 846 break
861 847 if collected < targetsize:
862 848 self.iterempty = True
863 849 self.buf = collector.getvalue()
864 850 s, self.buf = self.buf[:l], buffer(self.buf, l)
865 851 return s
866 852
867 853 def filechunkiter(f, size=65536, limit=None):
868 854 """Create a generator that produces the data in the file size
869 855 (default 65536) bytes at a time, up to optional limit (default is
870 856 to read all data). Chunks may be less than size bytes if the
871 857 chunk is the last chunk in the file, or the file is a socket or
872 858 some other type of file that sometimes reads less data than is
873 859 requested."""
874 860 assert size >= 0
875 861 assert limit is None or limit >= 0
876 862 while True:
877 863 if limit is None: nbytes = size
878 864 else: nbytes = min(limit, size)
879 865 s = nbytes and f.read(nbytes)
880 866 if not s: break
881 867 if limit: limit -= len(s)
882 868 yield s
883 869
884 870 def makedate():
885 871 lt = time.localtime()
886 872 if lt[8] == 1 and time.daylight:
887 873 tz = time.altzone
888 874 else:
889 875 tz = time.timezone
890 876 return time.mktime(lt), tz
891 877
892 878 def datestr(date=None, format='%a %b %d %H:%M:%S %Y', timezone=True):
893 879 """represent a (unixtime, offset) tuple as a localized time.
894 880 unixtime is seconds since the epoch, and offset is the time zone's
895 881 number of seconds away from UTC. if timezone is false, do not
896 882 append time zone to string."""
897 883 t, tz = date or makedate()
898 884 s = time.strftime(format, time.gmtime(float(t) - tz))
899 885 if timezone:
900 886 s += " %+03d%02d" % (-tz / 3600, ((-tz % 3600) / 60))
901 887 return s
902 888
903 889 def strdate(string, format='%a %b %d %H:%M:%S %Y'):
904 890 """parse a localized time string and return a (unixtime, offset) tuple.
905 891 if the string cannot be parsed, ValueError is raised."""
906 892 def hastimezone(string):
907 893 return (string[-4:].isdigit() and
908 894 (string[-5] == '+' or string[-5] == '-') and
909 895 string[-6].isspace())
910 896
911 897 # NOTE: unixtime = localunixtime + offset
912 898 if hastimezone(string):
913 899 date, tz = string[:-6], string[-5:]
914 900 tz = int(tz)
915 901 offset = - 3600 * (tz / 100) - 60 * (tz % 100)
916 902 else:
917 903 date, offset = string, None
918 904 timetuple = time.strptime(date, format)
919 905 localunixtime = int(calendar.timegm(timetuple))
920 906 if offset is None:
921 907 # local timezone
922 908 unixtime = int(time.mktime(timetuple))
923 909 offset = unixtime - localunixtime
924 910 else:
925 911 unixtime = localunixtime + offset
926 912 return unixtime, offset
927 913
928 914 def parsedate(string, formats=None):
929 915 """parse a localized time string and return a (unixtime, offset) tuple.
930 916 The date may be a "unixtime offset" string or in one of the specified
931 917 formats."""
932 918 if not formats:
933 919 formats = defaultdateformats
934 920 try:
935 921 when, offset = map(int, string.split(' '))
936 922 except ValueError:
937 923 for format in formats:
938 924 try:
939 925 when, offset = strdate(string, format)
940 926 except ValueError:
941 927 pass
942 928 else:
943 929 break
944 930 else:
945 931 raise ValueError(_('invalid date: %r '
946 932 'see hg(1) manual page for details')
947 933 % string)
948 934 # validate explicit (probably user-specified) date and
949 935 # time zone offset. values must fit in signed 32 bits for
950 936 # current 32-bit linux runtimes. timezones go from UTC-12
951 937 # to UTC+14
952 938 if abs(when) > 0x7fffffff:
953 939 raise ValueError(_('date exceeds 32 bits: %d') % when)
954 940 if offset < -50400 or offset > 43200:
955 941 raise ValueError(_('impossible time zone offset: %d') % offset)
956 942 return when, offset
957 943
958 944 def shortuser(user):
959 945 """Return a short representation of a user name or email address."""
960 946 f = user.find('@')
961 947 if f >= 0:
962 948 user = user[:f]
963 949 f = user.find('<')
964 950 if f >= 0:
965 951 user = user[f+1:]
966 952 f = user.find(' ')
967 953 if f >= 0:
968 954 user = user[:f]
969 955 return user
970 956
971 957 def walkrepos(path):
972 958 '''yield every hg repository under path, recursively.'''
973 959 def errhandler(err):
974 960 if err.filename == path:
975 961 raise err
976 962
977 963 for root, dirs, files in os.walk(path, onerror=errhandler):
978 964 for d in dirs:
979 965 if d == '.hg':
980 966 yield root
981 967 dirs[:] = []
982 968 break
983 969
984 970 _rcpath = None
985 971
986 972 def rcpath():
987 973 '''return hgrc search path. if env var HGRCPATH is set, use it.
988 974 for each item in path, if directory, use files ending in .rc,
989 975 else use item.
990 976 make HGRCPATH empty to only look in .hg/hgrc of current repo.
991 977 if no HGRCPATH, use default os-specific path.'''
992 978 global _rcpath
993 979 if _rcpath is None:
994 980 if 'HGRCPATH' in os.environ:
995 981 _rcpath = []
996 982 for p in os.environ['HGRCPATH'].split(os.pathsep):
997 983 if not p: continue
998 984 if os.path.isdir(p):
999 985 for f in os.listdir(p):
1000 986 if f.endswith('.rc'):
1001 987 _rcpath.append(os.path.join(p, f))
1002 988 else:
1003 989 _rcpath.append(p)
1004 990 else:
1005 991 _rcpath = os_rcpath()
1006 992 return _rcpath
1007 993
1008 994 def bytecount(nbytes):
1009 995 '''return byte count formatted as readable string, with units'''
1010 996
1011 997 units = (
1012 998 (100, 1<<30, _('%.0f GB')),
1013 999 (10, 1<<30, _('%.1f GB')),
1014 1000 (1, 1<<30, _('%.2f GB')),
1015 1001 (100, 1<<20, _('%.0f MB')),
1016 1002 (10, 1<<20, _('%.1f MB')),
1017 1003 (1, 1<<20, _('%.2f MB')),
1018 1004 (100, 1<<10, _('%.0f KB')),
1019 1005 (10, 1<<10, _('%.1f KB')),
1020 1006 (1, 1<<10, _('%.2f KB')),
1021 1007 (1, 1, _('%.0f bytes')),
1022 1008 )
1023 1009
1024 1010 for multiplier, divisor, format in units:
1025 1011 if nbytes >= divisor * multiplier:
1026 1012 return format % (nbytes / float(divisor))
1027 1013 return units[-1][2] % nbytes
1028 1014
1029 1015 def drop_scheme(scheme, path):
1030 1016 sc = scheme + ':'
1031 1017 if path.startswith(sc):
1032 1018 path = path[len(sc):]
1033 1019 if path.startswith('//'):
1034 1020 path = path[2:]
1035 1021 return path
@@ -1,301 +1,299
1 1 # util_win32.py - utility functions that use win32 API
2 2 #
3 3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 5 #
6 6 # This software may be used and distributed according to the terms of
7 7 # the GNU General Public License, incorporated herein by reference.
8 8
9 9 # Mark Hammond's win32all package allows better functionality on
10 10 # Windows. this module overrides definitions in util.py. if not
11 11 # available, import of this module will fail, and generic code will be
12 12 # used.
13 13
14 14 import win32api
15 15
16 16 from demandload import *
17 17 from i18n import gettext as _
18 18 demandload(globals(), 'errno os pywintypes win32con win32file win32process')
19 19 demandload(globals(), 'cStringIO win32com.shell:shell,shellcon winerror')
20 20
21 21 class WinError:
22 22 winerror_map = {
23 23 winerror.ERROR_ACCESS_DENIED: errno.EACCES,
24 24 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
25 25 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
26 26 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
27 27 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
28 28 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
29 29 winerror.ERROR_BAD_COMMAND: errno.EIO,
30 30 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
31 31 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
32 32 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
33 33 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
34 34 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
35 35 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
36 36 winerror.ERROR_BAD_PIPE: errno.EPIPE,
37 37 winerror.ERROR_BAD_UNIT: errno.ENODEV,
38 38 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
39 39 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
40 40 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
41 41 winerror.ERROR_BUSY: errno.EBUSY,
42 42 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
43 43 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
44 44 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
45 45 winerror.ERROR_CANTOPEN: errno.EIO,
46 46 winerror.ERROR_CANTREAD: errno.EIO,
47 47 winerror.ERROR_CANTWRITE: errno.EIO,
48 48 winerror.ERROR_CRC: errno.EIO,
49 49 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
50 50 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
51 51 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
52 52 winerror.ERROR_DIRECTORY: errno.EINVAL,
53 53 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
54 54 winerror.ERROR_DISK_CHANGE: errno.EIO,
55 55 winerror.ERROR_DISK_FULL: errno.ENOSPC,
56 56 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
57 57 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
58 58 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
59 59 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
60 60 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
61 61 winerror.ERROR_FILE_INVALID: errno.ENODEV,
62 62 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
63 63 winerror.ERROR_GEN_FAILURE: errno.EIO,
64 64 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
65 65 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
66 66 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
67 67 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
68 68 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
69 69 winerror.ERROR_INVALID_DATA: errno.EINVAL,
70 70 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
71 71 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
72 72 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
73 73 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
74 74 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
75 75 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
76 76 winerror.ERROR_INVALID_NAME: errno.EINVAL,
77 77 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
78 78 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
79 79 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
80 80 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
81 81 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
82 82 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
83 83 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
84 84 winerror.ERROR_IO_DEVICE: errno.EIO,
85 85 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
86 86 winerror.ERROR_LOCKED: errno.EBUSY,
87 87 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
88 88 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
89 89 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
90 90 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
91 91 winerror.ERROR_MORE_DATA: errno.EPIPE,
92 92 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
93 93 winerror.ERROR_NOACCESS: errno.EFAULT,
94 94 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
95 95 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
96 96 winerror.ERROR_NOT_READY: errno.EAGAIN,
97 97 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
98 98 winerror.ERROR_NO_DATA: errno.EPIPE,
99 99 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
100 100 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
101 101 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
102 102 winerror.ERROR_OPEN_FAILED: errno.EIO,
103 103 winerror.ERROR_OPEN_FILES: errno.EBUSY,
104 104 winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
105 105 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
106 106 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
107 107 winerror.ERROR_PATH_BUSY: errno.EBUSY,
108 108 winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
109 109 winerror.ERROR_PIPE_BUSY: errno.EBUSY,
110 110 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
111 111 winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
112 112 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
113 113 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
114 114 winerror.ERROR_READ_FAULT: errno.EIO,
115 115 winerror.ERROR_SEEK: errno.EIO,
116 116 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
117 117 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
118 118 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
119 119 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
120 120 winerror.ERROR_SWAPERROR: errno.ENOENT,
121 121 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
122 122 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
123 123 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
124 124 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
125 125 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
126 126 winerror.ERROR_WRITE_FAULT: errno.EIO,
127 127 winerror.ERROR_WRITE_PROTECT: errno.EROFS,
128 128 }
129 129
130 130 def __init__(self, err):
131 131 self.win_errno, self.win_function, self.win_strerror = err
132 132 if self.win_strerror.endswith('.'):
133 133 self.win_strerror = self.win_strerror[:-1]
134 134
135 135 class WinIOError(WinError, IOError):
136 136 def __init__(self, err, filename=None):
137 137 WinError.__init__(self, err)
138 138 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
139 139 self.win_strerror)
140 140 self.filename = filename
141 141
142 142 class WinOSError(WinError, OSError):
143 143 def __init__(self, err):
144 144 WinError.__init__(self, err)
145 145 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
146 146 self.win_strerror)
147 147
148 148 def os_link(src, dst):
149 149 # NB will only succeed on NTFS
150 150 try:
151 151 win32file.CreateHardLink(dst, src)
152 152 except pywintypes.error, details:
153 153 raise WinOSError(details)
154 154
155 155 def nlinks(pathname):
156 156 """Return number of hardlinks for the given file."""
157 157 try:
158 158 fh = win32file.CreateFile(pathname,
159 159 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
160 160 None, win32file.OPEN_EXISTING, 0, None)
161 161 res = win32file.GetFileInformationByHandle(fh)
162 162 fh.Close()
163 163 return res[7]
164 164 except pywintypes.error:
165 165 return os.lstat(pathname).st_nlink
166 166
167 167 def testpid(pid):
168 168 '''return True if pid is still running or unable to
169 169 determine, False otherwise'''
170 170 try:
171 171 handle = win32api.OpenProcess(
172 172 win32con.PROCESS_QUERY_INFORMATION, False, pid)
173 173 if handle:
174 174 status = win32process.GetExitCodeProcess(handle)
175 175 return status == win32con.STILL_ACTIVE
176 176 except pywintypes.error, details:
177 177 return details[0] != winerror.ERROR_INVALID_PARAMETER
178 178 return True
179 179
180 180 def system_rcpath_win32():
181 181 '''return default os-specific hgrc search path'''
182 182 proc = win32api.GetCurrentProcess()
183 183 try:
184 184 # This will fail on windows < NT
185 185 filename = win32process.GetModuleFileNameEx(proc, 0)
186 186 except:
187 187 filename = win32api.GetModuleFileName(0)
188 188 return [os.path.join(os.path.dirname(filename), 'mercurial.ini')]
189 189
190 190 def user_rcpath():
191 191 '''return os-specific hgrc search path to the user dir'''
192 192 userdir = os.path.expanduser('~')
193 193 if userdir == '~':
194 194 # We are on win < nt: fetch the APPDATA directory location and use
195 195 # the parent directory as the user home dir.
196 196 appdir = shell.SHGetPathFromIDList(
197 197 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
198 198 userdir = os.path.dirname(appdir)
199 199 return os.path.join(userdir, 'mercurial.ini')
200 200
201 201 class posixfile_nt(object):
202 202 '''file object with posix-like semantics. on windows, normal
203 203 files can not be deleted or renamed if they are open. must open
204 204 with win32file.FILE_SHARE_DELETE. this flag does not exist on
205 205 windows < nt, so do not use this class there.'''
206 206
207 207 # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
208 208 # but does not work at all. wrap win32 file api instead.
209 209
210 210 def __init__(self, name, mode='rb'):
211 211 access = 0
212 212 if 'r' in mode or '+' in mode:
213 213 access |= win32file.GENERIC_READ
214 214 if 'w' in mode or 'a' in mode:
215 215 access |= win32file.GENERIC_WRITE
216 216 if 'r' in mode:
217 217 creation = win32file.OPEN_EXISTING
218 218 elif 'a' in mode:
219 219 creation = win32file.OPEN_ALWAYS
220 220 else:
221 221 creation = win32file.CREATE_ALWAYS
222 222 try:
223 223 self.handle = win32file.CreateFile(name,
224 224 access,
225 225 win32file.FILE_SHARE_READ |
226 226 win32file.FILE_SHARE_WRITE |
227 227 win32file.FILE_SHARE_DELETE,
228 228 None,
229 229 creation,
230 230 win32file.FILE_ATTRIBUTE_NORMAL,
231 231 0)
232 232 except pywintypes.error, err:
233 233 raise WinIOError(err, name)
234 234 self.closed = False
235 235 self.name = name
236 236 self.mode = mode
237 237
238 238 def __iter__(self):
239 239 for line in self.read().splitlines(True):
240 240 yield line
241 241
242 242 def read(self, count=-1):
243 243 try:
244 244 cs = cStringIO.StringIO()
245 245 while count:
246 246 wincount = int(count)
247 247 if wincount == -1:
248 248 wincount = 1048576
249 249 val, data = win32file.ReadFile(self.handle, wincount)
250 250 if not data: break
251 251 cs.write(data)
252 252 if count != -1:
253 253 count -= len(data)
254 254 return cs.getvalue()
255 255 except pywintypes.error, err:
256 256 raise WinIOError(err)
257 257
258 258 def write(self, data):
259 259 try:
260 260 if 'a' in self.mode:
261 261 win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
262 262 nwrit = 0
263 263 while nwrit < len(data):
264 264 val, nwrit = win32file.WriteFile(self.handle, data)
265 265 data = data[nwrit:]
266 266 except pywintypes.error, err:
267 267 raise WinIOError(err)
268 268
269 269 def seek(self, pos, whence=0):
270 270 try:
271 271 win32file.SetFilePointer(self.handle, int(pos), whence)
272 272 except pywintypes.error, err:
273 273 raise WinIOError(err)
274 274
275 275 def tell(self):
276 276 try:
277 277 return win32file.SetFilePointer(self.handle, 0,
278 278 win32file.FILE_CURRENT)
279 279 except pywintypes.error, err:
280 280 raise WinIOError(err)
281 281
282 282 def close(self):
283 283 if not self.closed:
284 284 self.handle = None
285 285 self.closed = True
286 286
287 287 def flush(self):
288 288 try:
289 289 win32file.FlushFileBuffers(self.handle)
290 290 except pywintypes.error, err:
291 291 raise WinIOError(err)
292 292
293 293 def truncate(self, pos=0):
294 294 try:
295 295 win32file.SetFilePointer(self.handle, int(pos),
296 296 win32file.FILE_BEGIN)
297 297 win32file.SetEndOfFile(self.handle)
298 298 except pywintypes.error, err:
299 299 raise WinIOError(err)
300
301 getuser_fallback = win32api.GetUserName
@@ -1,12 +1,26
1 1 #!/bin/sh
2 2
3 3 unset HGUSER
4 4 EMAIL="My Name <myname@example.com>"
5 5 export EMAIL
6 6
7 7 hg init test
8 8 cd test
9 9 touch asdf
10 10 hg add asdf
11 11 hg commit -d '1000000 0' -m commit-1
12 12 hg tip
13
14 unset EMAIL
15 echo 1 > asdf
16 hg commit -d '1000000 0' -m commit-1
17 hg commit -d '1000000 0' -u "foo@bar.com" -m commit-1
18 hg tip
19 echo "[ui]" >> .hg/hgrc
20 echo "username = foobar <foo@bar.com>" >> .hg/hgrc
21 echo 12 > asdf
22 hg commit -d '1000000 0' -m commit-1
23 hg tip
24 echo 1 > asdf
25 hg commit -d '1000000 0' -u "foo@bar.com" -m commit-1
26 hg tip
@@ -1,6 +1,27
1 1 changeset: 0:9426b370c206
2 2 tag: tip
3 3 user: My Name <myname@example.com>
4 4 date: Mon Jan 12 13:46:40 1970 +0000
5 5 summary: commit-1
6 6
7 abort: No default username available, use -u
8 transaction abort!
9 rollback completed
10 changeset: 1:2becd0bae6e6
11 tag: tip
12 user: foo@bar.com
13 date: Mon Jan 12 13:46:40 1970 +0000
14 summary: commit-1
15
16 changeset: 2:7a0176714f78
17 tag: tip
18 user: foobar <foo@bar.com>
19 date: Mon Jan 12 13:46:40 1970 +0000
20 summary: commit-1
21
22 changeset: 3:f9b58c5a6352
23 tag: tip
24 user: foo@bar.com
25 date: Mon Jan 12 13:46:40 1970 +0000
26 summary: commit-1
27
General Comments 0
You need to be logged in to leave comments. Login now