##// END OF EJS Templates
progress: use absolute_import
Gregory Szorc -
r25968:1139d7cf default
parent child Browse files
Show More
@@ -1,252 +1,253
1 1 # progress.py progress bars related code
2 2 #
3 3 # Copyright (C) 2010 Augie Fackler <durin42@gmail.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 from __future__ import absolute_import
9
8 10 import sys
9 import time
10 11 import threading
11 from mercurial import encoding
12 import time
12 13
13 from mercurial.i18n import _
14
14 from .i18n import _
15 from . import encoding
15 16
16 17 def spacejoin(*args):
17 18 return ' '.join(s for s in args if s)
18 19
19 20 def shouldprint(ui):
20 21 return not (ui.quiet or ui.plain()) and (
21 22 ui._isatty(sys.stderr) or ui.configbool('progress', 'assume-tty'))
22 23
23 24 def fmtremaining(seconds):
24 25 """format a number of remaining seconds in humain readable way
25 26
26 27 This will properly display seconds, minutes, hours, days if needed"""
27 28 if seconds < 60:
28 29 # i18n: format XX seconds as "XXs"
29 30 return _("%02ds") % (seconds)
30 31 minutes = seconds // 60
31 32 if minutes < 60:
32 33 seconds -= minutes * 60
33 34 # i18n: format X minutes and YY seconds as "XmYYs"
34 35 return _("%dm%02ds") % (minutes, seconds)
35 36 # we're going to ignore seconds in this case
36 37 minutes += 1
37 38 hours = minutes // 60
38 39 minutes -= hours * 60
39 40 if hours < 30:
40 41 # i18n: format X hours and YY minutes as "XhYYm"
41 42 return _("%dh%02dm") % (hours, minutes)
42 43 # we're going to ignore minutes in this case
43 44 hours += 1
44 45 days = hours // 24
45 46 hours -= days * 24
46 47 if days < 15:
47 48 # i18n: format X days and YY hours as "XdYYh"
48 49 return _("%dd%02dh") % (days, hours)
49 50 # we're going to ignore hours in this case
50 51 days += 1
51 52 weeks = days // 7
52 53 days -= weeks * 7
53 54 if weeks < 55:
54 55 # i18n: format X weeks and YY days as "XwYYd"
55 56 return _("%dw%02dd") % (weeks, days)
56 57 # we're going to ignore days and treat a year as 52 weeks
57 58 weeks += 1
58 59 years = weeks // 52
59 60 weeks -= years * 52
60 61 # i18n: format X years and YY weeks as "XyYYw"
61 62 return _("%dy%02dw") % (years, weeks)
62 63
63 64 class progbar(object):
64 65 def __init__(self, ui):
65 66 self.ui = ui
66 67 self._refreshlock = threading.Lock()
67 68 self.resetstate()
68 69
69 70 def resetstate(self):
70 71 self.topics = []
71 72 self.topicstates = {}
72 73 self.starttimes = {}
73 74 self.startvals = {}
74 75 self.printed = False
75 76 self.lastprint = time.time() + float(self.ui.config(
76 77 'progress', 'delay', default=3))
77 78 self.curtopic = None
78 79 self.lasttopic = None
79 80 self.indetcount = 0
80 81 self.refresh = float(self.ui.config(
81 82 'progress', 'refresh', default=0.1))
82 83 self.changedelay = max(3 * self.refresh,
83 84 float(self.ui.config(
84 85 'progress', 'changedelay', default=1)))
85 86 self.order = self.ui.configlist(
86 87 'progress', 'format',
87 88 default=['topic', 'bar', 'number', 'estimate'])
88 89
89 90 def show(self, now, topic, pos, item, unit, total):
90 91 if not shouldprint(self.ui):
91 92 return
92 93 termwidth = self.width()
93 94 self.printed = True
94 95 head = ''
95 96 needprogress = False
96 97 tail = ''
97 98 for indicator in self.order:
98 99 add = ''
99 100 if indicator == 'topic':
100 101 add = topic
101 102 elif indicator == 'number':
102 103 if total:
103 104 add = ('% ' + str(len(str(total))) +
104 105 's/%s') % (pos, total)
105 106 else:
106 107 add = str(pos)
107 108 elif indicator.startswith('item') and item:
108 109 slice = 'end'
109 110 if '-' in indicator:
110 111 wid = int(indicator.split('-')[1])
111 112 elif '+' in indicator:
112 113 slice = 'beginning'
113 114 wid = int(indicator.split('+')[1])
114 115 else:
115 116 wid = 20
116 117 if slice == 'end':
117 118 add = encoding.trim(item, wid, leftside=True)
118 119 else:
119 120 add = encoding.trim(item, wid)
120 121 add += (wid - encoding.colwidth(add)) * ' '
121 122 elif indicator == 'bar':
122 123 add = ''
123 124 needprogress = True
124 125 elif indicator == 'unit' and unit:
125 126 add = unit
126 127 elif indicator == 'estimate':
127 128 add = self.estimate(topic, pos, total, now)
128 129 elif indicator == 'speed':
129 130 add = self.speed(topic, pos, unit, now)
130 131 if not needprogress:
131 132 head = spacejoin(head, add)
132 133 else:
133 134 tail = spacejoin(tail, add)
134 135 if needprogress:
135 136 used = 0
136 137 if head:
137 138 used += encoding.colwidth(head) + 1
138 139 if tail:
139 140 used += encoding.colwidth(tail) + 1
140 141 progwidth = termwidth - used - 3
141 142 if total and pos <= total:
142 143 amt = pos * progwidth // total
143 144 bar = '=' * (amt - 1)
144 145 if amt > 0:
145 146 bar += '>'
146 147 bar += ' ' * (progwidth - amt)
147 148 else:
148 149 progwidth -= 3
149 150 self.indetcount += 1
150 151 # mod the count by twice the width so we can make the
151 152 # cursor bounce between the right and left sides
152 153 amt = self.indetcount % (2 * progwidth)
153 154 amt -= progwidth
154 155 bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
155 156 ' ' * int(abs(amt)))
156 157 prog = ''.join(('[', bar , ']'))
157 158 out = spacejoin(head, prog, tail)
158 159 else:
159 160 out = spacejoin(head, tail)
160 161 sys.stderr.write('\r' + encoding.trim(out, termwidth))
161 162 self.lasttopic = topic
162 163 sys.stderr.flush()
163 164
164 165 def clear(self):
165 166 if not shouldprint(self.ui):
166 167 return
167 168 sys.stderr.write('\r%s\r' % (' ' * self.width()))
168 169
169 170 def complete(self):
170 171 if not shouldprint(self.ui):
171 172 return
172 173 if self.ui.configbool('progress', 'clear-complete', default=True):
173 174 self.clear()
174 175 else:
175 176 sys.stderr.write('\n')
176 177 sys.stderr.flush()
177 178
178 179 def width(self):
179 180 tw = self.ui.termwidth()
180 181 return min(int(self.ui.config('progress', 'width', default=tw)), tw)
181 182
182 183 def estimate(self, topic, pos, total, now):
183 184 if total is None:
184 185 return ''
185 186 initialpos = self.startvals[topic]
186 187 target = total - initialpos
187 188 delta = pos - initialpos
188 189 if delta > 0:
189 190 elapsed = now - self.starttimes[topic]
190 191 # experimental config: progress.estimate
191 192 if elapsed > float(
192 193 self.ui.config('progress', 'estimate', default=2)):
193 194 seconds = (elapsed * (target - delta)) // delta + 1
194 195 return fmtremaining(seconds)
195 196 return ''
196 197
197 198 def speed(self, topic, pos, unit, now):
198 199 initialpos = self.startvals[topic]
199 200 delta = pos - initialpos
200 201 elapsed = now - self.starttimes[topic]
201 202 if elapsed > float(
202 203 self.ui.config('progress', 'estimate', default=2)):
203 204 return _('%d %s/sec') % (delta / elapsed, unit)
204 205 return ''
205 206
206 207 def _oktoprint(self, now):
207 208 '''Check if conditions are met to print - e.g. changedelay elapsed'''
208 209 if (self.lasttopic is None # first time we printed
209 210 # not a topic change
210 211 or self.curtopic == self.lasttopic
211 212 # it's been long enough we should print anyway
212 213 or now - self.lastprint >= self.changedelay):
213 214 return True
214 215 else:
215 216 return False
216 217
217 218 def progress(self, topic, pos, item='', unit='', total=None):
218 219 now = time.time()
219 220 self._refreshlock.acquire()
220 221 try:
221 222 if pos is None:
222 223 self.starttimes.pop(topic, None)
223 224 self.startvals.pop(topic, None)
224 225 self.topicstates.pop(topic, None)
225 226 # reset the progress bar if this is the outermost topic
226 227 if self.topics and self.topics[0] == topic and self.printed:
227 228 self.complete()
228 229 self.resetstate()
229 230 # truncate the list of topics assuming all topics within
230 231 # this one are also closed
231 232 if topic in self.topics:
232 233 self.topics = self.topics[:self.topics.index(topic)]
233 234 # reset the last topic to the one we just unwound to,
234 235 # so that higher-level topics will be stickier than
235 236 # lower-level topics
236 237 if self.topics:
237 238 self.lasttopic = self.topics[-1]
238 239 else:
239 240 self.lasttopic = None
240 241 else:
241 242 if topic not in self.topics:
242 243 self.starttimes[topic] = now
243 244 self.startvals[topic] = pos
244 245 self.topics.append(topic)
245 246 self.topicstates[topic] = pos, item, unit, total
246 247 self.curtopic = topic
247 248 if now - self.lastprint >= self.refresh and self.topics:
248 249 if self._oktoprint(now):
249 250 self.lastprint = now
250 251 self.show(now, topic, *self.topicstates[topic])
251 252 finally:
252 253 self._refreshlock.release()
General Comments 0
You need to be logged in to leave comments. Login now