- more descriptive progress messages
[apt.git] / apt-pkg / contrib / progress.cc
1 // -*- mode: c++; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: progress.cc,v 1.2 2003/01/29 18:43:48 niemeyer Exp $
4 /* ######################################################################
5    
6    OpProgress - Operation Progress
7    
8    ##################################################################### */
9                                                                         /*}}}*/
10 // Include Files                                                        /*{{{*/
11 #ifdef __GNUG__
12 #pragma implementation "apt-pkg/progress.h"
13 #endif 
14 #include <apt-pkg/progress.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/configuration.h>
17
18 #include <apti18n.h>
19
20 #include <iostream>
21 #include <iomanip>
22 #include <stdio.h>
23                                                                         /*}}}*/
24
25 using namespace std;
26
27 // OpProgress::OpProgress - Constructor                                 /*{{{*/
28 // ---------------------------------------------------------------------
29 /* */
30 OpProgress::OpProgress() : Current(0), Total(0), Size(0), SubTotal(1), 
31                            LastPercent(0), Percent(0)
32 {
33    memset(&LastTime,0,sizeof(LastTime));
34 }
35                                                                         /*}}}*/
36 // OpProgress::Progress - Sub progress with no state change             /*{{{*/
37 // ---------------------------------------------------------------------
38 /* Current is the Base Overall progress in units of Total. Cur is the sub
39    progress in units of SubTotal. Size is a scaling factor that says what
40    percent of Total SubTotal is. */
41 void OpProgress::Progress(unsigned long Cur)
42 {
43    if (Total == 0 || Size == 0 || SubTotal == 0)
44       Percent = 0;
45    else
46       Percent = (Current + Cur/((float)SubTotal)*Size)*100.0/Total;
47    Update();
48 }
49                                                                         /*}}}*/
50 // OpProgress::OverallProgress - Set the overall progress               /*{{{*/
51 // ---------------------------------------------------------------------
52 /* */
53 void OpProgress::OverallProgress(unsigned long Current, unsigned long Total,
54                                  unsigned long Size,string Op)
55 {
56    this->Current = Current;
57    this->Total = Total;
58    this->Size = Size;
59    this->Op = Op;
60    SubOp = string();
61    if (Total == 0)
62       Percent = 0;
63    else
64       Percent = Current*100.0/Total;
65    Update();
66 }
67                                                                         /*}}}*/
68 // OpProgress::SubProgress - Set the sub progress state                 /*{{{*/
69 // ---------------------------------------------------------------------
70 /* */
71 void OpProgress::SubProgress(unsigned long SubTotal,string Op)
72 {
73    this->SubTotal = SubTotal;
74    SubOp = Op;
75    if (Total == 0)
76       Percent = 0;
77    else
78       Percent = Current*100.0/Total;
79    Update();
80 }
81                                                                         /*}}}*/
82 // OpProgress::SubProgress - Set the sub progress state                 /*{{{*/
83 // ---------------------------------------------------------------------
84 /* */
85 void OpProgress::SubProgress(unsigned long SubTotal)
86 {
87    this->SubTotal = SubTotal;
88    if (Total == 0)
89       Percent = 0;
90    else
91       Percent = Current*100.0/Total;
92    Update();
93 }
94                                                                         /*}}}*/
95 // OpProgress::CheckChange - See if the display should be updated       /*{{{*/
96 // ---------------------------------------------------------------------
97 /* Progress calls are made so frequently that if every one resulted in 
98    an update the display would be swamped and the system much slower.
99    This provides an upper bound on the update rate. */
100 bool OpProgress::CheckChange(float Interval)
101 {  
102    // New major progress indication
103    if (Op != LastOp)
104    {
105       MajorChange = true;
106       LastOp = Op;
107       return true;
108    }
109    MajorChange = false;
110
111    if (SubOp != LastSubOp)
112    {
113       LastSubOp = SubOp;
114       SubChange = true;
115       return true;
116    }
117    SubChange = false;
118    
119    if ((int)LastPercent == (int)Percent)
120       return false;
121    
122    if (Interval == 0)
123       return false;
124    
125    // Check time delta
126    struct timeval Now;
127    gettimeofday(&Now,0);
128    double Diff = Now.tv_sec - LastTime.tv_sec + (Now.tv_usec - LastTime.tv_usec)/1000000.0;
129    if (Diff < Interval)
130       return false;
131    LastTime = Now;   
132    LastPercent = Percent;
133    return true;
134 }
135                                                                         /*}}}*/
136 // OpTextProgress::OpTextProgress - Constructor                         /*{{{*/
137 // ---------------------------------------------------------------------
138 /* */
139 OpTextProgress::OpTextProgress(Configuration &Config) : 
140                                NoUpdate(false), NoDisplay(false), LastLen(0) 
141 {
142    if (Config.FindI("quiet",0) >= 1)
143       NoUpdate = true;
144    if (Config.FindI("quiet",0) >= 2)
145       NoDisplay = true;
146 }
147                                                                         /*}}}*/
148 // OpTextProgress::Done - Clean up the display                          /*{{{*/
149 // ---------------------------------------------------------------------
150 /* */
151 void OpTextProgress::Done()
152 {
153    if (NoUpdate == false && OldOp.empty() == false)
154    {
155       char S[300];
156       if (_error->PendingError() == true)
157          snprintf(S,sizeof(S),_("%c%s... Error!"),'\r',OldOp.c_str());
158       else
159          snprintf(S,sizeof(S),_("%c%s... Done"),'\r',OldOp.c_str());
160       Write(S);
161       cout << endl;
162       OldOp = string();
163    }
164    
165    if (NoUpdate == true && NoDisplay == false && OldOp.empty() == false)
166    {
167       OldOp = string();
168       cout << endl;   
169    }   
170 }
171                                                                         /*}}}*/
172 // OpTextProgress::Update - Simple text spinner                         /*{{{*/
173 // ---------------------------------------------------------------------
174 /* */
175 void OpTextProgress::Update()
176 {
177    if (CheckChange((NoUpdate == true?0:0.7)) == false)
178       return;
179    
180    // No percent spinner
181    if (NoUpdate == true)
182    {
183       if (MajorChange == false)
184          return;
185       if (NoDisplay == false)
186       {
187          if (OldOp.empty() == false)
188             cout << endl;
189          OldOp = "a";
190          cout << Op << "..." << flush;
191       }
192       
193       return;
194    }
195
196    // Erase the old text and 'log' the event
197    char S[300];
198    if (MajorChange == true && OldOp.empty() == false)
199    {
200       snprintf(S,sizeof(S),"\r%s",OldOp.c_str());
201       Write(S);
202       cout << endl;
203    }
204    
205    // Print the spinner
206    snprintf(S,sizeof(S),"\r%s... %u%%",Op.c_str(),(unsigned int)Percent);
207    Write(S);
208
209    OldOp = Op;
210 }
211                                                                         /*}}}*/
212 // OpTextProgress::Write - Write the progress string                    /*{{{*/
213 // ---------------------------------------------------------------------
214 /* This space fills the end to overwrite the previous text */
215 void OpTextProgress::Write(const char *S)
216 {
217    cout << S;
218    for (unsigned int I = strlen(S); I < LastLen; I++)
219       cout << ' ';
220    cout << '\r' << flush;
221    LastLen = strlen(S);
222 }
223                                                                         /*}}}*/
224
225 InstPercentProgress::InstPercentProgress(Configuration &Config) : 
226                                 InstProgress(Config)
227 {
228 }
229
230 void InstPercentProgress::Done()
231 {
232    Percent = 100;
233    Update();
234 }
235                                                                         /*}}}*/
236 void InstPercentProgress::Update()
237 {
238    if (CheckChange(0.001) == false)
239       return;
240
241    if (MajorChange == true)
242       return;
243    if (SubChange == true) {
244       if (State == Preparing) {
245          cout << SubOp << endl << flush;
246       } else if (State == Installing) {
247          cout << (*PackageData)["name"] << "-";
248          cout << (*PackageData)["version"] << "-";
249          cout << (*PackageData)["release"];
250          cout << endl << flush;
251       }
252    } else if (State == Installing or State == Preparing) {
253       cout.setf(ios_base::showpoint);
254       cout.setf(ios_base::fixed, ios_base::floatfield);
255       cout << "%% " << setprecision(6) << Percent << endl << flush;
256    }
257 }
258
259 void InstHashProgress::Update()
260 {
261    if (CheckChange(0.000001) == false)
262       return;
263
264    if (MajorChange == true) {
265       cout << Op << endl << flush;
266       return;
267    }
268    string s;
269    if (State == Preparing) {
270       s = SubOp; 
271    } else {
272       s = (*PackageData)["name"] + "-" + 
273           (*PackageData)["version"] + "-" + 
274           (*PackageData)["release"] + "." +
275           (*PackageData)["arch"]; 
276    }
277    const int namemax = 40;
278    cout << "\r";
279    cout.setf(ios_base::left);
280    cout << setw(namemax) << s.substr(0, namemax) << " ";
281    PrintHashes();
282 }
283
284 void InstHashProgress::PrintHashes()
285 {
286    int hashesTotal = 30;
287    int hashesNeeded = int(hashesTotal * Percent / 100);
288            
289    cout << setw(hashesNeeded) << setfill('#') << "";
290    cout << setw(hashesTotal-hashesNeeded) << setfill(' ') << "";
291    cout.setf(ios_base::left);
292    cout << " [" << setw(3) << int(Percent) << "%]";
293    if (hashesTotal == hashesNeeded) {
294       cout << endl;
295    }
296    cout << flush;
297 }
298
299 void InstHashProgress::Done()
300 {
301    Percent = 100;
302    Update();
303    cout << "Done." << endl;
304 }
305
306 // vim:sts=3:sw=3