##// END OF EJS Templates
plan9: initial support for plan 9 from bell labs...
Steven Stallion -
r16383:f5dd179b default
parent child Browse files
Show More
@@ -0,0 +1,42 b''
1 #!/bin/rc
2 # 9diff - Mercurial extdiff wrapper for diff(1)
3
4 rfork e
5
6 fn getfiles{
7 cd $1 && \
8 for(f in `{du -as | awk '{print $2}'})
9 test -f $f && echo `{cleanname $f}
10 }
11
12 fn usage{
13 echo >[1=2] usage: 9diff [diff options] parent child root
14 exit usage
15 }
16
17 opts=()
18 while(~ $1 -*){
19 opts=($opts $1)
20 shift
21 }
22 if(! ~ $#* 3)
23 usage
24
25 # extdiff will set the parent and child to a single file if there is
26 # only one change. If there are multiple changes, directories will be
27 # set. diff(1) does not cope particularly with directories; instead we
28 # do the recursion ourselves and diff each file individually.
29 if(test -f $1)
30 diff $opts $1 $2
31 if not{
32 # extdiff will create a snapshot of the working copy to prevent
33 # conflicts during the diff. We circumvent this behavior by
34 # diffing against the repository root to produce plumbable
35 # output. This is antisocial.
36 for(f in `{sort -u <{getfiles $1} <{getfiles $2}}){
37 file1=$1/$f; test -f $file1 || file1=/dev/null
38 file2=$3/$f; test -f $file2 || file2=/dev/null
39 diff $opts $file1 $file2
40 }
41 }
42 exit ''
@@ -0,0 +1,39 b''
1 Mercurial for Plan 9 from Bell Labs
2 ===================================
3
4 This directory contains support for Mercurial on Plan 9 from Bell Labs
5 platforms. It is assumed that the version of Python running on these
6 systems supports the ANSI/POSIX Environment (APE). At the time of this
7 writing, the bichued/python port is the most commonly installed version
8 of Python on these platforms. If a native port of Python is ever made,
9 some minor modification will need to be made to support some of the more
10 esoteric requirements of the platform rather than those currently made
11 (cf. posix.py).
12
13 By default, installations will have the factotum extension enabled; this
14 extension permits factotum(4) to act as an authentication agent for
15 HTTP repositories. Additionally, an extdiff command named 9diff is
16 enabled which generates diff(1) compatible output suitable for use with
17 the plumber(4).
18
19 Commit messages are plumbed using E if no editor is defined; users must
20 update the plumbed file to continue, otherwise the hg process must be
21 interrupted.
22
23 Some work remains with regard to documentation. Section 5 manual page
24 references for hgignore and hgrc need to be re-numbered to section 6 (file
25 formats) and a new man page writer should be written to support the
26 Plan 9 man macro set. Until these issues can be resolved, manual pages
27 are elided from the installation.
28
29 Basic install:
30
31 % mk install # do a system-wide install
32 % hg debuginstall # sanity-check setup
33 % hg # see help
34
35 A proto(2) file is included in this directory as an example of how a
36 binary distribution could be packaged, ostensibly with contrib(1).
37
38 See http://mercurial.selenic.com/ for detailed installation
39 instructions, platform-specific notes, and Mercurial user information.
@@ -0,0 +1,5 b''
1 [extensions]
2 extdiff =
3
4 [extdiff]
5 9diff = 9diff -cm $parent $child $root
@@ -0,0 +1,2 b''
1 [extensions]
2 factotum =
@@ -0,0 +1,37 b''
1 APE=/sys/src/ape
2 <$APE/config
3
4 PYTHON=python
5 PYTHONBIN=/rc/bin
6 SH=ape/psh
7
8 PURE=--pure
9 ROOT=../..
10
11 # This is slightly underhanded; Plan 9 does not support GNU gettext nor
12 # does it support dynamically loaded extension modules. We work around
13 # this by calling build_py and build_scripts directly; this avoids
14 # additional platform hacks in setup.py.
15 build:VQ:
16 @{
17 cd $ROOT
18 $SH -c '$PYTHON setup.py $PURE build_py build_scripts'
19 }
20
21 clean:VQ:
22 @{
23 cd $ROOT
24 $SH -c '$PYTHON setup.py $PURE clean --all'
25 }
26
27 install:VQ: build
28 @{
29 cd $ROOT
30 $SH -c '$PYTHON setup.py $PURE install \
31 --install-scripts $PYTHONBIN \
32 --skip-build' \
33 --force
34 }
35 mkdir -p /lib/mercurial/hgrc.d
36 dircp hgrc.d /lib/mercurial/hgrc.d
37 cp 9diff /rc/bin
@@ -0,0 +1,20 b''
1 lib - sys sys
2 mercurial - sys sys
3 hgrc.d - sys sys
4 9diff.rc - sys sys
5 factotum.rc - sys sys
6 rc - sys sys
7 bin - sys sys
8 9diff - sys sys
9 hg - sys sys
10 sys - sys sys
11 lib - sys sys
12 python - sys sys
13 lib - sys sys
14 python2.5 - sys sys
15 site-packages - sys sys
16 hgext - sys sys
17 + - sys sys
18 mercurial - sys sys
19 + - sys sys
20 mercurial-2.1.1-py2.5.egg-info - sys sys
@@ -0,0 +1,120 b''
1 # factotum.py - Plan 9 factotum integration for Mercurial
2 #
3 # Copyright (C) 2012 Steven Stallion <sstallion@gmail.com>
4 #
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 '''http authentication with factotum
20
21 This extension allows the factotum facility on Plan 9 from Bell Labs platforms
22 to provide authentication information for HTTP access. Configuration entries
23 specified in the auth section as well as authentication information provided
24 in the repository URL are fully supported. If no prefix is specified, a value
25 of ``*`` will be assumed.
26
27 By default, keys are specified as::
28
29 proto=pass service=hg prefix=<prefix> user=<username> !password=<password>
30
31 If the factotum extension is unable to read the required key, one will be
32 requested interactively.
33
34 A configuration section is available to customize runtime behavior. By
35 default, these entries are::
36
37 [factotum]
38 mount = /mnt/factotum
39 path = /bin/auth/factotum
40 service = hg
41
42 The mount entry defines the mount point for the factotum file service. The
43 path entry defines the full path to the factotum binary. Lastly, the service
44 entry controls the service name used when reading keys.
45
46 '''
47
48 from mercurial.i18n import _
49 from mercurial.url import passwordmgr
50 from mercurial import httpconnection, urllib2, util
51 import os
52
53 ERRMAX = 128
54
55 def auth_getkey(self, params):
56 if not self.ui.interactive():
57 raise util.Abort(_('factotum not interactive'))
58 if 'user=' not in params:
59 params = '%s user?' % params
60 params = '%s !password?' % params
61 os.system("%s -g '%s'" % (_path, params))
62
63 def auth_getuserpasswd(self, getkey, params):
64 params = 'proto=pass %s' % params
65 while True:
66 fd = os.open('%s/rpc' % _mount, os.O_RDWR)
67 try:
68 try:
69 os.write(fd, 'start %s' % params)
70 l = os.read(fd, ERRMAX).split()
71 if l[0] == 'ok':
72 os.write(fd, 'read')
73 l = os.read(fd, ERRMAX).split()
74 if l[0] == 'ok':
75 return l[1:]
76 except (OSError, IOError):
77 raise util.Abort(_('factotum not responding'))
78 finally:
79 os.close(fd)
80 getkey(self, params)
81
82 def monkeypatch_method(cls):
83 def decorator(func):
84 setattr(cls, func.__name__, func)
85 return func
86 return decorator
87
88 @monkeypatch_method(passwordmgr)
89 def find_user_password(self, realm, authuri):
90 user, passwd = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
91 self, realm, authuri)
92 if user and passwd:
93 self._writedebug(user, passwd)
94 return (user, passwd)
95
96 prefix = ''
97 res = httpconnection.readauthforuri(self.ui, authuri, user)
98 if res:
99 _, auth = res
100 prefix = auth.get('prefix')
101 user, passwd = auth.get('username'), auth.get('password')
102 if not user or not passwd:
103 if not prefix:
104 prefix = '*'
105 params = 'service=%s prefix=%s' % (_service, prefix)
106 if user:
107 params = '%s user=%s' % (params, user)
108 user, passwd = auth_getuserpasswd(self, auth_getkey, params)
109
110 self.add_password(realm, authuri, user, passwd)
111 self._writedebug(user, passwd)
112 return (user, passwd)
113
114 def uisetup(ui):
115 global _mount
116 _mount = ui.config('factotum', 'mount', '/mnt/factotum')
117 global _path
118 _path = ui.config('factotum', 'path', '/bin/auth/factotum')
119 global _service
120 _service = ui.config('factotum', 'service', 'hg')
@@ -1,1383 +1,1388 b''
1 1 The Mercurial system uses a set of configuration files to control
2 2 aspects of its behavior.
3 3
4 4 The configuration files use a simple ini-file format. A configuration
5 5 file consists of sections, led by a ``[section]`` header and followed
6 6 by ``name = value`` entries::
7 7
8 8 [ui]
9 9 username = Firstname Lastname <firstname.lastname@example.net>
10 10 verbose = True
11 11
12 12 The above entries will be referred to as ``ui.username`` and
13 13 ``ui.verbose``, respectively. See the Syntax section below.
14 14
15 15 Files
16 16 -----
17 17
18 18 Mercurial reads configuration data from several files, if they exist.
19 19 These files do not exist by default and you will have to create the
20 20 appropriate configuration files yourself: global configuration like
21 21 the username setting is typically put into
22 22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24 24
25 25 The names of these files depend on the system on which Mercurial is
26 26 installed. ``*.rc`` files from a single directory are read in
27 27 alphabetical order, later ones overriding earlier ones. Where multiple
28 28 paths are given below, settings from earlier paths override later
29 29 ones.
30 30
31 | (Unix, Windows) ``<repo>/.hg/hgrc``
31 | (All) ``<repo>/.hg/hgrc``
32 32
33 33 Per-repository configuration options that only apply in a
34 34 particular repository. This file is not version-controlled, and
35 35 will not get transferred during a "clone" operation. Options in
36 36 this file override options in all other configuration files. On
37 Unix, most of this file will be ignored if it doesn't belong to a
38 trusted user or to a trusted group. See the documentation for the
39 ``[trusted]`` section below for more details.
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
38 belong to a trusted user or to a trusted group. See the documentation
39 for the ``[trusted]`` section below for more details.
40 40
41 | (Plan 9) ``$home/lib/hgrc``
41 42 | (Unix) ``$HOME/.hgrc``
42 43 | (Windows) ``%USERPROFILE%\.hgrc``
43 44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 45 | (Windows) ``%HOME%\.hgrc``
45 46 | (Windows) ``%HOME%\Mercurial.ini``
46 47
47 48 Per-user configuration file(s), for the user running Mercurial. On
48 49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 50 files apply to all Mercurial commands executed by this user in any
50 51 directory. Options in these files override per-system and per-installation
51 52 options.
52 53
54 | (Plan 9) ``/lib/mercurial/hgrc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
53 56 | (Unix) ``/etc/mercurial/hgrc``
54 57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
55 58
56 59 Per-system configuration files, for the system on which Mercurial
57 60 is running. Options in these files apply to all Mercurial commands
58 61 executed by any user in any directory. Options in these files
59 62 override per-installation options.
60 63
64 | (Plan 9) ``<install-root>/lib/mercurial/hgrc``
65 | (Plan 9) ``<install-root>/lib/mercurial/hgrc.d/*.rc``
61 66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
62 67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
63 68
64 69 Per-installation configuration files, searched for in the
65 70 directory where Mercurial is installed. ``<install-root>`` is the
66 71 parent directory of the **hg** executable (or symlink) being run. For
67 72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
68 73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
69 74 to all Mercurial commands executed by any user in any directory.
70 75
71 76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
72 77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
73 78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
74 79
75 80 Per-installation/system configuration files, for the system on
76 81 which Mercurial is running. Options in these files apply to all
77 82 Mercurial commands executed by any user in any directory. Registry
78 83 keys contain PATH-like strings, every part of which must reference
79 84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
80 85 be read. Mercurial checks each of these locations in the specified
81 86 order until one or more configuration files are detected. If the
82 87 pywin32 extensions are not installed, Mercurial will only look for
83 88 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
84 89
85 90 Syntax
86 91 ------
87 92
88 93 A configuration file consists of sections, led by a ``[section]`` header
89 94 and followed by ``name = value`` entries (sometimes called
90 95 ``configuration keys``)::
91 96
92 97 [spam]
93 98 eggs=ham
94 99 green=
95 100 eggs
96 101
97 102 Each line contains one entry. If the lines that follow are indented,
98 103 they are treated as continuations of that entry. Leading whitespace is
99 104 removed from values. Empty lines are skipped. Lines beginning with
100 105 ``#`` or ``;`` are ignored and may be used to provide comments.
101 106
102 107 Configuration keys can be set multiple times, in which case Mercurial
103 108 will use the value that was configured last. As an example::
104 109
105 110 [spam]
106 111 eggs=large
107 112 ham=serrano
108 113 eggs=small
109 114
110 115 This would set the configuration key named ``eggs`` to ``small``.
111 116
112 117 It is also possible to define a section multiple times. A section can
113 118 be redefined on the same and/or on different configuration files. For
114 119 example::
115 120
116 121 [foo]
117 122 eggs=large
118 123 ham=serrano
119 124 eggs=small
120 125
121 126 [bar]
122 127 eggs=ham
123 128 green=
124 129 eggs
125 130
126 131 [foo]
127 132 ham=prosciutto
128 133 eggs=medium
129 134 bread=toasted
130 135
131 136 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
132 137 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
133 138 respectively. As you can see there only thing that matters is the last
134 139 value that was set for each of the configuration keys.
135 140
136 141 If a configuration key is set multiple times in different
137 142 configuration files the final value will depend on the order in which
138 143 the different configuration files are read, with settings from earlier
139 144 paths overriding later ones as described on the ``Files`` section
140 145 above.
141 146
142 147 A line of the form ``%include file`` will include ``file`` into the
143 148 current configuration file. The inclusion is recursive, which means
144 149 that included files can include other files. Filenames are relative to
145 150 the configuration file in which the ``%include`` directive is found.
146 151 Environment variables and ``~user`` constructs are expanded in
147 152 ``file``. This lets you do something like::
148 153
149 154 %include ~/.hgrc.d/$HOST.rc
150 155
151 156 to include a different configuration file on each computer you use.
152 157
153 158 A line with ``%unset name`` will remove ``name`` from the current
154 159 section, if it has been set previously.
155 160
156 161 The values are either free-form text strings, lists of text strings,
157 162 or Boolean values. Boolean values can be set to true using any of "1",
158 163 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
159 164 (all case insensitive).
160 165
161 166 List values are separated by whitespace or comma, except when values are
162 167 placed in double quotation marks::
163 168
164 169 allow_read = "John Doe, PhD", brian, betty
165 170
166 171 Quotation marks can be escaped by prefixing them with a backslash. Only
167 172 quotation marks at the beginning of a word is counted as a quotation
168 173 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
169 174
170 175 Sections
171 176 --------
172 177
173 178 This section describes the different sections that may appear in a
174 179 Mercurial configuration file, the purpose of each section, its possible
175 180 keys, and their possible values.
176 181
177 182 ``alias``
178 183 """""""""
179 184
180 185 Defines command aliases.
181 186 Aliases allow you to define your own commands in terms of other
182 187 commands (or aliases), optionally including arguments. Positional
183 188 arguments in the form of ``$1``, ``$2``, etc in the alias definition
184 189 are expanded by Mercurial before execution. Positional arguments not
185 190 already used by ``$N`` in the definition are put at the end of the
186 191 command to be executed.
187 192
188 193 Alias definitions consist of lines of the form::
189 194
190 195 <alias> = <command> [<argument>]...
191 196
192 197 For example, this definition::
193 198
194 199 latest = log --limit 5
195 200
196 201 creates a new command ``latest`` that shows only the five most recent
197 202 changesets. You can define subsequent aliases using earlier ones::
198 203
199 204 stable5 = latest -b stable
200 205
201 206 .. note:: It is possible to create aliases with the same names as
202 207 existing commands, which will then override the original
203 208 definitions. This is almost always a bad idea!
204 209
205 210 An alias can start with an exclamation point (``!``) to make it a
206 211 shell alias. A shell alias is executed with the shell and will let you
207 212 run arbitrary commands. As an example, ::
208 213
209 214 echo = !echo
210 215
211 216 will let you do ``hg echo foo`` to have ``foo`` printed in your
212 217 terminal. A better example might be::
213 218
214 219 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
215 220
216 221 which will make ``hg purge`` delete all unknown files in the
217 222 repository in the same manner as the purge extension.
218 223
219 224 Shell aliases are executed in an environment where ``$HG`` expand to
220 225 the path of the Mercurial that was used to execute the alias. This is
221 226 useful when you want to call further Mercurial commands in a shell
222 227 alias, as was done above for the purge alias. In addition,
223 228 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
224 229 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
225 230
226 231 .. note:: Some global configuration options such as ``-R`` are
227 232 processed before shell aliases and will thus not be passed to
228 233 aliases.
229 234
230 235
231 236 ``annotate``
232 237 """"""""""""
233 238
234 239 Settings used when displaying file annotations. All values are
235 240 Booleans and default to False. See ``diff`` section for related
236 241 options for the diff command.
237 242
238 243 ``ignorews``
239 244 Ignore white space when comparing lines.
240 245
241 246 ``ignorewsamount``
242 247 Ignore changes in the amount of white space.
243 248
244 249 ``ignoreblanklines``
245 250 Ignore changes whose lines are all blank.
246 251
247 252
248 253 ``auth``
249 254 """"""""
250 255
251 256 Authentication credentials for HTTP authentication. This section
252 257 allows you to store usernames and passwords for use when logging
253 258 *into* HTTP servers. See the ``[web]`` configuration section if
254 259 you want to configure *who* can login to your HTTP server.
255 260
256 261 Each line has the following format::
257 262
258 263 <name>.<argument> = <value>
259 264
260 265 where ``<name>`` is used to group arguments into authentication
261 266 entries. Example::
262 267
263 268 foo.prefix = hg.intevation.org/mercurial
264 269 foo.username = foo
265 270 foo.password = bar
266 271 foo.schemes = http https
267 272
268 273 bar.prefix = secure.example.org
269 274 bar.key = path/to/file.key
270 275 bar.cert = path/to/file.cert
271 276 bar.schemes = https
272 277
273 278 Supported arguments:
274 279
275 280 ``prefix``
276 281 Either ``*`` or a URI prefix with or without the scheme part.
277 282 The authentication entry with the longest matching prefix is used
278 283 (where ``*`` matches everything and counts as a match of length
279 284 1). If the prefix doesn't include a scheme, the match is performed
280 285 against the URI with its scheme stripped as well, and the schemes
281 286 argument, q.v., is then subsequently consulted.
282 287
283 288 ``username``
284 289 Optional. Username to authenticate with. If not given, and the
285 290 remote site requires basic or digest authentication, the user will
286 291 be prompted for it. Environment variables are expanded in the
287 292 username letting you do ``foo.username = $USER``. If the URI
288 293 includes a username, only ``[auth]`` entries with a matching
289 294 username or without a username will be considered.
290 295
291 296 ``password``
292 297 Optional. Password to authenticate with. If not given, and the
293 298 remote site requires basic or digest authentication, the user
294 299 will be prompted for it.
295 300
296 301 ``key``
297 302 Optional. PEM encoded client certificate key file. Environment
298 303 variables are expanded in the filename.
299 304
300 305 ``cert``
301 306 Optional. PEM encoded client certificate chain file. Environment
302 307 variables are expanded in the filename.
303 308
304 309 ``schemes``
305 310 Optional. Space separated list of URI schemes to use this
306 311 authentication entry with. Only used if the prefix doesn't include
307 312 a scheme. Supported schemes are http and https. They will match
308 313 static-http and static-https respectively, as well.
309 314 Default: https.
310 315
311 316 If no suitable authentication entry is found, the user is prompted
312 317 for credentials as usual if required by the remote.
313 318
314 319
315 320 ``decode/encode``
316 321 """""""""""""""""
317 322
318 323 Filters for transforming files on checkout/checkin. This would
319 324 typically be used for newline processing or other
320 325 localization/canonicalization of files.
321 326
322 327 Filters consist of a filter pattern followed by a filter command.
323 328 Filter patterns are globs by default, rooted at the repository root.
324 329 For example, to match any file ending in ``.txt`` in the root
325 330 directory only, use the pattern ``*.txt``. To match any file ending
326 331 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
327 332 For each file only the first matching filter applies.
328 333
329 334 The filter command can start with a specifier, either ``pipe:`` or
330 335 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
331 336
332 337 A ``pipe:`` command must accept data on stdin and return the transformed
333 338 data on stdout.
334 339
335 340 Pipe example::
336 341
337 342 [encode]
338 343 # uncompress gzip files on checkin to improve delta compression
339 344 # note: not necessarily a good idea, just an example
340 345 *.gz = pipe: gunzip
341 346
342 347 [decode]
343 348 # recompress gzip files when writing them to the working dir (we
344 349 # can safely omit "pipe:", because it's the default)
345 350 *.gz = gzip
346 351
347 352 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
348 353 with the name of a temporary file that contains the data to be
349 354 filtered by the command. The string ``OUTFILE`` is replaced with the name
350 355 of an empty temporary file, where the filtered data must be written by
351 356 the command.
352 357
353 358 .. note:: The tempfile mechanism is recommended for Windows systems,
354 359 where the standard shell I/O redirection operators often have
355 360 strange effects and may corrupt the contents of your files.
356 361
357 362 This filter mechanism is used internally by the ``eol`` extension to
358 363 translate line ending characters between Windows (CRLF) and Unix (LF)
359 364 format. We suggest you use the ``eol`` extension for convenience.
360 365
361 366
362 367 ``defaults``
363 368 """"""""""""
364 369
365 370 (defaults are deprecated. Don't use them. Use aliases instead)
366 371
367 372 Use the ``[defaults]`` section to define command defaults, i.e. the
368 373 default options/arguments to pass to the specified commands.
369 374
370 375 The following example makes :hg:`log` run in verbose mode, and
371 376 :hg:`status` show only the modified files, by default::
372 377
373 378 [defaults]
374 379 log = -v
375 380 status = -m
376 381
377 382 The actual commands, instead of their aliases, must be used when
378 383 defining command defaults. The command defaults will also be applied
379 384 to the aliases of the commands defined.
380 385
381 386
382 387 ``diff``
383 388 """"""""
384 389
385 390 Settings used when displaying diffs. Everything except for ``unified``
386 391 is a Boolean and defaults to False. See ``annotate`` section for
387 392 related options for the annotate command.
388 393
389 394 ``git``
390 395 Use git extended diff format.
391 396
392 397 ``nodates``
393 398 Don't include dates in diff headers.
394 399
395 400 ``showfunc``
396 401 Show which function each change is in.
397 402
398 403 ``ignorews``
399 404 Ignore white space when comparing lines.
400 405
401 406 ``ignorewsamount``
402 407 Ignore changes in the amount of white space.
403 408
404 409 ``ignoreblanklines``
405 410 Ignore changes whose lines are all blank.
406 411
407 412 ``unified``
408 413 Number of lines of context to show.
409 414
410 415 ``email``
411 416 """""""""
412 417
413 418 Settings for extensions that send email messages.
414 419
415 420 ``from``
416 421 Optional. Email address to use in "From" header and SMTP envelope
417 422 of outgoing messages.
418 423
419 424 ``to``
420 425 Optional. Comma-separated list of recipients' email addresses.
421 426
422 427 ``cc``
423 428 Optional. Comma-separated list of carbon copy recipients'
424 429 email addresses.
425 430
426 431 ``bcc``
427 432 Optional. Comma-separated list of blind carbon copy recipients'
428 433 email addresses.
429 434
430 435 ``method``
431 436 Optional. Method to use to send email messages. If value is ``smtp``
432 437 (default), use SMTP (see the ``[smtp]`` section for configuration).
433 438 Otherwise, use as name of program to run that acts like sendmail
434 439 (takes ``-f`` option for sender, list of recipients on command line,
435 440 message on stdin). Normally, setting this to ``sendmail`` or
436 441 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
437 442
438 443 ``charsets``
439 444 Optional. Comma-separated list of character sets considered
440 445 convenient for recipients. Addresses, headers, and parts not
441 446 containing patches of outgoing messages will be encoded in the
442 447 first character set to which conversion from local encoding
443 448 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
444 449 conversion fails, the text in question is sent as is. Defaults to
445 450 empty (explicit) list.
446 451
447 452 Order of outgoing email character sets:
448 453
449 454 1. ``us-ascii``: always first, regardless of settings
450 455 2. ``email.charsets``: in order given by user
451 456 3. ``ui.fallbackencoding``: if not in email.charsets
452 457 4. ``$HGENCODING``: if not in email.charsets
453 458 5. ``utf-8``: always last, regardless of settings
454 459
455 460 Email example::
456 461
457 462 [email]
458 463 from = Joseph User <joe.user@example.com>
459 464 method = /usr/sbin/sendmail
460 465 # charsets for western Europeans
461 466 # us-ascii, utf-8 omitted, as they are tried first and last
462 467 charsets = iso-8859-1, iso-8859-15, windows-1252
463 468
464 469
465 470 ``extensions``
466 471 """"""""""""""
467 472
468 473 Mercurial has an extension mechanism for adding new features. To
469 474 enable an extension, create an entry for it in this section.
470 475
471 476 If you know that the extension is already in Python's search path,
472 477 you can give the name of the module, followed by ``=``, with nothing
473 478 after the ``=``.
474 479
475 480 Otherwise, give a name that you choose, followed by ``=``, followed by
476 481 the path to the ``.py`` file (including the file name extension) that
477 482 defines the extension.
478 483
479 484 To explicitly disable an extension that is enabled in an hgrc of
480 485 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
481 486 or ``foo = !`` when path is not supplied.
482 487
483 488 Example for ``~/.hgrc``::
484 489
485 490 [extensions]
486 491 # (the mq extension will get loaded from Mercurial's path)
487 492 mq =
488 493 # (this extension will get loaded from the file specified)
489 494 myfeature = ~/.hgext/myfeature.py
490 495
491 496
492 497 ``format``
493 498 """"""""""
494 499
495 500 ``usestore``
496 501 Enable or disable the "store" repository format which improves
497 502 compatibility with systems that fold case or otherwise mangle
498 503 filenames. Enabled by default. Disabling this option will allow
499 504 you to store longer filenames in some situations at the expense of
500 505 compatibility and ensures that the on-disk format of newly created
501 506 repositories will be compatible with Mercurial before version 0.9.4.
502 507
503 508 ``usefncache``
504 509 Enable or disable the "fncache" repository format which enhances
505 510 the "store" repository format (which has to be enabled to use
506 511 fncache) to allow longer filenames and avoids using Windows
507 512 reserved names, e.g. "nul". Enabled by default. Disabling this
508 513 option ensures that the on-disk format of newly created
509 514 repositories will be compatible with Mercurial before version 1.1.
510 515
511 516 ``dotencode``
512 517 Enable or disable the "dotencode" repository format which enhances
513 518 the "fncache" repository format (which has to be enabled to use
514 519 dotencode) to avoid issues with filenames starting with ._ on
515 520 Mac OS X and spaces on Windows. Enabled by default. Disabling this
516 521 option ensures that the on-disk format of newly created
517 522 repositories will be compatible with Mercurial before version 1.7.
518 523
519 524 ``graph``
520 525 """""""""
521 526
522 527 Web graph view configuration. This section let you change graph
523 528 elements display properties by branches, for instance to make the
524 529 ``default`` branch stand out.
525 530
526 531 Each line has the following format::
527 532
528 533 <branch>.<argument> = <value>
529 534
530 535 where ``<branch>`` is the name of the branch being
531 536 customized. Example::
532 537
533 538 [graph]
534 539 # 2px width
535 540 default.width = 2
536 541 # red color
537 542 default.color = FF0000
538 543
539 544 Supported arguments:
540 545
541 546 ``width``
542 547 Set branch edges width in pixels.
543 548
544 549 ``color``
545 550 Set branch edges color in hexadecimal RGB notation.
546 551
547 552 ``hooks``
548 553 """""""""
549 554
550 555 Commands or Python functions that get automatically executed by
551 556 various actions such as starting or finishing a commit. Multiple
552 557 hooks can be run for the same action by appending a suffix to the
553 558 action. Overriding a site-wide hook can be done by changing its
554 559 value or setting it to an empty string. Hooks can be prioritized
555 560 by adding a prefix of ``priority`` to the hook name on a new line
556 561 and setting the priority. The default priority is 0 if
557 562 not specified.
558 563
559 564 Example ``.hg/hgrc``::
560 565
561 566 [hooks]
562 567 # update working directory after adding changesets
563 568 changegroup.update = hg update
564 569 # do not use the site-wide hook
565 570 incoming =
566 571 incoming.email = /my/email/hook
567 572 incoming.autobuild = /my/build/hook
568 573 # force autobuild hook to run before other incoming hooks
569 574 priority.incoming.autobuild = 1
570 575
571 576 Most hooks are run with environment variables set that give useful
572 577 additional information. For each hook below, the environment
573 578 variables it is passed are listed with names of the form ``$HG_foo``.
574 579
575 580 ``changegroup``
576 581 Run after a changegroup has been added via push, pull or unbundle.
577 582 ID of the first new changeset is in ``$HG_NODE``. URL from which
578 583 changes came is in ``$HG_URL``.
579 584
580 585 ``commit``
581 586 Run after a changeset has been created in the local repository. ID
582 587 of the newly created changeset is in ``$HG_NODE``. Parent changeset
583 588 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
584 589
585 590 ``incoming``
586 591 Run after a changeset has been pulled, pushed, or unbundled into
587 592 the local repository. The ID of the newly arrived changeset is in
588 593 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
589 594
590 595 ``outgoing``
591 596 Run after sending changes from local repository to another. ID of
592 597 first changeset sent is in ``$HG_NODE``. Source of operation is in
593 598 ``$HG_SOURCE``; see "preoutgoing" hook for description.
594 599
595 600 ``post-<command>``
596 601 Run after successful invocations of the associated command. The
597 602 contents of the command line are passed as ``$HG_ARGS`` and the result
598 603 code in ``$HG_RESULT``. Parsed command line arguments are passed as
599 604 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
600 605 the python data internally passed to <command>. ``$HG_OPTS`` is a
601 606 dictionary of options (with unspecified options set to their defaults).
602 607 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
603 608
604 609 ``pre-<command>``
605 610 Run before executing the associated command. The contents of the
606 611 command line are passed as ``$HG_ARGS``. Parsed command line arguments
607 612 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
608 613 representations of the data internally passed to <command>. ``$HG_OPTS``
609 614 is a dictionary of options (with unspecified options set to their
610 615 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
611 616 failure, the command doesn't execute and Mercurial returns the failure
612 617 code.
613 618
614 619 ``prechangegroup``
615 620 Run before a changegroup is added via push, pull or unbundle. Exit
616 621 status 0 allows the changegroup to proceed. Non-zero status will
617 622 cause the push, pull or unbundle to fail. URL from which changes
618 623 will come is in ``$HG_URL``.
619 624
620 625 ``precommit``
621 626 Run before starting a local commit. Exit status 0 allows the
622 627 commit to proceed. Non-zero status will cause the commit to fail.
623 628 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
624 629
625 630 ``prelistkeys``
626 631 Run before listing pushkeys (like bookmarks) in the
627 632 repository. Non-zero status will cause failure. The key namespace is
628 633 in ``$HG_NAMESPACE``.
629 634
630 635 ``preoutgoing``
631 636 Run before collecting changes to send from the local repository to
632 637 another. Non-zero status will cause failure. This lets you prevent
633 638 pull over HTTP or SSH. Also prevents against local pull, push
634 639 (outbound) or bundle commands, but not effective, since you can
635 640 just copy files instead then. Source of operation is in
636 641 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
637 642 SSH or HTTP repository. If "push", "pull" or "bundle", operation
638 643 is happening on behalf of repository on same system.
639 644
640 645 ``prepushkey``
641 646 Run before a pushkey (like a bookmark) is added to the
642 647 repository. Non-zero status will cause the key to be rejected. The
643 648 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
644 649 the old value (if any) is in ``$HG_OLD``, and the new value is in
645 650 ``$HG_NEW``.
646 651
647 652 ``pretag``
648 653 Run before creating a tag. Exit status 0 allows the tag to be
649 654 created. Non-zero status will cause the tag to fail. ID of
650 655 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
651 656 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
652 657
653 658 ``pretxnchangegroup``
654 659 Run after a changegroup has been added via push, pull or unbundle,
655 660 but before the transaction has been committed. Changegroup is
656 661 visible to hook program. This lets you validate incoming changes
657 662 before accepting them. Passed the ID of the first new changeset in
658 663 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
659 664 status will cause the transaction to be rolled back and the push,
660 665 pull or unbundle will fail. URL that was source of changes is in
661 666 ``$HG_URL``.
662 667
663 668 ``pretxncommit``
664 669 Run after a changeset has been created but the transaction not yet
665 670 committed. Changeset is visible to hook program. This lets you
666 671 validate commit message and changes. Exit status 0 allows the
667 672 commit to proceed. Non-zero status will cause the transaction to
668 673 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
669 674 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
670 675
671 676 ``preupdate``
672 677 Run before updating the working directory. Exit status 0 allows
673 678 the update to proceed. Non-zero status will prevent the update.
674 679 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
675 680 of second new parent is in ``$HG_PARENT2``.
676 681
677 682 ``listkeys``
678 683 Run after listing pushkeys (like bookmarks) in the repository. The
679 684 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
680 685 dictionary containing the keys and values.
681 686
682 687 ``pushkey``
683 688 Run after a pushkey (like a bookmark) is added to the
684 689 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
685 690 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
686 691 value is in ``$HG_NEW``.
687 692
688 693 ``tag``
689 694 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
690 695 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
691 696 repository if ``$HG_LOCAL=0``.
692 697
693 698 ``update``
694 699 Run after updating the working directory. Changeset ID of first
695 700 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
696 701 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
697 702 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
698 703
699 704 .. note:: It is generally better to use standard hooks rather than the
700 705 generic pre- and post- command hooks as they are guaranteed to be
701 706 called in the appropriate contexts for influencing transactions.
702 707 Also, hooks like "commit" will be called in all contexts that
703 708 generate a commit (e.g. tag) and not just the commit command.
704 709
705 710 .. note:: Environment variables with empty values may not be passed to
706 711 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
707 712 will have an empty value under Unix-like platforms for non-merge
708 713 changesets, while it will not be available at all under Windows.
709 714
710 715 The syntax for Python hooks is as follows::
711 716
712 717 hookname = python:modulename.submodule.callable
713 718 hookname = python:/path/to/python/module.py:callable
714 719
715 720 Python hooks are run within the Mercurial process. Each hook is
716 721 called with at least three keyword arguments: a ui object (keyword
717 722 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
718 723 keyword that tells what kind of hook is used. Arguments listed as
719 724 environment variables above are passed as keyword arguments, with no
720 725 ``HG_`` prefix, and names in lower case.
721 726
722 727 If a Python hook returns a "true" value or raises an exception, this
723 728 is treated as a failure.
724 729
725 730
726 731 ``hostfingerprints``
727 732 """"""""""""""""""""
728 733
729 734 Fingerprints of the certificates of known HTTPS servers.
730 735 A HTTPS connection to a server with a fingerprint configured here will
731 736 only succeed if the servers certificate matches the fingerprint.
732 737 This is very similar to how ssh known hosts works.
733 738 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
734 739 The CA chain and web.cacerts is not used for servers with a fingerprint.
735 740
736 741 For example::
737 742
738 743 [hostfingerprints]
739 744 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
740 745
741 746 This feature is only supported when using Python 2.6 or later.
742 747
743 748
744 749 ``http_proxy``
745 750 """"""""""""""
746 751
747 752 Used to access web-based Mercurial repositories through a HTTP
748 753 proxy.
749 754
750 755 ``host``
751 756 Host name and (optional) port of the proxy server, for example
752 757 "myproxy:8000".
753 758
754 759 ``no``
755 760 Optional. Comma-separated list of host names that should bypass
756 761 the proxy.
757 762
758 763 ``passwd``
759 764 Optional. Password to authenticate with at the proxy server.
760 765
761 766 ``user``
762 767 Optional. User name to authenticate with at the proxy server.
763 768
764 769 ``always``
765 770 Optional. Always use the proxy, even for localhost and any entries
766 771 in ``http_proxy.no``. True or False. Default: False.
767 772
768 773 ``merge-patterns``
769 774 """"""""""""""""""
770 775
771 776 This section specifies merge tools to associate with particular file
772 777 patterns. Tools matched here will take precedence over the default
773 778 merge tool. Patterns are globs by default, rooted at the repository
774 779 root.
775 780
776 781 Example::
777 782
778 783 [merge-patterns]
779 784 **.c = kdiff3
780 785 **.jpg = myimgmerge
781 786
782 787 ``merge-tools``
783 788 """""""""""""""
784 789
785 790 This section configures external merge tools to use for file-level
786 791 merges.
787 792
788 793 Example ``~/.hgrc``::
789 794
790 795 [merge-tools]
791 796 # Override stock tool location
792 797 kdiff3.executable = ~/bin/kdiff3
793 798 # Specify command line
794 799 kdiff3.args = $base $local $other -o $output
795 800 # Give higher priority
796 801 kdiff3.priority = 1
797 802
798 803 # Define new tool
799 804 myHtmlTool.args = -m $local $other $base $output
800 805 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
801 806 myHtmlTool.priority = 1
802 807
803 808 Supported arguments:
804 809
805 810 ``priority``
806 811 The priority in which to evaluate this tool.
807 812 Default: 0.
808 813
809 814 ``executable``
810 815 Either just the name of the executable or its pathname. On Windows,
811 816 the path can use environment variables with ${ProgramFiles} syntax.
812 817 Default: the tool name.
813 818
814 819 ``args``
815 820 The arguments to pass to the tool executable. You can refer to the
816 821 files being merged as well as the output file through these
817 822 variables: ``$base``, ``$local``, ``$other``, ``$output``.
818 823 Default: ``$local $base $other``
819 824
820 825 ``premerge``
821 826 Attempt to run internal non-interactive 3-way merge tool before
822 827 launching external tool. Options are ``true``, ``false``, or ``keep``
823 828 to leave markers in the file if the premerge fails.
824 829 Default: True
825 830
826 831 ``binary``
827 832 This tool can merge binary files. Defaults to False, unless tool
828 833 was selected by file pattern match.
829 834
830 835 ``symlink``
831 836 This tool can merge symlinks. Defaults to False, even if tool was
832 837 selected by file pattern match.
833 838
834 839 ``check``
835 840 A list of merge success-checking options:
836 841
837 842 ``changed``
838 843 Ask whether merge was successful when the merged file shows no changes.
839 844 ``conflicts``
840 845 Check whether there are conflicts even though the tool reported success.
841 846 ``prompt``
842 847 Always prompt for merge success, regardless of success reported by tool.
843 848
844 849 ``checkchanged``
845 850 True is equivalent to ``check = changed``.
846 851 Default: False
847 852
848 853 ``checkconflicts``
849 854 True is equivalent to ``check = conflicts``.
850 855 Default: False
851 856
852 857 ``fixeol``
853 858 Attempt to fix up EOL changes caused by the merge tool.
854 859 Default: False
855 860
856 861 ``gui``
857 862 This tool requires a graphical interface to run. Default: False
858 863
859 864 ``regkey``
860 865 Windows registry key which describes install location of this
861 866 tool. Mercurial will search for this key first under
862 867 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
863 868 Default: None
864 869
865 870 ``regkeyalt``
866 871 An alternate Windows registry key to try if the first key is not
867 872 found. The alternate key uses the same ``regname`` and ``regappend``
868 873 semantics of the primary key. The most common use for this key
869 874 is to search for 32bit applications on 64bit operating systems.
870 875 Default: None
871 876
872 877 ``regname``
873 878 Name of value to read from specified registry key. Defaults to the
874 879 unnamed (default) value.
875 880
876 881 ``regappend``
877 882 String to append to the value read from the registry, typically
878 883 the executable name of the tool.
879 884 Default: None
880 885
881 886
882 887 ``patch``
883 888 """""""""
884 889
885 890 Settings used when applying patches, for instance through the 'import'
886 891 command or with Mercurial Queues extension.
887 892
888 893 ``eol``
889 894 When set to 'strict' patch content and patched files end of lines
890 895 are preserved. When set to ``lf`` or ``crlf``, both files end of
891 896 lines are ignored when patching and the result line endings are
892 897 normalized to either LF (Unix) or CRLF (Windows). When set to
893 898 ``auto``, end of lines are again ignored while patching but line
894 899 endings in patched files are normalized to their original setting
895 900 on a per-file basis. If target file does not exist or has no end
896 901 of line, patch line endings are preserved.
897 902 Default: strict.
898 903
899 904
900 905 ``paths``
901 906 """""""""
902 907
903 908 Assigns symbolic names to repositories. The left side is the
904 909 symbolic name, and the right gives the directory or URL that is the
905 910 location of the repository. Default paths can be declared by setting
906 911 the following entries.
907 912
908 913 ``default``
909 914 Directory or URL to use when pulling if no source is specified.
910 915 Default is set to repository from which the current repository was
911 916 cloned.
912 917
913 918 ``default-push``
914 919 Optional. Directory or URL to use when pushing if no destination
915 920 is specified.
916 921
917 922 ``phases``
918 923 """"""""""
919 924
920 925 Specifies default handling of phases. See :hg:`help phases` for more
921 926 information about working with phases.
922 927
923 928 ``publish``
924 929 Controls draft phase behavior when working as a server. When true,
925 930 pushed changesets are set to public in both client and server and
926 931 pulled or cloned changesets are set to public in the client.
927 932 Default: True
928 933
929 934 ``new-commit``
930 935 Phase of newly-created commits.
931 936 Default: draft
932 937
933 938 ``profiling``
934 939 """""""""""""
935 940
936 941 Specifies profiling format and file output. In this section
937 942 description, 'profiling data' stands for the raw data collected
938 943 during profiling, while 'profiling report' stands for a statistical
939 944 text report generated from the profiling data. The profiling is done
940 945 using lsprof.
941 946
942 947 ``format``
943 948 Profiling format.
944 949 Default: text.
945 950
946 951 ``text``
947 952 Generate a profiling report. When saving to a file, it should be
948 953 noted that only the report is saved, and the profiling data is
949 954 not kept.
950 955 ``kcachegrind``
951 956 Format profiling data for kcachegrind use: when saving to a
952 957 file, the generated file can directly be loaded into
953 958 kcachegrind.
954 959
955 960 ``output``
956 961 File path where profiling data or report should be saved. If the
957 962 file exists, it is replaced. Default: None, data is printed on
958 963 stderr
959 964
960 965 ``revsetalias``
961 966 """""""""""""""
962 967
963 968 Alias definitions for revsets. See :hg:`help revsets` for details.
964 969
965 970 ``server``
966 971 """"""""""
967 972
968 973 Controls generic server settings.
969 974
970 975 ``uncompressed``
971 976 Whether to allow clients to clone a repository using the
972 977 uncompressed streaming protocol. This transfers about 40% more
973 978 data than a regular clone, but uses less memory and CPU on both
974 979 server and client. Over a LAN (100 Mbps or better) or a very fast
975 980 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
976 981 regular clone. Over most WAN connections (anything slower than
977 982 about 6 Mbps), uncompressed streaming is slower, because of the
978 983 extra data transfer overhead. This mode will also temporarily hold
979 984 the write lock while determining what data to transfer.
980 985 Default is True.
981 986
982 987 ``preferuncompressed``
983 988 When set, clients will try to use the uncompressed streaming
984 989 protocol. Default is False.
985 990
986 991 ``validate``
987 992 Whether to validate the completeness of pushed changesets by
988 993 checking that all new file revisions specified in manifests are
989 994 present. Default is False.
990 995
991 996 ``smtp``
992 997 """"""""
993 998
994 999 Configuration for extensions that need to send email messages.
995 1000
996 1001 ``host``
997 1002 Host name of mail server, e.g. "mail.example.com".
998 1003
999 1004 ``port``
1000 1005 Optional. Port to connect to on mail server. Default: 25.
1001 1006
1002 1007 ``tls``
1003 1008 Optional. Method to enable TLS when connecting to mail server: starttls,
1004 1009 smtps or none. Default: none.
1005 1010
1006 1011 ``username``
1007 1012 Optional. User name for authenticating with the SMTP server.
1008 1013 Default: none.
1009 1014
1010 1015 ``password``
1011 1016 Optional. Password for authenticating with the SMTP server. If not
1012 1017 specified, interactive sessions will prompt the user for a
1013 1018 password; non-interactive sessions will fail. Default: none.
1014 1019
1015 1020 ``local_hostname``
1016 1021 Optional. It's the hostname that the sender can use to identify
1017 1022 itself to the MTA.
1018 1023
1019 1024
1020 1025 ``subpaths``
1021 1026 """"""""""""
1022 1027
1023 1028 Defines subrepositories source locations rewriting rules of the form::
1024 1029
1025 1030 <pattern> = <replacement>
1026 1031
1027 1032 Where ``pattern`` is a regular expression matching the source and
1028 1033 ``replacement`` is the replacement string used to rewrite it. Groups
1029 1034 can be matched in ``pattern`` and referenced in ``replacements``. For
1030 1035 instance::
1031 1036
1032 1037 http://server/(.*)-hg/ = http://hg.server/\1/
1033 1038
1034 1039 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1035 1040
1036 1041 All patterns are applied in definition order.
1037 1042
1038 1043 ``trusted``
1039 1044 """""""""""
1040 1045
1041 1046 Mercurial will not use the settings in the
1042 1047 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1043 1048 user or to a trusted group, as various hgrc features allow arbitrary
1044 1049 commands to be run. This issue is often encountered when configuring
1045 1050 hooks or extensions for shared repositories or servers. However,
1046 1051 the web interface will use some safe settings from the ``[web]``
1047 1052 section.
1048 1053
1049 1054 This section specifies what users and groups are trusted. The
1050 1055 current user is always trusted. To trust everybody, list a user or a
1051 1056 group with name ``*``. These settings must be placed in an
1052 1057 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1053 1058 user or service running Mercurial.
1054 1059
1055 1060 ``users``
1056 1061 Comma-separated list of trusted users.
1057 1062
1058 1063 ``groups``
1059 1064 Comma-separated list of trusted groups.
1060 1065
1061 1066
1062 1067 ``ui``
1063 1068 """"""
1064 1069
1065 1070 User interface controls.
1066 1071
1067 1072 ``archivemeta``
1068 1073 Whether to include the .hg_archival.txt file containing meta data
1069 1074 (hashes for the repository base and for tip) in archives created
1070 1075 by the :hg:`archive` command or downloaded via hgweb.
1071 1076 Default is True.
1072 1077
1073 1078 ``askusername``
1074 1079 Whether to prompt for a username when committing. If True, and
1075 1080 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1076 1081 be prompted to enter a username. If no username is entered, the
1077 1082 default ``USER@HOST`` is used instead.
1078 1083 Default is False.
1079 1084
1080 1085 ``commitsubrepos``
1081 1086 Whether to commit modified subrepositories when committing the
1082 1087 parent repository. If False and one subrepository has uncommitted
1083 1088 changes, abort the commit.
1084 1089 Default is False.
1085 1090
1086 1091 ``debug``
1087 1092 Print debugging information. True or False. Default is False.
1088 1093
1089 1094 ``editor``
1090 1095 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1091 1096
1092 1097 ``fallbackencoding``
1093 1098 Encoding to try if it's not possible to decode the changelog using
1094 1099 UTF-8. Default is ISO-8859-1.
1095 1100
1096 1101 ``ignore``
1097 1102 A file to read per-user ignore patterns from. This file should be
1098 1103 in the same format as a repository-wide .hgignore file. This
1099 1104 option supports hook syntax, so if you want to specify multiple
1100 1105 ignore files, you can do so by setting something like
1101 1106 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1102 1107 format, see the ``hgignore(5)`` man page.
1103 1108
1104 1109 ``interactive``
1105 1110 Allow to prompt the user. True or False. Default is True.
1106 1111
1107 1112 ``logtemplate``
1108 1113 Template string for commands that print changesets.
1109 1114
1110 1115 ``merge``
1111 1116 The conflict resolution program to use during a manual merge.
1112 1117 For more information on merge tools see :hg:`help merge-tools`.
1113 1118 For configuring merge tools see the ``[merge-tools]`` section.
1114 1119
1115 1120 ``portablefilenames``
1116 1121 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1117 1122 Default is ``warn``.
1118 1123 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1119 1124 platforms, if a file with a non-portable filename is added (e.g. a file
1120 1125 with a name that can't be created on Windows because it contains reserved
1121 1126 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1122 1127 collision with an existing file).
1123 1128 If set to ``ignore`` (or ``false``), no warning is printed.
1124 1129 If set to ``abort``, the command is aborted.
1125 1130 On Windows, this configuration option is ignored and the command aborted.
1126 1131
1127 1132 ``quiet``
1128 1133 Reduce the amount of output printed. True or False. Default is False.
1129 1134
1130 1135 ``remotecmd``
1131 1136 remote command to use for clone/push/pull operations. Default is ``hg``.
1132 1137
1133 1138 ``report_untrusted``
1134 1139 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1135 1140 trusted user or group. True or False. Default is True.
1136 1141
1137 1142 ``slash``
1138 1143 Display paths using a slash (``/``) as the path separator. This
1139 1144 only makes a difference on systems where the default path
1140 1145 separator is not the slash character (e.g. Windows uses the
1141 1146 backslash character (``\``)).
1142 1147 Default is False.
1143 1148
1144 1149 ``ssh``
1145 1150 command to use for SSH connections. Default is ``ssh``.
1146 1151
1147 1152 ``strict``
1148 1153 Require exact command names, instead of allowing unambiguous
1149 1154 abbreviations. True or False. Default is False.
1150 1155
1151 1156 ``style``
1152 1157 Name of style to use for command output.
1153 1158
1154 1159 ``timeout``
1155 1160 The timeout used when a lock is held (in seconds), a negative value
1156 1161 means no timeout. Default is 600.
1157 1162
1158 1163 ``traceback``
1159 1164 Mercurial always prints a traceback when an unknown exception
1160 1165 occurs. Setting this to True will make Mercurial print a traceback
1161 1166 on all exceptions, even those recognized by Mercurial (such as
1162 1167 IOError or MemoryError). Default is False.
1163 1168
1164 1169 ``username``
1165 1170 The committer of a changeset created when running "commit".
1166 1171 Typically a person's name and email address, e.g. ``Fred Widget
1167 1172 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1168 1173 the username in hgrc is empty, it has to be specified manually or
1169 1174 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1170 1175 ``username =`` in the system hgrc). Environment variables in the
1171 1176 username are expanded.
1172 1177
1173 1178 ``verbose``
1174 1179 Increase the amount of output printed. True or False. Default is False.
1175 1180
1176 1181
1177 1182 ``web``
1178 1183 """""""
1179 1184
1180 1185 Web interface configuration. The settings in this section apply to
1181 1186 both the builtin webserver (started by :hg:`serve`) and the script you
1182 1187 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1183 1188 and WSGI).
1184 1189
1185 1190 The Mercurial webserver does no authentication (it does not prompt for
1186 1191 usernames and passwords to validate *who* users are), but it does do
1187 1192 authorization (it grants or denies access for *authenticated users*
1188 1193 based on settings in this section). You must either configure your
1189 1194 webserver to do authentication for you, or disable the authorization
1190 1195 checks.
1191 1196
1192 1197 For a quick setup in a trusted environment, e.g., a private LAN, where
1193 1198 you want it to accept pushes from anybody, you can use the following
1194 1199 command line::
1195 1200
1196 1201 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1197 1202
1198 1203 Note that this will allow anybody to push anything to the server and
1199 1204 that this should not be used for public servers.
1200 1205
1201 1206 The full set of options is:
1202 1207
1203 1208 ``accesslog``
1204 1209 Where to output the access log. Default is stdout.
1205 1210
1206 1211 ``address``
1207 1212 Interface address to bind to. Default is all.
1208 1213
1209 1214 ``allow_archive``
1210 1215 List of archive format (bz2, gz, zip) allowed for downloading.
1211 1216 Default is empty.
1212 1217
1213 1218 ``allowbz2``
1214 1219 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1215 1220 revisions.
1216 1221 Default is False.
1217 1222
1218 1223 ``allowgz``
1219 1224 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1220 1225 revisions.
1221 1226 Default is False.
1222 1227
1223 1228 ``allowpull``
1224 1229 Whether to allow pulling from the repository. Default is True.
1225 1230
1226 1231 ``allow_push``
1227 1232 Whether to allow pushing to the repository. If empty or not set,
1228 1233 push is not allowed. If the special value ``*``, any remote user can
1229 1234 push, including unauthenticated users. Otherwise, the remote user
1230 1235 must have been authenticated, and the authenticated user name must
1231 1236 be present in this list. The contents of the allow_push list are
1232 1237 examined after the deny_push list.
1233 1238
1234 1239 ``guessmime``
1235 1240 Control MIME types for raw download of file content.
1236 1241 Set to True to let hgweb guess the content type from the file
1237 1242 extension. This will serve HTML files as ``text/html`` and might
1238 1243 allow cross-site scripting attacks when serving untrusted
1239 1244 repositories. Default is False.
1240 1245
1241 1246 ``allow_read``
1242 1247 If the user has not already been denied repository access due to
1243 1248 the contents of deny_read, this list determines whether to grant
1244 1249 repository access to the user. If this list is not empty, and the
1245 1250 user is unauthenticated or not present in the list, then access is
1246 1251 denied for the user. If the list is empty or not set, then access
1247 1252 is permitted to all users by default. Setting allow_read to the
1248 1253 special value ``*`` is equivalent to it not being set (i.e. access
1249 1254 is permitted to all users). The contents of the allow_read list are
1250 1255 examined after the deny_read list.
1251 1256
1252 1257 ``allowzip``
1253 1258 (DEPRECATED) Whether to allow .zip downloading of repository
1254 1259 revisions. Default is False. This feature creates temporary files.
1255 1260
1256 1261 ``baseurl``
1257 1262 Base URL to use when publishing URLs in other locations, so
1258 1263 third-party tools like email notification hooks can construct
1259 1264 URLs. Example: ``http://hgserver/repos/``.
1260 1265
1261 1266 ``cacerts``
1262 1267 Path to file containing a list of PEM encoded certificate
1263 1268 authority certificates. Environment variables and ``~user``
1264 1269 constructs are expanded in the filename. If specified on the
1265 1270 client, then it will verify the identity of remote HTTPS servers
1266 1271 with these certificates. The form must be as follows::
1267 1272
1268 1273 -----BEGIN CERTIFICATE-----
1269 1274 ... (certificate in base64 PEM encoding) ...
1270 1275 -----END CERTIFICATE-----
1271 1276 -----BEGIN CERTIFICATE-----
1272 1277 ... (certificate in base64 PEM encoding) ...
1273 1278 -----END CERTIFICATE-----
1274 1279
1275 1280 This feature is only supported when using Python 2.6 or later. If you wish
1276 1281 to use it with earlier versions of Python, install the backported
1277 1282 version of the ssl library that is available from
1278 1283 ``http://pypi.python.org``.
1279 1284
1280 1285 You can use OpenSSL's CA certificate file if your platform has one.
1281 1286 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1282 1287 Otherwise you will have to generate this file manually.
1283 1288
1284 1289 To disable SSL verification temporarily, specify ``--insecure`` from
1285 1290 command line.
1286 1291
1287 1292 ``cache``
1288 1293 Whether to support caching in hgweb. Defaults to True.
1289 1294
1290 1295 ``contact``
1291 1296 Name or email address of the person in charge of the repository.
1292 1297 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1293 1298
1294 1299 ``deny_push``
1295 1300 Whether to deny pushing to the repository. If empty or not set,
1296 1301 push is not denied. If the special value ``*``, all remote users are
1297 1302 denied push. Otherwise, unauthenticated users are all denied, and
1298 1303 any authenticated user name present in this list is also denied. The
1299 1304 contents of the deny_push list are examined before the allow_push list.
1300 1305
1301 1306 ``deny_read``
1302 1307 Whether to deny reading/viewing of the repository. If this list is
1303 1308 not empty, unauthenticated users are all denied, and any
1304 1309 authenticated user name present in this list is also denied access to
1305 1310 the repository. If set to the special value ``*``, all remote users
1306 1311 are denied access (rarely needed ;). If deny_read is empty or not set,
1307 1312 the determination of repository access depends on the presence and
1308 1313 content of the allow_read list (see description). If both
1309 1314 deny_read and allow_read are empty or not set, then access is
1310 1315 permitted to all users by default. If the repository is being
1311 1316 served via hgwebdir, denied users will not be able to see it in
1312 1317 the list of repositories. The contents of the deny_read list have
1313 1318 priority over (are examined before) the contents of the allow_read
1314 1319 list.
1315 1320
1316 1321 ``descend``
1317 1322 hgwebdir indexes will not descend into subdirectories. Only repositories
1318 1323 directly in the current path will be shown (other repositories are still
1319 1324 available from the index corresponding to their containing path).
1320 1325
1321 1326 ``description``
1322 1327 Textual description of the repository's purpose or contents.
1323 1328 Default is "unknown".
1324 1329
1325 1330 ``encoding``
1326 1331 Character encoding name. Default is the current locale charset.
1327 1332 Example: "UTF-8"
1328 1333
1329 1334 ``errorlog``
1330 1335 Where to output the error log. Default is stderr.
1331 1336
1332 1337 ``hidden``
1333 1338 Whether to hide the repository in the hgwebdir index.
1334 1339 Default is False.
1335 1340
1336 1341 ``ipv6``
1337 1342 Whether to use IPv6. Default is False.
1338 1343
1339 1344 ``logoimg``
1340 1345 File name of the logo image that some templates display on each page.
1341 1346 The file name is relative to ``staticurl``. That is, the full path to
1342 1347 the logo image is "staticurl/logoimg".
1343 1348 If unset, ``hglogo.png`` will be used.
1344 1349
1345 1350 ``logourl``
1346 1351 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1347 1352 will be used.
1348 1353
1349 1354 ``name``
1350 1355 Repository name to use in the web interface. Default is current
1351 1356 working directory.
1352 1357
1353 1358 ``maxchanges``
1354 1359 Maximum number of changes to list on the changelog. Default is 10.
1355 1360
1356 1361 ``maxfiles``
1357 1362 Maximum number of files to list per changeset. Default is 10.
1358 1363
1359 1364 ``port``
1360 1365 Port to listen on. Default is 8000.
1361 1366
1362 1367 ``prefix``
1363 1368 Prefix path to serve from. Default is '' (server root).
1364 1369
1365 1370 ``push_ssl``
1366 1371 Whether to require that inbound pushes be transported over SSL to
1367 1372 prevent password sniffing. Default is True.
1368 1373
1369 1374 ``staticurl``
1370 1375 Base URL to use for static files. If unset, static files (e.g. the
1371 1376 hgicon.png favicon) will be served by the CGI script itself. Use
1372 1377 this setting to serve them directly with the HTTP server.
1373 1378 Example: ``http://hgserver/static/``.
1374 1379
1375 1380 ``stripes``
1376 1381 How many lines a "zebra stripe" should span in multiline output.
1377 1382 Default is 1; set to 0 to disable.
1378 1383
1379 1384 ``style``
1380 1385 Which template map style to use.
1381 1386
1382 1387 ``templates``
1383 1388 Where to find the HTML templates. Default is install path.
@@ -1,466 +1,469 b''
1 1 # posix.py - Posix utility function implementations for Mercurial
2 2 #
3 3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import os, sys, errno, stat, getpass, pwd, grp, tempfile, unicodedata
10 10
11 11 posixfile = open
12 12 nulldev = '/dev/null'
13 13 normpath = os.path.normpath
14 14 samestat = os.path.samestat
15 15 oslink = os.link
16 16 unlink = os.unlink
17 17 rename = os.rename
18 18 expandglobs = False
19 19
20 20 umask = os.umask(0)
21 21 os.umask(umask)
22 22
23 23 def openhardlinks():
24 24 '''return true if it is safe to hold open file handles to hardlinks'''
25 25 return True
26 26
27 27 def nlinks(name):
28 28 '''return number of hardlinks for the given file'''
29 29 return os.lstat(name).st_nlink
30 30
31 31 def parsepatchoutput(output_line):
32 32 """parses the output produced by patch and returns the filename"""
33 33 pf = output_line[14:]
34 34 if os.sys.platform == 'OpenVMS':
35 35 if pf[0] == '`':
36 36 pf = pf[1:-1] # Remove the quotes
37 37 else:
38 38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
39 39 pf = pf[1:-1] # Remove the quotes
40 40 return pf
41 41
42 42 def sshargs(sshcmd, host, user, port):
43 43 '''Build argument list for ssh'''
44 44 args = user and ("%s@%s" % (user, host)) or host
45 45 return port and ("%s -p %s" % (args, port)) or args
46 46
47 47 def isexec(f):
48 48 """check whether a file is executable"""
49 49 return (os.lstat(f).st_mode & 0100 != 0)
50 50
51 51 def setflags(f, l, x):
52 52 s = os.lstat(f).st_mode
53 53 if l:
54 54 if not stat.S_ISLNK(s):
55 55 # switch file to link
56 56 fp = open(f)
57 57 data = fp.read()
58 58 fp.close()
59 59 os.unlink(f)
60 60 try:
61 61 os.symlink(data, f)
62 62 except OSError:
63 63 # failed to make a link, rewrite file
64 64 fp = open(f, "w")
65 65 fp.write(data)
66 66 fp.close()
67 67 # no chmod needed at this point
68 68 return
69 69 if stat.S_ISLNK(s):
70 70 # switch link to file
71 71 data = os.readlink(f)
72 72 os.unlink(f)
73 73 fp = open(f, "w")
74 74 fp.write(data)
75 75 fp.close()
76 76 s = 0666 & ~umask # avoid restatting for chmod
77 77
78 78 sx = s & 0100
79 79 if x and not sx:
80 80 # Turn on +x for every +r bit when making a file executable
81 81 # and obey umask.
82 82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
83 83 elif not x and sx:
84 84 # Turn off all +x bits
85 85 os.chmod(f, s & 0666)
86 86
87 87 def copymode(src, dst, mode=None):
88 88 '''Copy the file mode from the file at path src to dst.
89 89 If src doesn't exist, we're using mode instead. If mode is None, we're
90 90 using umask.'''
91 91 try:
92 92 st_mode = os.lstat(src).st_mode & 0777
93 93 except OSError, inst:
94 94 if inst.errno != errno.ENOENT:
95 95 raise
96 96 st_mode = mode
97 97 if st_mode is None:
98 98 st_mode = ~umask
99 99 st_mode &= 0666
100 100 os.chmod(dst, st_mode)
101 101
102 102 def checkexec(path):
103 103 """
104 104 Check whether the given path is on a filesystem with UNIX-like exec flags
105 105
106 106 Requires a directory (like /foo/.hg)
107 107 """
108 108
109 109 # VFAT on some Linux versions can flip mode but it doesn't persist
110 110 # a FS remount. Frequently we can detect it if files are created
111 111 # with exec bit on.
112 112
113 113 try:
114 114 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
115 115 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
116 116 try:
117 117 os.close(fh)
118 118 m = os.stat(fn).st_mode & 0777
119 119 new_file_has_exec = m & EXECFLAGS
120 120 os.chmod(fn, m ^ EXECFLAGS)
121 121 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
122 122 finally:
123 123 os.unlink(fn)
124 124 except (IOError, OSError):
125 125 # we don't care, the user probably won't be able to commit anyway
126 126 return False
127 127 return not (new_file_has_exec or exec_flags_cannot_flip)
128 128
129 129 def checklink(path):
130 130 """check whether the given path is on a symlink-capable filesystem"""
131 131 # mktemp is not racy because symlink creation will fail if the
132 132 # file already exists
133 133 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
134 134 try:
135 135 os.symlink(".", name)
136 136 os.unlink(name)
137 137 return True
138 138 except (OSError, AttributeError):
139 139 return False
140 140
141 141 def checkosfilename(path):
142 142 '''Check that the base-relative path is a valid filename on this platform.
143 143 Returns None if the path is ok, or a UI string describing the problem.'''
144 144 pass # on posix platforms, every path is ok
145 145
146 146 def setbinary(fd):
147 147 pass
148 148
149 149 def pconvert(path):
150 150 return path
151 151
152 152 def localpath(path):
153 153 return path
154 154
155 155 def samefile(fpath1, fpath2):
156 156 """Returns whether path1 and path2 refer to the same file. This is only
157 157 guaranteed to work for files, not directories."""
158 158 return os.path.samefile(fpath1, fpath2)
159 159
160 160 def samedevice(fpath1, fpath2):
161 161 """Returns whether fpath1 and fpath2 are on the same device. This is only
162 162 guaranteed to work for files, not directories."""
163 163 st1 = os.lstat(fpath1)
164 164 st2 = os.lstat(fpath2)
165 165 return st1.st_dev == st2.st_dev
166 166
167 167 encodinglower = None
168 168 encodingupper = None
169 169
170 170 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
171 171 def normcase(path):
172 172 return path.lower()
173 173
174 174 if sys.platform == 'darwin':
175 175 import fcntl # only needed on darwin, missing on jython
176 176
177 177 def normcase(path):
178 178 try:
179 179 u = path.decode('utf-8')
180 180 except UnicodeDecodeError:
181 181 # percent-encode any characters that don't round-trip
182 182 p2 = path.decode('utf-8', 'ignore').encode('utf-8')
183 183 s = ""
184 184 pos = 0
185 185 for c in path:
186 186 if p2[pos:pos + 1] == c:
187 187 s += c
188 188 pos += 1
189 189 else:
190 190 s += "%%%02X" % ord(c)
191 191 u = s.decode('utf-8')
192 192
193 193 # Decompose then lowercase (HFS+ technote specifies lower)
194 194 return unicodedata.normalize('NFD', u).lower().encode('utf-8')
195 195
196 196 def realpath(path):
197 197 '''
198 198 Returns the true, canonical file system path equivalent to the given
199 199 path.
200 200
201 201 Equivalent means, in this case, resulting in the same, unique
202 202 file system link to the path. Every file system entry, whether a file,
203 203 directory, hard link or symbolic link or special, will have a single
204 204 path preferred by the system, but may allow multiple, differing path
205 205 lookups to point to it.
206 206
207 207 Most regular UNIX file systems only allow a file system entry to be
208 208 looked up by its distinct path. Obviously, this does not apply to case
209 209 insensitive file systems, whether case preserving or not. The most
210 210 complex issue to deal with is file systems transparently reencoding the
211 211 path, such as the non-standard Unicode normalisation required for HFS+
212 212 and HFSX.
213 213 '''
214 214 # Constants copied from /usr/include/sys/fcntl.h
215 215 F_GETPATH = 50
216 216 O_SYMLINK = 0x200000
217 217
218 218 try:
219 219 fd = os.open(path, O_SYMLINK)
220 220 except OSError, err:
221 221 if err.errno == errno.ENOENT:
222 222 return path
223 223 raise
224 224
225 225 try:
226 226 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
227 227 finally:
228 228 os.close(fd)
229 229 elif sys.version_info < (2, 4, 2, 'final'):
230 230 # Workaround for http://bugs.python.org/issue1213894 (os.path.realpath
231 231 # didn't resolve symlinks that were the first component of the path.)
232 232 def realpath(path):
233 233 if os.path.isabs(path):
234 234 return os.path.realpath(path)
235 235 else:
236 236 return os.path.realpath('./' + path)
237 237 else:
238 238 # Fallback to the likely inadequate Python builtin function.
239 239 realpath = os.path.realpath
240 240
241 241 if sys.platform == 'cygwin':
242 242 # workaround for cygwin, in which mount point part of path is
243 243 # treated as case sensitive, even though underlying NTFS is case
244 244 # insensitive.
245 245
246 246 # default mount points
247 247 cygwinmountpoints = sorted([
248 248 "/usr/bin",
249 249 "/usr/lib",
250 250 "/cygdrive",
251 251 ], reverse=True)
252 252
253 253 # use upper-ing as normcase as same as NTFS workaround
254 254 def normcase(path):
255 255 pathlen = len(path)
256 256 if (pathlen == 0) or (path[0] != os.sep):
257 257 # treat as relative
258 258 return encodingupper(path)
259 259
260 260 # to preserve case of mountpoint part
261 261 for mp in cygwinmountpoints:
262 262 if not path.startswith(mp):
263 263 continue
264 264
265 265 mplen = len(mp)
266 266 if mplen == pathlen: # mount point itself
267 267 return mp
268 268 if path[mplen] == os.sep:
269 269 return mp + encodingupper(path[mplen:])
270 270
271 271 return encodingupper(path)
272 272
273 273 # Cygwin translates native ACLs to POSIX permissions,
274 274 # but these translations are not supported by native
275 275 # tools, so the exec bit tends to be set erroneously.
276 276 # Therefore, disable executable bit access on Cygwin.
277 277 def checkexec(path):
278 278 return False
279 279
280 280 # Similarly, Cygwin's symlink emulation is likely to create
281 281 # problems when Mercurial is used from both Cygwin and native
282 282 # Windows, with other native tools, or on shared volumes
283 283 def checklink(path):
284 284 return False
285 285
286 286 def shellquote(s):
287 287 if os.sys.platform == 'OpenVMS':
288 288 return '"%s"' % s
289 289 else:
290 290 return "'%s'" % s.replace("'", "'\\''")
291 291
292 292 def quotecommand(cmd):
293 293 return cmd
294 294
295 295 def popen(command, mode='r'):
296 296 return os.popen(command, mode)
297 297
298 298 def testpid(pid):
299 299 '''return False if pid dead, True if running or not sure'''
300 300 if os.sys.platform == 'OpenVMS':
301 301 return True
302 302 try:
303 303 os.kill(pid, 0)
304 304 return True
305 305 except OSError, inst:
306 306 return inst.errno != errno.ESRCH
307 307
308 308 def explainexit(code):
309 309 """return a 2-tuple (desc, code) describing a subprocess status
310 310 (codes from kill are negative - not os.system/wait encoding)"""
311 311 if code >= 0:
312 312 return _("exited with status %d") % code, code
313 313 return _("killed by signal %d") % -code, -code
314 314
315 315 def isowner(st):
316 316 """Return True if the stat object st is from the current user."""
317 317 return st.st_uid == os.getuid()
318 318
319 319 def findexe(command):
320 320 '''Find executable for command searching like which does.
321 321 If command is a basename then PATH is searched for command.
322 322 PATH isn't searched if command is an absolute or relative path.
323 323 If command isn't found None is returned.'''
324 324 if sys.platform == 'OpenVMS':
325 325 return command
326 326
327 327 def findexisting(executable):
328 328 'Will return executable if existing file'
329 329 if os.path.isfile(executable) and os.access(executable, os.X_OK):
330 330 return executable
331 331 return None
332 332
333 333 if os.sep in command:
334 334 return findexisting(command)
335 335
336 if sys.platform == 'plan9':
337 return findexisting(os.path.join('/bin', command))
338
336 339 for path in os.environ.get('PATH', '').split(os.pathsep):
337 340 executable = findexisting(os.path.join(path, command))
338 341 if executable is not None:
339 342 return executable
340 343 return None
341 344
342 345 def setsignalhandler():
343 346 pass
344 347
345 348 def statfiles(files):
346 349 'Stat each file in files and yield stat or None if file does not exist.'
347 350 lstat = os.lstat
348 351 for nf in files:
349 352 try:
350 353 st = lstat(nf)
351 354 except OSError, err:
352 355 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
353 356 raise
354 357 st = None
355 358 yield st
356 359
357 360 def getuser():
358 361 '''return name of current user'''
359 362 return getpass.getuser()
360 363
361 364 def username(uid=None):
362 365 """Return the name of the user with the given uid.
363 366
364 367 If uid is None, return the name of the current user."""
365 368
366 369 if uid is None:
367 370 uid = os.getuid()
368 371 try:
369 372 return pwd.getpwuid(uid)[0]
370 373 except KeyError:
371 374 return str(uid)
372 375
373 376 def groupname(gid=None):
374 377 """Return the name of the group with the given gid.
375 378
376 379 If gid is None, return the name of the current group."""
377 380
378 381 if gid is None:
379 382 gid = os.getgid()
380 383 try:
381 384 return grp.getgrgid(gid)[0]
382 385 except KeyError:
383 386 return str(gid)
384 387
385 388 def groupmembers(name):
386 389 """Return the list of members of the group with the given
387 390 name, KeyError if the group does not exist.
388 391 """
389 392 return list(grp.getgrnam(name).gr_mem)
390 393
391 394 def spawndetached(args):
392 395 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
393 396 args[0], args)
394 397
395 398 def gethgcmd():
396 399 return sys.argv[:1]
397 400
398 401 def termwidth():
399 402 try:
400 403 import termios, array, fcntl
401 404 for dev in (sys.stderr, sys.stdout, sys.stdin):
402 405 try:
403 406 try:
404 407 fd = dev.fileno()
405 408 except AttributeError:
406 409 continue
407 410 if not os.isatty(fd):
408 411 continue
409 412 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
410 413 width = array.array('h', arri)[1]
411 414 if width > 0:
412 415 return width
413 416 except ValueError:
414 417 pass
415 418 except IOError, e:
416 419 if e[0] == errno.EINVAL:
417 420 pass
418 421 else:
419 422 raise
420 423 except ImportError:
421 424 pass
422 425 return 80
423 426
424 427 def makedir(path, notindexed):
425 428 os.mkdir(path)
426 429
427 430 def unlinkpath(f):
428 431 """unlink and remove the directory if it is empty"""
429 432 os.unlink(f)
430 433 # try removing directories that might now be empty
431 434 try:
432 435 os.removedirs(os.path.dirname(f))
433 436 except OSError:
434 437 pass
435 438
436 439 def lookupreg(key, name=None, scope=None):
437 440 return None
438 441
439 442 def hidewindow():
440 443 """Hide current shell window.
441 444
442 445 Used to hide the window opened when starting asynchronous
443 446 child process under Windows, unneeded on other systems.
444 447 """
445 448 pass
446 449
447 450 class cachestat(object):
448 451 def __init__(self, path):
449 452 self.stat = os.stat(path)
450 453
451 454 def cacheable(self):
452 455 return bool(self.stat.st_ino)
453 456
454 457 __hash__ = object.__hash__
455 458
456 459 def __eq__(self, other):
457 460 try:
458 461 return self.stat == other.stat
459 462 except AttributeError:
460 463 return False
461 464
462 465 def __ne__(self, other):
463 466 return not self == other
464 467
465 468 def executablepath():
466 469 return None # available on Windows only
@@ -1,859 +1,866 b''
1 1 # scmutil.py - Mercurial core utility functions
2 2 #
3 3 # Copyright Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import util, error, osutil, revset, similar, encoding
10 10 import match as matchmod
11 11 import os, errno, re, stat, sys, glob
12 12
13 13 def nochangesfound(ui, secretlist=None):
14 14 '''report no changes for push/pull'''
15 15 if secretlist:
16 16 ui.status(_("no changes found (ignored %d secret changesets)\n")
17 17 % len(secretlist))
18 18 else:
19 19 ui.status(_("no changes found\n"))
20 20
21 21 def checkfilename(f):
22 22 '''Check that the filename f is an acceptable filename for a tracked file'''
23 23 if '\r' in f or '\n' in f:
24 24 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
25 25
26 26 def checkportable(ui, f):
27 27 '''Check if filename f is portable and warn or abort depending on config'''
28 28 checkfilename(f)
29 29 abort, warn = checkportabilityalert(ui)
30 30 if abort or warn:
31 31 msg = util.checkwinfilename(f)
32 32 if msg:
33 33 msg = "%s: %r" % (msg, f)
34 34 if abort:
35 35 raise util.Abort(msg)
36 36 ui.warn(_("warning: %s\n") % msg)
37 37
38 38 def checkportabilityalert(ui):
39 39 '''check if the user's config requests nothing, a warning, or abort for
40 40 non-portable filenames'''
41 41 val = ui.config('ui', 'portablefilenames', 'warn')
42 42 lval = val.lower()
43 43 bval = util.parsebool(val)
44 44 abort = os.name == 'nt' or lval == 'abort'
45 45 warn = bval or lval == 'warn'
46 46 if bval is None and not (warn or abort or lval == 'ignore'):
47 47 raise error.ConfigError(
48 48 _("ui.portablefilenames value is invalid ('%s')") % val)
49 49 return abort, warn
50 50
51 51 class casecollisionauditor(object):
52 52 def __init__(self, ui, abort, existingiter):
53 53 self._ui = ui
54 54 self._abort = abort
55 55 self._map = {}
56 56 for f in existingiter:
57 57 self._map[encoding.lower(f)] = f
58 58
59 59 def __call__(self, f):
60 60 fl = encoding.lower(f)
61 61 map = self._map
62 62 if fl in map and map[fl] != f:
63 63 msg = _('possible case-folding collision for %s') % f
64 64 if self._abort:
65 65 raise util.Abort(msg)
66 66 self._ui.warn(_("warning: %s\n") % msg)
67 67 map[fl] = f
68 68
69 69 class pathauditor(object):
70 70 '''ensure that a filesystem path contains no banned components.
71 71 the following properties of a path are checked:
72 72
73 73 - ends with a directory separator
74 74 - under top-level .hg
75 75 - starts at the root of a windows drive
76 76 - contains ".."
77 77 - traverses a symlink (e.g. a/symlink_here/b)
78 78 - inside a nested repository (a callback can be used to approve
79 79 some nested repositories, e.g., subrepositories)
80 80 '''
81 81
82 82 def __init__(self, root, callback=None):
83 83 self.audited = set()
84 84 self.auditeddir = set()
85 85 self.root = root
86 86 self.callback = callback
87 87 if os.path.lexists(root) and not util.checkcase(root):
88 88 self.normcase = util.normcase
89 89 else:
90 90 self.normcase = lambda x: x
91 91
92 92 def __call__(self, path):
93 93 '''Check the relative path.
94 94 path may contain a pattern (e.g. foodir/**.txt)'''
95 95
96 96 path = util.localpath(path)
97 97 normpath = self.normcase(path)
98 98 if normpath in self.audited:
99 99 return
100 100 # AIX ignores "/" at end of path, others raise EISDIR.
101 101 if util.endswithsep(path):
102 102 raise util.Abort(_("path ends in directory separator: %s") % path)
103 103 parts = util.splitpath(path)
104 104 if (os.path.splitdrive(path)[0]
105 105 or parts[0].lower() in ('.hg', '.hg.', '')
106 106 or os.pardir in parts):
107 107 raise util.Abort(_("path contains illegal component: %s") % path)
108 108 if '.hg' in path.lower():
109 109 lparts = [p.lower() for p in parts]
110 110 for p in '.hg', '.hg.':
111 111 if p in lparts[1:]:
112 112 pos = lparts.index(p)
113 113 base = os.path.join(*parts[:pos])
114 114 raise util.Abort(_("path '%s' is inside nested repo %r")
115 115 % (path, base))
116 116
117 117 normparts = util.splitpath(normpath)
118 118 assert len(parts) == len(normparts)
119 119
120 120 parts.pop()
121 121 normparts.pop()
122 122 prefixes = []
123 123 while parts:
124 124 prefix = os.sep.join(parts)
125 125 normprefix = os.sep.join(normparts)
126 126 if normprefix in self.auditeddir:
127 127 break
128 128 curpath = os.path.join(self.root, prefix)
129 129 try:
130 130 st = os.lstat(curpath)
131 131 except OSError, err:
132 132 # EINVAL can be raised as invalid path syntax under win32.
133 133 # They must be ignored for patterns can be checked too.
134 134 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
135 135 raise
136 136 else:
137 137 if stat.S_ISLNK(st.st_mode):
138 138 raise util.Abort(
139 139 _('path %r traverses symbolic link %r')
140 140 % (path, prefix))
141 141 elif (stat.S_ISDIR(st.st_mode) and
142 142 os.path.isdir(os.path.join(curpath, '.hg'))):
143 143 if not self.callback or not self.callback(curpath):
144 144 raise util.Abort(_("path '%s' is inside nested repo %r") %
145 145 (path, prefix))
146 146 prefixes.append(normprefix)
147 147 parts.pop()
148 148 normparts.pop()
149 149
150 150 self.audited.add(normpath)
151 151 # only add prefixes to the cache after checking everything: we don't
152 152 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
153 153 self.auditeddir.update(prefixes)
154 154
155 155 class abstractopener(object):
156 156 """Abstract base class; cannot be instantiated"""
157 157
158 158 def __init__(self, *args, **kwargs):
159 159 '''Prevent instantiation; don't call this from subclasses.'''
160 160 raise NotImplementedError('attempted instantiating ' + str(type(self)))
161 161
162 162 def read(self, path):
163 163 fp = self(path, 'rb')
164 164 try:
165 165 return fp.read()
166 166 finally:
167 167 fp.close()
168 168
169 169 def write(self, path, data):
170 170 fp = self(path, 'wb')
171 171 try:
172 172 return fp.write(data)
173 173 finally:
174 174 fp.close()
175 175
176 176 def append(self, path, data):
177 177 fp = self(path, 'ab')
178 178 try:
179 179 return fp.write(data)
180 180 finally:
181 181 fp.close()
182 182
183 183 class opener(abstractopener):
184 184 '''Open files relative to a base directory
185 185
186 186 This class is used to hide the details of COW semantics and
187 187 remote file access from higher level code.
188 188 '''
189 189 def __init__(self, base, audit=True):
190 190 self.base = base
191 191 self._audit = audit
192 192 if audit:
193 193 self.auditor = pathauditor(base)
194 194 else:
195 195 self.auditor = util.always
196 196 self.createmode = None
197 197 self._trustnlink = None
198 198
199 199 @util.propertycache
200 200 def _cansymlink(self):
201 201 return util.checklink(self.base)
202 202
203 203 def _fixfilemode(self, name):
204 204 if self.createmode is None:
205 205 return
206 206 os.chmod(name, self.createmode & 0666)
207 207
208 208 def __call__(self, path, mode="r", text=False, atomictemp=False):
209 209 if self._audit:
210 210 r = util.checkosfilename(path)
211 211 if r:
212 212 raise util.Abort("%s: %r" % (r, path))
213 213 self.auditor(path)
214 214 f = self.join(path)
215 215
216 216 if not text and "b" not in mode:
217 217 mode += "b" # for that other OS
218 218
219 219 nlink = -1
220 220 dirname, basename = os.path.split(f)
221 221 # If basename is empty, then the path is malformed because it points
222 222 # to a directory. Let the posixfile() call below raise IOError.
223 223 if basename and mode not in ('r', 'rb'):
224 224 if atomictemp:
225 225 if not os.path.isdir(dirname):
226 226 util.makedirs(dirname, self.createmode)
227 227 return util.atomictempfile(f, mode, self.createmode)
228 228 try:
229 229 if 'w' in mode:
230 230 util.unlink(f)
231 231 nlink = 0
232 232 else:
233 233 # nlinks() may behave differently for files on Windows
234 234 # shares if the file is open.
235 235 fd = util.posixfile(f)
236 236 nlink = util.nlinks(f)
237 237 if nlink < 1:
238 238 nlink = 2 # force mktempcopy (issue1922)
239 239 fd.close()
240 240 except (OSError, IOError), e:
241 241 if e.errno != errno.ENOENT:
242 242 raise
243 243 nlink = 0
244 244 if not os.path.isdir(dirname):
245 245 util.makedirs(dirname, self.createmode)
246 246 if nlink > 0:
247 247 if self._trustnlink is None:
248 248 self._trustnlink = nlink > 1 or util.checknlink(f)
249 249 if nlink > 1 or not self._trustnlink:
250 250 util.rename(util.mktempcopy(f), f)
251 251 fp = util.posixfile(f, mode)
252 252 if nlink == 0:
253 253 self._fixfilemode(f)
254 254 return fp
255 255
256 256 def symlink(self, src, dst):
257 257 self.auditor(dst)
258 258 linkname = self.join(dst)
259 259 try:
260 260 os.unlink(linkname)
261 261 except OSError:
262 262 pass
263 263
264 264 dirname = os.path.dirname(linkname)
265 265 if not os.path.exists(dirname):
266 266 util.makedirs(dirname, self.createmode)
267 267
268 268 if self._cansymlink:
269 269 try:
270 270 os.symlink(src, linkname)
271 271 except OSError, err:
272 272 raise OSError(err.errno, _('could not symlink to %r: %s') %
273 273 (src, err.strerror), linkname)
274 274 else:
275 275 f = self(dst, "w")
276 276 f.write(src)
277 277 f.close()
278 278 self._fixfilemode(dst)
279 279
280 280 def audit(self, path):
281 281 self.auditor(path)
282 282
283 283 def join(self, path):
284 284 return os.path.join(self.base, path)
285 285
286 286 class filteropener(abstractopener):
287 287 '''Wrapper opener for filtering filenames with a function.'''
288 288
289 289 def __init__(self, opener, filter):
290 290 self._filter = filter
291 291 self._orig = opener
292 292
293 293 def __call__(self, path, *args, **kwargs):
294 294 return self._orig(self._filter(path), *args, **kwargs)
295 295
296 296 def canonpath(root, cwd, myname, auditor=None):
297 297 '''return the canonical path of myname, given cwd and root'''
298 298 if util.endswithsep(root):
299 299 rootsep = root
300 300 else:
301 301 rootsep = root + os.sep
302 302 name = myname
303 303 if not os.path.isabs(name):
304 304 name = os.path.join(root, cwd, name)
305 305 name = os.path.normpath(name)
306 306 if auditor is None:
307 307 auditor = pathauditor(root)
308 308 if name != rootsep and name.startswith(rootsep):
309 309 name = name[len(rootsep):]
310 310 auditor(name)
311 311 return util.pconvert(name)
312 312 elif name == root:
313 313 return ''
314 314 else:
315 315 # Determine whether `name' is in the hierarchy at or beneath `root',
316 316 # by iterating name=dirname(name) until that causes no change (can't
317 317 # check name == '/', because that doesn't work on windows). For each
318 318 # `name', compare dev/inode numbers. If they match, the list `rel'
319 319 # holds the reversed list of components making up the relative file
320 320 # name we want.
321 321 root_st = os.stat(root)
322 322 rel = []
323 323 while True:
324 324 try:
325 325 name_st = os.stat(name)
326 326 except OSError:
327 327 name_st = None
328 328 if name_st and util.samestat(name_st, root_st):
329 329 if not rel:
330 330 # name was actually the same as root (maybe a symlink)
331 331 return ''
332 332 rel.reverse()
333 333 name = os.path.join(*rel)
334 334 auditor(name)
335 335 return util.pconvert(name)
336 336 dirname, basename = os.path.split(name)
337 337 rel.append(basename)
338 338 if dirname == name:
339 339 break
340 340 name = dirname
341 341
342 342 raise util.Abort('%s not under root' % myname)
343 343
344 344 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
345 345 '''yield every hg repository under path, recursively.'''
346 346 def errhandler(err):
347 347 if err.filename == path:
348 348 raise err
349 349 samestat = getattr(os.path, 'samestat', None)
350 350 if followsym and samestat is not None:
351 351 def adddir(dirlst, dirname):
352 352 match = False
353 353 dirstat = os.stat(dirname)
354 354 for lstdirstat in dirlst:
355 355 if samestat(dirstat, lstdirstat):
356 356 match = True
357 357 break
358 358 if not match:
359 359 dirlst.append(dirstat)
360 360 return not match
361 361 else:
362 362 followsym = False
363 363
364 364 if (seen_dirs is None) and followsym:
365 365 seen_dirs = []
366 366 adddir(seen_dirs, path)
367 367 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
368 368 dirs.sort()
369 369 if '.hg' in dirs:
370 370 yield root # found a repository
371 371 qroot = os.path.join(root, '.hg', 'patches')
372 372 if os.path.isdir(os.path.join(qroot, '.hg')):
373 373 yield qroot # we have a patch queue repo here
374 374 if recurse:
375 375 # avoid recursing inside the .hg directory
376 376 dirs.remove('.hg')
377 377 else:
378 378 dirs[:] = [] # don't descend further
379 379 elif followsym:
380 380 newdirs = []
381 381 for d in dirs:
382 382 fname = os.path.join(root, d)
383 383 if adddir(seen_dirs, fname):
384 384 if os.path.islink(fname):
385 385 for hgname in walkrepos(fname, True, seen_dirs):
386 386 yield hgname
387 387 else:
388 388 newdirs.append(d)
389 389 dirs[:] = newdirs
390 390
391 391 def osrcpath():
392 392 '''return default os-specific hgrc search path'''
393 393 path = systemrcpath()
394 394 path.extend(userrcpath())
395 395 path = [os.path.normpath(f) for f in path]
396 396 return path
397 397
398 398 _rcpath = None
399 399
400 400 def rcpath():
401 401 '''return hgrc search path. if env var HGRCPATH is set, use it.
402 402 for each item in path, if directory, use files ending in .rc,
403 403 else use item.
404 404 make HGRCPATH empty to only look in .hg/hgrc of current repo.
405 405 if no HGRCPATH, use default os-specific path.'''
406 406 global _rcpath
407 407 if _rcpath is None:
408 408 if 'HGRCPATH' in os.environ:
409 409 _rcpath = []
410 410 for p in os.environ['HGRCPATH'].split(os.pathsep):
411 411 if not p:
412 412 continue
413 413 p = util.expandpath(p)
414 414 if os.path.isdir(p):
415 415 for f, kind in osutil.listdir(p):
416 416 if f.endswith('.rc'):
417 417 _rcpath.append(os.path.join(p, f))
418 418 else:
419 419 _rcpath.append(p)
420 420 else:
421 421 _rcpath = osrcpath()
422 422 return _rcpath
423 423
424 424 if os.name != 'nt':
425 425
426 426 def rcfiles(path):
427 427 rcs = [os.path.join(path, 'hgrc')]
428 428 rcdir = os.path.join(path, 'hgrc.d')
429 429 try:
430 430 rcs.extend([os.path.join(rcdir, f)
431 431 for f, kind in osutil.listdir(rcdir)
432 432 if f.endswith(".rc")])
433 433 except OSError:
434 434 pass
435 435 return rcs
436 436
437 437 def systemrcpath():
438 438 path = []
439 if sys.platform == 'plan9':
440 root = '/lib/mercurial'
441 else:
442 root = '/etc/mercurial'
439 443 # old mod_python does not set sys.argv
440 444 if len(getattr(sys, 'argv', [])) > 0:
441 445 p = os.path.dirname(os.path.dirname(sys.argv[0]))
442 path.extend(rcfiles(os.path.join(p, 'etc/mercurial')))
443 path.extend(rcfiles('/etc/mercurial'))
446 path.extend(rcfiles(os.path.join(p, root)))
447 path.extend(rcfiles(root))
444 448 return path
445 449
446 450 def userrcpath():
447 return [os.path.expanduser('~/.hgrc')]
451 if sys.platform == 'plan9':
452 return [os.environ['home'] + '/lib/hgrc']
453 else:
454 return [os.path.expanduser('~/.hgrc')]
448 455
449 456 else:
450 457
451 458 _HKEY_LOCAL_MACHINE = 0x80000002L
452 459
453 460 def systemrcpath():
454 461 '''return default os-specific hgrc search path'''
455 462 rcpath = []
456 463 filename = util.executablepath()
457 464 # Use mercurial.ini found in directory with hg.exe
458 465 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
459 466 if os.path.isfile(progrc):
460 467 rcpath.append(progrc)
461 468 return rcpath
462 469 # Use hgrc.d found in directory with hg.exe
463 470 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
464 471 if os.path.isdir(progrcd):
465 472 for f, kind in osutil.listdir(progrcd):
466 473 if f.endswith('.rc'):
467 474 rcpath.append(os.path.join(progrcd, f))
468 475 return rcpath
469 476 # else look for a system rcpath in the registry
470 477 value = util.lookupreg('SOFTWARE\\Mercurial', None,
471 478 _HKEY_LOCAL_MACHINE)
472 479 if not isinstance(value, str) or not value:
473 480 return rcpath
474 481 value = util.localpath(value)
475 482 for p in value.split(os.pathsep):
476 483 if p.lower().endswith('mercurial.ini'):
477 484 rcpath.append(p)
478 485 elif os.path.isdir(p):
479 486 for f, kind in osutil.listdir(p):
480 487 if f.endswith('.rc'):
481 488 rcpath.append(os.path.join(p, f))
482 489 return rcpath
483 490
484 491 def userrcpath():
485 492 '''return os-specific hgrc search path to the user dir'''
486 493 home = os.path.expanduser('~')
487 494 path = [os.path.join(home, 'mercurial.ini'),
488 495 os.path.join(home, '.hgrc')]
489 496 userprofile = os.environ.get('USERPROFILE')
490 497 if userprofile:
491 498 path.append(os.path.join(userprofile, 'mercurial.ini'))
492 499 path.append(os.path.join(userprofile, '.hgrc'))
493 500 return path
494 501
495 502 def revsingle(repo, revspec, default='.'):
496 503 if not revspec:
497 504 return repo[default]
498 505
499 506 l = revrange(repo, [revspec])
500 507 if len(l) < 1:
501 508 raise util.Abort(_('empty revision set'))
502 509 return repo[l[-1]]
503 510
504 511 def revpair(repo, revs):
505 512 if not revs:
506 513 return repo.dirstate.p1(), None
507 514
508 515 l = revrange(repo, revs)
509 516
510 517 if len(l) == 0:
511 518 return repo.dirstate.p1(), None
512 519
513 520 if len(l) == 1:
514 521 return repo.lookup(l[0]), None
515 522
516 523 return repo.lookup(l[0]), repo.lookup(l[-1])
517 524
518 525 _revrangesep = ':'
519 526
520 527 def revrange(repo, revs):
521 528 """Yield revision as strings from a list of revision specifications."""
522 529
523 530 def revfix(repo, val, defval):
524 531 if not val and val != 0 and defval is not None:
525 532 return defval
526 533 return repo[val].rev()
527 534
528 535 seen, l = set(), []
529 536 for spec in revs:
530 537 # attempt to parse old-style ranges first to deal with
531 538 # things like old-tag which contain query metacharacters
532 539 try:
533 540 if isinstance(spec, int):
534 541 seen.add(spec)
535 542 l.append(spec)
536 543 continue
537 544
538 545 if _revrangesep in spec:
539 546 start, end = spec.split(_revrangesep, 1)
540 547 start = revfix(repo, start, 0)
541 548 end = revfix(repo, end, len(repo) - 1)
542 549 step = start > end and -1 or 1
543 550 for rev in xrange(start, end + step, step):
544 551 if rev in seen:
545 552 continue
546 553 seen.add(rev)
547 554 l.append(rev)
548 555 continue
549 556 elif spec and spec in repo: # single unquoted rev
550 557 rev = revfix(repo, spec, None)
551 558 if rev in seen:
552 559 continue
553 560 seen.add(rev)
554 561 l.append(rev)
555 562 continue
556 563 except error.RepoLookupError:
557 564 pass
558 565
559 566 # fall through to new-style queries if old-style fails
560 567 m = revset.match(repo.ui, spec)
561 568 for r in m(repo, range(len(repo))):
562 569 if r not in seen:
563 570 l.append(r)
564 571 seen.update(l)
565 572
566 573 return l
567 574
568 575 def expandpats(pats):
569 576 if not util.expandglobs:
570 577 return list(pats)
571 578 ret = []
572 579 for p in pats:
573 580 kind, name = matchmod._patsplit(p, None)
574 581 if kind is None:
575 582 try:
576 583 globbed = glob.glob(name)
577 584 except re.error:
578 585 globbed = [name]
579 586 if globbed:
580 587 ret.extend(globbed)
581 588 continue
582 589 ret.append(p)
583 590 return ret
584 591
585 592 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
586 593 if pats == ("",):
587 594 pats = []
588 595 if not globbed and default == 'relpath':
589 596 pats = expandpats(pats or [])
590 597
591 598 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
592 599 default)
593 600 def badfn(f, msg):
594 601 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
595 602 m.bad = badfn
596 603 return m, pats
597 604
598 605 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
599 606 return matchandpats(ctx, pats, opts, globbed, default)[0]
600 607
601 608 def matchall(repo):
602 609 return matchmod.always(repo.root, repo.getcwd())
603 610
604 611 def matchfiles(repo, files):
605 612 return matchmod.exact(repo.root, repo.getcwd(), files)
606 613
607 614 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
608 615 if dry_run is None:
609 616 dry_run = opts.get('dry_run')
610 617 if similarity is None:
611 618 similarity = float(opts.get('similarity') or 0)
612 619 # we'd use status here, except handling of symlinks and ignore is tricky
613 620 added, unknown, deleted, removed = [], [], [], []
614 621 audit_path = pathauditor(repo.root)
615 622 m = match(repo[None], pats, opts)
616 623 rejected = []
617 624 m.bad = lambda x, y: rejected.append(x)
618 625
619 626 for abs in repo.walk(m):
620 627 target = repo.wjoin(abs)
621 628 good = True
622 629 try:
623 630 audit_path(abs)
624 631 except (OSError, util.Abort):
625 632 good = False
626 633 rel = m.rel(abs)
627 634 exact = m.exact(abs)
628 635 if good and abs not in repo.dirstate:
629 636 unknown.append(abs)
630 637 if repo.ui.verbose or not exact:
631 638 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
632 639 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
633 640 or (os.path.isdir(target) and not os.path.islink(target))):
634 641 deleted.append(abs)
635 642 if repo.ui.verbose or not exact:
636 643 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
637 644 # for finding renames
638 645 elif repo.dirstate[abs] == 'r':
639 646 removed.append(abs)
640 647 elif repo.dirstate[abs] == 'a':
641 648 added.append(abs)
642 649 copies = {}
643 650 if similarity > 0:
644 651 for old, new, score in similar.findrenames(repo,
645 652 added + unknown, removed + deleted, similarity):
646 653 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
647 654 repo.ui.status(_('recording removal of %s as rename to %s '
648 655 '(%d%% similar)\n') %
649 656 (m.rel(old), m.rel(new), score * 100))
650 657 copies[new] = old
651 658
652 659 if not dry_run:
653 660 wctx = repo[None]
654 661 wlock = repo.wlock()
655 662 try:
656 663 wctx.forget(deleted)
657 664 wctx.add(unknown)
658 665 for new, old in copies.iteritems():
659 666 wctx.copy(old, new)
660 667 finally:
661 668 wlock.release()
662 669
663 670 for f in rejected:
664 671 if f in m.files():
665 672 return 1
666 673 return 0
667 674
668 675 def updatedir(ui, repo, patches, similarity=0):
669 676 '''Update dirstate after patch application according to metadata'''
670 677 if not patches:
671 678 return []
672 679 copies = []
673 680 removes = set()
674 681 cfiles = patches.keys()
675 682 cwd = repo.getcwd()
676 683 if cwd:
677 684 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
678 685 for f in patches:
679 686 gp = patches[f]
680 687 if not gp:
681 688 continue
682 689 if gp.op == 'RENAME':
683 690 copies.append((gp.oldpath, gp.path))
684 691 removes.add(gp.oldpath)
685 692 elif gp.op == 'COPY':
686 693 copies.append((gp.oldpath, gp.path))
687 694 elif gp.op == 'DELETE':
688 695 removes.add(gp.path)
689 696
690 697 wctx = repo[None]
691 698 for src, dst in copies:
692 699 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
693 700 if (not similarity) and removes:
694 701 wctx.remove(sorted(removes), True)
695 702
696 703 for f in patches:
697 704 gp = patches[f]
698 705 if gp and gp.mode:
699 706 islink, isexec = gp.mode
700 707 dst = repo.wjoin(gp.path)
701 708 # patch won't create empty files
702 709 if gp.op == 'ADD' and not os.path.lexists(dst):
703 710 flags = (isexec and 'x' or '') + (islink and 'l' or '')
704 711 repo.wwrite(gp.path, '', flags)
705 712 util.setflags(dst, islink, isexec)
706 713 addremove(repo, cfiles, similarity=similarity)
707 714 files = patches.keys()
708 715 files.extend([r for r in removes if r not in files])
709 716 return sorted(files)
710 717
711 718 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
712 719 """Update the dirstate to reflect the intent of copying src to dst. For
713 720 different reasons it might not end with dst being marked as copied from src.
714 721 """
715 722 origsrc = repo.dirstate.copied(src) or src
716 723 if dst == origsrc: # copying back a copy?
717 724 if repo.dirstate[dst] not in 'mn' and not dryrun:
718 725 repo.dirstate.normallookup(dst)
719 726 else:
720 727 if repo.dirstate[origsrc] == 'a' and origsrc == src:
721 728 if not ui.quiet:
722 729 ui.warn(_("%s has not been committed yet, so no copy "
723 730 "data will be stored for %s.\n")
724 731 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
725 732 if repo.dirstate[dst] in '?r' and not dryrun:
726 733 wctx.add([dst])
727 734 elif not dryrun:
728 735 wctx.copy(origsrc, dst)
729 736
730 737 def readrequires(opener, supported):
731 738 '''Reads and parses .hg/requires and checks if all entries found
732 739 are in the list of supported features.'''
733 740 requirements = set(opener.read("requires").splitlines())
734 741 missings = []
735 742 for r in requirements:
736 743 if r not in supported:
737 744 if not r or not r[0].isalnum():
738 745 raise error.RequirementError(_(".hg/requires file is corrupt"))
739 746 missings.append(r)
740 747 missings.sort()
741 748 if missings:
742 749 raise error.RequirementError(_("unknown repository format: "
743 750 "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
744 751 return requirements
745 752
746 753 class filecacheentry(object):
747 754 def __init__(self, path):
748 755 self.path = path
749 756 self.cachestat = filecacheentry.stat(self.path)
750 757
751 758 if self.cachestat:
752 759 self._cacheable = self.cachestat.cacheable()
753 760 else:
754 761 # None means we don't know yet
755 762 self._cacheable = None
756 763
757 764 def refresh(self):
758 765 if self.cacheable():
759 766 self.cachestat = filecacheentry.stat(self.path)
760 767
761 768 def cacheable(self):
762 769 if self._cacheable is not None:
763 770 return self._cacheable
764 771
765 772 # we don't know yet, assume it is for now
766 773 return True
767 774
768 775 def changed(self):
769 776 # no point in going further if we can't cache it
770 777 if not self.cacheable():
771 778 return True
772 779
773 780 newstat = filecacheentry.stat(self.path)
774 781
775 782 # we may not know if it's cacheable yet, check again now
776 783 if newstat and self._cacheable is None:
777 784 self._cacheable = newstat.cacheable()
778 785
779 786 # check again
780 787 if not self._cacheable:
781 788 return True
782 789
783 790 if self.cachestat != newstat:
784 791 self.cachestat = newstat
785 792 return True
786 793 else:
787 794 return False
788 795
789 796 @staticmethod
790 797 def stat(path):
791 798 try:
792 799 return util.cachestat(path)
793 800 except OSError, e:
794 801 if e.errno != errno.ENOENT:
795 802 raise
796 803
797 804 class filecache(object):
798 805 '''A property like decorator that tracks a file under .hg/ for updates.
799 806
800 807 Records stat info when called in _filecache.
801 808
802 809 On subsequent calls, compares old stat info with new info, and recreates
803 810 the object when needed, updating the new stat info in _filecache.
804 811
805 812 Mercurial either atomic renames or appends for files under .hg,
806 813 so to ensure the cache is reliable we need the filesystem to be able
807 814 to tell us if a file has been replaced. If it can't, we fallback to
808 815 recreating the object on every call (essentially the same behaviour as
809 816 propertycache).'''
810 817 def __init__(self, path):
811 818 self.path = path
812 819
813 820 def join(self, obj, fname):
814 821 """Used to compute the runtime path of the cached file.
815 822
816 823 Users should subclass filecache and provide their own version of this
817 824 function to call the appropriate join function on 'obj' (an instance
818 825 of the class that its member function was decorated).
819 826 """
820 827 return obj.join(fname)
821 828
822 829 def __call__(self, func):
823 830 self.func = func
824 831 self.name = func.__name__
825 832 return self
826 833
827 834 def __get__(self, obj, type=None):
828 835 # do we need to check if the file changed?
829 836 if self.name in obj.__dict__:
830 837 return obj.__dict__[self.name]
831 838
832 839 entry = obj._filecache.get(self.name)
833 840
834 841 if entry:
835 842 if entry.changed():
836 843 entry.obj = self.func(obj)
837 844 else:
838 845 path = self.join(obj, self.path)
839 846
840 847 # We stat -before- creating the object so our cache doesn't lie if
841 848 # a writer modified between the time we read and stat
842 849 entry = filecacheentry(path)
843 850 entry.obj = self.func(obj)
844 851
845 852 obj._filecache[self.name] = entry
846 853
847 854 obj.__dict__[self.name] = entry.obj
848 855 return entry.obj
849 856
850 857 def __set__(self, obj, value):
851 858 if self.name in obj._filecache:
852 859 obj._filecache[self.name].obj = value # update cached copy
853 860 obj.__dict__[self.name] = value # update copy returned by obj.x
854 861
855 862 def __delete__(self, obj):
856 863 try:
857 864 del obj.__dict__[self.name]
858 865 except KeyError:
859 866 raise AttributeError, self.name
@@ -1,746 +1,753 b''
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from i18n import _
9 9 import errno, getpass, os, socket, sys, tempfile, traceback
10 10 import config, scmutil, util, error, formatter
11 11
12 12 class ui(object):
13 13 def __init__(self, src=None):
14 14 self._buffers = []
15 15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 16 self._reportuntrusted = True
17 17 self._ocfg = config.config() # overlay
18 18 self._tcfg = config.config() # trusted
19 19 self._ucfg = config.config() # untrusted
20 20 self._trustusers = set()
21 21 self._trustgroups = set()
22 22
23 23 if src:
24 24 self.fout = src.fout
25 25 self.ferr = src.ferr
26 26 self.fin = src.fin
27 27
28 28 self._tcfg = src._tcfg.copy()
29 29 self._ucfg = src._ucfg.copy()
30 30 self._ocfg = src._ocfg.copy()
31 31 self._trustusers = src._trustusers.copy()
32 32 self._trustgroups = src._trustgroups.copy()
33 33 self.environ = src.environ
34 34 self.fixconfig()
35 35 else:
36 36 self.fout = sys.stdout
37 37 self.ferr = sys.stderr
38 38 self.fin = sys.stdin
39 39
40 40 # shared read-only environment
41 41 self.environ = os.environ
42 42 # we always trust global config files
43 43 for f in scmutil.rcpath():
44 44 self.readconfig(f, trust=True)
45 45
46 46 def copy(self):
47 47 return self.__class__(self)
48 48
49 49 def formatter(self, topic, opts):
50 50 return formatter.formatter(self, topic, opts)
51 51
52 52 def _trusted(self, fp, f):
53 53 st = util.fstat(fp)
54 54 if util.isowner(st):
55 55 return True
56 56
57 57 tusers, tgroups = self._trustusers, self._trustgroups
58 58 if '*' in tusers or '*' in tgroups:
59 59 return True
60 60
61 61 user = util.username(st.st_uid)
62 62 group = util.groupname(st.st_gid)
63 63 if user in tusers or group in tgroups or user == util.username():
64 64 return True
65 65
66 66 if self._reportuntrusted:
67 67 self.warn(_('Not trusting file %s from untrusted '
68 68 'user %s, group %s\n') % (f, user, group))
69 69 return False
70 70
71 71 def readconfig(self, filename, root=None, trust=False,
72 72 sections=None, remap=None):
73 73 try:
74 74 fp = open(filename)
75 75 except IOError:
76 76 if not sections: # ignore unless we were looking for something
77 77 return
78 78 raise
79 79
80 80 cfg = config.config()
81 81 trusted = sections or trust or self._trusted(fp, filename)
82 82
83 83 try:
84 84 cfg.read(filename, fp, sections=sections, remap=remap)
85 85 fp.close()
86 86 except error.ConfigError, inst:
87 87 if trusted:
88 88 raise
89 89 self.warn(_("Ignored: %s\n") % str(inst))
90 90
91 91 if self.plain():
92 92 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
93 93 'logtemplate', 'style',
94 94 'traceback', 'verbose'):
95 95 if k in cfg['ui']:
96 96 del cfg['ui'][k]
97 97 for k, v in cfg.items('defaults'):
98 98 del cfg['defaults'][k]
99 99 # Don't remove aliases from the configuration if in the exceptionlist
100 100 if self.plain('alias'):
101 101 for k, v in cfg.items('alias'):
102 102 del cfg['alias'][k]
103 103
104 104 if trusted:
105 105 self._tcfg.update(cfg)
106 106 self._tcfg.update(self._ocfg)
107 107 self._ucfg.update(cfg)
108 108 self._ucfg.update(self._ocfg)
109 109
110 110 if root is None:
111 111 root = os.path.expanduser('~')
112 112 self.fixconfig(root=root)
113 113
114 114 def fixconfig(self, root=None, section=None):
115 115 if section in (None, 'paths'):
116 116 # expand vars and ~
117 117 # translate paths relative to root (or home) into absolute paths
118 118 root = root or os.getcwd()
119 119 for c in self._tcfg, self._ucfg, self._ocfg:
120 120 for n, p in c.items('paths'):
121 121 if not p:
122 122 continue
123 123 if '%%' in p:
124 124 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
125 125 % (n, p, self.configsource('paths', n)))
126 126 p = p.replace('%%', '%')
127 127 p = util.expandpath(p)
128 128 if not util.hasscheme(p) and not os.path.isabs(p):
129 129 p = os.path.normpath(os.path.join(root, p))
130 130 c.set("paths", n, p)
131 131
132 132 if section in (None, 'ui'):
133 133 # update ui options
134 134 self.debugflag = self.configbool('ui', 'debug')
135 135 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
136 136 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
137 137 if self.verbose and self.quiet:
138 138 self.quiet = self.verbose = False
139 139 self._reportuntrusted = self.debugflag or self.configbool("ui",
140 140 "report_untrusted", True)
141 141 self.tracebackflag = self.configbool('ui', 'traceback', False)
142 142
143 143 if section in (None, 'trusted'):
144 144 # update trust information
145 145 self._trustusers.update(self.configlist('trusted', 'users'))
146 146 self._trustgroups.update(self.configlist('trusted', 'groups'))
147 147
148 148 def backupconfig(self, section, item):
149 149 return (self._ocfg.backup(section, item),
150 150 self._tcfg.backup(section, item),
151 151 self._ucfg.backup(section, item),)
152 152 def restoreconfig(self, data):
153 153 self._ocfg.restore(data[0])
154 154 self._tcfg.restore(data[1])
155 155 self._ucfg.restore(data[2])
156 156
157 157 def setconfig(self, section, name, value, overlay=True):
158 158 if overlay:
159 159 self._ocfg.set(section, name, value)
160 160 self._tcfg.set(section, name, value)
161 161 self._ucfg.set(section, name, value)
162 162 self.fixconfig(section=section)
163 163
164 164 def _data(self, untrusted):
165 165 return untrusted and self._ucfg or self._tcfg
166 166
167 167 def configsource(self, section, name, untrusted=False):
168 168 return self._data(untrusted).source(section, name) or 'none'
169 169
170 170 def config(self, section, name, default=None, untrusted=False):
171 171 if isinstance(name, list):
172 172 alternates = name
173 173 else:
174 174 alternates = [name]
175 175
176 176 for n in alternates:
177 177 value = self._data(untrusted).get(section, name, None)
178 178 if value is not None:
179 179 name = n
180 180 break
181 181 else:
182 182 value = default
183 183
184 184 if self.debugflag and not untrusted and self._reportuntrusted:
185 185 uvalue = self._ucfg.get(section, name)
186 186 if uvalue is not None and uvalue != value:
187 187 self.debug("ignoring untrusted configuration option "
188 188 "%s.%s = %s\n" % (section, name, uvalue))
189 189 return value
190 190
191 191 def configpath(self, section, name, default=None, untrusted=False):
192 192 'get a path config item, expanded relative to repo root or config file'
193 193 v = self.config(section, name, default, untrusted)
194 194 if v is None:
195 195 return None
196 196 if not os.path.isabs(v) or "://" not in v:
197 197 src = self.configsource(section, name, untrusted)
198 198 if ':' in src:
199 199 base = os.path.dirname(src.rsplit(':')[0])
200 200 v = os.path.join(base, os.path.expanduser(v))
201 201 return v
202 202
203 203 def configbool(self, section, name, default=False, untrusted=False):
204 204 """parse a configuration element as a boolean
205 205
206 206 >>> u = ui(); s = 'foo'
207 207 >>> u.setconfig(s, 'true', 'yes')
208 208 >>> u.configbool(s, 'true')
209 209 True
210 210 >>> u.setconfig(s, 'false', 'no')
211 211 >>> u.configbool(s, 'false')
212 212 False
213 213 >>> u.configbool(s, 'unknown')
214 214 False
215 215 >>> u.configbool(s, 'unknown', True)
216 216 True
217 217 >>> u.setconfig(s, 'invalid', 'somevalue')
218 218 >>> u.configbool(s, 'invalid')
219 219 Traceback (most recent call last):
220 220 ...
221 221 ConfigError: foo.invalid is not a boolean ('somevalue')
222 222 """
223 223
224 224 v = self.config(section, name, None, untrusted)
225 225 if v is None:
226 226 return default
227 227 if isinstance(v, bool):
228 228 return v
229 229 b = util.parsebool(v)
230 230 if b is None:
231 231 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
232 232 % (section, name, v))
233 233 return b
234 234
235 235 def configint(self, section, name, default=None, untrusted=False):
236 236 """parse a configuration element as an integer
237 237
238 238 >>> u = ui(); s = 'foo'
239 239 >>> u.setconfig(s, 'int1', '42')
240 240 >>> u.configint(s, 'int1')
241 241 42
242 242 >>> u.setconfig(s, 'int2', '-42')
243 243 >>> u.configint(s, 'int2')
244 244 -42
245 245 >>> u.configint(s, 'unknown', 7)
246 246 7
247 247 >>> u.setconfig(s, 'invalid', 'somevalue')
248 248 >>> u.configint(s, 'invalid')
249 249 Traceback (most recent call last):
250 250 ...
251 251 ConfigError: foo.invalid is not an integer ('somevalue')
252 252 """
253 253
254 254 v = self.config(section, name, None, untrusted)
255 255 if v is None:
256 256 return default
257 257 try:
258 258 return int(v)
259 259 except ValueError:
260 260 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
261 261 % (section, name, v))
262 262
263 263 def configlist(self, section, name, default=None, untrusted=False):
264 264 """parse a configuration element as a list of comma/space separated
265 265 strings
266 266
267 267 >>> u = ui(); s = 'foo'
268 268 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
269 269 >>> u.configlist(s, 'list1')
270 270 ['this', 'is', 'a small', 'test']
271 271 """
272 272
273 273 def _parse_plain(parts, s, offset):
274 274 whitespace = False
275 275 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
276 276 whitespace = True
277 277 offset += 1
278 278 if offset >= len(s):
279 279 return None, parts, offset
280 280 if whitespace:
281 281 parts.append('')
282 282 if s[offset] == '"' and not parts[-1]:
283 283 return _parse_quote, parts, offset + 1
284 284 elif s[offset] == '"' and parts[-1][-1] == '\\':
285 285 parts[-1] = parts[-1][:-1] + s[offset]
286 286 return _parse_plain, parts, offset + 1
287 287 parts[-1] += s[offset]
288 288 return _parse_plain, parts, offset + 1
289 289
290 290 def _parse_quote(parts, s, offset):
291 291 if offset < len(s) and s[offset] == '"': # ""
292 292 parts.append('')
293 293 offset += 1
294 294 while offset < len(s) and (s[offset].isspace() or
295 295 s[offset] == ','):
296 296 offset += 1
297 297 return _parse_plain, parts, offset
298 298
299 299 while offset < len(s) and s[offset] != '"':
300 300 if (s[offset] == '\\' and offset + 1 < len(s)
301 301 and s[offset + 1] == '"'):
302 302 offset += 1
303 303 parts[-1] += '"'
304 304 else:
305 305 parts[-1] += s[offset]
306 306 offset += 1
307 307
308 308 if offset >= len(s):
309 309 real_parts = _configlist(parts[-1])
310 310 if not real_parts:
311 311 parts[-1] = '"'
312 312 else:
313 313 real_parts[0] = '"' + real_parts[0]
314 314 parts = parts[:-1]
315 315 parts.extend(real_parts)
316 316 return None, parts, offset
317 317
318 318 offset += 1
319 319 while offset < len(s) and s[offset] in [' ', ',']:
320 320 offset += 1
321 321
322 322 if offset < len(s):
323 323 if offset + 1 == len(s) and s[offset] == '"':
324 324 parts[-1] += '"'
325 325 offset += 1
326 326 else:
327 327 parts.append('')
328 328 else:
329 329 return None, parts, offset
330 330
331 331 return _parse_plain, parts, offset
332 332
333 333 def _configlist(s):
334 334 s = s.rstrip(' ,')
335 335 if not s:
336 336 return []
337 337 parser, parts, offset = _parse_plain, [''], 0
338 338 while parser:
339 339 parser, parts, offset = parser(parts, s, offset)
340 340 return parts
341 341
342 342 result = self.config(section, name, untrusted=untrusted)
343 343 if result is None:
344 344 result = default or []
345 345 if isinstance(result, basestring):
346 346 result = _configlist(result.lstrip(' ,\n'))
347 347 if result is None:
348 348 result = default or []
349 349 return result
350 350
351 351 def has_section(self, section, untrusted=False):
352 352 '''tell whether section exists in config.'''
353 353 return section in self._data(untrusted)
354 354
355 355 def configitems(self, section, untrusted=False):
356 356 items = self._data(untrusted).items(section)
357 357 if self.debugflag and not untrusted and self._reportuntrusted:
358 358 for k, v in self._ucfg.items(section):
359 359 if self._tcfg.get(section, k) != v:
360 360 self.debug("ignoring untrusted configuration option "
361 361 "%s.%s = %s\n" % (section, k, v))
362 362 return items
363 363
364 364 def walkconfig(self, untrusted=False):
365 365 cfg = self._data(untrusted)
366 366 for section in cfg.sections():
367 367 for name, value in self.configitems(section, untrusted):
368 368 yield section, name, value
369 369
370 370 def plain(self, feature=None):
371 371 '''is plain mode active?
372 372
373 373 Plain mode means that all configuration variables which affect
374 374 the behavior and output of Mercurial should be
375 375 ignored. Additionally, the output should be stable,
376 376 reproducible and suitable for use in scripts or applications.
377 377
378 378 The only way to trigger plain mode is by setting either the
379 379 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
380 380
381 381 The return value can either be
382 382 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
383 383 - True otherwise
384 384 '''
385 385 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
386 386 return False
387 387 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
388 388 if feature and exceptions:
389 389 return feature not in exceptions
390 390 return True
391 391
392 392 def username(self):
393 393 """Return default username to be used in commits.
394 394
395 395 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
396 396 and stop searching if one of these is set.
397 397 If not found and ui.askusername is True, ask the user, else use
398 398 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
399 399 """
400 400 user = os.environ.get("HGUSER")
401 401 if user is None:
402 402 user = self.config("ui", "username")
403 403 if user is not None:
404 404 user = os.path.expandvars(user)
405 405 if user is None:
406 406 user = os.environ.get("EMAIL")
407 407 if user is None and self.configbool("ui", "askusername"):
408 408 user = self.prompt(_("enter a commit username:"), default=None)
409 409 if user is None and not self.interactive():
410 410 try:
411 411 user = '%s@%s' % (util.getuser(), socket.getfqdn())
412 412 self.warn(_("No username found, using '%s' instead\n") % user)
413 413 except KeyError:
414 414 pass
415 415 if not user:
416 416 raise util.Abort(_('no username supplied (see "hg help config")'))
417 417 if "\n" in user:
418 418 raise util.Abort(_("username %s contains a newline\n") % repr(user))
419 419 return user
420 420
421 421 def shortuser(self, user):
422 422 """Return a short representation of a user name or email address."""
423 423 if not self.verbose:
424 424 user = util.shortuser(user)
425 425 return user
426 426
427 427 def expandpath(self, loc, default=None):
428 428 """Return repository location relative to cwd or from [paths]"""
429 429 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
430 430 return loc
431 431
432 432 path = self.config('paths', loc)
433 433 if not path and default is not None:
434 434 path = self.config('paths', default)
435 435 return path or loc
436 436
437 437 def pushbuffer(self):
438 438 self._buffers.append([])
439 439
440 440 def popbuffer(self, labeled=False):
441 441 '''pop the last buffer and return the buffered output
442 442
443 443 If labeled is True, any labels associated with buffered
444 444 output will be handled. By default, this has no effect
445 445 on the output returned, but extensions and GUI tools may
446 446 handle this argument and returned styled output. If output
447 447 is being buffered so it can be captured and parsed or
448 448 processed, labeled should not be set to True.
449 449 '''
450 450 return "".join(self._buffers.pop())
451 451
452 452 def write(self, *args, **opts):
453 453 '''write args to output
454 454
455 455 By default, this method simply writes to the buffer or stdout,
456 456 but extensions or GUI tools may override this method,
457 457 write_err(), popbuffer(), and label() to style output from
458 458 various parts of hg.
459 459
460 460 An optional keyword argument, "label", can be passed in.
461 461 This should be a string containing label names separated by
462 462 space. Label names take the form of "topic.type". For example,
463 463 ui.debug() issues a label of "ui.debug".
464 464
465 465 When labeling output for a specific command, a label of
466 466 "cmdname.type" is recommended. For example, status issues
467 467 a label of "status.modified" for modified files.
468 468 '''
469 469 if self._buffers:
470 470 self._buffers[-1].extend([str(a) for a in args])
471 471 else:
472 472 for a in args:
473 473 self.fout.write(str(a))
474 474
475 475 def write_err(self, *args, **opts):
476 476 try:
477 477 if not getattr(self.fout, 'closed', False):
478 478 self.fout.flush()
479 479 for a in args:
480 480 self.ferr.write(str(a))
481 481 # stderr may be buffered under win32 when redirected to files,
482 482 # including stdout.
483 483 if not getattr(self.ferr, 'closed', False):
484 484 self.ferr.flush()
485 485 except IOError, inst:
486 486 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
487 487 raise
488 488
489 489 def flush(self):
490 490 try: self.fout.flush()
491 491 except: pass
492 492 try: self.ferr.flush()
493 493 except: pass
494 494
495 495 def interactive(self):
496 496 '''is interactive input allowed?
497 497
498 498 An interactive session is a session where input can be reasonably read
499 499 from `sys.stdin'. If this function returns false, any attempt to read
500 500 from stdin should fail with an error, unless a sensible default has been
501 501 specified.
502 502
503 503 Interactiveness is triggered by the value of the `ui.interactive'
504 504 configuration variable or - if it is unset - when `sys.stdin' points
505 505 to a terminal device.
506 506
507 507 This function refers to input only; for output, see `ui.formatted()'.
508 508 '''
509 509 i = self.configbool("ui", "interactive", None)
510 510 if i is None:
511 511 # some environments replace stdin without implementing isatty
512 512 # usually those are non-interactive
513 513 return util.isatty(self.fin)
514 514
515 515 return i
516 516
517 517 def termwidth(self):
518 518 '''how wide is the terminal in columns?
519 519 '''
520 520 if 'COLUMNS' in os.environ:
521 521 try:
522 522 return int(os.environ['COLUMNS'])
523 523 except ValueError:
524 524 pass
525 525 return util.termwidth()
526 526
527 527 def formatted(self):
528 528 '''should formatted output be used?
529 529
530 530 It is often desirable to format the output to suite the output medium.
531 531 Examples of this are truncating long lines or colorizing messages.
532 532 However, this is not often not desirable when piping output into other
533 533 utilities, e.g. `grep'.
534 534
535 535 Formatted output is triggered by the value of the `ui.formatted'
536 536 configuration variable or - if it is unset - when `sys.stdout' points
537 537 to a terminal device. Please note that `ui.formatted' should be
538 538 considered an implementation detail; it is not intended for use outside
539 539 Mercurial or its extensions.
540 540
541 541 This function refers to output only; for input, see `ui.interactive()'.
542 542 This function always returns false when in plain mode, see `ui.plain()'.
543 543 '''
544 544 if self.plain():
545 545 return False
546 546
547 547 i = self.configbool("ui", "formatted", None)
548 548 if i is None:
549 549 # some environments replace stdout without implementing isatty
550 550 # usually those are non-interactive
551 551 return util.isatty(self.fout)
552 552
553 553 return i
554 554
555 555 def _readline(self, prompt=''):
556 556 if util.isatty(self.fin):
557 557 try:
558 558 # magically add command line editing support, where
559 559 # available
560 560 import readline
561 561 # force demandimport to really load the module
562 562 readline.read_history_file
563 563 # windows sometimes raises something other than ImportError
564 564 except Exception:
565 565 pass
566 566
567 567 # call write() so output goes through subclassed implementation
568 568 # e.g. color extension on Windows
569 569 self.write(prompt)
570 570
571 571 # instead of trying to emulate raw_input, swap (self.fin,
572 572 # self.fout) with (sys.stdin, sys.stdout)
573 573 oldin = sys.stdin
574 574 oldout = sys.stdout
575 575 sys.stdin = self.fin
576 576 sys.stdout = self.fout
577 577 line = raw_input(' ')
578 578 sys.stdin = oldin
579 579 sys.stdout = oldout
580 580
581 581 # When stdin is in binary mode on Windows, it can cause
582 582 # raw_input() to emit an extra trailing carriage return
583 583 if os.linesep == '\r\n' and line and line[-1] == '\r':
584 584 line = line[:-1]
585 585 return line
586 586
587 587 def prompt(self, msg, default="y"):
588 588 """Prompt user with msg, read response.
589 589 If ui is not interactive, the default is returned.
590 590 """
591 591 if not self.interactive():
592 592 self.write(msg, ' ', default, "\n")
593 593 return default
594 594 try:
595 595 r = self._readline(self.label(msg, 'ui.prompt'))
596 596 if not r:
597 597 return default
598 598 return r
599 599 except EOFError:
600 600 raise util.Abort(_('response expected'))
601 601
602 602 def promptchoice(self, msg, choices, default=0):
603 603 """Prompt user with msg, read response, and ensure it matches
604 604 one of the provided choices. The index of the choice is returned.
605 605 choices is a sequence of acceptable responses with the format:
606 606 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
607 607 If ui is not interactive, the default is returned.
608 608 """
609 609 resps = [s[s.index('&')+1].lower() for s in choices]
610 610 while True:
611 611 r = self.prompt(msg, resps[default])
612 612 if r.lower() in resps:
613 613 return resps.index(r.lower())
614 614 self.write(_("unrecognized response\n"))
615 615
616 616 def getpass(self, prompt=None, default=None):
617 617 if not self.interactive():
618 618 return default
619 619 try:
620 620 return getpass.getpass(prompt or _('password: '))
621 621 except EOFError:
622 622 raise util.Abort(_('response expected'))
623 623 def status(self, *msg, **opts):
624 624 '''write status message to output (if ui.quiet is False)
625 625
626 626 This adds an output label of "ui.status".
627 627 '''
628 628 if not self.quiet:
629 629 opts['label'] = opts.get('label', '') + ' ui.status'
630 630 self.write(*msg, **opts)
631 631 def warn(self, *msg, **opts):
632 632 '''write warning message to output (stderr)
633 633
634 634 This adds an output label of "ui.warning".
635 635 '''
636 636 opts['label'] = opts.get('label', '') + ' ui.warning'
637 637 self.write_err(*msg, **opts)
638 638 def note(self, *msg, **opts):
639 639 '''write note to output (if ui.verbose is True)
640 640
641 641 This adds an output label of "ui.note".
642 642 '''
643 643 if self.verbose:
644 644 opts['label'] = opts.get('label', '') + ' ui.note'
645 645 self.write(*msg, **opts)
646 646 def debug(self, *msg, **opts):
647 647 '''write debug message to output (if ui.debugflag is True)
648 648
649 649 This adds an output label of "ui.debug".
650 650 '''
651 651 if self.debugflag:
652 652 opts['label'] = opts.get('label', '') + ' ui.debug'
653 653 self.write(*msg, **opts)
654 654 def edit(self, text, user):
655 655 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
656 656 text=True)
657 657 try:
658 658 f = os.fdopen(fd, "w")
659 659 f.write(text)
660 660 f.close()
661 661
662 662 editor = self.geteditor()
663 663
664 664 util.system("%s \"%s\"" % (editor, name),
665 665 environ={'HGUSER': user},
666 666 onerr=util.Abort, errprefix=_("edit failed"),
667 667 out=self.fout)
668 668
669 669 f = open(name)
670 670 t = f.read()
671 671 f.close()
672 672 finally:
673 673 os.unlink(name)
674 674
675 675 return t
676 676
677 677 def traceback(self, exc=None):
678 678 '''print exception traceback if traceback printing enabled.
679 679 only to call in exception handler. returns true if traceback
680 680 printed.'''
681 681 if self.tracebackflag:
682 682 if exc:
683 683 traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
684 684 else:
685 685 traceback.print_exc(file=self.ferr)
686 686 return self.tracebackflag
687 687
688 688 def geteditor(self):
689 689 '''return editor to use'''
690 if sys.platform == 'plan9':
691 # vi is the MIPS instruction simulator on Plan 9. We
692 # instead default to E to plumb commit messages to
693 # avoid confusion.
694 editor = 'E'
695 else:
696 editor = 'vi'
690 697 return (os.environ.get("HGEDITOR") or
691 698 self.config("ui", "editor") or
692 699 os.environ.get("VISUAL") or
693 os.environ.get("EDITOR", "vi"))
700 os.environ.get("EDITOR", editor))
694 701
695 702 def progress(self, topic, pos, item="", unit="", total=None):
696 703 '''show a progress message
697 704
698 705 With stock hg, this is simply a debug message that is hidden
699 706 by default, but with extensions or GUI tools it may be
700 707 visible. 'topic' is the current operation, 'item' is a
701 708 non-numeric marker of the current position (ie the currently
702 709 in-process file), 'pos' is the current numeric position (ie
703 710 revision, bytes, etc.), unit is a corresponding unit label,
704 711 and total is the highest expected pos.
705 712
706 713 Multiple nested topics may be active at a time.
707 714
708 715 All topics should be marked closed by setting pos to None at
709 716 termination.
710 717 '''
711 718
712 719 if pos is None or not self.debugflag:
713 720 return
714 721
715 722 if unit:
716 723 unit = ' ' + unit
717 724 if item:
718 725 item = ' ' + item
719 726
720 727 if total:
721 728 pct = 100.0 * pos / total
722 729 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
723 730 % (topic, item, pos, total, unit, pct))
724 731 else:
725 732 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
726 733
727 734 def log(self, service, message):
728 735 '''hook for logging facility extensions
729 736
730 737 service should be a readily-identifiable subsystem, which will
731 738 allow filtering.
732 739 message should be a newline-terminated string to log.
733 740 '''
734 741 pass
735 742
736 743 def label(self, msg, label):
737 744 '''style msg based on supplied label
738 745
739 746 Like ui.write(), this just returns msg unchanged, but extensions
740 747 and GUI tools can override it to allow styling output without
741 748 writing it.
742 749
743 750 ui.write(s, 'label') is equivalent to
744 751 ui.write(ui.label(s, 'label')).
745 752 '''
746 753 return msg
@@ -1,1759 +1,1766 b''
1 1 # util.py - Mercurial utility functions and platform specfic implementations
2 2 #
3 3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 """Mercurial utility functions and platform specfic implementations.
11 11
12 12 This contains helper routines that are independent of the SCM core and
13 13 hide platform-specific details from the core.
14 14 """
15 15
16 16 from i18n import _
17 17 import error, osutil, encoding
18 18 import errno, re, shutil, sys, tempfile, traceback
19 19 import os, time, datetime, calendar, textwrap, signal
20 20 import imp, socket, urllib
21 21
22 22 if os.name == 'nt':
23 23 import windows as platform
24 24 else:
25 25 import posix as platform
26 26
27 27 platform.encodinglower = encoding.lower
28 28 platform.encodingupper = encoding.upper
29 29
30 30 cachestat = platform.cachestat
31 31 checkexec = platform.checkexec
32 32 checklink = platform.checklink
33 33 copymode = platform.copymode
34 34 executablepath = platform.executablepath
35 35 expandglobs = platform.expandglobs
36 36 explainexit = platform.explainexit
37 37 findexe = platform.findexe
38 38 gethgcmd = platform.gethgcmd
39 39 getuser = platform.getuser
40 40 groupmembers = platform.groupmembers
41 41 groupname = platform.groupname
42 42 hidewindow = platform.hidewindow
43 43 isexec = platform.isexec
44 44 isowner = platform.isowner
45 45 localpath = platform.localpath
46 46 lookupreg = platform.lookupreg
47 47 makedir = platform.makedir
48 48 nlinks = platform.nlinks
49 49 normpath = platform.normpath
50 50 normcase = platform.normcase
51 51 nulldev = platform.nulldev
52 52 openhardlinks = platform.openhardlinks
53 53 oslink = platform.oslink
54 54 parsepatchoutput = platform.parsepatchoutput
55 55 pconvert = platform.pconvert
56 56 popen = platform.popen
57 57 posixfile = platform.posixfile
58 58 quotecommand = platform.quotecommand
59 59 realpath = platform.realpath
60 60 rename = platform.rename
61 61 samedevice = platform.samedevice
62 62 samefile = platform.samefile
63 63 samestat = platform.samestat
64 64 setbinary = platform.setbinary
65 65 setflags = platform.setflags
66 66 setsignalhandler = platform.setsignalhandler
67 67 shellquote = platform.shellquote
68 68 spawndetached = platform.spawndetached
69 69 sshargs = platform.sshargs
70 70 statfiles = platform.statfiles
71 71 termwidth = platform.termwidth
72 72 testpid = platform.testpid
73 73 umask = platform.umask
74 74 unlink = platform.unlink
75 75 unlinkpath = platform.unlinkpath
76 76 username = platform.username
77 77
78 78 # Python compatibility
79 79
80 80 _notset = object()
81 81
82 82 def safehasattr(thing, attr):
83 83 return getattr(thing, attr, _notset) is not _notset
84 84
85 85 def sha1(s=''):
86 86 '''
87 87 Low-overhead wrapper around Python's SHA support
88 88
89 89 >>> f = _fastsha1
90 90 >>> a = sha1()
91 91 >>> a = f()
92 92 >>> a.hexdigest()
93 93 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
94 94 '''
95 95
96 96 return _fastsha1(s)
97 97
98 98 def _fastsha1(s=''):
99 99 # This function will import sha1 from hashlib or sha (whichever is
100 100 # available) and overwrite itself with it on the first call.
101 101 # Subsequent calls will go directly to the imported function.
102 102 if sys.version_info >= (2, 5):
103 103 from hashlib import sha1 as _sha1
104 104 else:
105 105 from sha import sha as _sha1
106 106 global _fastsha1, sha1
107 107 _fastsha1 = sha1 = _sha1
108 108 return _sha1(s)
109 109
110 110 try:
111 111 buffer = buffer
112 112 except NameError:
113 113 if sys.version_info[0] < 3:
114 114 def buffer(sliceable, offset=0):
115 115 return sliceable[offset:]
116 116 else:
117 117 def buffer(sliceable, offset=0):
118 118 return memoryview(sliceable)[offset:]
119 119
120 120 import subprocess
121 121 closefds = os.name == 'posix'
122 122
123 123 def popen2(cmd, env=None, newlines=False):
124 124 # Setting bufsize to -1 lets the system decide the buffer size.
125 125 # The default for bufsize is 0, meaning unbuffered. This leads to
126 126 # poor performance on Mac OS X: http://bugs.python.org/issue4194
127 127 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
128 128 close_fds=closefds,
129 129 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
130 130 universal_newlines=newlines,
131 131 env=env)
132 132 return p.stdin, p.stdout
133 133
134 134 def popen3(cmd, env=None, newlines=False):
135 135 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
136 136 close_fds=closefds,
137 137 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
138 138 stderr=subprocess.PIPE,
139 139 universal_newlines=newlines,
140 140 env=env)
141 141 return p.stdin, p.stdout, p.stderr
142 142
143 143 def version():
144 144 """Return version information if available."""
145 145 try:
146 146 import __version__
147 147 return __version__.version
148 148 except ImportError:
149 149 return 'unknown'
150 150
151 151 # used by parsedate
152 152 defaultdateformats = (
153 153 '%Y-%m-%d %H:%M:%S',
154 154 '%Y-%m-%d %I:%M:%S%p',
155 155 '%Y-%m-%d %H:%M',
156 156 '%Y-%m-%d %I:%M%p',
157 157 '%Y-%m-%d',
158 158 '%m-%d',
159 159 '%m/%d',
160 160 '%m/%d/%y',
161 161 '%m/%d/%Y',
162 162 '%a %b %d %H:%M:%S %Y',
163 163 '%a %b %d %I:%M:%S%p %Y',
164 164 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
165 165 '%b %d %H:%M:%S %Y',
166 166 '%b %d %I:%M:%S%p %Y',
167 167 '%b %d %H:%M:%S',
168 168 '%b %d %I:%M:%S%p',
169 169 '%b %d %H:%M',
170 170 '%b %d %I:%M%p',
171 171 '%b %d %Y',
172 172 '%b %d',
173 173 '%H:%M:%S',
174 174 '%I:%M:%S%p',
175 175 '%H:%M',
176 176 '%I:%M%p',
177 177 )
178 178
179 179 extendeddateformats = defaultdateformats + (
180 180 "%Y",
181 181 "%Y-%m",
182 182 "%b",
183 183 "%b %Y",
184 184 )
185 185
186 186 def cachefunc(func):
187 187 '''cache the result of function calls'''
188 188 # XXX doesn't handle keywords args
189 189 cache = {}
190 190 if func.func_code.co_argcount == 1:
191 191 # we gain a small amount of time because
192 192 # we don't need to pack/unpack the list
193 193 def f(arg):
194 194 if arg not in cache:
195 195 cache[arg] = func(arg)
196 196 return cache[arg]
197 197 else:
198 198 def f(*args):
199 199 if args not in cache:
200 200 cache[args] = func(*args)
201 201 return cache[args]
202 202
203 203 return f
204 204
205 205 def lrucachefunc(func):
206 206 '''cache most recent results of function calls'''
207 207 cache = {}
208 208 order = []
209 209 if func.func_code.co_argcount == 1:
210 210 def f(arg):
211 211 if arg not in cache:
212 212 if len(cache) > 20:
213 213 del cache[order.pop(0)]
214 214 cache[arg] = func(arg)
215 215 else:
216 216 order.remove(arg)
217 217 order.append(arg)
218 218 return cache[arg]
219 219 else:
220 220 def f(*args):
221 221 if args not in cache:
222 222 if len(cache) > 20:
223 223 del cache[order.pop(0)]
224 224 cache[args] = func(*args)
225 225 else:
226 226 order.remove(args)
227 227 order.append(args)
228 228 return cache[args]
229 229
230 230 return f
231 231
232 232 class propertycache(object):
233 233 def __init__(self, func):
234 234 self.func = func
235 235 self.name = func.__name__
236 236 def __get__(self, obj, type=None):
237 237 result = self.func(obj)
238 238 setattr(obj, self.name, result)
239 239 return result
240 240
241 241 def pipefilter(s, cmd):
242 242 '''filter string S through command CMD, returning its output'''
243 243 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
244 244 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
245 245 pout, perr = p.communicate(s)
246 246 return pout
247 247
248 248 def tempfilter(s, cmd):
249 249 '''filter string S through a pair of temporary files with CMD.
250 250 CMD is used as a template to create the real command to be run,
251 251 with the strings INFILE and OUTFILE replaced by the real names of
252 252 the temporary files generated.'''
253 253 inname, outname = None, None
254 254 try:
255 255 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
256 256 fp = os.fdopen(infd, 'wb')
257 257 fp.write(s)
258 258 fp.close()
259 259 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
260 260 os.close(outfd)
261 261 cmd = cmd.replace('INFILE', inname)
262 262 cmd = cmd.replace('OUTFILE', outname)
263 263 code = os.system(cmd)
264 264 if sys.platform == 'OpenVMS' and code & 1:
265 265 code = 0
266 266 if code:
267 267 raise Abort(_("command '%s' failed: %s") %
268 268 (cmd, explainexit(code)))
269 269 fp = open(outname, 'rb')
270 270 r = fp.read()
271 271 fp.close()
272 272 return r
273 273 finally:
274 274 try:
275 275 if inname:
276 276 os.unlink(inname)
277 277 except OSError:
278 278 pass
279 279 try:
280 280 if outname:
281 281 os.unlink(outname)
282 282 except OSError:
283 283 pass
284 284
285 285 filtertable = {
286 286 'tempfile:': tempfilter,
287 287 'pipe:': pipefilter,
288 288 }
289 289
290 290 def filter(s, cmd):
291 291 "filter a string through a command that transforms its input to its output"
292 292 for name, fn in filtertable.iteritems():
293 293 if cmd.startswith(name):
294 294 return fn(s, cmd[len(name):].lstrip())
295 295 return pipefilter(s, cmd)
296 296
297 297 def binary(s):
298 298 """return true if a string is binary data"""
299 299 return bool(s and '\0' in s)
300 300
301 301 def increasingchunks(source, min=1024, max=65536):
302 302 '''return no less than min bytes per chunk while data remains,
303 303 doubling min after each chunk until it reaches max'''
304 304 def log2(x):
305 305 if not x:
306 306 return 0
307 307 i = 0
308 308 while x:
309 309 x >>= 1
310 310 i += 1
311 311 return i - 1
312 312
313 313 buf = []
314 314 blen = 0
315 315 for chunk in source:
316 316 buf.append(chunk)
317 317 blen += len(chunk)
318 318 if blen >= min:
319 319 if min < max:
320 320 min = min << 1
321 321 nmin = 1 << log2(blen)
322 322 if nmin > min:
323 323 min = nmin
324 324 if min > max:
325 325 min = max
326 326 yield ''.join(buf)
327 327 blen = 0
328 328 buf = []
329 329 if buf:
330 330 yield ''.join(buf)
331 331
332 332 Abort = error.Abort
333 333
334 334 def always(fn):
335 335 return True
336 336
337 337 def never(fn):
338 338 return False
339 339
340 340 def pathto(root, n1, n2):
341 341 '''return the relative path from one place to another.
342 342 root should use os.sep to separate directories
343 343 n1 should use os.sep to separate directories
344 344 n2 should use "/" to separate directories
345 345 returns an os.sep-separated path.
346 346
347 347 If n1 is a relative path, it's assumed it's
348 348 relative to root.
349 349 n2 should always be relative to root.
350 350 '''
351 351 if not n1:
352 352 return localpath(n2)
353 353 if os.path.isabs(n1):
354 354 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
355 355 return os.path.join(root, localpath(n2))
356 356 n2 = '/'.join((pconvert(root), n2))
357 357 a, b = splitpath(n1), n2.split('/')
358 358 a.reverse()
359 359 b.reverse()
360 360 while a and b and a[-1] == b[-1]:
361 361 a.pop()
362 362 b.pop()
363 363 b.reverse()
364 364 return os.sep.join((['..'] * len(a)) + b) or '.'
365 365
366 366 _hgexecutable = None
367 367
368 368 def mainfrozen():
369 369 """return True if we are a frozen executable.
370 370
371 371 The code supports py2exe (most common, Windows only) and tools/freeze
372 372 (portable, not much used).
373 373 """
374 374 return (safehasattr(sys, "frozen") or # new py2exe
375 375 safehasattr(sys, "importers") or # old py2exe
376 376 imp.is_frozen("__main__")) # tools/freeze
377 377
378 378 def hgexecutable():
379 379 """return location of the 'hg' executable.
380 380
381 381 Defaults to $HG or 'hg' in the search path.
382 382 """
383 383 if _hgexecutable is None:
384 384 hg = os.environ.get('HG')
385 385 mainmod = sys.modules['__main__']
386 386 if hg:
387 387 _sethgexecutable(hg)
388 388 elif mainfrozen():
389 389 _sethgexecutable(sys.executable)
390 390 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
391 391 _sethgexecutable(mainmod.__file__)
392 392 else:
393 393 exe = findexe('hg') or os.path.basename(sys.argv[0])
394 394 _sethgexecutable(exe)
395 395 return _hgexecutable
396 396
397 397 def _sethgexecutable(path):
398 398 """set location of the 'hg' executable"""
399 399 global _hgexecutable
400 400 _hgexecutable = path
401 401
402 402 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
403 403 '''enhanced shell command execution.
404 404 run with environment maybe modified, maybe in different dir.
405 405
406 406 if command fails and onerr is None, return status. if ui object,
407 407 print error message and return status, else raise onerr object as
408 408 exception.
409 409
410 410 if out is specified, it is assumed to be a file-like object that has a
411 411 write() method. stdout and stderr will be redirected to out.'''
412 412 try:
413 413 sys.stdout.flush()
414 414 except Exception:
415 415 pass
416 416 def py2shell(val):
417 417 'convert python object into string that is useful to shell'
418 418 if val is None or val is False:
419 419 return '0'
420 420 if val is True:
421 421 return '1'
422 422 return str(val)
423 423 origcmd = cmd
424 424 cmd = quotecommand(cmd)
425 env = dict(os.environ)
426 env.update((k, py2shell(v)) for k, v in environ.iteritems())
427 env['HG'] = hgexecutable()
428 if out is None or out == sys.__stdout__:
429 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
430 env=env, cwd=cwd)
425 if sys.platform == 'plan9':
426 # subprocess kludge to work around issues in half-baked Python
427 # ports, notably bichued/python:
428 if not cwd is None:
429 os.chdir(cwd)
430 rc = os.system(cmd)
431 431 else:
432 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
433 env=env, cwd=cwd, stdout=subprocess.PIPE,
434 stderr=subprocess.STDOUT)
435 for line in proc.stdout:
436 out.write(line)
437 proc.wait()
438 rc = proc.returncode
439 if sys.platform == 'OpenVMS' and rc & 1:
440 rc = 0
432 env = dict(os.environ)
433 env.update((k, py2shell(v)) for k, v in environ.iteritems())
434 env['HG'] = hgexecutable()
435 if out is None or out == sys.__stdout__:
436 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
437 env=env, cwd=cwd)
438 else:
439 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
440 env=env, cwd=cwd, stdout=subprocess.PIPE,
441 stderr=subprocess.STDOUT)
442 for line in proc.stdout:
443 out.write(line)
444 proc.wait()
445 rc = proc.returncode
446 if sys.platform == 'OpenVMS' and rc & 1:
447 rc = 0
441 448 if rc and onerr:
442 449 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
443 450 explainexit(rc)[0])
444 451 if errprefix:
445 452 errmsg = '%s: %s' % (errprefix, errmsg)
446 453 try:
447 454 onerr.warn(errmsg + '\n')
448 455 except AttributeError:
449 456 raise onerr(errmsg)
450 457 return rc
451 458
452 459 def checksignature(func):
453 460 '''wrap a function with code to check for calling errors'''
454 461 def check(*args, **kwargs):
455 462 try:
456 463 return func(*args, **kwargs)
457 464 except TypeError:
458 465 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
459 466 raise error.SignatureError
460 467 raise
461 468
462 469 return check
463 470
464 471 def copyfile(src, dest):
465 472 "copy a file, preserving mode and atime/mtime"
466 473 if os.path.islink(src):
467 474 try:
468 475 os.unlink(dest)
469 476 except OSError:
470 477 pass
471 478 os.symlink(os.readlink(src), dest)
472 479 else:
473 480 try:
474 481 shutil.copyfile(src, dest)
475 482 shutil.copymode(src, dest)
476 483 except shutil.Error, inst:
477 484 raise Abort(str(inst))
478 485
479 486 def copyfiles(src, dst, hardlink=None):
480 487 """Copy a directory tree using hardlinks if possible"""
481 488
482 489 if hardlink is None:
483 490 hardlink = (os.stat(src).st_dev ==
484 491 os.stat(os.path.dirname(dst)).st_dev)
485 492
486 493 num = 0
487 494 if os.path.isdir(src):
488 495 os.mkdir(dst)
489 496 for name, kind in osutil.listdir(src):
490 497 srcname = os.path.join(src, name)
491 498 dstname = os.path.join(dst, name)
492 499 hardlink, n = copyfiles(srcname, dstname, hardlink)
493 500 num += n
494 501 else:
495 502 if hardlink:
496 503 try:
497 504 oslink(src, dst)
498 505 except (IOError, OSError):
499 506 hardlink = False
500 507 shutil.copy(src, dst)
501 508 else:
502 509 shutil.copy(src, dst)
503 510 num += 1
504 511
505 512 return hardlink, num
506 513
507 514 _winreservednames = '''con prn aux nul
508 515 com1 com2 com3 com4 com5 com6 com7 com8 com9
509 516 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
510 517 _winreservedchars = ':*?"<>|'
511 518 def checkwinfilename(path):
512 519 '''Check that the base-relative path is a valid filename on Windows.
513 520 Returns None if the path is ok, or a UI string describing the problem.
514 521
515 522 >>> checkwinfilename("just/a/normal/path")
516 523 >>> checkwinfilename("foo/bar/con.xml")
517 524 "filename contains 'con', which is reserved on Windows"
518 525 >>> checkwinfilename("foo/con.xml/bar")
519 526 "filename contains 'con', which is reserved on Windows"
520 527 >>> checkwinfilename("foo/bar/xml.con")
521 528 >>> checkwinfilename("foo/bar/AUX/bla.txt")
522 529 "filename contains 'AUX', which is reserved on Windows"
523 530 >>> checkwinfilename("foo/bar/bla:.txt")
524 531 "filename contains ':', which is reserved on Windows"
525 532 >>> checkwinfilename("foo/bar/b\07la.txt")
526 533 "filename contains '\\\\x07', which is invalid on Windows"
527 534 >>> checkwinfilename("foo/bar/bla ")
528 535 "filename ends with ' ', which is not allowed on Windows"
529 536 >>> checkwinfilename("../bar")
530 537 '''
531 538 for n in path.replace('\\', '/').split('/'):
532 539 if not n:
533 540 continue
534 541 for c in n:
535 542 if c in _winreservedchars:
536 543 return _("filename contains '%s', which is reserved "
537 544 "on Windows") % c
538 545 if ord(c) <= 31:
539 546 return _("filename contains %r, which is invalid "
540 547 "on Windows") % c
541 548 base = n.split('.')[0]
542 549 if base and base.lower() in _winreservednames:
543 550 return _("filename contains '%s', which is reserved "
544 551 "on Windows") % base
545 552 t = n[-1]
546 553 if t in '. ' and n not in '..':
547 554 return _("filename ends with '%s', which is not allowed "
548 555 "on Windows") % t
549 556
550 557 if os.name == 'nt':
551 558 checkosfilename = checkwinfilename
552 559 else:
553 560 checkosfilename = platform.checkosfilename
554 561
555 562 def makelock(info, pathname):
556 563 try:
557 564 return os.symlink(info, pathname)
558 565 except OSError, why:
559 566 if why.errno == errno.EEXIST:
560 567 raise
561 568 except AttributeError: # no symlink in os
562 569 pass
563 570
564 571 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
565 572 os.write(ld, info)
566 573 os.close(ld)
567 574
568 575 def readlock(pathname):
569 576 try:
570 577 return os.readlink(pathname)
571 578 except OSError, why:
572 579 if why.errno not in (errno.EINVAL, errno.ENOSYS):
573 580 raise
574 581 except AttributeError: # no symlink in os
575 582 pass
576 583 fp = posixfile(pathname)
577 584 r = fp.read()
578 585 fp.close()
579 586 return r
580 587
581 588 def fstat(fp):
582 589 '''stat file object that may not have fileno method.'''
583 590 try:
584 591 return os.fstat(fp.fileno())
585 592 except AttributeError:
586 593 return os.stat(fp.name)
587 594
588 595 # File system features
589 596
590 597 def checkcase(path):
591 598 """
592 599 Check whether the given path is on a case-sensitive filesystem
593 600
594 601 Requires a path (like /foo/.hg) ending with a foldable final
595 602 directory component.
596 603 """
597 604 s1 = os.stat(path)
598 605 d, b = os.path.split(path)
599 606 b2 = b.upper()
600 607 if b == b2:
601 608 b2 = b.lower()
602 609 if b == b2:
603 610 return True # no evidence against case sensitivity
604 611 p2 = os.path.join(d, b2)
605 612 try:
606 613 s2 = os.stat(p2)
607 614 if s2 == s1:
608 615 return False
609 616 return True
610 617 except OSError:
611 618 return True
612 619
613 620 _fspathcache = {}
614 621 def fspath(name, root):
615 622 '''Get name in the case stored in the filesystem
616 623
617 624 The name should be relative to root, and be normcase-ed for efficiency.
618 625
619 626 Note that this function is unnecessary, and should not be
620 627 called, for case-sensitive filesystems (simply because it's expensive).
621 628
622 629 The root should be normcase-ed, too.
623 630 '''
624 631 def find(p, contents):
625 632 for n in contents:
626 633 if normcase(n) == p:
627 634 return n
628 635 return None
629 636
630 637 seps = os.sep
631 638 if os.altsep:
632 639 seps = seps + os.altsep
633 640 # Protect backslashes. This gets silly very quickly.
634 641 seps.replace('\\','\\\\')
635 642 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
636 643 dir = os.path.normpath(root)
637 644 result = []
638 645 for part, sep in pattern.findall(name):
639 646 if sep:
640 647 result.append(sep)
641 648 continue
642 649
643 650 if dir not in _fspathcache:
644 651 _fspathcache[dir] = os.listdir(dir)
645 652 contents = _fspathcache[dir]
646 653
647 654 found = find(part, contents)
648 655 if not found:
649 656 # retry "once per directory" per "dirstate.walk" which
650 657 # may take place for each patches of "hg qpush", for example
651 658 contents = os.listdir(dir)
652 659 _fspathcache[dir] = contents
653 660 found = find(part, contents)
654 661
655 662 result.append(found or part)
656 663 dir = os.path.join(dir, part)
657 664
658 665 return ''.join(result)
659 666
660 667 def checknlink(testfile):
661 668 '''check whether hardlink count reporting works properly'''
662 669
663 670 # testfile may be open, so we need a separate file for checking to
664 671 # work around issue2543 (or testfile may get lost on Samba shares)
665 672 f1 = testfile + ".hgtmp1"
666 673 if os.path.lexists(f1):
667 674 return False
668 675 try:
669 676 posixfile(f1, 'w').close()
670 677 except IOError:
671 678 return False
672 679
673 680 f2 = testfile + ".hgtmp2"
674 681 fd = None
675 682 try:
676 683 try:
677 684 oslink(f1, f2)
678 685 except OSError:
679 686 return False
680 687
681 688 # nlinks() may behave differently for files on Windows shares if
682 689 # the file is open.
683 690 fd = posixfile(f2)
684 691 return nlinks(f2) > 1
685 692 finally:
686 693 if fd is not None:
687 694 fd.close()
688 695 for f in (f1, f2):
689 696 try:
690 697 os.unlink(f)
691 698 except OSError:
692 699 pass
693 700
694 701 return False
695 702
696 703 def endswithsep(path):
697 704 '''Check path ends with os.sep or os.altsep.'''
698 705 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
699 706
700 707 def splitpath(path):
701 708 '''Split path by os.sep.
702 709 Note that this function does not use os.altsep because this is
703 710 an alternative of simple "xxx.split(os.sep)".
704 711 It is recommended to use os.path.normpath() before using this
705 712 function if need.'''
706 713 return path.split(os.sep)
707 714
708 715 def gui():
709 716 '''Are we running in a GUI?'''
710 717 if sys.platform == 'darwin':
711 718 if 'SSH_CONNECTION' in os.environ:
712 719 # handle SSH access to a box where the user is logged in
713 720 return False
714 721 elif getattr(osutil, 'isgui', None):
715 722 # check if a CoreGraphics session is available
716 723 return osutil.isgui()
717 724 else:
718 725 # pure build; use a safe default
719 726 return True
720 727 else:
721 728 return os.name == "nt" or os.environ.get("DISPLAY")
722 729
723 730 def mktempcopy(name, emptyok=False, createmode=None):
724 731 """Create a temporary file with the same contents from name
725 732
726 733 The permission bits are copied from the original file.
727 734
728 735 If the temporary file is going to be truncated immediately, you
729 736 can use emptyok=True as an optimization.
730 737
731 738 Returns the name of the temporary file.
732 739 """
733 740 d, fn = os.path.split(name)
734 741 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
735 742 os.close(fd)
736 743 # Temporary files are created with mode 0600, which is usually not
737 744 # what we want. If the original file already exists, just copy
738 745 # its mode. Otherwise, manually obey umask.
739 746 copymode(name, temp, createmode)
740 747 if emptyok:
741 748 return temp
742 749 try:
743 750 try:
744 751 ifp = posixfile(name, "rb")
745 752 except IOError, inst:
746 753 if inst.errno == errno.ENOENT:
747 754 return temp
748 755 if not getattr(inst, 'filename', None):
749 756 inst.filename = name
750 757 raise
751 758 ofp = posixfile(temp, "wb")
752 759 for chunk in filechunkiter(ifp):
753 760 ofp.write(chunk)
754 761 ifp.close()
755 762 ofp.close()
756 763 except:
757 764 try: os.unlink(temp)
758 765 except: pass
759 766 raise
760 767 return temp
761 768
762 769 class atomictempfile(object):
763 770 '''writeable file object that atomically updates a file
764 771
765 772 All writes will go to a temporary copy of the original file. Call
766 773 close() when you are done writing, and atomictempfile will rename
767 774 the temporary copy to the original name, making the changes
768 775 visible. If the object is destroyed without being closed, all your
769 776 writes are discarded.
770 777 '''
771 778 def __init__(self, name, mode='w+b', createmode=None):
772 779 self.__name = name # permanent name
773 780 self._tempname = mktempcopy(name, emptyok=('w' in mode),
774 781 createmode=createmode)
775 782 self._fp = posixfile(self._tempname, mode)
776 783
777 784 # delegated methods
778 785 self.write = self._fp.write
779 786 self.fileno = self._fp.fileno
780 787
781 788 def close(self):
782 789 if not self._fp.closed:
783 790 self._fp.close()
784 791 rename(self._tempname, localpath(self.__name))
785 792
786 793 def discard(self):
787 794 if not self._fp.closed:
788 795 try:
789 796 os.unlink(self._tempname)
790 797 except OSError:
791 798 pass
792 799 self._fp.close()
793 800
794 801 def __del__(self):
795 802 if safehasattr(self, '_fp'): # constructor actually did something
796 803 self.discard()
797 804
798 805 def makedirs(name, mode=None):
799 806 """recursive directory creation with parent mode inheritance"""
800 807 try:
801 808 os.mkdir(name)
802 809 except OSError, err:
803 810 if err.errno == errno.EEXIST:
804 811 return
805 812 if err.errno != errno.ENOENT or not name:
806 813 raise
807 814 parent = os.path.dirname(os.path.abspath(name))
808 815 if parent == name:
809 816 raise
810 817 makedirs(parent, mode)
811 818 os.mkdir(name)
812 819 if mode is not None:
813 820 os.chmod(name, mode)
814 821
815 822 def readfile(path):
816 823 fp = open(path, 'rb')
817 824 try:
818 825 return fp.read()
819 826 finally:
820 827 fp.close()
821 828
822 829 def writefile(path, text):
823 830 fp = open(path, 'wb')
824 831 try:
825 832 fp.write(text)
826 833 finally:
827 834 fp.close()
828 835
829 836 def appendfile(path, text):
830 837 fp = open(path, 'ab')
831 838 try:
832 839 fp.write(text)
833 840 finally:
834 841 fp.close()
835 842
836 843 class chunkbuffer(object):
837 844 """Allow arbitrary sized chunks of data to be efficiently read from an
838 845 iterator over chunks of arbitrary size."""
839 846
840 847 def __init__(self, in_iter):
841 848 """in_iter is the iterator that's iterating over the input chunks.
842 849 targetsize is how big a buffer to try to maintain."""
843 850 def splitbig(chunks):
844 851 for chunk in chunks:
845 852 if len(chunk) > 2**20:
846 853 pos = 0
847 854 while pos < len(chunk):
848 855 end = pos + 2 ** 18
849 856 yield chunk[pos:end]
850 857 pos = end
851 858 else:
852 859 yield chunk
853 860 self.iter = splitbig(in_iter)
854 861 self._queue = []
855 862
856 863 def read(self, l):
857 864 """Read L bytes of data from the iterator of chunks of data.
858 865 Returns less than L bytes if the iterator runs dry."""
859 866 left = l
860 867 buf = ''
861 868 queue = self._queue
862 869 while left > 0:
863 870 # refill the queue
864 871 if not queue:
865 872 target = 2**18
866 873 for chunk in self.iter:
867 874 queue.append(chunk)
868 875 target -= len(chunk)
869 876 if target <= 0:
870 877 break
871 878 if not queue:
872 879 break
873 880
874 881 chunk = queue.pop(0)
875 882 left -= len(chunk)
876 883 if left < 0:
877 884 queue.insert(0, chunk[left:])
878 885 buf += chunk[:left]
879 886 else:
880 887 buf += chunk
881 888
882 889 return buf
883 890
884 891 def filechunkiter(f, size=65536, limit=None):
885 892 """Create a generator that produces the data in the file size
886 893 (default 65536) bytes at a time, up to optional limit (default is
887 894 to read all data). Chunks may be less than size bytes if the
888 895 chunk is the last chunk in the file, or the file is a socket or
889 896 some other type of file that sometimes reads less data than is
890 897 requested."""
891 898 assert size >= 0
892 899 assert limit is None or limit >= 0
893 900 while True:
894 901 if limit is None:
895 902 nbytes = size
896 903 else:
897 904 nbytes = min(limit, size)
898 905 s = nbytes and f.read(nbytes)
899 906 if not s:
900 907 break
901 908 if limit:
902 909 limit -= len(s)
903 910 yield s
904 911
905 912 def makedate():
906 913 ct = time.time()
907 914 if ct < 0:
908 915 hint = _("check your clock")
909 916 raise Abort(_("negative timestamp: %d") % ct, hint=hint)
910 917 delta = (datetime.datetime.utcfromtimestamp(ct) -
911 918 datetime.datetime.fromtimestamp(ct))
912 919 tz = delta.days * 86400 + delta.seconds
913 920 return ct, tz
914 921
915 922 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
916 923 """represent a (unixtime, offset) tuple as a localized time.
917 924 unixtime is seconds since the epoch, and offset is the time zone's
918 925 number of seconds away from UTC. if timezone is false, do not
919 926 append time zone to string."""
920 927 t, tz = date or makedate()
921 928 if t < 0:
922 929 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
923 930 tz = 0
924 931 if "%1" in format or "%2" in format:
925 932 sign = (tz > 0) and "-" or "+"
926 933 minutes = abs(tz) // 60
927 934 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
928 935 format = format.replace("%2", "%02d" % (minutes % 60))
929 936 try:
930 937 t = time.gmtime(float(t) - tz)
931 938 except ValueError:
932 939 # time was out of range
933 940 t = time.gmtime(sys.maxint)
934 941 s = time.strftime(format, t)
935 942 return s
936 943
937 944 def shortdate(date=None):
938 945 """turn (timestamp, tzoff) tuple into iso 8631 date."""
939 946 return datestr(date, format='%Y-%m-%d')
940 947
941 948 def strdate(string, format, defaults=[]):
942 949 """parse a localized time string and return a (unixtime, offset) tuple.
943 950 if the string cannot be parsed, ValueError is raised."""
944 951 def timezone(string):
945 952 tz = string.split()[-1]
946 953 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
947 954 sign = (tz[0] == "+") and 1 or -1
948 955 hours = int(tz[1:3])
949 956 minutes = int(tz[3:5])
950 957 return -sign * (hours * 60 + minutes) * 60
951 958 if tz == "GMT" or tz == "UTC":
952 959 return 0
953 960 return None
954 961
955 962 # NOTE: unixtime = localunixtime + offset
956 963 offset, date = timezone(string), string
957 964 if offset is not None:
958 965 date = " ".join(string.split()[:-1])
959 966
960 967 # add missing elements from defaults
961 968 usenow = False # default to using biased defaults
962 969 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
963 970 found = [True for p in part if ("%"+p) in format]
964 971 if not found:
965 972 date += "@" + defaults[part][usenow]
966 973 format += "@%" + part[0]
967 974 else:
968 975 # We've found a specific time element, less specific time
969 976 # elements are relative to today
970 977 usenow = True
971 978
972 979 timetuple = time.strptime(date, format)
973 980 localunixtime = int(calendar.timegm(timetuple))
974 981 if offset is None:
975 982 # local timezone
976 983 unixtime = int(time.mktime(timetuple))
977 984 offset = unixtime - localunixtime
978 985 else:
979 986 unixtime = localunixtime + offset
980 987 return unixtime, offset
981 988
982 989 def parsedate(date, formats=None, bias={}):
983 990 """parse a localized date/time and return a (unixtime, offset) tuple.
984 991
985 992 The date may be a "unixtime offset" string or in one of the specified
986 993 formats. If the date already is a (unixtime, offset) tuple, it is returned.
987 994 """
988 995 if not date:
989 996 return 0, 0
990 997 if isinstance(date, tuple) and len(date) == 2:
991 998 return date
992 999 if not formats:
993 1000 formats = defaultdateformats
994 1001 date = date.strip()
995 1002 try:
996 1003 when, offset = map(int, date.split(' '))
997 1004 except ValueError:
998 1005 # fill out defaults
999 1006 now = makedate()
1000 1007 defaults = {}
1001 1008 for part in ("d", "mb", "yY", "HI", "M", "S"):
1002 1009 # this piece is for rounding the specific end of unknowns
1003 1010 b = bias.get(part)
1004 1011 if b is None:
1005 1012 if part[0] in "HMS":
1006 1013 b = "00"
1007 1014 else:
1008 1015 b = "0"
1009 1016
1010 1017 # this piece is for matching the generic end to today's date
1011 1018 n = datestr(now, "%" + part[0])
1012 1019
1013 1020 defaults[part] = (b, n)
1014 1021
1015 1022 for format in formats:
1016 1023 try:
1017 1024 when, offset = strdate(date, format, defaults)
1018 1025 except (ValueError, OverflowError):
1019 1026 pass
1020 1027 else:
1021 1028 break
1022 1029 else:
1023 1030 raise Abort(_('invalid date: %r') % date)
1024 1031 # validate explicit (probably user-specified) date and
1025 1032 # time zone offset. values must fit in signed 32 bits for
1026 1033 # current 32-bit linux runtimes. timezones go from UTC-12
1027 1034 # to UTC+14
1028 1035 if abs(when) > 0x7fffffff:
1029 1036 raise Abort(_('date exceeds 32 bits: %d') % when)
1030 1037 if when < 0:
1031 1038 raise Abort(_('negative date value: %d') % when)
1032 1039 if offset < -50400 or offset > 43200:
1033 1040 raise Abort(_('impossible time zone offset: %d') % offset)
1034 1041 return when, offset
1035 1042
1036 1043 def matchdate(date):
1037 1044 """Return a function that matches a given date match specifier
1038 1045
1039 1046 Formats include:
1040 1047
1041 1048 '{date}' match a given date to the accuracy provided
1042 1049
1043 1050 '<{date}' on or before a given date
1044 1051
1045 1052 '>{date}' on or after a given date
1046 1053
1047 1054 >>> p1 = parsedate("10:29:59")
1048 1055 >>> p2 = parsedate("10:30:00")
1049 1056 >>> p3 = parsedate("10:30:59")
1050 1057 >>> p4 = parsedate("10:31:00")
1051 1058 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1052 1059 >>> f = matchdate("10:30")
1053 1060 >>> f(p1[0])
1054 1061 False
1055 1062 >>> f(p2[0])
1056 1063 True
1057 1064 >>> f(p3[0])
1058 1065 True
1059 1066 >>> f(p4[0])
1060 1067 False
1061 1068 >>> f(p5[0])
1062 1069 False
1063 1070 """
1064 1071
1065 1072 def lower(date):
1066 1073 d = dict(mb="1", d="1")
1067 1074 return parsedate(date, extendeddateformats, d)[0]
1068 1075
1069 1076 def upper(date):
1070 1077 d = dict(mb="12", HI="23", M="59", S="59")
1071 1078 for days in ("31", "30", "29"):
1072 1079 try:
1073 1080 d["d"] = days
1074 1081 return parsedate(date, extendeddateformats, d)[0]
1075 1082 except:
1076 1083 pass
1077 1084 d["d"] = "28"
1078 1085 return parsedate(date, extendeddateformats, d)[0]
1079 1086
1080 1087 date = date.strip()
1081 1088
1082 1089 if not date:
1083 1090 raise Abort(_("dates cannot consist entirely of whitespace"))
1084 1091 elif date[0] == "<":
1085 1092 if not date[1:]:
1086 1093 raise Abort(_("invalid day spec, use '<DATE'"))
1087 1094 when = upper(date[1:])
1088 1095 return lambda x: x <= when
1089 1096 elif date[0] == ">":
1090 1097 if not date[1:]:
1091 1098 raise Abort(_("invalid day spec, use '>DATE'"))
1092 1099 when = lower(date[1:])
1093 1100 return lambda x: x >= when
1094 1101 elif date[0] == "-":
1095 1102 try:
1096 1103 days = int(date[1:])
1097 1104 except ValueError:
1098 1105 raise Abort(_("invalid day spec: %s") % date[1:])
1099 1106 if days < 0:
1100 1107 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1101 1108 % date[1:])
1102 1109 when = makedate()[0] - days * 3600 * 24
1103 1110 return lambda x: x >= when
1104 1111 elif " to " in date:
1105 1112 a, b = date.split(" to ")
1106 1113 start, stop = lower(a), upper(b)
1107 1114 return lambda x: x >= start and x <= stop
1108 1115 else:
1109 1116 start, stop = lower(date), upper(date)
1110 1117 return lambda x: x >= start and x <= stop
1111 1118
1112 1119 def shortuser(user):
1113 1120 """Return a short representation of a user name or email address."""
1114 1121 f = user.find('@')
1115 1122 if f >= 0:
1116 1123 user = user[:f]
1117 1124 f = user.find('<')
1118 1125 if f >= 0:
1119 1126 user = user[f + 1:]
1120 1127 f = user.find(' ')
1121 1128 if f >= 0:
1122 1129 user = user[:f]
1123 1130 f = user.find('.')
1124 1131 if f >= 0:
1125 1132 user = user[:f]
1126 1133 return user
1127 1134
1128 1135 def emailuser(user):
1129 1136 """Return the user portion of an email address."""
1130 1137 f = user.find('@')
1131 1138 if f >= 0:
1132 1139 user = user[:f]
1133 1140 f = user.find('<')
1134 1141 if f >= 0:
1135 1142 user = user[f + 1:]
1136 1143 return user
1137 1144
1138 1145 def email(author):
1139 1146 '''get email of author.'''
1140 1147 r = author.find('>')
1141 1148 if r == -1:
1142 1149 r = None
1143 1150 return author[author.find('<') + 1:r]
1144 1151
1145 1152 def _ellipsis(text, maxlength):
1146 1153 if len(text) <= maxlength:
1147 1154 return text, False
1148 1155 else:
1149 1156 return "%s..." % (text[:maxlength - 3]), True
1150 1157
1151 1158 def ellipsis(text, maxlength=400):
1152 1159 """Trim string to at most maxlength (default: 400) characters."""
1153 1160 try:
1154 1161 # use unicode not to split at intermediate multi-byte sequence
1155 1162 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1156 1163 maxlength)
1157 1164 if not truncated:
1158 1165 return text
1159 1166 return utext.encode(encoding.encoding)
1160 1167 except (UnicodeDecodeError, UnicodeEncodeError):
1161 1168 return _ellipsis(text, maxlength)[0]
1162 1169
1163 1170 def bytecount(nbytes):
1164 1171 '''return byte count formatted as readable string, with units'''
1165 1172
1166 1173 units = (
1167 1174 (100, 1 << 30, _('%.0f GB')),
1168 1175 (10, 1 << 30, _('%.1f GB')),
1169 1176 (1, 1 << 30, _('%.2f GB')),
1170 1177 (100, 1 << 20, _('%.0f MB')),
1171 1178 (10, 1 << 20, _('%.1f MB')),
1172 1179 (1, 1 << 20, _('%.2f MB')),
1173 1180 (100, 1 << 10, _('%.0f KB')),
1174 1181 (10, 1 << 10, _('%.1f KB')),
1175 1182 (1, 1 << 10, _('%.2f KB')),
1176 1183 (1, 1, _('%.0f bytes')),
1177 1184 )
1178 1185
1179 1186 for multiplier, divisor, format in units:
1180 1187 if nbytes >= divisor * multiplier:
1181 1188 return format % (nbytes / float(divisor))
1182 1189 return units[-1][2] % nbytes
1183 1190
1184 1191 def uirepr(s):
1185 1192 # Avoid double backslash in Windows path repr()
1186 1193 return repr(s).replace('\\\\', '\\')
1187 1194
1188 1195 # delay import of textwrap
1189 1196 def MBTextWrapper(**kwargs):
1190 1197 class tw(textwrap.TextWrapper):
1191 1198 """
1192 1199 Extend TextWrapper for width-awareness.
1193 1200
1194 1201 Neither number of 'bytes' in any encoding nor 'characters' is
1195 1202 appropriate to calculate terminal columns for specified string.
1196 1203
1197 1204 Original TextWrapper implementation uses built-in 'len()' directly,
1198 1205 so overriding is needed to use width information of each characters.
1199 1206
1200 1207 In addition, characters classified into 'ambiguous' width are
1201 1208 treated as wide in east asian area, but as narrow in other.
1202 1209
1203 1210 This requires use decision to determine width of such characters.
1204 1211 """
1205 1212 def __init__(self, **kwargs):
1206 1213 textwrap.TextWrapper.__init__(self, **kwargs)
1207 1214
1208 1215 # for compatibility between 2.4 and 2.6
1209 1216 if getattr(self, 'drop_whitespace', None) is None:
1210 1217 self.drop_whitespace = kwargs.get('drop_whitespace', True)
1211 1218
1212 1219 def _cutdown(self, ucstr, space_left):
1213 1220 l = 0
1214 1221 colwidth = encoding.ucolwidth
1215 1222 for i in xrange(len(ucstr)):
1216 1223 l += colwidth(ucstr[i])
1217 1224 if space_left < l:
1218 1225 return (ucstr[:i], ucstr[i:])
1219 1226 return ucstr, ''
1220 1227
1221 1228 # overriding of base class
1222 1229 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1223 1230 space_left = max(width - cur_len, 1)
1224 1231
1225 1232 if self.break_long_words:
1226 1233 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1227 1234 cur_line.append(cut)
1228 1235 reversed_chunks[-1] = res
1229 1236 elif not cur_line:
1230 1237 cur_line.append(reversed_chunks.pop())
1231 1238
1232 1239 # this overriding code is imported from TextWrapper of python 2.6
1233 1240 # to calculate columns of string by 'encoding.ucolwidth()'
1234 1241 def _wrap_chunks(self, chunks):
1235 1242 colwidth = encoding.ucolwidth
1236 1243
1237 1244 lines = []
1238 1245 if self.width <= 0:
1239 1246 raise ValueError("invalid width %r (must be > 0)" % self.width)
1240 1247
1241 1248 # Arrange in reverse order so items can be efficiently popped
1242 1249 # from a stack of chucks.
1243 1250 chunks.reverse()
1244 1251
1245 1252 while chunks:
1246 1253
1247 1254 # Start the list of chunks that will make up the current line.
1248 1255 # cur_len is just the length of all the chunks in cur_line.
1249 1256 cur_line = []
1250 1257 cur_len = 0
1251 1258
1252 1259 # Figure out which static string will prefix this line.
1253 1260 if lines:
1254 1261 indent = self.subsequent_indent
1255 1262 else:
1256 1263 indent = self.initial_indent
1257 1264
1258 1265 # Maximum width for this line.
1259 1266 width = self.width - len(indent)
1260 1267
1261 1268 # First chunk on line is whitespace -- drop it, unless this
1262 1269 # is the very beginning of the text (ie. no lines started yet).
1263 1270 if self.drop_whitespace and chunks[-1].strip() == '' and lines:
1264 1271 del chunks[-1]
1265 1272
1266 1273 while chunks:
1267 1274 l = colwidth(chunks[-1])
1268 1275
1269 1276 # Can at least squeeze this chunk onto the current line.
1270 1277 if cur_len + l <= width:
1271 1278 cur_line.append(chunks.pop())
1272 1279 cur_len += l
1273 1280
1274 1281 # Nope, this line is full.
1275 1282 else:
1276 1283 break
1277 1284
1278 1285 # The current line is full, and the next chunk is too big to
1279 1286 # fit on *any* line (not just this one).
1280 1287 if chunks and colwidth(chunks[-1]) > width:
1281 1288 self._handle_long_word(chunks, cur_line, cur_len, width)
1282 1289
1283 1290 # If the last chunk on this line is all whitespace, drop it.
1284 1291 if (self.drop_whitespace and
1285 1292 cur_line and cur_line[-1].strip() == ''):
1286 1293 del cur_line[-1]
1287 1294
1288 1295 # Convert current line back to a string and store it in list
1289 1296 # of all lines (return value).
1290 1297 if cur_line:
1291 1298 lines.append(indent + ''.join(cur_line))
1292 1299
1293 1300 return lines
1294 1301
1295 1302 global MBTextWrapper
1296 1303 MBTextWrapper = tw
1297 1304 return tw(**kwargs)
1298 1305
1299 1306 def wrap(line, width, initindent='', hangindent=''):
1300 1307 maxindent = max(len(hangindent), len(initindent))
1301 1308 if width <= maxindent:
1302 1309 # adjust for weird terminal size
1303 1310 width = max(78, maxindent + 1)
1304 1311 line = line.decode(encoding.encoding, encoding.encodingmode)
1305 1312 initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
1306 1313 hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
1307 1314 wrapper = MBTextWrapper(width=width,
1308 1315 initial_indent=initindent,
1309 1316 subsequent_indent=hangindent)
1310 1317 return wrapper.fill(line).encode(encoding.encoding)
1311 1318
1312 1319 def iterlines(iterator):
1313 1320 for chunk in iterator:
1314 1321 for line in chunk.splitlines():
1315 1322 yield line
1316 1323
1317 1324 def expandpath(path):
1318 1325 return os.path.expanduser(os.path.expandvars(path))
1319 1326
1320 1327 def hgcmd():
1321 1328 """Return the command used to execute current hg
1322 1329
1323 1330 This is different from hgexecutable() because on Windows we want
1324 1331 to avoid things opening new shell windows like batch files, so we
1325 1332 get either the python call or current executable.
1326 1333 """
1327 1334 if mainfrozen():
1328 1335 return [sys.executable]
1329 1336 return gethgcmd()
1330 1337
1331 1338 def rundetached(args, condfn):
1332 1339 """Execute the argument list in a detached process.
1333 1340
1334 1341 condfn is a callable which is called repeatedly and should return
1335 1342 True once the child process is known to have started successfully.
1336 1343 At this point, the child process PID is returned. If the child
1337 1344 process fails to start or finishes before condfn() evaluates to
1338 1345 True, return -1.
1339 1346 """
1340 1347 # Windows case is easier because the child process is either
1341 1348 # successfully starting and validating the condition or exiting
1342 1349 # on failure. We just poll on its PID. On Unix, if the child
1343 1350 # process fails to start, it will be left in a zombie state until
1344 1351 # the parent wait on it, which we cannot do since we expect a long
1345 1352 # running process on success. Instead we listen for SIGCHLD telling
1346 1353 # us our child process terminated.
1347 1354 terminated = set()
1348 1355 def handler(signum, frame):
1349 1356 terminated.add(os.wait())
1350 1357 prevhandler = None
1351 1358 SIGCHLD = getattr(signal, 'SIGCHLD', None)
1352 1359 if SIGCHLD is not None:
1353 1360 prevhandler = signal.signal(SIGCHLD, handler)
1354 1361 try:
1355 1362 pid = spawndetached(args)
1356 1363 while not condfn():
1357 1364 if ((pid in terminated or not testpid(pid))
1358 1365 and not condfn()):
1359 1366 return -1
1360 1367 time.sleep(0.1)
1361 1368 return pid
1362 1369 finally:
1363 1370 if prevhandler is not None:
1364 1371 signal.signal(signal.SIGCHLD, prevhandler)
1365 1372
1366 1373 try:
1367 1374 any, all = any, all
1368 1375 except NameError:
1369 1376 def any(iterable):
1370 1377 for i in iterable:
1371 1378 if i:
1372 1379 return True
1373 1380 return False
1374 1381
1375 1382 def all(iterable):
1376 1383 for i in iterable:
1377 1384 if not i:
1378 1385 return False
1379 1386 return True
1380 1387
1381 1388 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1382 1389 """Return the result of interpolating items in the mapping into string s.
1383 1390
1384 1391 prefix is a single character string, or a two character string with
1385 1392 a backslash as the first character if the prefix needs to be escaped in
1386 1393 a regular expression.
1387 1394
1388 1395 fn is an optional function that will be applied to the replacement text
1389 1396 just before replacement.
1390 1397
1391 1398 escape_prefix is an optional flag that allows using doubled prefix for
1392 1399 its escaping.
1393 1400 """
1394 1401 fn = fn or (lambda s: s)
1395 1402 patterns = '|'.join(mapping.keys())
1396 1403 if escape_prefix:
1397 1404 patterns += '|' + prefix
1398 1405 if len(prefix) > 1:
1399 1406 prefix_char = prefix[1:]
1400 1407 else:
1401 1408 prefix_char = prefix
1402 1409 mapping[prefix_char] = prefix_char
1403 1410 r = re.compile(r'%s(%s)' % (prefix, patterns))
1404 1411 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1405 1412
1406 1413 def getport(port):
1407 1414 """Return the port for a given network service.
1408 1415
1409 1416 If port is an integer, it's returned as is. If it's a string, it's
1410 1417 looked up using socket.getservbyname(). If there's no matching
1411 1418 service, util.Abort is raised.
1412 1419 """
1413 1420 try:
1414 1421 return int(port)
1415 1422 except ValueError:
1416 1423 pass
1417 1424
1418 1425 try:
1419 1426 return socket.getservbyname(port)
1420 1427 except socket.error:
1421 1428 raise Abort(_("no port number associated with service '%s'") % port)
1422 1429
1423 1430 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1424 1431 '0': False, 'no': False, 'false': False, 'off': False,
1425 1432 'never': False}
1426 1433
1427 1434 def parsebool(s):
1428 1435 """Parse s into a boolean.
1429 1436
1430 1437 If s is not a valid boolean, returns None.
1431 1438 """
1432 1439 return _booleans.get(s.lower(), None)
1433 1440
1434 1441 _hexdig = '0123456789ABCDEFabcdef'
1435 1442 _hextochr = dict((a + b, chr(int(a + b, 16)))
1436 1443 for a in _hexdig for b in _hexdig)
1437 1444
1438 1445 def _urlunquote(s):
1439 1446 """unquote('abc%20def') -> 'abc def'."""
1440 1447 res = s.split('%')
1441 1448 # fastpath
1442 1449 if len(res) == 1:
1443 1450 return s
1444 1451 s = res[0]
1445 1452 for item in res[1:]:
1446 1453 try:
1447 1454 s += _hextochr[item[:2]] + item[2:]
1448 1455 except KeyError:
1449 1456 s += '%' + item
1450 1457 except UnicodeDecodeError:
1451 1458 s += unichr(int(item[:2], 16)) + item[2:]
1452 1459 return s
1453 1460
1454 1461 class url(object):
1455 1462 r"""Reliable URL parser.
1456 1463
1457 1464 This parses URLs and provides attributes for the following
1458 1465 components:
1459 1466
1460 1467 <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
1461 1468
1462 1469 Missing components are set to None. The only exception is
1463 1470 fragment, which is set to '' if present but empty.
1464 1471
1465 1472 If parsefragment is False, fragment is included in query. If
1466 1473 parsequery is False, query is included in path. If both are
1467 1474 False, both fragment and query are included in path.
1468 1475
1469 1476 See http://www.ietf.org/rfc/rfc2396.txt for more information.
1470 1477
1471 1478 Note that for backward compatibility reasons, bundle URLs do not
1472 1479 take host names. That means 'bundle://../' has a path of '../'.
1473 1480
1474 1481 Examples:
1475 1482
1476 1483 >>> url('http://www.ietf.org/rfc/rfc2396.txt')
1477 1484 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
1478 1485 >>> url('ssh://[::1]:2200//home/joe/repo')
1479 1486 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
1480 1487 >>> url('file:///home/joe/repo')
1481 1488 <url scheme: 'file', path: '/home/joe/repo'>
1482 1489 >>> url('file:///c:/temp/foo/')
1483 1490 <url scheme: 'file', path: 'c:/temp/foo/'>
1484 1491 >>> url('bundle:foo')
1485 1492 <url scheme: 'bundle', path: 'foo'>
1486 1493 >>> url('bundle://../foo')
1487 1494 <url scheme: 'bundle', path: '../foo'>
1488 1495 >>> url(r'c:\foo\bar')
1489 1496 <url path: 'c:\\foo\\bar'>
1490 1497 >>> url(r'\\blah\blah\blah')
1491 1498 <url path: '\\\\blah\\blah\\blah'>
1492 1499 >>> url(r'\\blah\blah\blah#baz')
1493 1500 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
1494 1501
1495 1502 Authentication credentials:
1496 1503
1497 1504 >>> url('ssh://joe:xyz@x/repo')
1498 1505 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
1499 1506 >>> url('ssh://joe@x/repo')
1500 1507 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
1501 1508
1502 1509 Query strings and fragments:
1503 1510
1504 1511 >>> url('http://host/a?b#c')
1505 1512 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
1506 1513 >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
1507 1514 <url scheme: 'http', host: 'host', path: 'a?b#c'>
1508 1515 """
1509 1516
1510 1517 _safechars = "!~*'()+"
1511 1518 _safepchars = "/!~*'()+:"
1512 1519 _matchscheme = re.compile(r'^[a-zA-Z0-9+.\-]+:').match
1513 1520
1514 1521 def __init__(self, path, parsequery=True, parsefragment=True):
1515 1522 # We slowly chomp away at path until we have only the path left
1516 1523 self.scheme = self.user = self.passwd = self.host = None
1517 1524 self.port = self.path = self.query = self.fragment = None
1518 1525 self._localpath = True
1519 1526 self._hostport = ''
1520 1527 self._origpath = path
1521 1528
1522 1529 if parsefragment and '#' in path:
1523 1530 path, self.fragment = path.split('#', 1)
1524 1531 if not path:
1525 1532 path = None
1526 1533
1527 1534 # special case for Windows drive letters and UNC paths
1528 1535 if hasdriveletter(path) or path.startswith(r'\\'):
1529 1536 self.path = path
1530 1537 return
1531 1538
1532 1539 # For compatibility reasons, we can't handle bundle paths as
1533 1540 # normal URLS
1534 1541 if path.startswith('bundle:'):
1535 1542 self.scheme = 'bundle'
1536 1543 path = path[7:]
1537 1544 if path.startswith('//'):
1538 1545 path = path[2:]
1539 1546 self.path = path
1540 1547 return
1541 1548
1542 1549 if self._matchscheme(path):
1543 1550 parts = path.split(':', 1)
1544 1551 if parts[0]:
1545 1552 self.scheme, path = parts
1546 1553 self._localpath = False
1547 1554
1548 1555 if not path:
1549 1556 path = None
1550 1557 if self._localpath:
1551 1558 self.path = ''
1552 1559 return
1553 1560 else:
1554 1561 if self._localpath:
1555 1562 self.path = path
1556 1563 return
1557 1564
1558 1565 if parsequery and '?' in path:
1559 1566 path, self.query = path.split('?', 1)
1560 1567 if not path:
1561 1568 path = None
1562 1569 if not self.query:
1563 1570 self.query = None
1564 1571
1565 1572 # // is required to specify a host/authority
1566 1573 if path and path.startswith('//'):
1567 1574 parts = path[2:].split('/', 1)
1568 1575 if len(parts) > 1:
1569 1576 self.host, path = parts
1570 1577 path = path
1571 1578 else:
1572 1579 self.host = parts[0]
1573 1580 path = None
1574 1581 if not self.host:
1575 1582 self.host = None
1576 1583 # path of file:///d is /d
1577 1584 # path of file:///d:/ is d:/, not /d:/
1578 1585 if path and not hasdriveletter(path):
1579 1586 path = '/' + path
1580 1587
1581 1588 if self.host and '@' in self.host:
1582 1589 self.user, self.host = self.host.rsplit('@', 1)
1583 1590 if ':' in self.user:
1584 1591 self.user, self.passwd = self.user.split(':', 1)
1585 1592 if not self.host:
1586 1593 self.host = None
1587 1594
1588 1595 # Don't split on colons in IPv6 addresses without ports
1589 1596 if (self.host and ':' in self.host and
1590 1597 not (self.host.startswith('[') and self.host.endswith(']'))):
1591 1598 self._hostport = self.host
1592 1599 self.host, self.port = self.host.rsplit(':', 1)
1593 1600 if not self.host:
1594 1601 self.host = None
1595 1602
1596 1603 if (self.host and self.scheme == 'file' and
1597 1604 self.host not in ('localhost', '127.0.0.1', '[::1]')):
1598 1605 raise Abort(_('file:// URLs can only refer to localhost'))
1599 1606
1600 1607 self.path = path
1601 1608
1602 1609 # leave the query string escaped
1603 1610 for a in ('user', 'passwd', 'host', 'port',
1604 1611 'path', 'fragment'):
1605 1612 v = getattr(self, a)
1606 1613 if v is not None:
1607 1614 setattr(self, a, _urlunquote(v))
1608 1615
1609 1616 def __repr__(self):
1610 1617 attrs = []
1611 1618 for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
1612 1619 'query', 'fragment'):
1613 1620 v = getattr(self, a)
1614 1621 if v is not None:
1615 1622 attrs.append('%s: %r' % (a, v))
1616 1623 return '<url %s>' % ', '.join(attrs)
1617 1624
1618 1625 def __str__(self):
1619 1626 r"""Join the URL's components back into a URL string.
1620 1627
1621 1628 Examples:
1622 1629
1623 1630 >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
1624 1631 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
1625 1632 >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
1626 1633 'http://user:pw@host:80/?foo=bar&baz=42'
1627 1634 >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
1628 1635 'http://user:pw@host:80/?foo=bar%3dbaz'
1629 1636 >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
1630 1637 'ssh://user:pw@[::1]:2200//home/joe#'
1631 1638 >>> str(url('http://localhost:80//'))
1632 1639 'http://localhost:80//'
1633 1640 >>> str(url('http://localhost:80/'))
1634 1641 'http://localhost:80/'
1635 1642 >>> str(url('http://localhost:80'))
1636 1643 'http://localhost:80/'
1637 1644 >>> str(url('bundle:foo'))
1638 1645 'bundle:foo'
1639 1646 >>> str(url('bundle://../foo'))
1640 1647 'bundle:../foo'
1641 1648 >>> str(url('path'))
1642 1649 'path'
1643 1650 >>> str(url('file:///tmp/foo/bar'))
1644 1651 'file:///tmp/foo/bar'
1645 1652 >>> str(url('file:///c:/tmp/foo/bar'))
1646 1653 'file:///c:/tmp/foo/bar'
1647 1654 >>> print url(r'bundle:foo\bar')
1648 1655 bundle:foo\bar
1649 1656 """
1650 1657 if self._localpath:
1651 1658 s = self.path
1652 1659 if self.scheme == 'bundle':
1653 1660 s = 'bundle:' + s
1654 1661 if self.fragment:
1655 1662 s += '#' + self.fragment
1656 1663 return s
1657 1664
1658 1665 s = self.scheme + ':'
1659 1666 if self.user or self.passwd or self.host:
1660 1667 s += '//'
1661 1668 elif self.scheme and (not self.path or self.path.startswith('/')
1662 1669 or hasdriveletter(self.path)):
1663 1670 s += '//'
1664 1671 if hasdriveletter(self.path):
1665 1672 s += '/'
1666 1673 if self.user:
1667 1674 s += urllib.quote(self.user, safe=self._safechars)
1668 1675 if self.passwd:
1669 1676 s += ':' + urllib.quote(self.passwd, safe=self._safechars)
1670 1677 if self.user or self.passwd:
1671 1678 s += '@'
1672 1679 if self.host:
1673 1680 if not (self.host.startswith('[') and self.host.endswith(']')):
1674 1681 s += urllib.quote(self.host)
1675 1682 else:
1676 1683 s += self.host
1677 1684 if self.port:
1678 1685 s += ':' + urllib.quote(self.port)
1679 1686 if self.host:
1680 1687 s += '/'
1681 1688 if self.path:
1682 1689 # TODO: similar to the query string, we should not unescape the
1683 1690 # path when we store it, the path might contain '%2f' = '/',
1684 1691 # which we should *not* escape.
1685 1692 s += urllib.quote(self.path, safe=self._safepchars)
1686 1693 if self.query:
1687 1694 # we store the query in escaped form.
1688 1695 s += '?' + self.query
1689 1696 if self.fragment is not None:
1690 1697 s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
1691 1698 return s
1692 1699
1693 1700 def authinfo(self):
1694 1701 user, passwd = self.user, self.passwd
1695 1702 try:
1696 1703 self.user, self.passwd = None, None
1697 1704 s = str(self)
1698 1705 finally:
1699 1706 self.user, self.passwd = user, passwd
1700 1707 if not self.user:
1701 1708 return (s, None)
1702 1709 # authinfo[1] is passed to urllib2 password manager, and its
1703 1710 # URIs must not contain credentials. The host is passed in the
1704 1711 # URIs list because Python < 2.4.3 uses only that to search for
1705 1712 # a password.
1706 1713 return (s, (None, (s, self.host),
1707 1714 self.user, self.passwd or ''))
1708 1715
1709 1716 def isabs(self):
1710 1717 if self.scheme and self.scheme != 'file':
1711 1718 return True # remote URL
1712 1719 if hasdriveletter(self.path):
1713 1720 return True # absolute for our purposes - can't be joined()
1714 1721 if self.path.startswith(r'\\'):
1715 1722 return True # Windows UNC path
1716 1723 if self.path.startswith('/'):
1717 1724 return True # POSIX-style
1718 1725 return False
1719 1726
1720 1727 def localpath(self):
1721 1728 if self.scheme == 'file' or self.scheme == 'bundle':
1722 1729 path = self.path or '/'
1723 1730 # For Windows, we need to promote hosts containing drive
1724 1731 # letters to paths with drive letters.
1725 1732 if hasdriveletter(self._hostport):
1726 1733 path = self._hostport + '/' + self.path
1727 1734 elif (self.host is not None and self.path
1728 1735 and not hasdriveletter(path)):
1729 1736 path = '/' + path
1730 1737 return path
1731 1738 return self._origpath
1732 1739
1733 1740 def hasscheme(path):
1734 1741 return bool(url(path).scheme)
1735 1742
1736 1743 def hasdriveletter(path):
1737 1744 return path and path[1:2] == ':' and path[0:1].isalpha()
1738 1745
1739 1746 def urllocalpath(path):
1740 1747 return url(path, parsequery=False, parsefragment=False).localpath()
1741 1748
1742 1749 def hidepassword(u):
1743 1750 '''hide user credential in a url string'''
1744 1751 u = url(u)
1745 1752 if u.passwd:
1746 1753 u.passwd = '***'
1747 1754 return str(u)
1748 1755
1749 1756 def removeauth(u):
1750 1757 '''remove all authentication information from a url string'''
1751 1758 u = url(u)
1752 1759 u.user = u.passwd = None
1753 1760 return str(u)
1754 1761
1755 1762 def isatty(fd):
1756 1763 try:
1757 1764 return fd.isatty()
1758 1765 except AttributeError:
1759 1766 return False
@@ -1,489 +1,495 b''
1 1 #
2 2 # This is the mercurial setup script.
3 3 #
4 4 # 'python setup.py install', or
5 5 # 'python setup.py --help' for more options
6 6
7 7 import sys, platform
8 8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10 10
11 11 if sys.version_info[0] >= 3:
12 12 def b(s):
13 13 '''A helper function to emulate 2.6+ bytes literals using string
14 14 literals.'''
15 15 return s.encode('latin1')
16 16 else:
17 17 def b(s):
18 18 '''A helper function to emulate 2.6+ bytes literals using string
19 19 literals.'''
20 20 return s
21 21
22 22 # Solaris Python packaging brain damage
23 23 try:
24 24 import hashlib
25 25 sha = hashlib.sha1()
26 26 except:
27 27 try:
28 28 import sha
29 29 except:
30 30 raise SystemExit(
31 31 "Couldn't import standard hashlib (incomplete Python install).")
32 32
33 33 try:
34 34 import zlib
35 35 except:
36 36 raise SystemExit(
37 37 "Couldn't import standard zlib (incomplete Python install).")
38 38
39 39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 40 isironpython = False
41 41 try:
42 42 isironpython = platform.python_implementation().lower().find("ironpython") != -1
43 43 except:
44 44 pass
45 45
46 46 if isironpython:
47 47 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
48 48 else:
49 49 try:
50 50 import bz2
51 51 except:
52 52 raise SystemExit(
53 53 "Couldn't import standard bz2 (incomplete Python install).")
54 54
55 55 import os, subprocess, time
56 56 import shutil
57 57 import tempfile
58 58 from distutils import log
59 59 from distutils.core import setup, Command, Extension
60 60 from distutils.dist import Distribution
61 61 from distutils.command.build import build
62 62 from distutils.command.build_ext import build_ext
63 63 from distutils.command.build_py import build_py
64 64 from distutils.command.install_scripts import install_scripts
65 65 from distutils.spawn import spawn, find_executable
66 66 from distutils.ccompiler import new_compiler
67 67 from distutils.errors import CCompilerError, DistutilsExecError
68 68 from distutils.sysconfig import get_python_inc
69 69 from distutils.version import StrictVersion
70 70
71 71 convert2to3 = '--c2to3' in sys.argv
72 72 if convert2to3:
73 73 try:
74 74 from distutils.command.build_py import build_py_2to3 as build_py
75 75 from lib2to3.refactor import get_fixers_from_package as getfixers
76 76 except ImportError:
77 77 if sys.version_info[0] < 3:
78 78 raise SystemExit("--c2to3 is only compatible with python3.")
79 79 raise
80 80 sys.path.append('contrib')
81 81 elif sys.version_info[0] >= 3:
82 82 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
83 83
84 84 scripts = ['hg']
85 85 if os.name == 'nt':
86 86 scripts.append('contrib/win32/hg.bat')
87 87
88 88 # simplified version of distutils.ccompiler.CCompiler.has_function
89 89 # that actually removes its temporary files.
90 90 def hasfunction(cc, funcname):
91 91 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
92 92 devnull = oldstderr = None
93 93 try:
94 94 try:
95 95 fname = os.path.join(tmpdir, 'funcname.c')
96 96 f = open(fname, 'w')
97 97 f.write('int main(void) {\n')
98 98 f.write(' %s();\n' % funcname)
99 99 f.write('}\n')
100 100 f.close()
101 101 # Redirect stderr to /dev/null to hide any error messages
102 102 # from the compiler.
103 103 # This will have to be changed if we ever have to check
104 104 # for a function on Windows.
105 105 devnull = open('/dev/null', 'w')
106 106 oldstderr = os.dup(sys.stderr.fileno())
107 107 os.dup2(devnull.fileno(), sys.stderr.fileno())
108 108 objects = cc.compile([fname], output_dir=tmpdir)
109 109 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
110 110 except:
111 111 return False
112 112 return True
113 113 finally:
114 114 if oldstderr is not None:
115 115 os.dup2(oldstderr, sys.stderr.fileno())
116 116 if devnull is not None:
117 117 devnull.close()
118 118 shutil.rmtree(tmpdir)
119 119
120 120 # py2exe needs to be installed to work
121 121 try:
122 122 import py2exe
123 123 py2exeloaded = True
124 124 # import py2exe's patched Distribution class
125 125 from distutils.core import Distribution
126 126 except ImportError:
127 127 py2exeloaded = False
128 128
129 129 def runcmd(cmd, env):
130 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
131 stderr=subprocess.PIPE, env=env)
132 out, err = p.communicate()
133 return out, err
130 if sys.platform == 'plan9':
131 # subprocess kludge to work around issues in half-baked Python
132 # ports, notably bichued/python:
133 _, out, err = os.popen3(cmd)
134 return str(out), str(err)
135 else:
136 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
137 stderr=subprocess.PIPE, env=env)
138 out, err = p.communicate()
139 return out, err
134 140
135 141 def runhg(cmd, env):
136 142 out, err = runcmd(cmd, env)
137 143 # If root is executing setup.py, but the repository is owned by
138 144 # another user (as in "sudo python setup.py install") we will get
139 145 # trust warnings since the .hg/hgrc file is untrusted. That is
140 146 # fine, we don't want to load it anyway. Python may warn about
141 147 # a missing __init__.py in mercurial/locale, we also ignore that.
142 148 err = [e for e in err.splitlines()
143 149 if not e.startswith(b('Not trusting file')) \
144 150 and not e.startswith(b('warning: Not importing'))]
145 151 if err:
146 152 return ''
147 153 return out
148 154
149 155 version = ''
150 156
151 157 # Execute hg out of this directory with a custom environment which
152 158 # includes the pure Python modules in mercurial/pure. We also take
153 159 # care to not use any hgrc files and do no localization.
154 160 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
155 161 env = {'PYTHONPATH': os.pathsep.join(pypath),
156 162 'HGRCPATH': '',
157 163 'LANGUAGE': 'C'}
158 164 if 'LD_LIBRARY_PATH' in os.environ:
159 165 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
160 166 if 'SystemRoot' in os.environ:
161 167 # Copy SystemRoot into the custom environment for Python 2.6
162 168 # under Windows. Otherwise, the subprocess will fail with
163 169 # error 0xc0150004. See: http://bugs.python.org/issue3440
164 170 env['SystemRoot'] = os.environ['SystemRoot']
165 171
166 172 if os.path.isdir('.hg'):
167 173 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
168 174 l = runhg(cmd, env).split()
169 175 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
170 176 l.pop()
171 177 if len(l) > 1: # tag found
172 178 version = l[-1]
173 179 if l[0].endswith('+'): # propagate the dirty status to the tag
174 180 version += '+'
175 181 elif len(l) == 1: # no tag found
176 182 cmd = [sys.executable, 'hg', 'parents', '--template',
177 183 '{latesttag}+{latesttagdistance}-']
178 184 version = runhg(cmd, env) + l[0]
179 185 if version.endswith('+'):
180 186 version += time.strftime('%Y%m%d')
181 187 elif os.path.exists('.hg_archival.txt'):
182 188 kw = dict([[t.strip() for t in l.split(':', 1)]
183 189 for l in open('.hg_archival.txt')])
184 190 if 'tag' in kw:
185 191 version = kw['tag']
186 192 elif 'latesttag' in kw:
187 193 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
188 194 else:
189 195 version = kw.get('node', '')[:12]
190 196
191 197 if version:
192 198 f = open("mercurial/__version__.py", "w")
193 199 f.write('# this file is autogenerated by setup.py\n')
194 200 f.write('version = "%s"\n' % version)
195 201 f.close()
196 202
197 203
198 204 try:
199 205 from mercurial import __version__
200 206 version = __version__.version
201 207 except ImportError:
202 208 version = 'unknown'
203 209
204 210 class hgbuild(build):
205 211 # Insert hgbuildmo first so that files in mercurial/locale/ are found
206 212 # when build_py is run next.
207 213 sub_commands = [('build_mo', None),
208 214 # We also need build_ext before build_py. Otherwise, when 2to3 is called (in
209 215 # build_py), it will not find osutil & friends, thinking that those modules are
210 216 # global and, consequently, making a mess, now that all module imports are
211 217 # global.
212 218 ('build_ext', build.has_ext_modules),
213 219 ] + build.sub_commands
214 220
215 221 class hgbuildmo(build):
216 222
217 223 description = "build translations (.mo files)"
218 224
219 225 def run(self):
220 226 if not find_executable('msgfmt'):
221 227 self.warn("could not find msgfmt executable, no translations "
222 228 "will be built")
223 229 return
224 230
225 231 podir = 'i18n'
226 232 if not os.path.isdir(podir):
227 233 self.warn("could not find %s/ directory" % podir)
228 234 return
229 235
230 236 join = os.path.join
231 237 for po in os.listdir(podir):
232 238 if not po.endswith('.po'):
233 239 continue
234 240 pofile = join(podir, po)
235 241 modir = join('locale', po[:-3], 'LC_MESSAGES')
236 242 mofile = join(modir, 'hg.mo')
237 243 mobuildfile = join('mercurial', mofile)
238 244 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
239 245 if sys.platform != 'sunos5':
240 246 # msgfmt on Solaris does not know about -c
241 247 cmd.append('-c')
242 248 self.mkpath(join('mercurial', modir))
243 249 self.make_file([pofile], mobuildfile, spawn, (cmd,))
244 250
245 251
246 252 class hgdist(Distribution):
247 253 pure = 0
248 254
249 255 global_options = Distribution.global_options + \
250 256 [('pure', None, "use pure (slow) Python "
251 257 "code instead of C extensions"),
252 258 ('c2to3', None, "(experimental!) convert "
253 259 "code with 2to3"),
254 260 ]
255 261
256 262 def has_ext_modules(self):
257 263 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
258 264 # too late for some cases
259 265 return not self.pure and Distribution.has_ext_modules(self)
260 266
261 267 class hgbuildext(build_ext):
262 268
263 269 def build_extension(self, ext):
264 270 try:
265 271 build_ext.build_extension(self, ext)
266 272 except CCompilerError:
267 273 if not getattr(ext, 'optional', False):
268 274 raise
269 275 log.warn("Failed to build optional extension '%s' (skipping)",
270 276 ext.name)
271 277
272 278 class hgbuildpy(build_py):
273 279 if convert2to3:
274 280 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
275 281 getfixers("hgfixes")))
276 282
277 283 def finalize_options(self):
278 284 build_py.finalize_options(self)
279 285
280 286 if self.distribution.pure:
281 287 if self.py_modules is None:
282 288 self.py_modules = []
283 289 for ext in self.distribution.ext_modules:
284 290 if ext.name.startswith("mercurial."):
285 291 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
286 292 self.distribution.ext_modules = []
287 293 else:
288 294 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
289 295 raise SystemExit("Python headers are required to build Mercurial")
290 296
291 297 def find_modules(self):
292 298 modules = build_py.find_modules(self)
293 299 for module in modules:
294 300 if module[0] == "mercurial.pure":
295 301 if module[1] != "__init__":
296 302 yield ("mercurial", module[1], module[2])
297 303 else:
298 304 yield module
299 305
300 306 class buildhgextindex(Command):
301 307 description = 'generate prebuilt index of hgext (for frozen package)'
302 308 user_options = []
303 309 _indexfilename = 'hgext/__index__.py'
304 310
305 311 def initialize_options(self):
306 312 pass
307 313
308 314 def finalize_options(self):
309 315 pass
310 316
311 317 def run(self):
312 318 if os.path.exists(self._indexfilename):
313 319 os.unlink(self._indexfilename)
314 320
315 321 # here no extension enabled, disabled() lists up everything
316 322 code = ('import pprint; from mercurial import extensions; '
317 323 'pprint.pprint(extensions.disabled())')
318 324 out, err = runcmd([sys.executable, '-c', code], env)
319 325 if err:
320 326 raise DistutilsExecError(err)
321 327
322 328 f = open(self._indexfilename, 'w')
323 329 f.write('# this file is autogenerated by setup.py\n')
324 330 f.write('docs = ')
325 331 f.write(out)
326 332 f.close()
327 333
328 334 class hginstallscripts(install_scripts):
329 335 '''
330 336 This is a specialization of install_scripts that replaces the @LIBDIR@ with
331 337 the configured directory for modules. If possible, the path is made relative
332 338 to the directory for scripts.
333 339 '''
334 340
335 341 def initialize_options(self):
336 342 install_scripts.initialize_options(self)
337 343
338 344 self.install_lib = None
339 345
340 346 def finalize_options(self):
341 347 install_scripts.finalize_options(self)
342 348 self.set_undefined_options('install',
343 349 ('install_lib', 'install_lib'))
344 350
345 351 def run(self):
346 352 install_scripts.run(self)
347 353
348 354 if (os.path.splitdrive(self.install_dir)[0] !=
349 355 os.path.splitdrive(self.install_lib)[0]):
350 356 # can't make relative paths from one drive to another, so use an
351 357 # absolute path instead
352 358 libdir = self.install_lib
353 359 else:
354 360 common = os.path.commonprefix((self.install_dir, self.install_lib))
355 361 rest = self.install_dir[len(common):]
356 362 uplevel = len([n for n in os.path.split(rest) if n])
357 363
358 364 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
359 365
360 366 for outfile in self.outfiles:
361 367 fp = open(outfile, 'rb')
362 368 data = fp.read()
363 369 fp.close()
364 370
365 371 # skip binary files
366 372 if b('\0') in data:
367 373 continue
368 374
369 375 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
370 376 fp = open(outfile, 'wb')
371 377 fp.write(data)
372 378 fp.close()
373 379
374 380 cmdclass = {'build': hgbuild,
375 381 'build_mo': hgbuildmo,
376 382 'build_ext': hgbuildext,
377 383 'build_py': hgbuildpy,
378 384 'build_hgextindex': buildhgextindex,
379 385 'install_scripts': hginstallscripts}
380 386
381 387 packages = ['mercurial', 'mercurial.hgweb',
382 388 'mercurial.httpclient', 'mercurial.httpclient.tests',
383 389 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
384 390 'hgext.largefiles']
385 391
386 392 pymodules = []
387 393
388 394 extmodules = [
389 395 Extension('mercurial.base85', ['mercurial/base85.c']),
390 396 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
391 397 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
392 398 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
393 399 Extension('mercurial.parsers', ['mercurial/parsers.c']),
394 400 ]
395 401
396 402 osutil_ldflags = []
397 403
398 404 if sys.platform == 'darwin':
399 405 osutil_ldflags += ['-framework', 'ApplicationServices']
400 406
401 407 # disable osutil.c under windows + python 2.4 (issue1364)
402 408 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
403 409 pymodules.append('mercurial.pure.osutil')
404 410 else:
405 411 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
406 412 extra_link_args=osutil_ldflags))
407 413
408 414 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
409 415 # The inotify extension is only usable with Linux 2.6 kernels.
410 416 # You also need a reasonably recent C library.
411 417 # In any case, if it fails to build the error will be skipped ('optional').
412 418 cc = new_compiler()
413 419 if hasfunction(cc, 'inotify_add_watch'):
414 420 inotify = Extension('hgext.inotify.linux._inotify',
415 421 ['hgext/inotify/linux/_inotify.c'],
416 422 ['mercurial'])
417 423 inotify.optional = True
418 424 extmodules.append(inotify)
419 425 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
420 426
421 427 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
422 428 'help/*.txt']}
423 429
424 430 def ordinarypath(p):
425 431 return p and p[0] != '.' and p[-1] != '~'
426 432
427 433 for root in ('templates',):
428 434 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
429 435 curdir = curdir.split(os.sep, 1)[1]
430 436 dirs[:] = filter(ordinarypath, dirs)
431 437 for f in filter(ordinarypath, files):
432 438 f = os.path.join(curdir, f)
433 439 packagedata['mercurial'].append(f)
434 440
435 441 datafiles = []
436 442 setupversion = version
437 443 extra = {}
438 444
439 445 if py2exeloaded:
440 446 extra['console'] = [
441 447 {'script':'hg',
442 448 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
443 449 'product_version':version}]
444 450 # sub command of 'build' because 'py2exe' does not handle sub_commands
445 451 build.sub_commands.insert(0, ('build_hgextindex', None))
446 452
447 453 if os.name == 'nt':
448 454 # Windows binary file versions for exe/dll files must have the
449 455 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
450 456 setupversion = version.split('+', 1)[0]
451 457
452 458 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
453 459 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
454 460 # distutils.sysconfig
455 461 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
456 462 if version:
457 463 version = version[0]
458 464 xcode4 = (version.startswith('Xcode') and
459 465 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
460 466 else:
461 467 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
462 468 # installed, but instead with only command-line tools. Assume
463 469 # that only happens on >= Lion, thus no PPC support.
464 470 xcode4 = True
465 471
466 472 if xcode4:
467 473 os.environ['ARCHFLAGS'] = ''
468 474
469 475 setup(name='mercurial',
470 476 version=setupversion,
471 477 author='Matt Mackall',
472 478 author_email='mpm@selenic.com',
473 479 url='http://mercurial.selenic.com/',
474 480 description='Scalable distributed SCM',
475 481 license='GNU GPLv2+',
476 482 scripts=scripts,
477 483 packages=packages,
478 484 py_modules=pymodules,
479 485 ext_modules=extmodules,
480 486 data_files=datafiles,
481 487 package_data=packagedata,
482 488 cmdclass=cmdclass,
483 489 distclass=hgdist,
484 490 options=dict(py2exe=dict(packages=['hgext', 'email']),
485 491 bdist_mpkg=dict(zipdist=True,
486 492 license='COPYING',
487 493 readme='contrib/macosx/Readme.html',
488 494 welcome='contrib/macosx/Welcome.html')),
489 495 **extra)
@@ -1,36 +1,36 b''
1 1 import os
2 2 from mercurial import ui, commands, extensions
3 3
4 ignore = set(['highlight', 'inotify', 'win32text'])
4 ignore = set(['highlight', 'inotify', 'win32text', 'factotum'])
5 5
6 6 if os.name != 'nt':
7 7 ignore.add('win32mbcs')
8 8
9 9 disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
10 10
11 11 hgrc = open(os.environ["HGRCPATH"], 'w')
12 12 hgrc.write('[extensions]\n')
13 13
14 14 for ext in disabled:
15 15 hgrc.write(ext + '=\n')
16 16
17 17 hgrc.close()
18 18
19 19 u = ui.ui()
20 20 extensions.loadall(u)
21 21
22 22 globalshort = set()
23 23 globallong = set()
24 24 for option in commands.globalopts:
25 25 option[0] and globalshort.add(option[0])
26 26 option[1] and globallong.add(option[1])
27 27
28 28 for cmd, entry in commands.table.iteritems():
29 29 seenshort = globalshort.copy()
30 30 seenlong = globallong.copy()
31 31 for option in entry[1]:
32 32 if (option[0] and option[0] in seenshort) or \
33 33 (option[1] and option[1] in seenlong):
34 34 print "command '" + cmd + "' has duplicate option " + str(option)
35 35 seenshort.add(option[0])
36 36 seenlong.add(option[1])
General Comments 0
You need to be logged in to leave comments. Login now