[PC-BSD Dev] pcbsd system source idea and question

Ken Moore ken at pcbsd.org
Mon Dec 23 04:50:51 PST 2013

On 12/22/13 00:39, Joe Maloney wrote:
> In order to make this work with pbsystemtab.ui could you give an example?  In particular I am not sure what I should do for this section.
> void PBSystemTab::fetchPortsPressed()
> {
>      portsnapUI = new PortsnapProc();
>      portsnapUI->init(true, Version);
>      portsnapUI->show();
> }
> Joe Maloney
> On Dec 21, 2013, at 6:49 PM, Ken Moore <ken at pcbsd.org> wrote:
>> On 12/21/13 16:02, Joe Maloney wrote:
>>> I’ve made the necessary changes as suggested and now it’s working much better.
>>> http://pastebin.com/ka5U9E1i
>>> The only thing I’m missing is a way to connect these processes to most importantly fetchDone.  If I were somehow able to do this I should be able to have initPorts continue on to startPorts without the need for two buttons, initPorts, startPorts.  I know this was working at least before I changed initPorts to also use  QCoreApplication::processEvents() as I did initially for startPorts.
>>> I believe that I could also use  QCoreApplication::processEvents(); to put everything under startPorts() and do away with initPorts.  I’m starting to understand how it works now.  The second button idea would also still be an easy fix.
>>> However the blocker is I still need a way to tell the portsnapprogress GUI that the task is done running. Otherwise it just sits there with a cancel button even when it’s finished no matter how I go about it.
>>> I’m not sure how to implement something like this if it’s even possible without closing the entire application when finished.
>>> portsnap->setProcessChannelMode(QProcess::MergedChannels);
>>> connect(portsnap, SIGNAL(readyReadStandardOutput()), this, SLOT(parseUpdate()));
>>> connect(portsnap, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(fetchDone()));
>>> Joe Maloney
>>> On Dec 19, 2013, at 8:24 AM, Ken Moore <ken at pcbsd.org> wrote:
>>>> On 12/19/13 09:16, Kris Moore wrote:
>>>>> On 12/19/2013 03:12, Joe Maloney wrote:
>>>>>> Here is what I've been able to come up with now for a more simple version.
>>>>>> http://pastebin.com/7PHASL4S
>>>>>> I've been testing and it works but it takes about 25 minutes to fetch all the source.
>>>>>> I had to use something like this to make up for not being able to run to instances of prog, args in startPorts to run two git commands on after another.:
>>>>>> system("git --git-dir=/usr/ports/.git fetch" );
>>>>>> Otherwise they would run at the same time which would be bad.  I'm not sure of a better way to do it at this point but my gut tells me using system() might not be a great idea.
>>>>>> I haven't commited this yet as it's really slow and I figured I would see what your thoughts were first.
>>>>>> Joe Maloney
>>>>> So, to speed it up, I would add --depth=1, which will greatly speed up the initial checkout.
>>>>> # git clone --depth=1 https://github.com/pcbsd/freebsd-ports.git
>>>>> I do that on my builders here and it took the checkout from 20 minutes down to about 45 seconds :)
>>>>> As for using "system" it may be better to use QProcess::execute() instead.
>>>> -snip-
>>>> Since you are already using QProcesses, you can also have it run QCoreApplication::processEvents() in regular intervals while the command is running to prevent the GUI from hanging like this:
>>>> --------------------------
>>>> proc->start("command")
>>>> while(!proc->waitForFinished(500)){ //0.5 sec wait
>>>>    QCoreApplication::processEvents();
>>>> }
>>>> if( proc->exitCode() != 0){ qDebug() << "Error"; }
>>>> else{
>>>>    proc->start("command 2")
>>>> }
>>>> ---------------------------
>>>> and repeat as necessary to run other commands in sequence.
>>>> You might want to look at the QProcess.setWorkingDirectory() function as well, so you might not need to run special flags for running in an alternate directory if you just make the process "change" into the directory you want to run from.
>>>> -- 
>>>> ~~ Ken Moore ~~
>>>> PC-BSD/iXsystems
>>>> _______________________________________________
>>>> Dev mailing list
>>>> Dev at lists.pcbsd.org
>>>> http://lists.pcbsd.org/mailman/listinfo/dev
>> First impression:
>> There is a bit of a disconnect between the InitPorts(), startPorts(), and startSource() functions in that they all use different QProcesses - so only the startSource/portsnap process will actually send out the update and finished signals. I would set them all up to use a single known QProcess (portsnap) for all the long downloads to make use of the signals without a lot of duplication (assuming you only plan on one of these running at a time).
>> My recommendation:
>> It seems like you need to disconnect the process from the GUI a bit more - maybe just subclass QProcess and add a couple special signals for GUI output.
>> For instance, something like the quick header file I am attaching should work quite well for you. You will just need to fill in the rest of the functions (and probably put the special ones I explicitly wrote out into a companion *.cpp file), but it should give you the general idea at least. The basic idea is that you just have a single PortsnapProc in your GUI class that you can just connect the signals to GUI slots that will update the GUI appropriately - while all the "grisly bits" can be separated out of the GUI class this way.
>> -- 
>> ~~ Ken Moore ~~
>> PC-BSD/iXsystems
>> <portsnapProc.h>
In your *.h file for the GUI, you just make sure you have this declared:
  PortsnapProc *longProcess;
And in the GUI *.cpp file you set it up like this:
<in Initilization code>
longProcess = new PortsnapProc;
   connect(longProcess, SIGNAL(ProcMessage(QString)), this, 
SLOT(UpdateProcessDisplay(QString)) );
   connect(longProcess, SIGNAL(procFinished(bool)), this, 
SLOT(ProcessFinished(bool)) );

<To use it to start a process in a later function>
if( longProcess->isRunning() ){
qDebug() << "Ports are already being modified, try again after it finishes";
if( longProcess->startInitPorts() ){ qDebug() << "Ports init started 
successfully"; }
else{ qDebug() << "Ports init could not be started"; }
(same idea to just use startPorts() or startSource() )

The main distinction is that you just need to treat it like another 
simple variable (like a QString), you don't need to worry about 
"init"ing it or showing it because it is just a background process 
worker. Once you have the two signals connected to the GUI slots below, 
you basically just need to call the appropriate "start" function on it 
to get it going.

sample GUI connection slots
void UpdateProcessDisplay(QString msg){

void ProcessFinished(bool success){
     QMessageBox::info(this, tr("Success"), tr("Ports Tree successfully 
modified") );
     QMessageBox::warning(this, tr("Failure"), tr("Ports Tree 
modification failed") );
   //Clean up the display
   ui->lineEdit_processDisplay->setVisible(false); //assuming you make 
it visible appropraitely

If you want to get more information out of the process regarding failure 
messages and such, it then becomes just a trivial modification to the 
signal/slot to add another output variable (like a QStringList with an 
error log).

I hope this helps!

~~ Ken Moore ~~

More information about the Dev mailing list