[haiku-development] Re: Package Kit woes - Need help ASAP

  • From: Brian Hill <brianh@xxxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Sat, 31 Dec 2016 09:37:30 -0500

On 12/21/2016 12:42 AM, kallisti5 wrote:

BRefreshRepositoryRequest is where things start getting painful, that
context is a BContext
which needs all kinds of custom Decision providers and Job state
listeners defined.
(which seems insane to me as you generally don't have very many
decisions around refreshing
repositories)

At a quick glance it seems ATM there is indeed no decision making needed in 
this case. When we start to use cryptographically verify the repository 
origin and integrity, however, encountering a new repository certificate will 
definitely be something that requires a user interaction. I don't know how 
you want to handle it other than with a callback. 

TBH, I'm not too fond of the BDecisionProvider interface. But that's mainly 
because the callback interface is completely text based. Currently it isn't 
really practical to handle certain decisions programmatically, because you'd 
have to parse the (theoretically internationalized) question text to 
determine what it is about. 

That aside, neither BDecisionProvider nor BJobStateListener are abstract. If 
you don't need job progress updates and always want to go with the default 
decisions, you don't need to subclass anything and can refresh the cache for 
a given repository in 5 lines (4, if you omit the BRefreshRepositoryRequest 
variable). Another line could be saved by introducing a BContext constructor 
that doesn't require a BJobStateListener (I'd rather keep and explicit 
BDecisionProvider parameter, though). 

CU, Ingo

If you need an example you can take a look at my implementation of these here:
https://github.com/Perelandra0x309/depots/blob/master/src/TaskLooper.h

A dummy decision provider only takes 10 lines of code.  And the job state 
listener is totally usable in a GUI application.  I found the way these were 
designed very usable for my needs and looking at the pkgman code as an example 
I cut out all the command interface code and made it usable for my purpose.  I 
can see how if there is a need an Alert or other custom dialog window can be 
used for decision making.  Here is an example of what I was able to do:


class DecisionProvider : public BPackageKit::BDecisionProvider {
public:
                                                                
DecisionProvider(){}

        virtual bool                            YesNoDecisionNeeded(const 
BString& description,
                                                                        const 
BString& question,
                                                                        const 
BString& yes,
                                                                        const 
BString& no,
                                                                        const 
BString& defaultChoice)
                                                                        { 
return true; }
};


class JobStateListener : public BSupportKit::BJobStateListener {
public:
                                                                
JobStateListener(){}

        virtual void                            JobStarted(BSupportKit::BJob* 
job);
        virtual void                            JobSucceeded(BSupportKit::BJob* 
job);
        virtual void                            JobFailed(BSupportKit::BJob* 
job);
        virtual void                            JobAborted(BSupportKit::BJob* 
job);
        BString                                         GetJobLog();

private:
                        BStringList                     fJobLog;
};



static const BString kLogResultIndicator = "***";
static const BString kCompletedText =
        B_TRANSLATE_COMMENT("Completed", "Completed task status message");
static const BString kFailedText =
        B_TRANSLATE_COMMENT("Failed", "Failed task status message");
static const BString kAbortedText =
        B_TRANSLATE_COMMENT("Aborted", "Aborted task status message");
static const BString kDescriptionText =
        B_TRANSLATE_COMMENT("Description", "Failed task error description");
static const BString kDetailsText =
        B_TRANSLATE_COMMENT("Details", "Job log details header");


using BSupportKit::BJob;


void
JobStateListener::JobStarted(BJob* job)
{
        fJobLog.Add(job->Title());
}


void
JobStateListener::JobSucceeded(BJob* job)
{
        BString resultText(kLogResultIndicator);
        fJobLog.Add(resultText.Append(kCompletedText));
}


void
JobStateListener::JobFailed(BJob* job)
{
        BString resultText(kLogResultIndicator);
        resultText.Append(kFailedText).Append(": ")
                .Append(strerror(job->Result()));
        fJobLog.Add(resultText);
        if(job->ErrorString().Length() > 0) {
                resultText.SetTo(kLogResultIndicator);
                resultText.Append(kDescriptionText).Append(": ")
                        .Append(job->ErrorString());
                fJobLog.Add(resultText);
        }
}


void
JobStateListener::JobAborted(BJob* job)
{
        BString resultText(kLogResultIndicator);
        resultText.Append(kAbortedText).Append(": ")
                .Append(strerror(job->Result()));
        fJobLog.Add(resultText);
        if(job->ErrorString().Length() > 0) {
                resultText.SetTo(kLogResultIndicator);
                resultText.Append(kDescriptionText).Append(": ")
                        .Append(job->ErrorString());
                fJobLog.Add(resultText);
        }
}


BString
JobStateListener::GetJobLog()
{
        return fJobLog.Join("\n");
}


-Brian

Other related posts: