source: src-qt4/pc-updatecenter/syscontroller.cpp @ c21cafa

releng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since c21cafa was c21cafa, checked in by yurkis <yurkis@…>, 12 months ago

Update center - current base system update description showing

  • Property mode set to 100644
File size: 17.3 KB
Line 
1/**************************************************************************
2*   Copyright (C) 2013- by Yuri Momotyuk                                   *
3*   yurkis@gmail.com                                                      *
4*                                                                         *
5*   Permission is hereby granted, free of charge, to any person obtaining *
6*   a copy of this software and associated documentation files (the       *
7*   "Software"), to deal in the Software without restriction, including   *
8*   without limitation the rights to use, copy, modify, merge, publish,   *
9*   distribute, sublicense, and/or sell copies of the Software, and to    *
10*   permit persons to whom the Software is furnished to do so, subject to *
11*   the following conditions:                                             *
12*                                                                         *
13*   The above copyright notice and this permission notice shall be        *
14*   included in all copies or substantial portions of the Software.       *
15*                                                                         *
16*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
17*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
18*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
19*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
20*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
21*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
22*   OTHER DEALINGS IN THE SOFTWARE.                                       *
23***************************************************************************/
24
25#include "syscontroller.h"
26#include "utils.h"
27#include "pcbsd-utils.h"
28#include <QDebug>
29#include <QRegExp>
30
31__string_constant PC_UPDATE_COMMAND = "pc-updatemanager";
32//_STRING_CONSTANT FBSD_UPDATE_COMMAND = "cat";
33__string_constant FBSD_UPDATE_COMMAND = "pc-fbsdupdatecheck";
34static const QStringList PC_UPDATE_ARGS(QStringList()<<"check");
35static const QStringList FBSD_UPDATE_ARGS (QStringList()<<"update");
36//static const QStringList FBSD_UPDATE_ARGS (QStringList()<<"/home/yurkis/_sysbasesys_check.txt");
37
38__string_constant NAME_TAG = "NAME:";
39__string_constant TYPE_TAG = "TYPE:";
40__string_constant TAG_TAG = "TAG:";
41__string_constant VERSION_TAG = "VERSION:";
42__string_constant DEATILS_TAG = "DETAILS:";
43__string_constant DATE_TAG = "DATE:";
44__string_constant SIZE_TAG = "SIZE:";
45__string_constant CU_END_MARKER = "To install:";
46__string_constant PATCH_TYPE = "PATCH";
47__string_constant SYSUPDATE_TYPE = "SYSUPDATE";
48__string_constant STANDALONE_TAG = "STANDALONE:";
49__string_constant REQUIRESREBOOT_TAG = "REQUIRESREBOOT:";
50
51__string_constant FILES_MODIFYED_LOCALLY = "been downloaded because the files have been modified locally:";
52__string_constant FILES_TO_DELETE = "The following files will be removed as part of updating to";
53__string_constant FILES_TO_UPDATE = "The following files will be updated as part of updating to";
54
55__string_constant NETWORKING_PROBLEM= "No mirrors remaining, giving up.";
56
57__string_constant SYS_PATCH_DOWNLOADING_WORD= "DOWNLOADING:";
58__string_constant SYS_PATCH_FETCH= "FETCH";
59__string_constant SYS_PATCH_DL_FINISHED= "DOWNLOADFINISHED:";
60__string_constant SYS_PATCH_TOTAL_STEPS= "TOTALSTEPS:";
61__string_constant SYS_PATCH_SETSTEPS= "SETSTEPS:";
62__string_constant SYS_PATCH_MSG= "MSG:";
63__string_constant SYS_PATCH_FINISHED= "INSTALLFINISHED:";
64
65__string_constant UPDATE_DESCRIPTIONS_FETCH_COMMAND = "fetch -q -o-";
66__string_constant UPDATE_DESCRIPTIONS_URL = "http://fbsd-update.pcbsd.org/updates.desc";
67__string_constant UPDATE_DESCRIPTIONS_FIELDS_SEPARATOR = ":::";
68
69__string_constant FILES_REQUIRED_REBOOT []= { "/boot/*", "/usr/lib/libc*" };
70
71const int FILES_REQUIRED_REBOOT_SIZE = sizeof(FILES_REQUIRED_REBOOT) / sizeof(char*);
72
73///////////////////////////////////////////////////////////////////////////////
74CSysController::CSysController()
75{
76    misFREEBSDCheck= false;
77
78    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
79    env.insert("PCFETCHGUI", "YES");
80    process().setProcessEnvironment(env);
81    misFBSDRebootRequired= false;
82    misRebootRequired = false;
83}
84
85///////////////////////////////////////////////////////////////////////////////
86bool CSysController::rebootRequired()
87{
88    return misRebootRequired && (currentState()!= eUPDATING);
89}
90
91///////////////////////////////////////////////////////////////////////////////
92QVector<CSysController::SFbsdUpdatesDescription> CSysController::updateDescriptions(QString RelName, bool isForse)
93{
94    QVector<CSysController::SFbsdUpdatesDescription> out;
95
96    if (!mvFbsdUpdateDescriptions.size() || isForse)
97    {
98        QStringList fetch_out = pcbsd::Utils::runShellCommand(QString(UPDATE_DESCRIPTIONS_FETCH_COMMAND) + " " + UPDATE_DESCRIPTIONS_URL);
99        mvFbsdUpdateDescriptions.clear();
100        for (int i=0; i<fetch_out.size(); i++)
101        {
102            SFbsdUpdatesDescription entry;
103            QStringList line_split = fetch_out[i].split(UPDATE_DESCRIPTIONS_FIELDS_SEPARATOR);
104            if (line_split.size() < 3)
105                continue;
106            entry.mRelease = line_split[0];
107            entry.mDescription = line_split[2];
108            entry.mUpdateNo = line_split[1].toInt();
109            mvFbsdUpdateDescriptions.push_back(entry);
110        }
111    }
112
113    //filter by RelName
114    for (int i=0; i<mvFbsdUpdateDescriptions.size(); i++)
115    {
116        if ((!RelName.length()) || RelName.trimmed().toUpper() == mvFbsdUpdateDescriptions[i].mRelease.trimmed().toUpper() )
117        {
118            out.push_back(mvFbsdUpdateDescriptions[i]);
119        }
120    }
121    return out;
122}
123
124///////////////////////////////////////////////////////////////////////////////
125void CSysController::updateSelected(QVector<CSysController::SSystemUpdate> selectedUpdates)
126{
127    mvUpdatesToApply= selectedUpdates;
128    mCurrentUpdate= 0;
129    launchUpdate();
130}
131
132///////////////////////////////////////////////////////////////////////////////
133void CSysController::onCheckUpdates()
134{
135    misFREEBSDCheck= false;
136    mvUpdates.clear();
137    mFilesLocallyModifyed.clear();
138    mFilesToRemove.clear();
139    mFilesToUpdate.clear();
140    mCurrentFbsdDescription = tr("Base system update");
141    updateDescriptions();
142}
143
144///////////////////////////////////////////////////////////////////////////////
145void CSysController::onUpdateAll()
146{
147    mvUpdatesToApply = mvUpdates;
148    mCurrentUpdate= 0;
149    launchUpdate();
150}
151
152///////////////////////////////////////////////////////////////////////////////
153void CSysController::checkShellCommand(QString &cmd, QStringList &args)
154{
155    if (misFREEBSDCheck)
156    {
157        cmd= FBSD_UPDATE_COMMAND;
158        args= FBSD_UPDATE_ARGS;
159    }
160    else
161    {
162        cmd= PC_UPDATE_COMMAND;
163        args= PC_UPDATE_ARGS;
164    }
165}
166
167///////////////////////////////////////////////////////////////////////////////
168void CSysController::updateShellCommand(QString &cmd, QStringList &args)
169{
170    if (mCurrentUpdate>=mvUpdatesToApply.size())
171        return;
172
173    ESysUpdate currUpdateType= mvUpdatesToApply[mCurrentUpdate].mType;
174    if ((currUpdateType == ePATCH) || (currUpdateType == eSYSUPDATE))
175    {
176        cmd= PC_UPDATE_COMMAND;
177        args= QStringList()<<"install"<<mvUpdatesToApply[mCurrentUpdate].mTag;
178    }
179    else
180    {
181        cmd="freebsd-update";
182        args= QStringList()<<"install";
183    }
184
185}
186
187///////////////////////////////////////////////////////////////////////////////
188void CSysController::onReadCheckLine(QString line)
189{   
190    if (misFREEBSDCheck)
191        parseCheckFREEBSDLine(line);
192    else
193        parseCheckPCBSDLine(line);
194
195}
196
197///////////////////////////////////////////////////////////////////////////////
198void CSysController::onReadUpdateLine(QString line)
199{
200    line= line.trimmed();
201    if (mCurrentUpdate>=mvUpdatesToApply.size())
202        return;
203    ESysUpdate currUpdateType= mvUpdatesToApply[mCurrentUpdate].mType;
204    misRebootRequired |= mvUpdatesToApply[mCurrentUpdate].misRequiresReboot;
205
206    switch(currUpdateType)
207    {
208        case ePATCH:
209            parsePatchUpdateLine(line);
210            break;
211        case eSYSUPDATE:
212            parseUpgradeLine(line);
213            break;
214        case eFBSDUPDATE:
215            parseFreeBSDUpdateLine(line);
216            break;
217    }
218}
219
220///////////////////////////////////////////////////////////////////////////////
221void CSysController::onReadProcessChar(char character)
222{
223    qDebug()<<character;
224}
225
226///////////////////////////////////////////////////////////////////////////////
227void CSysController::onCheckProcessfinished(int exitCode)
228{
229    if (!misFREEBSDCheck)
230    {       
231        misFREEBSDCheck= true;
232        misFBSDRebootRequired= false;
233        launchCheck();
234    }
235    else
236    {       
237        if (mFilesToRemove.size() || mFilesToUpdate.size())
238        {
239            SSystemUpdate entry;
240            entry.mName = mCurrentFbsdDescription;
241            entry.mType= eFBSDUPDATE;
242            entry.misRequiresReboot= misFBSDRebootRequired;
243            mvUpdates.push_back(entry);
244        }
245
246        int n= mvUpdates.size();
247
248        if (n)
249        {
250
251            if (n>1)
252                reportUpdatesAvail(tr("%1 system updates avilable").arg(QString::number(n)));
253            else
254                reportUpdatesAvail(tr("System update is available"));
255            return;
256        }
257        else
258        {
259            if (!exitCode)
260            {
261                setCurrentState(eFULLY_UPDATED);
262            }
263            else
264            {
265                reportError(tr("Error while system update check process"));
266            }
267            return;
268        }
269    }
270}
271
272///////////////////////////////////////////////////////////////////////////////
273void CSysController::onUpdateProcessfinished(int exitCode)
274{
275    Q_UNUSED(exitCode);
276
277    if (currentState() != eUPDATING)
278        return;
279    mCurrentUpdate++;
280    if (mCurrentUpdate == mvUpdatesToApply.size())
281    {
282        if (misRebootRequired)
283        {
284            system("touch /tmp/.fbsdup-reboot");
285        }
286        check();
287    }
288    else
289    {
290        launchUpdate();
291    }
292}
293
294///////////////////////////////////////////////////////////////////////////////
295void CSysController::onCancel()
296{
297    process().terminate();
298    process().waitForFinished();
299    check();
300}
301
302///////////////////////////////////////////////////////////////////////////////
303void CSysController::parseCheckPCBSDLine(QString line)
304{
305    /*if (line == QString("Your system is up to date!"))
306    {
307        setCurrentState(eFULLY_UPDATED);
308    }*/   
309    static SSystemUpdate upd;
310    line= line.trimmed();
311
312#define _GET_TAG(tag, field)  if(line.indexOf(tag) == 0) {upd.field = line.replace(tag,""); return;}
313    _GET_TAG(NAME_TAG, mName);
314    _GET_TAG(TAG_TAG, mTag);
315    _GET_TAG(VERSION_TAG, mVersion);
316    _GET_TAG(DEATILS_TAG, mDetails);
317    _GET_TAG(SIZE_TAG, mSize);
318#undef _GET_TAG
319
320    if (line.indexOf(TYPE_TAG) == 0)
321    {
322        line= line.replace(TYPE_TAG, "");
323        if (line.contains(SYSUPDATE_TYPE))
324        {
325            upd.mType = eSYSUPDATE;
326        }
327        else
328        {
329            upd.mType = ePATCH;
330        }
331    }
332
333    if (line.indexOf(DATE_TAG) == 0)
334    {
335        //Example:
336        // DATE: 02-10-2013
337        // x     ^0 ^1 ^2   (m-d-y)?
338        QString y,m,d;
339        line= line.replace(DATE_TAG, "");
340        QStringList line_list = line.split("-");
341        upd.mDate= QDate(line_list[2].toInt(),
342                         line_list[0].toInt(),
343                         line_list[1].toInt());       
344        return;
345    }
346
347    if (line.indexOf(STANDALONE_TAG) == 0)
348    {
349        line= line.replace(STANDALONE_TAG, "");
350        if (line.trimmed().toLower() == "yes")
351            upd.misStandalone= true;
352    }
353
354    if (line.indexOf(REQUIRESREBOOT_TAG) == 0)
355    {
356        line= line.replace(REQUIRESREBOOT_TAG, "");
357        if (line.trimmed().toLower() == "yes")
358            upd.misRequiresReboot= true;
359    }
360
361    if (line.indexOf(CU_END_MARKER) == 0)
362    {
363        mvUpdates.push_back(upd);
364        upd = SSystemUpdate();
365        return;
366    }
367}
368
369///////////////////////////////////////////////////////////////////////////////
370void CSysController::parseCheckFREEBSDLine(QString line)
371{
372    typedef enum{
373        eUndefined,
374        eFilesModifyedLocally,
375        eFilesToDelete,
376        eFilesToUpdate
377    }ECheckState;
378
379    static ECheckState currCheckState = eUndefined;
380
381    line=line.trimmed();
382    if (!line.length())
383    {
384        return;
385    }
386
387    if (line.contains(NETWORKING_PROBLEM) && (!mvUpdates.size()))
388    {
389        reportError(tr("Error during update check. Check network connection"));
390    }
391
392    if (line.contains(FILES_MODIFYED_LOCALLY))
393    {
394        currCheckState= eFilesModifyedLocally;       
395        return;
396    }
397    else if (line.contains(FILES_TO_DELETE))
398    {
399        currCheckState= eFilesToDelete;
400        mCurrentFbsdDescription= fbsdUpdateDescription(line);
401        return;
402    }
403    else if (line.contains(FILES_TO_UPDATE))
404    {       
405        currCheckState= eFilesToUpdate;
406        mCurrentFbsdDescription= fbsdUpdateDescription(line);
407
408        return;
409    }
410
411
412    if (eFilesModifyedLocally == currCheckState)
413    {
414        mFilesLocallyModifyed<<line;
415    }
416    else
417    if (eFilesToDelete == currCheckState)
418    {
419        mFilesToRemove<<line;
420    }
421    else
422    if(eFilesToUpdate == currCheckState)
423    {
424        mFilesToUpdate<<line;
425        // Check if reboot requuired.
426        // FILES_REQUIRED_REBOOT const array contains wildcards for files.
427        // Modification of that files requires system reboot
428        QRegExp rx;
429        rx.setPatternSyntax(QRegExp::WildcardUnix);
430        for (int i=0; i<FILES_REQUIRED_REBOOT_SIZE; i++)
431        {
432            rx.setPattern(FILES_REQUIRED_REBOOT[i]);
433            if (rx.exactMatch(line))
434            {
435                misFBSDRebootRequired= true;
436            }//if match
437        }//for all wildcard
438    }
439
440}
441
442///////////////////////////////////////////////////////////////////////////////
443void CSysController::parsePatchUpdateLine(QString line)
444{
445    SProgress progress;
446    static int total_steps = 0;
447    QString dl_speed;
448    long dl_size, dl_complete;
449
450    line= line.trimmed();
451
452    if (line.indexOf(SYS_PATCH_DOWNLOADING_WORD) == 0)
453    {
454        reportLogLine(QString("---------------------"));
455        reportLogLine(QString("Installing update ") + mvUpdatesToApply[mCurrentUpdate].mName);
456        reportLogLine(line.replace(SYS_PATCH_DOWNLOADING_WORD, "Downloading"));
457        progress.mMessage= tr("Preparing to download ") + mvUpdatesToApply[mCurrentUpdate].mName;
458        reportProgress(progress);
459        return;
460    }
461    else
462    if (line.indexOf(SYS_PATCH_FETCH) == 0)
463    {
464        return;
465    }
466    else
467    if (parseFetchOutput(line, dl_size, dl_complete, dl_speed))
468    {
469        progress.mMessage=tr("Downloading update (%1/%2 at %3)").arg(pcbsd::Utils::bytesToHumanReadable(dl_size),
470                                                                   pcbsd::Utils::bytesToHumanReadable(dl_complete),
471                                                                   dl_speed);
472        progress.mProgressMax= dl_size;
473        progress.mProgressCurr= dl_complete;
474        progress.mSubstate= eDownload;
475        progress.misCanCancel= true;
476        reportProgress(progress);
477        return;
478    }
479    else
480    if (line.indexOf(SYS_PATCH_TOTAL_STEPS) == 0)
481    {
482        line.replace(SYS_PATCH_TOTAL_STEPS, "");
483        total_steps= line.toInt();
484        return;
485    }
486    else
487    if (line.indexOf(SYS_PATCH_SETSTEPS) == 0)
488    {
489        line.replace(SYS_PATCH_SETSTEPS, "");
490        progress.mMessage= tr("Installing update ") + mvUpdatesToApply[mCurrentUpdate].mName;
491        progress.mProgressMax= total_steps;
492        progress.mProgressCurr= line.toInt();
493        progress.mSubstate= eInstall;
494        reportProgress(progress);
495        return;
496    }
497    else
498    if (line.indexOf(SYS_PATCH_MSG) == 0)
499    {
500        line.replace(SYS_PATCH_MSG, "");
501        reportLogLine(line);
502        return;
503    }
504    else
505    if (line.indexOf(SYS_PATCH_FINISHED) == 0)
506    {
507        reportLogLine(QString("Finished install: ") + mvUpdatesToApply[mCurrentUpdate].mName);
508        return;
509    }
510
511}
512
513///////////////////////////////////////////////////////////////////////////////
514void CSysController::parseUpgradeLine(QString line)
515{
516    SProgress progress;
517    progress.mMessage = tr("Installing system upgrade");
518    reportProgress(progress);
519    reportLogLine(line);
520}
521
522///////////////////////////////////////////////////////////////////////////////
523void CSysController::parseFreeBSDUpdateLine(QString line)
524{
525    SProgress progress;
526    progress.mMessage = tr("Installing system update");
527    reportProgress(progress);
528    reportLogLine(line);
529}
530
531///////////////////////////////////////////////////////////////////////////////
532QString CSysController::fbsdUpdateDescription(QString line)
533{
534    // Example line: "The following files will be updated as part of updating to 10.0-RELEASE-p3:"
535    line = line.trimmed();
536    QString release = line.right(line.length() - line.lastIndexOf(" "));
537    release = release.left(release.lastIndexOf("-")).trimmed();
538    QString patch = line.right(line.length() - line.lastIndexOf("-")).replace("-p","").replace(':',"");
539    int patch_num = patch.toInt();
540    QVector<SFbsdUpdatesDescription> descrs = updateDescriptions(release);
541
542    QString ret = tr("Base system update");
543
544    for(int i=0; i<descrs.size(); i++)
545    {
546        if (descrs[i].mUpdateNo == patch_num)
547        {
548            ret = descrs[i].mDescription;
549            break;
550        }
551    }
552    return ret;
553}
Note: See TracBrowser for help on using the repository browser.