source: src-qt4/pc-softwaremanager/processManager.cpp @ f981222

9.2-releasereleng/10.0releng/10.0.1
Last change on this file since f981222 was 74c359f, checked in by Ken Moore <ken@…>, 9 months ago

Setup the AppCafe? so that the status displayed in the treewidget is a short status, with the full status at the bottom of the info group if selected. This status shows not only the current download percent and rate, but also any install/remove/update status notifications as they happen.

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/***************************************************************************
2 *   Copyright (C) 2011 - iXsystems                                       *
3 *   kris@pcbsd.org  *
4 *   tim@pcbsd.org   *
5 *   ken@pcbsd.org   *
6 *                                                                         *
7 *   Permission is hereby granted, free of charge, to any person obtaining *
8 *   a copy of this software and associated documentation files (the       *
9 *   "Software"), to deal in the Software without restriction, including   *
10 *   without limitation the rights to use, copy, modify, merge, publish,   *
11 *   distribute, sublicense, and/or sell copies of the Software, and to    *
12 *   permit persons to whom the Software is furnished to do so, subject to *
13 *   the following conditions:                                             *
14 *                                                                         *
15 *   The above copyright notice and this permission notice shall be        *
16 *   included in all copies or substantial portions of the Software.       *
17 *                                                                         *
18 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
19 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
20 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
21 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
22 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
23 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
24 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
25 ***************************************************************************/
26 #include "processManager.h"
27
28ProcessManager::ProcessManager(){
29  //Get the system environment for all the processes
30  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
31    env.insert("PBI_FETCH_PARSING","YES"); //For readable download notifications
32    //Initialize the UPDATE Process
33    upProc = new QProcess; upProc->setProcessEnvironment(env);
34    upProc->setProcessChannelMode(QProcess::MergedChannels);
35    connect(upProc, SIGNAL(readyRead()),this,SLOT(slotUpProcMessage()) );
36    connect(upProc, SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotUpProcFinished()) );
37    //Initialize the REMOVE Process
38    remProc = new QProcess; remProc->setProcessEnvironment(env);
39    remProc->setProcessChannelMode(QProcess::MergedChannels);
40    connect(remProc, SIGNAL(readyRead()),this,SLOT(slotRemProcMessage()) );
41    connect(remProc, SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotRemProcFinished()) );
42    //Initialize the DOWNLOAD Process
43    dlProc = new QProcess; dlProc->setProcessEnvironment(env);
44    dlProc->setProcessChannelMode(QProcess::MergedChannels);
45    connect(dlProc, SIGNAL(readyRead()),this,SLOT(slotDlProcMessage()) );
46    connect(dlProc, SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotDlProcFinished()) );
47    //Initialize the INSTALL Process
48    inProc = new QProcess; inProc->setProcessEnvironment(env);
49    inProc->setProcessChannelMode(QProcess::MergedChannels);
50    connect(inProc, SIGNAL(readyRead()),this,SLOT(slotInProcMessage()) );
51    connect(inProc, SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotInProcFinished()) );
52    //Initialize the OTHER Process
53    otProc = new QProcess; otProc->setProcessEnvironment(env);
54    connect(otProc, SIGNAL(readyReadStandardOutput()),this,SLOT(slotOtProcMessage()) );
55    connect(otProc, SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(slotOtProcFinished()) );
56}
57
58ProcessManager::~ProcessManager(){
59}
60
61void ProcessManager::goToDirectory(ProcessID ID, QString dir){
62  if( ID == UPDATE ){
63    upProc->setWorkingDirectory(dir);     
64  }else if( ID == REMOVE ){
65    remProc->setWorkingDirectory(dir);           
66  }else if( ID == DOWNLOAD ){
67    dlProc->setWorkingDirectory(dir);     
68  }else if( ID == INSTALL ){
69    inProc->setWorkingDirectory(dir);             
70  }else if( ID == OTHER ){
71    otProc->setWorkingDirectory(dir);             
72  }     
73}
74
75// =========================
76// ===== PUBLIC ACCESS =====
77// =========================
78void ProcessManager::startProcess(ProcessID ID, QString cmd){
79  if( ID == UPDATE ){
80    qDebug() << "Update Process Started:" << cmd;
81    upLog.clear(); //clear the log for action
82    upProc->start(cmd);   
83  }else if( ID == REMOVE ){
84    qDebug() << "Removal Process Started:" << cmd;
85    remLog.clear();
86    remProc->start(cmd);                 
87  }else if( ID == DOWNLOAD ){
88    qDebug() << "Download Process Started:" << cmd;
89    dlLog.clear();
90    dlProc->start(cmd);           
91  }else if( ID == INSTALL ){
92    qDebug() << "Install Process Started:" << cmd;
93    inLog.clear();
94    inProc->start(cmd);           
95  }else if( ID == OTHER ){
96    qDebug() << "Other Process Started:" << cmd;
97    otProc->start(cmd);           
98  }
99       
100}
101
102void ProcessManager::stopProcess(ProcessID ID){
103  if((ID == ALL) || (ID == UPDATE)){
104    upProc->terminate();         
105  }
106  if((ID == ALL) || (ID == REMOVE)){
107    remProc->terminate();         
108  }
109  if((ID == ALL) || (ID == DOWNLOAD)){
110    dlProc->terminate();         
111  }
112  if((ID == ALL) || (ID == INSTALL)){
113    inProc->terminate();         
114  }
115  if((ID == ALL) || (ID == OTHER)){
116    otProc->terminate();         
117  }     
118}
119
120QStringList ProcessManager::getProcessLog(ProcessID ID){
121  if( ID == UPDATE ){ return upLog; }
122  else if( ID == REMOVE ){ return remLog; }
123  else if( ID == DOWNLOAD ){ return dlLog; }
124  else if( ID == INSTALL ){ return inLog; }
125  else{ return QStringList(); }
126}
127
128// =========================
129// ===== PRIVATE SLOTS =====
130// =========================
131QString ProcessManager::parseDlLine(QString line){
132  /*DOWNLOAD NOTIFICATION CODES:
133  Download complete: "DLDONE"
134  Download running: "DLSTAT::<percent>::<total size>::<download speed>"
135        -- A value of "??" means that it is unknown
136  Download starting: "DLSTART"
137  */
138  QString out;
139  if( line.startsWith("FETCH:") ){ return "DLSTART"; }
140  else if( line == "FETCHDONE"){ return "DLDONE"; }
141  else if(!line.startsWith("SIZE:")){ return out; }
142  //qDebug() << "parse Download Line:" << line;
143  //Line format: SIZE:  <KB> DOWNLOADED:  <KB> SPEED:  <KB/s> KB/s
144  line = line.simplified();
145  line.replace("SIZE: ","");
146  line.replace("DOWNLOADED: ", "");
147  line.replace("SPEED: ","");
148  line.replace("KB/s","");
149  bool totok, curok, spdok;
150  double tot, cur, spd;
151  tot = line.section(" ",0,0).toDouble(&totok);
152  cur = line.section(" ",1,1).toDouble(&curok);
153  spd = line.section(" ",2,2).toDouble(&spdok);
154  //qDebug() << " - DownloadStats:" << tot << cur << spd;
155  if(totok && tot==0){totok=FALSE;}
156  if(curok && cur==0){curok=FALSE;}
157  if(spdok && spd==0){spdok=FALSE;}
158  //Now format the output string
159  QString stats;
160  out = "DLSTAT::";
161  //Get percent and totals
162  if(totok && curok){
163    bool totErr = (tot==cur); //catch for a display error where the cur is always identical to the tot
164    if(!totErr){         
165      //Calculate the percentage
166      double percent = (cur/tot)*100;
167      percent = int(percent*10)/10.0;
168      out.append(QString::number(percent)+"::");
169      //Now list the total
170      out.append( Extras::sizeKToDisplay(QString::number(tot)) +"::" );
171    }else{
172      //Only Total/Current is known (unknown percentage since not complete yet)
173      out.append("??::"+Extras::sizeKToDisplay(QString::number(tot))+"::");
174    }       
175  }else if(curok){
176    //Only Total/Current is known (unknown percentage since not complete yet)
177    out.append("??::"+Extras::sizeKToDisplay(QString::number(cur))+"::");
178  }else if(totok){
179    //Only Total/Current is known (unknown percentage since not complete yet)
180    out.append("??::"+Extras::sizeKToDisplay(QString::number(tot))+"::");
181  }else{
182    //Unknown Total and Current
183    out.append("??::??::");
184  }
185  //Now get the speed
186  if(spdok){
187    out.append( Extras::sizeKToDisplay(QString::number(spd))+"/s" );
188  }else{
189    out.append("??");
190  }
191  /*
192    int i=0;
193    QStringList lab; lab << "KB" <<"MB"<<"GB"<<"TB"<<"PB";
194    while( (tot>1000) && (i<lab.length()) ){
195      cur=cur/1024; tot=tot/1024; i++;
196    }
197
198    cur = int(cur*10)/10.0;
199    tot = int(tot*10)/10.0;
200    if(totErr){ // cur==tot
201      //Percentage unknown (since fetch is not done)
202      out.append("??::"+QString::number(tot)+" "+lab[i]+"::");
203      //stats = QString::number(tot)+" "+lab[i];
204    }else{
205      out.append(QString::number(percent)+"::"+QString::number(tot)+" "+lab[i]+"::");
206      //stats = QString::number(cur)+"/"+QString::number(tot)+" "+lab[i]+" ("+QString::number(percent)+"%)";
207    }
208    // Format:  <current>/<total> <size label> (<percent>%)
209  }else if(curok){
210    stats = Extras::sizeKToDisplay(QString::number(cur));
211  }
212  QString speed;
213  if(spdok){
214    speed = Extras::sizeKToDisplay(QString::number(spd))+"/s";   
215  }
216  //Now put the output string together and return it
217  if(stats.isEmpty() && speed.isEmpty()){}
218  else if(stats.isEmpty()){ out = speed; }
219  else if(speed.isEmpty()){ out = stats; }
220  else{ out = QString( tr("%1 at %2") ).arg(stats,speed); }
221  */
222  //qDebug() << " - Result:" << out;
223  return out;
224}
225
226// == UPDATE PROCESS ==
227void ProcessManager::slotUpProcMessage(){
228  while( upProc->canReadLine() ){
229    QString line = upProc->readLine().simplified();
230    if(line.isEmpty()){ continue; }
231    QString dl = parseDlLine(line);
232    if(!dl.isEmpty()){ 
233      emit ProcessMessage(UPDATE,dl); //Download status
234      if( !dl.startsWith("DLSTAT::") ){
235        upLog << line; //not just a status update - add to the log (log download start/stop)   
236      }
237    }else{ 
238      emit ProcessMessage(UPDATE,line); 
239      upLog << line; //not a download line - add to the log
240    }
241  }
242}
243
244void ProcessManager::slotUpProcFinished(){
245  if(upProc->exitStatus() != QProcess::NormalExit || upProc->exitCode() != 0){
246    //Emit the command log
247    qDebug() << "Update Process Error Log:\n"<<upLog.join("\n");
248    emit ProcessError(UPDATE, upLog);
249  }else{
250    qDebug() << "Update Process Finished";
251    emit ProcessFinished(UPDATE);         
252  }
253}
254
255// == REMOVE PROCESS ==
256void ProcessManager::slotRemProcMessage(){
257  while( remProc->canReadLine() ){
258    QString line = remProc->readLine().simplified();
259    if(!line.isEmpty()){ 
260      remLog << line; 
261      emit ProcessMessage(REMOVE,line);
262    }
263  }
264}
265
266void ProcessManager::slotRemProcFinished(){
267  if(remProc->exitStatus() != QProcess::NormalExit){
268    qDebug() << "Removal Process Error Log:\n"<<remLog.join("\n");
269    emit ProcessError(REMOVE, remLog);
270  }else{
271    qDebug() << "Removal Process Finished";
272    emit ProcessFinished(REMOVE);         
273  }
274}
275
276// == DOWNLOAD PROCESS ==
277void ProcessManager::slotDlProcMessage(){
278  while( dlProc->canReadLine() ){
279    QString line = dlProc->readLine().simplified();
280    if(line.isEmpty()){ continue; }
281    QString dl = parseDlLine(line);
282    if(!dl.isEmpty()){ 
283      emit ProcessMessage(DOWNLOAD,dl); //Download status
284      if( !dl.startsWith("DLSTAT::") ){
285        dlLog << line; //not just a status update - add to the log (log download start/stop)   
286      }
287    }else{ 
288      emit ProcessMessage(DOWNLOAD,line); 
289      dlLog << line; //not a download line - add to the log
290    }
291  }
292}
293
294void ProcessManager::slotDlProcFinished(){
295  if(dlProc->exitStatus() != QProcess::NormalExit){
296    qDebug() << "Download Process Error Log:\n"<<dlLog.join("\n");
297    emit ProcessError(DOWNLOAD, dlLog);
298  }else{
299    qDebug() << "Download Process Finished";
300    emit ProcessFinished(DOWNLOAD);       
301  }
302}
303
304// == INSTALL PROCESS ==
305void ProcessManager::slotInProcMessage(){
306  while( inProc->canReadLine() ){
307    QString line = inProc->readLine().simplified();
308    if(!line.isEmpty()){ 
309      inLog << line; 
310      emit ProcessMessage(INSTALL,line);
311    }
312  }
313}
314
315void ProcessManager::slotInProcFinished(){
316  if(inProc->exitStatus() != QProcess::NormalExit){
317    qDebug() << "Install Process Error Log:\n"<<inLog.join("\n");
318    emit ProcessError(INSTALL, inLog);
319  }else{
320    qDebug() << "Install Process Finished";
321    emit ProcessFinished(INSTALL);       
322  }
323}
324
325// == OTHER PROCESS ==
326void ProcessManager::slotOtProcMessage(){
327  QString msg = otProc->readAllStandardOutput();
328  emit ProcessMessage(OTHER,msg);
329}
330
331void ProcessManager::slotOtProcFinished(){
332  if(otProc->exitStatus() != QProcess::NormalExit){
333    QString msg = otProc->readAllStandardError();
334    if(msg.isEmpty()){ msg = otProc->readAllStandardOutput(); }
335    if(msg.isEmpty()){ msg = tr("Unknown Error"); }
336    qDebug() << "Other Process Error:"<<msg;
337    emit ProcessError(OTHER, QStringList(msg));
338  }else{
339    qDebug() << "Other Process Finished";
340    emit ProcessFinished(OTHER);         
341  }
342}
343
Note: See TracBrowser for help on using the repository browser.