##// END OF EJS Templates
formatter: add pickle format...
Matt Mackall -
r22430:968247e8 default
parent child Browse files
Show More
@@ -1,119 +1,132
1 1 # formatter.py - generic output formatting for mercurial
2 2 #
3 3 # Copyright 2012 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 import cPickle
8 9 from i18n import _
9 10 import encoding, util
10 11
11 12 class baseformatter(object):
12 13 def __init__(self, ui, topic, opts):
13 14 self._ui = ui
14 15 self._topic = topic
15 16 self._style = opts.get("style")
16 17 self._template = opts.get("template")
17 18 self._item = None
18 19 def __bool__(self):
19 20 '''return False if we're not doing real templating so we can
20 21 skip extra work'''
21 22 return True
22 23 def _showitem(self):
23 24 '''show a formatted item once all data is collected'''
24 25 pass
25 26 def startitem(self):
26 27 '''begin an item in the format list'''
27 28 if self._item is not None:
28 29 self._showitem()
29 30 self._item = {}
30 31 def data(self, **data):
31 32 '''insert data into item that's not shown in default output'''
32 33 self._item.update(data)
33 34 def write(self, fields, deftext, *fielddata, **opts):
34 35 '''do default text output while assigning data to item'''
35 36 for k, v in zip(fields.split(), fielddata):
36 37 self._item[k] = v
37 38 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
38 39 '''do conditional write (primarily for plain formatter)'''
39 40 for k, v in zip(fields.split(), fielddata):
40 41 self._item[k] = v
41 42 def plain(self, text, **opts):
42 43 '''show raw text for non-templated mode'''
43 44 pass
44 45 def end(self):
45 46 '''end output for the formatter'''
46 47 if self._item is not None:
47 48 self._showitem()
48 49
49 50 class plainformatter(baseformatter):
50 51 '''the default text output scheme'''
51 52 def __init__(self, ui, topic, opts):
52 53 baseformatter.__init__(self, ui, topic, opts)
53 54 def __bool__(self):
54 55 return False
55 56 def startitem(self):
56 57 pass
57 58 def data(self, **data):
58 59 pass
59 60 def write(self, fields, deftext, *fielddata, **opts):
60 61 self._ui.write(deftext % fielddata, **opts)
61 62 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
62 63 '''do conditional write'''
63 64 if cond:
64 65 self._ui.write(deftext % fielddata, **opts)
65 66 def plain(self, text, **opts):
66 67 self._ui.write(text, **opts)
67 68 def end(self):
68 69 pass
69 70
70 71 class debugformatter(baseformatter):
71 72 def __init__(self, ui, topic, opts):
72 73 baseformatter.__init__(self, ui, topic, opts)
73 74 self._ui.write("%s = [\n" % self._topic)
74 75 def _showitem(self):
75 76 self._ui.write(" " + repr(self._item) + ",\n")
76 77 def end(self):
77 78 baseformatter.end(self)
78 79 self._ui.write("]\n")
79 80
81 class pickleformatter(baseformatter):
82 def __init__(self, ui, topic, opts):
83 baseformatter.__init__(self, ui, topic, opts)
84 self._data = []
85 def _showitem(self):
86 self._data.append(self._item)
87 def end(self):
88 baseformatter.end(self)
89 self._ui.write(cPickle.dumps(self._data))
90
80 91 class jsonformatter(baseformatter):
81 92 def __init__(self, ui, topic, opts):
82 93 baseformatter.__init__(self, ui, topic, opts)
83 94 self._ui.write("[")
84 95 self._ui._first = True
85 96 def _showitem(self):
86 97 if self._ui._first:
87 98 self._ui._first = False
88 99 else:
89 100 self._ui.write(",")
90 101
91 102 self._ui.write("\n {\n")
92 103 first = True
93 104 for k, v in sorted(self._item.items()):
94 105 if first:
95 106 first = False
96 107 else:
97 108 self._ui.write(",\n")
98 109 if isinstance(v, int):
99 110 self._ui.write(' "%s": %d' % (k, v))
100 111 else:
101 112 self._ui.write(' "%s": "%s"' % (k, encoding.jsonescape(v)))
102 113 self._ui.write("\n }")
103 114 def end(self):
104 115 baseformatter.end(self)
105 116 self._ui.write("\n]\n")
106 117
107 118 def formatter(ui, topic, opts):
108 119 template = opts.get("template", "")
109 120 if template == "json":
110 121 return jsonformatter(ui, topic, opts)
122 elif template == "pickle":
123 return pickleformatter(ui, topic, opts)
111 124 elif template == "debug":
112 125 return debugformatter(ui, topic, opts)
113 126 elif template != "":
114 127 raise util.Abort(_("custom templates not yet supported"))
115 128 elif ui.configbool('ui', 'formatdebug'):
116 129 return debugformatter(ui, topic, opts)
117 130 elif ui.configbool('ui', 'formatjson'):
118 131 return jsonformatter(ui, topic, opts)
119 132 return plainformatter(ui, topic, opts)
@@ -1,131 +1,141
1 1 $ hg init repo
2 2 $ cd repo
3 3 $ echo 0 > a
4 4 $ echo 0 > b
5 5 $ echo 0 > t.h
6 6 $ mkdir t
7 7 $ echo 0 > t/x
8 8 $ echo 0 > t/b
9 9 $ echo 0 > t/e.h
10 10 $ mkdir dir.h
11 11 $ echo 0 > dir.h/foo
12 12
13 13 $ hg ci -A -m m
14 14 adding a
15 15 adding b
16 16 adding dir.h/foo
17 17 adding t.h
18 18 adding t/b
19 19 adding t/e.h
20 20 adding t/x
21 21
22 22 $ touch nottracked
23 23
24 24 $ hg locate a
25 25 a
26 26
27 27 $ hg locate NONEXISTENT
28 28 [1]
29 29
30 30 $ hg locate
31 31 a
32 32 b
33 33 dir.h/foo
34 34 t.h
35 35 t/b
36 36 t/e.h
37 37 t/x
38 38
39 39 $ hg rm a
40 40 $ hg ci -m m
41 41
42 42 $ hg locate a
43 43 [1]
44 44 $ hg locate NONEXISTENT
45 45 [1]
46 46 $ hg locate relpath:NONEXISTENT
47 47 [1]
48 48 $ hg locate
49 49 b
50 50 dir.h/foo
51 51 t.h
52 52 t/b
53 53 t/e.h
54 54 t/x
55 55 $ hg locate -r 0 a
56 56 a
57 57 $ hg locate -r 0 NONEXISTENT
58 58 [1]
59 59 $ hg locate -r 0 relpath:NONEXISTENT
60 60 [1]
61 61 $ hg locate -r 0
62 62 a
63 63 b
64 64 dir.h/foo
65 65 t.h
66 66 t/b
67 67 t/e.h
68 68 t/x
69 69
70 70 -I/-X with relative path should work:
71 71
72 72 $ cd t
73 73 $ hg locate
74 74 b
75 75 dir.h/foo
76 76 t.h
77 77 t/b
78 78 t/e.h
79 79 t/x
80 80 $ hg locate -I ../t
81 81 t/b
82 82 t/e.h
83 83 t/x
84 84
85 85 Issue294: hg remove --after dir fails when dir.* also exists
86 86
87 87 $ cd ..
88 88 $ rm -r t
89 89
90 90 $ hg locate 't/**'
91 91 t/b (glob)
92 92 t/e.h (glob)
93 93 t/x (glob)
94 94
95 95 $ hg files
96 96 b
97 97 dir.h/foo
98 98 t.h
99 99 t/b
100 100 t/e.h
101 101 t/x
102 102 $ hg files b
103 103 b
104 104
105 105 $ mkdir otherdir
106 106 $ cd otherdir
107 107
108 108 $ hg locate b
109 109 ../b (glob)
110 110 ../t/b (glob)
111 111 $ hg locate '*.h'
112 112 ../t.h (glob)
113 113 ../t/e.h (glob)
114 114 $ hg locate path:t/x
115 115 ../t/x (glob)
116 116 $ hg locate 're:.*\.h$'
117 117 ../t.h (glob)
118 118 ../t/e.h (glob)
119 119 $ hg locate -r 0 b
120 120 ../b (glob)
121 121 ../t/b (glob)
122 122 $ hg locate -r 0 '*.h'
123 123 ../t.h (glob)
124 124 ../t/e.h (glob)
125 125 $ hg locate -r 0 path:t/x
126 126 ../t/x (glob)
127 127 $ hg locate -r 0 're:.*\.h$'
128 128 ../t.h (glob)
129 129 ../t/e.h (glob)
130 130
131 $ hg files
132 ../b
133 ../dir.h/foo
134 ../t.h
135 ../t/b
136 ../t/e.h
137 ../t/x
138 $ hg files .
139 [1]
140
131 141 $ cd ../..
@@ -1,399 +1,405
1 1 $ hg init repo1
2 2 $ cd repo1
3 3 $ mkdir a b a/1 b/1 b/2
4 4 $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
5 5
6 6 hg status in repo root:
7 7
8 8 $ hg status
9 9 ? a/1/in_a_1
10 10 ? a/in_a
11 11 ? b/1/in_b_1
12 12 ? b/2/in_b_2
13 13 ? b/in_b
14 14 ? in_root
15 15
16 16 hg status . in repo root:
17 17
18 18 $ hg status .
19 19 ? a/1/in_a_1
20 20 ? a/in_a
21 21 ? b/1/in_b_1
22 22 ? b/2/in_b_2
23 23 ? b/in_b
24 24 ? in_root
25 25
26 26 $ hg status --cwd a
27 27 ? a/1/in_a_1
28 28 ? a/in_a
29 29 ? b/1/in_b_1
30 30 ? b/2/in_b_2
31 31 ? b/in_b
32 32 ? in_root
33 33 $ hg status --cwd a .
34 34 ? 1/in_a_1
35 35 ? in_a
36 36 $ hg status --cwd a ..
37 37 ? 1/in_a_1
38 38 ? in_a
39 39 ? ../b/1/in_b_1
40 40 ? ../b/2/in_b_2
41 41 ? ../b/in_b
42 42 ? ../in_root
43 43
44 44 $ hg status --cwd b
45 45 ? a/1/in_a_1
46 46 ? a/in_a
47 47 ? b/1/in_b_1
48 48 ? b/2/in_b_2
49 49 ? b/in_b
50 50 ? in_root
51 51 $ hg status --cwd b .
52 52 ? 1/in_b_1
53 53 ? 2/in_b_2
54 54 ? in_b
55 55 $ hg status --cwd b ..
56 56 ? ../a/1/in_a_1
57 57 ? ../a/in_a
58 58 ? 1/in_b_1
59 59 ? 2/in_b_2
60 60 ? in_b
61 61 ? ../in_root
62 62
63 63 $ hg status --cwd a/1
64 64 ? a/1/in_a_1
65 65 ? a/in_a
66 66 ? b/1/in_b_1
67 67 ? b/2/in_b_2
68 68 ? b/in_b
69 69 ? in_root
70 70 $ hg status --cwd a/1 .
71 71 ? in_a_1
72 72 $ hg status --cwd a/1 ..
73 73 ? in_a_1
74 74 ? ../in_a
75 75
76 76 $ hg status --cwd b/1
77 77 ? a/1/in_a_1
78 78 ? a/in_a
79 79 ? b/1/in_b_1
80 80 ? b/2/in_b_2
81 81 ? b/in_b
82 82 ? in_root
83 83 $ hg status --cwd b/1 .
84 84 ? in_b_1
85 85 $ hg status --cwd b/1 ..
86 86 ? in_b_1
87 87 ? ../2/in_b_2
88 88 ? ../in_b
89 89
90 90 $ hg status --cwd b/2
91 91 ? a/1/in_a_1
92 92 ? a/in_a
93 93 ? b/1/in_b_1
94 94 ? b/2/in_b_2
95 95 ? b/in_b
96 96 ? in_root
97 97 $ hg status --cwd b/2 .
98 98 ? in_b_2
99 99 $ hg status --cwd b/2 ..
100 100 ? ../1/in_b_1
101 101 ? in_b_2
102 102 ? ../in_b
103 103
104 104 combining patterns with root and patterns without a root works
105 105
106 106 $ hg st a/in_a re:.*b$
107 107 ? a/in_a
108 108 ? b/in_b
109 109
110 110 $ cd ..
111 111
112 112 $ hg init repo2
113 113 $ cd repo2
114 114 $ touch modified removed deleted ignored
115 115 $ echo "^ignored$" > .hgignore
116 116 $ hg ci -A -m 'initial checkin'
117 117 adding .hgignore
118 118 adding deleted
119 119 adding modified
120 120 adding removed
121 121 $ touch modified added unknown ignored
122 122 $ hg add added
123 123 $ hg remove removed
124 124 $ rm deleted
125 125
126 126 hg status:
127 127
128 128 $ hg status
129 129 A added
130 130 R removed
131 131 ! deleted
132 132 ? unknown
133 133
134 134 hg status modified added removed deleted unknown never-existed ignored:
135 135
136 136 $ hg status modified added removed deleted unknown never-existed ignored
137 137 never-existed: * (glob)
138 138 A added
139 139 R removed
140 140 ! deleted
141 141 ? unknown
142 142
143 143 $ hg copy modified copied
144 144
145 145 hg status -C:
146 146
147 147 $ hg status -C
148 148 A added
149 149 A copied
150 150 modified
151 151 R removed
152 152 ! deleted
153 153 ? unknown
154 154
155 155 hg status -A:
156 156
157 157 $ hg status -A
158 158 A added
159 159 A copied
160 160 modified
161 161 R removed
162 162 ! deleted
163 163 ? unknown
164 164 I ignored
165 165 C .hgignore
166 166 C modified
167 167
168 168 $ hg status -A -Tjson
169 169 [
170 170 {
171 171 "path": "added",
172 172 "status": "A"
173 173 },
174 174 {
175 175 "copy": "modified",
176 176 "path": "copied",
177 177 "status": "A"
178 178 },
179 179 {
180 180 "path": "removed",
181 181 "status": "R"
182 182 },
183 183 {
184 184 "path": "deleted",
185 185 "status": "!"
186 186 },
187 187 {
188 188 "path": "unknown",
189 189 "status": "?"
190 190 },
191 191 {
192 192 "path": "ignored",
193 193 "status": "I"
194 194 },
195 195 {
196 196 "path": ".hgignore",
197 197 "status": "C"
198 198 },
199 199 {
200 200 "path": "modified",
201 201 "status": "C"
202 202 }
203 203 ]
204 204
205 $ hg status -A -Tpickle > pickle
206 >>> import pickle
207 >>> print sorted((x['status'], x['path']) for x in pickle.load(open("pickle")))
208 [('!', 'deleted'), ('?', 'pickle'), ('?', 'unknown'), ('A', 'added'), ('A', 'copied'), ('C', '.hgignore'), ('C', 'modified'), ('I', 'ignored'), ('R', 'removed')]
209 $ rm pickle
210
205 211 $ echo "^ignoreddir$" > .hgignore
206 212 $ mkdir ignoreddir
207 213 $ touch ignoreddir/file
208 214
209 215 hg status ignoreddir/file:
210 216
211 217 $ hg status ignoreddir/file
212 218
213 219 hg status -i ignoreddir/file:
214 220
215 221 $ hg status -i ignoreddir/file
216 222 I ignoreddir/file
217 223 $ cd ..
218 224
219 225 Check 'status -q' and some combinations
220 226
221 227 $ hg init repo3
222 228 $ cd repo3
223 229 $ touch modified removed deleted ignored
224 230 $ echo "^ignored$" > .hgignore
225 231 $ hg commit -A -m 'initial checkin'
226 232 adding .hgignore
227 233 adding deleted
228 234 adding modified
229 235 adding removed
230 236 $ touch added unknown ignored
231 237 $ hg add added
232 238 $ echo "test" >> modified
233 239 $ hg remove removed
234 240 $ rm deleted
235 241 $ hg copy modified copied
236 242
237 243 Run status with 2 different flags.
238 244 Check if result is the same or different.
239 245 If result is not as expected, raise error
240 246
241 247 $ assert() {
242 248 > hg status $1 > ../a
243 249 > hg status $2 > ../b
244 250 > if diff ../a ../b > /dev/null; then
245 251 > out=0
246 252 > else
247 253 > out=1
248 254 > fi
249 255 > if [ $3 -eq 0 ]; then
250 256 > df="same"
251 257 > else
252 258 > df="different"
253 259 > fi
254 260 > if [ $out -ne $3 ]; then
255 261 > echo "Error on $1 and $2, should be $df."
256 262 > fi
257 263 > }
258 264
259 265 Assert flag1 flag2 [0-same | 1-different]
260 266
261 267 $ assert "-q" "-mard" 0
262 268 $ assert "-A" "-marduicC" 0
263 269 $ assert "-qA" "-mardcC" 0
264 270 $ assert "-qAui" "-A" 0
265 271 $ assert "-qAu" "-marducC" 0
266 272 $ assert "-qAi" "-mardicC" 0
267 273 $ assert "-qu" "-u" 0
268 274 $ assert "-q" "-u" 1
269 275 $ assert "-m" "-a" 1
270 276 $ assert "-r" "-d" 1
271 277 $ cd ..
272 278
273 279 $ hg init repo4
274 280 $ cd repo4
275 281 $ touch modified removed deleted
276 282 $ hg ci -q -A -m 'initial checkin'
277 283 $ touch added unknown
278 284 $ hg add added
279 285 $ hg remove removed
280 286 $ rm deleted
281 287 $ echo x > modified
282 288 $ hg copy modified copied
283 289 $ hg ci -m 'test checkin' -d "1000001 0"
284 290 $ rm *
285 291 $ touch unrelated
286 292 $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0"
287 293
288 294 hg status --change 1:
289 295
290 296 $ hg status --change 1
291 297 M modified
292 298 A added
293 299 A copied
294 300 R removed
295 301
296 302 hg status --change 1 unrelated:
297 303
298 304 $ hg status --change 1 unrelated
299 305
300 306 hg status -C --change 1 added modified copied removed deleted:
301 307
302 308 $ hg status -C --change 1 added modified copied removed deleted
303 309 M modified
304 310 A added
305 311 A copied
306 312 modified
307 313 R removed
308 314
309 315 hg status -A --change 1 and revset:
310 316
311 317 $ hg status -A --change '1|1'
312 318 M modified
313 319 A added
314 320 A copied
315 321 modified
316 322 R removed
317 323 C deleted
318 324
319 325 status against non-parent with unknown file (issue4321)
320 326
321 327 $ touch unknown
322 328 $ hg status --rev 0 unknown
323 329 ? unknown
324 330
325 331 status of removed but existing in working directory. "? removed" should
326 332 not be included:
327 333
328 334 $ touch removed
329 335 $ hg status --rev 0 removed
330 336 R removed
331 337
332 338 $ cd ..
333 339
334 340 hg status of binary file starting with '\1\n', a separator for metadata:
335 341
336 342 $ hg init repo5
337 343 $ cd repo5
338 344 >>> open("010a", "wb").write("\1\nfoo")
339 345 $ hg ci -q -A -m 'initial checkin'
340 346 $ hg status -A
341 347 C 010a
342 348
343 349 >>> open("010a", "wb").write("\1\nbar")
344 350 $ hg status -A
345 351 M 010a
346 352 $ hg ci -q -m 'modify 010a'
347 353 $ hg status -A --rev 0:1
348 354 M 010a
349 355
350 356 $ touch empty
351 357 $ hg ci -q -A -m 'add another file'
352 358 $ hg status -A --rev 1:2 010a
353 359 C 010a
354 360
355 361 $ cd ..
356 362
357 363 test "hg status" with "directory pattern" which matches against files
358 364 only known on target revision.
359 365
360 366 $ hg init repo6
361 367 $ cd repo6
362 368
363 369 $ echo a > a.txt
364 370 $ hg add a.txt
365 371 $ hg commit -m '#0'
366 372 $ mkdir -p 1/2/3/4/5
367 373 $ echo b > 1/2/3/4/5/b.txt
368 374 $ hg add 1/2/3/4/5/b.txt
369 375 $ hg commit -m '#1'
370 376
371 377 $ hg update -C 0 > /dev/null
372 378 $ hg status -A
373 379 C a.txt
374 380
375 381 the directory matching against specified pattern should be removed,
376 382 because directory existence prevents 'dirstate.walk()' from showing
377 383 warning message about such pattern.
378 384
379 385 $ test ! -d 1
380 386 $ hg status -A --rev 1 1/2/3/4/5/b.txt
381 387 R 1/2/3/4/5/b.txt
382 388 $ hg status -A --rev 1 1/2/3/4/5
383 389 R 1/2/3/4/5/b.txt
384 390 $ hg status -A --rev 1 1/2/3
385 391 R 1/2/3/4/5/b.txt
386 392 $ hg status -A --rev 1 1
387 393 R 1/2/3/4/5/b.txt
388 394
389 395 $ hg status --config ui.formatdebug=True --rev 1 1
390 396 status = [
391 397 {*'path': '1/2/3/4/5/b.txt'*}, (glob)
392 398 ]
393 399
394 400 #if windows
395 401 $ hg --config ui.slash=false status -A --rev 1 1
396 402 R 1\2\3\4\5\b.txt
397 403 #endif
398 404
399 405 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now