- initial import of revision 374 from cnc
[apt.git] / cmdline / acqprogress.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description                                                          /*{{{*/
3 // $Id: acqprogress.cc,v 1.24 2003/04/27 01:56:48 doogie Exp $
4 /* ######################################################################
5
6    Acquire Progress - Command line progress meter 
7    
8    ##################################################################### */
9                                                                         /*}}}*/
10 // Include files                                                        /*{{{*/
11 #include "acqprogress.h"
12 #include <apt-pkg/acquire-item.h>
13 #include <apt-pkg/acquire-worker.h>
14 #include <apt-pkg/strutl.h>
15 #include <apt-pkg/error.h>
16
17 #include <apti18n.h>
18     
19 #include <stdio.h>
20 #include <signal.h>
21 #include <iostream>
22                                                                         /*}}}*/
23
24 using namespace std;
25
26 // AcqTextStatus::AcqTextStatus - Constructor                           /*{{{*/
27 // ---------------------------------------------------------------------
28 /* */
29 AcqTextStatus::AcqTextStatus(unsigned int &ScreenWidth,unsigned int Quiet) :
30     ScreenWidth(ScreenWidth), Quiet(Quiet)
31 {
32 }
33                                                                         /*}}}*/
34 // AcqTextStatus::Start - Downloading has started                       /*{{{*/
35 // ---------------------------------------------------------------------
36 /* */
37 void AcqTextStatus::Start() 
38 {
39    pkgAcquireStatus::Start(); 
40    BlankLine[0] = 0;
41    ID = 1;
42 };
43                                                                         /*}}}*/
44 // AcqTextStatus::IMSHit - Called when an item got a HIT response       /*{{{*/
45 // ---------------------------------------------------------------------
46 /* */
47 void AcqTextStatus::IMSHit(pkgAcquire::ItemDesc &Itm)
48 {
49    if (Quiet > 1)
50       return;
51
52    if (Quiet <= 0)
53       cout << '\r' << BlankLine << '\r';   
54    
55    cout << _("Hit ") << Itm.Description;
56    if (Itm.Owner->FileSize != 0)
57       cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
58    cout << endl;
59    Update = true;
60 };
61                                                                         /*}}}*/
62 // AcqTextStatus::Fetch - An item has started to download               /*{{{*/
63 // ---------------------------------------------------------------------
64 /* This prints out the short description and the expected size */
65 void AcqTextStatus::Fetch(pkgAcquire::ItemDesc &Itm)
66 {
67    Update = true;
68    if (Itm.Owner->Complete == true)
69       return;
70    
71    Itm.Owner->ID = ID++;
72    
73    if (Quiet > 1)
74       return;
75
76    if (Quiet <= 0)
77       cout << '\r' << BlankLine << '\r';
78    
79    cout << _("Get:") << Itm.Owner->ID << ' ' << Itm.Description;
80    if (Itm.Owner->FileSize != 0)
81       cout << " [" << SizeToStr(Itm.Owner->FileSize) << "B]";
82    cout << endl;
83 };
84                                                                         /*}}}*/
85 // AcqTextStatus::Done - Completed a download                           /*{{{*/
86 // ---------------------------------------------------------------------
87 /* We don't display anything... */
88 void AcqTextStatus::Done(pkgAcquire::ItemDesc &Itm)
89 {
90    Update = true;
91 };
92                                                                         /*}}}*/
93 // AcqTextStatus::Fail - Called when an item fails to download          /*{{{*/
94 // ---------------------------------------------------------------------
95 /* We print out the error text  */
96 void AcqTextStatus::Fail(pkgAcquire::ItemDesc &Itm)
97 {
98    if (Quiet > 1)
99       return;
100
101    // Ignore certain kinds of transient failures (bad code)
102    if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
103       return;
104       
105    if (Quiet <= 0)
106       cout << '\r' << BlankLine << '\r';
107    
108    if (Itm.Owner->Status == pkgAcquire::Item::StatDone)
109    {
110       cout << _("Ign ") << Itm.Description << endl;
111    }
112    else
113    {
114       cout << _("Err ") << Itm.Description << endl;
115       cout << "  " << Itm.Owner->ErrorText << endl;
116    }
117    
118    Update = true;
119 };
120                                                                         /*}}}*/
121 // AcqTextStatus::Stop - Finished downloading                           /*{{{*/
122 // ---------------------------------------------------------------------
123 /* This prints out the bytes downloaded and the overall average line
124    speed */
125 void AcqTextStatus::Stop()
126 {
127    pkgAcquireStatus::Stop();
128    if (Quiet > 1)
129       return;
130
131    if (Quiet <= 0)
132       cout << '\r' << BlankLine << '\r' << flush;
133
134    if (FetchedBytes != 0 && _error->PendingError() == false)
135       ioprintf(cout,_("Fetched %sB in %s (%sB/s)\n"),
136                SizeToStr(FetchedBytes).c_str(),
137                TimeToStr(ElapsedTime).c_str(),
138                SizeToStr(CurrentCPS).c_str());
139 }
140                                                                         /*}}}*/
141 // AcqTextStatus::Pulse - Regular event pulse                           /*{{{*/
142 // ---------------------------------------------------------------------
143 /* This draws the current progress. Each line has an overall percent
144    meter and a per active item status meter along with an overall 
145    bandwidth and ETA indicator. */
146 bool AcqTextStatus::Pulse(pkgAcquire *Owner)
147 {
148    if (Quiet > 0)
149       return true;
150    
151    pkgAcquireStatus::Pulse(Owner);
152    
153    enum {Long = 0,Medium,Short} Mode = Long;
154    
155    char Buffer[sizeof(BlankLine)];
156    char *End = Buffer + sizeof(Buffer);
157    char *S = Buffer;
158    if (ScreenWidth >= sizeof(Buffer))
159       ScreenWidth = sizeof(Buffer)-1;
160
161    // Put in the percent done
162    sprintf(S,"%ld%%",long(double((CurrentBytes + CurrentItems)*100.0)/double(TotalBytes+TotalItems)));
163
164    bool Shown = false;
165    for (pkgAcquire::Worker *I = Owner->WorkersBegin(); I != 0;
166         I = Owner->WorkerStep(I))
167    {
168       S += strlen(S);
169       
170       // There is no item running 
171       if (I->CurrentItem == 0)
172       {
173          if (I->Status.empty() == false)
174          {
175             snprintf(S,End-S," [%s]",I->Status.c_str());
176             Shown = true;
177          }
178          
179          continue;
180       }
181
182       Shown = true;
183       
184       // Add in the short description
185       if (I->CurrentItem->Owner->ID != 0)
186          snprintf(S,End-S," [%lu %s",I->CurrentItem->Owner->ID,
187                   I->CurrentItem->ShortDesc.c_str());
188       else
189          snprintf(S,End-S," [%s",I->CurrentItem->ShortDesc.c_str());
190       S += strlen(S);
191
192       // Show the short mode string
193       if (I->CurrentItem->Owner->Mode != 0)
194       {
195          snprintf(S,End-S," %s",I->CurrentItem->Owner->Mode);
196          S += strlen(S);
197       }
198             
199       // Add the current progress
200       if (Mode == Long)
201          snprintf(S,End-S," %lu",I->CurrentSize);
202       else
203       {
204          if (Mode == Medium || I->TotalSize == 0)
205             snprintf(S,End-S," %sB",SizeToStr(I->CurrentSize).c_str());
206       }
207       S += strlen(S);
208       
209       // Add the total size and percent
210       if (I->TotalSize > 0 && I->CurrentItem->Owner->Complete == false)
211       {
212          if (Mode == Short)
213             snprintf(S,End-S," %lu%%",
214                      long(double(I->CurrentSize*100.0)/double(I->TotalSize)));
215          else
216             snprintf(S,End-S,"/%sB %lu%%",SizeToStr(I->TotalSize).c_str(),
217                      long(double(I->CurrentSize*100.0)/double(I->TotalSize)));
218       }      
219       S += strlen(S);
220       snprintf(S,End-S,"]");
221    }
222
223    // Show something..
224    if (Shown == false)
225       snprintf(S,End-S,_(" [Working]"));
226       
227    /* Put in the ETA and cps meter, block off signals to prevent strangeness
228       during resizing */
229    sigset_t Sigs,OldSigs;
230    sigemptyset(&Sigs);
231    sigaddset(&Sigs,SIGWINCH);
232    sigprocmask(SIG_BLOCK,&Sigs,&OldSigs);
233    
234    if (CurrentCPS != 0)
235    {      
236       char Tmp[300];
237       unsigned long ETA = (unsigned long)((TotalBytes - CurrentBytes)/CurrentCPS);
238       sprintf(Tmp," %sB/s %s",SizeToStr(CurrentCPS).c_str(),TimeToStr(ETA).c_str());
239       unsigned int Len = strlen(Buffer);
240       unsigned int LenT = strlen(Tmp);
241       if (Len + LenT < ScreenWidth)
242       {  
243          memset(Buffer + Len,' ',ScreenWidth - Len);
244          strcpy(Buffer + ScreenWidth - LenT,Tmp);
245       }      
246    }
247    Buffer[ScreenWidth] = 0;
248    BlankLine[ScreenWidth] = 0;
249    sigprocmask(SIG_SETMASK,&OldSigs,0);
250
251    // Draw the current status
252    if (strlen(Buffer) == strlen(BlankLine))
253       cout << '\r' << Buffer << flush;
254    else
255       cout << '\r' << BlankLine << '\r' << Buffer << flush;
256    memset(BlankLine,' ',strlen(Buffer));
257    BlankLine[strlen(Buffer)] = 0;
258    
259    Update = false;
260
261    return true;
262 }
263                                                                         /*}}}*/
264 // AcqTextStatus::MediaChange - Media need to be swapped                /*{{{*/
265 // ---------------------------------------------------------------------
266 /* Prompt for a media swap */
267 bool AcqTextStatus::MediaChange(string Media,string Drive)
268 {
269    if (Quiet <= 0)
270       cout << '\r' << BlankLine << '\r';
271    ioprintf(cout,_("Media Change: Please insert the disc labeled\n"
272                    " '%s'\n"
273                    "in the drive '%s' and press enter\n"),
274             Media.c_str(),Drive.c_str());
275
276    char C = 0;
277    while (C != '\n' && C != '\r')
278       read(STDIN_FILENO,&C,1);
279    
280    Update = true;
281    return true;
282 }
283                                                                         /*}}}*/