14 from .i18n import _ |
14 from .i18n import _ |
15 from . import encoding |
15 from . import encoding |
16 |
16 |
17 |
17 |
18 def spacejoin(*args): |
18 def spacejoin(*args): |
19 return ' '.join(s for s in args if s) |
19 return b' '.join(s for s in args if s) |
20 |
20 |
21 |
21 |
22 def shouldprint(ui): |
22 def shouldprint(ui): |
23 return not (ui.quiet or ui.plain('progress')) and ( |
23 return not (ui.quiet or ui.plain(b'progress')) and ( |
24 ui._isatty(ui.ferr) or ui.configbool('progress', 'assume-tty') |
24 ui._isatty(ui.ferr) or ui.configbool(b'progress', b'assume-tty') |
25 ) |
25 ) |
26 |
26 |
27 |
27 |
28 def fmtremaining(seconds): |
28 def fmtremaining(seconds): |
29 """format a number of remaining seconds in human readable way |
29 """format a number of remaining seconds in human readable way |
30 |
30 |
31 This will properly display seconds, minutes, hours, days if needed""" |
31 This will properly display seconds, minutes, hours, days if needed""" |
32 if seconds < 60: |
32 if seconds < 60: |
33 # i18n: format XX seconds as "XXs" |
33 # i18n: format XX seconds as "XXs" |
34 return _("%02ds") % seconds |
34 return _(b"%02ds") % seconds |
35 minutes = seconds // 60 |
35 minutes = seconds // 60 |
36 if minutes < 60: |
36 if minutes < 60: |
37 seconds -= minutes * 60 |
37 seconds -= minutes * 60 |
38 # i18n: format X minutes and YY seconds as "XmYYs" |
38 # i18n: format X minutes and YY seconds as "XmYYs" |
39 return _("%dm%02ds") % (minutes, seconds) |
39 return _(b"%dm%02ds") % (minutes, seconds) |
40 # we're going to ignore seconds in this case |
40 # we're going to ignore seconds in this case |
41 minutes += 1 |
41 minutes += 1 |
42 hours = minutes // 60 |
42 hours = minutes // 60 |
43 minutes -= hours * 60 |
43 minutes -= hours * 60 |
44 if hours < 30: |
44 if hours < 30: |
45 # i18n: format X hours and YY minutes as "XhYYm" |
45 # i18n: format X hours and YY minutes as "XhYYm" |
46 return _("%dh%02dm") % (hours, minutes) |
46 return _(b"%dh%02dm") % (hours, minutes) |
47 # we're going to ignore minutes in this case |
47 # we're going to ignore minutes in this case |
48 hours += 1 |
48 hours += 1 |
49 days = hours // 24 |
49 days = hours // 24 |
50 hours -= days * 24 |
50 hours -= days * 24 |
51 if days < 15: |
51 if days < 15: |
52 # i18n: format X days and YY hours as "XdYYh" |
52 # i18n: format X days and YY hours as "XdYYh" |
53 return _("%dd%02dh") % (days, hours) |
53 return _(b"%dd%02dh") % (days, hours) |
54 # we're going to ignore hours in this case |
54 # we're going to ignore hours in this case |
55 days += 1 |
55 days += 1 |
56 weeks = days // 7 |
56 weeks = days // 7 |
57 days -= weeks * 7 |
57 days -= weeks * 7 |
58 if weeks < 55: |
58 if weeks < 55: |
59 # i18n: format X weeks and YY days as "XwYYd" |
59 # i18n: format X weeks and YY days as "XwYYd" |
60 return _("%dw%02dd") % (weeks, days) |
60 return _(b"%dw%02dd") % (weeks, days) |
61 # we're going to ignore days and treat a year as 52 weeks |
61 # we're going to ignore days and treat a year as 52 weeks |
62 weeks += 1 |
62 weeks += 1 |
63 years = weeks // 52 |
63 years = weeks // 52 |
64 weeks -= years * 52 |
64 weeks -= years * 52 |
65 # i18n: format X years and YY weeks as "XyYYw" |
65 # i18n: format X years and YY weeks as "XyYYw" |
66 return _("%dy%02dw") % (years, weeks) |
66 return _(b"%dy%02dw") % (years, weeks) |
67 |
67 |
68 |
68 |
69 # file_write() and file_flush() of Python 2 do not restart on EINTR if |
69 # file_write() and file_flush() of Python 2 do not restart on EINTR if |
70 # the file is attached to a "slow" device (e.g. a terminal) and raise |
70 # the file is attached to a "slow" device (e.g. a terminal) and raise |
71 # IOError. We cannot know how many bytes would be written by file_write(), |
71 # IOError. We cannot know how many bytes would be written by file_write(), |
96 self.topicstates = {} |
96 self.topicstates = {} |
97 self.starttimes = {} |
97 self.starttimes = {} |
98 self.startvals = {} |
98 self.startvals = {} |
99 self.printed = False |
99 self.printed = False |
100 self.lastprint = time.time() + float( |
100 self.lastprint = time.time() + float( |
101 self.ui.config('progress', 'delay') |
101 self.ui.config(b'progress', b'delay') |
102 ) |
102 ) |
103 self.curtopic = None |
103 self.curtopic = None |
104 self.lasttopic = None |
104 self.lasttopic = None |
105 self.indetcount = 0 |
105 self.indetcount = 0 |
106 self.refresh = float(self.ui.config('progress', 'refresh')) |
106 self.refresh = float(self.ui.config(b'progress', b'refresh')) |
107 self.changedelay = max( |
107 self.changedelay = max( |
108 3 * self.refresh, float(self.ui.config('progress', 'changedelay')) |
108 3 * self.refresh, float(self.ui.config(b'progress', b'changedelay')) |
109 ) |
109 ) |
110 self.order = self.ui.configlist('progress', 'format') |
110 self.order = self.ui.configlist(b'progress', b'format') |
111 self.estimateinterval = self.ui.configwith( |
111 self.estimateinterval = self.ui.configwith( |
112 float, 'progress', 'estimateinterval' |
112 float, b'progress', b'estimateinterval' |
113 ) |
113 ) |
114 |
114 |
115 def show(self, now, topic, pos, item, unit, total): |
115 def show(self, now, topic, pos, item, unit, total): |
116 if not shouldprint(self.ui): |
116 if not shouldprint(self.ui): |
117 return |
117 return |
118 termwidth = self.width() |
118 termwidth = self.width() |
119 self.printed = True |
119 self.printed = True |
120 head = '' |
120 head = b'' |
121 needprogress = False |
121 needprogress = False |
122 tail = '' |
122 tail = b'' |
123 for indicator in self.order: |
123 for indicator in self.order: |
124 add = '' |
124 add = b'' |
125 if indicator == 'topic': |
125 if indicator == b'topic': |
126 add = topic |
126 add = topic |
127 elif indicator == 'number': |
127 elif indicator == b'number': |
128 if total: |
128 if total: |
129 add = b'%*d/%d' % (len(str(total)), pos, total) |
129 add = b'%*d/%d' % (len(str(total)), pos, total) |
130 else: |
130 else: |
131 add = b'%d' % pos |
131 add = b'%d' % pos |
132 elif indicator.startswith('item') and item: |
132 elif indicator.startswith(b'item') and item: |
133 slice = 'end' |
133 slice = b'end' |
134 if '-' in indicator: |
134 if b'-' in indicator: |
135 wid = int(indicator.split('-')[1]) |
135 wid = int(indicator.split(b'-')[1]) |
136 elif '+' in indicator: |
136 elif b'+' in indicator: |
137 slice = 'beginning' |
137 slice = b'beginning' |
138 wid = int(indicator.split('+')[1]) |
138 wid = int(indicator.split(b'+')[1]) |
139 else: |
139 else: |
140 wid = 20 |
140 wid = 20 |
141 if slice == 'end': |
141 if slice == b'end': |
142 add = encoding.trim(item, wid, leftside=True) |
142 add = encoding.trim(item, wid, leftside=True) |
143 else: |
143 else: |
144 add = encoding.trim(item, wid) |
144 add = encoding.trim(item, wid) |
145 add += (wid - encoding.colwidth(add)) * ' ' |
145 add += (wid - encoding.colwidth(add)) * b' ' |
146 elif indicator == 'bar': |
146 elif indicator == b'bar': |
147 add = '' |
147 add = b'' |
148 needprogress = True |
148 needprogress = True |
149 elif indicator == 'unit' and unit: |
149 elif indicator == b'unit' and unit: |
150 add = unit |
150 add = unit |
151 elif indicator == 'estimate': |
151 elif indicator == b'estimate': |
152 add = self.estimate(topic, pos, total, now) |
152 add = self.estimate(topic, pos, total, now) |
153 elif indicator == 'speed': |
153 elif indicator == b'speed': |
154 add = self.speed(topic, pos, unit, now) |
154 add = self.speed(topic, pos, unit, now) |
155 if not needprogress: |
155 if not needprogress: |
156 head = spacejoin(head, add) |
156 head = spacejoin(head, add) |
157 else: |
157 else: |
158 tail = spacejoin(tail, add) |
158 tail = spacejoin(tail, add) |
163 if tail: |
163 if tail: |
164 used += encoding.colwidth(tail) + 1 |
164 used += encoding.colwidth(tail) + 1 |
165 progwidth = termwidth - used - 3 |
165 progwidth = termwidth - used - 3 |
166 if total and pos <= total: |
166 if total and pos <= total: |
167 amt = pos * progwidth // total |
167 amt = pos * progwidth // total |
168 bar = '=' * (amt - 1) |
168 bar = b'=' * (amt - 1) |
169 if amt > 0: |
169 if amt > 0: |
170 bar += '>' |
170 bar += b'>' |
171 bar += ' ' * (progwidth - amt) |
171 bar += b' ' * (progwidth - amt) |
172 else: |
172 else: |
173 progwidth -= 3 |
173 progwidth -= 3 |
174 self.indetcount += 1 |
174 self.indetcount += 1 |
175 # mod the count by twice the width so we can make the |
175 # mod the count by twice the width so we can make the |
176 # cursor bounce between the right and left sides |
176 # cursor bounce between the right and left sides |
177 amt = self.indetcount % (2 * progwidth) |
177 amt = self.indetcount % (2 * progwidth) |
178 amt -= progwidth |
178 amt -= progwidth |
179 bar = ( |
179 bar = ( |
180 ' ' * int(progwidth - abs(amt)) |
180 b' ' * int(progwidth - abs(amt)) |
181 + '<=>' |
181 + b'<=>' |
182 + ' ' * int(abs(amt)) |
182 + b' ' * int(abs(amt)) |
183 ) |
183 ) |
184 prog = ''.join(('[', bar, ']')) |
184 prog = b''.join((b'[', bar, b']')) |
185 out = spacejoin(head, prog, tail) |
185 out = spacejoin(head, prog, tail) |
186 else: |
186 else: |
187 out = spacejoin(head, tail) |
187 out = spacejoin(head, tail) |
188 self._writeerr('\r' + encoding.trim(out, termwidth)) |
188 self._writeerr(b'\r' + encoding.trim(out, termwidth)) |
189 self.lasttopic = topic |
189 self.lasttopic = topic |
190 self._flusherr() |
190 self._flusherr() |
191 |
191 |
192 def clear(self): |
192 def clear(self): |
193 if not self.printed or not self.lastprint or not shouldprint(self.ui): |
193 if not self.printed or not self.lastprint or not shouldprint(self.ui): |
194 return |
194 return |
195 self._writeerr('\r%s\r' % (' ' * self.width())) |
195 self._writeerr(b'\r%s\r' % (b' ' * self.width())) |
196 if self.printed: |
196 if self.printed: |
197 # force immediate re-paint of progress bar |
197 # force immediate re-paint of progress bar |
198 self.lastprint = 0 |
198 self.lastprint = 0 |
199 |
199 |
200 def complete(self): |
200 def complete(self): |
201 if not shouldprint(self.ui): |
201 if not shouldprint(self.ui): |
202 return |
202 return |
203 if self.ui.configbool('progress', 'clear-complete'): |
203 if self.ui.configbool(b'progress', b'clear-complete'): |
204 self.clear() |
204 self.clear() |
205 else: |
205 else: |
206 self._writeerr('\n') |
206 self._writeerr(b'\n') |
207 self._flusherr() |
207 self._flusherr() |
208 |
208 |
209 def _flusherr(self): |
209 def _flusherr(self): |
210 _eintrretry(self.ui.ferr.flush) |
210 _eintrretry(self.ui.ferr.flush) |
211 |
211 |
212 def _writeerr(self, msg): |
212 def _writeerr(self, msg): |
213 _eintrretry(self.ui.ferr.write, msg) |
213 _eintrretry(self.ui.ferr.write, msg) |
214 |
214 |
215 def width(self): |
215 def width(self): |
216 tw = self.ui.termwidth() |
216 tw = self.ui.termwidth() |
217 return min(int(self.ui.config('progress', 'width', default=tw)), tw) |
217 return min(int(self.ui.config(b'progress', b'width', default=tw)), tw) |
218 |
218 |
219 def estimate(self, topic, pos, total, now): |
219 def estimate(self, topic, pos, total, now): |
220 if total is None: |
220 if total is None: |
221 return '' |
221 return b'' |
222 initialpos = self.startvals[topic] |
222 initialpos = self.startvals[topic] |
223 target = total - initialpos |
223 target = total - initialpos |
224 delta = pos - initialpos |
224 delta = pos - initialpos |
225 if delta > 0: |
225 if delta > 0: |
226 elapsed = now - self.starttimes[topic] |
226 elapsed = now - self.starttimes[topic] |
227 seconds = (elapsed * (target - delta)) // delta + 1 |
227 seconds = (elapsed * (target - delta)) // delta + 1 |
228 return fmtremaining(seconds) |
228 return fmtremaining(seconds) |
229 return '' |
229 return b'' |
230 |
230 |
231 def speed(self, topic, pos, unit, now): |
231 def speed(self, topic, pos, unit, now): |
232 initialpos = self.startvals[topic] |
232 initialpos = self.startvals[topic] |
233 delta = pos - initialpos |
233 delta = pos - initialpos |
234 elapsed = now - self.starttimes[topic] |
234 elapsed = now - self.starttimes[topic] |
235 if elapsed > 0: |
235 if elapsed > 0: |
236 return _('%d %s/sec') % (delta / elapsed, unit) |
236 return _(b'%d %s/sec') % (delta / elapsed, unit) |
237 return '' |
237 return b'' |
238 |
238 |
239 def _oktoprint(self, now): |
239 def _oktoprint(self, now): |
240 '''Check if conditions are met to print - e.g. changedelay elapsed''' |
240 '''Check if conditions are met to print - e.g. changedelay elapsed''' |
241 if ( |
241 if ( |
242 self.lasttopic is None # first time we printed |
242 self.lasttopic is None # first time we printed |