Show More
@@ -67,20 +67,53 b' decode/encode::' | |||||
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. |
@@ -12,10 +12,10 b' platform-specific details from the core.' | |||||
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 |
|
|
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) | |
@@ -30,6 +30,45 b' def filter(s, cmd):' | |||||
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""" | |
@@ -43,7 +82,7 b' def patch(strip, patchname, ui):' | |||||
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: |
|
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): |
General Comments 0
You need to be logged in to leave comments.
Login now