##// 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 The Mercurial system uses a set of configuration files to control
1 The Mercurial system uses a set of configuration files to control
2 aspects of its behavior.
2 aspects of its behavior.
3
3
4 The configuration files use a simple ini-file format. A configuration
4 The configuration files use a simple ini-file format. A configuration
5 file consists of sections, led by a ``[section]`` header and followed
5 file consists of sections, led by a ``[section]`` header and followed
6 by ``name = value`` entries::
6 by ``name = value`` entries::
7
7
8 [ui]
8 [ui]
9 username = Firstname Lastname <firstname.lastname@example.net>
9 username = Firstname Lastname <firstname.lastname@example.net>
10 verbose = True
10 verbose = True
11
11
12 The above entries will be referred to as ``ui.username`` and
12 The above entries will be referred to as ``ui.username`` and
13 ``ui.verbose``, respectively. See the Syntax section below.
13 ``ui.verbose``, respectively. See the Syntax section below.
14
14
15 Files
15 Files
16 -----
16 -----
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 These files do not exist by default and you will have to create the
19 These files do not exist by default and you will have to create the
20 appropriate configuration files yourself: global configuration like
20 appropriate configuration files yourself: global configuration like
21 the username setting is typically put into
21 the username setting is typically put into
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
22 ``%USERPROFILE%\mercurial.ini`` or ``$HOME/.hgrc`` and local
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
23 configuration is put into the per-repository ``<repo>/.hg/hgrc`` file.
24
24
25 The names of these files depend on the system on which Mercurial is
25 The names of these files depend on the system on which Mercurial is
26 installed. ``*.rc`` files from a single directory are read in
26 installed. ``*.rc`` files from a single directory are read in
27 alphabetical order, later ones overriding earlier ones. Where multiple
27 alphabetical order, later ones overriding earlier ones. Where multiple
28 paths are given below, settings from earlier paths override later
28 paths are given below, settings from earlier paths override later
29 ones.
29 ones.
30
30
31 | (Unix, Windows) ``<repo>/.hg/hgrc``
31 | (All) ``<repo>/.hg/hgrc``
32
32
33 Per-repository configuration options that only apply in a
33 Per-repository configuration options that only apply in a
34 particular repository. This file is not version-controlled, and
34 particular repository. This file is not version-controlled, and
35 will not get transferred during a "clone" operation. Options in
35 will not get transferred during a "clone" operation. Options in
36 this file override options in all other configuration files. On
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
37 Plan 9 and Unix, most of this file will be ignored if it doesn't
38 trusted user or to a trusted group. See the documentation for the
38 belong to a trusted user or to a trusted group. See the documentation
39 ``[trusted]`` section below for more details.
39 for the ``[trusted]`` section below for more details.
40
40
41 | (Plan 9) ``$home/lib/hgrc``
41 | (Unix) ``$HOME/.hgrc``
42 | (Unix) ``$HOME/.hgrc``
42 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\.hgrc``
43 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%USERPROFILE%\Mercurial.ini``
44 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\.hgrc``
45 | (Windows) ``%HOME%\Mercurial.ini``
46 | (Windows) ``%HOME%\Mercurial.ini``
46
47
47 Per-user configuration file(s), for the user running Mercurial. On
48 Per-user configuration file(s), for the user running Mercurial. On
48 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
49 files apply to all Mercurial commands executed by this user in any
50 files apply to all Mercurial commands executed by this user in any
50 directory. Options in these files override per-system and per-installation
51 directory. Options in these files override per-system and per-installation
51 options.
52 options.
52
53
54 | (Plan 9) ``/lib/mercurial/hgrc``
55 | (Plan 9) ``/lib/mercurial/hgrc.d/*.rc``
53 | (Unix) ``/etc/mercurial/hgrc``
56 | (Unix) ``/etc/mercurial/hgrc``
54 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
57 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
55
58
56 Per-system configuration files, for the system on which Mercurial
59 Per-system configuration files, for the system on which Mercurial
57 is running. Options in these files apply to all Mercurial commands
60 is running. Options in these files apply to all Mercurial commands
58 executed by any user in any directory. Options in these files
61 executed by any user in any directory. Options in these files
59 override per-installation options.
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 | (Unix) ``<install-root>/etc/mercurial/hgrc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc``
62 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
67 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
63
68
64 Per-installation configuration files, searched for in the
69 Per-installation configuration files, searched for in the
65 directory where Mercurial is installed. ``<install-root>`` is the
70 directory where Mercurial is installed. ``<install-root>`` is the
66 parent directory of the **hg** executable (or symlink) being run. For
71 parent directory of the **hg** executable (or symlink) being run. For
67 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
72 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
68 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
73 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
69 to all Mercurial commands executed by any user in any directory.
74 to all Mercurial commands executed by any user in any directory.
70
75
71 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
76 | (Windows) ``<install-dir>\Mercurial.ini`` **or**
72 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
77 | (Windows) ``<install-dir>\hgrc.d\*.rc`` **or**
73 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
78 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
74
79
75 Per-installation/system configuration files, for the system on
80 Per-installation/system configuration files, for the system on
76 which Mercurial is running. Options in these files apply to all
81 which Mercurial is running. Options in these files apply to all
77 Mercurial commands executed by any user in any directory. Registry
82 Mercurial commands executed by any user in any directory. Registry
78 keys contain PATH-like strings, every part of which must reference
83 keys contain PATH-like strings, every part of which must reference
79 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
84 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
80 be read. Mercurial checks each of these locations in the specified
85 be read. Mercurial checks each of these locations in the specified
81 order until one or more configuration files are detected. If the
86 order until one or more configuration files are detected. If the
82 pywin32 extensions are not installed, Mercurial will only look for
87 pywin32 extensions are not installed, Mercurial will only look for
83 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
88 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
84
89
85 Syntax
90 Syntax
86 ------
91 ------
87
92
88 A configuration file consists of sections, led by a ``[section]`` header
93 A configuration file consists of sections, led by a ``[section]`` header
89 and followed by ``name = value`` entries (sometimes called
94 and followed by ``name = value`` entries (sometimes called
90 ``configuration keys``)::
95 ``configuration keys``)::
91
96
92 [spam]
97 [spam]
93 eggs=ham
98 eggs=ham
94 green=
99 green=
95 eggs
100 eggs
96
101
97 Each line contains one entry. If the lines that follow are indented,
102 Each line contains one entry. If the lines that follow are indented,
98 they are treated as continuations of that entry. Leading whitespace is
103 they are treated as continuations of that entry. Leading whitespace is
99 removed from values. Empty lines are skipped. Lines beginning with
104 removed from values. Empty lines are skipped. Lines beginning with
100 ``#`` or ``;`` are ignored and may be used to provide comments.
105 ``#`` or ``;`` are ignored and may be used to provide comments.
101
106
102 Configuration keys can be set multiple times, in which case Mercurial
107 Configuration keys can be set multiple times, in which case Mercurial
103 will use the value that was configured last. As an example::
108 will use the value that was configured last. As an example::
104
109
105 [spam]
110 [spam]
106 eggs=large
111 eggs=large
107 ham=serrano
112 ham=serrano
108 eggs=small
113 eggs=small
109
114
110 This would set the configuration key named ``eggs`` to ``small``.
115 This would set the configuration key named ``eggs`` to ``small``.
111
116
112 It is also possible to define a section multiple times. A section can
117 It is also possible to define a section multiple times. A section can
113 be redefined on the same and/or on different configuration files. For
118 be redefined on the same and/or on different configuration files. For
114 example::
119 example::
115
120
116 [foo]
121 [foo]
117 eggs=large
122 eggs=large
118 ham=serrano
123 ham=serrano
119 eggs=small
124 eggs=small
120
125
121 [bar]
126 [bar]
122 eggs=ham
127 eggs=ham
123 green=
128 green=
124 eggs
129 eggs
125
130
126 [foo]
131 [foo]
127 ham=prosciutto
132 ham=prosciutto
128 eggs=medium
133 eggs=medium
129 bread=toasted
134 bread=toasted
130
135
131 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
136 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
132 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
137 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
133 respectively. As you can see there only thing that matters is the last
138 respectively. As you can see there only thing that matters is the last
134 value that was set for each of the configuration keys.
139 value that was set for each of the configuration keys.
135
140
136 If a configuration key is set multiple times in different
141 If a configuration key is set multiple times in different
137 configuration files the final value will depend on the order in which
142 configuration files the final value will depend on the order in which
138 the different configuration files are read, with settings from earlier
143 the different configuration files are read, with settings from earlier
139 paths overriding later ones as described on the ``Files`` section
144 paths overriding later ones as described on the ``Files`` section
140 above.
145 above.
141
146
142 A line of the form ``%include file`` will include ``file`` into the
147 A line of the form ``%include file`` will include ``file`` into the
143 current configuration file. The inclusion is recursive, which means
148 current configuration file. The inclusion is recursive, which means
144 that included files can include other files. Filenames are relative to
149 that included files can include other files. Filenames are relative to
145 the configuration file in which the ``%include`` directive is found.
150 the configuration file in which the ``%include`` directive is found.
146 Environment variables and ``~user`` constructs are expanded in
151 Environment variables and ``~user`` constructs are expanded in
147 ``file``. This lets you do something like::
152 ``file``. This lets you do something like::
148
153
149 %include ~/.hgrc.d/$HOST.rc
154 %include ~/.hgrc.d/$HOST.rc
150
155
151 to include a different configuration file on each computer you use.
156 to include a different configuration file on each computer you use.
152
157
153 A line with ``%unset name`` will remove ``name`` from the current
158 A line with ``%unset name`` will remove ``name`` from the current
154 section, if it has been set previously.
159 section, if it has been set previously.
155
160
156 The values are either free-form text strings, lists of text strings,
161 The values are either free-form text strings, lists of text strings,
157 or Boolean values. Boolean values can be set to true using any of "1",
162 or Boolean values. Boolean values can be set to true using any of "1",
158 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
163 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
159 (all case insensitive).
164 (all case insensitive).
160
165
161 List values are separated by whitespace or comma, except when values are
166 List values are separated by whitespace or comma, except when values are
162 placed in double quotation marks::
167 placed in double quotation marks::
163
168
164 allow_read = "John Doe, PhD", brian, betty
169 allow_read = "John Doe, PhD", brian, betty
165
170
166 Quotation marks can be escaped by prefixing them with a backslash. Only
171 Quotation marks can be escaped by prefixing them with a backslash. Only
167 quotation marks at the beginning of a word is counted as a quotation
172 quotation marks at the beginning of a word is counted as a quotation
168 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
173 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
169
174
170 Sections
175 Sections
171 --------
176 --------
172
177
173 This section describes the different sections that may appear in a
178 This section describes the different sections that may appear in a
174 Mercurial configuration file, the purpose of each section, its possible
179 Mercurial configuration file, the purpose of each section, its possible
175 keys, and their possible values.
180 keys, and their possible values.
176
181
177 ``alias``
182 ``alias``
178 """""""""
183 """""""""
179
184
180 Defines command aliases.
185 Defines command aliases.
181 Aliases allow you to define your own commands in terms of other
186 Aliases allow you to define your own commands in terms of other
182 commands (or aliases), optionally including arguments. Positional
187 commands (or aliases), optionally including arguments. Positional
183 arguments in the form of ``$1``, ``$2``, etc in the alias definition
188 arguments in the form of ``$1``, ``$2``, etc in the alias definition
184 are expanded by Mercurial before execution. Positional arguments not
189 are expanded by Mercurial before execution. Positional arguments not
185 already used by ``$N`` in the definition are put at the end of the
190 already used by ``$N`` in the definition are put at the end of the
186 command to be executed.
191 command to be executed.
187
192
188 Alias definitions consist of lines of the form::
193 Alias definitions consist of lines of the form::
189
194
190 <alias> = <command> [<argument>]...
195 <alias> = <command> [<argument>]...
191
196
192 For example, this definition::
197 For example, this definition::
193
198
194 latest = log --limit 5
199 latest = log --limit 5
195
200
196 creates a new command ``latest`` that shows only the five most recent
201 creates a new command ``latest`` that shows only the five most recent
197 changesets. You can define subsequent aliases using earlier ones::
202 changesets. You can define subsequent aliases using earlier ones::
198
203
199 stable5 = latest -b stable
204 stable5 = latest -b stable
200
205
201 .. note:: It is possible to create aliases with the same names as
206 .. note:: It is possible to create aliases with the same names as
202 existing commands, which will then override the original
207 existing commands, which will then override the original
203 definitions. This is almost always a bad idea!
208 definitions. This is almost always a bad idea!
204
209
205 An alias can start with an exclamation point (``!``) to make it a
210 An alias can start with an exclamation point (``!``) to make it a
206 shell alias. A shell alias is executed with the shell and will let you
211 shell alias. A shell alias is executed with the shell and will let you
207 run arbitrary commands. As an example, ::
212 run arbitrary commands. As an example, ::
208
213
209 echo = !echo
214 echo = !echo
210
215
211 will let you do ``hg echo foo`` to have ``foo`` printed in your
216 will let you do ``hg echo foo`` to have ``foo`` printed in your
212 terminal. A better example might be::
217 terminal. A better example might be::
213
218
214 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
219 purge = !$HG status --no-status --unknown -0 | xargs -0 rm
215
220
216 which will make ``hg purge`` delete all unknown files in the
221 which will make ``hg purge`` delete all unknown files in the
217 repository in the same manner as the purge extension.
222 repository in the same manner as the purge extension.
218
223
219 Shell aliases are executed in an environment where ``$HG`` expand to
224 Shell aliases are executed in an environment where ``$HG`` expand to
220 the path of the Mercurial that was used to execute the alias. This is
225 the path of the Mercurial that was used to execute the alias. This is
221 useful when you want to call further Mercurial commands in a shell
226 useful when you want to call further Mercurial commands in a shell
222 alias, as was done above for the purge alias. In addition,
227 alias, as was done above for the purge alias. In addition,
223 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
228 ``$HG_ARGS`` expand to the arguments given to Mercurial. In the ``hg
224 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
229 echo foo`` call above, ``$HG_ARGS`` would expand to ``echo foo``.
225
230
226 .. note:: Some global configuration options such as ``-R`` are
231 .. note:: Some global configuration options such as ``-R`` are
227 processed before shell aliases and will thus not be passed to
232 processed before shell aliases and will thus not be passed to
228 aliases.
233 aliases.
229
234
230
235
231 ``annotate``
236 ``annotate``
232 """"""""""""
237 """"""""""""
233
238
234 Settings used when displaying file annotations. All values are
239 Settings used when displaying file annotations. All values are
235 Booleans and default to False. See ``diff`` section for related
240 Booleans and default to False. See ``diff`` section for related
236 options for the diff command.
241 options for the diff command.
237
242
238 ``ignorews``
243 ``ignorews``
239 Ignore white space when comparing lines.
244 Ignore white space when comparing lines.
240
245
241 ``ignorewsamount``
246 ``ignorewsamount``
242 Ignore changes in the amount of white space.
247 Ignore changes in the amount of white space.
243
248
244 ``ignoreblanklines``
249 ``ignoreblanklines``
245 Ignore changes whose lines are all blank.
250 Ignore changes whose lines are all blank.
246
251
247
252
248 ``auth``
253 ``auth``
249 """"""""
254 """"""""
250
255
251 Authentication credentials for HTTP authentication. This section
256 Authentication credentials for HTTP authentication. This section
252 allows you to store usernames and passwords for use when logging
257 allows you to store usernames and passwords for use when logging
253 *into* HTTP servers. See the ``[web]`` configuration section if
258 *into* HTTP servers. See the ``[web]`` configuration section if
254 you want to configure *who* can login to your HTTP server.
259 you want to configure *who* can login to your HTTP server.
255
260
256 Each line has the following format::
261 Each line has the following format::
257
262
258 <name>.<argument> = <value>
263 <name>.<argument> = <value>
259
264
260 where ``<name>`` is used to group arguments into authentication
265 where ``<name>`` is used to group arguments into authentication
261 entries. Example::
266 entries. Example::
262
267
263 foo.prefix = hg.intevation.org/mercurial
268 foo.prefix = hg.intevation.org/mercurial
264 foo.username = foo
269 foo.username = foo
265 foo.password = bar
270 foo.password = bar
266 foo.schemes = http https
271 foo.schemes = http https
267
272
268 bar.prefix = secure.example.org
273 bar.prefix = secure.example.org
269 bar.key = path/to/file.key
274 bar.key = path/to/file.key
270 bar.cert = path/to/file.cert
275 bar.cert = path/to/file.cert
271 bar.schemes = https
276 bar.schemes = https
272
277
273 Supported arguments:
278 Supported arguments:
274
279
275 ``prefix``
280 ``prefix``
276 Either ``*`` or a URI prefix with or without the scheme part.
281 Either ``*`` or a URI prefix with or without the scheme part.
277 The authentication entry with the longest matching prefix is used
282 The authentication entry with the longest matching prefix is used
278 (where ``*`` matches everything and counts as a match of length
283 (where ``*`` matches everything and counts as a match of length
279 1). If the prefix doesn't include a scheme, the match is performed
284 1). If the prefix doesn't include a scheme, the match is performed
280 against the URI with its scheme stripped as well, and the schemes
285 against the URI with its scheme stripped as well, and the schemes
281 argument, q.v., is then subsequently consulted.
286 argument, q.v., is then subsequently consulted.
282
287
283 ``username``
288 ``username``
284 Optional. Username to authenticate with. If not given, and the
289 Optional. Username to authenticate with. If not given, and the
285 remote site requires basic or digest authentication, the user will
290 remote site requires basic or digest authentication, the user will
286 be prompted for it. Environment variables are expanded in the
291 be prompted for it. Environment variables are expanded in the
287 username letting you do ``foo.username = $USER``. If the URI
292 username letting you do ``foo.username = $USER``. If the URI
288 includes a username, only ``[auth]`` entries with a matching
293 includes a username, only ``[auth]`` entries with a matching
289 username or without a username will be considered.
294 username or without a username will be considered.
290
295
291 ``password``
296 ``password``
292 Optional. Password to authenticate with. If not given, and the
297 Optional. Password to authenticate with. If not given, and the
293 remote site requires basic or digest authentication, the user
298 remote site requires basic or digest authentication, the user
294 will be prompted for it.
299 will be prompted for it.
295
300
296 ``key``
301 ``key``
297 Optional. PEM encoded client certificate key file. Environment
302 Optional. PEM encoded client certificate key file. Environment
298 variables are expanded in the filename.
303 variables are expanded in the filename.
299
304
300 ``cert``
305 ``cert``
301 Optional. PEM encoded client certificate chain file. Environment
306 Optional. PEM encoded client certificate chain file. Environment
302 variables are expanded in the filename.
307 variables are expanded in the filename.
303
308
304 ``schemes``
309 ``schemes``
305 Optional. Space separated list of URI schemes to use this
310 Optional. Space separated list of URI schemes to use this
306 authentication entry with. Only used if the prefix doesn't include
311 authentication entry with. Only used if the prefix doesn't include
307 a scheme. Supported schemes are http and https. They will match
312 a scheme. Supported schemes are http and https. They will match
308 static-http and static-https respectively, as well.
313 static-http and static-https respectively, as well.
309 Default: https.
314 Default: https.
310
315
311 If no suitable authentication entry is found, the user is prompted
316 If no suitable authentication entry is found, the user is prompted
312 for credentials as usual if required by the remote.
317 for credentials as usual if required by the remote.
313
318
314
319
315 ``decode/encode``
320 ``decode/encode``
316 """""""""""""""""
321 """""""""""""""""
317
322
318 Filters for transforming files on checkout/checkin. This would
323 Filters for transforming files on checkout/checkin. This would
319 typically be used for newline processing or other
324 typically be used for newline processing or other
320 localization/canonicalization of files.
325 localization/canonicalization of files.
321
326
322 Filters consist of a filter pattern followed by a filter command.
327 Filters consist of a filter pattern followed by a filter command.
323 Filter patterns are globs by default, rooted at the repository root.
328 Filter patterns are globs by default, rooted at the repository root.
324 For example, to match any file ending in ``.txt`` in the root
329 For example, to match any file ending in ``.txt`` in the root
325 directory only, use the pattern ``*.txt``. To match any file ending
330 directory only, use the pattern ``*.txt``. To match any file ending
326 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
331 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
327 For each file only the first matching filter applies.
332 For each file only the first matching filter applies.
328
333
329 The filter command can start with a specifier, either ``pipe:`` or
334 The filter command can start with a specifier, either ``pipe:`` or
330 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
335 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
331
336
332 A ``pipe:`` command must accept data on stdin and return the transformed
337 A ``pipe:`` command must accept data on stdin and return the transformed
333 data on stdout.
338 data on stdout.
334
339
335 Pipe example::
340 Pipe example::
336
341
337 [encode]
342 [encode]
338 # uncompress gzip files on checkin to improve delta compression
343 # uncompress gzip files on checkin to improve delta compression
339 # note: not necessarily a good idea, just an example
344 # note: not necessarily a good idea, just an example
340 *.gz = pipe: gunzip
345 *.gz = pipe: gunzip
341
346
342 [decode]
347 [decode]
343 # recompress gzip files when writing them to the working dir (we
348 # recompress gzip files when writing them to the working dir (we
344 # can safely omit "pipe:", because it's the default)
349 # can safely omit "pipe:", because it's the default)
345 *.gz = gzip
350 *.gz = gzip
346
351
347 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
352 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
348 with the name of a temporary file that contains the data to be
353 with the name of a temporary file that contains the data to be
349 filtered by the command. The string ``OUTFILE`` is replaced with the name
354 filtered by the command. The string ``OUTFILE`` is replaced with the name
350 of an empty temporary file, where the filtered data must be written by
355 of an empty temporary file, where the filtered data must be written by
351 the command.
356 the command.
352
357
353 .. note:: The tempfile mechanism is recommended for Windows systems,
358 .. note:: The tempfile mechanism is recommended for Windows systems,
354 where the standard shell I/O redirection operators often have
359 where the standard shell I/O redirection operators often have
355 strange effects and may corrupt the contents of your files.
360 strange effects and may corrupt the contents of your files.
356
361
357 This filter mechanism is used internally by the ``eol`` extension to
362 This filter mechanism is used internally by the ``eol`` extension to
358 translate line ending characters between Windows (CRLF) and Unix (LF)
363 translate line ending characters between Windows (CRLF) and Unix (LF)
359 format. We suggest you use the ``eol`` extension for convenience.
364 format. We suggest you use the ``eol`` extension for convenience.
360
365
361
366
362 ``defaults``
367 ``defaults``
363 """"""""""""
368 """"""""""""
364
369
365 (defaults are deprecated. Don't use them. Use aliases instead)
370 (defaults are deprecated. Don't use them. Use aliases instead)
366
371
367 Use the ``[defaults]`` section to define command defaults, i.e. the
372 Use the ``[defaults]`` section to define command defaults, i.e. the
368 default options/arguments to pass to the specified commands.
373 default options/arguments to pass to the specified commands.
369
374
370 The following example makes :hg:`log` run in verbose mode, and
375 The following example makes :hg:`log` run in verbose mode, and
371 :hg:`status` show only the modified files, by default::
376 :hg:`status` show only the modified files, by default::
372
377
373 [defaults]
378 [defaults]
374 log = -v
379 log = -v
375 status = -m
380 status = -m
376
381
377 The actual commands, instead of their aliases, must be used when
382 The actual commands, instead of their aliases, must be used when
378 defining command defaults. The command defaults will also be applied
383 defining command defaults. The command defaults will also be applied
379 to the aliases of the commands defined.
384 to the aliases of the commands defined.
380
385
381
386
382 ``diff``
387 ``diff``
383 """"""""
388 """"""""
384
389
385 Settings used when displaying diffs. Everything except for ``unified``
390 Settings used when displaying diffs. Everything except for ``unified``
386 is a Boolean and defaults to False. See ``annotate`` section for
391 is a Boolean and defaults to False. See ``annotate`` section for
387 related options for the annotate command.
392 related options for the annotate command.
388
393
389 ``git``
394 ``git``
390 Use git extended diff format.
395 Use git extended diff format.
391
396
392 ``nodates``
397 ``nodates``
393 Don't include dates in diff headers.
398 Don't include dates in diff headers.
394
399
395 ``showfunc``
400 ``showfunc``
396 Show which function each change is in.
401 Show which function each change is in.
397
402
398 ``ignorews``
403 ``ignorews``
399 Ignore white space when comparing lines.
404 Ignore white space when comparing lines.
400
405
401 ``ignorewsamount``
406 ``ignorewsamount``
402 Ignore changes in the amount of white space.
407 Ignore changes in the amount of white space.
403
408
404 ``ignoreblanklines``
409 ``ignoreblanklines``
405 Ignore changes whose lines are all blank.
410 Ignore changes whose lines are all blank.
406
411
407 ``unified``
412 ``unified``
408 Number of lines of context to show.
413 Number of lines of context to show.
409
414
410 ``email``
415 ``email``
411 """""""""
416 """""""""
412
417
413 Settings for extensions that send email messages.
418 Settings for extensions that send email messages.
414
419
415 ``from``
420 ``from``
416 Optional. Email address to use in "From" header and SMTP envelope
421 Optional. Email address to use in "From" header and SMTP envelope
417 of outgoing messages.
422 of outgoing messages.
418
423
419 ``to``
424 ``to``
420 Optional. Comma-separated list of recipients' email addresses.
425 Optional. Comma-separated list of recipients' email addresses.
421
426
422 ``cc``
427 ``cc``
423 Optional. Comma-separated list of carbon copy recipients'
428 Optional. Comma-separated list of carbon copy recipients'
424 email addresses.
429 email addresses.
425
430
426 ``bcc``
431 ``bcc``
427 Optional. Comma-separated list of blind carbon copy recipients'
432 Optional. Comma-separated list of blind carbon copy recipients'
428 email addresses.
433 email addresses.
429
434
430 ``method``
435 ``method``
431 Optional. Method to use to send email messages. If value is ``smtp``
436 Optional. Method to use to send email messages. If value is ``smtp``
432 (default), use SMTP (see the ``[smtp]`` section for configuration).
437 (default), use SMTP (see the ``[smtp]`` section for configuration).
433 Otherwise, use as name of program to run that acts like sendmail
438 Otherwise, use as name of program to run that acts like sendmail
434 (takes ``-f`` option for sender, list of recipients on command line,
439 (takes ``-f`` option for sender, list of recipients on command line,
435 message on stdin). Normally, setting this to ``sendmail`` or
440 message on stdin). Normally, setting this to ``sendmail`` or
436 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
441 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
437
442
438 ``charsets``
443 ``charsets``
439 Optional. Comma-separated list of character sets considered
444 Optional. Comma-separated list of character sets considered
440 convenient for recipients. Addresses, headers, and parts not
445 convenient for recipients. Addresses, headers, and parts not
441 containing patches of outgoing messages will be encoded in the
446 containing patches of outgoing messages will be encoded in the
442 first character set to which conversion from local encoding
447 first character set to which conversion from local encoding
443 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
448 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
444 conversion fails, the text in question is sent as is. Defaults to
449 conversion fails, the text in question is sent as is. Defaults to
445 empty (explicit) list.
450 empty (explicit) list.
446
451
447 Order of outgoing email character sets:
452 Order of outgoing email character sets:
448
453
449 1. ``us-ascii``: always first, regardless of settings
454 1. ``us-ascii``: always first, regardless of settings
450 2. ``email.charsets``: in order given by user
455 2. ``email.charsets``: in order given by user
451 3. ``ui.fallbackencoding``: if not in email.charsets
456 3. ``ui.fallbackencoding``: if not in email.charsets
452 4. ``$HGENCODING``: if not in email.charsets
457 4. ``$HGENCODING``: if not in email.charsets
453 5. ``utf-8``: always last, regardless of settings
458 5. ``utf-8``: always last, regardless of settings
454
459
455 Email example::
460 Email example::
456
461
457 [email]
462 [email]
458 from = Joseph User <joe.user@example.com>
463 from = Joseph User <joe.user@example.com>
459 method = /usr/sbin/sendmail
464 method = /usr/sbin/sendmail
460 # charsets for western Europeans
465 # charsets for western Europeans
461 # us-ascii, utf-8 omitted, as they are tried first and last
466 # us-ascii, utf-8 omitted, as they are tried first and last
462 charsets = iso-8859-1, iso-8859-15, windows-1252
467 charsets = iso-8859-1, iso-8859-15, windows-1252
463
468
464
469
465 ``extensions``
470 ``extensions``
466 """"""""""""""
471 """"""""""""""
467
472
468 Mercurial has an extension mechanism for adding new features. To
473 Mercurial has an extension mechanism for adding new features. To
469 enable an extension, create an entry for it in this section.
474 enable an extension, create an entry for it in this section.
470
475
471 If you know that the extension is already in Python's search path,
476 If you know that the extension is already in Python's search path,
472 you can give the name of the module, followed by ``=``, with nothing
477 you can give the name of the module, followed by ``=``, with nothing
473 after the ``=``.
478 after the ``=``.
474
479
475 Otherwise, give a name that you choose, followed by ``=``, followed by
480 Otherwise, give a name that you choose, followed by ``=``, followed by
476 the path to the ``.py`` file (including the file name extension) that
481 the path to the ``.py`` file (including the file name extension) that
477 defines the extension.
482 defines the extension.
478
483
479 To explicitly disable an extension that is enabled in an hgrc of
484 To explicitly disable an extension that is enabled in an hgrc of
480 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
485 broader scope, prepend its path with ``!``, as in ``foo = !/ext/path``
481 or ``foo = !`` when path is not supplied.
486 or ``foo = !`` when path is not supplied.
482
487
483 Example for ``~/.hgrc``::
488 Example for ``~/.hgrc``::
484
489
485 [extensions]
490 [extensions]
486 # (the mq extension will get loaded from Mercurial's path)
491 # (the mq extension will get loaded from Mercurial's path)
487 mq =
492 mq =
488 # (this extension will get loaded from the file specified)
493 # (this extension will get loaded from the file specified)
489 myfeature = ~/.hgext/myfeature.py
494 myfeature = ~/.hgext/myfeature.py
490
495
491
496
492 ``format``
497 ``format``
493 """"""""""
498 """"""""""
494
499
495 ``usestore``
500 ``usestore``
496 Enable or disable the "store" repository format which improves
501 Enable or disable the "store" repository format which improves
497 compatibility with systems that fold case or otherwise mangle
502 compatibility with systems that fold case or otherwise mangle
498 filenames. Enabled by default. Disabling this option will allow
503 filenames. Enabled by default. Disabling this option will allow
499 you to store longer filenames in some situations at the expense of
504 you to store longer filenames in some situations at the expense of
500 compatibility and ensures that the on-disk format of newly created
505 compatibility and ensures that the on-disk format of newly created
501 repositories will be compatible with Mercurial before version 0.9.4.
506 repositories will be compatible with Mercurial before version 0.9.4.
502
507
503 ``usefncache``
508 ``usefncache``
504 Enable or disable the "fncache" repository format which enhances
509 Enable or disable the "fncache" repository format which enhances
505 the "store" repository format (which has to be enabled to use
510 the "store" repository format (which has to be enabled to use
506 fncache) to allow longer filenames and avoids using Windows
511 fncache) to allow longer filenames and avoids using Windows
507 reserved names, e.g. "nul". Enabled by default. Disabling this
512 reserved names, e.g. "nul". Enabled by default. Disabling this
508 option ensures that the on-disk format of newly created
513 option ensures that the on-disk format of newly created
509 repositories will be compatible with Mercurial before version 1.1.
514 repositories will be compatible with Mercurial before version 1.1.
510
515
511 ``dotencode``
516 ``dotencode``
512 Enable or disable the "dotencode" repository format which enhances
517 Enable or disable the "dotencode" repository format which enhances
513 the "fncache" repository format (which has to be enabled to use
518 the "fncache" repository format (which has to be enabled to use
514 dotencode) to avoid issues with filenames starting with ._ on
519 dotencode) to avoid issues with filenames starting with ._ on
515 Mac OS X and spaces on Windows. Enabled by default. Disabling this
520 Mac OS X and spaces on Windows. Enabled by default. Disabling this
516 option ensures that the on-disk format of newly created
521 option ensures that the on-disk format of newly created
517 repositories will be compatible with Mercurial before version 1.7.
522 repositories will be compatible with Mercurial before version 1.7.
518
523
519 ``graph``
524 ``graph``
520 """""""""
525 """""""""
521
526
522 Web graph view configuration. This section let you change graph
527 Web graph view configuration. This section let you change graph
523 elements display properties by branches, for instance to make the
528 elements display properties by branches, for instance to make the
524 ``default`` branch stand out.
529 ``default`` branch stand out.
525
530
526 Each line has the following format::
531 Each line has the following format::
527
532
528 <branch>.<argument> = <value>
533 <branch>.<argument> = <value>
529
534
530 where ``<branch>`` is the name of the branch being
535 where ``<branch>`` is the name of the branch being
531 customized. Example::
536 customized. Example::
532
537
533 [graph]
538 [graph]
534 # 2px width
539 # 2px width
535 default.width = 2
540 default.width = 2
536 # red color
541 # red color
537 default.color = FF0000
542 default.color = FF0000
538
543
539 Supported arguments:
544 Supported arguments:
540
545
541 ``width``
546 ``width``
542 Set branch edges width in pixels.
547 Set branch edges width in pixels.
543
548
544 ``color``
549 ``color``
545 Set branch edges color in hexadecimal RGB notation.
550 Set branch edges color in hexadecimal RGB notation.
546
551
547 ``hooks``
552 ``hooks``
548 """""""""
553 """""""""
549
554
550 Commands or Python functions that get automatically executed by
555 Commands or Python functions that get automatically executed by
551 various actions such as starting or finishing a commit. Multiple
556 various actions such as starting or finishing a commit. Multiple
552 hooks can be run for the same action by appending a suffix to the
557 hooks can be run for the same action by appending a suffix to the
553 action. Overriding a site-wide hook can be done by changing its
558 action. Overriding a site-wide hook can be done by changing its
554 value or setting it to an empty string. Hooks can be prioritized
559 value or setting it to an empty string. Hooks can be prioritized
555 by adding a prefix of ``priority`` to the hook name on a new line
560 by adding a prefix of ``priority`` to the hook name on a new line
556 and setting the priority. The default priority is 0 if
561 and setting the priority. The default priority is 0 if
557 not specified.
562 not specified.
558
563
559 Example ``.hg/hgrc``::
564 Example ``.hg/hgrc``::
560
565
561 [hooks]
566 [hooks]
562 # update working directory after adding changesets
567 # update working directory after adding changesets
563 changegroup.update = hg update
568 changegroup.update = hg update
564 # do not use the site-wide hook
569 # do not use the site-wide hook
565 incoming =
570 incoming =
566 incoming.email = /my/email/hook
571 incoming.email = /my/email/hook
567 incoming.autobuild = /my/build/hook
572 incoming.autobuild = /my/build/hook
568 # force autobuild hook to run before other incoming hooks
573 # force autobuild hook to run before other incoming hooks
569 priority.incoming.autobuild = 1
574 priority.incoming.autobuild = 1
570
575
571 Most hooks are run with environment variables set that give useful
576 Most hooks are run with environment variables set that give useful
572 additional information. For each hook below, the environment
577 additional information. For each hook below, the environment
573 variables it is passed are listed with names of the form ``$HG_foo``.
578 variables it is passed are listed with names of the form ``$HG_foo``.
574
579
575 ``changegroup``
580 ``changegroup``
576 Run after a changegroup has been added via push, pull or unbundle.
581 Run after a changegroup has been added via push, pull or unbundle.
577 ID of the first new changeset is in ``$HG_NODE``. URL from which
582 ID of the first new changeset is in ``$HG_NODE``. URL from which
578 changes came is in ``$HG_URL``.
583 changes came is in ``$HG_URL``.
579
584
580 ``commit``
585 ``commit``
581 Run after a changeset has been created in the local repository. ID
586 Run after a changeset has been created in the local repository. ID
582 of the newly created changeset is in ``$HG_NODE``. Parent changeset
587 of the newly created changeset is in ``$HG_NODE``. Parent changeset
583 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
588 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
584
589
585 ``incoming``
590 ``incoming``
586 Run after a changeset has been pulled, pushed, or unbundled into
591 Run after a changeset has been pulled, pushed, or unbundled into
587 the local repository. The ID of the newly arrived changeset is in
592 the local repository. The ID of the newly arrived changeset is in
588 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
593 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
589
594
590 ``outgoing``
595 ``outgoing``
591 Run after sending changes from local repository to another. ID of
596 Run after sending changes from local repository to another. ID of
592 first changeset sent is in ``$HG_NODE``. Source of operation is in
597 first changeset sent is in ``$HG_NODE``. Source of operation is in
593 ``$HG_SOURCE``; see "preoutgoing" hook for description.
598 ``$HG_SOURCE``; see "preoutgoing" hook for description.
594
599
595 ``post-<command>``
600 ``post-<command>``
596 Run after successful invocations of the associated command. The
601 Run after successful invocations of the associated command. The
597 contents of the command line are passed as ``$HG_ARGS`` and the result
602 contents of the command line are passed as ``$HG_ARGS`` and the result
598 code in ``$HG_RESULT``. Parsed command line arguments are passed as
603 code in ``$HG_RESULT``. Parsed command line arguments are passed as
599 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
604 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
600 the python data internally passed to <command>. ``$HG_OPTS`` is a
605 the python data internally passed to <command>. ``$HG_OPTS`` is a
601 dictionary of options (with unspecified options set to their defaults).
606 dictionary of options (with unspecified options set to their defaults).
602 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
607 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
603
608
604 ``pre-<command>``
609 ``pre-<command>``
605 Run before executing the associated command. The contents of the
610 Run before executing the associated command. The contents of the
606 command line are passed as ``$HG_ARGS``. Parsed command line arguments
611 command line are passed as ``$HG_ARGS``. Parsed command line arguments
607 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
612 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
608 representations of the data internally passed to <command>. ``$HG_OPTS``
613 representations of the data internally passed to <command>. ``$HG_OPTS``
609 is a dictionary of options (with unspecified options set to their
614 is a dictionary of options (with unspecified options set to their
610 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
615 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
611 failure, the command doesn't execute and Mercurial returns the failure
616 failure, the command doesn't execute and Mercurial returns the failure
612 code.
617 code.
613
618
614 ``prechangegroup``
619 ``prechangegroup``
615 Run before a changegroup is added via push, pull or unbundle. Exit
620 Run before a changegroup is added via push, pull or unbundle. Exit
616 status 0 allows the changegroup to proceed. Non-zero status will
621 status 0 allows the changegroup to proceed. Non-zero status will
617 cause the push, pull or unbundle to fail. URL from which changes
622 cause the push, pull or unbundle to fail. URL from which changes
618 will come is in ``$HG_URL``.
623 will come is in ``$HG_URL``.
619
624
620 ``precommit``
625 ``precommit``
621 Run before starting a local commit. Exit status 0 allows the
626 Run before starting a local commit. Exit status 0 allows the
622 commit to proceed. Non-zero status will cause the commit to fail.
627 commit to proceed. Non-zero status will cause the commit to fail.
623 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
628 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
624
629
625 ``prelistkeys``
630 ``prelistkeys``
626 Run before listing pushkeys (like bookmarks) in the
631 Run before listing pushkeys (like bookmarks) in the
627 repository. Non-zero status will cause failure. The key namespace is
632 repository. Non-zero status will cause failure. The key namespace is
628 in ``$HG_NAMESPACE``.
633 in ``$HG_NAMESPACE``.
629
634
630 ``preoutgoing``
635 ``preoutgoing``
631 Run before collecting changes to send from the local repository to
636 Run before collecting changes to send from the local repository to
632 another. Non-zero status will cause failure. This lets you prevent
637 another. Non-zero status will cause failure. This lets you prevent
633 pull over HTTP or SSH. Also prevents against local pull, push
638 pull over HTTP or SSH. Also prevents against local pull, push
634 (outbound) or bundle commands, but not effective, since you can
639 (outbound) or bundle commands, but not effective, since you can
635 just copy files instead then. Source of operation is in
640 just copy files instead then. Source of operation is in
636 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
641 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
637 SSH or HTTP repository. If "push", "pull" or "bundle", operation
642 SSH or HTTP repository. If "push", "pull" or "bundle", operation
638 is happening on behalf of repository on same system.
643 is happening on behalf of repository on same system.
639
644
640 ``prepushkey``
645 ``prepushkey``
641 Run before a pushkey (like a bookmark) is added to the
646 Run before a pushkey (like a bookmark) is added to the
642 repository. Non-zero status will cause the key to be rejected. The
647 repository. Non-zero status will cause the key to be rejected. The
643 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
648 key namespace is in ``$HG_NAMESPACE``, the key is in ``$HG_KEY``,
644 the old value (if any) is in ``$HG_OLD``, and the new value is in
649 the old value (if any) is in ``$HG_OLD``, and the new value is in
645 ``$HG_NEW``.
650 ``$HG_NEW``.
646
651
647 ``pretag``
652 ``pretag``
648 Run before creating a tag. Exit status 0 allows the tag to be
653 Run before creating a tag. Exit status 0 allows the tag to be
649 created. Non-zero status will cause the tag to fail. ID of
654 created. Non-zero status will cause the tag to fail. ID of
650 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
655 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
651 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
656 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
652
657
653 ``pretxnchangegroup``
658 ``pretxnchangegroup``
654 Run after a changegroup has been added via push, pull or unbundle,
659 Run after a changegroup has been added via push, pull or unbundle,
655 but before the transaction has been committed. Changegroup is
660 but before the transaction has been committed. Changegroup is
656 visible to hook program. This lets you validate incoming changes
661 visible to hook program. This lets you validate incoming changes
657 before accepting them. Passed the ID of the first new changeset in
662 before accepting them. Passed the ID of the first new changeset in
658 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
663 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
659 status will cause the transaction to be rolled back and the push,
664 status will cause the transaction to be rolled back and the push,
660 pull or unbundle will fail. URL that was source of changes is in
665 pull or unbundle will fail. URL that was source of changes is in
661 ``$HG_URL``.
666 ``$HG_URL``.
662
667
663 ``pretxncommit``
668 ``pretxncommit``
664 Run after a changeset has been created but the transaction not yet
669 Run after a changeset has been created but the transaction not yet
665 committed. Changeset is visible to hook program. This lets you
670 committed. Changeset is visible to hook program. This lets you
666 validate commit message and changes. Exit status 0 allows the
671 validate commit message and changes. Exit status 0 allows the
667 commit to proceed. Non-zero status will cause the transaction to
672 commit to proceed. Non-zero status will cause the transaction to
668 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
673 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
669 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
674 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
670
675
671 ``preupdate``
676 ``preupdate``
672 Run before updating the working directory. Exit status 0 allows
677 Run before updating the working directory. Exit status 0 allows
673 the update to proceed. Non-zero status will prevent the update.
678 the update to proceed. Non-zero status will prevent the update.
674 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
679 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
675 of second new parent is in ``$HG_PARENT2``.
680 of second new parent is in ``$HG_PARENT2``.
676
681
677 ``listkeys``
682 ``listkeys``
678 Run after listing pushkeys (like bookmarks) in the repository. The
683 Run after listing pushkeys (like bookmarks) in the repository. The
679 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
684 key namespace is in ``$HG_NAMESPACE``. ``$HG_VALUES`` is a
680 dictionary containing the keys and values.
685 dictionary containing the keys and values.
681
686
682 ``pushkey``
687 ``pushkey``
683 Run after a pushkey (like a bookmark) is added to the
688 Run after a pushkey (like a bookmark) is added to the
684 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
689 repository. The key namespace is in ``$HG_NAMESPACE``, the key is in
685 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
690 ``$HG_KEY``, the old value (if any) is in ``$HG_OLD``, and the new
686 value is in ``$HG_NEW``.
691 value is in ``$HG_NEW``.
687
692
688 ``tag``
693 ``tag``
689 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
694 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
690 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
695 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
691 repository if ``$HG_LOCAL=0``.
696 repository if ``$HG_LOCAL=0``.
692
697
693 ``update``
698 ``update``
694 Run after updating the working directory. Changeset ID of first
699 Run after updating the working directory. Changeset ID of first
695 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
700 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
696 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
701 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
697 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
702 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
698
703
699 .. note:: It is generally better to use standard hooks rather than the
704 .. note:: It is generally better to use standard hooks rather than the
700 generic pre- and post- command hooks as they are guaranteed to be
705 generic pre- and post- command hooks as they are guaranteed to be
701 called in the appropriate contexts for influencing transactions.
706 called in the appropriate contexts for influencing transactions.
702 Also, hooks like "commit" will be called in all contexts that
707 Also, hooks like "commit" will be called in all contexts that
703 generate a commit (e.g. tag) and not just the commit command.
708 generate a commit (e.g. tag) and not just the commit command.
704
709
705 .. note:: Environment variables with empty values may not be passed to
710 .. note:: Environment variables with empty values may not be passed to
706 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
711 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
707 will have an empty value under Unix-like platforms for non-merge
712 will have an empty value under Unix-like platforms for non-merge
708 changesets, while it will not be available at all under Windows.
713 changesets, while it will not be available at all under Windows.
709
714
710 The syntax for Python hooks is as follows::
715 The syntax for Python hooks is as follows::
711
716
712 hookname = python:modulename.submodule.callable
717 hookname = python:modulename.submodule.callable
713 hookname = python:/path/to/python/module.py:callable
718 hookname = python:/path/to/python/module.py:callable
714
719
715 Python hooks are run within the Mercurial process. Each hook is
720 Python hooks are run within the Mercurial process. Each hook is
716 called with at least three keyword arguments: a ui object (keyword
721 called with at least three keyword arguments: a ui object (keyword
717 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
722 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
718 keyword that tells what kind of hook is used. Arguments listed as
723 keyword that tells what kind of hook is used. Arguments listed as
719 environment variables above are passed as keyword arguments, with no
724 environment variables above are passed as keyword arguments, with no
720 ``HG_`` prefix, and names in lower case.
725 ``HG_`` prefix, and names in lower case.
721
726
722 If a Python hook returns a "true" value or raises an exception, this
727 If a Python hook returns a "true" value or raises an exception, this
723 is treated as a failure.
728 is treated as a failure.
724
729
725
730
726 ``hostfingerprints``
731 ``hostfingerprints``
727 """"""""""""""""""""
732 """"""""""""""""""""
728
733
729 Fingerprints of the certificates of known HTTPS servers.
734 Fingerprints of the certificates of known HTTPS servers.
730 A HTTPS connection to a server with a fingerprint configured here will
735 A HTTPS connection to a server with a fingerprint configured here will
731 only succeed if the servers certificate matches the fingerprint.
736 only succeed if the servers certificate matches the fingerprint.
732 This is very similar to how ssh known hosts works.
737 This is very similar to how ssh known hosts works.
733 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
738 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
734 The CA chain and web.cacerts is not used for servers with a fingerprint.
739 The CA chain and web.cacerts is not used for servers with a fingerprint.
735
740
736 For example::
741 For example::
737
742
738 [hostfingerprints]
743 [hostfingerprints]
739 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
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 This feature is only supported when using Python 2.6 or later.
746 This feature is only supported when using Python 2.6 or later.
742
747
743
748
744 ``http_proxy``
749 ``http_proxy``
745 """"""""""""""
750 """"""""""""""
746
751
747 Used to access web-based Mercurial repositories through a HTTP
752 Used to access web-based Mercurial repositories through a HTTP
748 proxy.
753 proxy.
749
754
750 ``host``
755 ``host``
751 Host name and (optional) port of the proxy server, for example
756 Host name and (optional) port of the proxy server, for example
752 "myproxy:8000".
757 "myproxy:8000".
753
758
754 ``no``
759 ``no``
755 Optional. Comma-separated list of host names that should bypass
760 Optional. Comma-separated list of host names that should bypass
756 the proxy.
761 the proxy.
757
762
758 ``passwd``
763 ``passwd``
759 Optional. Password to authenticate with at the proxy server.
764 Optional. Password to authenticate with at the proxy server.
760
765
761 ``user``
766 ``user``
762 Optional. User name to authenticate with at the proxy server.
767 Optional. User name to authenticate with at the proxy server.
763
768
764 ``always``
769 ``always``
765 Optional. Always use the proxy, even for localhost and any entries
770 Optional. Always use the proxy, even for localhost and any entries
766 in ``http_proxy.no``. True or False. Default: False.
771 in ``http_proxy.no``. True or False. Default: False.
767
772
768 ``merge-patterns``
773 ``merge-patterns``
769 """"""""""""""""""
774 """"""""""""""""""
770
775
771 This section specifies merge tools to associate with particular file
776 This section specifies merge tools to associate with particular file
772 patterns. Tools matched here will take precedence over the default
777 patterns. Tools matched here will take precedence over the default
773 merge tool. Patterns are globs by default, rooted at the repository
778 merge tool. Patterns are globs by default, rooted at the repository
774 root.
779 root.
775
780
776 Example::
781 Example::
777
782
778 [merge-patterns]
783 [merge-patterns]
779 **.c = kdiff3
784 **.c = kdiff3
780 **.jpg = myimgmerge
785 **.jpg = myimgmerge
781
786
782 ``merge-tools``
787 ``merge-tools``
783 """""""""""""""
788 """""""""""""""
784
789
785 This section configures external merge tools to use for file-level
790 This section configures external merge tools to use for file-level
786 merges.
791 merges.
787
792
788 Example ``~/.hgrc``::
793 Example ``~/.hgrc``::
789
794
790 [merge-tools]
795 [merge-tools]
791 # Override stock tool location
796 # Override stock tool location
792 kdiff3.executable = ~/bin/kdiff3
797 kdiff3.executable = ~/bin/kdiff3
793 # Specify command line
798 # Specify command line
794 kdiff3.args = $base $local $other -o $output
799 kdiff3.args = $base $local $other -o $output
795 # Give higher priority
800 # Give higher priority
796 kdiff3.priority = 1
801 kdiff3.priority = 1
797
802
798 # Define new tool
803 # Define new tool
799 myHtmlTool.args = -m $local $other $base $output
804 myHtmlTool.args = -m $local $other $base $output
800 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
805 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
801 myHtmlTool.priority = 1
806 myHtmlTool.priority = 1
802
807
803 Supported arguments:
808 Supported arguments:
804
809
805 ``priority``
810 ``priority``
806 The priority in which to evaluate this tool.
811 The priority in which to evaluate this tool.
807 Default: 0.
812 Default: 0.
808
813
809 ``executable``
814 ``executable``
810 Either just the name of the executable or its pathname. On Windows,
815 Either just the name of the executable or its pathname. On Windows,
811 the path can use environment variables with ${ProgramFiles} syntax.
816 the path can use environment variables with ${ProgramFiles} syntax.
812 Default: the tool name.
817 Default: the tool name.
813
818
814 ``args``
819 ``args``
815 The arguments to pass to the tool executable. You can refer to the
820 The arguments to pass to the tool executable. You can refer to the
816 files being merged as well as the output file through these
821 files being merged as well as the output file through these
817 variables: ``$base``, ``$local``, ``$other``, ``$output``.
822 variables: ``$base``, ``$local``, ``$other``, ``$output``.
818 Default: ``$local $base $other``
823 Default: ``$local $base $other``
819
824
820 ``premerge``
825 ``premerge``
821 Attempt to run internal non-interactive 3-way merge tool before
826 Attempt to run internal non-interactive 3-way merge tool before
822 launching external tool. Options are ``true``, ``false``, or ``keep``
827 launching external tool. Options are ``true``, ``false``, or ``keep``
823 to leave markers in the file if the premerge fails.
828 to leave markers in the file if the premerge fails.
824 Default: True
829 Default: True
825
830
826 ``binary``
831 ``binary``
827 This tool can merge binary files. Defaults to False, unless tool
832 This tool can merge binary files. Defaults to False, unless tool
828 was selected by file pattern match.
833 was selected by file pattern match.
829
834
830 ``symlink``
835 ``symlink``
831 This tool can merge symlinks. Defaults to False, even if tool was
836 This tool can merge symlinks. Defaults to False, even if tool was
832 selected by file pattern match.
837 selected by file pattern match.
833
838
834 ``check``
839 ``check``
835 A list of merge success-checking options:
840 A list of merge success-checking options:
836
841
837 ``changed``
842 ``changed``
838 Ask whether merge was successful when the merged file shows no changes.
843 Ask whether merge was successful when the merged file shows no changes.
839 ``conflicts``
844 ``conflicts``
840 Check whether there are conflicts even though the tool reported success.
845 Check whether there are conflicts even though the tool reported success.
841 ``prompt``
846 ``prompt``
842 Always prompt for merge success, regardless of success reported by tool.
847 Always prompt for merge success, regardless of success reported by tool.
843
848
844 ``checkchanged``
849 ``checkchanged``
845 True is equivalent to ``check = changed``.
850 True is equivalent to ``check = changed``.
846 Default: False
851 Default: False
847
852
848 ``checkconflicts``
853 ``checkconflicts``
849 True is equivalent to ``check = conflicts``.
854 True is equivalent to ``check = conflicts``.
850 Default: False
855 Default: False
851
856
852 ``fixeol``
857 ``fixeol``
853 Attempt to fix up EOL changes caused by the merge tool.
858 Attempt to fix up EOL changes caused by the merge tool.
854 Default: False
859 Default: False
855
860
856 ``gui``
861 ``gui``
857 This tool requires a graphical interface to run. Default: False
862 This tool requires a graphical interface to run. Default: False
858
863
859 ``regkey``
864 ``regkey``
860 Windows registry key which describes install location of this
865 Windows registry key which describes install location of this
861 tool. Mercurial will search for this key first under
866 tool. Mercurial will search for this key first under
862 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
867 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
863 Default: None
868 Default: None
864
869
865 ``regkeyalt``
870 ``regkeyalt``
866 An alternate Windows registry key to try if the first key is not
871 An alternate Windows registry key to try if the first key is not
867 found. The alternate key uses the same ``regname`` and ``regappend``
872 found. The alternate key uses the same ``regname`` and ``regappend``
868 semantics of the primary key. The most common use for this key
873 semantics of the primary key. The most common use for this key
869 is to search for 32bit applications on 64bit operating systems.
874 is to search for 32bit applications on 64bit operating systems.
870 Default: None
875 Default: None
871
876
872 ``regname``
877 ``regname``
873 Name of value to read from specified registry key. Defaults to the
878 Name of value to read from specified registry key. Defaults to the
874 unnamed (default) value.
879 unnamed (default) value.
875
880
876 ``regappend``
881 ``regappend``
877 String to append to the value read from the registry, typically
882 String to append to the value read from the registry, typically
878 the executable name of the tool.
883 the executable name of the tool.
879 Default: None
884 Default: None
880
885
881
886
882 ``patch``
887 ``patch``
883 """""""""
888 """""""""
884
889
885 Settings used when applying patches, for instance through the 'import'
890 Settings used when applying patches, for instance through the 'import'
886 command or with Mercurial Queues extension.
891 command or with Mercurial Queues extension.
887
892
888 ``eol``
893 ``eol``
889 When set to 'strict' patch content and patched files end of lines
894 When set to 'strict' patch content and patched files end of lines
890 are preserved. When set to ``lf`` or ``crlf``, both files end of
895 are preserved. When set to ``lf`` or ``crlf``, both files end of
891 lines are ignored when patching and the result line endings are
896 lines are ignored when patching and the result line endings are
892 normalized to either LF (Unix) or CRLF (Windows). When set to
897 normalized to either LF (Unix) or CRLF (Windows). When set to
893 ``auto``, end of lines are again ignored while patching but line
898 ``auto``, end of lines are again ignored while patching but line
894 endings in patched files are normalized to their original setting
899 endings in patched files are normalized to their original setting
895 on a per-file basis. If target file does not exist or has no end
900 on a per-file basis. If target file does not exist or has no end
896 of line, patch line endings are preserved.
901 of line, patch line endings are preserved.
897 Default: strict.
902 Default: strict.
898
903
899
904
900 ``paths``
905 ``paths``
901 """""""""
906 """""""""
902
907
903 Assigns symbolic names to repositories. The left side is the
908 Assigns symbolic names to repositories. The left side is the
904 symbolic name, and the right gives the directory or URL that is the
909 symbolic name, and the right gives the directory or URL that is the
905 location of the repository. Default paths can be declared by setting
910 location of the repository. Default paths can be declared by setting
906 the following entries.
911 the following entries.
907
912
908 ``default``
913 ``default``
909 Directory or URL to use when pulling if no source is specified.
914 Directory or URL to use when pulling if no source is specified.
910 Default is set to repository from which the current repository was
915 Default is set to repository from which the current repository was
911 cloned.
916 cloned.
912
917
913 ``default-push``
918 ``default-push``
914 Optional. Directory or URL to use when pushing if no destination
919 Optional. Directory or URL to use when pushing if no destination
915 is specified.
920 is specified.
916
921
917 ``phases``
922 ``phases``
918 """"""""""
923 """"""""""
919
924
920 Specifies default handling of phases. See :hg:`help phases` for more
925 Specifies default handling of phases. See :hg:`help phases` for more
921 information about working with phases.
926 information about working with phases.
922
927
923 ``publish``
928 ``publish``
924 Controls draft phase behavior when working as a server. When true,
929 Controls draft phase behavior when working as a server. When true,
925 pushed changesets are set to public in both client and server and
930 pushed changesets are set to public in both client and server and
926 pulled or cloned changesets are set to public in the client.
931 pulled or cloned changesets are set to public in the client.
927 Default: True
932 Default: True
928
933
929 ``new-commit``
934 ``new-commit``
930 Phase of newly-created commits.
935 Phase of newly-created commits.
931 Default: draft
936 Default: draft
932
937
933 ``profiling``
938 ``profiling``
934 """""""""""""
939 """""""""""""
935
940
936 Specifies profiling format and file output. In this section
941 Specifies profiling format and file output. In this section
937 description, 'profiling data' stands for the raw data collected
942 description, 'profiling data' stands for the raw data collected
938 during profiling, while 'profiling report' stands for a statistical
943 during profiling, while 'profiling report' stands for a statistical
939 text report generated from the profiling data. The profiling is done
944 text report generated from the profiling data. The profiling is done
940 using lsprof.
945 using lsprof.
941
946
942 ``format``
947 ``format``
943 Profiling format.
948 Profiling format.
944 Default: text.
949 Default: text.
945
950
946 ``text``
951 ``text``
947 Generate a profiling report. When saving to a file, it should be
952 Generate a profiling report. When saving to a file, it should be
948 noted that only the report is saved, and the profiling data is
953 noted that only the report is saved, and the profiling data is
949 not kept.
954 not kept.
950 ``kcachegrind``
955 ``kcachegrind``
951 Format profiling data for kcachegrind use: when saving to a
956 Format profiling data for kcachegrind use: when saving to a
952 file, the generated file can directly be loaded into
957 file, the generated file can directly be loaded into
953 kcachegrind.
958 kcachegrind.
954
959
955 ``output``
960 ``output``
956 File path where profiling data or report should be saved. If the
961 File path where profiling data or report should be saved. If the
957 file exists, it is replaced. Default: None, data is printed on
962 file exists, it is replaced. Default: None, data is printed on
958 stderr
963 stderr
959
964
960 ``revsetalias``
965 ``revsetalias``
961 """""""""""""""
966 """""""""""""""
962
967
963 Alias definitions for revsets. See :hg:`help revsets` for details.
968 Alias definitions for revsets. See :hg:`help revsets` for details.
964
969
965 ``server``
970 ``server``
966 """"""""""
971 """"""""""
967
972
968 Controls generic server settings.
973 Controls generic server settings.
969
974
970 ``uncompressed``
975 ``uncompressed``
971 Whether to allow clients to clone a repository using the
976 Whether to allow clients to clone a repository using the
972 uncompressed streaming protocol. This transfers about 40% more
977 uncompressed streaming protocol. This transfers about 40% more
973 data than a regular clone, but uses less memory and CPU on both
978 data than a regular clone, but uses less memory and CPU on both
974 server and client. Over a LAN (100 Mbps or better) or a very fast
979 server and client. Over a LAN (100 Mbps or better) or a very fast
975 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
980 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
976 regular clone. Over most WAN connections (anything slower than
981 regular clone. Over most WAN connections (anything slower than
977 about 6 Mbps), uncompressed streaming is slower, because of the
982 about 6 Mbps), uncompressed streaming is slower, because of the
978 extra data transfer overhead. This mode will also temporarily hold
983 extra data transfer overhead. This mode will also temporarily hold
979 the write lock while determining what data to transfer.
984 the write lock while determining what data to transfer.
980 Default is True.
985 Default is True.
981
986
982 ``preferuncompressed``
987 ``preferuncompressed``
983 When set, clients will try to use the uncompressed streaming
988 When set, clients will try to use the uncompressed streaming
984 protocol. Default is False.
989 protocol. Default is False.
985
990
986 ``validate``
991 ``validate``
987 Whether to validate the completeness of pushed changesets by
992 Whether to validate the completeness of pushed changesets by
988 checking that all new file revisions specified in manifests are
993 checking that all new file revisions specified in manifests are
989 present. Default is False.
994 present. Default is False.
990
995
991 ``smtp``
996 ``smtp``
992 """"""""
997 """"""""
993
998
994 Configuration for extensions that need to send email messages.
999 Configuration for extensions that need to send email messages.
995
1000
996 ``host``
1001 ``host``
997 Host name of mail server, e.g. "mail.example.com".
1002 Host name of mail server, e.g. "mail.example.com".
998
1003
999 ``port``
1004 ``port``
1000 Optional. Port to connect to on mail server. Default: 25.
1005 Optional. Port to connect to on mail server. Default: 25.
1001
1006
1002 ``tls``
1007 ``tls``
1003 Optional. Method to enable TLS when connecting to mail server: starttls,
1008 Optional. Method to enable TLS when connecting to mail server: starttls,
1004 smtps or none. Default: none.
1009 smtps or none. Default: none.
1005
1010
1006 ``username``
1011 ``username``
1007 Optional. User name for authenticating with the SMTP server.
1012 Optional. User name for authenticating with the SMTP server.
1008 Default: none.
1013 Default: none.
1009
1014
1010 ``password``
1015 ``password``
1011 Optional. Password for authenticating with the SMTP server. If not
1016 Optional. Password for authenticating with the SMTP server. If not
1012 specified, interactive sessions will prompt the user for a
1017 specified, interactive sessions will prompt the user for a
1013 password; non-interactive sessions will fail. Default: none.
1018 password; non-interactive sessions will fail. Default: none.
1014
1019
1015 ``local_hostname``
1020 ``local_hostname``
1016 Optional. It's the hostname that the sender can use to identify
1021 Optional. It's the hostname that the sender can use to identify
1017 itself to the MTA.
1022 itself to the MTA.
1018
1023
1019
1024
1020 ``subpaths``
1025 ``subpaths``
1021 """"""""""""
1026 """"""""""""
1022
1027
1023 Defines subrepositories source locations rewriting rules of the form::
1028 Defines subrepositories source locations rewriting rules of the form::
1024
1029
1025 <pattern> = <replacement>
1030 <pattern> = <replacement>
1026
1031
1027 Where ``pattern`` is a regular expression matching the source and
1032 Where ``pattern`` is a regular expression matching the source and
1028 ``replacement`` is the replacement string used to rewrite it. Groups
1033 ``replacement`` is the replacement string used to rewrite it. Groups
1029 can be matched in ``pattern`` and referenced in ``replacements``. For
1034 can be matched in ``pattern`` and referenced in ``replacements``. For
1030 instance::
1035 instance::
1031
1036
1032 http://server/(.*)-hg/ = http://hg.server/\1/
1037 http://server/(.*)-hg/ = http://hg.server/\1/
1033
1038
1034 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1039 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
1035
1040
1036 All patterns are applied in definition order.
1041 All patterns are applied in definition order.
1037
1042
1038 ``trusted``
1043 ``trusted``
1039 """""""""""
1044 """""""""""
1040
1045
1041 Mercurial will not use the settings in the
1046 Mercurial will not use the settings in the
1042 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1047 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
1043 user or to a trusted group, as various hgrc features allow arbitrary
1048 user or to a trusted group, as various hgrc features allow arbitrary
1044 commands to be run. This issue is often encountered when configuring
1049 commands to be run. This issue is often encountered when configuring
1045 hooks or extensions for shared repositories or servers. However,
1050 hooks or extensions for shared repositories or servers. However,
1046 the web interface will use some safe settings from the ``[web]``
1051 the web interface will use some safe settings from the ``[web]``
1047 section.
1052 section.
1048
1053
1049 This section specifies what users and groups are trusted. The
1054 This section specifies what users and groups are trusted. The
1050 current user is always trusted. To trust everybody, list a user or a
1055 current user is always trusted. To trust everybody, list a user or a
1051 group with name ``*``. These settings must be placed in an
1056 group with name ``*``. These settings must be placed in an
1052 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1057 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
1053 user or service running Mercurial.
1058 user or service running Mercurial.
1054
1059
1055 ``users``
1060 ``users``
1056 Comma-separated list of trusted users.
1061 Comma-separated list of trusted users.
1057
1062
1058 ``groups``
1063 ``groups``
1059 Comma-separated list of trusted groups.
1064 Comma-separated list of trusted groups.
1060
1065
1061
1066
1062 ``ui``
1067 ``ui``
1063 """"""
1068 """"""
1064
1069
1065 User interface controls.
1070 User interface controls.
1066
1071
1067 ``archivemeta``
1072 ``archivemeta``
1068 Whether to include the .hg_archival.txt file containing meta data
1073 Whether to include the .hg_archival.txt file containing meta data
1069 (hashes for the repository base and for tip) in archives created
1074 (hashes for the repository base and for tip) in archives created
1070 by the :hg:`archive` command or downloaded via hgweb.
1075 by the :hg:`archive` command or downloaded via hgweb.
1071 Default is True.
1076 Default is True.
1072
1077
1073 ``askusername``
1078 ``askusername``
1074 Whether to prompt for a username when committing. If True, and
1079 Whether to prompt for a username when committing. If True, and
1075 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1080 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
1076 be prompted to enter a username. If no username is entered, the
1081 be prompted to enter a username. If no username is entered, the
1077 default ``USER@HOST`` is used instead.
1082 default ``USER@HOST`` is used instead.
1078 Default is False.
1083 Default is False.
1079
1084
1080 ``commitsubrepos``
1085 ``commitsubrepos``
1081 Whether to commit modified subrepositories when committing the
1086 Whether to commit modified subrepositories when committing the
1082 parent repository. If False and one subrepository has uncommitted
1087 parent repository. If False and one subrepository has uncommitted
1083 changes, abort the commit.
1088 changes, abort the commit.
1084 Default is False.
1089 Default is False.
1085
1090
1086 ``debug``
1091 ``debug``
1087 Print debugging information. True or False. Default is False.
1092 Print debugging information. True or False. Default is False.
1088
1093
1089 ``editor``
1094 ``editor``
1090 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1095 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
1091
1096
1092 ``fallbackencoding``
1097 ``fallbackencoding``
1093 Encoding to try if it's not possible to decode the changelog using
1098 Encoding to try if it's not possible to decode the changelog using
1094 UTF-8. Default is ISO-8859-1.
1099 UTF-8. Default is ISO-8859-1.
1095
1100
1096 ``ignore``
1101 ``ignore``
1097 A file to read per-user ignore patterns from. This file should be
1102 A file to read per-user ignore patterns from. This file should be
1098 in the same format as a repository-wide .hgignore file. This
1103 in the same format as a repository-wide .hgignore file. This
1099 option supports hook syntax, so if you want to specify multiple
1104 option supports hook syntax, so if you want to specify multiple
1100 ignore files, you can do so by setting something like
1105 ignore files, you can do so by setting something like
1101 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1106 ``ignore.other = ~/.hgignore2``. For details of the ignore file
1102 format, see the ``hgignore(5)`` man page.
1107 format, see the ``hgignore(5)`` man page.
1103
1108
1104 ``interactive``
1109 ``interactive``
1105 Allow to prompt the user. True or False. Default is True.
1110 Allow to prompt the user. True or False. Default is True.
1106
1111
1107 ``logtemplate``
1112 ``logtemplate``
1108 Template string for commands that print changesets.
1113 Template string for commands that print changesets.
1109
1114
1110 ``merge``
1115 ``merge``
1111 The conflict resolution program to use during a manual merge.
1116 The conflict resolution program to use during a manual merge.
1112 For more information on merge tools see :hg:`help merge-tools`.
1117 For more information on merge tools see :hg:`help merge-tools`.
1113 For configuring merge tools see the ``[merge-tools]`` section.
1118 For configuring merge tools see the ``[merge-tools]`` section.
1114
1119
1115 ``portablefilenames``
1120 ``portablefilenames``
1116 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1121 Check for portable filenames. Can be ``warn``, ``ignore`` or ``abort``.
1117 Default is ``warn``.
1122 Default is ``warn``.
1118 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1123 If set to ``warn`` (or ``true``), a warning message is printed on POSIX
1119 platforms, if a file with a non-portable filename is added (e.g. a file
1124 platforms, if a file with a non-portable filename is added (e.g. a file
1120 with a name that can't be created on Windows because it contains reserved
1125 with a name that can't be created on Windows because it contains reserved
1121 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1126 parts like ``AUX``, reserved characters like ``:``, or would cause a case
1122 collision with an existing file).
1127 collision with an existing file).
1123 If set to ``ignore`` (or ``false``), no warning is printed.
1128 If set to ``ignore`` (or ``false``), no warning is printed.
1124 If set to ``abort``, the command is aborted.
1129 If set to ``abort``, the command is aborted.
1125 On Windows, this configuration option is ignored and the command aborted.
1130 On Windows, this configuration option is ignored and the command aborted.
1126
1131
1127 ``quiet``
1132 ``quiet``
1128 Reduce the amount of output printed. True or False. Default is False.
1133 Reduce the amount of output printed. True or False. Default is False.
1129
1134
1130 ``remotecmd``
1135 ``remotecmd``
1131 remote command to use for clone/push/pull operations. Default is ``hg``.
1136 remote command to use for clone/push/pull operations. Default is ``hg``.
1132
1137
1133 ``report_untrusted``
1138 ``report_untrusted``
1134 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1139 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
1135 trusted user or group. True or False. Default is True.
1140 trusted user or group. True or False. Default is True.
1136
1141
1137 ``slash``
1142 ``slash``
1138 Display paths using a slash (``/``) as the path separator. This
1143 Display paths using a slash (``/``) as the path separator. This
1139 only makes a difference on systems where the default path
1144 only makes a difference on systems where the default path
1140 separator is not the slash character (e.g. Windows uses the
1145 separator is not the slash character (e.g. Windows uses the
1141 backslash character (``\``)).
1146 backslash character (``\``)).
1142 Default is False.
1147 Default is False.
1143
1148
1144 ``ssh``
1149 ``ssh``
1145 command to use for SSH connections. Default is ``ssh``.
1150 command to use for SSH connections. Default is ``ssh``.
1146
1151
1147 ``strict``
1152 ``strict``
1148 Require exact command names, instead of allowing unambiguous
1153 Require exact command names, instead of allowing unambiguous
1149 abbreviations. True or False. Default is False.
1154 abbreviations. True or False. Default is False.
1150
1155
1151 ``style``
1156 ``style``
1152 Name of style to use for command output.
1157 Name of style to use for command output.
1153
1158
1154 ``timeout``
1159 ``timeout``
1155 The timeout used when a lock is held (in seconds), a negative value
1160 The timeout used when a lock is held (in seconds), a negative value
1156 means no timeout. Default is 600.
1161 means no timeout. Default is 600.
1157
1162
1158 ``traceback``
1163 ``traceback``
1159 Mercurial always prints a traceback when an unknown exception
1164 Mercurial always prints a traceback when an unknown exception
1160 occurs. Setting this to True will make Mercurial print a traceback
1165 occurs. Setting this to True will make Mercurial print a traceback
1161 on all exceptions, even those recognized by Mercurial (such as
1166 on all exceptions, even those recognized by Mercurial (such as
1162 IOError or MemoryError). Default is False.
1167 IOError or MemoryError). Default is False.
1163
1168
1164 ``username``
1169 ``username``
1165 The committer of a changeset created when running "commit".
1170 The committer of a changeset created when running "commit".
1166 Typically a person's name and email address, e.g. ``Fred Widget
1171 Typically a person's name and email address, e.g. ``Fred Widget
1167 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1172 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
1168 the username in hgrc is empty, it has to be specified manually or
1173 the username in hgrc is empty, it has to be specified manually or
1169 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1174 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
1170 ``username =`` in the system hgrc). Environment variables in the
1175 ``username =`` in the system hgrc). Environment variables in the
1171 username are expanded.
1176 username are expanded.
1172
1177
1173 ``verbose``
1178 ``verbose``
1174 Increase the amount of output printed. True or False. Default is False.
1179 Increase the amount of output printed. True or False. Default is False.
1175
1180
1176
1181
1177 ``web``
1182 ``web``
1178 """""""
1183 """""""
1179
1184
1180 Web interface configuration. The settings in this section apply to
1185 Web interface configuration. The settings in this section apply to
1181 both the builtin webserver (started by :hg:`serve`) and the script you
1186 both the builtin webserver (started by :hg:`serve`) and the script you
1182 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1187 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
1183 and WSGI).
1188 and WSGI).
1184
1189
1185 The Mercurial webserver does no authentication (it does not prompt for
1190 The Mercurial webserver does no authentication (it does not prompt for
1186 usernames and passwords to validate *who* users are), but it does do
1191 usernames and passwords to validate *who* users are), but it does do
1187 authorization (it grants or denies access for *authenticated users*
1192 authorization (it grants or denies access for *authenticated users*
1188 based on settings in this section). You must either configure your
1193 based on settings in this section). You must either configure your
1189 webserver to do authentication for you, or disable the authorization
1194 webserver to do authentication for you, or disable the authorization
1190 checks.
1195 checks.
1191
1196
1192 For a quick setup in a trusted environment, e.g., a private LAN, where
1197 For a quick setup in a trusted environment, e.g., a private LAN, where
1193 you want it to accept pushes from anybody, you can use the following
1198 you want it to accept pushes from anybody, you can use the following
1194 command line::
1199 command line::
1195
1200
1196 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1201 $ hg --config web.allow_push=* --config web.push_ssl=False serve
1197
1202
1198 Note that this will allow anybody to push anything to the server and
1203 Note that this will allow anybody to push anything to the server and
1199 that this should not be used for public servers.
1204 that this should not be used for public servers.
1200
1205
1201 The full set of options is:
1206 The full set of options is:
1202
1207
1203 ``accesslog``
1208 ``accesslog``
1204 Where to output the access log. Default is stdout.
1209 Where to output the access log. Default is stdout.
1205
1210
1206 ``address``
1211 ``address``
1207 Interface address to bind to. Default is all.
1212 Interface address to bind to. Default is all.
1208
1213
1209 ``allow_archive``
1214 ``allow_archive``
1210 List of archive format (bz2, gz, zip) allowed for downloading.
1215 List of archive format (bz2, gz, zip) allowed for downloading.
1211 Default is empty.
1216 Default is empty.
1212
1217
1213 ``allowbz2``
1218 ``allowbz2``
1214 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1219 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
1215 revisions.
1220 revisions.
1216 Default is False.
1221 Default is False.
1217
1222
1218 ``allowgz``
1223 ``allowgz``
1219 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1224 (DEPRECATED) Whether to allow .tar.gz downloading of repository
1220 revisions.
1225 revisions.
1221 Default is False.
1226 Default is False.
1222
1227
1223 ``allowpull``
1228 ``allowpull``
1224 Whether to allow pulling from the repository. Default is True.
1229 Whether to allow pulling from the repository. Default is True.
1225
1230
1226 ``allow_push``
1231 ``allow_push``
1227 Whether to allow pushing to the repository. If empty or not set,
1232 Whether to allow pushing to the repository. If empty or not set,
1228 push is not allowed. If the special value ``*``, any remote user can
1233 push is not allowed. If the special value ``*``, any remote user can
1229 push, including unauthenticated users. Otherwise, the remote user
1234 push, including unauthenticated users. Otherwise, the remote user
1230 must have been authenticated, and the authenticated user name must
1235 must have been authenticated, and the authenticated user name must
1231 be present in this list. The contents of the allow_push list are
1236 be present in this list. The contents of the allow_push list are
1232 examined after the deny_push list.
1237 examined after the deny_push list.
1233
1238
1234 ``guessmime``
1239 ``guessmime``
1235 Control MIME types for raw download of file content.
1240 Control MIME types for raw download of file content.
1236 Set to True to let hgweb guess the content type from the file
1241 Set to True to let hgweb guess the content type from the file
1237 extension. This will serve HTML files as ``text/html`` and might
1242 extension. This will serve HTML files as ``text/html`` and might
1238 allow cross-site scripting attacks when serving untrusted
1243 allow cross-site scripting attacks when serving untrusted
1239 repositories. Default is False.
1244 repositories. Default is False.
1240
1245
1241 ``allow_read``
1246 ``allow_read``
1242 If the user has not already been denied repository access due to
1247 If the user has not already been denied repository access due to
1243 the contents of deny_read, this list determines whether to grant
1248 the contents of deny_read, this list determines whether to grant
1244 repository access to the user. If this list is not empty, and the
1249 repository access to the user. If this list is not empty, and the
1245 user is unauthenticated or not present in the list, then access is
1250 user is unauthenticated or not present in the list, then access is
1246 denied for the user. If the list is empty or not set, then access
1251 denied for the user. If the list is empty or not set, then access
1247 is permitted to all users by default. Setting allow_read to the
1252 is permitted to all users by default. Setting allow_read to the
1248 special value ``*`` is equivalent to it not being set (i.e. access
1253 special value ``*`` is equivalent to it not being set (i.e. access
1249 is permitted to all users). The contents of the allow_read list are
1254 is permitted to all users). The contents of the allow_read list are
1250 examined after the deny_read list.
1255 examined after the deny_read list.
1251
1256
1252 ``allowzip``
1257 ``allowzip``
1253 (DEPRECATED) Whether to allow .zip downloading of repository
1258 (DEPRECATED) Whether to allow .zip downloading of repository
1254 revisions. Default is False. This feature creates temporary files.
1259 revisions. Default is False. This feature creates temporary files.
1255
1260
1256 ``baseurl``
1261 ``baseurl``
1257 Base URL to use when publishing URLs in other locations, so
1262 Base URL to use when publishing URLs in other locations, so
1258 third-party tools like email notification hooks can construct
1263 third-party tools like email notification hooks can construct
1259 URLs. Example: ``http://hgserver/repos/``.
1264 URLs. Example: ``http://hgserver/repos/``.
1260
1265
1261 ``cacerts``
1266 ``cacerts``
1262 Path to file containing a list of PEM encoded certificate
1267 Path to file containing a list of PEM encoded certificate
1263 authority certificates. Environment variables and ``~user``
1268 authority certificates. Environment variables and ``~user``
1264 constructs are expanded in the filename. If specified on the
1269 constructs are expanded in the filename. If specified on the
1265 client, then it will verify the identity of remote HTTPS servers
1270 client, then it will verify the identity of remote HTTPS servers
1266 with these certificates. The form must be as follows::
1271 with these certificates. The form must be as follows::
1267
1272
1268 -----BEGIN CERTIFICATE-----
1273 -----BEGIN CERTIFICATE-----
1269 ... (certificate in base64 PEM encoding) ...
1274 ... (certificate in base64 PEM encoding) ...
1270 -----END CERTIFICATE-----
1275 -----END CERTIFICATE-----
1271 -----BEGIN CERTIFICATE-----
1276 -----BEGIN CERTIFICATE-----
1272 ... (certificate in base64 PEM encoding) ...
1277 ... (certificate in base64 PEM encoding) ...
1273 -----END CERTIFICATE-----
1278 -----END CERTIFICATE-----
1274
1279
1275 This feature is only supported when using Python 2.6 or later. If you wish
1280 This feature is only supported when using Python 2.6 or later. If you wish
1276 to use it with earlier versions of Python, install the backported
1281 to use it with earlier versions of Python, install the backported
1277 version of the ssl library that is available from
1282 version of the ssl library that is available from
1278 ``http://pypi.python.org``.
1283 ``http://pypi.python.org``.
1279
1284
1280 You can use OpenSSL's CA certificate file if your platform has one.
1285 You can use OpenSSL's CA certificate file if your platform has one.
1281 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1286 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1282 Otherwise you will have to generate this file manually.
1287 Otherwise you will have to generate this file manually.
1283
1288
1284 To disable SSL verification temporarily, specify ``--insecure`` from
1289 To disable SSL verification temporarily, specify ``--insecure`` from
1285 command line.
1290 command line.
1286
1291
1287 ``cache``
1292 ``cache``
1288 Whether to support caching in hgweb. Defaults to True.
1293 Whether to support caching in hgweb. Defaults to True.
1289
1294
1290 ``contact``
1295 ``contact``
1291 Name or email address of the person in charge of the repository.
1296 Name or email address of the person in charge of the repository.
1292 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1297 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1293
1298
1294 ``deny_push``
1299 ``deny_push``
1295 Whether to deny pushing to the repository. If empty or not set,
1300 Whether to deny pushing to the repository. If empty or not set,
1296 push is not denied. If the special value ``*``, all remote users are
1301 push is not denied. If the special value ``*``, all remote users are
1297 denied push. Otherwise, unauthenticated users are all denied, and
1302 denied push. Otherwise, unauthenticated users are all denied, and
1298 any authenticated user name present in this list is also denied. The
1303 any authenticated user name present in this list is also denied. The
1299 contents of the deny_push list are examined before the allow_push list.
1304 contents of the deny_push list are examined before the allow_push list.
1300
1305
1301 ``deny_read``
1306 ``deny_read``
1302 Whether to deny reading/viewing of the repository. If this list is
1307 Whether to deny reading/viewing of the repository. If this list is
1303 not empty, unauthenticated users are all denied, and any
1308 not empty, unauthenticated users are all denied, and any
1304 authenticated user name present in this list is also denied access to
1309 authenticated user name present in this list is also denied access to
1305 the repository. If set to the special value ``*``, all remote users
1310 the repository. If set to the special value ``*``, all remote users
1306 are denied access (rarely needed ;). If deny_read is empty or not set,
1311 are denied access (rarely needed ;). If deny_read is empty or not set,
1307 the determination of repository access depends on the presence and
1312 the determination of repository access depends on the presence and
1308 content of the allow_read list (see description). If both
1313 content of the allow_read list (see description). If both
1309 deny_read and allow_read are empty or not set, then access is
1314 deny_read and allow_read are empty or not set, then access is
1310 permitted to all users by default. If the repository is being
1315 permitted to all users by default. If the repository is being
1311 served via hgwebdir, denied users will not be able to see it in
1316 served via hgwebdir, denied users will not be able to see it in
1312 the list of repositories. The contents of the deny_read list have
1317 the list of repositories. The contents of the deny_read list have
1313 priority over (are examined before) the contents of the allow_read
1318 priority over (are examined before) the contents of the allow_read
1314 list.
1319 list.
1315
1320
1316 ``descend``
1321 ``descend``
1317 hgwebdir indexes will not descend into subdirectories. Only repositories
1322 hgwebdir indexes will not descend into subdirectories. Only repositories
1318 directly in the current path will be shown (other repositories are still
1323 directly in the current path will be shown (other repositories are still
1319 available from the index corresponding to their containing path).
1324 available from the index corresponding to their containing path).
1320
1325
1321 ``description``
1326 ``description``
1322 Textual description of the repository's purpose or contents.
1327 Textual description of the repository's purpose or contents.
1323 Default is "unknown".
1328 Default is "unknown".
1324
1329
1325 ``encoding``
1330 ``encoding``
1326 Character encoding name. Default is the current locale charset.
1331 Character encoding name. Default is the current locale charset.
1327 Example: "UTF-8"
1332 Example: "UTF-8"
1328
1333
1329 ``errorlog``
1334 ``errorlog``
1330 Where to output the error log. Default is stderr.
1335 Where to output the error log. Default is stderr.
1331
1336
1332 ``hidden``
1337 ``hidden``
1333 Whether to hide the repository in the hgwebdir index.
1338 Whether to hide the repository in the hgwebdir index.
1334 Default is False.
1339 Default is False.
1335
1340
1336 ``ipv6``
1341 ``ipv6``
1337 Whether to use IPv6. Default is False.
1342 Whether to use IPv6. Default is False.
1338
1343
1339 ``logoimg``
1344 ``logoimg``
1340 File name of the logo image that some templates display on each page.
1345 File name of the logo image that some templates display on each page.
1341 The file name is relative to ``staticurl``. That is, the full path to
1346 The file name is relative to ``staticurl``. That is, the full path to
1342 the logo image is "staticurl/logoimg".
1347 the logo image is "staticurl/logoimg".
1343 If unset, ``hglogo.png`` will be used.
1348 If unset, ``hglogo.png`` will be used.
1344
1349
1345 ``logourl``
1350 ``logourl``
1346 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1351 Base URL to use for logos. If unset, ``http://mercurial.selenic.com/``
1347 will be used.
1352 will be used.
1348
1353
1349 ``name``
1354 ``name``
1350 Repository name to use in the web interface. Default is current
1355 Repository name to use in the web interface. Default is current
1351 working directory.
1356 working directory.
1352
1357
1353 ``maxchanges``
1358 ``maxchanges``
1354 Maximum number of changes to list on the changelog. Default is 10.
1359 Maximum number of changes to list on the changelog. Default is 10.
1355
1360
1356 ``maxfiles``
1361 ``maxfiles``
1357 Maximum number of files to list per changeset. Default is 10.
1362 Maximum number of files to list per changeset. Default is 10.
1358
1363
1359 ``port``
1364 ``port``
1360 Port to listen on. Default is 8000.
1365 Port to listen on. Default is 8000.
1361
1366
1362 ``prefix``
1367 ``prefix``
1363 Prefix path to serve from. Default is '' (server root).
1368 Prefix path to serve from. Default is '' (server root).
1364
1369
1365 ``push_ssl``
1370 ``push_ssl``
1366 Whether to require that inbound pushes be transported over SSL to
1371 Whether to require that inbound pushes be transported over SSL to
1367 prevent password sniffing. Default is True.
1372 prevent password sniffing. Default is True.
1368
1373
1369 ``staticurl``
1374 ``staticurl``
1370 Base URL to use for static files. If unset, static files (e.g. the
1375 Base URL to use for static files. If unset, static files (e.g. the
1371 hgicon.png favicon) will be served by the CGI script itself. Use
1376 hgicon.png favicon) will be served by the CGI script itself. Use
1372 this setting to serve them directly with the HTTP server.
1377 this setting to serve them directly with the HTTP server.
1373 Example: ``http://hgserver/static/``.
1378 Example: ``http://hgserver/static/``.
1374
1379
1375 ``stripes``
1380 ``stripes``
1376 How many lines a "zebra stripe" should span in multiline output.
1381 How many lines a "zebra stripe" should span in multiline output.
1377 Default is 1; set to 0 to disable.
1382 Default is 1; set to 0 to disable.
1378
1383
1379 ``style``
1384 ``style``
1380 Which template map style to use.
1385 Which template map style to use.
1381
1386
1382 ``templates``
1387 ``templates``
1383 Where to find the HTML templates. Default is install path.
1388 Where to find the HTML templates. Default is install path.
@@ -1,466 +1,469 b''
1 # posix.py - Posix utility function implementations for Mercurial
1 # posix.py - Posix utility function implementations for Mercurial
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import os, sys, errno, stat, getpass, pwd, grp, tempfile, unicodedata
9 import os, sys, errno, stat, getpass, pwd, grp, tempfile, unicodedata
10
10
11 posixfile = open
11 posixfile = open
12 nulldev = '/dev/null'
12 nulldev = '/dev/null'
13 normpath = os.path.normpath
13 normpath = os.path.normpath
14 samestat = os.path.samestat
14 samestat = os.path.samestat
15 oslink = os.link
15 oslink = os.link
16 unlink = os.unlink
16 unlink = os.unlink
17 rename = os.rename
17 rename = os.rename
18 expandglobs = False
18 expandglobs = False
19
19
20 umask = os.umask(0)
20 umask = os.umask(0)
21 os.umask(umask)
21 os.umask(umask)
22
22
23 def openhardlinks():
23 def openhardlinks():
24 '''return true if it is safe to hold open file handles to hardlinks'''
24 '''return true if it is safe to hold open file handles to hardlinks'''
25 return True
25 return True
26
26
27 def nlinks(name):
27 def nlinks(name):
28 '''return number of hardlinks for the given file'''
28 '''return number of hardlinks for the given file'''
29 return os.lstat(name).st_nlink
29 return os.lstat(name).st_nlink
30
30
31 def parsepatchoutput(output_line):
31 def parsepatchoutput(output_line):
32 """parses the output produced by patch and returns the filename"""
32 """parses the output produced by patch and returns the filename"""
33 pf = output_line[14:]
33 pf = output_line[14:]
34 if os.sys.platform == 'OpenVMS':
34 if os.sys.platform == 'OpenVMS':
35 if pf[0] == '`':
35 if pf[0] == '`':
36 pf = pf[1:-1] # Remove the quotes
36 pf = pf[1:-1] # Remove the quotes
37 else:
37 else:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
38 if pf.startswith("'") and pf.endswith("'") and " " in pf:
39 pf = pf[1:-1] # Remove the quotes
39 pf = pf[1:-1] # Remove the quotes
40 return pf
40 return pf
41
41
42 def sshargs(sshcmd, host, user, port):
42 def sshargs(sshcmd, host, user, port):
43 '''Build argument list for ssh'''
43 '''Build argument list for ssh'''
44 args = user and ("%s@%s" % (user, host)) or host
44 args = user and ("%s@%s" % (user, host)) or host
45 return port and ("%s -p %s" % (args, port)) or args
45 return port and ("%s -p %s" % (args, port)) or args
46
46
47 def isexec(f):
47 def isexec(f):
48 """check whether a file is executable"""
48 """check whether a file is executable"""
49 return (os.lstat(f).st_mode & 0100 != 0)
49 return (os.lstat(f).st_mode & 0100 != 0)
50
50
51 def setflags(f, l, x):
51 def setflags(f, l, x):
52 s = os.lstat(f).st_mode
52 s = os.lstat(f).st_mode
53 if l:
53 if l:
54 if not stat.S_ISLNK(s):
54 if not stat.S_ISLNK(s):
55 # switch file to link
55 # switch file to link
56 fp = open(f)
56 fp = open(f)
57 data = fp.read()
57 data = fp.read()
58 fp.close()
58 fp.close()
59 os.unlink(f)
59 os.unlink(f)
60 try:
60 try:
61 os.symlink(data, f)
61 os.symlink(data, f)
62 except OSError:
62 except OSError:
63 # failed to make a link, rewrite file
63 # failed to make a link, rewrite file
64 fp = open(f, "w")
64 fp = open(f, "w")
65 fp.write(data)
65 fp.write(data)
66 fp.close()
66 fp.close()
67 # no chmod needed at this point
67 # no chmod needed at this point
68 return
68 return
69 if stat.S_ISLNK(s):
69 if stat.S_ISLNK(s):
70 # switch link to file
70 # switch link to file
71 data = os.readlink(f)
71 data = os.readlink(f)
72 os.unlink(f)
72 os.unlink(f)
73 fp = open(f, "w")
73 fp = open(f, "w")
74 fp.write(data)
74 fp.write(data)
75 fp.close()
75 fp.close()
76 s = 0666 & ~umask # avoid restatting for chmod
76 s = 0666 & ~umask # avoid restatting for chmod
77
77
78 sx = s & 0100
78 sx = s & 0100
79 if x and not sx:
79 if x and not sx:
80 # Turn on +x for every +r bit when making a file executable
80 # Turn on +x for every +r bit when making a file executable
81 # and obey umask.
81 # and obey umask.
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
82 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
83 elif not x and sx:
83 elif not x and sx:
84 # Turn off all +x bits
84 # Turn off all +x bits
85 os.chmod(f, s & 0666)
85 os.chmod(f, s & 0666)
86
86
87 def copymode(src, dst, mode=None):
87 def copymode(src, dst, mode=None):
88 '''Copy the file mode from the file at path src to dst.
88 '''Copy the file mode from the file at path src to dst.
89 If src doesn't exist, we're using mode instead. If mode is None, we're
89 If src doesn't exist, we're using mode instead. If mode is None, we're
90 using umask.'''
90 using umask.'''
91 try:
91 try:
92 st_mode = os.lstat(src).st_mode & 0777
92 st_mode = os.lstat(src).st_mode & 0777
93 except OSError, inst:
93 except OSError, inst:
94 if inst.errno != errno.ENOENT:
94 if inst.errno != errno.ENOENT:
95 raise
95 raise
96 st_mode = mode
96 st_mode = mode
97 if st_mode is None:
97 if st_mode is None:
98 st_mode = ~umask
98 st_mode = ~umask
99 st_mode &= 0666
99 st_mode &= 0666
100 os.chmod(dst, st_mode)
100 os.chmod(dst, st_mode)
101
101
102 def checkexec(path):
102 def checkexec(path):
103 """
103 """
104 Check whether the given path is on a filesystem with UNIX-like exec flags
104 Check whether the given path is on a filesystem with UNIX-like exec flags
105
105
106 Requires a directory (like /foo/.hg)
106 Requires a directory (like /foo/.hg)
107 """
107 """
108
108
109 # VFAT on some Linux versions can flip mode but it doesn't persist
109 # VFAT on some Linux versions can flip mode but it doesn't persist
110 # a FS remount. Frequently we can detect it if files are created
110 # a FS remount. Frequently we can detect it if files are created
111 # with exec bit on.
111 # with exec bit on.
112
112
113 try:
113 try:
114 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
114 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
115 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
115 fh, fn = tempfile.mkstemp(dir=path, prefix='hg-checkexec-')
116 try:
116 try:
117 os.close(fh)
117 os.close(fh)
118 m = os.stat(fn).st_mode & 0777
118 m = os.stat(fn).st_mode & 0777
119 new_file_has_exec = m & EXECFLAGS
119 new_file_has_exec = m & EXECFLAGS
120 os.chmod(fn, m ^ EXECFLAGS)
120 os.chmod(fn, m ^ EXECFLAGS)
121 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
121 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0777) == m)
122 finally:
122 finally:
123 os.unlink(fn)
123 os.unlink(fn)
124 except (IOError, OSError):
124 except (IOError, OSError):
125 # we don't care, the user probably won't be able to commit anyway
125 # we don't care, the user probably won't be able to commit anyway
126 return False
126 return False
127 return not (new_file_has_exec or exec_flags_cannot_flip)
127 return not (new_file_has_exec or exec_flags_cannot_flip)
128
128
129 def checklink(path):
129 def checklink(path):
130 """check whether the given path is on a symlink-capable filesystem"""
130 """check whether the given path is on a symlink-capable filesystem"""
131 # mktemp is not racy because symlink creation will fail if the
131 # mktemp is not racy because symlink creation will fail if the
132 # file already exists
132 # file already exists
133 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
133 name = tempfile.mktemp(dir=path, prefix='hg-checklink-')
134 try:
134 try:
135 os.symlink(".", name)
135 os.symlink(".", name)
136 os.unlink(name)
136 os.unlink(name)
137 return True
137 return True
138 except (OSError, AttributeError):
138 except (OSError, AttributeError):
139 return False
139 return False
140
140
141 def checkosfilename(path):
141 def checkosfilename(path):
142 '''Check that the base-relative path is a valid filename on this platform.
142 '''Check that the base-relative path is a valid filename on this platform.
143 Returns None if the path is ok, or a UI string describing the problem.'''
143 Returns None if the path is ok, or a UI string describing the problem.'''
144 pass # on posix platforms, every path is ok
144 pass # on posix platforms, every path is ok
145
145
146 def setbinary(fd):
146 def setbinary(fd):
147 pass
147 pass
148
148
149 def pconvert(path):
149 def pconvert(path):
150 return path
150 return path
151
151
152 def localpath(path):
152 def localpath(path):
153 return path
153 return path
154
154
155 def samefile(fpath1, fpath2):
155 def samefile(fpath1, fpath2):
156 """Returns whether path1 and path2 refer to the same file. This is only
156 """Returns whether path1 and path2 refer to the same file. This is only
157 guaranteed to work for files, not directories."""
157 guaranteed to work for files, not directories."""
158 return os.path.samefile(fpath1, fpath2)
158 return os.path.samefile(fpath1, fpath2)
159
159
160 def samedevice(fpath1, fpath2):
160 def samedevice(fpath1, fpath2):
161 """Returns whether fpath1 and fpath2 are on the same device. This is only
161 """Returns whether fpath1 and fpath2 are on the same device. This is only
162 guaranteed to work for files, not directories."""
162 guaranteed to work for files, not directories."""
163 st1 = os.lstat(fpath1)
163 st1 = os.lstat(fpath1)
164 st2 = os.lstat(fpath2)
164 st2 = os.lstat(fpath2)
165 return st1.st_dev == st2.st_dev
165 return st1.st_dev == st2.st_dev
166
166
167 encodinglower = None
167 encodinglower = None
168 encodingupper = None
168 encodingupper = None
169
169
170 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
170 # os.path.normcase is a no-op, which doesn't help us on non-native filesystems
171 def normcase(path):
171 def normcase(path):
172 return path.lower()
172 return path.lower()
173
173
174 if sys.platform == 'darwin':
174 if sys.platform == 'darwin':
175 import fcntl # only needed on darwin, missing on jython
175 import fcntl # only needed on darwin, missing on jython
176
176
177 def normcase(path):
177 def normcase(path):
178 try:
178 try:
179 u = path.decode('utf-8')
179 u = path.decode('utf-8')
180 except UnicodeDecodeError:
180 except UnicodeDecodeError:
181 # percent-encode any characters that don't round-trip
181 # percent-encode any characters that don't round-trip
182 p2 = path.decode('utf-8', 'ignore').encode('utf-8')
182 p2 = path.decode('utf-8', 'ignore').encode('utf-8')
183 s = ""
183 s = ""
184 pos = 0
184 pos = 0
185 for c in path:
185 for c in path:
186 if p2[pos:pos + 1] == c:
186 if p2[pos:pos + 1] == c:
187 s += c
187 s += c
188 pos += 1
188 pos += 1
189 else:
189 else:
190 s += "%%%02X" % ord(c)
190 s += "%%%02X" % ord(c)
191 u = s.decode('utf-8')
191 u = s.decode('utf-8')
192
192
193 # Decompose then lowercase (HFS+ technote specifies lower)
193 # Decompose then lowercase (HFS+ technote specifies lower)
194 return unicodedata.normalize('NFD', u).lower().encode('utf-8')
194 return unicodedata.normalize('NFD', u).lower().encode('utf-8')
195
195
196 def realpath(path):
196 def realpath(path):
197 '''
197 '''
198 Returns the true, canonical file system path equivalent to the given
198 Returns the true, canonical file system path equivalent to the given
199 path.
199 path.
200
200
201 Equivalent means, in this case, resulting in the same, unique
201 Equivalent means, in this case, resulting in the same, unique
202 file system link to the path. Every file system entry, whether a file,
202 file system link to the path. Every file system entry, whether a file,
203 directory, hard link or symbolic link or special, will have a single
203 directory, hard link or symbolic link or special, will have a single
204 path preferred by the system, but may allow multiple, differing path
204 path preferred by the system, but may allow multiple, differing path
205 lookups to point to it.
205 lookups to point to it.
206
206
207 Most regular UNIX file systems only allow a file system entry to be
207 Most regular UNIX file systems only allow a file system entry to be
208 looked up by its distinct path. Obviously, this does not apply to case
208 looked up by its distinct path. Obviously, this does not apply to case
209 insensitive file systems, whether case preserving or not. The most
209 insensitive file systems, whether case preserving or not. The most
210 complex issue to deal with is file systems transparently reencoding the
210 complex issue to deal with is file systems transparently reencoding the
211 path, such as the non-standard Unicode normalisation required for HFS+
211 path, such as the non-standard Unicode normalisation required for HFS+
212 and HFSX.
212 and HFSX.
213 '''
213 '''
214 # Constants copied from /usr/include/sys/fcntl.h
214 # Constants copied from /usr/include/sys/fcntl.h
215 F_GETPATH = 50
215 F_GETPATH = 50
216 O_SYMLINK = 0x200000
216 O_SYMLINK = 0x200000
217
217
218 try:
218 try:
219 fd = os.open(path, O_SYMLINK)
219 fd = os.open(path, O_SYMLINK)
220 except OSError, err:
220 except OSError, err:
221 if err.errno == errno.ENOENT:
221 if err.errno == errno.ENOENT:
222 return path
222 return path
223 raise
223 raise
224
224
225 try:
225 try:
226 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
226 return fcntl.fcntl(fd, F_GETPATH, '\0' * 1024).rstrip('\0')
227 finally:
227 finally:
228 os.close(fd)
228 os.close(fd)
229 elif sys.version_info < (2, 4, 2, 'final'):
229 elif sys.version_info < (2, 4, 2, 'final'):
230 # Workaround for http://bugs.python.org/issue1213894 (os.path.realpath
230 # Workaround for http://bugs.python.org/issue1213894 (os.path.realpath
231 # didn't resolve symlinks that were the first component of the path.)
231 # didn't resolve symlinks that were the first component of the path.)
232 def realpath(path):
232 def realpath(path):
233 if os.path.isabs(path):
233 if os.path.isabs(path):
234 return os.path.realpath(path)
234 return os.path.realpath(path)
235 else:
235 else:
236 return os.path.realpath('./' + path)
236 return os.path.realpath('./' + path)
237 else:
237 else:
238 # Fallback to the likely inadequate Python builtin function.
238 # Fallback to the likely inadequate Python builtin function.
239 realpath = os.path.realpath
239 realpath = os.path.realpath
240
240
241 if sys.platform == 'cygwin':
241 if sys.platform == 'cygwin':
242 # workaround for cygwin, in which mount point part of path is
242 # workaround for cygwin, in which mount point part of path is
243 # treated as case sensitive, even though underlying NTFS is case
243 # treated as case sensitive, even though underlying NTFS is case
244 # insensitive.
244 # insensitive.
245
245
246 # default mount points
246 # default mount points
247 cygwinmountpoints = sorted([
247 cygwinmountpoints = sorted([
248 "/usr/bin",
248 "/usr/bin",
249 "/usr/lib",
249 "/usr/lib",
250 "/cygdrive",
250 "/cygdrive",
251 ], reverse=True)
251 ], reverse=True)
252
252
253 # use upper-ing as normcase as same as NTFS workaround
253 # use upper-ing as normcase as same as NTFS workaround
254 def normcase(path):
254 def normcase(path):
255 pathlen = len(path)
255 pathlen = len(path)
256 if (pathlen == 0) or (path[0] != os.sep):
256 if (pathlen == 0) or (path[0] != os.sep):
257 # treat as relative
257 # treat as relative
258 return encodingupper(path)
258 return encodingupper(path)
259
259
260 # to preserve case of mountpoint part
260 # to preserve case of mountpoint part
261 for mp in cygwinmountpoints:
261 for mp in cygwinmountpoints:
262 if not path.startswith(mp):
262 if not path.startswith(mp):
263 continue
263 continue
264
264
265 mplen = len(mp)
265 mplen = len(mp)
266 if mplen == pathlen: # mount point itself
266 if mplen == pathlen: # mount point itself
267 return mp
267 return mp
268 if path[mplen] == os.sep:
268 if path[mplen] == os.sep:
269 return mp + encodingupper(path[mplen:])
269 return mp + encodingupper(path[mplen:])
270
270
271 return encodingupper(path)
271 return encodingupper(path)
272
272
273 # Cygwin translates native ACLs to POSIX permissions,
273 # Cygwin translates native ACLs to POSIX permissions,
274 # but these translations are not supported by native
274 # but these translations are not supported by native
275 # tools, so the exec bit tends to be set erroneously.
275 # tools, so the exec bit tends to be set erroneously.
276 # Therefore, disable executable bit access on Cygwin.
276 # Therefore, disable executable bit access on Cygwin.
277 def checkexec(path):
277 def checkexec(path):
278 return False
278 return False
279
279
280 # Similarly, Cygwin's symlink emulation is likely to create
280 # Similarly, Cygwin's symlink emulation is likely to create
281 # problems when Mercurial is used from both Cygwin and native
281 # problems when Mercurial is used from both Cygwin and native
282 # Windows, with other native tools, or on shared volumes
282 # Windows, with other native tools, or on shared volumes
283 def checklink(path):
283 def checklink(path):
284 return False
284 return False
285
285
286 def shellquote(s):
286 def shellquote(s):
287 if os.sys.platform == 'OpenVMS':
287 if os.sys.platform == 'OpenVMS':
288 return '"%s"' % s
288 return '"%s"' % s
289 else:
289 else:
290 return "'%s'" % s.replace("'", "'\\''")
290 return "'%s'" % s.replace("'", "'\\''")
291
291
292 def quotecommand(cmd):
292 def quotecommand(cmd):
293 return cmd
293 return cmd
294
294
295 def popen(command, mode='r'):
295 def popen(command, mode='r'):
296 return os.popen(command, mode)
296 return os.popen(command, mode)
297
297
298 def testpid(pid):
298 def testpid(pid):
299 '''return False if pid dead, True if running or not sure'''
299 '''return False if pid dead, True if running or not sure'''
300 if os.sys.platform == 'OpenVMS':
300 if os.sys.platform == 'OpenVMS':
301 return True
301 return True
302 try:
302 try:
303 os.kill(pid, 0)
303 os.kill(pid, 0)
304 return True
304 return True
305 except OSError, inst:
305 except OSError, inst:
306 return inst.errno != errno.ESRCH
306 return inst.errno != errno.ESRCH
307
307
308 def explainexit(code):
308 def explainexit(code):
309 """return a 2-tuple (desc, code) describing a subprocess status
309 """return a 2-tuple (desc, code) describing a subprocess status
310 (codes from kill are negative - not os.system/wait encoding)"""
310 (codes from kill are negative - not os.system/wait encoding)"""
311 if code >= 0:
311 if code >= 0:
312 return _("exited with status %d") % code, code
312 return _("exited with status %d") % code, code
313 return _("killed by signal %d") % -code, -code
313 return _("killed by signal %d") % -code, -code
314
314
315 def isowner(st):
315 def isowner(st):
316 """Return True if the stat object st is from the current user."""
316 """Return True if the stat object st is from the current user."""
317 return st.st_uid == os.getuid()
317 return st.st_uid == os.getuid()
318
318
319 def findexe(command):
319 def findexe(command):
320 '''Find executable for command searching like which does.
320 '''Find executable for command searching like which does.
321 If command is a basename then PATH is searched for command.
321 If command is a basename then PATH is searched for command.
322 PATH isn't searched if command is an absolute or relative path.
322 PATH isn't searched if command is an absolute or relative path.
323 If command isn't found None is returned.'''
323 If command isn't found None is returned.'''
324 if sys.platform == 'OpenVMS':
324 if sys.platform == 'OpenVMS':
325 return command
325 return command
326
326
327 def findexisting(executable):
327 def findexisting(executable):
328 'Will return executable if existing file'
328 'Will return executable if existing file'
329 if os.path.isfile(executable) and os.access(executable, os.X_OK):
329 if os.path.isfile(executable) and os.access(executable, os.X_OK):
330 return executable
330 return executable
331 return None
331 return None
332
332
333 if os.sep in command:
333 if os.sep in command:
334 return findexisting(command)
334 return findexisting(command)
335
335
336 if sys.platform == 'plan9':
337 return findexisting(os.path.join('/bin', command))
338
336 for path in os.environ.get('PATH', '').split(os.pathsep):
339 for path in os.environ.get('PATH', '').split(os.pathsep):
337 executable = findexisting(os.path.join(path, command))
340 executable = findexisting(os.path.join(path, command))
338 if executable is not None:
341 if executable is not None:
339 return executable
342 return executable
340 return None
343 return None
341
344
342 def setsignalhandler():
345 def setsignalhandler():
343 pass
346 pass
344
347
345 def statfiles(files):
348 def statfiles(files):
346 'Stat each file in files and yield stat or None if file does not exist.'
349 'Stat each file in files and yield stat or None if file does not exist.'
347 lstat = os.lstat
350 lstat = os.lstat
348 for nf in files:
351 for nf in files:
349 try:
352 try:
350 st = lstat(nf)
353 st = lstat(nf)
351 except OSError, err:
354 except OSError, err:
352 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
355 if err.errno not in (errno.ENOENT, errno.ENOTDIR):
353 raise
356 raise
354 st = None
357 st = None
355 yield st
358 yield st
356
359
357 def getuser():
360 def getuser():
358 '''return name of current user'''
361 '''return name of current user'''
359 return getpass.getuser()
362 return getpass.getuser()
360
363
361 def username(uid=None):
364 def username(uid=None):
362 """Return the name of the user with the given uid.
365 """Return the name of the user with the given uid.
363
366
364 If uid is None, return the name of the current user."""
367 If uid is None, return the name of the current user."""
365
368
366 if uid is None:
369 if uid is None:
367 uid = os.getuid()
370 uid = os.getuid()
368 try:
371 try:
369 return pwd.getpwuid(uid)[0]
372 return pwd.getpwuid(uid)[0]
370 except KeyError:
373 except KeyError:
371 return str(uid)
374 return str(uid)
372
375
373 def groupname(gid=None):
376 def groupname(gid=None):
374 """Return the name of the group with the given gid.
377 """Return the name of the group with the given gid.
375
378
376 If gid is None, return the name of the current group."""
379 If gid is None, return the name of the current group."""
377
380
378 if gid is None:
381 if gid is None:
379 gid = os.getgid()
382 gid = os.getgid()
380 try:
383 try:
381 return grp.getgrgid(gid)[0]
384 return grp.getgrgid(gid)[0]
382 except KeyError:
385 except KeyError:
383 return str(gid)
386 return str(gid)
384
387
385 def groupmembers(name):
388 def groupmembers(name):
386 """Return the list of members of the group with the given
389 """Return the list of members of the group with the given
387 name, KeyError if the group does not exist.
390 name, KeyError if the group does not exist.
388 """
391 """
389 return list(grp.getgrnam(name).gr_mem)
392 return list(grp.getgrnam(name).gr_mem)
390
393
391 def spawndetached(args):
394 def spawndetached(args):
392 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
395 return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
393 args[0], args)
396 args[0], args)
394
397
395 def gethgcmd():
398 def gethgcmd():
396 return sys.argv[:1]
399 return sys.argv[:1]
397
400
398 def termwidth():
401 def termwidth():
399 try:
402 try:
400 import termios, array, fcntl
403 import termios, array, fcntl
401 for dev in (sys.stderr, sys.stdout, sys.stdin):
404 for dev in (sys.stderr, sys.stdout, sys.stdin):
402 try:
405 try:
403 try:
406 try:
404 fd = dev.fileno()
407 fd = dev.fileno()
405 except AttributeError:
408 except AttributeError:
406 continue
409 continue
407 if not os.isatty(fd):
410 if not os.isatty(fd):
408 continue
411 continue
409 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
412 arri = fcntl.ioctl(fd, termios.TIOCGWINSZ, '\0' * 8)
410 width = array.array('h', arri)[1]
413 width = array.array('h', arri)[1]
411 if width > 0:
414 if width > 0:
412 return width
415 return width
413 except ValueError:
416 except ValueError:
414 pass
417 pass
415 except IOError, e:
418 except IOError, e:
416 if e[0] == errno.EINVAL:
419 if e[0] == errno.EINVAL:
417 pass
420 pass
418 else:
421 else:
419 raise
422 raise
420 except ImportError:
423 except ImportError:
421 pass
424 pass
422 return 80
425 return 80
423
426
424 def makedir(path, notindexed):
427 def makedir(path, notindexed):
425 os.mkdir(path)
428 os.mkdir(path)
426
429
427 def unlinkpath(f):
430 def unlinkpath(f):
428 """unlink and remove the directory if it is empty"""
431 """unlink and remove the directory if it is empty"""
429 os.unlink(f)
432 os.unlink(f)
430 # try removing directories that might now be empty
433 # try removing directories that might now be empty
431 try:
434 try:
432 os.removedirs(os.path.dirname(f))
435 os.removedirs(os.path.dirname(f))
433 except OSError:
436 except OSError:
434 pass
437 pass
435
438
436 def lookupreg(key, name=None, scope=None):
439 def lookupreg(key, name=None, scope=None):
437 return None
440 return None
438
441
439 def hidewindow():
442 def hidewindow():
440 """Hide current shell window.
443 """Hide current shell window.
441
444
442 Used to hide the window opened when starting asynchronous
445 Used to hide the window opened when starting asynchronous
443 child process under Windows, unneeded on other systems.
446 child process under Windows, unneeded on other systems.
444 """
447 """
445 pass
448 pass
446
449
447 class cachestat(object):
450 class cachestat(object):
448 def __init__(self, path):
451 def __init__(self, path):
449 self.stat = os.stat(path)
452 self.stat = os.stat(path)
450
453
451 def cacheable(self):
454 def cacheable(self):
452 return bool(self.stat.st_ino)
455 return bool(self.stat.st_ino)
453
456
454 __hash__ = object.__hash__
457 __hash__ = object.__hash__
455
458
456 def __eq__(self, other):
459 def __eq__(self, other):
457 try:
460 try:
458 return self.stat == other.stat
461 return self.stat == other.stat
459 except AttributeError:
462 except AttributeError:
460 return False
463 return False
461
464
462 def __ne__(self, other):
465 def __ne__(self, other):
463 return not self == other
466 return not self == other
464
467
465 def executablepath():
468 def executablepath():
466 return None # available on Windows only
469 return None # available on Windows only
@@ -1,859 +1,866 b''
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import util, error, osutil, revset, similar, encoding
9 import util, error, osutil, revset, similar, encoding
10 import match as matchmod
10 import match as matchmod
11 import os, errno, re, stat, sys, glob
11 import os, errno, re, stat, sys, glob
12
12
13 def nochangesfound(ui, secretlist=None):
13 def nochangesfound(ui, secretlist=None):
14 '''report no changes for push/pull'''
14 '''report no changes for push/pull'''
15 if secretlist:
15 if secretlist:
16 ui.status(_("no changes found (ignored %d secret changesets)\n")
16 ui.status(_("no changes found (ignored %d secret changesets)\n")
17 % len(secretlist))
17 % len(secretlist))
18 else:
18 else:
19 ui.status(_("no changes found\n"))
19 ui.status(_("no changes found\n"))
20
20
21 def checkfilename(f):
21 def checkfilename(f):
22 '''Check that the filename f is an acceptable filename for a tracked file'''
22 '''Check that the filename f is an acceptable filename for a tracked file'''
23 if '\r' in f or '\n' in f:
23 if '\r' in f or '\n' in f:
24 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
24 raise util.Abort(_("'\\n' and '\\r' disallowed in filenames: %r") % f)
25
25
26 def checkportable(ui, f):
26 def checkportable(ui, f):
27 '''Check if filename f is portable and warn or abort depending on config'''
27 '''Check if filename f is portable and warn or abort depending on config'''
28 checkfilename(f)
28 checkfilename(f)
29 abort, warn = checkportabilityalert(ui)
29 abort, warn = checkportabilityalert(ui)
30 if abort or warn:
30 if abort or warn:
31 msg = util.checkwinfilename(f)
31 msg = util.checkwinfilename(f)
32 if msg:
32 if msg:
33 msg = "%s: %r" % (msg, f)
33 msg = "%s: %r" % (msg, f)
34 if abort:
34 if abort:
35 raise util.Abort(msg)
35 raise util.Abort(msg)
36 ui.warn(_("warning: %s\n") % msg)
36 ui.warn(_("warning: %s\n") % msg)
37
37
38 def checkportabilityalert(ui):
38 def checkportabilityalert(ui):
39 '''check if the user's config requests nothing, a warning, or abort for
39 '''check if the user's config requests nothing, a warning, or abort for
40 non-portable filenames'''
40 non-portable filenames'''
41 val = ui.config('ui', 'portablefilenames', 'warn')
41 val = ui.config('ui', 'portablefilenames', 'warn')
42 lval = val.lower()
42 lval = val.lower()
43 bval = util.parsebool(val)
43 bval = util.parsebool(val)
44 abort = os.name == 'nt' or lval == 'abort'
44 abort = os.name == 'nt' or lval == 'abort'
45 warn = bval or lval == 'warn'
45 warn = bval or lval == 'warn'
46 if bval is None and not (warn or abort or lval == 'ignore'):
46 if bval is None and not (warn or abort or lval == 'ignore'):
47 raise error.ConfigError(
47 raise error.ConfigError(
48 _("ui.portablefilenames value is invalid ('%s')") % val)
48 _("ui.portablefilenames value is invalid ('%s')") % val)
49 return abort, warn
49 return abort, warn
50
50
51 class casecollisionauditor(object):
51 class casecollisionauditor(object):
52 def __init__(self, ui, abort, existingiter):
52 def __init__(self, ui, abort, existingiter):
53 self._ui = ui
53 self._ui = ui
54 self._abort = abort
54 self._abort = abort
55 self._map = {}
55 self._map = {}
56 for f in existingiter:
56 for f in existingiter:
57 self._map[encoding.lower(f)] = f
57 self._map[encoding.lower(f)] = f
58
58
59 def __call__(self, f):
59 def __call__(self, f):
60 fl = encoding.lower(f)
60 fl = encoding.lower(f)
61 map = self._map
61 map = self._map
62 if fl in map and map[fl] != f:
62 if fl in map and map[fl] != f:
63 msg = _('possible case-folding collision for %s') % f
63 msg = _('possible case-folding collision for %s') % f
64 if self._abort:
64 if self._abort:
65 raise util.Abort(msg)
65 raise util.Abort(msg)
66 self._ui.warn(_("warning: %s\n") % msg)
66 self._ui.warn(_("warning: %s\n") % msg)
67 map[fl] = f
67 map[fl] = f
68
68
69 class pathauditor(object):
69 class pathauditor(object):
70 '''ensure that a filesystem path contains no banned components.
70 '''ensure that a filesystem path contains no banned components.
71 the following properties of a path are checked:
71 the following properties of a path are checked:
72
72
73 - ends with a directory separator
73 - ends with a directory separator
74 - under top-level .hg
74 - under top-level .hg
75 - starts at the root of a windows drive
75 - starts at the root of a windows drive
76 - contains ".."
76 - contains ".."
77 - traverses a symlink (e.g. a/symlink_here/b)
77 - traverses a symlink (e.g. a/symlink_here/b)
78 - inside a nested repository (a callback can be used to approve
78 - inside a nested repository (a callback can be used to approve
79 some nested repositories, e.g., subrepositories)
79 some nested repositories, e.g., subrepositories)
80 '''
80 '''
81
81
82 def __init__(self, root, callback=None):
82 def __init__(self, root, callback=None):
83 self.audited = set()
83 self.audited = set()
84 self.auditeddir = set()
84 self.auditeddir = set()
85 self.root = root
85 self.root = root
86 self.callback = callback
86 self.callback = callback
87 if os.path.lexists(root) and not util.checkcase(root):
87 if os.path.lexists(root) and not util.checkcase(root):
88 self.normcase = util.normcase
88 self.normcase = util.normcase
89 else:
89 else:
90 self.normcase = lambda x: x
90 self.normcase = lambda x: x
91
91
92 def __call__(self, path):
92 def __call__(self, path):
93 '''Check the relative path.
93 '''Check the relative path.
94 path may contain a pattern (e.g. foodir/**.txt)'''
94 path may contain a pattern (e.g. foodir/**.txt)'''
95
95
96 path = util.localpath(path)
96 path = util.localpath(path)
97 normpath = self.normcase(path)
97 normpath = self.normcase(path)
98 if normpath in self.audited:
98 if normpath in self.audited:
99 return
99 return
100 # AIX ignores "/" at end of path, others raise EISDIR.
100 # AIX ignores "/" at end of path, others raise EISDIR.
101 if util.endswithsep(path):
101 if util.endswithsep(path):
102 raise util.Abort(_("path ends in directory separator: %s") % path)
102 raise util.Abort(_("path ends in directory separator: %s") % path)
103 parts = util.splitpath(path)
103 parts = util.splitpath(path)
104 if (os.path.splitdrive(path)[0]
104 if (os.path.splitdrive(path)[0]
105 or parts[0].lower() in ('.hg', '.hg.', '')
105 or parts[0].lower() in ('.hg', '.hg.', '')
106 or os.pardir in parts):
106 or os.pardir in parts):
107 raise util.Abort(_("path contains illegal component: %s") % path)
107 raise util.Abort(_("path contains illegal component: %s") % path)
108 if '.hg' in path.lower():
108 if '.hg' in path.lower():
109 lparts = [p.lower() for p in parts]
109 lparts = [p.lower() for p in parts]
110 for p in '.hg', '.hg.':
110 for p in '.hg', '.hg.':
111 if p in lparts[1:]:
111 if p in lparts[1:]:
112 pos = lparts.index(p)
112 pos = lparts.index(p)
113 base = os.path.join(*parts[:pos])
113 base = os.path.join(*parts[:pos])
114 raise util.Abort(_("path '%s' is inside nested repo %r")
114 raise util.Abort(_("path '%s' is inside nested repo %r")
115 % (path, base))
115 % (path, base))
116
116
117 normparts = util.splitpath(normpath)
117 normparts = util.splitpath(normpath)
118 assert len(parts) == len(normparts)
118 assert len(parts) == len(normparts)
119
119
120 parts.pop()
120 parts.pop()
121 normparts.pop()
121 normparts.pop()
122 prefixes = []
122 prefixes = []
123 while parts:
123 while parts:
124 prefix = os.sep.join(parts)
124 prefix = os.sep.join(parts)
125 normprefix = os.sep.join(normparts)
125 normprefix = os.sep.join(normparts)
126 if normprefix in self.auditeddir:
126 if normprefix in self.auditeddir:
127 break
127 break
128 curpath = os.path.join(self.root, prefix)
128 curpath = os.path.join(self.root, prefix)
129 try:
129 try:
130 st = os.lstat(curpath)
130 st = os.lstat(curpath)
131 except OSError, err:
131 except OSError, err:
132 # EINVAL can be raised as invalid path syntax under win32.
132 # EINVAL can be raised as invalid path syntax under win32.
133 # They must be ignored for patterns can be checked too.
133 # They must be ignored for patterns can be checked too.
134 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
134 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
135 raise
135 raise
136 else:
136 else:
137 if stat.S_ISLNK(st.st_mode):
137 if stat.S_ISLNK(st.st_mode):
138 raise util.Abort(
138 raise util.Abort(
139 _('path %r traverses symbolic link %r')
139 _('path %r traverses symbolic link %r')
140 % (path, prefix))
140 % (path, prefix))
141 elif (stat.S_ISDIR(st.st_mode) and
141 elif (stat.S_ISDIR(st.st_mode) and
142 os.path.isdir(os.path.join(curpath, '.hg'))):
142 os.path.isdir(os.path.join(curpath, '.hg'))):
143 if not self.callback or not self.callback(curpath):
143 if not self.callback or not self.callback(curpath):
144 raise util.Abort(_("path '%s' is inside nested repo %r") %
144 raise util.Abort(_("path '%s' is inside nested repo %r") %
145 (path, prefix))
145 (path, prefix))
146 prefixes.append(normprefix)
146 prefixes.append(normprefix)
147 parts.pop()
147 parts.pop()
148 normparts.pop()
148 normparts.pop()
149
149
150 self.audited.add(normpath)
150 self.audited.add(normpath)
151 # only add prefixes to the cache after checking everything: we don't
151 # only add prefixes to the cache after checking everything: we don't
152 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
152 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
153 self.auditeddir.update(prefixes)
153 self.auditeddir.update(prefixes)
154
154
155 class abstractopener(object):
155 class abstractopener(object):
156 """Abstract base class; cannot be instantiated"""
156 """Abstract base class; cannot be instantiated"""
157
157
158 def __init__(self, *args, **kwargs):
158 def __init__(self, *args, **kwargs):
159 '''Prevent instantiation; don't call this from subclasses.'''
159 '''Prevent instantiation; don't call this from subclasses.'''
160 raise NotImplementedError('attempted instantiating ' + str(type(self)))
160 raise NotImplementedError('attempted instantiating ' + str(type(self)))
161
161
162 def read(self, path):
162 def read(self, path):
163 fp = self(path, 'rb')
163 fp = self(path, 'rb')
164 try:
164 try:
165 return fp.read()
165 return fp.read()
166 finally:
166 finally:
167 fp.close()
167 fp.close()
168
168
169 def write(self, path, data):
169 def write(self, path, data):
170 fp = self(path, 'wb')
170 fp = self(path, 'wb')
171 try:
171 try:
172 return fp.write(data)
172 return fp.write(data)
173 finally:
173 finally:
174 fp.close()
174 fp.close()
175
175
176 def append(self, path, data):
176 def append(self, path, data):
177 fp = self(path, 'ab')
177 fp = self(path, 'ab')
178 try:
178 try:
179 return fp.write(data)
179 return fp.write(data)
180 finally:
180 finally:
181 fp.close()
181 fp.close()
182
182
183 class opener(abstractopener):
183 class opener(abstractopener):
184 '''Open files relative to a base directory
184 '''Open files relative to a base directory
185
185
186 This class is used to hide the details of COW semantics and
186 This class is used to hide the details of COW semantics and
187 remote file access from higher level code.
187 remote file access from higher level code.
188 '''
188 '''
189 def __init__(self, base, audit=True):
189 def __init__(self, base, audit=True):
190 self.base = base
190 self.base = base
191 self._audit = audit
191 self._audit = audit
192 if audit:
192 if audit:
193 self.auditor = pathauditor(base)
193 self.auditor = pathauditor(base)
194 else:
194 else:
195 self.auditor = util.always
195 self.auditor = util.always
196 self.createmode = None
196 self.createmode = None
197 self._trustnlink = None
197 self._trustnlink = None
198
198
199 @util.propertycache
199 @util.propertycache
200 def _cansymlink(self):
200 def _cansymlink(self):
201 return util.checklink(self.base)
201 return util.checklink(self.base)
202
202
203 def _fixfilemode(self, name):
203 def _fixfilemode(self, name):
204 if self.createmode is None:
204 if self.createmode is None:
205 return
205 return
206 os.chmod(name, self.createmode & 0666)
206 os.chmod(name, self.createmode & 0666)
207
207
208 def __call__(self, path, mode="r", text=False, atomictemp=False):
208 def __call__(self, path, mode="r", text=False, atomictemp=False):
209 if self._audit:
209 if self._audit:
210 r = util.checkosfilename(path)
210 r = util.checkosfilename(path)
211 if r:
211 if r:
212 raise util.Abort("%s: %r" % (r, path))
212 raise util.Abort("%s: %r" % (r, path))
213 self.auditor(path)
213 self.auditor(path)
214 f = self.join(path)
214 f = self.join(path)
215
215
216 if not text and "b" not in mode:
216 if not text and "b" not in mode:
217 mode += "b" # for that other OS
217 mode += "b" # for that other OS
218
218
219 nlink = -1
219 nlink = -1
220 dirname, basename = os.path.split(f)
220 dirname, basename = os.path.split(f)
221 # If basename is empty, then the path is malformed because it points
221 # If basename is empty, then the path is malformed because it points
222 # to a directory. Let the posixfile() call below raise IOError.
222 # to a directory. Let the posixfile() call below raise IOError.
223 if basename and mode not in ('r', 'rb'):
223 if basename and mode not in ('r', 'rb'):
224 if atomictemp:
224 if atomictemp:
225 if not os.path.isdir(dirname):
225 if not os.path.isdir(dirname):
226 util.makedirs(dirname, self.createmode)
226 util.makedirs(dirname, self.createmode)
227 return util.atomictempfile(f, mode, self.createmode)
227 return util.atomictempfile(f, mode, self.createmode)
228 try:
228 try:
229 if 'w' in mode:
229 if 'w' in mode:
230 util.unlink(f)
230 util.unlink(f)
231 nlink = 0
231 nlink = 0
232 else:
232 else:
233 # nlinks() may behave differently for files on Windows
233 # nlinks() may behave differently for files on Windows
234 # shares if the file is open.
234 # shares if the file is open.
235 fd = util.posixfile(f)
235 fd = util.posixfile(f)
236 nlink = util.nlinks(f)
236 nlink = util.nlinks(f)
237 if nlink < 1:
237 if nlink < 1:
238 nlink = 2 # force mktempcopy (issue1922)
238 nlink = 2 # force mktempcopy (issue1922)
239 fd.close()
239 fd.close()
240 except (OSError, IOError), e:
240 except (OSError, IOError), e:
241 if e.errno != errno.ENOENT:
241 if e.errno != errno.ENOENT:
242 raise
242 raise
243 nlink = 0
243 nlink = 0
244 if not os.path.isdir(dirname):
244 if not os.path.isdir(dirname):
245 util.makedirs(dirname, self.createmode)
245 util.makedirs(dirname, self.createmode)
246 if nlink > 0:
246 if nlink > 0:
247 if self._trustnlink is None:
247 if self._trustnlink is None:
248 self._trustnlink = nlink > 1 or util.checknlink(f)
248 self._trustnlink = nlink > 1 or util.checknlink(f)
249 if nlink > 1 or not self._trustnlink:
249 if nlink > 1 or not self._trustnlink:
250 util.rename(util.mktempcopy(f), f)
250 util.rename(util.mktempcopy(f), f)
251 fp = util.posixfile(f, mode)
251 fp = util.posixfile(f, mode)
252 if nlink == 0:
252 if nlink == 0:
253 self._fixfilemode(f)
253 self._fixfilemode(f)
254 return fp
254 return fp
255
255
256 def symlink(self, src, dst):
256 def symlink(self, src, dst):
257 self.auditor(dst)
257 self.auditor(dst)
258 linkname = self.join(dst)
258 linkname = self.join(dst)
259 try:
259 try:
260 os.unlink(linkname)
260 os.unlink(linkname)
261 except OSError:
261 except OSError:
262 pass
262 pass
263
263
264 dirname = os.path.dirname(linkname)
264 dirname = os.path.dirname(linkname)
265 if not os.path.exists(dirname):
265 if not os.path.exists(dirname):
266 util.makedirs(dirname, self.createmode)
266 util.makedirs(dirname, self.createmode)
267
267
268 if self._cansymlink:
268 if self._cansymlink:
269 try:
269 try:
270 os.symlink(src, linkname)
270 os.symlink(src, linkname)
271 except OSError, err:
271 except OSError, err:
272 raise OSError(err.errno, _('could not symlink to %r: %s') %
272 raise OSError(err.errno, _('could not symlink to %r: %s') %
273 (src, err.strerror), linkname)
273 (src, err.strerror), linkname)
274 else:
274 else:
275 f = self(dst, "w")
275 f = self(dst, "w")
276 f.write(src)
276 f.write(src)
277 f.close()
277 f.close()
278 self._fixfilemode(dst)
278 self._fixfilemode(dst)
279
279
280 def audit(self, path):
280 def audit(self, path):
281 self.auditor(path)
281 self.auditor(path)
282
282
283 def join(self, path):
283 def join(self, path):
284 return os.path.join(self.base, path)
284 return os.path.join(self.base, path)
285
285
286 class filteropener(abstractopener):
286 class filteropener(abstractopener):
287 '''Wrapper opener for filtering filenames with a function.'''
287 '''Wrapper opener for filtering filenames with a function.'''
288
288
289 def __init__(self, opener, filter):
289 def __init__(self, opener, filter):
290 self._filter = filter
290 self._filter = filter
291 self._orig = opener
291 self._orig = opener
292
292
293 def __call__(self, path, *args, **kwargs):
293 def __call__(self, path, *args, **kwargs):
294 return self._orig(self._filter(path), *args, **kwargs)
294 return self._orig(self._filter(path), *args, **kwargs)
295
295
296 def canonpath(root, cwd, myname, auditor=None):
296 def canonpath(root, cwd, myname, auditor=None):
297 '''return the canonical path of myname, given cwd and root'''
297 '''return the canonical path of myname, given cwd and root'''
298 if util.endswithsep(root):
298 if util.endswithsep(root):
299 rootsep = root
299 rootsep = root
300 else:
300 else:
301 rootsep = root + os.sep
301 rootsep = root + os.sep
302 name = myname
302 name = myname
303 if not os.path.isabs(name):
303 if not os.path.isabs(name):
304 name = os.path.join(root, cwd, name)
304 name = os.path.join(root, cwd, name)
305 name = os.path.normpath(name)
305 name = os.path.normpath(name)
306 if auditor is None:
306 if auditor is None:
307 auditor = pathauditor(root)
307 auditor = pathauditor(root)
308 if name != rootsep and name.startswith(rootsep):
308 if name != rootsep and name.startswith(rootsep):
309 name = name[len(rootsep):]
309 name = name[len(rootsep):]
310 auditor(name)
310 auditor(name)
311 return util.pconvert(name)
311 return util.pconvert(name)
312 elif name == root:
312 elif name == root:
313 return ''
313 return ''
314 else:
314 else:
315 # Determine whether `name' is in the hierarchy at or beneath `root',
315 # Determine whether `name' is in the hierarchy at or beneath `root',
316 # by iterating name=dirname(name) until that causes no change (can't
316 # by iterating name=dirname(name) until that causes no change (can't
317 # check name == '/', because that doesn't work on windows). For each
317 # check name == '/', because that doesn't work on windows). For each
318 # `name', compare dev/inode numbers. If they match, the list `rel'
318 # `name', compare dev/inode numbers. If they match, the list `rel'
319 # holds the reversed list of components making up the relative file
319 # holds the reversed list of components making up the relative file
320 # name we want.
320 # name we want.
321 root_st = os.stat(root)
321 root_st = os.stat(root)
322 rel = []
322 rel = []
323 while True:
323 while True:
324 try:
324 try:
325 name_st = os.stat(name)
325 name_st = os.stat(name)
326 except OSError:
326 except OSError:
327 name_st = None
327 name_st = None
328 if name_st and util.samestat(name_st, root_st):
328 if name_st and util.samestat(name_st, root_st):
329 if not rel:
329 if not rel:
330 # name was actually the same as root (maybe a symlink)
330 # name was actually the same as root (maybe a symlink)
331 return ''
331 return ''
332 rel.reverse()
332 rel.reverse()
333 name = os.path.join(*rel)
333 name = os.path.join(*rel)
334 auditor(name)
334 auditor(name)
335 return util.pconvert(name)
335 return util.pconvert(name)
336 dirname, basename = os.path.split(name)
336 dirname, basename = os.path.split(name)
337 rel.append(basename)
337 rel.append(basename)
338 if dirname == name:
338 if dirname == name:
339 break
339 break
340 name = dirname
340 name = dirname
341
341
342 raise util.Abort('%s not under root' % myname)
342 raise util.Abort('%s not under root' % myname)
343
343
344 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
344 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
345 '''yield every hg repository under path, recursively.'''
345 '''yield every hg repository under path, recursively.'''
346 def errhandler(err):
346 def errhandler(err):
347 if err.filename == path:
347 if err.filename == path:
348 raise err
348 raise err
349 samestat = getattr(os.path, 'samestat', None)
349 samestat = getattr(os.path, 'samestat', None)
350 if followsym and samestat is not None:
350 if followsym and samestat is not None:
351 def adddir(dirlst, dirname):
351 def adddir(dirlst, dirname):
352 match = False
352 match = False
353 dirstat = os.stat(dirname)
353 dirstat = os.stat(dirname)
354 for lstdirstat in dirlst:
354 for lstdirstat in dirlst:
355 if samestat(dirstat, lstdirstat):
355 if samestat(dirstat, lstdirstat):
356 match = True
356 match = True
357 break
357 break
358 if not match:
358 if not match:
359 dirlst.append(dirstat)
359 dirlst.append(dirstat)
360 return not match
360 return not match
361 else:
361 else:
362 followsym = False
362 followsym = False
363
363
364 if (seen_dirs is None) and followsym:
364 if (seen_dirs is None) and followsym:
365 seen_dirs = []
365 seen_dirs = []
366 adddir(seen_dirs, path)
366 adddir(seen_dirs, path)
367 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
367 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
368 dirs.sort()
368 dirs.sort()
369 if '.hg' in dirs:
369 if '.hg' in dirs:
370 yield root # found a repository
370 yield root # found a repository
371 qroot = os.path.join(root, '.hg', 'patches')
371 qroot = os.path.join(root, '.hg', 'patches')
372 if os.path.isdir(os.path.join(qroot, '.hg')):
372 if os.path.isdir(os.path.join(qroot, '.hg')):
373 yield qroot # we have a patch queue repo here
373 yield qroot # we have a patch queue repo here
374 if recurse:
374 if recurse:
375 # avoid recursing inside the .hg directory
375 # avoid recursing inside the .hg directory
376 dirs.remove('.hg')
376 dirs.remove('.hg')
377 else:
377 else:
378 dirs[:] = [] # don't descend further
378 dirs[:] = [] # don't descend further
379 elif followsym:
379 elif followsym:
380 newdirs = []
380 newdirs = []
381 for d in dirs:
381 for d in dirs:
382 fname = os.path.join(root, d)
382 fname = os.path.join(root, d)
383 if adddir(seen_dirs, fname):
383 if adddir(seen_dirs, fname):
384 if os.path.islink(fname):
384 if os.path.islink(fname):
385 for hgname in walkrepos(fname, True, seen_dirs):
385 for hgname in walkrepos(fname, True, seen_dirs):
386 yield hgname
386 yield hgname
387 else:
387 else:
388 newdirs.append(d)
388 newdirs.append(d)
389 dirs[:] = newdirs
389 dirs[:] = newdirs
390
390
391 def osrcpath():
391 def osrcpath():
392 '''return default os-specific hgrc search path'''
392 '''return default os-specific hgrc search path'''
393 path = systemrcpath()
393 path = systemrcpath()
394 path.extend(userrcpath())
394 path.extend(userrcpath())
395 path = [os.path.normpath(f) for f in path]
395 path = [os.path.normpath(f) for f in path]
396 return path
396 return path
397
397
398 _rcpath = None
398 _rcpath = None
399
399
400 def rcpath():
400 def rcpath():
401 '''return hgrc search path. if env var HGRCPATH is set, use it.
401 '''return hgrc search path. if env var HGRCPATH is set, use it.
402 for each item in path, if directory, use files ending in .rc,
402 for each item in path, if directory, use files ending in .rc,
403 else use item.
403 else use item.
404 make HGRCPATH empty to only look in .hg/hgrc of current repo.
404 make HGRCPATH empty to only look in .hg/hgrc of current repo.
405 if no HGRCPATH, use default os-specific path.'''
405 if no HGRCPATH, use default os-specific path.'''
406 global _rcpath
406 global _rcpath
407 if _rcpath is None:
407 if _rcpath is None:
408 if 'HGRCPATH' in os.environ:
408 if 'HGRCPATH' in os.environ:
409 _rcpath = []
409 _rcpath = []
410 for p in os.environ['HGRCPATH'].split(os.pathsep):
410 for p in os.environ['HGRCPATH'].split(os.pathsep):
411 if not p:
411 if not p:
412 continue
412 continue
413 p = util.expandpath(p)
413 p = util.expandpath(p)
414 if os.path.isdir(p):
414 if os.path.isdir(p):
415 for f, kind in osutil.listdir(p):
415 for f, kind in osutil.listdir(p):
416 if f.endswith('.rc'):
416 if f.endswith('.rc'):
417 _rcpath.append(os.path.join(p, f))
417 _rcpath.append(os.path.join(p, f))
418 else:
418 else:
419 _rcpath.append(p)
419 _rcpath.append(p)
420 else:
420 else:
421 _rcpath = osrcpath()
421 _rcpath = osrcpath()
422 return _rcpath
422 return _rcpath
423
423
424 if os.name != 'nt':
424 if os.name != 'nt':
425
425
426 def rcfiles(path):
426 def rcfiles(path):
427 rcs = [os.path.join(path, 'hgrc')]
427 rcs = [os.path.join(path, 'hgrc')]
428 rcdir = os.path.join(path, 'hgrc.d')
428 rcdir = os.path.join(path, 'hgrc.d')
429 try:
429 try:
430 rcs.extend([os.path.join(rcdir, f)
430 rcs.extend([os.path.join(rcdir, f)
431 for f, kind in osutil.listdir(rcdir)
431 for f, kind in osutil.listdir(rcdir)
432 if f.endswith(".rc")])
432 if f.endswith(".rc")])
433 except OSError:
433 except OSError:
434 pass
434 pass
435 return rcs
435 return rcs
436
436
437 def systemrcpath():
437 def systemrcpath():
438 path = []
438 path = []
439 if sys.platform == 'plan9':
440 root = '/lib/mercurial'
441 else:
442 root = '/etc/mercurial'
439 # old mod_python does not set sys.argv
443 # old mod_python does not set sys.argv
440 if len(getattr(sys, 'argv', [])) > 0:
444 if len(getattr(sys, 'argv', [])) > 0:
441 p = os.path.dirname(os.path.dirname(sys.argv[0]))
445 p = os.path.dirname(os.path.dirname(sys.argv[0]))
442 path.extend(rcfiles(os.path.join(p, 'etc/mercurial')))
446 path.extend(rcfiles(os.path.join(p, root)))
443 path.extend(rcfiles('/etc/mercurial'))
447 path.extend(rcfiles(root))
444 return path
448 return path
445
449
446 def userrcpath():
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 else:
456 else:
450
457
451 _HKEY_LOCAL_MACHINE = 0x80000002L
458 _HKEY_LOCAL_MACHINE = 0x80000002L
452
459
453 def systemrcpath():
460 def systemrcpath():
454 '''return default os-specific hgrc search path'''
461 '''return default os-specific hgrc search path'''
455 rcpath = []
462 rcpath = []
456 filename = util.executablepath()
463 filename = util.executablepath()
457 # Use mercurial.ini found in directory with hg.exe
464 # Use mercurial.ini found in directory with hg.exe
458 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
465 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
459 if os.path.isfile(progrc):
466 if os.path.isfile(progrc):
460 rcpath.append(progrc)
467 rcpath.append(progrc)
461 return rcpath
468 return rcpath
462 # Use hgrc.d found in directory with hg.exe
469 # Use hgrc.d found in directory with hg.exe
463 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
470 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
464 if os.path.isdir(progrcd):
471 if os.path.isdir(progrcd):
465 for f, kind in osutil.listdir(progrcd):
472 for f, kind in osutil.listdir(progrcd):
466 if f.endswith('.rc'):
473 if f.endswith('.rc'):
467 rcpath.append(os.path.join(progrcd, f))
474 rcpath.append(os.path.join(progrcd, f))
468 return rcpath
475 return rcpath
469 # else look for a system rcpath in the registry
476 # else look for a system rcpath in the registry
470 value = util.lookupreg('SOFTWARE\\Mercurial', None,
477 value = util.lookupreg('SOFTWARE\\Mercurial', None,
471 _HKEY_LOCAL_MACHINE)
478 _HKEY_LOCAL_MACHINE)
472 if not isinstance(value, str) or not value:
479 if not isinstance(value, str) or not value:
473 return rcpath
480 return rcpath
474 value = util.localpath(value)
481 value = util.localpath(value)
475 for p in value.split(os.pathsep):
482 for p in value.split(os.pathsep):
476 if p.lower().endswith('mercurial.ini'):
483 if p.lower().endswith('mercurial.ini'):
477 rcpath.append(p)
484 rcpath.append(p)
478 elif os.path.isdir(p):
485 elif os.path.isdir(p):
479 for f, kind in osutil.listdir(p):
486 for f, kind in osutil.listdir(p):
480 if f.endswith('.rc'):
487 if f.endswith('.rc'):
481 rcpath.append(os.path.join(p, f))
488 rcpath.append(os.path.join(p, f))
482 return rcpath
489 return rcpath
483
490
484 def userrcpath():
491 def userrcpath():
485 '''return os-specific hgrc search path to the user dir'''
492 '''return os-specific hgrc search path to the user dir'''
486 home = os.path.expanduser('~')
493 home = os.path.expanduser('~')
487 path = [os.path.join(home, 'mercurial.ini'),
494 path = [os.path.join(home, 'mercurial.ini'),
488 os.path.join(home, '.hgrc')]
495 os.path.join(home, '.hgrc')]
489 userprofile = os.environ.get('USERPROFILE')
496 userprofile = os.environ.get('USERPROFILE')
490 if userprofile:
497 if userprofile:
491 path.append(os.path.join(userprofile, 'mercurial.ini'))
498 path.append(os.path.join(userprofile, 'mercurial.ini'))
492 path.append(os.path.join(userprofile, '.hgrc'))
499 path.append(os.path.join(userprofile, '.hgrc'))
493 return path
500 return path
494
501
495 def revsingle(repo, revspec, default='.'):
502 def revsingle(repo, revspec, default='.'):
496 if not revspec:
503 if not revspec:
497 return repo[default]
504 return repo[default]
498
505
499 l = revrange(repo, [revspec])
506 l = revrange(repo, [revspec])
500 if len(l) < 1:
507 if len(l) < 1:
501 raise util.Abort(_('empty revision set'))
508 raise util.Abort(_('empty revision set'))
502 return repo[l[-1]]
509 return repo[l[-1]]
503
510
504 def revpair(repo, revs):
511 def revpair(repo, revs):
505 if not revs:
512 if not revs:
506 return repo.dirstate.p1(), None
513 return repo.dirstate.p1(), None
507
514
508 l = revrange(repo, revs)
515 l = revrange(repo, revs)
509
516
510 if len(l) == 0:
517 if len(l) == 0:
511 return repo.dirstate.p1(), None
518 return repo.dirstate.p1(), None
512
519
513 if len(l) == 1:
520 if len(l) == 1:
514 return repo.lookup(l[0]), None
521 return repo.lookup(l[0]), None
515
522
516 return repo.lookup(l[0]), repo.lookup(l[-1])
523 return repo.lookup(l[0]), repo.lookup(l[-1])
517
524
518 _revrangesep = ':'
525 _revrangesep = ':'
519
526
520 def revrange(repo, revs):
527 def revrange(repo, revs):
521 """Yield revision as strings from a list of revision specifications."""
528 """Yield revision as strings from a list of revision specifications."""
522
529
523 def revfix(repo, val, defval):
530 def revfix(repo, val, defval):
524 if not val and val != 0 and defval is not None:
531 if not val and val != 0 and defval is not None:
525 return defval
532 return defval
526 return repo[val].rev()
533 return repo[val].rev()
527
534
528 seen, l = set(), []
535 seen, l = set(), []
529 for spec in revs:
536 for spec in revs:
530 # attempt to parse old-style ranges first to deal with
537 # attempt to parse old-style ranges first to deal with
531 # things like old-tag which contain query metacharacters
538 # things like old-tag which contain query metacharacters
532 try:
539 try:
533 if isinstance(spec, int):
540 if isinstance(spec, int):
534 seen.add(spec)
541 seen.add(spec)
535 l.append(spec)
542 l.append(spec)
536 continue
543 continue
537
544
538 if _revrangesep in spec:
545 if _revrangesep in spec:
539 start, end = spec.split(_revrangesep, 1)
546 start, end = spec.split(_revrangesep, 1)
540 start = revfix(repo, start, 0)
547 start = revfix(repo, start, 0)
541 end = revfix(repo, end, len(repo) - 1)
548 end = revfix(repo, end, len(repo) - 1)
542 step = start > end and -1 or 1
549 step = start > end and -1 or 1
543 for rev in xrange(start, end + step, step):
550 for rev in xrange(start, end + step, step):
544 if rev in seen:
551 if rev in seen:
545 continue
552 continue
546 seen.add(rev)
553 seen.add(rev)
547 l.append(rev)
554 l.append(rev)
548 continue
555 continue
549 elif spec and spec in repo: # single unquoted rev
556 elif spec and spec in repo: # single unquoted rev
550 rev = revfix(repo, spec, None)
557 rev = revfix(repo, spec, None)
551 if rev in seen:
558 if rev in seen:
552 continue
559 continue
553 seen.add(rev)
560 seen.add(rev)
554 l.append(rev)
561 l.append(rev)
555 continue
562 continue
556 except error.RepoLookupError:
563 except error.RepoLookupError:
557 pass
564 pass
558
565
559 # fall through to new-style queries if old-style fails
566 # fall through to new-style queries if old-style fails
560 m = revset.match(repo.ui, spec)
567 m = revset.match(repo.ui, spec)
561 for r in m(repo, range(len(repo))):
568 for r in m(repo, range(len(repo))):
562 if r not in seen:
569 if r not in seen:
563 l.append(r)
570 l.append(r)
564 seen.update(l)
571 seen.update(l)
565
572
566 return l
573 return l
567
574
568 def expandpats(pats):
575 def expandpats(pats):
569 if not util.expandglobs:
576 if not util.expandglobs:
570 return list(pats)
577 return list(pats)
571 ret = []
578 ret = []
572 for p in pats:
579 for p in pats:
573 kind, name = matchmod._patsplit(p, None)
580 kind, name = matchmod._patsplit(p, None)
574 if kind is None:
581 if kind is None:
575 try:
582 try:
576 globbed = glob.glob(name)
583 globbed = glob.glob(name)
577 except re.error:
584 except re.error:
578 globbed = [name]
585 globbed = [name]
579 if globbed:
586 if globbed:
580 ret.extend(globbed)
587 ret.extend(globbed)
581 continue
588 continue
582 ret.append(p)
589 ret.append(p)
583 return ret
590 return ret
584
591
585 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
592 def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
586 if pats == ("",):
593 if pats == ("",):
587 pats = []
594 pats = []
588 if not globbed and default == 'relpath':
595 if not globbed and default == 'relpath':
589 pats = expandpats(pats or [])
596 pats = expandpats(pats or [])
590
597
591 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
598 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
592 default)
599 default)
593 def badfn(f, msg):
600 def badfn(f, msg):
594 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
601 ctx._repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
595 m.bad = badfn
602 m.bad = badfn
596 return m, pats
603 return m, pats
597
604
598 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
605 def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
599 return matchandpats(ctx, pats, opts, globbed, default)[0]
606 return matchandpats(ctx, pats, opts, globbed, default)[0]
600
607
601 def matchall(repo):
608 def matchall(repo):
602 return matchmod.always(repo.root, repo.getcwd())
609 return matchmod.always(repo.root, repo.getcwd())
603
610
604 def matchfiles(repo, files):
611 def matchfiles(repo, files):
605 return matchmod.exact(repo.root, repo.getcwd(), files)
612 return matchmod.exact(repo.root, repo.getcwd(), files)
606
613
607 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
614 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
608 if dry_run is None:
615 if dry_run is None:
609 dry_run = opts.get('dry_run')
616 dry_run = opts.get('dry_run')
610 if similarity is None:
617 if similarity is None:
611 similarity = float(opts.get('similarity') or 0)
618 similarity = float(opts.get('similarity') or 0)
612 # we'd use status here, except handling of symlinks and ignore is tricky
619 # we'd use status here, except handling of symlinks and ignore is tricky
613 added, unknown, deleted, removed = [], [], [], []
620 added, unknown, deleted, removed = [], [], [], []
614 audit_path = pathauditor(repo.root)
621 audit_path = pathauditor(repo.root)
615 m = match(repo[None], pats, opts)
622 m = match(repo[None], pats, opts)
616 rejected = []
623 rejected = []
617 m.bad = lambda x, y: rejected.append(x)
624 m.bad = lambda x, y: rejected.append(x)
618
625
619 for abs in repo.walk(m):
626 for abs in repo.walk(m):
620 target = repo.wjoin(abs)
627 target = repo.wjoin(abs)
621 good = True
628 good = True
622 try:
629 try:
623 audit_path(abs)
630 audit_path(abs)
624 except (OSError, util.Abort):
631 except (OSError, util.Abort):
625 good = False
632 good = False
626 rel = m.rel(abs)
633 rel = m.rel(abs)
627 exact = m.exact(abs)
634 exact = m.exact(abs)
628 if good and abs not in repo.dirstate:
635 if good and abs not in repo.dirstate:
629 unknown.append(abs)
636 unknown.append(abs)
630 if repo.ui.verbose or not exact:
637 if repo.ui.verbose or not exact:
631 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
638 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
632 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
639 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target)
633 or (os.path.isdir(target) and not os.path.islink(target))):
640 or (os.path.isdir(target) and not os.path.islink(target))):
634 deleted.append(abs)
641 deleted.append(abs)
635 if repo.ui.verbose or not exact:
642 if repo.ui.verbose or not exact:
636 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
643 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
637 # for finding renames
644 # for finding renames
638 elif repo.dirstate[abs] == 'r':
645 elif repo.dirstate[abs] == 'r':
639 removed.append(abs)
646 removed.append(abs)
640 elif repo.dirstate[abs] == 'a':
647 elif repo.dirstate[abs] == 'a':
641 added.append(abs)
648 added.append(abs)
642 copies = {}
649 copies = {}
643 if similarity > 0:
650 if similarity > 0:
644 for old, new, score in similar.findrenames(repo,
651 for old, new, score in similar.findrenames(repo,
645 added + unknown, removed + deleted, similarity):
652 added + unknown, removed + deleted, similarity):
646 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
653 if repo.ui.verbose or not m.exact(old) or not m.exact(new):
647 repo.ui.status(_('recording removal of %s as rename to %s '
654 repo.ui.status(_('recording removal of %s as rename to %s '
648 '(%d%% similar)\n') %
655 '(%d%% similar)\n') %
649 (m.rel(old), m.rel(new), score * 100))
656 (m.rel(old), m.rel(new), score * 100))
650 copies[new] = old
657 copies[new] = old
651
658
652 if not dry_run:
659 if not dry_run:
653 wctx = repo[None]
660 wctx = repo[None]
654 wlock = repo.wlock()
661 wlock = repo.wlock()
655 try:
662 try:
656 wctx.forget(deleted)
663 wctx.forget(deleted)
657 wctx.add(unknown)
664 wctx.add(unknown)
658 for new, old in copies.iteritems():
665 for new, old in copies.iteritems():
659 wctx.copy(old, new)
666 wctx.copy(old, new)
660 finally:
667 finally:
661 wlock.release()
668 wlock.release()
662
669
663 for f in rejected:
670 for f in rejected:
664 if f in m.files():
671 if f in m.files():
665 return 1
672 return 1
666 return 0
673 return 0
667
674
668 def updatedir(ui, repo, patches, similarity=0):
675 def updatedir(ui, repo, patches, similarity=0):
669 '''Update dirstate after patch application according to metadata'''
676 '''Update dirstate after patch application according to metadata'''
670 if not patches:
677 if not patches:
671 return []
678 return []
672 copies = []
679 copies = []
673 removes = set()
680 removes = set()
674 cfiles = patches.keys()
681 cfiles = patches.keys()
675 cwd = repo.getcwd()
682 cwd = repo.getcwd()
676 if cwd:
683 if cwd:
677 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
684 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
678 for f in patches:
685 for f in patches:
679 gp = patches[f]
686 gp = patches[f]
680 if not gp:
687 if not gp:
681 continue
688 continue
682 if gp.op == 'RENAME':
689 if gp.op == 'RENAME':
683 copies.append((gp.oldpath, gp.path))
690 copies.append((gp.oldpath, gp.path))
684 removes.add(gp.oldpath)
691 removes.add(gp.oldpath)
685 elif gp.op == 'COPY':
692 elif gp.op == 'COPY':
686 copies.append((gp.oldpath, gp.path))
693 copies.append((gp.oldpath, gp.path))
687 elif gp.op == 'DELETE':
694 elif gp.op == 'DELETE':
688 removes.add(gp.path)
695 removes.add(gp.path)
689
696
690 wctx = repo[None]
697 wctx = repo[None]
691 for src, dst in copies:
698 for src, dst in copies:
692 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
699 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
693 if (not similarity) and removes:
700 if (not similarity) and removes:
694 wctx.remove(sorted(removes), True)
701 wctx.remove(sorted(removes), True)
695
702
696 for f in patches:
703 for f in patches:
697 gp = patches[f]
704 gp = patches[f]
698 if gp and gp.mode:
705 if gp and gp.mode:
699 islink, isexec = gp.mode
706 islink, isexec = gp.mode
700 dst = repo.wjoin(gp.path)
707 dst = repo.wjoin(gp.path)
701 # patch won't create empty files
708 # patch won't create empty files
702 if gp.op == 'ADD' and not os.path.lexists(dst):
709 if gp.op == 'ADD' and not os.path.lexists(dst):
703 flags = (isexec and 'x' or '') + (islink and 'l' or '')
710 flags = (isexec and 'x' or '') + (islink and 'l' or '')
704 repo.wwrite(gp.path, '', flags)
711 repo.wwrite(gp.path, '', flags)
705 util.setflags(dst, islink, isexec)
712 util.setflags(dst, islink, isexec)
706 addremove(repo, cfiles, similarity=similarity)
713 addremove(repo, cfiles, similarity=similarity)
707 files = patches.keys()
714 files = patches.keys()
708 files.extend([r for r in removes if r not in files])
715 files.extend([r for r in removes if r not in files])
709 return sorted(files)
716 return sorted(files)
710
717
711 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
718 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
712 """Update the dirstate to reflect the intent of copying src to dst. For
719 """Update the dirstate to reflect the intent of copying src to dst. For
713 different reasons it might not end with dst being marked as copied from src.
720 different reasons it might not end with dst being marked as copied from src.
714 """
721 """
715 origsrc = repo.dirstate.copied(src) or src
722 origsrc = repo.dirstate.copied(src) or src
716 if dst == origsrc: # copying back a copy?
723 if dst == origsrc: # copying back a copy?
717 if repo.dirstate[dst] not in 'mn' and not dryrun:
724 if repo.dirstate[dst] not in 'mn' and not dryrun:
718 repo.dirstate.normallookup(dst)
725 repo.dirstate.normallookup(dst)
719 else:
726 else:
720 if repo.dirstate[origsrc] == 'a' and origsrc == src:
727 if repo.dirstate[origsrc] == 'a' and origsrc == src:
721 if not ui.quiet:
728 if not ui.quiet:
722 ui.warn(_("%s has not been committed yet, so no copy "
729 ui.warn(_("%s has not been committed yet, so no copy "
723 "data will be stored for %s.\n")
730 "data will be stored for %s.\n")
724 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
731 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
725 if repo.dirstate[dst] in '?r' and not dryrun:
732 if repo.dirstate[dst] in '?r' and not dryrun:
726 wctx.add([dst])
733 wctx.add([dst])
727 elif not dryrun:
734 elif not dryrun:
728 wctx.copy(origsrc, dst)
735 wctx.copy(origsrc, dst)
729
736
730 def readrequires(opener, supported):
737 def readrequires(opener, supported):
731 '''Reads and parses .hg/requires and checks if all entries found
738 '''Reads and parses .hg/requires and checks if all entries found
732 are in the list of supported features.'''
739 are in the list of supported features.'''
733 requirements = set(opener.read("requires").splitlines())
740 requirements = set(opener.read("requires").splitlines())
734 missings = []
741 missings = []
735 for r in requirements:
742 for r in requirements:
736 if r not in supported:
743 if r not in supported:
737 if not r or not r[0].isalnum():
744 if not r or not r[0].isalnum():
738 raise error.RequirementError(_(".hg/requires file is corrupt"))
745 raise error.RequirementError(_(".hg/requires file is corrupt"))
739 missings.append(r)
746 missings.append(r)
740 missings.sort()
747 missings.sort()
741 if missings:
748 if missings:
742 raise error.RequirementError(_("unknown repository format: "
749 raise error.RequirementError(_("unknown repository format: "
743 "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
750 "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
744 return requirements
751 return requirements
745
752
746 class filecacheentry(object):
753 class filecacheentry(object):
747 def __init__(self, path):
754 def __init__(self, path):
748 self.path = path
755 self.path = path
749 self.cachestat = filecacheentry.stat(self.path)
756 self.cachestat = filecacheentry.stat(self.path)
750
757
751 if self.cachestat:
758 if self.cachestat:
752 self._cacheable = self.cachestat.cacheable()
759 self._cacheable = self.cachestat.cacheable()
753 else:
760 else:
754 # None means we don't know yet
761 # None means we don't know yet
755 self._cacheable = None
762 self._cacheable = None
756
763
757 def refresh(self):
764 def refresh(self):
758 if self.cacheable():
765 if self.cacheable():
759 self.cachestat = filecacheentry.stat(self.path)
766 self.cachestat = filecacheentry.stat(self.path)
760
767
761 def cacheable(self):
768 def cacheable(self):
762 if self._cacheable is not None:
769 if self._cacheable is not None:
763 return self._cacheable
770 return self._cacheable
764
771
765 # we don't know yet, assume it is for now
772 # we don't know yet, assume it is for now
766 return True
773 return True
767
774
768 def changed(self):
775 def changed(self):
769 # no point in going further if we can't cache it
776 # no point in going further if we can't cache it
770 if not self.cacheable():
777 if not self.cacheable():
771 return True
778 return True
772
779
773 newstat = filecacheentry.stat(self.path)
780 newstat = filecacheentry.stat(self.path)
774
781
775 # we may not know if it's cacheable yet, check again now
782 # we may not know if it's cacheable yet, check again now
776 if newstat and self._cacheable is None:
783 if newstat and self._cacheable is None:
777 self._cacheable = newstat.cacheable()
784 self._cacheable = newstat.cacheable()
778
785
779 # check again
786 # check again
780 if not self._cacheable:
787 if not self._cacheable:
781 return True
788 return True
782
789
783 if self.cachestat != newstat:
790 if self.cachestat != newstat:
784 self.cachestat = newstat
791 self.cachestat = newstat
785 return True
792 return True
786 else:
793 else:
787 return False
794 return False
788
795
789 @staticmethod
796 @staticmethod
790 def stat(path):
797 def stat(path):
791 try:
798 try:
792 return util.cachestat(path)
799 return util.cachestat(path)
793 except OSError, e:
800 except OSError, e:
794 if e.errno != errno.ENOENT:
801 if e.errno != errno.ENOENT:
795 raise
802 raise
796
803
797 class filecache(object):
804 class filecache(object):
798 '''A property like decorator that tracks a file under .hg/ for updates.
805 '''A property like decorator that tracks a file under .hg/ for updates.
799
806
800 Records stat info when called in _filecache.
807 Records stat info when called in _filecache.
801
808
802 On subsequent calls, compares old stat info with new info, and recreates
809 On subsequent calls, compares old stat info with new info, and recreates
803 the object when needed, updating the new stat info in _filecache.
810 the object when needed, updating the new stat info in _filecache.
804
811
805 Mercurial either atomic renames or appends for files under .hg,
812 Mercurial either atomic renames or appends for files under .hg,
806 so to ensure the cache is reliable we need the filesystem to be able
813 so to ensure the cache is reliable we need the filesystem to be able
807 to tell us if a file has been replaced. If it can't, we fallback to
814 to tell us if a file has been replaced. If it can't, we fallback to
808 recreating the object on every call (essentially the same behaviour as
815 recreating the object on every call (essentially the same behaviour as
809 propertycache).'''
816 propertycache).'''
810 def __init__(self, path):
817 def __init__(self, path):
811 self.path = path
818 self.path = path
812
819
813 def join(self, obj, fname):
820 def join(self, obj, fname):
814 """Used to compute the runtime path of the cached file.
821 """Used to compute the runtime path of the cached file.
815
822
816 Users should subclass filecache and provide their own version of this
823 Users should subclass filecache and provide their own version of this
817 function to call the appropriate join function on 'obj' (an instance
824 function to call the appropriate join function on 'obj' (an instance
818 of the class that its member function was decorated).
825 of the class that its member function was decorated).
819 """
826 """
820 return obj.join(fname)
827 return obj.join(fname)
821
828
822 def __call__(self, func):
829 def __call__(self, func):
823 self.func = func
830 self.func = func
824 self.name = func.__name__
831 self.name = func.__name__
825 return self
832 return self
826
833
827 def __get__(self, obj, type=None):
834 def __get__(self, obj, type=None):
828 # do we need to check if the file changed?
835 # do we need to check if the file changed?
829 if self.name in obj.__dict__:
836 if self.name in obj.__dict__:
830 return obj.__dict__[self.name]
837 return obj.__dict__[self.name]
831
838
832 entry = obj._filecache.get(self.name)
839 entry = obj._filecache.get(self.name)
833
840
834 if entry:
841 if entry:
835 if entry.changed():
842 if entry.changed():
836 entry.obj = self.func(obj)
843 entry.obj = self.func(obj)
837 else:
844 else:
838 path = self.join(obj, self.path)
845 path = self.join(obj, self.path)
839
846
840 # We stat -before- creating the object so our cache doesn't lie if
847 # We stat -before- creating the object so our cache doesn't lie if
841 # a writer modified between the time we read and stat
848 # a writer modified between the time we read and stat
842 entry = filecacheentry(path)
849 entry = filecacheentry(path)
843 entry.obj = self.func(obj)
850 entry.obj = self.func(obj)
844
851
845 obj._filecache[self.name] = entry
852 obj._filecache[self.name] = entry
846
853
847 obj.__dict__[self.name] = entry.obj
854 obj.__dict__[self.name] = entry.obj
848 return entry.obj
855 return entry.obj
849
856
850 def __set__(self, obj, value):
857 def __set__(self, obj, value):
851 if self.name in obj._filecache:
858 if self.name in obj._filecache:
852 obj._filecache[self.name].obj = value # update cached copy
859 obj._filecache[self.name].obj = value # update cached copy
853 obj.__dict__[self.name] = value # update copy returned by obj.x
860 obj.__dict__[self.name] = value # update copy returned by obj.x
854
861
855 def __delete__(self, obj):
862 def __delete__(self, obj):
856 try:
863 try:
857 del obj.__dict__[self.name]
864 del obj.__dict__[self.name]
858 except KeyError:
865 except KeyError:
859 raise AttributeError, self.name
866 raise AttributeError, self.name
@@ -1,746 +1,753 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, scmutil, util, error, formatter
10 import config, scmutil, util, error, formatter
11
11
12 class ui(object):
12 class ui(object):
13 def __init__(self, src=None):
13 def __init__(self, src=None):
14 self._buffers = []
14 self._buffers = []
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
15 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
16 self._reportuntrusted = True
16 self._reportuntrusted = True
17 self._ocfg = config.config() # overlay
17 self._ocfg = config.config() # overlay
18 self._tcfg = config.config() # trusted
18 self._tcfg = config.config() # trusted
19 self._ucfg = config.config() # untrusted
19 self._ucfg = config.config() # untrusted
20 self._trustusers = set()
20 self._trustusers = set()
21 self._trustgroups = set()
21 self._trustgroups = set()
22
22
23 if src:
23 if src:
24 self.fout = src.fout
24 self.fout = src.fout
25 self.ferr = src.ferr
25 self.ferr = src.ferr
26 self.fin = src.fin
26 self.fin = src.fin
27
27
28 self._tcfg = src._tcfg.copy()
28 self._tcfg = src._tcfg.copy()
29 self._ucfg = src._ucfg.copy()
29 self._ucfg = src._ucfg.copy()
30 self._ocfg = src._ocfg.copy()
30 self._ocfg = src._ocfg.copy()
31 self._trustusers = src._trustusers.copy()
31 self._trustusers = src._trustusers.copy()
32 self._trustgroups = src._trustgroups.copy()
32 self._trustgroups = src._trustgroups.copy()
33 self.environ = src.environ
33 self.environ = src.environ
34 self.fixconfig()
34 self.fixconfig()
35 else:
35 else:
36 self.fout = sys.stdout
36 self.fout = sys.stdout
37 self.ferr = sys.stderr
37 self.ferr = sys.stderr
38 self.fin = sys.stdin
38 self.fin = sys.stdin
39
39
40 # shared read-only environment
40 # shared read-only environment
41 self.environ = os.environ
41 self.environ = os.environ
42 # we always trust global config files
42 # we always trust global config files
43 for f in scmutil.rcpath():
43 for f in scmutil.rcpath():
44 self.readconfig(f, trust=True)
44 self.readconfig(f, trust=True)
45
45
46 def copy(self):
46 def copy(self):
47 return self.__class__(self)
47 return self.__class__(self)
48
48
49 def formatter(self, topic, opts):
49 def formatter(self, topic, opts):
50 return formatter.formatter(self, topic, opts)
50 return formatter.formatter(self, topic, opts)
51
51
52 def _trusted(self, fp, f):
52 def _trusted(self, fp, f):
53 st = util.fstat(fp)
53 st = util.fstat(fp)
54 if util.isowner(st):
54 if util.isowner(st):
55 return True
55 return True
56
56
57 tusers, tgroups = self._trustusers, self._trustgroups
57 tusers, tgroups = self._trustusers, self._trustgroups
58 if '*' in tusers or '*' in tgroups:
58 if '*' in tusers or '*' in tgroups:
59 return True
59 return True
60
60
61 user = util.username(st.st_uid)
61 user = util.username(st.st_uid)
62 group = util.groupname(st.st_gid)
62 group = util.groupname(st.st_gid)
63 if user in tusers or group in tgroups or user == util.username():
63 if user in tusers or group in tgroups or user == util.username():
64 return True
64 return True
65
65
66 if self._reportuntrusted:
66 if self._reportuntrusted:
67 self.warn(_('Not trusting file %s from untrusted '
67 self.warn(_('Not trusting file %s from untrusted '
68 'user %s, group %s\n') % (f, user, group))
68 'user %s, group %s\n') % (f, user, group))
69 return False
69 return False
70
70
71 def readconfig(self, filename, root=None, trust=False,
71 def readconfig(self, filename, root=None, trust=False,
72 sections=None, remap=None):
72 sections=None, remap=None):
73 try:
73 try:
74 fp = open(filename)
74 fp = open(filename)
75 except IOError:
75 except IOError:
76 if not sections: # ignore unless we were looking for something
76 if not sections: # ignore unless we were looking for something
77 return
77 return
78 raise
78 raise
79
79
80 cfg = config.config()
80 cfg = config.config()
81 trusted = sections or trust or self._trusted(fp, filename)
81 trusted = sections or trust or self._trusted(fp, filename)
82
82
83 try:
83 try:
84 cfg.read(filename, fp, sections=sections, remap=remap)
84 cfg.read(filename, fp, sections=sections, remap=remap)
85 fp.close()
85 fp.close()
86 except error.ConfigError, inst:
86 except error.ConfigError, inst:
87 if trusted:
87 if trusted:
88 raise
88 raise
89 self.warn(_("Ignored: %s\n") % str(inst))
89 self.warn(_("Ignored: %s\n") % str(inst))
90
90
91 if self.plain():
91 if self.plain():
92 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
92 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
93 'logtemplate', 'style',
93 'logtemplate', 'style',
94 'traceback', 'verbose'):
94 'traceback', 'verbose'):
95 if k in cfg['ui']:
95 if k in cfg['ui']:
96 del cfg['ui'][k]
96 del cfg['ui'][k]
97 for k, v in cfg.items('defaults'):
97 for k, v in cfg.items('defaults'):
98 del cfg['defaults'][k]
98 del cfg['defaults'][k]
99 # Don't remove aliases from the configuration if in the exceptionlist
99 # Don't remove aliases from the configuration if in the exceptionlist
100 if self.plain('alias'):
100 if self.plain('alias'):
101 for k, v in cfg.items('alias'):
101 for k, v in cfg.items('alias'):
102 del cfg['alias'][k]
102 del cfg['alias'][k]
103
103
104 if trusted:
104 if trusted:
105 self._tcfg.update(cfg)
105 self._tcfg.update(cfg)
106 self._tcfg.update(self._ocfg)
106 self._tcfg.update(self._ocfg)
107 self._ucfg.update(cfg)
107 self._ucfg.update(cfg)
108 self._ucfg.update(self._ocfg)
108 self._ucfg.update(self._ocfg)
109
109
110 if root is None:
110 if root is None:
111 root = os.path.expanduser('~')
111 root = os.path.expanduser('~')
112 self.fixconfig(root=root)
112 self.fixconfig(root=root)
113
113
114 def fixconfig(self, root=None, section=None):
114 def fixconfig(self, root=None, section=None):
115 if section in (None, 'paths'):
115 if section in (None, 'paths'):
116 # expand vars and ~
116 # expand vars and ~
117 # translate paths relative to root (or home) into absolute paths
117 # translate paths relative to root (or home) into absolute paths
118 root = root or os.getcwd()
118 root = root or os.getcwd()
119 for c in self._tcfg, self._ucfg, self._ocfg:
119 for c in self._tcfg, self._ucfg, self._ocfg:
120 for n, p in c.items('paths'):
120 for n, p in c.items('paths'):
121 if not p:
121 if not p:
122 continue
122 continue
123 if '%%' in p:
123 if '%%' in p:
124 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
124 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
125 % (n, p, self.configsource('paths', n)))
125 % (n, p, self.configsource('paths', n)))
126 p = p.replace('%%', '%')
126 p = p.replace('%%', '%')
127 p = util.expandpath(p)
127 p = util.expandpath(p)
128 if not util.hasscheme(p) and not os.path.isabs(p):
128 if not util.hasscheme(p) and not os.path.isabs(p):
129 p = os.path.normpath(os.path.join(root, p))
129 p = os.path.normpath(os.path.join(root, p))
130 c.set("paths", n, p)
130 c.set("paths", n, p)
131
131
132 if section in (None, 'ui'):
132 if section in (None, 'ui'):
133 # update ui options
133 # update ui options
134 self.debugflag = self.configbool('ui', 'debug')
134 self.debugflag = self.configbool('ui', 'debug')
135 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
135 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
136 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
136 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
137 if self.verbose and self.quiet:
137 if self.verbose and self.quiet:
138 self.quiet = self.verbose = False
138 self.quiet = self.verbose = False
139 self._reportuntrusted = self.debugflag or self.configbool("ui",
139 self._reportuntrusted = self.debugflag or self.configbool("ui",
140 "report_untrusted", True)
140 "report_untrusted", True)
141 self.tracebackflag = self.configbool('ui', 'traceback', False)
141 self.tracebackflag = self.configbool('ui', 'traceback', False)
142
142
143 if section in (None, 'trusted'):
143 if section in (None, 'trusted'):
144 # update trust information
144 # update trust information
145 self._trustusers.update(self.configlist('trusted', 'users'))
145 self._trustusers.update(self.configlist('trusted', 'users'))
146 self._trustgroups.update(self.configlist('trusted', 'groups'))
146 self._trustgroups.update(self.configlist('trusted', 'groups'))
147
147
148 def backupconfig(self, section, item):
148 def backupconfig(self, section, item):
149 return (self._ocfg.backup(section, item),
149 return (self._ocfg.backup(section, item),
150 self._tcfg.backup(section, item),
150 self._tcfg.backup(section, item),
151 self._ucfg.backup(section, item),)
151 self._ucfg.backup(section, item),)
152 def restoreconfig(self, data):
152 def restoreconfig(self, data):
153 self._ocfg.restore(data[0])
153 self._ocfg.restore(data[0])
154 self._tcfg.restore(data[1])
154 self._tcfg.restore(data[1])
155 self._ucfg.restore(data[2])
155 self._ucfg.restore(data[2])
156
156
157 def setconfig(self, section, name, value, overlay=True):
157 def setconfig(self, section, name, value, overlay=True):
158 if overlay:
158 if overlay:
159 self._ocfg.set(section, name, value)
159 self._ocfg.set(section, name, value)
160 self._tcfg.set(section, name, value)
160 self._tcfg.set(section, name, value)
161 self._ucfg.set(section, name, value)
161 self._ucfg.set(section, name, value)
162 self.fixconfig(section=section)
162 self.fixconfig(section=section)
163
163
164 def _data(self, untrusted):
164 def _data(self, untrusted):
165 return untrusted and self._ucfg or self._tcfg
165 return untrusted and self._ucfg or self._tcfg
166
166
167 def configsource(self, section, name, untrusted=False):
167 def configsource(self, section, name, untrusted=False):
168 return self._data(untrusted).source(section, name) or 'none'
168 return self._data(untrusted).source(section, name) or 'none'
169
169
170 def config(self, section, name, default=None, untrusted=False):
170 def config(self, section, name, default=None, untrusted=False):
171 if isinstance(name, list):
171 if isinstance(name, list):
172 alternates = name
172 alternates = name
173 else:
173 else:
174 alternates = [name]
174 alternates = [name]
175
175
176 for n in alternates:
176 for n in alternates:
177 value = self._data(untrusted).get(section, name, None)
177 value = self._data(untrusted).get(section, name, None)
178 if value is not None:
178 if value is not None:
179 name = n
179 name = n
180 break
180 break
181 else:
181 else:
182 value = default
182 value = default
183
183
184 if self.debugflag and not untrusted and self._reportuntrusted:
184 if self.debugflag and not untrusted and self._reportuntrusted:
185 uvalue = self._ucfg.get(section, name)
185 uvalue = self._ucfg.get(section, name)
186 if uvalue is not None and uvalue != value:
186 if uvalue is not None and uvalue != value:
187 self.debug("ignoring untrusted configuration option "
187 self.debug("ignoring untrusted configuration option "
188 "%s.%s = %s\n" % (section, name, uvalue))
188 "%s.%s = %s\n" % (section, name, uvalue))
189 return value
189 return value
190
190
191 def configpath(self, section, name, default=None, untrusted=False):
191 def configpath(self, section, name, default=None, untrusted=False):
192 'get a path config item, expanded relative to repo root or config file'
192 'get a path config item, expanded relative to repo root or config file'
193 v = self.config(section, name, default, untrusted)
193 v = self.config(section, name, default, untrusted)
194 if v is None:
194 if v is None:
195 return None
195 return None
196 if not os.path.isabs(v) or "://" not in v:
196 if not os.path.isabs(v) or "://" not in v:
197 src = self.configsource(section, name, untrusted)
197 src = self.configsource(section, name, untrusted)
198 if ':' in src:
198 if ':' in src:
199 base = os.path.dirname(src.rsplit(':')[0])
199 base = os.path.dirname(src.rsplit(':')[0])
200 v = os.path.join(base, os.path.expanduser(v))
200 v = os.path.join(base, os.path.expanduser(v))
201 return v
201 return v
202
202
203 def configbool(self, section, name, default=False, untrusted=False):
203 def configbool(self, section, name, default=False, untrusted=False):
204 """parse a configuration element as a boolean
204 """parse a configuration element as a boolean
205
205
206 >>> u = ui(); s = 'foo'
206 >>> u = ui(); s = 'foo'
207 >>> u.setconfig(s, 'true', 'yes')
207 >>> u.setconfig(s, 'true', 'yes')
208 >>> u.configbool(s, 'true')
208 >>> u.configbool(s, 'true')
209 True
209 True
210 >>> u.setconfig(s, 'false', 'no')
210 >>> u.setconfig(s, 'false', 'no')
211 >>> u.configbool(s, 'false')
211 >>> u.configbool(s, 'false')
212 False
212 False
213 >>> u.configbool(s, 'unknown')
213 >>> u.configbool(s, 'unknown')
214 False
214 False
215 >>> u.configbool(s, 'unknown', True)
215 >>> u.configbool(s, 'unknown', True)
216 True
216 True
217 >>> u.setconfig(s, 'invalid', 'somevalue')
217 >>> u.setconfig(s, 'invalid', 'somevalue')
218 >>> u.configbool(s, 'invalid')
218 >>> u.configbool(s, 'invalid')
219 Traceback (most recent call last):
219 Traceback (most recent call last):
220 ...
220 ...
221 ConfigError: foo.invalid is not a boolean ('somevalue')
221 ConfigError: foo.invalid is not a boolean ('somevalue')
222 """
222 """
223
223
224 v = self.config(section, name, None, untrusted)
224 v = self.config(section, name, None, untrusted)
225 if v is None:
225 if v is None:
226 return default
226 return default
227 if isinstance(v, bool):
227 if isinstance(v, bool):
228 return v
228 return v
229 b = util.parsebool(v)
229 b = util.parsebool(v)
230 if b is None:
230 if b is None:
231 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
231 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
232 % (section, name, v))
232 % (section, name, v))
233 return b
233 return b
234
234
235 def configint(self, section, name, default=None, untrusted=False):
235 def configint(self, section, name, default=None, untrusted=False):
236 """parse a configuration element as an integer
236 """parse a configuration element as an integer
237
237
238 >>> u = ui(); s = 'foo'
238 >>> u = ui(); s = 'foo'
239 >>> u.setconfig(s, 'int1', '42')
239 >>> u.setconfig(s, 'int1', '42')
240 >>> u.configint(s, 'int1')
240 >>> u.configint(s, 'int1')
241 42
241 42
242 >>> u.setconfig(s, 'int2', '-42')
242 >>> u.setconfig(s, 'int2', '-42')
243 >>> u.configint(s, 'int2')
243 >>> u.configint(s, 'int2')
244 -42
244 -42
245 >>> u.configint(s, 'unknown', 7)
245 >>> u.configint(s, 'unknown', 7)
246 7
246 7
247 >>> u.setconfig(s, 'invalid', 'somevalue')
247 >>> u.setconfig(s, 'invalid', 'somevalue')
248 >>> u.configint(s, 'invalid')
248 >>> u.configint(s, 'invalid')
249 Traceback (most recent call last):
249 Traceback (most recent call last):
250 ...
250 ...
251 ConfigError: foo.invalid is not an integer ('somevalue')
251 ConfigError: foo.invalid is not an integer ('somevalue')
252 """
252 """
253
253
254 v = self.config(section, name, None, untrusted)
254 v = self.config(section, name, None, untrusted)
255 if v is None:
255 if v is None:
256 return default
256 return default
257 try:
257 try:
258 return int(v)
258 return int(v)
259 except ValueError:
259 except ValueError:
260 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
260 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
261 % (section, name, v))
261 % (section, name, v))
262
262
263 def configlist(self, section, name, default=None, untrusted=False):
263 def configlist(self, section, name, default=None, untrusted=False):
264 """parse a configuration element as a list of comma/space separated
264 """parse a configuration element as a list of comma/space separated
265 strings
265 strings
266
266
267 >>> u = ui(); s = 'foo'
267 >>> u = ui(); s = 'foo'
268 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
268 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
269 >>> u.configlist(s, 'list1')
269 >>> u.configlist(s, 'list1')
270 ['this', 'is', 'a small', 'test']
270 ['this', 'is', 'a small', 'test']
271 """
271 """
272
272
273 def _parse_plain(parts, s, offset):
273 def _parse_plain(parts, s, offset):
274 whitespace = False
274 whitespace = False
275 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
275 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
276 whitespace = True
276 whitespace = True
277 offset += 1
277 offset += 1
278 if offset >= len(s):
278 if offset >= len(s):
279 return None, parts, offset
279 return None, parts, offset
280 if whitespace:
280 if whitespace:
281 parts.append('')
281 parts.append('')
282 if s[offset] == '"' and not parts[-1]:
282 if s[offset] == '"' and not parts[-1]:
283 return _parse_quote, parts, offset + 1
283 return _parse_quote, parts, offset + 1
284 elif s[offset] == '"' and parts[-1][-1] == '\\':
284 elif s[offset] == '"' and parts[-1][-1] == '\\':
285 parts[-1] = parts[-1][:-1] + s[offset]
285 parts[-1] = parts[-1][:-1] + s[offset]
286 return _parse_plain, parts, offset + 1
286 return _parse_plain, parts, offset + 1
287 parts[-1] += s[offset]
287 parts[-1] += s[offset]
288 return _parse_plain, parts, offset + 1
288 return _parse_plain, parts, offset + 1
289
289
290 def _parse_quote(parts, s, offset):
290 def _parse_quote(parts, s, offset):
291 if offset < len(s) and s[offset] == '"': # ""
291 if offset < len(s) and s[offset] == '"': # ""
292 parts.append('')
292 parts.append('')
293 offset += 1
293 offset += 1
294 while offset < len(s) and (s[offset].isspace() or
294 while offset < len(s) and (s[offset].isspace() or
295 s[offset] == ','):
295 s[offset] == ','):
296 offset += 1
296 offset += 1
297 return _parse_plain, parts, offset
297 return _parse_plain, parts, offset
298
298
299 while offset < len(s) and s[offset] != '"':
299 while offset < len(s) and s[offset] != '"':
300 if (s[offset] == '\\' and offset + 1 < len(s)
300 if (s[offset] == '\\' and offset + 1 < len(s)
301 and s[offset + 1] == '"'):
301 and s[offset + 1] == '"'):
302 offset += 1
302 offset += 1
303 parts[-1] += '"'
303 parts[-1] += '"'
304 else:
304 else:
305 parts[-1] += s[offset]
305 parts[-1] += s[offset]
306 offset += 1
306 offset += 1
307
307
308 if offset >= len(s):
308 if offset >= len(s):
309 real_parts = _configlist(parts[-1])
309 real_parts = _configlist(parts[-1])
310 if not real_parts:
310 if not real_parts:
311 parts[-1] = '"'
311 parts[-1] = '"'
312 else:
312 else:
313 real_parts[0] = '"' + real_parts[0]
313 real_parts[0] = '"' + real_parts[0]
314 parts = parts[:-1]
314 parts = parts[:-1]
315 parts.extend(real_parts)
315 parts.extend(real_parts)
316 return None, parts, offset
316 return None, parts, offset
317
317
318 offset += 1
318 offset += 1
319 while offset < len(s) and s[offset] in [' ', ',']:
319 while offset < len(s) and s[offset] in [' ', ',']:
320 offset += 1
320 offset += 1
321
321
322 if offset < len(s):
322 if offset < len(s):
323 if offset + 1 == len(s) and s[offset] == '"':
323 if offset + 1 == len(s) and s[offset] == '"':
324 parts[-1] += '"'
324 parts[-1] += '"'
325 offset += 1
325 offset += 1
326 else:
326 else:
327 parts.append('')
327 parts.append('')
328 else:
328 else:
329 return None, parts, offset
329 return None, parts, offset
330
330
331 return _parse_plain, parts, offset
331 return _parse_plain, parts, offset
332
332
333 def _configlist(s):
333 def _configlist(s):
334 s = s.rstrip(' ,')
334 s = s.rstrip(' ,')
335 if not s:
335 if not s:
336 return []
336 return []
337 parser, parts, offset = _parse_plain, [''], 0
337 parser, parts, offset = _parse_plain, [''], 0
338 while parser:
338 while parser:
339 parser, parts, offset = parser(parts, s, offset)
339 parser, parts, offset = parser(parts, s, offset)
340 return parts
340 return parts
341
341
342 result = self.config(section, name, untrusted=untrusted)
342 result = self.config(section, name, untrusted=untrusted)
343 if result is None:
343 if result is None:
344 result = default or []
344 result = default or []
345 if isinstance(result, basestring):
345 if isinstance(result, basestring):
346 result = _configlist(result.lstrip(' ,\n'))
346 result = _configlist(result.lstrip(' ,\n'))
347 if result is None:
347 if result is None:
348 result = default or []
348 result = default or []
349 return result
349 return result
350
350
351 def has_section(self, section, untrusted=False):
351 def has_section(self, section, untrusted=False):
352 '''tell whether section exists in config.'''
352 '''tell whether section exists in config.'''
353 return section in self._data(untrusted)
353 return section in self._data(untrusted)
354
354
355 def configitems(self, section, untrusted=False):
355 def configitems(self, section, untrusted=False):
356 items = self._data(untrusted).items(section)
356 items = self._data(untrusted).items(section)
357 if self.debugflag and not untrusted and self._reportuntrusted:
357 if self.debugflag and not untrusted and self._reportuntrusted:
358 for k, v in self._ucfg.items(section):
358 for k, v in self._ucfg.items(section):
359 if self._tcfg.get(section, k) != v:
359 if self._tcfg.get(section, k) != v:
360 self.debug("ignoring untrusted configuration option "
360 self.debug("ignoring untrusted configuration option "
361 "%s.%s = %s\n" % (section, k, v))
361 "%s.%s = %s\n" % (section, k, v))
362 return items
362 return items
363
363
364 def walkconfig(self, untrusted=False):
364 def walkconfig(self, untrusted=False):
365 cfg = self._data(untrusted)
365 cfg = self._data(untrusted)
366 for section in cfg.sections():
366 for section in cfg.sections():
367 for name, value in self.configitems(section, untrusted):
367 for name, value in self.configitems(section, untrusted):
368 yield section, name, value
368 yield section, name, value
369
369
370 def plain(self, feature=None):
370 def plain(self, feature=None):
371 '''is plain mode active?
371 '''is plain mode active?
372
372
373 Plain mode means that all configuration variables which affect
373 Plain mode means that all configuration variables which affect
374 the behavior and output of Mercurial should be
374 the behavior and output of Mercurial should be
375 ignored. Additionally, the output should be stable,
375 ignored. Additionally, the output should be stable,
376 reproducible and suitable for use in scripts or applications.
376 reproducible and suitable for use in scripts or applications.
377
377
378 The only way to trigger plain mode is by setting either the
378 The only way to trigger plain mode is by setting either the
379 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
379 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
380
380
381 The return value can either be
381 The return value can either be
382 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
382 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
383 - True otherwise
383 - True otherwise
384 '''
384 '''
385 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
385 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
386 return False
386 return False
387 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
387 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
388 if feature and exceptions:
388 if feature and exceptions:
389 return feature not in exceptions
389 return feature not in exceptions
390 return True
390 return True
391
391
392 def username(self):
392 def username(self):
393 """Return default username to be used in commits.
393 """Return default username to be used in commits.
394
394
395 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
395 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
396 and stop searching if one of these is set.
396 and stop searching if one of these is set.
397 If not found and ui.askusername is True, ask the user, else use
397 If not found and ui.askusername is True, ask the user, else use
398 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
398 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
399 """
399 """
400 user = os.environ.get("HGUSER")
400 user = os.environ.get("HGUSER")
401 if user is None:
401 if user is None:
402 user = self.config("ui", "username")
402 user = self.config("ui", "username")
403 if user is not None:
403 if user is not None:
404 user = os.path.expandvars(user)
404 user = os.path.expandvars(user)
405 if user is None:
405 if user is None:
406 user = os.environ.get("EMAIL")
406 user = os.environ.get("EMAIL")
407 if user is None and self.configbool("ui", "askusername"):
407 if user is None and self.configbool("ui", "askusername"):
408 user = self.prompt(_("enter a commit username:"), default=None)
408 user = self.prompt(_("enter a commit username:"), default=None)
409 if user is None and not self.interactive():
409 if user is None and not self.interactive():
410 try:
410 try:
411 user = '%s@%s' % (util.getuser(), socket.getfqdn())
411 user = '%s@%s' % (util.getuser(), socket.getfqdn())
412 self.warn(_("No username found, using '%s' instead\n") % user)
412 self.warn(_("No username found, using '%s' instead\n") % user)
413 except KeyError:
413 except KeyError:
414 pass
414 pass
415 if not user:
415 if not user:
416 raise util.Abort(_('no username supplied (see "hg help config")'))
416 raise util.Abort(_('no username supplied (see "hg help config")'))
417 if "\n" in user:
417 if "\n" in user:
418 raise util.Abort(_("username %s contains a newline\n") % repr(user))
418 raise util.Abort(_("username %s contains a newline\n") % repr(user))
419 return user
419 return user
420
420
421 def shortuser(self, user):
421 def shortuser(self, user):
422 """Return a short representation of a user name or email address."""
422 """Return a short representation of a user name or email address."""
423 if not self.verbose:
423 if not self.verbose:
424 user = util.shortuser(user)
424 user = util.shortuser(user)
425 return user
425 return user
426
426
427 def expandpath(self, loc, default=None):
427 def expandpath(self, loc, default=None):
428 """Return repository location relative to cwd or from [paths]"""
428 """Return repository location relative to cwd or from [paths]"""
429 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
429 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
430 return loc
430 return loc
431
431
432 path = self.config('paths', loc)
432 path = self.config('paths', loc)
433 if not path and default is not None:
433 if not path and default is not None:
434 path = self.config('paths', default)
434 path = self.config('paths', default)
435 return path or loc
435 return path or loc
436
436
437 def pushbuffer(self):
437 def pushbuffer(self):
438 self._buffers.append([])
438 self._buffers.append([])
439
439
440 def popbuffer(self, labeled=False):
440 def popbuffer(self, labeled=False):
441 '''pop the last buffer and return the buffered output
441 '''pop the last buffer and return the buffered output
442
442
443 If labeled is True, any labels associated with buffered
443 If labeled is True, any labels associated with buffered
444 output will be handled. By default, this has no effect
444 output will be handled. By default, this has no effect
445 on the output returned, but extensions and GUI tools may
445 on the output returned, but extensions and GUI tools may
446 handle this argument and returned styled output. If output
446 handle this argument and returned styled output. If output
447 is being buffered so it can be captured and parsed or
447 is being buffered so it can be captured and parsed or
448 processed, labeled should not be set to True.
448 processed, labeled should not be set to True.
449 '''
449 '''
450 return "".join(self._buffers.pop())
450 return "".join(self._buffers.pop())
451
451
452 def write(self, *args, **opts):
452 def write(self, *args, **opts):
453 '''write args to output
453 '''write args to output
454
454
455 By default, this method simply writes to the buffer or stdout,
455 By default, this method simply writes to the buffer or stdout,
456 but extensions or GUI tools may override this method,
456 but extensions or GUI tools may override this method,
457 write_err(), popbuffer(), and label() to style output from
457 write_err(), popbuffer(), and label() to style output from
458 various parts of hg.
458 various parts of hg.
459
459
460 An optional keyword argument, "label", can be passed in.
460 An optional keyword argument, "label", can be passed in.
461 This should be a string containing label names separated by
461 This should be a string containing label names separated by
462 space. Label names take the form of "topic.type". For example,
462 space. Label names take the form of "topic.type". For example,
463 ui.debug() issues a label of "ui.debug".
463 ui.debug() issues a label of "ui.debug".
464
464
465 When labeling output for a specific command, a label of
465 When labeling output for a specific command, a label of
466 "cmdname.type" is recommended. For example, status issues
466 "cmdname.type" is recommended. For example, status issues
467 a label of "status.modified" for modified files.
467 a label of "status.modified" for modified files.
468 '''
468 '''
469 if self._buffers:
469 if self._buffers:
470 self._buffers[-1].extend([str(a) for a in args])
470 self._buffers[-1].extend([str(a) for a in args])
471 else:
471 else:
472 for a in args:
472 for a in args:
473 self.fout.write(str(a))
473 self.fout.write(str(a))
474
474
475 def write_err(self, *args, **opts):
475 def write_err(self, *args, **opts):
476 try:
476 try:
477 if not getattr(self.fout, 'closed', False):
477 if not getattr(self.fout, 'closed', False):
478 self.fout.flush()
478 self.fout.flush()
479 for a in args:
479 for a in args:
480 self.ferr.write(str(a))
480 self.ferr.write(str(a))
481 # stderr may be buffered under win32 when redirected to files,
481 # stderr may be buffered under win32 when redirected to files,
482 # including stdout.
482 # including stdout.
483 if not getattr(self.ferr, 'closed', False):
483 if not getattr(self.ferr, 'closed', False):
484 self.ferr.flush()
484 self.ferr.flush()
485 except IOError, inst:
485 except IOError, inst:
486 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
486 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
487 raise
487 raise
488
488
489 def flush(self):
489 def flush(self):
490 try: self.fout.flush()
490 try: self.fout.flush()
491 except: pass
491 except: pass
492 try: self.ferr.flush()
492 try: self.ferr.flush()
493 except: pass
493 except: pass
494
494
495 def interactive(self):
495 def interactive(self):
496 '''is interactive input allowed?
496 '''is interactive input allowed?
497
497
498 An interactive session is a session where input can be reasonably read
498 An interactive session is a session where input can be reasonably read
499 from `sys.stdin'. If this function returns false, any attempt to read
499 from `sys.stdin'. If this function returns false, any attempt to read
500 from stdin should fail with an error, unless a sensible default has been
500 from stdin should fail with an error, unless a sensible default has been
501 specified.
501 specified.
502
502
503 Interactiveness is triggered by the value of the `ui.interactive'
503 Interactiveness is triggered by the value of the `ui.interactive'
504 configuration variable or - if it is unset - when `sys.stdin' points
504 configuration variable or - if it is unset - when `sys.stdin' points
505 to a terminal device.
505 to a terminal device.
506
506
507 This function refers to input only; for output, see `ui.formatted()'.
507 This function refers to input only; for output, see `ui.formatted()'.
508 '''
508 '''
509 i = self.configbool("ui", "interactive", None)
509 i = self.configbool("ui", "interactive", None)
510 if i is None:
510 if i is None:
511 # some environments replace stdin without implementing isatty
511 # some environments replace stdin without implementing isatty
512 # usually those are non-interactive
512 # usually those are non-interactive
513 return util.isatty(self.fin)
513 return util.isatty(self.fin)
514
514
515 return i
515 return i
516
516
517 def termwidth(self):
517 def termwidth(self):
518 '''how wide is the terminal in columns?
518 '''how wide is the terminal in columns?
519 '''
519 '''
520 if 'COLUMNS' in os.environ:
520 if 'COLUMNS' in os.environ:
521 try:
521 try:
522 return int(os.environ['COLUMNS'])
522 return int(os.environ['COLUMNS'])
523 except ValueError:
523 except ValueError:
524 pass
524 pass
525 return util.termwidth()
525 return util.termwidth()
526
526
527 def formatted(self):
527 def formatted(self):
528 '''should formatted output be used?
528 '''should formatted output be used?
529
529
530 It is often desirable to format the output to suite the output medium.
530 It is often desirable to format the output to suite the output medium.
531 Examples of this are truncating long lines or colorizing messages.
531 Examples of this are truncating long lines or colorizing messages.
532 However, this is not often not desirable when piping output into other
532 However, this is not often not desirable when piping output into other
533 utilities, e.g. `grep'.
533 utilities, e.g. `grep'.
534
534
535 Formatted output is triggered by the value of the `ui.formatted'
535 Formatted output is triggered by the value of the `ui.formatted'
536 configuration variable or - if it is unset - when `sys.stdout' points
536 configuration variable or - if it is unset - when `sys.stdout' points
537 to a terminal device. Please note that `ui.formatted' should be
537 to a terminal device. Please note that `ui.formatted' should be
538 considered an implementation detail; it is not intended for use outside
538 considered an implementation detail; it is not intended for use outside
539 Mercurial or its extensions.
539 Mercurial or its extensions.
540
540
541 This function refers to output only; for input, see `ui.interactive()'.
541 This function refers to output only; for input, see `ui.interactive()'.
542 This function always returns false when in plain mode, see `ui.plain()'.
542 This function always returns false when in plain mode, see `ui.plain()'.
543 '''
543 '''
544 if self.plain():
544 if self.plain():
545 return False
545 return False
546
546
547 i = self.configbool("ui", "formatted", None)
547 i = self.configbool("ui", "formatted", None)
548 if i is None:
548 if i is None:
549 # some environments replace stdout without implementing isatty
549 # some environments replace stdout without implementing isatty
550 # usually those are non-interactive
550 # usually those are non-interactive
551 return util.isatty(self.fout)
551 return util.isatty(self.fout)
552
552
553 return i
553 return i
554
554
555 def _readline(self, prompt=''):
555 def _readline(self, prompt=''):
556 if util.isatty(self.fin):
556 if util.isatty(self.fin):
557 try:
557 try:
558 # magically add command line editing support, where
558 # magically add command line editing support, where
559 # available
559 # available
560 import readline
560 import readline
561 # force demandimport to really load the module
561 # force demandimport to really load the module
562 readline.read_history_file
562 readline.read_history_file
563 # windows sometimes raises something other than ImportError
563 # windows sometimes raises something other than ImportError
564 except Exception:
564 except Exception:
565 pass
565 pass
566
566
567 # call write() so output goes through subclassed implementation
567 # call write() so output goes through subclassed implementation
568 # e.g. color extension on Windows
568 # e.g. color extension on Windows
569 self.write(prompt)
569 self.write(prompt)
570
570
571 # instead of trying to emulate raw_input, swap (self.fin,
571 # instead of trying to emulate raw_input, swap (self.fin,
572 # self.fout) with (sys.stdin, sys.stdout)
572 # self.fout) with (sys.stdin, sys.stdout)
573 oldin = sys.stdin
573 oldin = sys.stdin
574 oldout = sys.stdout
574 oldout = sys.stdout
575 sys.stdin = self.fin
575 sys.stdin = self.fin
576 sys.stdout = self.fout
576 sys.stdout = self.fout
577 line = raw_input(' ')
577 line = raw_input(' ')
578 sys.stdin = oldin
578 sys.stdin = oldin
579 sys.stdout = oldout
579 sys.stdout = oldout
580
580
581 # When stdin is in binary mode on Windows, it can cause
581 # When stdin is in binary mode on Windows, it can cause
582 # raw_input() to emit an extra trailing carriage return
582 # raw_input() to emit an extra trailing carriage return
583 if os.linesep == '\r\n' and line and line[-1] == '\r':
583 if os.linesep == '\r\n' and line and line[-1] == '\r':
584 line = line[:-1]
584 line = line[:-1]
585 return line
585 return line
586
586
587 def prompt(self, msg, default="y"):
587 def prompt(self, msg, default="y"):
588 """Prompt user with msg, read response.
588 """Prompt user with msg, read response.
589 If ui is not interactive, the default is returned.
589 If ui is not interactive, the default is returned.
590 """
590 """
591 if not self.interactive():
591 if not self.interactive():
592 self.write(msg, ' ', default, "\n")
592 self.write(msg, ' ', default, "\n")
593 return default
593 return default
594 try:
594 try:
595 r = self._readline(self.label(msg, 'ui.prompt'))
595 r = self._readline(self.label(msg, 'ui.prompt'))
596 if not r:
596 if not r:
597 return default
597 return default
598 return r
598 return r
599 except EOFError:
599 except EOFError:
600 raise util.Abort(_('response expected'))
600 raise util.Abort(_('response expected'))
601
601
602 def promptchoice(self, msg, choices, default=0):
602 def promptchoice(self, msg, choices, default=0):
603 """Prompt user with msg, read response, and ensure it matches
603 """Prompt user with msg, read response, and ensure it matches
604 one of the provided choices. The index of the choice is returned.
604 one of the provided choices. The index of the choice is returned.
605 choices is a sequence of acceptable responses with the format:
605 choices is a sequence of acceptable responses with the format:
606 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
606 ('&None', 'E&xec', 'Sym&link') Responses are case insensitive.
607 If ui is not interactive, the default is returned.
607 If ui is not interactive, the default is returned.
608 """
608 """
609 resps = [s[s.index('&')+1].lower() for s in choices]
609 resps = [s[s.index('&')+1].lower() for s in choices]
610 while True:
610 while True:
611 r = self.prompt(msg, resps[default])
611 r = self.prompt(msg, resps[default])
612 if r.lower() in resps:
612 if r.lower() in resps:
613 return resps.index(r.lower())
613 return resps.index(r.lower())
614 self.write(_("unrecognized response\n"))
614 self.write(_("unrecognized response\n"))
615
615
616 def getpass(self, prompt=None, default=None):
616 def getpass(self, prompt=None, default=None):
617 if not self.interactive():
617 if not self.interactive():
618 return default
618 return default
619 try:
619 try:
620 return getpass.getpass(prompt or _('password: '))
620 return getpass.getpass(prompt or _('password: '))
621 except EOFError:
621 except EOFError:
622 raise util.Abort(_('response expected'))
622 raise util.Abort(_('response expected'))
623 def status(self, *msg, **opts):
623 def status(self, *msg, **opts):
624 '''write status message to output (if ui.quiet is False)
624 '''write status message to output (if ui.quiet is False)
625
625
626 This adds an output label of "ui.status".
626 This adds an output label of "ui.status".
627 '''
627 '''
628 if not self.quiet:
628 if not self.quiet:
629 opts['label'] = opts.get('label', '') + ' ui.status'
629 opts['label'] = opts.get('label', '') + ' ui.status'
630 self.write(*msg, **opts)
630 self.write(*msg, **opts)
631 def warn(self, *msg, **opts):
631 def warn(self, *msg, **opts):
632 '''write warning message to output (stderr)
632 '''write warning message to output (stderr)
633
633
634 This adds an output label of "ui.warning".
634 This adds an output label of "ui.warning".
635 '''
635 '''
636 opts['label'] = opts.get('label', '') + ' ui.warning'
636 opts['label'] = opts.get('label', '') + ' ui.warning'
637 self.write_err(*msg, **opts)
637 self.write_err(*msg, **opts)
638 def note(self, *msg, **opts):
638 def note(self, *msg, **opts):
639 '''write note to output (if ui.verbose is True)
639 '''write note to output (if ui.verbose is True)
640
640
641 This adds an output label of "ui.note".
641 This adds an output label of "ui.note".
642 '''
642 '''
643 if self.verbose:
643 if self.verbose:
644 opts['label'] = opts.get('label', '') + ' ui.note'
644 opts['label'] = opts.get('label', '') + ' ui.note'
645 self.write(*msg, **opts)
645 self.write(*msg, **opts)
646 def debug(self, *msg, **opts):
646 def debug(self, *msg, **opts):
647 '''write debug message to output (if ui.debugflag is True)
647 '''write debug message to output (if ui.debugflag is True)
648
648
649 This adds an output label of "ui.debug".
649 This adds an output label of "ui.debug".
650 '''
650 '''
651 if self.debugflag:
651 if self.debugflag:
652 opts['label'] = opts.get('label', '') + ' ui.debug'
652 opts['label'] = opts.get('label', '') + ' ui.debug'
653 self.write(*msg, **opts)
653 self.write(*msg, **opts)
654 def edit(self, text, user):
654 def edit(self, text, user):
655 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
655 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
656 text=True)
656 text=True)
657 try:
657 try:
658 f = os.fdopen(fd, "w")
658 f = os.fdopen(fd, "w")
659 f.write(text)
659 f.write(text)
660 f.close()
660 f.close()
661
661
662 editor = self.geteditor()
662 editor = self.geteditor()
663
663
664 util.system("%s \"%s\"" % (editor, name),
664 util.system("%s \"%s\"" % (editor, name),
665 environ={'HGUSER': user},
665 environ={'HGUSER': user},
666 onerr=util.Abort, errprefix=_("edit failed"),
666 onerr=util.Abort, errprefix=_("edit failed"),
667 out=self.fout)
667 out=self.fout)
668
668
669 f = open(name)
669 f = open(name)
670 t = f.read()
670 t = f.read()
671 f.close()
671 f.close()
672 finally:
672 finally:
673 os.unlink(name)
673 os.unlink(name)
674
674
675 return t
675 return t
676
676
677 def traceback(self, exc=None):
677 def traceback(self, exc=None):
678 '''print exception traceback if traceback printing enabled.
678 '''print exception traceback if traceback printing enabled.
679 only to call in exception handler. returns true if traceback
679 only to call in exception handler. returns true if traceback
680 printed.'''
680 printed.'''
681 if self.tracebackflag:
681 if self.tracebackflag:
682 if exc:
682 if exc:
683 traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
683 traceback.print_exception(exc[0], exc[1], exc[2], file=self.ferr)
684 else:
684 else:
685 traceback.print_exc(file=self.ferr)
685 traceback.print_exc(file=self.ferr)
686 return self.tracebackflag
686 return self.tracebackflag
687
687
688 def geteditor(self):
688 def geteditor(self):
689 '''return editor to use'''
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 return (os.environ.get("HGEDITOR") or
697 return (os.environ.get("HGEDITOR") or
691 self.config("ui", "editor") or
698 self.config("ui", "editor") or
692 os.environ.get("VISUAL") or
699 os.environ.get("VISUAL") or
693 os.environ.get("EDITOR", "vi"))
700 os.environ.get("EDITOR", editor))
694
701
695 def progress(self, topic, pos, item="", unit="", total=None):
702 def progress(self, topic, pos, item="", unit="", total=None):
696 '''show a progress message
703 '''show a progress message
697
704
698 With stock hg, this is simply a debug message that is hidden
705 With stock hg, this is simply a debug message that is hidden
699 by default, but with extensions or GUI tools it may be
706 by default, but with extensions or GUI tools it may be
700 visible. 'topic' is the current operation, 'item' is a
707 visible. 'topic' is the current operation, 'item' is a
701 non-numeric marker of the current position (ie the currently
708 non-numeric marker of the current position (ie the currently
702 in-process file), 'pos' is the current numeric position (ie
709 in-process file), 'pos' is the current numeric position (ie
703 revision, bytes, etc.), unit is a corresponding unit label,
710 revision, bytes, etc.), unit is a corresponding unit label,
704 and total is the highest expected pos.
711 and total is the highest expected pos.
705
712
706 Multiple nested topics may be active at a time.
713 Multiple nested topics may be active at a time.
707
714
708 All topics should be marked closed by setting pos to None at
715 All topics should be marked closed by setting pos to None at
709 termination.
716 termination.
710 '''
717 '''
711
718
712 if pos is None or not self.debugflag:
719 if pos is None or not self.debugflag:
713 return
720 return
714
721
715 if unit:
722 if unit:
716 unit = ' ' + unit
723 unit = ' ' + unit
717 if item:
724 if item:
718 item = ' ' + item
725 item = ' ' + item
719
726
720 if total:
727 if total:
721 pct = 100.0 * pos / total
728 pct = 100.0 * pos / total
722 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
729 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
723 % (topic, item, pos, total, unit, pct))
730 % (topic, item, pos, total, unit, pct))
724 else:
731 else:
725 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
732 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
726
733
727 def log(self, service, message):
734 def log(self, service, message):
728 '''hook for logging facility extensions
735 '''hook for logging facility extensions
729
736
730 service should be a readily-identifiable subsystem, which will
737 service should be a readily-identifiable subsystem, which will
731 allow filtering.
738 allow filtering.
732 message should be a newline-terminated string to log.
739 message should be a newline-terminated string to log.
733 '''
740 '''
734 pass
741 pass
735
742
736 def label(self, msg, label):
743 def label(self, msg, label):
737 '''style msg based on supplied label
744 '''style msg based on supplied label
738
745
739 Like ui.write(), this just returns msg unchanged, but extensions
746 Like ui.write(), this just returns msg unchanged, but extensions
740 and GUI tools can override it to allow styling output without
747 and GUI tools can override it to allow styling output without
741 writing it.
748 writing it.
742
749
743 ui.write(s, 'label') is equivalent to
750 ui.write(s, 'label') is equivalent to
744 ui.write(ui.label(s, 'label')).
751 ui.write(ui.label(s, 'label')).
745 '''
752 '''
746 return msg
753 return msg
@@ -1,1759 +1,1766 b''
1 # util.py - Mercurial utility functions and platform specfic implementations
1 # util.py - Mercurial utility functions and platform specfic implementations
2 #
2 #
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
3 # Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 """Mercurial utility functions and platform specfic implementations.
10 """Mercurial utility functions and platform specfic implementations.
11
11
12 This contains helper routines that are independent of the SCM core and
12 This contains helper routines that are independent of the SCM core and
13 hide platform-specific details from the core.
13 hide platform-specific details from the core.
14 """
14 """
15
15
16 from i18n import _
16 from i18n import _
17 import error, osutil, encoding
17 import error, osutil, encoding
18 import errno, re, shutil, sys, tempfile, traceback
18 import errno, re, shutil, sys, tempfile, traceback
19 import os, time, datetime, calendar, textwrap, signal
19 import os, time, datetime, calendar, textwrap, signal
20 import imp, socket, urllib
20 import imp, socket, urllib
21
21
22 if os.name == 'nt':
22 if os.name == 'nt':
23 import windows as platform
23 import windows as platform
24 else:
24 else:
25 import posix as platform
25 import posix as platform
26
26
27 platform.encodinglower = encoding.lower
27 platform.encodinglower = encoding.lower
28 platform.encodingupper = encoding.upper
28 platform.encodingupper = encoding.upper
29
29
30 cachestat = platform.cachestat
30 cachestat = platform.cachestat
31 checkexec = platform.checkexec
31 checkexec = platform.checkexec
32 checklink = platform.checklink
32 checklink = platform.checklink
33 copymode = platform.copymode
33 copymode = platform.copymode
34 executablepath = platform.executablepath
34 executablepath = platform.executablepath
35 expandglobs = platform.expandglobs
35 expandglobs = platform.expandglobs
36 explainexit = platform.explainexit
36 explainexit = platform.explainexit
37 findexe = platform.findexe
37 findexe = platform.findexe
38 gethgcmd = platform.gethgcmd
38 gethgcmd = platform.gethgcmd
39 getuser = platform.getuser
39 getuser = platform.getuser
40 groupmembers = platform.groupmembers
40 groupmembers = platform.groupmembers
41 groupname = platform.groupname
41 groupname = platform.groupname
42 hidewindow = platform.hidewindow
42 hidewindow = platform.hidewindow
43 isexec = platform.isexec
43 isexec = platform.isexec
44 isowner = platform.isowner
44 isowner = platform.isowner
45 localpath = platform.localpath
45 localpath = platform.localpath
46 lookupreg = platform.lookupreg
46 lookupreg = platform.lookupreg
47 makedir = platform.makedir
47 makedir = platform.makedir
48 nlinks = platform.nlinks
48 nlinks = platform.nlinks
49 normpath = platform.normpath
49 normpath = platform.normpath
50 normcase = platform.normcase
50 normcase = platform.normcase
51 nulldev = platform.nulldev
51 nulldev = platform.nulldev
52 openhardlinks = platform.openhardlinks
52 openhardlinks = platform.openhardlinks
53 oslink = platform.oslink
53 oslink = platform.oslink
54 parsepatchoutput = platform.parsepatchoutput
54 parsepatchoutput = platform.parsepatchoutput
55 pconvert = platform.pconvert
55 pconvert = platform.pconvert
56 popen = platform.popen
56 popen = platform.popen
57 posixfile = platform.posixfile
57 posixfile = platform.posixfile
58 quotecommand = platform.quotecommand
58 quotecommand = platform.quotecommand
59 realpath = platform.realpath
59 realpath = platform.realpath
60 rename = platform.rename
60 rename = platform.rename
61 samedevice = platform.samedevice
61 samedevice = platform.samedevice
62 samefile = platform.samefile
62 samefile = platform.samefile
63 samestat = platform.samestat
63 samestat = platform.samestat
64 setbinary = platform.setbinary
64 setbinary = platform.setbinary
65 setflags = platform.setflags
65 setflags = platform.setflags
66 setsignalhandler = platform.setsignalhandler
66 setsignalhandler = platform.setsignalhandler
67 shellquote = platform.shellquote
67 shellquote = platform.shellquote
68 spawndetached = platform.spawndetached
68 spawndetached = platform.spawndetached
69 sshargs = platform.sshargs
69 sshargs = platform.sshargs
70 statfiles = platform.statfiles
70 statfiles = platform.statfiles
71 termwidth = platform.termwidth
71 termwidth = platform.termwidth
72 testpid = platform.testpid
72 testpid = platform.testpid
73 umask = platform.umask
73 umask = platform.umask
74 unlink = platform.unlink
74 unlink = platform.unlink
75 unlinkpath = platform.unlinkpath
75 unlinkpath = platform.unlinkpath
76 username = platform.username
76 username = platform.username
77
77
78 # Python compatibility
78 # Python compatibility
79
79
80 _notset = object()
80 _notset = object()
81
81
82 def safehasattr(thing, attr):
82 def safehasattr(thing, attr):
83 return getattr(thing, attr, _notset) is not _notset
83 return getattr(thing, attr, _notset) is not _notset
84
84
85 def sha1(s=''):
85 def sha1(s=''):
86 '''
86 '''
87 Low-overhead wrapper around Python's SHA support
87 Low-overhead wrapper around Python's SHA support
88
88
89 >>> f = _fastsha1
89 >>> f = _fastsha1
90 >>> a = sha1()
90 >>> a = sha1()
91 >>> a = f()
91 >>> a = f()
92 >>> a.hexdigest()
92 >>> a.hexdigest()
93 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
93 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
94 '''
94 '''
95
95
96 return _fastsha1(s)
96 return _fastsha1(s)
97
97
98 def _fastsha1(s=''):
98 def _fastsha1(s=''):
99 # This function will import sha1 from hashlib or sha (whichever is
99 # This function will import sha1 from hashlib or sha (whichever is
100 # available) and overwrite itself with it on the first call.
100 # available) and overwrite itself with it on the first call.
101 # Subsequent calls will go directly to the imported function.
101 # Subsequent calls will go directly to the imported function.
102 if sys.version_info >= (2, 5):
102 if sys.version_info >= (2, 5):
103 from hashlib import sha1 as _sha1
103 from hashlib import sha1 as _sha1
104 else:
104 else:
105 from sha import sha as _sha1
105 from sha import sha as _sha1
106 global _fastsha1, sha1
106 global _fastsha1, sha1
107 _fastsha1 = sha1 = _sha1
107 _fastsha1 = sha1 = _sha1
108 return _sha1(s)
108 return _sha1(s)
109
109
110 try:
110 try:
111 buffer = buffer
111 buffer = buffer
112 except NameError:
112 except NameError:
113 if sys.version_info[0] < 3:
113 if sys.version_info[0] < 3:
114 def buffer(sliceable, offset=0):
114 def buffer(sliceable, offset=0):
115 return sliceable[offset:]
115 return sliceable[offset:]
116 else:
116 else:
117 def buffer(sliceable, offset=0):
117 def buffer(sliceable, offset=0):
118 return memoryview(sliceable)[offset:]
118 return memoryview(sliceable)[offset:]
119
119
120 import subprocess
120 import subprocess
121 closefds = os.name == 'posix'
121 closefds = os.name == 'posix'
122
122
123 def popen2(cmd, env=None, newlines=False):
123 def popen2(cmd, env=None, newlines=False):
124 # Setting bufsize to -1 lets the system decide the buffer size.
124 # Setting bufsize to -1 lets the system decide the buffer size.
125 # The default for bufsize is 0, meaning unbuffered. This leads to
125 # The default for bufsize is 0, meaning unbuffered. This leads to
126 # poor performance on Mac OS X: http://bugs.python.org/issue4194
126 # poor performance on Mac OS X: http://bugs.python.org/issue4194
127 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
127 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
128 close_fds=closefds,
128 close_fds=closefds,
129 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
129 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
130 universal_newlines=newlines,
130 universal_newlines=newlines,
131 env=env)
131 env=env)
132 return p.stdin, p.stdout
132 return p.stdin, p.stdout
133
133
134 def popen3(cmd, env=None, newlines=False):
134 def popen3(cmd, env=None, newlines=False):
135 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
135 p = subprocess.Popen(cmd, shell=True, bufsize=-1,
136 close_fds=closefds,
136 close_fds=closefds,
137 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
137 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
138 stderr=subprocess.PIPE,
138 stderr=subprocess.PIPE,
139 universal_newlines=newlines,
139 universal_newlines=newlines,
140 env=env)
140 env=env)
141 return p.stdin, p.stdout, p.stderr
141 return p.stdin, p.stdout, p.stderr
142
142
143 def version():
143 def version():
144 """Return version information if available."""
144 """Return version information if available."""
145 try:
145 try:
146 import __version__
146 import __version__
147 return __version__.version
147 return __version__.version
148 except ImportError:
148 except ImportError:
149 return 'unknown'
149 return 'unknown'
150
150
151 # used by parsedate
151 # used by parsedate
152 defaultdateformats = (
152 defaultdateformats = (
153 '%Y-%m-%d %H:%M:%S',
153 '%Y-%m-%d %H:%M:%S',
154 '%Y-%m-%d %I:%M:%S%p',
154 '%Y-%m-%d %I:%M:%S%p',
155 '%Y-%m-%d %H:%M',
155 '%Y-%m-%d %H:%M',
156 '%Y-%m-%d %I:%M%p',
156 '%Y-%m-%d %I:%M%p',
157 '%Y-%m-%d',
157 '%Y-%m-%d',
158 '%m-%d',
158 '%m-%d',
159 '%m/%d',
159 '%m/%d',
160 '%m/%d/%y',
160 '%m/%d/%y',
161 '%m/%d/%Y',
161 '%m/%d/%Y',
162 '%a %b %d %H:%M:%S %Y',
162 '%a %b %d %H:%M:%S %Y',
163 '%a %b %d %I:%M:%S%p %Y',
163 '%a %b %d %I:%M:%S%p %Y',
164 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
164 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
165 '%b %d %H:%M:%S %Y',
165 '%b %d %H:%M:%S %Y',
166 '%b %d %I:%M:%S%p %Y',
166 '%b %d %I:%M:%S%p %Y',
167 '%b %d %H:%M:%S',
167 '%b %d %H:%M:%S',
168 '%b %d %I:%M:%S%p',
168 '%b %d %I:%M:%S%p',
169 '%b %d %H:%M',
169 '%b %d %H:%M',
170 '%b %d %I:%M%p',
170 '%b %d %I:%M%p',
171 '%b %d %Y',
171 '%b %d %Y',
172 '%b %d',
172 '%b %d',
173 '%H:%M:%S',
173 '%H:%M:%S',
174 '%I:%M:%S%p',
174 '%I:%M:%S%p',
175 '%H:%M',
175 '%H:%M',
176 '%I:%M%p',
176 '%I:%M%p',
177 )
177 )
178
178
179 extendeddateformats = defaultdateformats + (
179 extendeddateformats = defaultdateformats + (
180 "%Y",
180 "%Y",
181 "%Y-%m",
181 "%Y-%m",
182 "%b",
182 "%b",
183 "%b %Y",
183 "%b %Y",
184 )
184 )
185
185
186 def cachefunc(func):
186 def cachefunc(func):
187 '''cache the result of function calls'''
187 '''cache the result of function calls'''
188 # XXX doesn't handle keywords args
188 # XXX doesn't handle keywords args
189 cache = {}
189 cache = {}
190 if func.func_code.co_argcount == 1:
190 if func.func_code.co_argcount == 1:
191 # we gain a small amount of time because
191 # we gain a small amount of time because
192 # we don't need to pack/unpack the list
192 # we don't need to pack/unpack the list
193 def f(arg):
193 def f(arg):
194 if arg not in cache:
194 if arg not in cache:
195 cache[arg] = func(arg)
195 cache[arg] = func(arg)
196 return cache[arg]
196 return cache[arg]
197 else:
197 else:
198 def f(*args):
198 def f(*args):
199 if args not in cache:
199 if args not in cache:
200 cache[args] = func(*args)
200 cache[args] = func(*args)
201 return cache[args]
201 return cache[args]
202
202
203 return f
203 return f
204
204
205 def lrucachefunc(func):
205 def lrucachefunc(func):
206 '''cache most recent results of function calls'''
206 '''cache most recent results of function calls'''
207 cache = {}
207 cache = {}
208 order = []
208 order = []
209 if func.func_code.co_argcount == 1:
209 if func.func_code.co_argcount == 1:
210 def f(arg):
210 def f(arg):
211 if arg not in cache:
211 if arg not in cache:
212 if len(cache) > 20:
212 if len(cache) > 20:
213 del cache[order.pop(0)]
213 del cache[order.pop(0)]
214 cache[arg] = func(arg)
214 cache[arg] = func(arg)
215 else:
215 else:
216 order.remove(arg)
216 order.remove(arg)
217 order.append(arg)
217 order.append(arg)
218 return cache[arg]
218 return cache[arg]
219 else:
219 else:
220 def f(*args):
220 def f(*args):
221 if args not in cache:
221 if args not in cache:
222 if len(cache) > 20:
222 if len(cache) > 20:
223 del cache[order.pop(0)]
223 del cache[order.pop(0)]
224 cache[args] = func(*args)
224 cache[args] = func(*args)
225 else:
225 else:
226 order.remove(args)
226 order.remove(args)
227 order.append(args)
227 order.append(args)
228 return cache[args]
228 return cache[args]
229
229
230 return f
230 return f
231
231
232 class propertycache(object):
232 class propertycache(object):
233 def __init__(self, func):
233 def __init__(self, func):
234 self.func = func
234 self.func = func
235 self.name = func.__name__
235 self.name = func.__name__
236 def __get__(self, obj, type=None):
236 def __get__(self, obj, type=None):
237 result = self.func(obj)
237 result = self.func(obj)
238 setattr(obj, self.name, result)
238 setattr(obj, self.name, result)
239 return result
239 return result
240
240
241 def pipefilter(s, cmd):
241 def pipefilter(s, cmd):
242 '''filter string S through command CMD, returning its output'''
242 '''filter string S through command CMD, returning its output'''
243 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
243 p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
244 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
244 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
245 pout, perr = p.communicate(s)
245 pout, perr = p.communicate(s)
246 return pout
246 return pout
247
247
248 def tempfilter(s, cmd):
248 def tempfilter(s, cmd):
249 '''filter string S through a pair of temporary files with CMD.
249 '''filter string S through a pair of temporary files with CMD.
250 CMD is used as a template to create the real command to be run,
250 CMD is used as a template to create the real command to be run,
251 with the strings INFILE and OUTFILE replaced by the real names of
251 with the strings INFILE and OUTFILE replaced by the real names of
252 the temporary files generated.'''
252 the temporary files generated.'''
253 inname, outname = None, None
253 inname, outname = None, None
254 try:
254 try:
255 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
255 infd, inname = tempfile.mkstemp(prefix='hg-filter-in-')
256 fp = os.fdopen(infd, 'wb')
256 fp = os.fdopen(infd, 'wb')
257 fp.write(s)
257 fp.write(s)
258 fp.close()
258 fp.close()
259 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
259 outfd, outname = tempfile.mkstemp(prefix='hg-filter-out-')
260 os.close(outfd)
260 os.close(outfd)
261 cmd = cmd.replace('INFILE', inname)
261 cmd = cmd.replace('INFILE', inname)
262 cmd = cmd.replace('OUTFILE', outname)
262 cmd = cmd.replace('OUTFILE', outname)
263 code = os.system(cmd)
263 code = os.system(cmd)
264 if sys.platform == 'OpenVMS' and code & 1:
264 if sys.platform == 'OpenVMS' and code & 1:
265 code = 0
265 code = 0
266 if code:
266 if code:
267 raise Abort(_("command '%s' failed: %s") %
267 raise Abort(_("command '%s' failed: %s") %
268 (cmd, explainexit(code)))
268 (cmd, explainexit(code)))
269 fp = open(outname, 'rb')
269 fp = open(outname, 'rb')
270 r = fp.read()
270 r = fp.read()
271 fp.close()
271 fp.close()
272 return r
272 return r
273 finally:
273 finally:
274 try:
274 try:
275 if inname:
275 if inname:
276 os.unlink(inname)
276 os.unlink(inname)
277 except OSError:
277 except OSError:
278 pass
278 pass
279 try:
279 try:
280 if outname:
280 if outname:
281 os.unlink(outname)
281 os.unlink(outname)
282 except OSError:
282 except OSError:
283 pass
283 pass
284
284
285 filtertable = {
285 filtertable = {
286 'tempfile:': tempfilter,
286 'tempfile:': tempfilter,
287 'pipe:': pipefilter,
287 'pipe:': pipefilter,
288 }
288 }
289
289
290 def filter(s, cmd):
290 def filter(s, cmd):
291 "filter a string through a command that transforms its input to its output"
291 "filter a string through a command that transforms its input to its output"
292 for name, fn in filtertable.iteritems():
292 for name, fn in filtertable.iteritems():
293 if cmd.startswith(name):
293 if cmd.startswith(name):
294 return fn(s, cmd[len(name):].lstrip())
294 return fn(s, cmd[len(name):].lstrip())
295 return pipefilter(s, cmd)
295 return pipefilter(s, cmd)
296
296
297 def binary(s):
297 def binary(s):
298 """return true if a string is binary data"""
298 """return true if a string is binary data"""
299 return bool(s and '\0' in s)
299 return bool(s and '\0' in s)
300
300
301 def increasingchunks(source, min=1024, max=65536):
301 def increasingchunks(source, min=1024, max=65536):
302 '''return no less than min bytes per chunk while data remains,
302 '''return no less than min bytes per chunk while data remains,
303 doubling min after each chunk until it reaches max'''
303 doubling min after each chunk until it reaches max'''
304 def log2(x):
304 def log2(x):
305 if not x:
305 if not x:
306 return 0
306 return 0
307 i = 0
307 i = 0
308 while x:
308 while x:
309 x >>= 1
309 x >>= 1
310 i += 1
310 i += 1
311 return i - 1
311 return i - 1
312
312
313 buf = []
313 buf = []
314 blen = 0
314 blen = 0
315 for chunk in source:
315 for chunk in source:
316 buf.append(chunk)
316 buf.append(chunk)
317 blen += len(chunk)
317 blen += len(chunk)
318 if blen >= min:
318 if blen >= min:
319 if min < max:
319 if min < max:
320 min = min << 1
320 min = min << 1
321 nmin = 1 << log2(blen)
321 nmin = 1 << log2(blen)
322 if nmin > min:
322 if nmin > min:
323 min = nmin
323 min = nmin
324 if min > max:
324 if min > max:
325 min = max
325 min = max
326 yield ''.join(buf)
326 yield ''.join(buf)
327 blen = 0
327 blen = 0
328 buf = []
328 buf = []
329 if buf:
329 if buf:
330 yield ''.join(buf)
330 yield ''.join(buf)
331
331
332 Abort = error.Abort
332 Abort = error.Abort
333
333
334 def always(fn):
334 def always(fn):
335 return True
335 return True
336
336
337 def never(fn):
337 def never(fn):
338 return False
338 return False
339
339
340 def pathto(root, n1, n2):
340 def pathto(root, n1, n2):
341 '''return the relative path from one place to another.
341 '''return the relative path from one place to another.
342 root should use os.sep to separate directories
342 root should use os.sep to separate directories
343 n1 should use os.sep to separate directories
343 n1 should use os.sep to separate directories
344 n2 should use "/" to separate directories
344 n2 should use "/" to separate directories
345 returns an os.sep-separated path.
345 returns an os.sep-separated path.
346
346
347 If n1 is a relative path, it's assumed it's
347 If n1 is a relative path, it's assumed it's
348 relative to root.
348 relative to root.
349 n2 should always be relative to root.
349 n2 should always be relative to root.
350 '''
350 '''
351 if not n1:
351 if not n1:
352 return localpath(n2)
352 return localpath(n2)
353 if os.path.isabs(n1):
353 if os.path.isabs(n1):
354 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
354 if os.path.splitdrive(root)[0] != os.path.splitdrive(n1)[0]:
355 return os.path.join(root, localpath(n2))
355 return os.path.join(root, localpath(n2))
356 n2 = '/'.join((pconvert(root), n2))
356 n2 = '/'.join((pconvert(root), n2))
357 a, b = splitpath(n1), n2.split('/')
357 a, b = splitpath(n1), n2.split('/')
358 a.reverse()
358 a.reverse()
359 b.reverse()
359 b.reverse()
360 while a and b and a[-1] == b[-1]:
360 while a and b and a[-1] == b[-1]:
361 a.pop()
361 a.pop()
362 b.pop()
362 b.pop()
363 b.reverse()
363 b.reverse()
364 return os.sep.join((['..'] * len(a)) + b) or '.'
364 return os.sep.join((['..'] * len(a)) + b) or '.'
365
365
366 _hgexecutable = None
366 _hgexecutable = None
367
367
368 def mainfrozen():
368 def mainfrozen():
369 """return True if we are a frozen executable.
369 """return True if we are a frozen executable.
370
370
371 The code supports py2exe (most common, Windows only) and tools/freeze
371 The code supports py2exe (most common, Windows only) and tools/freeze
372 (portable, not much used).
372 (portable, not much used).
373 """
373 """
374 return (safehasattr(sys, "frozen") or # new py2exe
374 return (safehasattr(sys, "frozen") or # new py2exe
375 safehasattr(sys, "importers") or # old py2exe
375 safehasattr(sys, "importers") or # old py2exe
376 imp.is_frozen("__main__")) # tools/freeze
376 imp.is_frozen("__main__")) # tools/freeze
377
377
378 def hgexecutable():
378 def hgexecutable():
379 """return location of the 'hg' executable.
379 """return location of the 'hg' executable.
380
380
381 Defaults to $HG or 'hg' in the search path.
381 Defaults to $HG or 'hg' in the search path.
382 """
382 """
383 if _hgexecutable is None:
383 if _hgexecutable is None:
384 hg = os.environ.get('HG')
384 hg = os.environ.get('HG')
385 mainmod = sys.modules['__main__']
385 mainmod = sys.modules['__main__']
386 if hg:
386 if hg:
387 _sethgexecutable(hg)
387 _sethgexecutable(hg)
388 elif mainfrozen():
388 elif mainfrozen():
389 _sethgexecutable(sys.executable)
389 _sethgexecutable(sys.executable)
390 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
390 elif os.path.basename(getattr(mainmod, '__file__', '')) == 'hg':
391 _sethgexecutable(mainmod.__file__)
391 _sethgexecutable(mainmod.__file__)
392 else:
392 else:
393 exe = findexe('hg') or os.path.basename(sys.argv[0])
393 exe = findexe('hg') or os.path.basename(sys.argv[0])
394 _sethgexecutable(exe)
394 _sethgexecutable(exe)
395 return _hgexecutable
395 return _hgexecutable
396
396
397 def _sethgexecutable(path):
397 def _sethgexecutable(path):
398 """set location of the 'hg' executable"""
398 """set location of the 'hg' executable"""
399 global _hgexecutable
399 global _hgexecutable
400 _hgexecutable = path
400 _hgexecutable = path
401
401
402 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
402 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None, out=None):
403 '''enhanced shell command execution.
403 '''enhanced shell command execution.
404 run with environment maybe modified, maybe in different dir.
404 run with environment maybe modified, maybe in different dir.
405
405
406 if command fails and onerr is None, return status. if ui object,
406 if command fails and onerr is None, return status. if ui object,
407 print error message and return status, else raise onerr object as
407 print error message and return status, else raise onerr object as
408 exception.
408 exception.
409
409
410 if out is specified, it is assumed to be a file-like object that has a
410 if out is specified, it is assumed to be a file-like object that has a
411 write() method. stdout and stderr will be redirected to out.'''
411 write() method. stdout and stderr will be redirected to out.'''
412 try:
412 try:
413 sys.stdout.flush()
413 sys.stdout.flush()
414 except Exception:
414 except Exception:
415 pass
415 pass
416 def py2shell(val):
416 def py2shell(val):
417 'convert python object into string that is useful to shell'
417 'convert python object into string that is useful to shell'
418 if val is None or val is False:
418 if val is None or val is False:
419 return '0'
419 return '0'
420 if val is True:
420 if val is True:
421 return '1'
421 return '1'
422 return str(val)
422 return str(val)
423 origcmd = cmd
423 origcmd = cmd
424 cmd = quotecommand(cmd)
424 cmd = quotecommand(cmd)
425 env = dict(os.environ)
425 if sys.platform == 'plan9':
426 env.update((k, py2shell(v)) for k, v in environ.iteritems())
426 # subprocess kludge to work around issues in half-baked Python
427 env['HG'] = hgexecutable()
427 # ports, notably bichued/python:
428 if out is None or out == sys.__stdout__:
428 if not cwd is None:
429 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
429 os.chdir(cwd)
430 env=env, cwd=cwd)
430 rc = os.system(cmd)
431 else:
431 else:
432 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
432 env = dict(os.environ)
433 env=env, cwd=cwd, stdout=subprocess.PIPE,
433 env.update((k, py2shell(v)) for k, v in environ.iteritems())
434 stderr=subprocess.STDOUT)
434 env['HG'] = hgexecutable()
435 for line in proc.stdout:
435 if out is None or out == sys.__stdout__:
436 out.write(line)
436 rc = subprocess.call(cmd, shell=True, close_fds=closefds,
437 proc.wait()
437 env=env, cwd=cwd)
438 rc = proc.returncode
438 else:
439 if sys.platform == 'OpenVMS' and rc & 1:
439 proc = subprocess.Popen(cmd, shell=True, close_fds=closefds,
440 rc = 0
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 if rc and onerr:
448 if rc and onerr:
442 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
449 errmsg = '%s %s' % (os.path.basename(origcmd.split(None, 1)[0]),
443 explainexit(rc)[0])
450 explainexit(rc)[0])
444 if errprefix:
451 if errprefix:
445 errmsg = '%s: %s' % (errprefix, errmsg)
452 errmsg = '%s: %s' % (errprefix, errmsg)
446 try:
453 try:
447 onerr.warn(errmsg + '\n')
454 onerr.warn(errmsg + '\n')
448 except AttributeError:
455 except AttributeError:
449 raise onerr(errmsg)
456 raise onerr(errmsg)
450 return rc
457 return rc
451
458
452 def checksignature(func):
459 def checksignature(func):
453 '''wrap a function with code to check for calling errors'''
460 '''wrap a function with code to check for calling errors'''
454 def check(*args, **kwargs):
461 def check(*args, **kwargs):
455 try:
462 try:
456 return func(*args, **kwargs)
463 return func(*args, **kwargs)
457 except TypeError:
464 except TypeError:
458 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
465 if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
459 raise error.SignatureError
466 raise error.SignatureError
460 raise
467 raise
461
468
462 return check
469 return check
463
470
464 def copyfile(src, dest):
471 def copyfile(src, dest):
465 "copy a file, preserving mode and atime/mtime"
472 "copy a file, preserving mode and atime/mtime"
466 if os.path.islink(src):
473 if os.path.islink(src):
467 try:
474 try:
468 os.unlink(dest)
475 os.unlink(dest)
469 except OSError:
476 except OSError:
470 pass
477 pass
471 os.symlink(os.readlink(src), dest)
478 os.symlink(os.readlink(src), dest)
472 else:
479 else:
473 try:
480 try:
474 shutil.copyfile(src, dest)
481 shutil.copyfile(src, dest)
475 shutil.copymode(src, dest)
482 shutil.copymode(src, dest)
476 except shutil.Error, inst:
483 except shutil.Error, inst:
477 raise Abort(str(inst))
484 raise Abort(str(inst))
478
485
479 def copyfiles(src, dst, hardlink=None):
486 def copyfiles(src, dst, hardlink=None):
480 """Copy a directory tree using hardlinks if possible"""
487 """Copy a directory tree using hardlinks if possible"""
481
488
482 if hardlink is None:
489 if hardlink is None:
483 hardlink = (os.stat(src).st_dev ==
490 hardlink = (os.stat(src).st_dev ==
484 os.stat(os.path.dirname(dst)).st_dev)
491 os.stat(os.path.dirname(dst)).st_dev)
485
492
486 num = 0
493 num = 0
487 if os.path.isdir(src):
494 if os.path.isdir(src):
488 os.mkdir(dst)
495 os.mkdir(dst)
489 for name, kind in osutil.listdir(src):
496 for name, kind in osutil.listdir(src):
490 srcname = os.path.join(src, name)
497 srcname = os.path.join(src, name)
491 dstname = os.path.join(dst, name)
498 dstname = os.path.join(dst, name)
492 hardlink, n = copyfiles(srcname, dstname, hardlink)
499 hardlink, n = copyfiles(srcname, dstname, hardlink)
493 num += n
500 num += n
494 else:
501 else:
495 if hardlink:
502 if hardlink:
496 try:
503 try:
497 oslink(src, dst)
504 oslink(src, dst)
498 except (IOError, OSError):
505 except (IOError, OSError):
499 hardlink = False
506 hardlink = False
500 shutil.copy(src, dst)
507 shutil.copy(src, dst)
501 else:
508 else:
502 shutil.copy(src, dst)
509 shutil.copy(src, dst)
503 num += 1
510 num += 1
504
511
505 return hardlink, num
512 return hardlink, num
506
513
507 _winreservednames = '''con prn aux nul
514 _winreservednames = '''con prn aux nul
508 com1 com2 com3 com4 com5 com6 com7 com8 com9
515 com1 com2 com3 com4 com5 com6 com7 com8 com9
509 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
516 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
510 _winreservedchars = ':*?"<>|'
517 _winreservedchars = ':*?"<>|'
511 def checkwinfilename(path):
518 def checkwinfilename(path):
512 '''Check that the base-relative path is a valid filename on Windows.
519 '''Check that the base-relative path is a valid filename on Windows.
513 Returns None if the path is ok, or a UI string describing the problem.
520 Returns None if the path is ok, or a UI string describing the problem.
514
521
515 >>> checkwinfilename("just/a/normal/path")
522 >>> checkwinfilename("just/a/normal/path")
516 >>> checkwinfilename("foo/bar/con.xml")
523 >>> checkwinfilename("foo/bar/con.xml")
517 "filename contains 'con', which is reserved on Windows"
524 "filename contains 'con', which is reserved on Windows"
518 >>> checkwinfilename("foo/con.xml/bar")
525 >>> checkwinfilename("foo/con.xml/bar")
519 "filename contains 'con', which is reserved on Windows"
526 "filename contains 'con', which is reserved on Windows"
520 >>> checkwinfilename("foo/bar/xml.con")
527 >>> checkwinfilename("foo/bar/xml.con")
521 >>> checkwinfilename("foo/bar/AUX/bla.txt")
528 >>> checkwinfilename("foo/bar/AUX/bla.txt")
522 "filename contains 'AUX', which is reserved on Windows"
529 "filename contains 'AUX', which is reserved on Windows"
523 >>> checkwinfilename("foo/bar/bla:.txt")
530 >>> checkwinfilename("foo/bar/bla:.txt")
524 "filename contains ':', which is reserved on Windows"
531 "filename contains ':', which is reserved on Windows"
525 >>> checkwinfilename("foo/bar/b\07la.txt")
532 >>> checkwinfilename("foo/bar/b\07la.txt")
526 "filename contains '\\\\x07', which is invalid on Windows"
533 "filename contains '\\\\x07', which is invalid on Windows"
527 >>> checkwinfilename("foo/bar/bla ")
534 >>> checkwinfilename("foo/bar/bla ")
528 "filename ends with ' ', which is not allowed on Windows"
535 "filename ends with ' ', which is not allowed on Windows"
529 >>> checkwinfilename("../bar")
536 >>> checkwinfilename("../bar")
530 '''
537 '''
531 for n in path.replace('\\', '/').split('/'):
538 for n in path.replace('\\', '/').split('/'):
532 if not n:
539 if not n:
533 continue
540 continue
534 for c in n:
541 for c in n:
535 if c in _winreservedchars:
542 if c in _winreservedchars:
536 return _("filename contains '%s', which is reserved "
543 return _("filename contains '%s', which is reserved "
537 "on Windows") % c
544 "on Windows") % c
538 if ord(c) <= 31:
545 if ord(c) <= 31:
539 return _("filename contains %r, which is invalid "
546 return _("filename contains %r, which is invalid "
540 "on Windows") % c
547 "on Windows") % c
541 base = n.split('.')[0]
548 base = n.split('.')[0]
542 if base and base.lower() in _winreservednames:
549 if base and base.lower() in _winreservednames:
543 return _("filename contains '%s', which is reserved "
550 return _("filename contains '%s', which is reserved "
544 "on Windows") % base
551 "on Windows") % base
545 t = n[-1]
552 t = n[-1]
546 if t in '. ' and n not in '..':
553 if t in '. ' and n not in '..':
547 return _("filename ends with '%s', which is not allowed "
554 return _("filename ends with '%s', which is not allowed "
548 "on Windows") % t
555 "on Windows") % t
549
556
550 if os.name == 'nt':
557 if os.name == 'nt':
551 checkosfilename = checkwinfilename
558 checkosfilename = checkwinfilename
552 else:
559 else:
553 checkosfilename = platform.checkosfilename
560 checkosfilename = platform.checkosfilename
554
561
555 def makelock(info, pathname):
562 def makelock(info, pathname):
556 try:
563 try:
557 return os.symlink(info, pathname)
564 return os.symlink(info, pathname)
558 except OSError, why:
565 except OSError, why:
559 if why.errno == errno.EEXIST:
566 if why.errno == errno.EEXIST:
560 raise
567 raise
561 except AttributeError: # no symlink in os
568 except AttributeError: # no symlink in os
562 pass
569 pass
563
570
564 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
571 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
565 os.write(ld, info)
572 os.write(ld, info)
566 os.close(ld)
573 os.close(ld)
567
574
568 def readlock(pathname):
575 def readlock(pathname):
569 try:
576 try:
570 return os.readlink(pathname)
577 return os.readlink(pathname)
571 except OSError, why:
578 except OSError, why:
572 if why.errno not in (errno.EINVAL, errno.ENOSYS):
579 if why.errno not in (errno.EINVAL, errno.ENOSYS):
573 raise
580 raise
574 except AttributeError: # no symlink in os
581 except AttributeError: # no symlink in os
575 pass
582 pass
576 fp = posixfile(pathname)
583 fp = posixfile(pathname)
577 r = fp.read()
584 r = fp.read()
578 fp.close()
585 fp.close()
579 return r
586 return r
580
587
581 def fstat(fp):
588 def fstat(fp):
582 '''stat file object that may not have fileno method.'''
589 '''stat file object that may not have fileno method.'''
583 try:
590 try:
584 return os.fstat(fp.fileno())
591 return os.fstat(fp.fileno())
585 except AttributeError:
592 except AttributeError:
586 return os.stat(fp.name)
593 return os.stat(fp.name)
587
594
588 # File system features
595 # File system features
589
596
590 def checkcase(path):
597 def checkcase(path):
591 """
598 """
592 Check whether the given path is on a case-sensitive filesystem
599 Check whether the given path is on a case-sensitive filesystem
593
600
594 Requires a path (like /foo/.hg) ending with a foldable final
601 Requires a path (like /foo/.hg) ending with a foldable final
595 directory component.
602 directory component.
596 """
603 """
597 s1 = os.stat(path)
604 s1 = os.stat(path)
598 d, b = os.path.split(path)
605 d, b = os.path.split(path)
599 b2 = b.upper()
606 b2 = b.upper()
600 if b == b2:
607 if b == b2:
601 b2 = b.lower()
608 b2 = b.lower()
602 if b == b2:
609 if b == b2:
603 return True # no evidence against case sensitivity
610 return True # no evidence against case sensitivity
604 p2 = os.path.join(d, b2)
611 p2 = os.path.join(d, b2)
605 try:
612 try:
606 s2 = os.stat(p2)
613 s2 = os.stat(p2)
607 if s2 == s1:
614 if s2 == s1:
608 return False
615 return False
609 return True
616 return True
610 except OSError:
617 except OSError:
611 return True
618 return True
612
619
613 _fspathcache = {}
620 _fspathcache = {}
614 def fspath(name, root):
621 def fspath(name, root):
615 '''Get name in the case stored in the filesystem
622 '''Get name in the case stored in the filesystem
616
623
617 The name should be relative to root, and be normcase-ed for efficiency.
624 The name should be relative to root, and be normcase-ed for efficiency.
618
625
619 Note that this function is unnecessary, and should not be
626 Note that this function is unnecessary, and should not be
620 called, for case-sensitive filesystems (simply because it's expensive).
627 called, for case-sensitive filesystems (simply because it's expensive).
621
628
622 The root should be normcase-ed, too.
629 The root should be normcase-ed, too.
623 '''
630 '''
624 def find(p, contents):
631 def find(p, contents):
625 for n in contents:
632 for n in contents:
626 if normcase(n) == p:
633 if normcase(n) == p:
627 return n
634 return n
628 return None
635 return None
629
636
630 seps = os.sep
637 seps = os.sep
631 if os.altsep:
638 if os.altsep:
632 seps = seps + os.altsep
639 seps = seps + os.altsep
633 # Protect backslashes. This gets silly very quickly.
640 # Protect backslashes. This gets silly very quickly.
634 seps.replace('\\','\\\\')
641 seps.replace('\\','\\\\')
635 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
642 pattern = re.compile(r'([^%s]+)|([%s]+)' % (seps, seps))
636 dir = os.path.normpath(root)
643 dir = os.path.normpath(root)
637 result = []
644 result = []
638 for part, sep in pattern.findall(name):
645 for part, sep in pattern.findall(name):
639 if sep:
646 if sep:
640 result.append(sep)
647 result.append(sep)
641 continue
648 continue
642
649
643 if dir not in _fspathcache:
650 if dir not in _fspathcache:
644 _fspathcache[dir] = os.listdir(dir)
651 _fspathcache[dir] = os.listdir(dir)
645 contents = _fspathcache[dir]
652 contents = _fspathcache[dir]
646
653
647 found = find(part, contents)
654 found = find(part, contents)
648 if not found:
655 if not found:
649 # retry "once per directory" per "dirstate.walk" which
656 # retry "once per directory" per "dirstate.walk" which
650 # may take place for each patches of "hg qpush", for example
657 # may take place for each patches of "hg qpush", for example
651 contents = os.listdir(dir)
658 contents = os.listdir(dir)
652 _fspathcache[dir] = contents
659 _fspathcache[dir] = contents
653 found = find(part, contents)
660 found = find(part, contents)
654
661
655 result.append(found or part)
662 result.append(found or part)
656 dir = os.path.join(dir, part)
663 dir = os.path.join(dir, part)
657
664
658 return ''.join(result)
665 return ''.join(result)
659
666
660 def checknlink(testfile):
667 def checknlink(testfile):
661 '''check whether hardlink count reporting works properly'''
668 '''check whether hardlink count reporting works properly'''
662
669
663 # testfile may be open, so we need a separate file for checking to
670 # testfile may be open, so we need a separate file for checking to
664 # work around issue2543 (or testfile may get lost on Samba shares)
671 # work around issue2543 (or testfile may get lost on Samba shares)
665 f1 = testfile + ".hgtmp1"
672 f1 = testfile + ".hgtmp1"
666 if os.path.lexists(f1):
673 if os.path.lexists(f1):
667 return False
674 return False
668 try:
675 try:
669 posixfile(f1, 'w').close()
676 posixfile(f1, 'w').close()
670 except IOError:
677 except IOError:
671 return False
678 return False
672
679
673 f2 = testfile + ".hgtmp2"
680 f2 = testfile + ".hgtmp2"
674 fd = None
681 fd = None
675 try:
682 try:
676 try:
683 try:
677 oslink(f1, f2)
684 oslink(f1, f2)
678 except OSError:
685 except OSError:
679 return False
686 return False
680
687
681 # nlinks() may behave differently for files on Windows shares if
688 # nlinks() may behave differently for files on Windows shares if
682 # the file is open.
689 # the file is open.
683 fd = posixfile(f2)
690 fd = posixfile(f2)
684 return nlinks(f2) > 1
691 return nlinks(f2) > 1
685 finally:
692 finally:
686 if fd is not None:
693 if fd is not None:
687 fd.close()
694 fd.close()
688 for f in (f1, f2):
695 for f in (f1, f2):
689 try:
696 try:
690 os.unlink(f)
697 os.unlink(f)
691 except OSError:
698 except OSError:
692 pass
699 pass
693
700
694 return False
701 return False
695
702
696 def endswithsep(path):
703 def endswithsep(path):
697 '''Check path ends with os.sep or os.altsep.'''
704 '''Check path ends with os.sep or os.altsep.'''
698 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
705 return path.endswith(os.sep) or os.altsep and path.endswith(os.altsep)
699
706
700 def splitpath(path):
707 def splitpath(path):
701 '''Split path by os.sep.
708 '''Split path by os.sep.
702 Note that this function does not use os.altsep because this is
709 Note that this function does not use os.altsep because this is
703 an alternative of simple "xxx.split(os.sep)".
710 an alternative of simple "xxx.split(os.sep)".
704 It is recommended to use os.path.normpath() before using this
711 It is recommended to use os.path.normpath() before using this
705 function if need.'''
712 function if need.'''
706 return path.split(os.sep)
713 return path.split(os.sep)
707
714
708 def gui():
715 def gui():
709 '''Are we running in a GUI?'''
716 '''Are we running in a GUI?'''
710 if sys.platform == 'darwin':
717 if sys.platform == 'darwin':
711 if 'SSH_CONNECTION' in os.environ:
718 if 'SSH_CONNECTION' in os.environ:
712 # handle SSH access to a box where the user is logged in
719 # handle SSH access to a box where the user is logged in
713 return False
720 return False
714 elif getattr(osutil, 'isgui', None):
721 elif getattr(osutil, 'isgui', None):
715 # check if a CoreGraphics session is available
722 # check if a CoreGraphics session is available
716 return osutil.isgui()
723 return osutil.isgui()
717 else:
724 else:
718 # pure build; use a safe default
725 # pure build; use a safe default
719 return True
726 return True
720 else:
727 else:
721 return os.name == "nt" or os.environ.get("DISPLAY")
728 return os.name == "nt" or os.environ.get("DISPLAY")
722
729
723 def mktempcopy(name, emptyok=False, createmode=None):
730 def mktempcopy(name, emptyok=False, createmode=None):
724 """Create a temporary file with the same contents from name
731 """Create a temporary file with the same contents from name
725
732
726 The permission bits are copied from the original file.
733 The permission bits are copied from the original file.
727
734
728 If the temporary file is going to be truncated immediately, you
735 If the temporary file is going to be truncated immediately, you
729 can use emptyok=True as an optimization.
736 can use emptyok=True as an optimization.
730
737
731 Returns the name of the temporary file.
738 Returns the name of the temporary file.
732 """
739 """
733 d, fn = os.path.split(name)
740 d, fn = os.path.split(name)
734 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
741 fd, temp = tempfile.mkstemp(prefix='.%s-' % fn, dir=d)
735 os.close(fd)
742 os.close(fd)
736 # Temporary files are created with mode 0600, which is usually not
743 # Temporary files are created with mode 0600, which is usually not
737 # what we want. If the original file already exists, just copy
744 # what we want. If the original file already exists, just copy
738 # its mode. Otherwise, manually obey umask.
745 # its mode. Otherwise, manually obey umask.
739 copymode(name, temp, createmode)
746 copymode(name, temp, createmode)
740 if emptyok:
747 if emptyok:
741 return temp
748 return temp
742 try:
749 try:
743 try:
750 try:
744 ifp = posixfile(name, "rb")
751 ifp = posixfile(name, "rb")
745 except IOError, inst:
752 except IOError, inst:
746 if inst.errno == errno.ENOENT:
753 if inst.errno == errno.ENOENT:
747 return temp
754 return temp
748 if not getattr(inst, 'filename', None):
755 if not getattr(inst, 'filename', None):
749 inst.filename = name
756 inst.filename = name
750 raise
757 raise
751 ofp = posixfile(temp, "wb")
758 ofp = posixfile(temp, "wb")
752 for chunk in filechunkiter(ifp):
759 for chunk in filechunkiter(ifp):
753 ofp.write(chunk)
760 ofp.write(chunk)
754 ifp.close()
761 ifp.close()
755 ofp.close()
762 ofp.close()
756 except:
763 except:
757 try: os.unlink(temp)
764 try: os.unlink(temp)
758 except: pass
765 except: pass
759 raise
766 raise
760 return temp
767 return temp
761
768
762 class atomictempfile(object):
769 class atomictempfile(object):
763 '''writeable file object that atomically updates a file
770 '''writeable file object that atomically updates a file
764
771
765 All writes will go to a temporary copy of the original file. Call
772 All writes will go to a temporary copy of the original file. Call
766 close() when you are done writing, and atomictempfile will rename
773 close() when you are done writing, and atomictempfile will rename
767 the temporary copy to the original name, making the changes
774 the temporary copy to the original name, making the changes
768 visible. If the object is destroyed without being closed, all your
775 visible. If the object is destroyed without being closed, all your
769 writes are discarded.
776 writes are discarded.
770 '''
777 '''
771 def __init__(self, name, mode='w+b', createmode=None):
778 def __init__(self, name, mode='w+b', createmode=None):
772 self.__name = name # permanent name
779 self.__name = name # permanent name
773 self._tempname = mktempcopy(name, emptyok=('w' in mode),
780 self._tempname = mktempcopy(name, emptyok=('w' in mode),
774 createmode=createmode)
781 createmode=createmode)
775 self._fp = posixfile(self._tempname, mode)
782 self._fp = posixfile(self._tempname, mode)
776
783
777 # delegated methods
784 # delegated methods
778 self.write = self._fp.write
785 self.write = self._fp.write
779 self.fileno = self._fp.fileno
786 self.fileno = self._fp.fileno
780
787
781 def close(self):
788 def close(self):
782 if not self._fp.closed:
789 if not self._fp.closed:
783 self._fp.close()
790 self._fp.close()
784 rename(self._tempname, localpath(self.__name))
791 rename(self._tempname, localpath(self.__name))
785
792
786 def discard(self):
793 def discard(self):
787 if not self._fp.closed:
794 if not self._fp.closed:
788 try:
795 try:
789 os.unlink(self._tempname)
796 os.unlink(self._tempname)
790 except OSError:
797 except OSError:
791 pass
798 pass
792 self._fp.close()
799 self._fp.close()
793
800
794 def __del__(self):
801 def __del__(self):
795 if safehasattr(self, '_fp'): # constructor actually did something
802 if safehasattr(self, '_fp'): # constructor actually did something
796 self.discard()
803 self.discard()
797
804
798 def makedirs(name, mode=None):
805 def makedirs(name, mode=None):
799 """recursive directory creation with parent mode inheritance"""
806 """recursive directory creation with parent mode inheritance"""
800 try:
807 try:
801 os.mkdir(name)
808 os.mkdir(name)
802 except OSError, err:
809 except OSError, err:
803 if err.errno == errno.EEXIST:
810 if err.errno == errno.EEXIST:
804 return
811 return
805 if err.errno != errno.ENOENT or not name:
812 if err.errno != errno.ENOENT or not name:
806 raise
813 raise
807 parent = os.path.dirname(os.path.abspath(name))
814 parent = os.path.dirname(os.path.abspath(name))
808 if parent == name:
815 if parent == name:
809 raise
816 raise
810 makedirs(parent, mode)
817 makedirs(parent, mode)
811 os.mkdir(name)
818 os.mkdir(name)
812 if mode is not None:
819 if mode is not None:
813 os.chmod(name, mode)
820 os.chmod(name, mode)
814
821
815 def readfile(path):
822 def readfile(path):
816 fp = open(path, 'rb')
823 fp = open(path, 'rb')
817 try:
824 try:
818 return fp.read()
825 return fp.read()
819 finally:
826 finally:
820 fp.close()
827 fp.close()
821
828
822 def writefile(path, text):
829 def writefile(path, text):
823 fp = open(path, 'wb')
830 fp = open(path, 'wb')
824 try:
831 try:
825 fp.write(text)
832 fp.write(text)
826 finally:
833 finally:
827 fp.close()
834 fp.close()
828
835
829 def appendfile(path, text):
836 def appendfile(path, text):
830 fp = open(path, 'ab')
837 fp = open(path, 'ab')
831 try:
838 try:
832 fp.write(text)
839 fp.write(text)
833 finally:
840 finally:
834 fp.close()
841 fp.close()
835
842
836 class chunkbuffer(object):
843 class chunkbuffer(object):
837 """Allow arbitrary sized chunks of data to be efficiently read from an
844 """Allow arbitrary sized chunks of data to be efficiently read from an
838 iterator over chunks of arbitrary size."""
845 iterator over chunks of arbitrary size."""
839
846
840 def __init__(self, in_iter):
847 def __init__(self, in_iter):
841 """in_iter is the iterator that's iterating over the input chunks.
848 """in_iter is the iterator that's iterating over the input chunks.
842 targetsize is how big a buffer to try to maintain."""
849 targetsize is how big a buffer to try to maintain."""
843 def splitbig(chunks):
850 def splitbig(chunks):
844 for chunk in chunks:
851 for chunk in chunks:
845 if len(chunk) > 2**20:
852 if len(chunk) > 2**20:
846 pos = 0
853 pos = 0
847 while pos < len(chunk):
854 while pos < len(chunk):
848 end = pos + 2 ** 18
855 end = pos + 2 ** 18
849 yield chunk[pos:end]
856 yield chunk[pos:end]
850 pos = end
857 pos = end
851 else:
858 else:
852 yield chunk
859 yield chunk
853 self.iter = splitbig(in_iter)
860 self.iter = splitbig(in_iter)
854 self._queue = []
861 self._queue = []
855
862
856 def read(self, l):
863 def read(self, l):
857 """Read L bytes of data from the iterator of chunks of data.
864 """Read L bytes of data from the iterator of chunks of data.
858 Returns less than L bytes if the iterator runs dry."""
865 Returns less than L bytes if the iterator runs dry."""
859 left = l
866 left = l
860 buf = ''
867 buf = ''
861 queue = self._queue
868 queue = self._queue
862 while left > 0:
869 while left > 0:
863 # refill the queue
870 # refill the queue
864 if not queue:
871 if not queue:
865 target = 2**18
872 target = 2**18
866 for chunk in self.iter:
873 for chunk in self.iter:
867 queue.append(chunk)
874 queue.append(chunk)
868 target -= len(chunk)
875 target -= len(chunk)
869 if target <= 0:
876 if target <= 0:
870 break
877 break
871 if not queue:
878 if not queue:
872 break
879 break
873
880
874 chunk = queue.pop(0)
881 chunk = queue.pop(0)
875 left -= len(chunk)
882 left -= len(chunk)
876 if left < 0:
883 if left < 0:
877 queue.insert(0, chunk[left:])
884 queue.insert(0, chunk[left:])
878 buf += chunk[:left]
885 buf += chunk[:left]
879 else:
886 else:
880 buf += chunk
887 buf += chunk
881
888
882 return buf
889 return buf
883
890
884 def filechunkiter(f, size=65536, limit=None):
891 def filechunkiter(f, size=65536, limit=None):
885 """Create a generator that produces the data in the file size
892 """Create a generator that produces the data in the file size
886 (default 65536) bytes at a time, up to optional limit (default is
893 (default 65536) bytes at a time, up to optional limit (default is
887 to read all data). Chunks may be less than size bytes if the
894 to read all data). Chunks may be less than size bytes if the
888 chunk is the last chunk in the file, or the file is a socket or
895 chunk is the last chunk in the file, or the file is a socket or
889 some other type of file that sometimes reads less data than is
896 some other type of file that sometimes reads less data than is
890 requested."""
897 requested."""
891 assert size >= 0
898 assert size >= 0
892 assert limit is None or limit >= 0
899 assert limit is None or limit >= 0
893 while True:
900 while True:
894 if limit is None:
901 if limit is None:
895 nbytes = size
902 nbytes = size
896 else:
903 else:
897 nbytes = min(limit, size)
904 nbytes = min(limit, size)
898 s = nbytes and f.read(nbytes)
905 s = nbytes and f.read(nbytes)
899 if not s:
906 if not s:
900 break
907 break
901 if limit:
908 if limit:
902 limit -= len(s)
909 limit -= len(s)
903 yield s
910 yield s
904
911
905 def makedate():
912 def makedate():
906 ct = time.time()
913 ct = time.time()
907 if ct < 0:
914 if ct < 0:
908 hint = _("check your clock")
915 hint = _("check your clock")
909 raise Abort(_("negative timestamp: %d") % ct, hint=hint)
916 raise Abort(_("negative timestamp: %d") % ct, hint=hint)
910 delta = (datetime.datetime.utcfromtimestamp(ct) -
917 delta = (datetime.datetime.utcfromtimestamp(ct) -
911 datetime.datetime.fromtimestamp(ct))
918 datetime.datetime.fromtimestamp(ct))
912 tz = delta.days * 86400 + delta.seconds
919 tz = delta.days * 86400 + delta.seconds
913 return ct, tz
920 return ct, tz
914
921
915 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
922 def datestr(date=None, format='%a %b %d %H:%M:%S %Y %1%2'):
916 """represent a (unixtime, offset) tuple as a localized time.
923 """represent a (unixtime, offset) tuple as a localized time.
917 unixtime is seconds since the epoch, and offset is the time zone's
924 unixtime is seconds since the epoch, and offset is the time zone's
918 number of seconds away from UTC. if timezone is false, do not
925 number of seconds away from UTC. if timezone is false, do not
919 append time zone to string."""
926 append time zone to string."""
920 t, tz = date or makedate()
927 t, tz = date or makedate()
921 if t < 0:
928 if t < 0:
922 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
929 t = 0 # time.gmtime(lt) fails on Windows for lt < -43200
923 tz = 0
930 tz = 0
924 if "%1" in format or "%2" in format:
931 if "%1" in format or "%2" in format:
925 sign = (tz > 0) and "-" or "+"
932 sign = (tz > 0) and "-" or "+"
926 minutes = abs(tz) // 60
933 minutes = abs(tz) // 60
927 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
934 format = format.replace("%1", "%c%02d" % (sign, minutes // 60))
928 format = format.replace("%2", "%02d" % (minutes % 60))
935 format = format.replace("%2", "%02d" % (minutes % 60))
929 try:
936 try:
930 t = time.gmtime(float(t) - tz)
937 t = time.gmtime(float(t) - tz)
931 except ValueError:
938 except ValueError:
932 # time was out of range
939 # time was out of range
933 t = time.gmtime(sys.maxint)
940 t = time.gmtime(sys.maxint)
934 s = time.strftime(format, t)
941 s = time.strftime(format, t)
935 return s
942 return s
936
943
937 def shortdate(date=None):
944 def shortdate(date=None):
938 """turn (timestamp, tzoff) tuple into iso 8631 date."""
945 """turn (timestamp, tzoff) tuple into iso 8631 date."""
939 return datestr(date, format='%Y-%m-%d')
946 return datestr(date, format='%Y-%m-%d')
940
947
941 def strdate(string, format, defaults=[]):
948 def strdate(string, format, defaults=[]):
942 """parse a localized time string and return a (unixtime, offset) tuple.
949 """parse a localized time string and return a (unixtime, offset) tuple.
943 if the string cannot be parsed, ValueError is raised."""
950 if the string cannot be parsed, ValueError is raised."""
944 def timezone(string):
951 def timezone(string):
945 tz = string.split()[-1]
952 tz = string.split()[-1]
946 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
953 if tz[0] in "+-" and len(tz) == 5 and tz[1:].isdigit():
947 sign = (tz[0] == "+") and 1 or -1
954 sign = (tz[0] == "+") and 1 or -1
948 hours = int(tz[1:3])
955 hours = int(tz[1:3])
949 minutes = int(tz[3:5])
956 minutes = int(tz[3:5])
950 return -sign * (hours * 60 + minutes) * 60
957 return -sign * (hours * 60 + minutes) * 60
951 if tz == "GMT" or tz == "UTC":
958 if tz == "GMT" or tz == "UTC":
952 return 0
959 return 0
953 return None
960 return None
954
961
955 # NOTE: unixtime = localunixtime + offset
962 # NOTE: unixtime = localunixtime + offset
956 offset, date = timezone(string), string
963 offset, date = timezone(string), string
957 if offset is not None:
964 if offset is not None:
958 date = " ".join(string.split()[:-1])
965 date = " ".join(string.split()[:-1])
959
966
960 # add missing elements from defaults
967 # add missing elements from defaults
961 usenow = False # default to using biased defaults
968 usenow = False # default to using biased defaults
962 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
969 for part in ("S", "M", "HI", "d", "mb", "yY"): # decreasing specificity
963 found = [True for p in part if ("%"+p) in format]
970 found = [True for p in part if ("%"+p) in format]
964 if not found:
971 if not found:
965 date += "@" + defaults[part][usenow]
972 date += "@" + defaults[part][usenow]
966 format += "@%" + part[0]
973 format += "@%" + part[0]
967 else:
974 else:
968 # We've found a specific time element, less specific time
975 # We've found a specific time element, less specific time
969 # elements are relative to today
976 # elements are relative to today
970 usenow = True
977 usenow = True
971
978
972 timetuple = time.strptime(date, format)
979 timetuple = time.strptime(date, format)
973 localunixtime = int(calendar.timegm(timetuple))
980 localunixtime = int(calendar.timegm(timetuple))
974 if offset is None:
981 if offset is None:
975 # local timezone
982 # local timezone
976 unixtime = int(time.mktime(timetuple))
983 unixtime = int(time.mktime(timetuple))
977 offset = unixtime - localunixtime
984 offset = unixtime - localunixtime
978 else:
985 else:
979 unixtime = localunixtime + offset
986 unixtime = localunixtime + offset
980 return unixtime, offset
987 return unixtime, offset
981
988
982 def parsedate(date, formats=None, bias={}):
989 def parsedate(date, formats=None, bias={}):
983 """parse a localized date/time and return a (unixtime, offset) tuple.
990 """parse a localized date/time and return a (unixtime, offset) tuple.
984
991
985 The date may be a "unixtime offset" string or in one of the specified
992 The date may be a "unixtime offset" string or in one of the specified
986 formats. If the date already is a (unixtime, offset) tuple, it is returned.
993 formats. If the date already is a (unixtime, offset) tuple, it is returned.
987 """
994 """
988 if not date:
995 if not date:
989 return 0, 0
996 return 0, 0
990 if isinstance(date, tuple) and len(date) == 2:
997 if isinstance(date, tuple) and len(date) == 2:
991 return date
998 return date
992 if not formats:
999 if not formats:
993 formats = defaultdateformats
1000 formats = defaultdateformats
994 date = date.strip()
1001 date = date.strip()
995 try:
1002 try:
996 when, offset = map(int, date.split(' '))
1003 when, offset = map(int, date.split(' '))
997 except ValueError:
1004 except ValueError:
998 # fill out defaults
1005 # fill out defaults
999 now = makedate()
1006 now = makedate()
1000 defaults = {}
1007 defaults = {}
1001 for part in ("d", "mb", "yY", "HI", "M", "S"):
1008 for part in ("d", "mb", "yY", "HI", "M", "S"):
1002 # this piece is for rounding the specific end of unknowns
1009 # this piece is for rounding the specific end of unknowns
1003 b = bias.get(part)
1010 b = bias.get(part)
1004 if b is None:
1011 if b is None:
1005 if part[0] in "HMS":
1012 if part[0] in "HMS":
1006 b = "00"
1013 b = "00"
1007 else:
1014 else:
1008 b = "0"
1015 b = "0"
1009
1016
1010 # this piece is for matching the generic end to today's date
1017 # this piece is for matching the generic end to today's date
1011 n = datestr(now, "%" + part[0])
1018 n = datestr(now, "%" + part[0])
1012
1019
1013 defaults[part] = (b, n)
1020 defaults[part] = (b, n)
1014
1021
1015 for format in formats:
1022 for format in formats:
1016 try:
1023 try:
1017 when, offset = strdate(date, format, defaults)
1024 when, offset = strdate(date, format, defaults)
1018 except (ValueError, OverflowError):
1025 except (ValueError, OverflowError):
1019 pass
1026 pass
1020 else:
1027 else:
1021 break
1028 break
1022 else:
1029 else:
1023 raise Abort(_('invalid date: %r') % date)
1030 raise Abort(_('invalid date: %r') % date)
1024 # validate explicit (probably user-specified) date and
1031 # validate explicit (probably user-specified) date and
1025 # time zone offset. values must fit in signed 32 bits for
1032 # time zone offset. values must fit in signed 32 bits for
1026 # current 32-bit linux runtimes. timezones go from UTC-12
1033 # current 32-bit linux runtimes. timezones go from UTC-12
1027 # to UTC+14
1034 # to UTC+14
1028 if abs(when) > 0x7fffffff:
1035 if abs(when) > 0x7fffffff:
1029 raise Abort(_('date exceeds 32 bits: %d') % when)
1036 raise Abort(_('date exceeds 32 bits: %d') % when)
1030 if when < 0:
1037 if when < 0:
1031 raise Abort(_('negative date value: %d') % when)
1038 raise Abort(_('negative date value: %d') % when)
1032 if offset < -50400 or offset > 43200:
1039 if offset < -50400 or offset > 43200:
1033 raise Abort(_('impossible time zone offset: %d') % offset)
1040 raise Abort(_('impossible time zone offset: %d') % offset)
1034 return when, offset
1041 return when, offset
1035
1042
1036 def matchdate(date):
1043 def matchdate(date):
1037 """Return a function that matches a given date match specifier
1044 """Return a function that matches a given date match specifier
1038
1045
1039 Formats include:
1046 Formats include:
1040
1047
1041 '{date}' match a given date to the accuracy provided
1048 '{date}' match a given date to the accuracy provided
1042
1049
1043 '<{date}' on or before a given date
1050 '<{date}' on or before a given date
1044
1051
1045 '>{date}' on or after a given date
1052 '>{date}' on or after a given date
1046
1053
1047 >>> p1 = parsedate("10:29:59")
1054 >>> p1 = parsedate("10:29:59")
1048 >>> p2 = parsedate("10:30:00")
1055 >>> p2 = parsedate("10:30:00")
1049 >>> p3 = parsedate("10:30:59")
1056 >>> p3 = parsedate("10:30:59")
1050 >>> p4 = parsedate("10:31:00")
1057 >>> p4 = parsedate("10:31:00")
1051 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1058 >>> p5 = parsedate("Sep 15 10:30:00 1999")
1052 >>> f = matchdate("10:30")
1059 >>> f = matchdate("10:30")
1053 >>> f(p1[0])
1060 >>> f(p1[0])
1054 False
1061 False
1055 >>> f(p2[0])
1062 >>> f(p2[0])
1056 True
1063 True
1057 >>> f(p3[0])
1064 >>> f(p3[0])
1058 True
1065 True
1059 >>> f(p4[0])
1066 >>> f(p4[0])
1060 False
1067 False
1061 >>> f(p5[0])
1068 >>> f(p5[0])
1062 False
1069 False
1063 """
1070 """
1064
1071
1065 def lower(date):
1072 def lower(date):
1066 d = dict(mb="1", d="1")
1073 d = dict(mb="1", d="1")
1067 return parsedate(date, extendeddateformats, d)[0]
1074 return parsedate(date, extendeddateformats, d)[0]
1068
1075
1069 def upper(date):
1076 def upper(date):
1070 d = dict(mb="12", HI="23", M="59", S="59")
1077 d = dict(mb="12", HI="23", M="59", S="59")
1071 for days in ("31", "30", "29"):
1078 for days in ("31", "30", "29"):
1072 try:
1079 try:
1073 d["d"] = days
1080 d["d"] = days
1074 return parsedate(date, extendeddateformats, d)[0]
1081 return parsedate(date, extendeddateformats, d)[0]
1075 except:
1082 except:
1076 pass
1083 pass
1077 d["d"] = "28"
1084 d["d"] = "28"
1078 return parsedate(date, extendeddateformats, d)[0]
1085 return parsedate(date, extendeddateformats, d)[0]
1079
1086
1080 date = date.strip()
1087 date = date.strip()
1081
1088
1082 if not date:
1089 if not date:
1083 raise Abort(_("dates cannot consist entirely of whitespace"))
1090 raise Abort(_("dates cannot consist entirely of whitespace"))
1084 elif date[0] == "<":
1091 elif date[0] == "<":
1085 if not date[1:]:
1092 if not date[1:]:
1086 raise Abort(_("invalid day spec, use '<DATE'"))
1093 raise Abort(_("invalid day spec, use '<DATE'"))
1087 when = upper(date[1:])
1094 when = upper(date[1:])
1088 return lambda x: x <= when
1095 return lambda x: x <= when
1089 elif date[0] == ">":
1096 elif date[0] == ">":
1090 if not date[1:]:
1097 if not date[1:]:
1091 raise Abort(_("invalid day spec, use '>DATE'"))
1098 raise Abort(_("invalid day spec, use '>DATE'"))
1092 when = lower(date[1:])
1099 when = lower(date[1:])
1093 return lambda x: x >= when
1100 return lambda x: x >= when
1094 elif date[0] == "-":
1101 elif date[0] == "-":
1095 try:
1102 try:
1096 days = int(date[1:])
1103 days = int(date[1:])
1097 except ValueError:
1104 except ValueError:
1098 raise Abort(_("invalid day spec: %s") % date[1:])
1105 raise Abort(_("invalid day spec: %s") % date[1:])
1099 if days < 0:
1106 if days < 0:
1100 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1107 raise Abort(_("%s must be nonnegative (see 'hg help dates')")
1101 % date[1:])
1108 % date[1:])
1102 when = makedate()[0] - days * 3600 * 24
1109 when = makedate()[0] - days * 3600 * 24
1103 return lambda x: x >= when
1110 return lambda x: x >= when
1104 elif " to " in date:
1111 elif " to " in date:
1105 a, b = date.split(" to ")
1112 a, b = date.split(" to ")
1106 start, stop = lower(a), upper(b)
1113 start, stop = lower(a), upper(b)
1107 return lambda x: x >= start and x <= stop
1114 return lambda x: x >= start and x <= stop
1108 else:
1115 else:
1109 start, stop = lower(date), upper(date)
1116 start, stop = lower(date), upper(date)
1110 return lambda x: x >= start and x <= stop
1117 return lambda x: x >= start and x <= stop
1111
1118
1112 def shortuser(user):
1119 def shortuser(user):
1113 """Return a short representation of a user name or email address."""
1120 """Return a short representation of a user name or email address."""
1114 f = user.find('@')
1121 f = user.find('@')
1115 if f >= 0:
1122 if f >= 0:
1116 user = user[:f]
1123 user = user[:f]
1117 f = user.find('<')
1124 f = user.find('<')
1118 if f >= 0:
1125 if f >= 0:
1119 user = user[f + 1:]
1126 user = user[f + 1:]
1120 f = user.find(' ')
1127 f = user.find(' ')
1121 if f >= 0:
1128 if f >= 0:
1122 user = user[:f]
1129 user = user[:f]
1123 f = user.find('.')
1130 f = user.find('.')
1124 if f >= 0:
1131 if f >= 0:
1125 user = user[:f]
1132 user = user[:f]
1126 return user
1133 return user
1127
1134
1128 def emailuser(user):
1135 def emailuser(user):
1129 """Return the user portion of an email address."""
1136 """Return the user portion of an email address."""
1130 f = user.find('@')
1137 f = user.find('@')
1131 if f >= 0:
1138 if f >= 0:
1132 user = user[:f]
1139 user = user[:f]
1133 f = user.find('<')
1140 f = user.find('<')
1134 if f >= 0:
1141 if f >= 0:
1135 user = user[f + 1:]
1142 user = user[f + 1:]
1136 return user
1143 return user
1137
1144
1138 def email(author):
1145 def email(author):
1139 '''get email of author.'''
1146 '''get email of author.'''
1140 r = author.find('>')
1147 r = author.find('>')
1141 if r == -1:
1148 if r == -1:
1142 r = None
1149 r = None
1143 return author[author.find('<') + 1:r]
1150 return author[author.find('<') + 1:r]
1144
1151
1145 def _ellipsis(text, maxlength):
1152 def _ellipsis(text, maxlength):
1146 if len(text) <= maxlength:
1153 if len(text) <= maxlength:
1147 return text, False
1154 return text, False
1148 else:
1155 else:
1149 return "%s..." % (text[:maxlength - 3]), True
1156 return "%s..." % (text[:maxlength - 3]), True
1150
1157
1151 def ellipsis(text, maxlength=400):
1158 def ellipsis(text, maxlength=400):
1152 """Trim string to at most maxlength (default: 400) characters."""
1159 """Trim string to at most maxlength (default: 400) characters."""
1153 try:
1160 try:
1154 # use unicode not to split at intermediate multi-byte sequence
1161 # use unicode not to split at intermediate multi-byte sequence
1155 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1162 utext, truncated = _ellipsis(text.decode(encoding.encoding),
1156 maxlength)
1163 maxlength)
1157 if not truncated:
1164 if not truncated:
1158 return text
1165 return text
1159 return utext.encode(encoding.encoding)
1166 return utext.encode(encoding.encoding)
1160 except (UnicodeDecodeError, UnicodeEncodeError):
1167 except (UnicodeDecodeError, UnicodeEncodeError):
1161 return _ellipsis(text, maxlength)[0]
1168 return _ellipsis(text, maxlength)[0]
1162
1169
1163 def bytecount(nbytes):
1170 def bytecount(nbytes):
1164 '''return byte count formatted as readable string, with units'''
1171 '''return byte count formatted as readable string, with units'''
1165
1172
1166 units = (
1173 units = (
1167 (100, 1 << 30, _('%.0f GB')),
1174 (100, 1 << 30, _('%.0f GB')),
1168 (10, 1 << 30, _('%.1f GB')),
1175 (10, 1 << 30, _('%.1f GB')),
1169 (1, 1 << 30, _('%.2f GB')),
1176 (1, 1 << 30, _('%.2f GB')),
1170 (100, 1 << 20, _('%.0f MB')),
1177 (100, 1 << 20, _('%.0f MB')),
1171 (10, 1 << 20, _('%.1f MB')),
1178 (10, 1 << 20, _('%.1f MB')),
1172 (1, 1 << 20, _('%.2f MB')),
1179 (1, 1 << 20, _('%.2f MB')),
1173 (100, 1 << 10, _('%.0f KB')),
1180 (100, 1 << 10, _('%.0f KB')),
1174 (10, 1 << 10, _('%.1f KB')),
1181 (10, 1 << 10, _('%.1f KB')),
1175 (1, 1 << 10, _('%.2f KB')),
1182 (1, 1 << 10, _('%.2f KB')),
1176 (1, 1, _('%.0f bytes')),
1183 (1, 1, _('%.0f bytes')),
1177 )
1184 )
1178
1185
1179 for multiplier, divisor, format in units:
1186 for multiplier, divisor, format in units:
1180 if nbytes >= divisor * multiplier:
1187 if nbytes >= divisor * multiplier:
1181 return format % (nbytes / float(divisor))
1188 return format % (nbytes / float(divisor))
1182 return units[-1][2] % nbytes
1189 return units[-1][2] % nbytes
1183
1190
1184 def uirepr(s):
1191 def uirepr(s):
1185 # Avoid double backslash in Windows path repr()
1192 # Avoid double backslash in Windows path repr()
1186 return repr(s).replace('\\\\', '\\')
1193 return repr(s).replace('\\\\', '\\')
1187
1194
1188 # delay import of textwrap
1195 # delay import of textwrap
1189 def MBTextWrapper(**kwargs):
1196 def MBTextWrapper(**kwargs):
1190 class tw(textwrap.TextWrapper):
1197 class tw(textwrap.TextWrapper):
1191 """
1198 """
1192 Extend TextWrapper for width-awareness.
1199 Extend TextWrapper for width-awareness.
1193
1200
1194 Neither number of 'bytes' in any encoding nor 'characters' is
1201 Neither number of 'bytes' in any encoding nor 'characters' is
1195 appropriate to calculate terminal columns for specified string.
1202 appropriate to calculate terminal columns for specified string.
1196
1203
1197 Original TextWrapper implementation uses built-in 'len()' directly,
1204 Original TextWrapper implementation uses built-in 'len()' directly,
1198 so overriding is needed to use width information of each characters.
1205 so overriding is needed to use width information of each characters.
1199
1206
1200 In addition, characters classified into 'ambiguous' width are
1207 In addition, characters classified into 'ambiguous' width are
1201 treated as wide in east asian area, but as narrow in other.
1208 treated as wide in east asian area, but as narrow in other.
1202
1209
1203 This requires use decision to determine width of such characters.
1210 This requires use decision to determine width of such characters.
1204 """
1211 """
1205 def __init__(self, **kwargs):
1212 def __init__(self, **kwargs):
1206 textwrap.TextWrapper.__init__(self, **kwargs)
1213 textwrap.TextWrapper.__init__(self, **kwargs)
1207
1214
1208 # for compatibility between 2.4 and 2.6
1215 # for compatibility between 2.4 and 2.6
1209 if getattr(self, 'drop_whitespace', None) is None:
1216 if getattr(self, 'drop_whitespace', None) is None:
1210 self.drop_whitespace = kwargs.get('drop_whitespace', True)
1217 self.drop_whitespace = kwargs.get('drop_whitespace', True)
1211
1218
1212 def _cutdown(self, ucstr, space_left):
1219 def _cutdown(self, ucstr, space_left):
1213 l = 0
1220 l = 0
1214 colwidth = encoding.ucolwidth
1221 colwidth = encoding.ucolwidth
1215 for i in xrange(len(ucstr)):
1222 for i in xrange(len(ucstr)):
1216 l += colwidth(ucstr[i])
1223 l += colwidth(ucstr[i])
1217 if space_left < l:
1224 if space_left < l:
1218 return (ucstr[:i], ucstr[i:])
1225 return (ucstr[:i], ucstr[i:])
1219 return ucstr, ''
1226 return ucstr, ''
1220
1227
1221 # overriding of base class
1228 # overriding of base class
1222 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1229 def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
1223 space_left = max(width - cur_len, 1)
1230 space_left = max(width - cur_len, 1)
1224
1231
1225 if self.break_long_words:
1232 if self.break_long_words:
1226 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1233 cut, res = self._cutdown(reversed_chunks[-1], space_left)
1227 cur_line.append(cut)
1234 cur_line.append(cut)
1228 reversed_chunks[-1] = res
1235 reversed_chunks[-1] = res
1229 elif not cur_line:
1236 elif not cur_line:
1230 cur_line.append(reversed_chunks.pop())
1237 cur_line.append(reversed_chunks.pop())
1231
1238
1232 # this overriding code is imported from TextWrapper of python 2.6
1239 # this overriding code is imported from TextWrapper of python 2.6
1233 # to calculate columns of string by 'encoding.ucolwidth()'
1240 # to calculate columns of string by 'encoding.ucolwidth()'
1234 def _wrap_chunks(self, chunks):
1241 def _wrap_chunks(self, chunks):
1235 colwidth = encoding.ucolwidth
1242 colwidth = encoding.ucolwidth
1236
1243
1237 lines = []
1244 lines = []
1238 if self.width <= 0:
1245 if self.width <= 0:
1239 raise ValueError("invalid width %r (must be > 0)" % self.width)
1246 raise ValueError("invalid width %r (must be > 0)" % self.width)
1240
1247
1241 # Arrange in reverse order so items can be efficiently popped
1248 # Arrange in reverse order so items can be efficiently popped
1242 # from a stack of chucks.
1249 # from a stack of chucks.
1243 chunks.reverse()
1250 chunks.reverse()
1244
1251
1245 while chunks:
1252 while chunks:
1246
1253
1247 # Start the list of chunks that will make up the current line.
1254 # Start the list of chunks that will make up the current line.
1248 # cur_len is just the length of all the chunks in cur_line.
1255 # cur_len is just the length of all the chunks in cur_line.
1249 cur_line = []
1256 cur_line = []
1250 cur_len = 0
1257 cur_len = 0
1251
1258
1252 # Figure out which static string will prefix this line.
1259 # Figure out which static string will prefix this line.
1253 if lines:
1260 if lines:
1254 indent = self.subsequent_indent
1261 indent = self.subsequent_indent
1255 else:
1262 else:
1256 indent = self.initial_indent
1263 indent = self.initial_indent
1257
1264
1258 # Maximum width for this line.
1265 # Maximum width for this line.
1259 width = self.width - len(indent)
1266 width = self.width - len(indent)
1260
1267
1261 # First chunk on line is whitespace -- drop it, unless this
1268 # First chunk on line is whitespace -- drop it, unless this
1262 # is the very beginning of the text (ie. no lines started yet).
1269 # is the very beginning of the text (ie. no lines started yet).
1263 if self.drop_whitespace and chunks[-1].strip() == '' and lines:
1270 if self.drop_whitespace and chunks[-1].strip() == '' and lines:
1264 del chunks[-1]
1271 del chunks[-1]
1265
1272
1266 while chunks:
1273 while chunks:
1267 l = colwidth(chunks[-1])
1274 l = colwidth(chunks[-1])
1268
1275
1269 # Can at least squeeze this chunk onto the current line.
1276 # Can at least squeeze this chunk onto the current line.
1270 if cur_len + l <= width:
1277 if cur_len + l <= width:
1271 cur_line.append(chunks.pop())
1278 cur_line.append(chunks.pop())
1272 cur_len += l
1279 cur_len += l
1273
1280
1274 # Nope, this line is full.
1281 # Nope, this line is full.
1275 else:
1282 else:
1276 break
1283 break
1277
1284
1278 # The current line is full, and the next chunk is too big to
1285 # The current line is full, and the next chunk is too big to
1279 # fit on *any* line (not just this one).
1286 # fit on *any* line (not just this one).
1280 if chunks and colwidth(chunks[-1]) > width:
1287 if chunks and colwidth(chunks[-1]) > width:
1281 self._handle_long_word(chunks, cur_line, cur_len, width)
1288 self._handle_long_word(chunks, cur_line, cur_len, width)
1282
1289
1283 # If the last chunk on this line is all whitespace, drop it.
1290 # If the last chunk on this line is all whitespace, drop it.
1284 if (self.drop_whitespace and
1291 if (self.drop_whitespace and
1285 cur_line and cur_line[-1].strip() == ''):
1292 cur_line and cur_line[-1].strip() == ''):
1286 del cur_line[-1]
1293 del cur_line[-1]
1287
1294
1288 # Convert current line back to a string and store it in list
1295 # Convert current line back to a string and store it in list
1289 # of all lines (return value).
1296 # of all lines (return value).
1290 if cur_line:
1297 if cur_line:
1291 lines.append(indent + ''.join(cur_line))
1298 lines.append(indent + ''.join(cur_line))
1292
1299
1293 return lines
1300 return lines
1294
1301
1295 global MBTextWrapper
1302 global MBTextWrapper
1296 MBTextWrapper = tw
1303 MBTextWrapper = tw
1297 return tw(**kwargs)
1304 return tw(**kwargs)
1298
1305
1299 def wrap(line, width, initindent='', hangindent=''):
1306 def wrap(line, width, initindent='', hangindent=''):
1300 maxindent = max(len(hangindent), len(initindent))
1307 maxindent = max(len(hangindent), len(initindent))
1301 if width <= maxindent:
1308 if width <= maxindent:
1302 # adjust for weird terminal size
1309 # adjust for weird terminal size
1303 width = max(78, maxindent + 1)
1310 width = max(78, maxindent + 1)
1304 line = line.decode(encoding.encoding, encoding.encodingmode)
1311 line = line.decode(encoding.encoding, encoding.encodingmode)
1305 initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
1312 initindent = initindent.decode(encoding.encoding, encoding.encodingmode)
1306 hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
1313 hangindent = hangindent.decode(encoding.encoding, encoding.encodingmode)
1307 wrapper = MBTextWrapper(width=width,
1314 wrapper = MBTextWrapper(width=width,
1308 initial_indent=initindent,
1315 initial_indent=initindent,
1309 subsequent_indent=hangindent)
1316 subsequent_indent=hangindent)
1310 return wrapper.fill(line).encode(encoding.encoding)
1317 return wrapper.fill(line).encode(encoding.encoding)
1311
1318
1312 def iterlines(iterator):
1319 def iterlines(iterator):
1313 for chunk in iterator:
1320 for chunk in iterator:
1314 for line in chunk.splitlines():
1321 for line in chunk.splitlines():
1315 yield line
1322 yield line
1316
1323
1317 def expandpath(path):
1324 def expandpath(path):
1318 return os.path.expanduser(os.path.expandvars(path))
1325 return os.path.expanduser(os.path.expandvars(path))
1319
1326
1320 def hgcmd():
1327 def hgcmd():
1321 """Return the command used to execute current hg
1328 """Return the command used to execute current hg
1322
1329
1323 This is different from hgexecutable() because on Windows we want
1330 This is different from hgexecutable() because on Windows we want
1324 to avoid things opening new shell windows like batch files, so we
1331 to avoid things opening new shell windows like batch files, so we
1325 get either the python call or current executable.
1332 get either the python call or current executable.
1326 """
1333 """
1327 if mainfrozen():
1334 if mainfrozen():
1328 return [sys.executable]
1335 return [sys.executable]
1329 return gethgcmd()
1336 return gethgcmd()
1330
1337
1331 def rundetached(args, condfn):
1338 def rundetached(args, condfn):
1332 """Execute the argument list in a detached process.
1339 """Execute the argument list in a detached process.
1333
1340
1334 condfn is a callable which is called repeatedly and should return
1341 condfn is a callable which is called repeatedly and should return
1335 True once the child process is known to have started successfully.
1342 True once the child process is known to have started successfully.
1336 At this point, the child process PID is returned. If the child
1343 At this point, the child process PID is returned. If the child
1337 process fails to start or finishes before condfn() evaluates to
1344 process fails to start or finishes before condfn() evaluates to
1338 True, return -1.
1345 True, return -1.
1339 """
1346 """
1340 # Windows case is easier because the child process is either
1347 # Windows case is easier because the child process is either
1341 # successfully starting and validating the condition or exiting
1348 # successfully starting and validating the condition or exiting
1342 # on failure. We just poll on its PID. On Unix, if the child
1349 # on failure. We just poll on its PID. On Unix, if the child
1343 # process fails to start, it will be left in a zombie state until
1350 # process fails to start, it will be left in a zombie state until
1344 # the parent wait on it, which we cannot do since we expect a long
1351 # the parent wait on it, which we cannot do since we expect a long
1345 # running process on success. Instead we listen for SIGCHLD telling
1352 # running process on success. Instead we listen for SIGCHLD telling
1346 # us our child process terminated.
1353 # us our child process terminated.
1347 terminated = set()
1354 terminated = set()
1348 def handler(signum, frame):
1355 def handler(signum, frame):
1349 terminated.add(os.wait())
1356 terminated.add(os.wait())
1350 prevhandler = None
1357 prevhandler = None
1351 SIGCHLD = getattr(signal, 'SIGCHLD', None)
1358 SIGCHLD = getattr(signal, 'SIGCHLD', None)
1352 if SIGCHLD is not None:
1359 if SIGCHLD is not None:
1353 prevhandler = signal.signal(SIGCHLD, handler)
1360 prevhandler = signal.signal(SIGCHLD, handler)
1354 try:
1361 try:
1355 pid = spawndetached(args)
1362 pid = spawndetached(args)
1356 while not condfn():
1363 while not condfn():
1357 if ((pid in terminated or not testpid(pid))
1364 if ((pid in terminated or not testpid(pid))
1358 and not condfn()):
1365 and not condfn()):
1359 return -1
1366 return -1
1360 time.sleep(0.1)
1367 time.sleep(0.1)
1361 return pid
1368 return pid
1362 finally:
1369 finally:
1363 if prevhandler is not None:
1370 if prevhandler is not None:
1364 signal.signal(signal.SIGCHLD, prevhandler)
1371 signal.signal(signal.SIGCHLD, prevhandler)
1365
1372
1366 try:
1373 try:
1367 any, all = any, all
1374 any, all = any, all
1368 except NameError:
1375 except NameError:
1369 def any(iterable):
1376 def any(iterable):
1370 for i in iterable:
1377 for i in iterable:
1371 if i:
1378 if i:
1372 return True
1379 return True
1373 return False
1380 return False
1374
1381
1375 def all(iterable):
1382 def all(iterable):
1376 for i in iterable:
1383 for i in iterable:
1377 if not i:
1384 if not i:
1378 return False
1385 return False
1379 return True
1386 return True
1380
1387
1381 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1388 def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
1382 """Return the result of interpolating items in the mapping into string s.
1389 """Return the result of interpolating items in the mapping into string s.
1383
1390
1384 prefix is a single character string, or a two character string with
1391 prefix is a single character string, or a two character string with
1385 a backslash as the first character if the prefix needs to be escaped in
1392 a backslash as the first character if the prefix needs to be escaped in
1386 a regular expression.
1393 a regular expression.
1387
1394
1388 fn is an optional function that will be applied to the replacement text
1395 fn is an optional function that will be applied to the replacement text
1389 just before replacement.
1396 just before replacement.
1390
1397
1391 escape_prefix is an optional flag that allows using doubled prefix for
1398 escape_prefix is an optional flag that allows using doubled prefix for
1392 its escaping.
1399 its escaping.
1393 """
1400 """
1394 fn = fn or (lambda s: s)
1401 fn = fn or (lambda s: s)
1395 patterns = '|'.join(mapping.keys())
1402 patterns = '|'.join(mapping.keys())
1396 if escape_prefix:
1403 if escape_prefix:
1397 patterns += '|' + prefix
1404 patterns += '|' + prefix
1398 if len(prefix) > 1:
1405 if len(prefix) > 1:
1399 prefix_char = prefix[1:]
1406 prefix_char = prefix[1:]
1400 else:
1407 else:
1401 prefix_char = prefix
1408 prefix_char = prefix
1402 mapping[prefix_char] = prefix_char
1409 mapping[prefix_char] = prefix_char
1403 r = re.compile(r'%s(%s)' % (prefix, patterns))
1410 r = re.compile(r'%s(%s)' % (prefix, patterns))
1404 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1411 return r.sub(lambda x: fn(mapping[x.group()[1:]]), s)
1405
1412
1406 def getport(port):
1413 def getport(port):
1407 """Return the port for a given network service.
1414 """Return the port for a given network service.
1408
1415
1409 If port is an integer, it's returned as is. If it's a string, it's
1416 If port is an integer, it's returned as is. If it's a string, it's
1410 looked up using socket.getservbyname(). If there's no matching
1417 looked up using socket.getservbyname(). If there's no matching
1411 service, util.Abort is raised.
1418 service, util.Abort is raised.
1412 """
1419 """
1413 try:
1420 try:
1414 return int(port)
1421 return int(port)
1415 except ValueError:
1422 except ValueError:
1416 pass
1423 pass
1417
1424
1418 try:
1425 try:
1419 return socket.getservbyname(port)
1426 return socket.getservbyname(port)
1420 except socket.error:
1427 except socket.error:
1421 raise Abort(_("no port number associated with service '%s'") % port)
1428 raise Abort(_("no port number associated with service '%s'") % port)
1422
1429
1423 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1430 _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, 'always': True,
1424 '0': False, 'no': False, 'false': False, 'off': False,
1431 '0': False, 'no': False, 'false': False, 'off': False,
1425 'never': False}
1432 'never': False}
1426
1433
1427 def parsebool(s):
1434 def parsebool(s):
1428 """Parse s into a boolean.
1435 """Parse s into a boolean.
1429
1436
1430 If s is not a valid boolean, returns None.
1437 If s is not a valid boolean, returns None.
1431 """
1438 """
1432 return _booleans.get(s.lower(), None)
1439 return _booleans.get(s.lower(), None)
1433
1440
1434 _hexdig = '0123456789ABCDEFabcdef'
1441 _hexdig = '0123456789ABCDEFabcdef'
1435 _hextochr = dict((a + b, chr(int(a + b, 16)))
1442 _hextochr = dict((a + b, chr(int(a + b, 16)))
1436 for a in _hexdig for b in _hexdig)
1443 for a in _hexdig for b in _hexdig)
1437
1444
1438 def _urlunquote(s):
1445 def _urlunquote(s):
1439 """unquote('abc%20def') -> 'abc def'."""
1446 """unquote('abc%20def') -> 'abc def'."""
1440 res = s.split('%')
1447 res = s.split('%')
1441 # fastpath
1448 # fastpath
1442 if len(res) == 1:
1449 if len(res) == 1:
1443 return s
1450 return s
1444 s = res[0]
1451 s = res[0]
1445 for item in res[1:]:
1452 for item in res[1:]:
1446 try:
1453 try:
1447 s += _hextochr[item[:2]] + item[2:]
1454 s += _hextochr[item[:2]] + item[2:]
1448 except KeyError:
1455 except KeyError:
1449 s += '%' + item
1456 s += '%' + item
1450 except UnicodeDecodeError:
1457 except UnicodeDecodeError:
1451 s += unichr(int(item[:2], 16)) + item[2:]
1458 s += unichr(int(item[:2], 16)) + item[2:]
1452 return s
1459 return s
1453
1460
1454 class url(object):
1461 class url(object):
1455 r"""Reliable URL parser.
1462 r"""Reliable URL parser.
1456
1463
1457 This parses URLs and provides attributes for the following
1464 This parses URLs and provides attributes for the following
1458 components:
1465 components:
1459
1466
1460 <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
1467 <scheme>://<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
1461
1468
1462 Missing components are set to None. The only exception is
1469 Missing components are set to None. The only exception is
1463 fragment, which is set to '' if present but empty.
1470 fragment, which is set to '' if present but empty.
1464
1471
1465 If parsefragment is False, fragment is included in query. If
1472 If parsefragment is False, fragment is included in query. If
1466 parsequery is False, query is included in path. If both are
1473 parsequery is False, query is included in path. If both are
1467 False, both fragment and query are included in path.
1474 False, both fragment and query are included in path.
1468
1475
1469 See http://www.ietf.org/rfc/rfc2396.txt for more information.
1476 See http://www.ietf.org/rfc/rfc2396.txt for more information.
1470
1477
1471 Note that for backward compatibility reasons, bundle URLs do not
1478 Note that for backward compatibility reasons, bundle URLs do not
1472 take host names. That means 'bundle://../' has a path of '../'.
1479 take host names. That means 'bundle://../' has a path of '../'.
1473
1480
1474 Examples:
1481 Examples:
1475
1482
1476 >>> url('http://www.ietf.org/rfc/rfc2396.txt')
1483 >>> url('http://www.ietf.org/rfc/rfc2396.txt')
1477 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
1484 <url scheme: 'http', host: 'www.ietf.org', path: 'rfc/rfc2396.txt'>
1478 >>> url('ssh://[::1]:2200//home/joe/repo')
1485 >>> url('ssh://[::1]:2200//home/joe/repo')
1479 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
1486 <url scheme: 'ssh', host: '[::1]', port: '2200', path: '/home/joe/repo'>
1480 >>> url('file:///home/joe/repo')
1487 >>> url('file:///home/joe/repo')
1481 <url scheme: 'file', path: '/home/joe/repo'>
1488 <url scheme: 'file', path: '/home/joe/repo'>
1482 >>> url('file:///c:/temp/foo/')
1489 >>> url('file:///c:/temp/foo/')
1483 <url scheme: 'file', path: 'c:/temp/foo/'>
1490 <url scheme: 'file', path: 'c:/temp/foo/'>
1484 >>> url('bundle:foo')
1491 >>> url('bundle:foo')
1485 <url scheme: 'bundle', path: 'foo'>
1492 <url scheme: 'bundle', path: 'foo'>
1486 >>> url('bundle://../foo')
1493 >>> url('bundle://../foo')
1487 <url scheme: 'bundle', path: '../foo'>
1494 <url scheme: 'bundle', path: '../foo'>
1488 >>> url(r'c:\foo\bar')
1495 >>> url(r'c:\foo\bar')
1489 <url path: 'c:\\foo\\bar'>
1496 <url path: 'c:\\foo\\bar'>
1490 >>> url(r'\\blah\blah\blah')
1497 >>> url(r'\\blah\blah\blah')
1491 <url path: '\\\\blah\\blah\\blah'>
1498 <url path: '\\\\blah\\blah\\blah'>
1492 >>> url(r'\\blah\blah\blah#baz')
1499 >>> url(r'\\blah\blah\blah#baz')
1493 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
1500 <url path: '\\\\blah\\blah\\blah', fragment: 'baz'>
1494
1501
1495 Authentication credentials:
1502 Authentication credentials:
1496
1503
1497 >>> url('ssh://joe:xyz@x/repo')
1504 >>> url('ssh://joe:xyz@x/repo')
1498 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
1505 <url scheme: 'ssh', user: 'joe', passwd: 'xyz', host: 'x', path: 'repo'>
1499 >>> url('ssh://joe@x/repo')
1506 >>> url('ssh://joe@x/repo')
1500 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
1507 <url scheme: 'ssh', user: 'joe', host: 'x', path: 'repo'>
1501
1508
1502 Query strings and fragments:
1509 Query strings and fragments:
1503
1510
1504 >>> url('http://host/a?b#c')
1511 >>> url('http://host/a?b#c')
1505 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
1512 <url scheme: 'http', host: 'host', path: 'a', query: 'b', fragment: 'c'>
1506 >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
1513 >>> url('http://host/a?b#c', parsequery=False, parsefragment=False)
1507 <url scheme: 'http', host: 'host', path: 'a?b#c'>
1514 <url scheme: 'http', host: 'host', path: 'a?b#c'>
1508 """
1515 """
1509
1516
1510 _safechars = "!~*'()+"
1517 _safechars = "!~*'()+"
1511 _safepchars = "/!~*'()+:"
1518 _safepchars = "/!~*'()+:"
1512 _matchscheme = re.compile(r'^[a-zA-Z0-9+.\-]+:').match
1519 _matchscheme = re.compile(r'^[a-zA-Z0-9+.\-]+:').match
1513
1520
1514 def __init__(self, path, parsequery=True, parsefragment=True):
1521 def __init__(self, path, parsequery=True, parsefragment=True):
1515 # We slowly chomp away at path until we have only the path left
1522 # We slowly chomp away at path until we have only the path left
1516 self.scheme = self.user = self.passwd = self.host = None
1523 self.scheme = self.user = self.passwd = self.host = None
1517 self.port = self.path = self.query = self.fragment = None
1524 self.port = self.path = self.query = self.fragment = None
1518 self._localpath = True
1525 self._localpath = True
1519 self._hostport = ''
1526 self._hostport = ''
1520 self._origpath = path
1527 self._origpath = path
1521
1528
1522 if parsefragment and '#' in path:
1529 if parsefragment and '#' in path:
1523 path, self.fragment = path.split('#', 1)
1530 path, self.fragment = path.split('#', 1)
1524 if not path:
1531 if not path:
1525 path = None
1532 path = None
1526
1533
1527 # special case for Windows drive letters and UNC paths
1534 # special case for Windows drive letters and UNC paths
1528 if hasdriveletter(path) or path.startswith(r'\\'):
1535 if hasdriveletter(path) or path.startswith(r'\\'):
1529 self.path = path
1536 self.path = path
1530 return
1537 return
1531
1538
1532 # For compatibility reasons, we can't handle bundle paths as
1539 # For compatibility reasons, we can't handle bundle paths as
1533 # normal URLS
1540 # normal URLS
1534 if path.startswith('bundle:'):
1541 if path.startswith('bundle:'):
1535 self.scheme = 'bundle'
1542 self.scheme = 'bundle'
1536 path = path[7:]
1543 path = path[7:]
1537 if path.startswith('//'):
1544 if path.startswith('//'):
1538 path = path[2:]
1545 path = path[2:]
1539 self.path = path
1546 self.path = path
1540 return
1547 return
1541
1548
1542 if self._matchscheme(path):
1549 if self._matchscheme(path):
1543 parts = path.split(':', 1)
1550 parts = path.split(':', 1)
1544 if parts[0]:
1551 if parts[0]:
1545 self.scheme, path = parts
1552 self.scheme, path = parts
1546 self._localpath = False
1553 self._localpath = False
1547
1554
1548 if not path:
1555 if not path:
1549 path = None
1556 path = None
1550 if self._localpath:
1557 if self._localpath:
1551 self.path = ''
1558 self.path = ''
1552 return
1559 return
1553 else:
1560 else:
1554 if self._localpath:
1561 if self._localpath:
1555 self.path = path
1562 self.path = path
1556 return
1563 return
1557
1564
1558 if parsequery and '?' in path:
1565 if parsequery and '?' in path:
1559 path, self.query = path.split('?', 1)
1566 path, self.query = path.split('?', 1)
1560 if not path:
1567 if not path:
1561 path = None
1568 path = None
1562 if not self.query:
1569 if not self.query:
1563 self.query = None
1570 self.query = None
1564
1571
1565 # // is required to specify a host/authority
1572 # // is required to specify a host/authority
1566 if path and path.startswith('//'):
1573 if path and path.startswith('//'):
1567 parts = path[2:].split('/', 1)
1574 parts = path[2:].split('/', 1)
1568 if len(parts) > 1:
1575 if len(parts) > 1:
1569 self.host, path = parts
1576 self.host, path = parts
1570 path = path
1577 path = path
1571 else:
1578 else:
1572 self.host = parts[0]
1579 self.host = parts[0]
1573 path = None
1580 path = None
1574 if not self.host:
1581 if not self.host:
1575 self.host = None
1582 self.host = None
1576 # path of file:///d is /d
1583 # path of file:///d is /d
1577 # path of file:///d:/ is d:/, not /d:/
1584 # path of file:///d:/ is d:/, not /d:/
1578 if path and not hasdriveletter(path):
1585 if path and not hasdriveletter(path):
1579 path = '/' + path
1586 path = '/' + path
1580
1587
1581 if self.host and '@' in self.host:
1588 if self.host and '@' in self.host:
1582 self.user, self.host = self.host.rsplit('@', 1)
1589 self.user, self.host = self.host.rsplit('@', 1)
1583 if ':' in self.user:
1590 if ':' in self.user:
1584 self.user, self.passwd = self.user.split(':', 1)
1591 self.user, self.passwd = self.user.split(':', 1)
1585 if not self.host:
1592 if not self.host:
1586 self.host = None
1593 self.host = None
1587
1594
1588 # Don't split on colons in IPv6 addresses without ports
1595 # Don't split on colons in IPv6 addresses without ports
1589 if (self.host and ':' in self.host and
1596 if (self.host and ':' in self.host and
1590 not (self.host.startswith('[') and self.host.endswith(']'))):
1597 not (self.host.startswith('[') and self.host.endswith(']'))):
1591 self._hostport = self.host
1598 self._hostport = self.host
1592 self.host, self.port = self.host.rsplit(':', 1)
1599 self.host, self.port = self.host.rsplit(':', 1)
1593 if not self.host:
1600 if not self.host:
1594 self.host = None
1601 self.host = None
1595
1602
1596 if (self.host and self.scheme == 'file' and
1603 if (self.host and self.scheme == 'file' and
1597 self.host not in ('localhost', '127.0.0.1', '[::1]')):
1604 self.host not in ('localhost', '127.0.0.1', '[::1]')):
1598 raise Abort(_('file:// URLs can only refer to localhost'))
1605 raise Abort(_('file:// URLs can only refer to localhost'))
1599
1606
1600 self.path = path
1607 self.path = path
1601
1608
1602 # leave the query string escaped
1609 # leave the query string escaped
1603 for a in ('user', 'passwd', 'host', 'port',
1610 for a in ('user', 'passwd', 'host', 'port',
1604 'path', 'fragment'):
1611 'path', 'fragment'):
1605 v = getattr(self, a)
1612 v = getattr(self, a)
1606 if v is not None:
1613 if v is not None:
1607 setattr(self, a, _urlunquote(v))
1614 setattr(self, a, _urlunquote(v))
1608
1615
1609 def __repr__(self):
1616 def __repr__(self):
1610 attrs = []
1617 attrs = []
1611 for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
1618 for a in ('scheme', 'user', 'passwd', 'host', 'port', 'path',
1612 'query', 'fragment'):
1619 'query', 'fragment'):
1613 v = getattr(self, a)
1620 v = getattr(self, a)
1614 if v is not None:
1621 if v is not None:
1615 attrs.append('%s: %r' % (a, v))
1622 attrs.append('%s: %r' % (a, v))
1616 return '<url %s>' % ', '.join(attrs)
1623 return '<url %s>' % ', '.join(attrs)
1617
1624
1618 def __str__(self):
1625 def __str__(self):
1619 r"""Join the URL's components back into a URL string.
1626 r"""Join the URL's components back into a URL string.
1620
1627
1621 Examples:
1628 Examples:
1622
1629
1623 >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
1630 >>> str(url('http://user:pw@host:80/c:/bob?fo:oo#ba:ar'))
1624 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
1631 'http://user:pw@host:80/c:/bob?fo:oo#ba:ar'
1625 >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
1632 >>> str(url('http://user:pw@host:80/?foo=bar&baz=42'))
1626 'http://user:pw@host:80/?foo=bar&baz=42'
1633 'http://user:pw@host:80/?foo=bar&baz=42'
1627 >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
1634 >>> str(url('http://user:pw@host:80/?foo=bar%3dbaz'))
1628 'http://user:pw@host:80/?foo=bar%3dbaz'
1635 'http://user:pw@host:80/?foo=bar%3dbaz'
1629 >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
1636 >>> str(url('ssh://user:pw@[::1]:2200//home/joe#'))
1630 'ssh://user:pw@[::1]:2200//home/joe#'
1637 'ssh://user:pw@[::1]:2200//home/joe#'
1631 >>> str(url('http://localhost:80//'))
1638 >>> str(url('http://localhost:80//'))
1632 'http://localhost:80//'
1639 'http://localhost:80//'
1633 >>> str(url('http://localhost:80/'))
1640 >>> str(url('http://localhost:80/'))
1634 'http://localhost:80/'
1641 'http://localhost:80/'
1635 >>> str(url('http://localhost:80'))
1642 >>> str(url('http://localhost:80'))
1636 'http://localhost:80/'
1643 'http://localhost:80/'
1637 >>> str(url('bundle:foo'))
1644 >>> str(url('bundle:foo'))
1638 'bundle:foo'
1645 'bundle:foo'
1639 >>> str(url('bundle://../foo'))
1646 >>> str(url('bundle://../foo'))
1640 'bundle:../foo'
1647 'bundle:../foo'
1641 >>> str(url('path'))
1648 >>> str(url('path'))
1642 'path'
1649 'path'
1643 >>> str(url('file:///tmp/foo/bar'))
1650 >>> str(url('file:///tmp/foo/bar'))
1644 'file:///tmp/foo/bar'
1651 'file:///tmp/foo/bar'
1645 >>> str(url('file:///c:/tmp/foo/bar'))
1652 >>> str(url('file:///c:/tmp/foo/bar'))
1646 'file:///c:/tmp/foo/bar'
1653 'file:///c:/tmp/foo/bar'
1647 >>> print url(r'bundle:foo\bar')
1654 >>> print url(r'bundle:foo\bar')
1648 bundle:foo\bar
1655 bundle:foo\bar
1649 """
1656 """
1650 if self._localpath:
1657 if self._localpath:
1651 s = self.path
1658 s = self.path
1652 if self.scheme == 'bundle':
1659 if self.scheme == 'bundle':
1653 s = 'bundle:' + s
1660 s = 'bundle:' + s
1654 if self.fragment:
1661 if self.fragment:
1655 s += '#' + self.fragment
1662 s += '#' + self.fragment
1656 return s
1663 return s
1657
1664
1658 s = self.scheme + ':'
1665 s = self.scheme + ':'
1659 if self.user or self.passwd or self.host:
1666 if self.user or self.passwd or self.host:
1660 s += '//'
1667 s += '//'
1661 elif self.scheme and (not self.path or self.path.startswith('/')
1668 elif self.scheme and (not self.path or self.path.startswith('/')
1662 or hasdriveletter(self.path)):
1669 or hasdriveletter(self.path)):
1663 s += '//'
1670 s += '//'
1664 if hasdriveletter(self.path):
1671 if hasdriveletter(self.path):
1665 s += '/'
1672 s += '/'
1666 if self.user:
1673 if self.user:
1667 s += urllib.quote(self.user, safe=self._safechars)
1674 s += urllib.quote(self.user, safe=self._safechars)
1668 if self.passwd:
1675 if self.passwd:
1669 s += ':' + urllib.quote(self.passwd, safe=self._safechars)
1676 s += ':' + urllib.quote(self.passwd, safe=self._safechars)
1670 if self.user or self.passwd:
1677 if self.user or self.passwd:
1671 s += '@'
1678 s += '@'
1672 if self.host:
1679 if self.host:
1673 if not (self.host.startswith('[') and self.host.endswith(']')):
1680 if not (self.host.startswith('[') and self.host.endswith(']')):
1674 s += urllib.quote(self.host)
1681 s += urllib.quote(self.host)
1675 else:
1682 else:
1676 s += self.host
1683 s += self.host
1677 if self.port:
1684 if self.port:
1678 s += ':' + urllib.quote(self.port)
1685 s += ':' + urllib.quote(self.port)
1679 if self.host:
1686 if self.host:
1680 s += '/'
1687 s += '/'
1681 if self.path:
1688 if self.path:
1682 # TODO: similar to the query string, we should not unescape the
1689 # TODO: similar to the query string, we should not unescape the
1683 # path when we store it, the path might contain '%2f' = '/',
1690 # path when we store it, the path might contain '%2f' = '/',
1684 # which we should *not* escape.
1691 # which we should *not* escape.
1685 s += urllib.quote(self.path, safe=self._safepchars)
1692 s += urllib.quote(self.path, safe=self._safepchars)
1686 if self.query:
1693 if self.query:
1687 # we store the query in escaped form.
1694 # we store the query in escaped form.
1688 s += '?' + self.query
1695 s += '?' + self.query
1689 if self.fragment is not None:
1696 if self.fragment is not None:
1690 s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
1697 s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
1691 return s
1698 return s
1692
1699
1693 def authinfo(self):
1700 def authinfo(self):
1694 user, passwd = self.user, self.passwd
1701 user, passwd = self.user, self.passwd
1695 try:
1702 try:
1696 self.user, self.passwd = None, None
1703 self.user, self.passwd = None, None
1697 s = str(self)
1704 s = str(self)
1698 finally:
1705 finally:
1699 self.user, self.passwd = user, passwd
1706 self.user, self.passwd = user, passwd
1700 if not self.user:
1707 if not self.user:
1701 return (s, None)
1708 return (s, None)
1702 # authinfo[1] is passed to urllib2 password manager, and its
1709 # authinfo[1] is passed to urllib2 password manager, and its
1703 # URIs must not contain credentials. The host is passed in the
1710 # URIs must not contain credentials. The host is passed in the
1704 # URIs list because Python < 2.4.3 uses only that to search for
1711 # URIs list because Python < 2.4.3 uses only that to search for
1705 # a password.
1712 # a password.
1706 return (s, (None, (s, self.host),
1713 return (s, (None, (s, self.host),
1707 self.user, self.passwd or ''))
1714 self.user, self.passwd or ''))
1708
1715
1709 def isabs(self):
1716 def isabs(self):
1710 if self.scheme and self.scheme != 'file':
1717 if self.scheme and self.scheme != 'file':
1711 return True # remote URL
1718 return True # remote URL
1712 if hasdriveletter(self.path):
1719 if hasdriveletter(self.path):
1713 return True # absolute for our purposes - can't be joined()
1720 return True # absolute for our purposes - can't be joined()
1714 if self.path.startswith(r'\\'):
1721 if self.path.startswith(r'\\'):
1715 return True # Windows UNC path
1722 return True # Windows UNC path
1716 if self.path.startswith('/'):
1723 if self.path.startswith('/'):
1717 return True # POSIX-style
1724 return True # POSIX-style
1718 return False
1725 return False
1719
1726
1720 def localpath(self):
1727 def localpath(self):
1721 if self.scheme == 'file' or self.scheme == 'bundle':
1728 if self.scheme == 'file' or self.scheme == 'bundle':
1722 path = self.path or '/'
1729 path = self.path or '/'
1723 # For Windows, we need to promote hosts containing drive
1730 # For Windows, we need to promote hosts containing drive
1724 # letters to paths with drive letters.
1731 # letters to paths with drive letters.
1725 if hasdriveletter(self._hostport):
1732 if hasdriveletter(self._hostport):
1726 path = self._hostport + '/' + self.path
1733 path = self._hostport + '/' + self.path
1727 elif (self.host is not None and self.path
1734 elif (self.host is not None and self.path
1728 and not hasdriveletter(path)):
1735 and not hasdriveletter(path)):
1729 path = '/' + path
1736 path = '/' + path
1730 return path
1737 return path
1731 return self._origpath
1738 return self._origpath
1732
1739
1733 def hasscheme(path):
1740 def hasscheme(path):
1734 return bool(url(path).scheme)
1741 return bool(url(path).scheme)
1735
1742
1736 def hasdriveletter(path):
1743 def hasdriveletter(path):
1737 return path and path[1:2] == ':' and path[0:1].isalpha()
1744 return path and path[1:2] == ':' and path[0:1].isalpha()
1738
1745
1739 def urllocalpath(path):
1746 def urllocalpath(path):
1740 return url(path, parsequery=False, parsefragment=False).localpath()
1747 return url(path, parsequery=False, parsefragment=False).localpath()
1741
1748
1742 def hidepassword(u):
1749 def hidepassword(u):
1743 '''hide user credential in a url string'''
1750 '''hide user credential in a url string'''
1744 u = url(u)
1751 u = url(u)
1745 if u.passwd:
1752 if u.passwd:
1746 u.passwd = '***'
1753 u.passwd = '***'
1747 return str(u)
1754 return str(u)
1748
1755
1749 def removeauth(u):
1756 def removeauth(u):
1750 '''remove all authentication information from a url string'''
1757 '''remove all authentication information from a url string'''
1751 u = url(u)
1758 u = url(u)
1752 u.user = u.passwd = None
1759 u.user = u.passwd = None
1753 return str(u)
1760 return str(u)
1754
1761
1755 def isatty(fd):
1762 def isatty(fd):
1756 try:
1763 try:
1757 return fd.isatty()
1764 return fd.isatty()
1758 except AttributeError:
1765 except AttributeError:
1759 return False
1766 return False
@@ -1,489 +1,495 b''
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 def b(s):
12 def b(s):
13 '''A helper function to emulate 2.6+ bytes literals using string
13 '''A helper function to emulate 2.6+ bytes literals using string
14 literals.'''
14 literals.'''
15 return s.encode('latin1')
15 return s.encode('latin1')
16 else:
16 else:
17 def b(s):
17 def b(s):
18 '''A helper function to emulate 2.6+ bytes literals using string
18 '''A helper function to emulate 2.6+ bytes literals using string
19 literals.'''
19 literals.'''
20 return s
20 return s
21
21
22 # Solaris Python packaging brain damage
22 # Solaris Python packaging brain damage
23 try:
23 try:
24 import hashlib
24 import hashlib
25 sha = hashlib.sha1()
25 sha = hashlib.sha1()
26 except:
26 except:
27 try:
27 try:
28 import sha
28 import sha
29 except:
29 except:
30 raise SystemExit(
30 raise SystemExit(
31 "Couldn't import standard hashlib (incomplete Python install).")
31 "Couldn't import standard hashlib (incomplete Python install).")
32
32
33 try:
33 try:
34 import zlib
34 import zlib
35 except:
35 except:
36 raise SystemExit(
36 raise SystemExit(
37 "Couldn't import standard zlib (incomplete Python install).")
37 "Couldn't import standard zlib (incomplete Python install).")
38
38
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
39 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
40 isironpython = False
40 isironpython = False
41 try:
41 try:
42 isironpython = platform.python_implementation().lower().find("ironpython") != -1
42 isironpython = platform.python_implementation().lower().find("ironpython") != -1
43 except:
43 except:
44 pass
44 pass
45
45
46 if isironpython:
46 if isironpython:
47 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
47 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
48 else:
48 else:
49 try:
49 try:
50 import bz2
50 import bz2
51 except:
51 except:
52 raise SystemExit(
52 raise SystemExit(
53 "Couldn't import standard bz2 (incomplete Python install).")
53 "Couldn't import standard bz2 (incomplete Python install).")
54
54
55 import os, subprocess, time
55 import os, subprocess, time
56 import shutil
56 import shutil
57 import tempfile
57 import tempfile
58 from distutils import log
58 from distutils import log
59 from distutils.core import setup, Command, Extension
59 from distutils.core import setup, Command, Extension
60 from distutils.dist import Distribution
60 from distutils.dist import Distribution
61 from distutils.command.build import build
61 from distutils.command.build import build
62 from distutils.command.build_ext import build_ext
62 from distutils.command.build_ext import build_ext
63 from distutils.command.build_py import build_py
63 from distutils.command.build_py import build_py
64 from distutils.command.install_scripts import install_scripts
64 from distutils.command.install_scripts import install_scripts
65 from distutils.spawn import spawn, find_executable
65 from distutils.spawn import spawn, find_executable
66 from distutils.ccompiler import new_compiler
66 from distutils.ccompiler import new_compiler
67 from distutils.errors import CCompilerError, DistutilsExecError
67 from distutils.errors import CCompilerError, DistutilsExecError
68 from distutils.sysconfig import get_python_inc
68 from distutils.sysconfig import get_python_inc
69 from distutils.version import StrictVersion
69 from distutils.version import StrictVersion
70
70
71 convert2to3 = '--c2to3' in sys.argv
71 convert2to3 = '--c2to3' in sys.argv
72 if convert2to3:
72 if convert2to3:
73 try:
73 try:
74 from distutils.command.build_py import build_py_2to3 as build_py
74 from distutils.command.build_py import build_py_2to3 as build_py
75 from lib2to3.refactor import get_fixers_from_package as getfixers
75 from lib2to3.refactor import get_fixers_from_package as getfixers
76 except ImportError:
76 except ImportError:
77 if sys.version_info[0] < 3:
77 if sys.version_info[0] < 3:
78 raise SystemExit("--c2to3 is only compatible with python3.")
78 raise SystemExit("--c2to3 is only compatible with python3.")
79 raise
79 raise
80 sys.path.append('contrib')
80 sys.path.append('contrib')
81 elif sys.version_info[0] >= 3:
81 elif sys.version_info[0] >= 3:
82 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
82 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
83
83
84 scripts = ['hg']
84 scripts = ['hg']
85 if os.name == 'nt':
85 if os.name == 'nt':
86 scripts.append('contrib/win32/hg.bat')
86 scripts.append('contrib/win32/hg.bat')
87
87
88 # simplified version of distutils.ccompiler.CCompiler.has_function
88 # simplified version of distutils.ccompiler.CCompiler.has_function
89 # that actually removes its temporary files.
89 # that actually removes its temporary files.
90 def hasfunction(cc, funcname):
90 def hasfunction(cc, funcname):
91 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
91 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
92 devnull = oldstderr = None
92 devnull = oldstderr = None
93 try:
93 try:
94 try:
94 try:
95 fname = os.path.join(tmpdir, 'funcname.c')
95 fname = os.path.join(tmpdir, 'funcname.c')
96 f = open(fname, 'w')
96 f = open(fname, 'w')
97 f.write('int main(void) {\n')
97 f.write('int main(void) {\n')
98 f.write(' %s();\n' % funcname)
98 f.write(' %s();\n' % funcname)
99 f.write('}\n')
99 f.write('}\n')
100 f.close()
100 f.close()
101 # Redirect stderr to /dev/null to hide any error messages
101 # Redirect stderr to /dev/null to hide any error messages
102 # from the compiler.
102 # from the compiler.
103 # This will have to be changed if we ever have to check
103 # This will have to be changed if we ever have to check
104 # for a function on Windows.
104 # for a function on Windows.
105 devnull = open('/dev/null', 'w')
105 devnull = open('/dev/null', 'w')
106 oldstderr = os.dup(sys.stderr.fileno())
106 oldstderr = os.dup(sys.stderr.fileno())
107 os.dup2(devnull.fileno(), sys.stderr.fileno())
107 os.dup2(devnull.fileno(), sys.stderr.fileno())
108 objects = cc.compile([fname], output_dir=tmpdir)
108 objects = cc.compile([fname], output_dir=tmpdir)
109 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
109 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
110 except:
110 except:
111 return False
111 return False
112 return True
112 return True
113 finally:
113 finally:
114 if oldstderr is not None:
114 if oldstderr is not None:
115 os.dup2(oldstderr, sys.stderr.fileno())
115 os.dup2(oldstderr, sys.stderr.fileno())
116 if devnull is not None:
116 if devnull is not None:
117 devnull.close()
117 devnull.close()
118 shutil.rmtree(tmpdir)
118 shutil.rmtree(tmpdir)
119
119
120 # py2exe needs to be installed to work
120 # py2exe needs to be installed to work
121 try:
121 try:
122 import py2exe
122 import py2exe
123 py2exeloaded = True
123 py2exeloaded = True
124 # import py2exe's patched Distribution class
124 # import py2exe's patched Distribution class
125 from distutils.core import Distribution
125 from distutils.core import Distribution
126 except ImportError:
126 except ImportError:
127 py2exeloaded = False
127 py2exeloaded = False
128
128
129 def runcmd(cmd, env):
129 def runcmd(cmd, env):
130 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
130 if sys.platform == 'plan9':
131 stderr=subprocess.PIPE, env=env)
131 # subprocess kludge to work around issues in half-baked Python
132 out, err = p.communicate()
132 # ports, notably bichued/python:
133 return out, err
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 def runhg(cmd, env):
141 def runhg(cmd, env):
136 out, err = runcmd(cmd, env)
142 out, err = runcmd(cmd, env)
137 # If root is executing setup.py, but the repository is owned by
143 # If root is executing setup.py, but the repository is owned by
138 # another user (as in "sudo python setup.py install") we will get
144 # another user (as in "sudo python setup.py install") we will get
139 # trust warnings since the .hg/hgrc file is untrusted. That is
145 # trust warnings since the .hg/hgrc file is untrusted. That is
140 # fine, we don't want to load it anyway. Python may warn about
146 # fine, we don't want to load it anyway. Python may warn about
141 # a missing __init__.py in mercurial/locale, we also ignore that.
147 # a missing __init__.py in mercurial/locale, we also ignore that.
142 err = [e for e in err.splitlines()
148 err = [e for e in err.splitlines()
143 if not e.startswith(b('Not trusting file')) \
149 if not e.startswith(b('Not trusting file')) \
144 and not e.startswith(b('warning: Not importing'))]
150 and not e.startswith(b('warning: Not importing'))]
145 if err:
151 if err:
146 return ''
152 return ''
147 return out
153 return out
148
154
149 version = ''
155 version = ''
150
156
151 # Execute hg out of this directory with a custom environment which
157 # Execute hg out of this directory with a custom environment which
152 # includes the pure Python modules in mercurial/pure. We also take
158 # includes the pure Python modules in mercurial/pure. We also take
153 # care to not use any hgrc files and do no localization.
159 # care to not use any hgrc files and do no localization.
154 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
160 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
155 env = {'PYTHONPATH': os.pathsep.join(pypath),
161 env = {'PYTHONPATH': os.pathsep.join(pypath),
156 'HGRCPATH': '',
162 'HGRCPATH': '',
157 'LANGUAGE': 'C'}
163 'LANGUAGE': 'C'}
158 if 'LD_LIBRARY_PATH' in os.environ:
164 if 'LD_LIBRARY_PATH' in os.environ:
159 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
165 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
160 if 'SystemRoot' in os.environ:
166 if 'SystemRoot' in os.environ:
161 # Copy SystemRoot into the custom environment for Python 2.6
167 # Copy SystemRoot into the custom environment for Python 2.6
162 # under Windows. Otherwise, the subprocess will fail with
168 # under Windows. Otherwise, the subprocess will fail with
163 # error 0xc0150004. See: http://bugs.python.org/issue3440
169 # error 0xc0150004. See: http://bugs.python.org/issue3440
164 env['SystemRoot'] = os.environ['SystemRoot']
170 env['SystemRoot'] = os.environ['SystemRoot']
165
171
166 if os.path.isdir('.hg'):
172 if os.path.isdir('.hg'):
167 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
173 cmd = [sys.executable, 'hg', 'id', '-i', '-t']
168 l = runhg(cmd, env).split()
174 l = runhg(cmd, env).split()
169 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
175 while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags
170 l.pop()
176 l.pop()
171 if len(l) > 1: # tag found
177 if len(l) > 1: # tag found
172 version = l[-1]
178 version = l[-1]
173 if l[0].endswith('+'): # propagate the dirty status to the tag
179 if l[0].endswith('+'): # propagate the dirty status to the tag
174 version += '+'
180 version += '+'
175 elif len(l) == 1: # no tag found
181 elif len(l) == 1: # no tag found
176 cmd = [sys.executable, 'hg', 'parents', '--template',
182 cmd = [sys.executable, 'hg', 'parents', '--template',
177 '{latesttag}+{latesttagdistance}-']
183 '{latesttag}+{latesttagdistance}-']
178 version = runhg(cmd, env) + l[0]
184 version = runhg(cmd, env) + l[0]
179 if version.endswith('+'):
185 if version.endswith('+'):
180 version += time.strftime('%Y%m%d')
186 version += time.strftime('%Y%m%d')
181 elif os.path.exists('.hg_archival.txt'):
187 elif os.path.exists('.hg_archival.txt'):
182 kw = dict([[t.strip() for t in l.split(':', 1)]
188 kw = dict([[t.strip() for t in l.split(':', 1)]
183 for l in open('.hg_archival.txt')])
189 for l in open('.hg_archival.txt')])
184 if 'tag' in kw:
190 if 'tag' in kw:
185 version = kw['tag']
191 version = kw['tag']
186 elif 'latesttag' in kw:
192 elif 'latesttag' in kw:
187 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
193 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
188 else:
194 else:
189 version = kw.get('node', '')[:12]
195 version = kw.get('node', '')[:12]
190
196
191 if version:
197 if version:
192 f = open("mercurial/__version__.py", "w")
198 f = open("mercurial/__version__.py", "w")
193 f.write('# this file is autogenerated by setup.py\n')
199 f.write('# this file is autogenerated by setup.py\n')
194 f.write('version = "%s"\n' % version)
200 f.write('version = "%s"\n' % version)
195 f.close()
201 f.close()
196
202
197
203
198 try:
204 try:
199 from mercurial import __version__
205 from mercurial import __version__
200 version = __version__.version
206 version = __version__.version
201 except ImportError:
207 except ImportError:
202 version = 'unknown'
208 version = 'unknown'
203
209
204 class hgbuild(build):
210 class hgbuild(build):
205 # Insert hgbuildmo first so that files in mercurial/locale/ are found
211 # Insert hgbuildmo first so that files in mercurial/locale/ are found
206 # when build_py is run next.
212 # when build_py is run next.
207 sub_commands = [('build_mo', None),
213 sub_commands = [('build_mo', None),
208 # We also need build_ext before build_py. Otherwise, when 2to3 is called (in
214 # We also need build_ext before build_py. Otherwise, when 2to3 is called (in
209 # build_py), it will not find osutil & friends, thinking that those modules are
215 # build_py), it will not find osutil & friends, thinking that those modules are
210 # global and, consequently, making a mess, now that all module imports are
216 # global and, consequently, making a mess, now that all module imports are
211 # global.
217 # global.
212 ('build_ext', build.has_ext_modules),
218 ('build_ext', build.has_ext_modules),
213 ] + build.sub_commands
219 ] + build.sub_commands
214
220
215 class hgbuildmo(build):
221 class hgbuildmo(build):
216
222
217 description = "build translations (.mo files)"
223 description = "build translations (.mo files)"
218
224
219 def run(self):
225 def run(self):
220 if not find_executable('msgfmt'):
226 if not find_executable('msgfmt'):
221 self.warn("could not find msgfmt executable, no translations "
227 self.warn("could not find msgfmt executable, no translations "
222 "will be built")
228 "will be built")
223 return
229 return
224
230
225 podir = 'i18n'
231 podir = 'i18n'
226 if not os.path.isdir(podir):
232 if not os.path.isdir(podir):
227 self.warn("could not find %s/ directory" % podir)
233 self.warn("could not find %s/ directory" % podir)
228 return
234 return
229
235
230 join = os.path.join
236 join = os.path.join
231 for po in os.listdir(podir):
237 for po in os.listdir(podir):
232 if not po.endswith('.po'):
238 if not po.endswith('.po'):
233 continue
239 continue
234 pofile = join(podir, po)
240 pofile = join(podir, po)
235 modir = join('locale', po[:-3], 'LC_MESSAGES')
241 modir = join('locale', po[:-3], 'LC_MESSAGES')
236 mofile = join(modir, 'hg.mo')
242 mofile = join(modir, 'hg.mo')
237 mobuildfile = join('mercurial', mofile)
243 mobuildfile = join('mercurial', mofile)
238 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
244 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
239 if sys.platform != 'sunos5':
245 if sys.platform != 'sunos5':
240 # msgfmt on Solaris does not know about -c
246 # msgfmt on Solaris does not know about -c
241 cmd.append('-c')
247 cmd.append('-c')
242 self.mkpath(join('mercurial', modir))
248 self.mkpath(join('mercurial', modir))
243 self.make_file([pofile], mobuildfile, spawn, (cmd,))
249 self.make_file([pofile], mobuildfile, spawn, (cmd,))
244
250
245
251
246 class hgdist(Distribution):
252 class hgdist(Distribution):
247 pure = 0
253 pure = 0
248
254
249 global_options = Distribution.global_options + \
255 global_options = Distribution.global_options + \
250 [('pure', None, "use pure (slow) Python "
256 [('pure', None, "use pure (slow) Python "
251 "code instead of C extensions"),
257 "code instead of C extensions"),
252 ('c2to3', None, "(experimental!) convert "
258 ('c2to3', None, "(experimental!) convert "
253 "code with 2to3"),
259 "code with 2to3"),
254 ]
260 ]
255
261
256 def has_ext_modules(self):
262 def has_ext_modules(self):
257 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
263 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
258 # too late for some cases
264 # too late for some cases
259 return not self.pure and Distribution.has_ext_modules(self)
265 return not self.pure and Distribution.has_ext_modules(self)
260
266
261 class hgbuildext(build_ext):
267 class hgbuildext(build_ext):
262
268
263 def build_extension(self, ext):
269 def build_extension(self, ext):
264 try:
270 try:
265 build_ext.build_extension(self, ext)
271 build_ext.build_extension(self, ext)
266 except CCompilerError:
272 except CCompilerError:
267 if not getattr(ext, 'optional', False):
273 if not getattr(ext, 'optional', False):
268 raise
274 raise
269 log.warn("Failed to build optional extension '%s' (skipping)",
275 log.warn("Failed to build optional extension '%s' (skipping)",
270 ext.name)
276 ext.name)
271
277
272 class hgbuildpy(build_py):
278 class hgbuildpy(build_py):
273 if convert2to3:
279 if convert2to3:
274 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
280 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
275 getfixers("hgfixes")))
281 getfixers("hgfixes")))
276
282
277 def finalize_options(self):
283 def finalize_options(self):
278 build_py.finalize_options(self)
284 build_py.finalize_options(self)
279
285
280 if self.distribution.pure:
286 if self.distribution.pure:
281 if self.py_modules is None:
287 if self.py_modules is None:
282 self.py_modules = []
288 self.py_modules = []
283 for ext in self.distribution.ext_modules:
289 for ext in self.distribution.ext_modules:
284 if ext.name.startswith("mercurial."):
290 if ext.name.startswith("mercurial."):
285 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
291 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
286 self.distribution.ext_modules = []
292 self.distribution.ext_modules = []
287 else:
293 else:
288 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
294 if not os.path.exists(os.path.join(get_python_inc(), 'Python.h')):
289 raise SystemExit("Python headers are required to build Mercurial")
295 raise SystemExit("Python headers are required to build Mercurial")
290
296
291 def find_modules(self):
297 def find_modules(self):
292 modules = build_py.find_modules(self)
298 modules = build_py.find_modules(self)
293 for module in modules:
299 for module in modules:
294 if module[0] == "mercurial.pure":
300 if module[0] == "mercurial.pure":
295 if module[1] != "__init__":
301 if module[1] != "__init__":
296 yield ("mercurial", module[1], module[2])
302 yield ("mercurial", module[1], module[2])
297 else:
303 else:
298 yield module
304 yield module
299
305
300 class buildhgextindex(Command):
306 class buildhgextindex(Command):
301 description = 'generate prebuilt index of hgext (for frozen package)'
307 description = 'generate prebuilt index of hgext (for frozen package)'
302 user_options = []
308 user_options = []
303 _indexfilename = 'hgext/__index__.py'
309 _indexfilename = 'hgext/__index__.py'
304
310
305 def initialize_options(self):
311 def initialize_options(self):
306 pass
312 pass
307
313
308 def finalize_options(self):
314 def finalize_options(self):
309 pass
315 pass
310
316
311 def run(self):
317 def run(self):
312 if os.path.exists(self._indexfilename):
318 if os.path.exists(self._indexfilename):
313 os.unlink(self._indexfilename)
319 os.unlink(self._indexfilename)
314
320
315 # here no extension enabled, disabled() lists up everything
321 # here no extension enabled, disabled() lists up everything
316 code = ('import pprint; from mercurial import extensions; '
322 code = ('import pprint; from mercurial import extensions; '
317 'pprint.pprint(extensions.disabled())')
323 'pprint.pprint(extensions.disabled())')
318 out, err = runcmd([sys.executable, '-c', code], env)
324 out, err = runcmd([sys.executable, '-c', code], env)
319 if err:
325 if err:
320 raise DistutilsExecError(err)
326 raise DistutilsExecError(err)
321
327
322 f = open(self._indexfilename, 'w')
328 f = open(self._indexfilename, 'w')
323 f.write('# this file is autogenerated by setup.py\n')
329 f.write('# this file is autogenerated by setup.py\n')
324 f.write('docs = ')
330 f.write('docs = ')
325 f.write(out)
331 f.write(out)
326 f.close()
332 f.close()
327
333
328 class hginstallscripts(install_scripts):
334 class hginstallscripts(install_scripts):
329 '''
335 '''
330 This is a specialization of install_scripts that replaces the @LIBDIR@ with
336 This is a specialization of install_scripts that replaces the @LIBDIR@ with
331 the configured directory for modules. If possible, the path is made relative
337 the configured directory for modules. If possible, the path is made relative
332 to the directory for scripts.
338 to the directory for scripts.
333 '''
339 '''
334
340
335 def initialize_options(self):
341 def initialize_options(self):
336 install_scripts.initialize_options(self)
342 install_scripts.initialize_options(self)
337
343
338 self.install_lib = None
344 self.install_lib = None
339
345
340 def finalize_options(self):
346 def finalize_options(self):
341 install_scripts.finalize_options(self)
347 install_scripts.finalize_options(self)
342 self.set_undefined_options('install',
348 self.set_undefined_options('install',
343 ('install_lib', 'install_lib'))
349 ('install_lib', 'install_lib'))
344
350
345 def run(self):
351 def run(self):
346 install_scripts.run(self)
352 install_scripts.run(self)
347
353
348 if (os.path.splitdrive(self.install_dir)[0] !=
354 if (os.path.splitdrive(self.install_dir)[0] !=
349 os.path.splitdrive(self.install_lib)[0]):
355 os.path.splitdrive(self.install_lib)[0]):
350 # can't make relative paths from one drive to another, so use an
356 # can't make relative paths from one drive to another, so use an
351 # absolute path instead
357 # absolute path instead
352 libdir = self.install_lib
358 libdir = self.install_lib
353 else:
359 else:
354 common = os.path.commonprefix((self.install_dir, self.install_lib))
360 common = os.path.commonprefix((self.install_dir, self.install_lib))
355 rest = self.install_dir[len(common):]
361 rest = self.install_dir[len(common):]
356 uplevel = len([n for n in os.path.split(rest) if n])
362 uplevel = len([n for n in os.path.split(rest) if n])
357
363
358 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
364 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
359
365
360 for outfile in self.outfiles:
366 for outfile in self.outfiles:
361 fp = open(outfile, 'rb')
367 fp = open(outfile, 'rb')
362 data = fp.read()
368 data = fp.read()
363 fp.close()
369 fp.close()
364
370
365 # skip binary files
371 # skip binary files
366 if b('\0') in data:
372 if b('\0') in data:
367 continue
373 continue
368
374
369 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
375 data = data.replace('@LIBDIR@', libdir.encode('string_escape'))
370 fp = open(outfile, 'wb')
376 fp = open(outfile, 'wb')
371 fp.write(data)
377 fp.write(data)
372 fp.close()
378 fp.close()
373
379
374 cmdclass = {'build': hgbuild,
380 cmdclass = {'build': hgbuild,
375 'build_mo': hgbuildmo,
381 'build_mo': hgbuildmo,
376 'build_ext': hgbuildext,
382 'build_ext': hgbuildext,
377 'build_py': hgbuildpy,
383 'build_py': hgbuildpy,
378 'build_hgextindex': buildhgextindex,
384 'build_hgextindex': buildhgextindex,
379 'install_scripts': hginstallscripts}
385 'install_scripts': hginstallscripts}
380
386
381 packages = ['mercurial', 'mercurial.hgweb',
387 packages = ['mercurial', 'mercurial.hgweb',
382 'mercurial.httpclient', 'mercurial.httpclient.tests',
388 'mercurial.httpclient', 'mercurial.httpclient.tests',
383 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
389 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
384 'hgext.largefiles']
390 'hgext.largefiles']
385
391
386 pymodules = []
392 pymodules = []
387
393
388 extmodules = [
394 extmodules = [
389 Extension('mercurial.base85', ['mercurial/base85.c']),
395 Extension('mercurial.base85', ['mercurial/base85.c']),
390 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
396 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
391 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
397 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
392 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
398 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
393 Extension('mercurial.parsers', ['mercurial/parsers.c']),
399 Extension('mercurial.parsers', ['mercurial/parsers.c']),
394 ]
400 ]
395
401
396 osutil_ldflags = []
402 osutil_ldflags = []
397
403
398 if sys.platform == 'darwin':
404 if sys.platform == 'darwin':
399 osutil_ldflags += ['-framework', 'ApplicationServices']
405 osutil_ldflags += ['-framework', 'ApplicationServices']
400
406
401 # disable osutil.c under windows + python 2.4 (issue1364)
407 # disable osutil.c under windows + python 2.4 (issue1364)
402 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
408 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
403 pymodules.append('mercurial.pure.osutil')
409 pymodules.append('mercurial.pure.osutil')
404 else:
410 else:
405 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
411 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
406 extra_link_args=osutil_ldflags))
412 extra_link_args=osutil_ldflags))
407
413
408 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
414 if sys.platform.startswith('linux') and os.uname()[2] > '2.6':
409 # The inotify extension is only usable with Linux 2.6 kernels.
415 # The inotify extension is only usable with Linux 2.6 kernels.
410 # You also need a reasonably recent C library.
416 # You also need a reasonably recent C library.
411 # In any case, if it fails to build the error will be skipped ('optional').
417 # In any case, if it fails to build the error will be skipped ('optional').
412 cc = new_compiler()
418 cc = new_compiler()
413 if hasfunction(cc, 'inotify_add_watch'):
419 if hasfunction(cc, 'inotify_add_watch'):
414 inotify = Extension('hgext.inotify.linux._inotify',
420 inotify = Extension('hgext.inotify.linux._inotify',
415 ['hgext/inotify/linux/_inotify.c'],
421 ['hgext/inotify/linux/_inotify.c'],
416 ['mercurial'])
422 ['mercurial'])
417 inotify.optional = True
423 inotify.optional = True
418 extmodules.append(inotify)
424 extmodules.append(inotify)
419 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
425 packages.extend(['hgext.inotify', 'hgext.inotify.linux'])
420
426
421 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
427 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
422 'help/*.txt']}
428 'help/*.txt']}
423
429
424 def ordinarypath(p):
430 def ordinarypath(p):
425 return p and p[0] != '.' and p[-1] != '~'
431 return p and p[0] != '.' and p[-1] != '~'
426
432
427 for root in ('templates',):
433 for root in ('templates',):
428 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
434 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
429 curdir = curdir.split(os.sep, 1)[1]
435 curdir = curdir.split(os.sep, 1)[1]
430 dirs[:] = filter(ordinarypath, dirs)
436 dirs[:] = filter(ordinarypath, dirs)
431 for f in filter(ordinarypath, files):
437 for f in filter(ordinarypath, files):
432 f = os.path.join(curdir, f)
438 f = os.path.join(curdir, f)
433 packagedata['mercurial'].append(f)
439 packagedata['mercurial'].append(f)
434
440
435 datafiles = []
441 datafiles = []
436 setupversion = version
442 setupversion = version
437 extra = {}
443 extra = {}
438
444
439 if py2exeloaded:
445 if py2exeloaded:
440 extra['console'] = [
446 extra['console'] = [
441 {'script':'hg',
447 {'script':'hg',
442 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
448 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
443 'product_version':version}]
449 'product_version':version}]
444 # sub command of 'build' because 'py2exe' does not handle sub_commands
450 # sub command of 'build' because 'py2exe' does not handle sub_commands
445 build.sub_commands.insert(0, ('build_hgextindex', None))
451 build.sub_commands.insert(0, ('build_hgextindex', None))
446
452
447 if os.name == 'nt':
453 if os.name == 'nt':
448 # Windows binary file versions for exe/dll files must have the
454 # Windows binary file versions for exe/dll files must have the
449 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
455 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
450 setupversion = version.split('+', 1)[0]
456 setupversion = version.split('+', 1)[0]
451
457
452 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
458 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
453 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
459 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
454 # distutils.sysconfig
460 # distutils.sysconfig
455 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
461 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
456 if version:
462 if version:
457 version = version[0]
463 version = version[0]
458 xcode4 = (version.startswith('Xcode') and
464 xcode4 = (version.startswith('Xcode') and
459 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
465 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
460 else:
466 else:
461 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
467 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
462 # installed, but instead with only command-line tools. Assume
468 # installed, but instead with only command-line tools. Assume
463 # that only happens on >= Lion, thus no PPC support.
469 # that only happens on >= Lion, thus no PPC support.
464 xcode4 = True
470 xcode4 = True
465
471
466 if xcode4:
472 if xcode4:
467 os.environ['ARCHFLAGS'] = ''
473 os.environ['ARCHFLAGS'] = ''
468
474
469 setup(name='mercurial',
475 setup(name='mercurial',
470 version=setupversion,
476 version=setupversion,
471 author='Matt Mackall',
477 author='Matt Mackall',
472 author_email='mpm@selenic.com',
478 author_email='mpm@selenic.com',
473 url='http://mercurial.selenic.com/',
479 url='http://mercurial.selenic.com/',
474 description='Scalable distributed SCM',
480 description='Scalable distributed SCM',
475 license='GNU GPLv2+',
481 license='GNU GPLv2+',
476 scripts=scripts,
482 scripts=scripts,
477 packages=packages,
483 packages=packages,
478 py_modules=pymodules,
484 py_modules=pymodules,
479 ext_modules=extmodules,
485 ext_modules=extmodules,
480 data_files=datafiles,
486 data_files=datafiles,
481 package_data=packagedata,
487 package_data=packagedata,
482 cmdclass=cmdclass,
488 cmdclass=cmdclass,
483 distclass=hgdist,
489 distclass=hgdist,
484 options=dict(py2exe=dict(packages=['hgext', 'email']),
490 options=dict(py2exe=dict(packages=['hgext', 'email']),
485 bdist_mpkg=dict(zipdist=True,
491 bdist_mpkg=dict(zipdist=True,
486 license='COPYING',
492 license='COPYING',
487 readme='contrib/macosx/Readme.html',
493 readme='contrib/macosx/Readme.html',
488 welcome='contrib/macosx/Welcome.html')),
494 welcome='contrib/macosx/Welcome.html')),
489 **extra)
495 **extra)
@@ -1,36 +1,36 b''
1 import os
1 import os
2 from mercurial import ui, commands, extensions
2 from mercurial import ui, commands, extensions
3
3
4 ignore = set(['highlight', 'inotify', 'win32text'])
4 ignore = set(['highlight', 'inotify', 'win32text', 'factotum'])
5
5
6 if os.name != 'nt':
6 if os.name != 'nt':
7 ignore.add('win32mbcs')
7 ignore.add('win32mbcs')
8
8
9 disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
9 disabled = [ext for ext in extensions.disabled().keys() if ext not in ignore]
10
10
11 hgrc = open(os.environ["HGRCPATH"], 'w')
11 hgrc = open(os.environ["HGRCPATH"], 'w')
12 hgrc.write('[extensions]\n')
12 hgrc.write('[extensions]\n')
13
13
14 for ext in disabled:
14 for ext in disabled:
15 hgrc.write(ext + '=\n')
15 hgrc.write(ext + '=\n')
16
16
17 hgrc.close()
17 hgrc.close()
18
18
19 u = ui.ui()
19 u = ui.ui()
20 extensions.loadall(u)
20 extensions.loadall(u)
21
21
22 globalshort = set()
22 globalshort = set()
23 globallong = set()
23 globallong = set()
24 for option in commands.globalopts:
24 for option in commands.globalopts:
25 option[0] and globalshort.add(option[0])
25 option[0] and globalshort.add(option[0])
26 option[1] and globallong.add(option[1])
26 option[1] and globallong.add(option[1])
27
27
28 for cmd, entry in commands.table.iteritems():
28 for cmd, entry in commands.table.iteritems():
29 seenshort = globalshort.copy()
29 seenshort = globalshort.copy()
30 seenlong = globallong.copy()
30 seenlong = globallong.copy()
31 for option in entry[1]:
31 for option in entry[1]:
32 if (option[0] and option[0] in seenshort) or \
32 if (option[0] and option[0] in seenshort) or \
33 (option[1] and option[1] in seenlong):
33 (option[1] and option[1] in seenlong):
34 print "command '" + cmd + "' has duplicate option " + str(option)
34 print "command '" + cmd + "' has duplicate option " + str(option)
35 seenshort.add(option[0])
35 seenshort.add(option[0])
36 seenlong.add(option[1])
36 seenlong.add(option[1])
General Comments 0
You need to be logged in to leave comments. Login now