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