##// END OF EJS Templates
Enhance the file filtering capabilities....
Bryan O'Sullivan -
r1293:a6ffcebd default
parent child Browse files
Show More
@@ -1,192 +1,225 b''
1 HGRC(5)
1 HGRC(5)
2 =======
2 =======
3 Bryan O'Sullivan <bos@serpentine.com>
3 Bryan O'Sullivan <bos@serpentine.com>
4
4
5 NAME
5 NAME
6 ----
6 ----
7 hgrc - configuration files for Mercurial
7 hgrc - configuration files for Mercurial
8
8
9 SYNOPSIS
9 SYNOPSIS
10 --------
10 --------
11
11
12 The Mercurial system uses a set of configuration files to control
12 The Mercurial system uses a set of configuration files to control
13 aspects of its behaviour.
13 aspects of its behaviour.
14
14
15 FILES
15 FILES
16 -----
16 -----
17
17
18 Mercurial reads configuration data from three files:
18 Mercurial reads configuration data from three files:
19
19
20 /etc/mercurial/hgrc::
20 /etc/mercurial/hgrc::
21 Options in this global configuration file apply to all Mercurial
21 Options in this global configuration file apply to all Mercurial
22 commands executed by any user in any directory.
22 commands executed by any user in any directory.
23
23
24 $HOME/.hgrc::
24 $HOME/.hgrc::
25 Per-user configuration options that apply to all Mercurial commands,
25 Per-user configuration options that apply to all Mercurial commands,
26 no matter from which directory they are run. Values in this file
26 no matter from which directory they are run. Values in this file
27 override global settings.
27 override global settings.
28
28
29 <repo>/.hg/hgrc::
29 <repo>/.hg/hgrc::
30 Per-repository configuration options that only apply in a
30 Per-repository configuration options that only apply in a
31 particular repository. This file is not version-controlled, and
31 particular repository. This file is not version-controlled, and
32 will not get transferred during a "clone" operation. Values in
32 will not get transferred during a "clone" operation. Values in
33 this file override global and per-user settings.
33 this file override global and per-user settings.
34
34
35 SYNTAX
35 SYNTAX
36 ------
36 ------
37
37
38 A configuration file consists of sections, led by a "[section]" header
38 A configuration file consists of sections, led by a "[section]" header
39 and followed by "name: value" entries; "name=value" is also accepted.
39 and followed by "name: value" entries; "name=value" is also accepted.
40
40
41 [spam]
41 [spam]
42 eggs=ham
42 eggs=ham
43 green=
43 green=
44 eggs
44 eggs
45
45
46 Each line contains one entry. If the lines that follow are indented,
46 Each line contains one entry. If the lines that follow are indented,
47 they are treated as continuations of that entry.
47 they are treated as continuations of that entry.
48
48
49 Leading whitespace is removed from values. Empty lines are skipped.
49 Leading whitespace is removed from values. Empty lines are skipped.
50
50
51 The optional values can contain format strings which refer to other
51 The optional values can contain format strings which refer to other
52 values in the same section, or values in a special DEFAULT section.
52 values in the same section, or values in a special DEFAULT section.
53
53
54 Lines beginning with "#" or ";" are ignored and may be used to provide
54 Lines beginning with "#" or ";" are ignored and may be used to provide
55 comments.
55 comments.
56
56
57 SECTIONS
57 SECTIONS
58 --------
58 --------
59
59
60 This section describes the different sections that may appear in a
60 This section describes the different sections that may appear in a
61 Mercurial "hgrc" file, the purpose of each section, its possible
61 Mercurial "hgrc" file, the purpose of each section, its possible
62 keys, and their possible values.
62 keys, and their possible values.
63
63
64 decode/encode::
64 decode/encode::
65 Filters for transforming files on checkout/checkin. This would
65 Filters for transforming files on checkout/checkin. This would
66 typically be used for newline processing or other
66 typically be used for newline processing or other
67 localization/canonicalization of files.
67 localization/canonicalization of files.
68
68
69 Filters consist of a filter pattern followed by a filter command.
69 Filters consist of a filter pattern followed by a filter command.
70 The command must accept data on stdin and return the transformed
70 Filter patterns are globs by default, rooted at the repository
71 data on stdout.
71 root. For example, to match any file ending in ".txt" in the root
72 directory only, use the pattern "*.txt". To match any file ending
73 in ".c" anywhere in the repository, use the pattern "**.c".
72
74
73 Example:
75 The filter command can start with a specifier, either "pipe:" or
76 "tempfile:". If no specifier is given, "pipe:" is used by default.
77
78 A "pipe:" command must accept data on stdin and return the
79 transformed data on stdout.
80
81 Pipe example:
74
82
75 [encode]
83 [encode]
76 # uncompress gzip files on checkin to improve delta compression
84 # uncompress gzip files on checkin to improve delta compression
77 # note: not necessarily a good idea, just an example
85 # note: not necessarily a good idea, just an example
78 *.gz = gunzip
86 *.gz = pipe: gunzip
79
87
80 [decode]
88 [decode]
81 # recompress gzip files when writing them to the working dir
89 # recompress gzip files when writing them to the working dir (we
90 # can safely omit "pipe:", because it's the default)
82 *.gz = gzip
91 *.gz = gzip
83
92
93 A "tempfile:" command is a template. The string INFILE is replaced
94 with the name of a temporary file that contains the data to be
95 filtered by the command. The string OUTFILE is replaced with the
96 name of an empty temporary file, where the filtered data must be
97 written by the command.
98
99 NOTE: the tempfile mechanism is recommended for Windows systems,
100 where the standard shell I/O redirection operators often have
101 strange effects. In particular, if you are doing line ending
102 conversion on Windows using the popular dos2unix and unix2dos
103 programs, you *must* use the tempfile mechanism, as using pipes will
104 corrupt the contents of your files.
105
106 Tempfile example:
107
108 [encode]
109 # convert files to unix line ending conventions on checkin
110 **.txt = tempfile: dos2unix -n INFILE OUTFILE
111
112 [decode]
113 # convert files to windows line ending conventions when writing
114 # them to the working dir
115 **.txt = tempfile: unix2dos -n INFILE OUTFILE
116
84 hooks::
117 hooks::
85 Commands that get automatically executed by various actions such as
118 Commands that get automatically executed by various actions such as
86 starting or finishing a commit.
119 starting or finishing a commit.
87 changegroup;;
120 changegroup;;
88 Run after a changegroup has been added via push or pull.
121 Run after a changegroup has been added via push or pull.
89 commit;;
122 commit;;
90 Run after a changeset has been created. Passed the ID of the newly
123 Run after a changeset has been created. Passed the ID of the newly
91 created changeset.
124 created changeset.
92 precommit;;
125 precommit;;
93 Run before starting a commit. Exit status 0 allows the commit to
126 Run before starting a commit. Exit status 0 allows the commit to
94 proceed. Non-zero status will cause the commit to fail.
127 proceed. Non-zero status will cause the commit to fail.
95
128
96 http_proxy::
129 http_proxy::
97 Used to access web-based Mercurial repositories through a HTTP
130 Used to access web-based Mercurial repositories through a HTTP
98 proxy.
131 proxy.
99 host;;
132 host;;
100 Host name and (optional) port of the proxy server, for example
133 Host name and (optional) port of the proxy server, for example
101 "myproxy:8000".
134 "myproxy:8000".
102 no;;
135 no;;
103 Optional. Comma-separated list of host names that should bypass
136 Optional. Comma-separated list of host names that should bypass
104 the proxy.
137 the proxy.
105 passwd;;
138 passwd;;
106 Optional. Password to authenticate with at the proxy server.
139 Optional. Password to authenticate with at the proxy server.
107 user;;
140 user;;
108 Optional. User name to authenticate with at the proxy server.
141 Optional. User name to authenticate with at the proxy server.
109
142
110 paths::
143 paths::
111 Assigns symbolic names to repositories. The left side is the
144 Assigns symbolic names to repositories. The left side is the
112 symbolic name, and the right gives the directory or URL that is the
145 symbolic name, and the right gives the directory or URL that is the
113 location of the repository.
146 location of the repository.
114
147
115 ui::
148 ui::
116 User interface controls.
149 User interface controls.
117 debug;;
150 debug;;
118 Print debugging information. True or False. Default is False.
151 Print debugging information. True or False. Default is False.
119 editor;;
152 editor;;
120 The editor to use during a commit. Default is $EDITOR or "vi".
153 The editor to use during a commit. Default is $EDITOR or "vi".
121 interactive;;
154 interactive;;
122 Allow to prompt the user. True or False. Default is True.
155 Allow to prompt the user. True or False. Default is True.
123 merge;;
156 merge;;
124 The conflict resolution program to use during a manual merge.
157 The conflict resolution program to use during a manual merge.
125 Default is "hgmerge".
158 Default is "hgmerge".
126 quiet;;
159 quiet;;
127 Reduce the amount of output printed. True or False. Default is False.
160 Reduce the amount of output printed. True or False. Default is False.
128 remotecmd;;
161 remotecmd;;
129 remote command to use for clone/push/pull operations. Default is 'hg'.
162 remote command to use for clone/push/pull operations. Default is 'hg'.
130 ssh;;
163 ssh;;
131 command to use for SSH connections. Default is 'ssh'.
164 command to use for SSH connections. Default is 'ssh'.
132 username;;
165 username;;
133 The committer of a changeset created when running "commit".
166 The committer of a changeset created when running "commit".
134 Typically a person's name and email address, e.g. "Fred Widget
167 Typically a person's name and email address, e.g. "Fred Widget
135 <fred@example.com>". Default is $EMAIL or username@hostname.
168 <fred@example.com>". Default is $EMAIL or username@hostname.
136 verbose;;
169 verbose;;
137 Increase the amount of output printed. True or False. Default is False.
170 Increase the amount of output printed. True or False. Default is False.
138
171
139
172
140 web::
173 web::
141 Web interface configuration.
174 Web interface configuration.
142 accesslog;;
175 accesslog;;
143 Where to output the access log. Default is stdout.
176 Where to output the access log. Default is stdout.
144 address;;
177 address;;
145 Interface address to bind to. Default is all.
178 Interface address to bind to. Default is all.
146 allowbz2;;
179 allowbz2;;
147 Whether to allow .tar.bz2 downloading of repo revisions. Default is false.
180 Whether to allow .tar.bz2 downloading of repo revisions. Default is false.
148 allowgz;;
181 allowgz;;
149 Whether to allow .tar.gz downloading of repo revisions. Default is false.
182 Whether to allow .tar.gz downloading of repo revisions. Default is false.
150 allowpull;;
183 allowpull;;
151 Whether to allow pulling from the repository. Default is true.
184 Whether to allow pulling from the repository. Default is true.
152 allowzip;;
185 allowzip;;
153 Whether to allow .zip downloading of repo revisions. Default is false.
186 Whether to allow .zip downloading of repo revisions. Default is false.
154 This feature creates temporary files.
187 This feature creates temporary files.
155 description;;
188 description;;
156 Textual description of the repository's purpose or contents.
189 Textual description of the repository's purpose or contents.
157 Default is "unknown".
190 Default is "unknown".
158 errorlog;;
191 errorlog;;
159 Where to output the error log. Default is stderr.
192 Where to output the error log. Default is stderr.
160 ipv6;;
193 ipv6;;
161 Whether to use IPv6. Default is false.
194 Whether to use IPv6. Default is false.
162 name;;
195 name;;
163 Repository name to use in the web interface. Default is current
196 Repository name to use in the web interface. Default is current
164 working directory.
197 working directory.
165 maxchanges;;
198 maxchanges;;
166 Maximum number of changes to list on the changelog. Default is 10.
199 Maximum number of changes to list on the changelog. Default is 10.
167 maxfiles;;
200 maxfiles;;
168 Maximum number of files to list per changeset. Default is 10.
201 Maximum number of files to list per changeset. Default is 10.
169 port;;
202 port;;
170 Port to listen on. Default is 8000.
203 Port to listen on. Default is 8000.
171 style;;
204 style;;
172 Which template map style to use.
205 Which template map style to use.
173 templates;;
206 templates;;
174 Where to find the HTML templates. Default is install path.
207 Where to find the HTML templates. Default is install path.
175
208
176
209
177 AUTHOR
210 AUTHOR
178 ------
211 ------
179 Bryan O'Sullivan <bos@serpentine.com>.
212 Bryan O'Sullivan <bos@serpentine.com>.
180
213
181 Mercurial was written by Matt Mackall <mpm@selenic.com>.
214 Mercurial was written by Matt Mackall <mpm@selenic.com>.
182
215
183 SEE ALSO
216 SEE ALSO
184 --------
217 --------
185 hg(1)
218 hg(1)
186
219
187 COPYING
220 COPYING
188 -------
221 -------
189 This manual page is copyright 2005 Bryan O'Sullivan.
222 This manual page is copyright 2005 Bryan O'Sullivan.
190 Mercurial is copyright 2005 Matt Mackall.
223 Mercurial is copyright 2005 Matt Mackall.
191 Free use of this software is granted under the terms of the GNU General
224 Free use of this software is granted under the terms of the GNU General
192 Public License (GPL).
225 Public License (GPL).
@@ -1,506 +1,545 b''
1 """
1 """
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8
8
9 This contains helper routines that are independent of the SCM core and hide
9 This contains helper routines that are independent of the SCM core and hide
10 platform-specific details from the core.
10 platform-specific details from the core.
11 """
11 """
12
12
13 import os, errno
13 import os, errno
14 from demandload import *
14 from demandload import *
15 demandload(globals(), "re cStringIO shutil popen2 threading")
15 demandload(globals(), "re cStringIO shutil popen2 tempfile threading")
16
16
17 def filter(s, cmd):
17 def pipefilter(s, cmd):
18 "filter a string through a command that transforms its input to its output"
18 '''filter string S through command CMD, returning its output'''
19 (pout, pin) = popen2.popen2(cmd, -1, 'b')
19 (pout, pin) = popen2.popen2(cmd, -1, 'b')
20 def writer():
20 def writer():
21 pin.write(s)
21 pin.write(s)
22 pin.close()
22 pin.close()
23
23
24 # we should use select instead on UNIX, but this will work on most
24 # we should use select instead on UNIX, but this will work on most
25 # systems, including Windows
25 # systems, including Windows
26 w = threading.Thread(target=writer)
26 w = threading.Thread(target=writer)
27 w.start()
27 w.start()
28 f = pout.read()
28 f = pout.read()
29 pout.close()
29 pout.close()
30 w.join()
30 w.join()
31 return f
31 return f
32
32
33 def tempfilter(s, cmd):
34 '''filter string S through a pair of temporary files with CMD.
35 CMD is used as a template to create the real command to be run,
36 with the strings INFILE and OUTFILE replaced by the real names of
37 the temporary files generated.'''
38 inname, outname = None, None
39 try:
40 infd, inname = tempfile.mkstemp(prefix='hgfin')
41 fp = os.fdopen(infd, 'wb')
42 fp.write(s)
43 fp.close()
44 outfd, outname = tempfile.mkstemp(prefix='hgfout')
45 os.close(outfd)
46 cmd = cmd.replace('INFILE', inname)
47 cmd = cmd.replace('OUTFILE', outname)
48 code = os.system(cmd)
49 if code: raise Abort("command '%s' failed: %s" %
50 (cmd, explain_exit(code)))
51 return open(outname, 'rb').read()
52 finally:
53 try:
54 if inname: os.unlink(inname)
55 except: pass
56 try:
57 if outname: os.unlink(outname)
58 except: pass
59
60 filtertable = {
61 'tempfile:': tempfilter,
62 'pipe:': pipefilter,
63 }
64
65 def filter(s, cmd):
66 "filter a string through a command that transforms its input to its output"
67 for name, fn in filtertable.iteritems():
68 if cmd.startswith(name):
69 return fn(s, cmd[len(name):].lstrip())
70 return pipefilter(s, cmd)
71
33 def patch(strip, patchname, ui):
72 def patch(strip, patchname, ui):
34 """apply the patch <patchname> to the working directory.
73 """apply the patch <patchname> to the working directory.
35 a list of patched files is returned"""
74 a list of patched files is returned"""
36 fp = os.popen('patch -p%d < "%s"' % (strip, patchname))
75 fp = os.popen('patch -p%d < "%s"' % (strip, patchname))
37 files = {}
76 files = {}
38 for line in fp:
77 for line in fp:
39 line = line.rstrip()
78 line = line.rstrip()
40 ui.status("%s\n" % line)
79 ui.status("%s\n" % line)
41 if line.startswith('patching file '):
80 if line.startswith('patching file '):
42 pf = parse_patch_output(line)
81 pf = parse_patch_output(line)
43 files.setdefault(pf, 1)
82 files.setdefault(pf, 1)
44 code = fp.close()
83 code = fp.close()
45 if code:
84 if code:
46 raise Abort("patch command failed: exit status %s " % code)
85 raise Abort("patch command failed: %s" % explain_exit(code))
47 return files.keys()
86 return files.keys()
48
87
49 def binary(s):
88 def binary(s):
50 """return true if a string is binary data using diff's heuristic"""
89 """return true if a string is binary data using diff's heuristic"""
51 if s and '\0' in s[:4096]:
90 if s and '\0' in s[:4096]:
52 return True
91 return True
53 return False
92 return False
54
93
55 def unique(g):
94 def unique(g):
56 """return the uniq elements of iterable g"""
95 """return the uniq elements of iterable g"""
57 seen = {}
96 seen = {}
58 for f in g:
97 for f in g:
59 if f not in seen:
98 if f not in seen:
60 seen[f] = 1
99 seen[f] = 1
61 yield f
100 yield f
62
101
63 class Abort(Exception):
102 class Abort(Exception):
64 """Raised if a command needs to print an error and exit."""
103 """Raised if a command needs to print an error and exit."""
65
104
66 def always(fn): return True
105 def always(fn): return True
67 def never(fn): return False
106 def never(fn): return False
68
107
69 def globre(pat, head='^', tail='$'):
108 def globre(pat, head='^', tail='$'):
70 "convert a glob pattern into a regexp"
109 "convert a glob pattern into a regexp"
71 i, n = 0, len(pat)
110 i, n = 0, len(pat)
72 res = ''
111 res = ''
73 group = False
112 group = False
74 def peek(): return i < n and pat[i]
113 def peek(): return i < n and pat[i]
75 while i < n:
114 while i < n:
76 c = pat[i]
115 c = pat[i]
77 i = i+1
116 i = i+1
78 if c == '*':
117 if c == '*':
79 if peek() == '*':
118 if peek() == '*':
80 i += 1
119 i += 1
81 res += '.*'
120 res += '.*'
82 else:
121 else:
83 res += '[^/]*'
122 res += '[^/]*'
84 elif c == '?':
123 elif c == '?':
85 res += '.'
124 res += '.'
86 elif c == '[':
125 elif c == '[':
87 j = i
126 j = i
88 if j < n and pat[j] in '!]':
127 if j < n and pat[j] in '!]':
89 j += 1
128 j += 1
90 while j < n and pat[j] != ']':
129 while j < n and pat[j] != ']':
91 j += 1
130 j += 1
92 if j >= n:
131 if j >= n:
93 res += '\\['
132 res += '\\['
94 else:
133 else:
95 stuff = pat[i:j].replace('\\','\\\\')
134 stuff = pat[i:j].replace('\\','\\\\')
96 i = j + 1
135 i = j + 1
97 if stuff[0] == '!':
136 if stuff[0] == '!':
98 stuff = '^' + stuff[1:]
137 stuff = '^' + stuff[1:]
99 elif stuff[0] == '^':
138 elif stuff[0] == '^':
100 stuff = '\\' + stuff
139 stuff = '\\' + stuff
101 res = '%s[%s]' % (res, stuff)
140 res = '%s[%s]' % (res, stuff)
102 elif c == '{':
141 elif c == '{':
103 group = True
142 group = True
104 res += '(?:'
143 res += '(?:'
105 elif c == '}' and group:
144 elif c == '}' and group:
106 res += ')'
145 res += ')'
107 group = False
146 group = False
108 elif c == ',' and group:
147 elif c == ',' and group:
109 res += '|'
148 res += '|'
110 else:
149 else:
111 res += re.escape(c)
150 res += re.escape(c)
112 return head + res + tail
151 return head + res + tail
113
152
114 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
153 _globchars = {'[': 1, '{': 1, '*': 1, '?': 1}
115
154
116 def pathto(n1, n2):
155 def pathto(n1, n2):
117 '''return the relative path from one place to another.
156 '''return the relative path from one place to another.
118 this returns a path in the form used by the local filesystem, not hg.'''
157 this returns a path in the form used by the local filesystem, not hg.'''
119 if not n1: return localpath(n2)
158 if not n1: return localpath(n2)
120 a, b = n1.split('/'), n2.split('/')
159 a, b = n1.split('/'), n2.split('/')
121 a.reverse(), b.reverse()
160 a.reverse(), b.reverse()
122 while a and b and a[-1] == b[-1]:
161 while a and b and a[-1] == b[-1]:
123 a.pop(), b.pop()
162 a.pop(), b.pop()
124 b.reverse()
163 b.reverse()
125 return os.sep.join((['..'] * len(a)) + b)
164 return os.sep.join((['..'] * len(a)) + b)
126
165
127 def canonpath(root, cwd, myname):
166 def canonpath(root, cwd, myname):
128 """return the canonical path of myname, given cwd and root"""
167 """return the canonical path of myname, given cwd and root"""
129 rootsep = root + os.sep
168 rootsep = root + os.sep
130 name = myname
169 name = myname
131 if not name.startswith(os.sep):
170 if not name.startswith(os.sep):
132 name = os.path.join(root, cwd, name)
171 name = os.path.join(root, cwd, name)
133 name = os.path.normpath(name)
172 name = os.path.normpath(name)
134 if name.startswith(rootsep):
173 if name.startswith(rootsep):
135 return pconvert(name[len(rootsep):])
174 return pconvert(name[len(rootsep):])
136 elif name == root:
175 elif name == root:
137 return ''
176 return ''
138 else:
177 else:
139 raise Abort('%s not under root' % myname)
178 raise Abort('%s not under root' % myname)
140
179
141 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
180 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head=''):
142 """build a function to match a set of file patterns
181 """build a function to match a set of file patterns
143
182
144 arguments:
183 arguments:
145 canonroot - the canonical root of the tree you're matching against
184 canonroot - the canonical root of the tree you're matching against
146 cwd - the current working directory, if relevant
185 cwd - the current working directory, if relevant
147 names - patterns to find
186 names - patterns to find
148 inc - patterns to include
187 inc - patterns to include
149 exc - patterns to exclude
188 exc - patterns to exclude
150 head - a regex to prepend to patterns to control whether a match is rooted
189 head - a regex to prepend to patterns to control whether a match is rooted
151
190
152 a pattern is one of:
191 a pattern is one of:
153 'glob:<rooted glob>'
192 'glob:<rooted glob>'
154 're:<rooted regexp>'
193 're:<rooted regexp>'
155 'path:<rooted path>'
194 'path:<rooted path>'
156 'relglob:<relative glob>'
195 'relglob:<relative glob>'
157 'relpath:<relative path>'
196 'relpath:<relative path>'
158 'relre:<relative regexp>'
197 'relre:<relative regexp>'
159 '<rooted path or regexp>'
198 '<rooted path or regexp>'
160
199
161 returns:
200 returns:
162 a 3-tuple containing
201 a 3-tuple containing
163 - list of explicit non-pattern names passed in
202 - list of explicit non-pattern names passed in
164 - a bool match(filename) function
203 - a bool match(filename) function
165 - a bool indicating if any patterns were passed in
204 - a bool indicating if any patterns were passed in
166
205
167 todo:
206 todo:
168 make head regex a rooted bool
207 make head regex a rooted bool
169 """
208 """
170
209
171 def patkind(name):
210 def patkind(name):
172 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
211 for prefix in 're', 'glob', 'path', 'relglob', 'relpath', 'relre':
173 if name.startswith(prefix + ':'): return name.split(':', 1)
212 if name.startswith(prefix + ':'): return name.split(':', 1)
174 for c in name:
213 for c in name:
175 if c in _globchars: return 'glob', name
214 if c in _globchars: return 'glob', name
176 return 'relpath', name
215 return 'relpath', name
177
216
178 def regex(kind, name, tail):
217 def regex(kind, name, tail):
179 '''convert a pattern into a regular expression'''
218 '''convert a pattern into a regular expression'''
180 if kind == 're':
219 if kind == 're':
181 return name
220 return name
182 elif kind == 'path':
221 elif kind == 'path':
183 return '^' + re.escape(name) + '(?:/|$)'
222 return '^' + re.escape(name) + '(?:/|$)'
184 elif kind == 'relglob':
223 elif kind == 'relglob':
185 return head + globre(name, '(?:|.*/)', tail)
224 return head + globre(name, '(?:|.*/)', tail)
186 elif kind == 'relpath':
225 elif kind == 'relpath':
187 return head + re.escape(name) + tail
226 return head + re.escape(name) + tail
188 elif kind == 'relre':
227 elif kind == 'relre':
189 if name.startswith('^'):
228 if name.startswith('^'):
190 return name
229 return name
191 return '.*' + name
230 return '.*' + name
192 return head + globre(name, '', tail)
231 return head + globre(name, '', tail)
193
232
194 def matchfn(pats, tail):
233 def matchfn(pats, tail):
195 """build a matching function from a set of patterns"""
234 """build a matching function from a set of patterns"""
196 if pats:
235 if pats:
197 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
236 pat = '(?:%s)' % '|'.join([regex(k, p, tail) for (k, p) in pats])
198 return re.compile(pat).match
237 return re.compile(pat).match
199
238
200 def globprefix(pat):
239 def globprefix(pat):
201 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
240 '''return the non-glob prefix of a path, e.g. foo/* -> foo'''
202 root = []
241 root = []
203 for p in pat.split(os.sep):
242 for p in pat.split(os.sep):
204 if patkind(p)[0] == 'glob': break
243 if patkind(p)[0] == 'glob': break
205 root.append(p)
244 root.append(p)
206 return '/'.join(root)
245 return '/'.join(root)
207
246
208 pats = []
247 pats = []
209 files = []
248 files = []
210 roots = []
249 roots = []
211 for kind, name in map(patkind, names):
250 for kind, name in map(patkind, names):
212 if kind in ('glob', 'relpath'):
251 if kind in ('glob', 'relpath'):
213 name = canonpath(canonroot, cwd, name)
252 name = canonpath(canonroot, cwd, name)
214 if name == '':
253 if name == '':
215 kind, name = 'glob', '**'
254 kind, name = 'glob', '**'
216 if kind in ('glob', 'path', 're'):
255 if kind in ('glob', 'path', 're'):
217 pats.append((kind, name))
256 pats.append((kind, name))
218 if kind == 'glob':
257 if kind == 'glob':
219 root = globprefix(name)
258 root = globprefix(name)
220 if root: roots.append(root)
259 if root: roots.append(root)
221 elif kind == 'relpath':
260 elif kind == 'relpath':
222 files.append((kind, name))
261 files.append((kind, name))
223 roots.append(name)
262 roots.append(name)
224
263
225 patmatch = matchfn(pats, '$') or always
264 patmatch = matchfn(pats, '$') or always
226 filematch = matchfn(files, '(?:/|$)') or always
265 filematch = matchfn(files, '(?:/|$)') or always
227 incmatch = always
266 incmatch = always
228 if inc:
267 if inc:
229 incmatch = matchfn(map(patkind, inc), '(?:/|$)')
268 incmatch = matchfn(map(patkind, inc), '(?:/|$)')
230 excmatch = lambda fn: False
269 excmatch = lambda fn: False
231 if exc:
270 if exc:
232 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
271 excmatch = matchfn(map(patkind, exc), '(?:/|$)')
233
272
234 return (roots,
273 return (roots,
235 lambda fn: (incmatch(fn) and not excmatch(fn) and
274 lambda fn: (incmatch(fn) and not excmatch(fn) and
236 (fn.endswith('/') or
275 (fn.endswith('/') or
237 (not pats and not files) or
276 (not pats and not files) or
238 (pats and patmatch(fn)) or
277 (pats and patmatch(fn)) or
239 (files and filematch(fn)))),
278 (files and filematch(fn)))),
240 (inc or exc or (pats and pats != [('glob', '**')])) and True)
279 (inc or exc or (pats and pats != [('glob', '**')])) and True)
241
280
242 def system(cmd, errprefix=None):
281 def system(cmd, errprefix=None):
243 """execute a shell command that must succeed"""
282 """execute a shell command that must succeed"""
244 rc = os.system(cmd)
283 rc = os.system(cmd)
245 if rc:
284 if rc:
246 errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
285 errmsg = "%s %s" % (os.path.basename(cmd.split(None, 1)[0]),
247 explain_exit(rc)[0])
286 explain_exit(rc)[0])
248 if errprefix:
287 if errprefix:
249 errmsg = "%s: %s" % (errprefix, errmsg)
288 errmsg = "%s: %s" % (errprefix, errmsg)
250 raise Abort(errmsg)
289 raise Abort(errmsg)
251
290
252 def rename(src, dst):
291 def rename(src, dst):
253 """forcibly rename a file"""
292 """forcibly rename a file"""
254 try:
293 try:
255 os.rename(src, dst)
294 os.rename(src, dst)
256 except:
295 except:
257 os.unlink(dst)
296 os.unlink(dst)
258 os.rename(src, dst)
297 os.rename(src, dst)
259
298
260 def copyfiles(src, dst, hardlink=None):
299 def copyfiles(src, dst, hardlink=None):
261 """Copy a directory tree using hardlinks if possible"""
300 """Copy a directory tree using hardlinks if possible"""
262
301
263 if hardlink is None:
302 if hardlink is None:
264 hardlink = (os.stat(src).st_dev ==
303 hardlink = (os.stat(src).st_dev ==
265 os.stat(os.path.dirname(dst)).st_dev)
304 os.stat(os.path.dirname(dst)).st_dev)
266
305
267 if os.path.isdir(src):
306 if os.path.isdir(src):
268 os.mkdir(dst)
307 os.mkdir(dst)
269 for name in os.listdir(src):
308 for name in os.listdir(src):
270 srcname = os.path.join(src, name)
309 srcname = os.path.join(src, name)
271 dstname = os.path.join(dst, name)
310 dstname = os.path.join(dst, name)
272 copyfiles(srcname, dstname, hardlink)
311 copyfiles(srcname, dstname, hardlink)
273 else:
312 else:
274 if hardlink:
313 if hardlink:
275 try:
314 try:
276 os_link(src, dst)
315 os_link(src, dst)
277 except:
316 except:
278 hardlink = False
317 hardlink = False
279 shutil.copy2(src, dst)
318 shutil.copy2(src, dst)
280 else:
319 else:
281 shutil.copy2(src, dst)
320 shutil.copy2(src, dst)
282
321
283 def opener(base):
322 def opener(base):
284 """
323 """
285 return a function that opens files relative to base
324 return a function that opens files relative to base
286
325
287 this function is used to hide the details of COW semantics and
326 this function is used to hide the details of COW semantics and
288 remote file access from higher level code.
327 remote file access from higher level code.
289 """
328 """
290 p = base
329 p = base
291 def o(path, mode="r"):
330 def o(path, mode="r"):
292 f = os.path.join(p, path)
331 f = os.path.join(p, path)
293
332
294 mode += "b" # for that other OS
333 mode += "b" # for that other OS
295
334
296 if mode[0] != "r":
335 if mode[0] != "r":
297 try:
336 try:
298 nlink = nlinks(f)
337 nlink = nlinks(f)
299 except OSError:
338 except OSError:
300 d = os.path.dirname(f)
339 d = os.path.dirname(f)
301 if not os.path.isdir(d):
340 if not os.path.isdir(d):
302 os.makedirs(d)
341 os.makedirs(d)
303 else:
342 else:
304 if nlink > 1:
343 if nlink > 1:
305 file(f + ".tmp", "wb").write(file(f, "rb").read())
344 file(f + ".tmp", "wb").write(file(f, "rb").read())
306 rename(f+".tmp", f)
345 rename(f+".tmp", f)
307
346
308 return file(f, mode)
347 return file(f, mode)
309
348
310 return o
349 return o
311
350
312 def _makelock_file(info, pathname):
351 def _makelock_file(info, pathname):
313 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
352 ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
314 os.write(ld, info)
353 os.write(ld, info)
315 os.close(ld)
354 os.close(ld)
316
355
317 def _readlock_file(pathname):
356 def _readlock_file(pathname):
318 return file(pathname).read()
357 return file(pathname).read()
319
358
320 def nlinks(pathname):
359 def nlinks(pathname):
321 """Return number of hardlinks for the given file."""
360 """Return number of hardlinks for the given file."""
322 return os.stat(pathname).st_nlink
361 return os.stat(pathname).st_nlink
323
362
324 if hasattr(os, 'link'):
363 if hasattr(os, 'link'):
325 os_link = os.link
364 os_link = os.link
326 else:
365 else:
327 def os_link(src, dst):
366 def os_link(src, dst):
328 raise OSError(0, "Hardlinks not supported")
367 raise OSError(0, "Hardlinks not supported")
329
368
330 # Platform specific variants
369 # Platform specific variants
331 if os.name == 'nt':
370 if os.name == 'nt':
332 nulldev = 'NUL:'
371 nulldev = 'NUL:'
333
372
334 rcpath = (r'c:\mercurial\mercurial.ini',
373 rcpath = (r'c:\mercurial\mercurial.ini',
335 os.path.join(os.path.expanduser('~'), 'mercurial.ini'))
374 os.path.join(os.path.expanduser('~'), 'mercurial.ini'))
336
375
337 def parse_patch_output(output_line):
376 def parse_patch_output(output_line):
338 """parses the output produced by patch and returns the file name"""
377 """parses the output produced by patch and returns the file name"""
339 pf = output_line[14:]
378 pf = output_line[14:]
340 if pf[0] == '`':
379 if pf[0] == '`':
341 pf = pf[1:-1] # Remove the quotes
380 pf = pf[1:-1] # Remove the quotes
342 return pf
381 return pf
343
382
344 try: # ActivePython can create hard links using win32file module
383 try: # ActivePython can create hard links using win32file module
345 import win32file
384 import win32file
346
385
347 def os_link(src, dst): # NB will only succeed on NTFS
386 def os_link(src, dst): # NB will only succeed on NTFS
348 win32file.CreateHardLink(dst, src)
387 win32file.CreateHardLink(dst, src)
349
388
350 def nlinks(pathname):
389 def nlinks(pathname):
351 """Return number of hardlinks for the given file."""
390 """Return number of hardlinks for the given file."""
352 try:
391 try:
353 fh = win32file.CreateFile(pathname,
392 fh = win32file.CreateFile(pathname,
354 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
393 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
355 None, win32file.OPEN_EXISTING, 0, None)
394 None, win32file.OPEN_EXISTING, 0, None)
356 res = win32file.GetFileInformationByHandle(fh)
395 res = win32file.GetFileInformationByHandle(fh)
357 fh.Close()
396 fh.Close()
358 return res[7]
397 return res[7]
359 except:
398 except:
360 return os.stat(pathname).st_nlink
399 return os.stat(pathname).st_nlink
361
400
362 except ImportError:
401 except ImportError:
363 pass
402 pass
364
403
365 def is_exec(f, last):
404 def is_exec(f, last):
366 return last
405 return last
367
406
368 def set_exec(f, mode):
407 def set_exec(f, mode):
369 pass
408 pass
370
409
371 def pconvert(path):
410 def pconvert(path):
372 return path.replace("\\", "/")
411 return path.replace("\\", "/")
373
412
374 def localpath(path):
413 def localpath(path):
375 return path.replace('/', '\\')
414 return path.replace('/', '\\')
376
415
377 def normpath(path):
416 def normpath(path):
378 return pconvert(os.path.normpath(path))
417 return pconvert(os.path.normpath(path))
379
418
380 makelock = _makelock_file
419 makelock = _makelock_file
381 readlock = _readlock_file
420 readlock = _readlock_file
382
421
383 def explain_exit(code):
422 def explain_exit(code):
384 return "exited with status %d" % code, code
423 return "exited with status %d" % code, code
385
424
386 else:
425 else:
387 nulldev = '/dev/null'
426 nulldev = '/dev/null'
388
427
389 rcpath = map(os.path.normpath,
428 rcpath = map(os.path.normpath,
390 ('/etc/mercurial/hgrc', os.path.expanduser('~/.hgrc')))
429 ('/etc/mercurial/hgrc', os.path.expanduser('~/.hgrc')))
391
430
392 def parse_patch_output(output_line):
431 def parse_patch_output(output_line):
393 """parses the output produced by patch and returns the file name"""
432 """parses the output produced by patch and returns the file name"""
394 return output_line[14:]
433 return output_line[14:]
395
434
396 def is_exec(f, last):
435 def is_exec(f, last):
397 """check whether a file is executable"""
436 """check whether a file is executable"""
398 return (os.stat(f).st_mode & 0100 != 0)
437 return (os.stat(f).st_mode & 0100 != 0)
399
438
400 def set_exec(f, mode):
439 def set_exec(f, mode):
401 s = os.stat(f).st_mode
440 s = os.stat(f).st_mode
402 if (s & 0100 != 0) == mode:
441 if (s & 0100 != 0) == mode:
403 return
442 return
404 if mode:
443 if mode:
405 # Turn on +x for every +r bit when making a file executable
444 # Turn on +x for every +r bit when making a file executable
406 # and obey umask.
445 # and obey umask.
407 umask = os.umask(0)
446 umask = os.umask(0)
408 os.umask(umask)
447 os.umask(umask)
409 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
448 os.chmod(f, s | (s & 0444) >> 2 & ~umask)
410 else:
449 else:
411 os.chmod(f, s & 0666)
450 os.chmod(f, s & 0666)
412
451
413 def pconvert(path):
452 def pconvert(path):
414 return path
453 return path
415
454
416 def localpath(path):
455 def localpath(path):
417 return path
456 return path
418
457
419 normpath = os.path.normpath
458 normpath = os.path.normpath
420
459
421 def makelock(info, pathname):
460 def makelock(info, pathname):
422 try:
461 try:
423 os.symlink(info, pathname)
462 os.symlink(info, pathname)
424 except OSError, why:
463 except OSError, why:
425 if why.errno == errno.EEXIST:
464 if why.errno == errno.EEXIST:
426 raise
465 raise
427 else:
466 else:
428 _makelock_file(info, pathname)
467 _makelock_file(info, pathname)
429
468
430 def readlock(pathname):
469 def readlock(pathname):
431 try:
470 try:
432 return os.readlink(pathname)
471 return os.readlink(pathname)
433 except OSError, why:
472 except OSError, why:
434 if why.errno == errno.EINVAL:
473 if why.errno == errno.EINVAL:
435 return _readlock_file(pathname)
474 return _readlock_file(pathname)
436 else:
475 else:
437 raise
476 raise
438
477
439 def explain_exit(code):
478 def explain_exit(code):
440 """return a 2-tuple (desc, code) describing a process's status"""
479 """return a 2-tuple (desc, code) describing a process's status"""
441 if os.WIFEXITED(code):
480 if os.WIFEXITED(code):
442 val = os.WEXITSTATUS(code)
481 val = os.WEXITSTATUS(code)
443 return "exited with status %d" % val, val
482 return "exited with status %d" % val, val
444 elif os.WIFSIGNALED(code):
483 elif os.WIFSIGNALED(code):
445 val = os.WTERMSIG(code)
484 val = os.WTERMSIG(code)
446 return "killed by signal %d" % val, val
485 return "killed by signal %d" % val, val
447 elif os.WIFSTOPPED(code):
486 elif os.WIFSTOPPED(code):
448 val = os.WSTOPSIG(code)
487 val = os.WSTOPSIG(code)
449 return "stopped by signal %d" % val, val
488 return "stopped by signal %d" % val, val
450 raise ValueError("invalid exit code")
489 raise ValueError("invalid exit code")
451
490
452 class chunkbuffer(object):
491 class chunkbuffer(object):
453 """Allow arbitrary sized chunks of data to be efficiently read from an
492 """Allow arbitrary sized chunks of data to be efficiently read from an
454 iterator over chunks of arbitrary size."""
493 iterator over chunks of arbitrary size."""
455
494
456 def __init__(self, in_iter, targetsize = 2**16):
495 def __init__(self, in_iter, targetsize = 2**16):
457 """in_iter is the iterator that's iterating over the input chunks.
496 """in_iter is the iterator that's iterating over the input chunks.
458 targetsize is how big a buffer to try to maintain."""
497 targetsize is how big a buffer to try to maintain."""
459 self.in_iter = iter(in_iter)
498 self.in_iter = iter(in_iter)
460 self.buf = ''
499 self.buf = ''
461 self.targetsize = int(targetsize)
500 self.targetsize = int(targetsize)
462 if self.targetsize <= 0:
501 if self.targetsize <= 0:
463 raise ValueError("targetsize must be greater than 0, was %d" %
502 raise ValueError("targetsize must be greater than 0, was %d" %
464 targetsize)
503 targetsize)
465 self.iterempty = False
504 self.iterempty = False
466
505
467 def fillbuf(self):
506 def fillbuf(self):
468 """Ignore target size; read every chunk from iterator until empty."""
507 """Ignore target size; read every chunk from iterator until empty."""
469 if not self.iterempty:
508 if not self.iterempty:
470 collector = cStringIO.StringIO()
509 collector = cStringIO.StringIO()
471 collector.write(self.buf)
510 collector.write(self.buf)
472 for ch in self.in_iter:
511 for ch in self.in_iter:
473 collector.write(ch)
512 collector.write(ch)
474 self.buf = collector.getvalue()
513 self.buf = collector.getvalue()
475 self.iterempty = True
514 self.iterempty = True
476
515
477 def read(self, l):
516 def read(self, l):
478 """Read L bytes of data from the iterator of chunks of data.
517 """Read L bytes of data from the iterator of chunks of data.
479 Returns less than L bytes if the iterator runs dry."""
518 Returns less than L bytes if the iterator runs dry."""
480 if l > len(self.buf) and not self.iterempty:
519 if l > len(self.buf) and not self.iterempty:
481 # Clamp to a multiple of self.targetsize
520 # Clamp to a multiple of self.targetsize
482 targetsize = self.targetsize * ((l // self.targetsize) + 1)
521 targetsize = self.targetsize * ((l // self.targetsize) + 1)
483 collector = cStringIO.StringIO()
522 collector = cStringIO.StringIO()
484 collector.write(self.buf)
523 collector.write(self.buf)
485 collected = len(self.buf)
524 collected = len(self.buf)
486 for chunk in self.in_iter:
525 for chunk in self.in_iter:
487 collector.write(chunk)
526 collector.write(chunk)
488 collected += len(chunk)
527 collected += len(chunk)
489 if collected >= targetsize:
528 if collected >= targetsize:
490 break
529 break
491 if collected < targetsize:
530 if collected < targetsize:
492 self.iterempty = True
531 self.iterempty = True
493 self.buf = collector.getvalue()
532 self.buf = collector.getvalue()
494 s, self.buf = self.buf[:l], buffer(self.buf, l)
533 s, self.buf = self.buf[:l], buffer(self.buf, l)
495 return s
534 return s
496
535
497 def filechunkiter(f, size = 65536):
536 def filechunkiter(f, size = 65536):
498 """Create a generator that produces all the data in the file size
537 """Create a generator that produces all the data in the file size
499 (default 65536) bytes at a time. Chunks may be less than size
538 (default 65536) bytes at a time. Chunks may be less than size
500 bytes if the chunk is the last chunk in the file, or the file is a
539 bytes if the chunk is the last chunk in the file, or the file is a
501 socket or some other type of file that sometimes reads less data
540 socket or some other type of file that sometimes reads less data
502 than is requested."""
541 than is requested."""
503 s = f.read(size)
542 s = f.read(size)
504 while len(s) >= 0:
543 while len(s) >= 0:
505 yield s
544 yield s
506 s = f.read(size)
545 s = f.read(size)
General Comments 0
You need to be logged in to leave comments. Login now