SoftwareUpdater version 1.0.1

Changes:
-Bug fix in output when no network is detected on x64. Fixes #13345
-Do not display a final notification if SoftwareUpdater is front most
	window (redundant since the same message is displayed in window)
-Remove the "Continue anyway" prompt when no network detected
-Implement the --verbose command option:
	For update and full-sync modes, only displays Terminal output when
	--verbose is used
	For check mode show output on notifications
-Replace the "Show more details" popup menu with a check box
-Replace fprintf commands with other non-formatting commands if no
	formatting is needed (thanks Axel)
-Display a dialog and button to open the Repositories preflet if no
	repositories are enabled
-Do not display confirmation to quit until after downloads have started
This commit is contained in:
Brian Hill 2017-05-01 22:12:59 -04:00
parent 37422dff73
commit b35bccc0a4
16 changed files with 390 additions and 319 deletions

View File

@ -23,10 +23,10 @@ using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate;
CheckAction::CheckAction()
CheckAction::CheckAction(bool verbose)
{
fCheckManager = new(std::nothrow)
CheckManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
CheckManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, verbose);
}
@ -61,7 +61,8 @@ CheckAction::Perform()
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BNothingToDoException ex) {
fprintf(stdout, B_TRANSLATE("There were no updates found."));
puts(B_TRANSLATE("There were no updates found."));
fCheckManager->NoUpdatesNotification();
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BException ex) {

View File

@ -14,7 +14,7 @@
class CheckAction {
public:
CheckAction();
CheckAction(bool verbose);
~CheckAction();
status_t Perform();

View File

@ -15,6 +15,7 @@
#include <sys/ioctl.h>
#include <unistd.h>
#include <Application.h>
#include <Catalog.h>
#include <Message.h>
#include <Messenger.h>
@ -38,12 +39,25 @@ using namespace BPackageKit::BManager::BPrivate;
#define B_TRANSLATION_CONTEXT "CheckManager"
CheckManager::CheckManager(BPackageInstallationLocation location)
CheckManager::CheckManager(BPackageInstallationLocation location,
bool verbose)
:
BPackageManager(location, &fClientInstallationInterface, this),
BPackageManager::UserInteractionHandler(),
fClientInstallationInterface()
fClientInstallationInterface(),
fVerbose(verbose),
fNotificationId("")
{
if (verbose) {
app_info info;
if (be_app->GetAppInfo(&info)!= B_OK)
fVerbose = false;
else
fNotificationId << info.team;
}
fHeaderChecking = B_TRANSLATE("Checking for updates");
fTextContacting = B_TRANSLATE("Contacting software repositories to check "
"for package updates.");
}
@ -62,7 +76,7 @@ CheckManager::CheckNetworkConnection()
}
// No network connection detected, cannot continue
fprintf(stderr, B_TRANSLATE("No active network connection was found.\n"));
fputs(B_TRANSLATE("No active network connection was found.\n"), stderr);
throw BAbortedByUserException();
}
@ -81,7 +95,7 @@ CheckManager::JobFailed(BSupportKit::BJob* job)
void
CheckManager::JobAborted(BSupportKit::BJob* job)
{
printf("Job aborted\n");
puts("Job aborted");
BString error = job->ErrorString();
if (error.Length() > 0) {
error.ReplaceAll("\n", "\n*** ");
@ -90,10 +104,21 @@ CheckManager::JobAborted(BSupportKit::BJob* job)
}
void
CheckManager::NoUpdatesNotification()
{
if (fVerbose) {
BString header = B_TRANSLATE("No updates available");
BString text = B_TRANSLATE("There were no updates found.");
_SendNotification(header.String(), text.String());
}
}
void
CheckManager::HandleProblems()
{
printf("Encountered problems:\n");
puts("Encountered problems:");
int32 problemCount = fSolver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
@ -132,7 +157,7 @@ CheckManager::ConfirmChanges(bool fromMostSpecific)
count << updateCount;
title.ReplaceFirst("%count%", count);
BString text(B_TRANSLATE("Click here to install updates."));
_SendNotification(title, text);
_SendNotification(title.String(), text.String());
}
throw BAbortedByUserException();
}
@ -147,7 +172,7 @@ CheckManager::Warn(status_t error, const char* format, ...)
va_end(args);
if (error == B_OK)
printf("\n");
puts("");
else
printf(": %s\n", strerror(error));
}
@ -156,6 +181,9 @@ CheckManager::Warn(status_t error, const char* format, ...)
void
CheckManager::ProgressPackageDownloadStarted(const char* packageName)
{
if (fVerbose)
_SendNotification(fHeaderChecking.String(), fTextContacting.String());
printf("Downloading %s...\n", packageName);
}
@ -188,18 +216,18 @@ CheckManager::ProgressPackageDownloadActive(const char* packageName,
int ipart = (int)(completionPercentage * width);
int fpart = (int)(((completionPercentage * width) - ipart) * 8);
printf("\r"); // return to the beginning of the line
fputs("\r", stdout); // return to the beginning of the line
for (position = 0; position < width; position++) {
if (position < ipart) {
// This part is fully downloaded, show a full block
printf(progressChars[7]);
fputs(progressChars[7], stdout);
} else if (position > ipart) {
// This part is not downloaded, show a space
printf(" ");
fputs(" ", stdout);
} else {
// This part is partially downloaded
printf(progressChars[fpart]);
fputs(progressChars[fpart], stdout);
}
}
@ -215,12 +243,12 @@ void
CheckManager::ProgressPackageDownloadComplete(const char* packageName)
{
// Overwrite the progress bar with whitespace
printf("\r");
fputs("\r", stdout);
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
for (int i = 0; i < (w.ws_col); i++)
printf(" ");
printf("\r\x1b[1A"); // Go to previous line.
fputs(" ", stdout);
fputs("\r\x1b[1A", stdout); // Go to previous line.
printf("Downloading %s...done.\n", packageName);
}
@ -229,6 +257,9 @@ CheckManager::ProgressPackageDownloadComplete(const char* packageName)
void
CheckManager::ProgressPackageChecksumStarted(const char* title)
{
if (fVerbose)
_SendNotification(fHeaderChecking.String(), title);
printf("%s...", title);
}
@ -236,7 +267,7 @@ CheckManager::ProgressPackageChecksumStarted(const char* title)
void
CheckManager::ProgressPackageChecksumComplete(const char* title)
{
printf("done.\n");
puts("done.");
}
@ -275,11 +306,12 @@ CheckManager::_SendNotification(const char* title, const char* text)
notification.SetTitle(title);
notification.SetContent(text);
notification.SetOnClickApp(kAppSignature);
if(fVerbose)
notification.SetMessageID(fNotificationId);
BBitmap icon(_GetIcon());
if (icon.IsValid())
notification.SetIcon(&icon);
bigtime_t timeout = 30000000;
notification.Send(timeout);
notification.Send();
}

View File

@ -31,11 +31,13 @@ class CheckManager : public BPackageManager,
private BPackageManager::UserInteractionHandler {
public:
CheckManager(
BPackageInstallationLocation location);
BPackageInstallationLocation location,
bool verbose);
void CheckNetworkConnection();
virtual void JobFailed(BSupportKit::BJob* job);
virtual void JobAborted(BSupportKit::BJob* job);
void NoUpdatesNotification();
private:
// UserInteractionHandler
@ -69,6 +71,10 @@ private:
fClientInstallationInterface;
ProblemWindow* fProblemWindow;
bool fVerbose;
BString fNotificationId;
BString fHeaderChecking;
BString fTextContacting;
};

View File

@ -5,7 +5,7 @@ resource app_flags B_SINGLE_LAUNCH;
resource app_version {
major = 1,
middle = 0,
minor = 0,
minor = 1,
variety = B_APPV_BETA,
internal = 0,
short_info = "SoftwareUpdater",

View File

@ -9,6 +9,9 @@
#include "SoftwareUpdaterApp.h"
#include <getopt.h>
#include <stdlib.h>
#include <Catalog.h>
#undef B_TRANSLATION_CONTEXT
@ -16,7 +19,7 @@
static const char* const kUsage = B_TRANSLATE_COMMENT(
"Usage: SoftwareUpdater <command>\n"
"Usage: SoftwareUpdater <command> [ <option> ]\n"
"Updates installed packages.\n"
"\n"
"Commands:\n"
@ -24,16 +27,29 @@ static const char* const kUsage = B_TRANSLATE_COMMENT(
" check - Check for available updates but only display a "
"notification with results.\n"
" full-sync - Synchronize the installed packages with the "
"repositories.\n", "Command line usage help")
"repositories.\n"
"\n"
"Options:\n"
" -h or --help Print this usage help\n"
" -v or --verbose Output verbose information\n",
"Command line usage help")
;
static struct option const kLongOptions[] = {
{"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{NULL}
};
SoftwareUpdaterApp::SoftwareUpdaterApp()
:
BApplication(kAppSignature),
fWorker(NULL),
fFinalQuitFlag(false),
fActionRequested(UPDATE)
fActionRequested(UPDATE),
fVerbose(false),
fArgvsAccepted(true)
{
}
@ -67,29 +83,63 @@ SoftwareUpdaterApp::QuitRequested()
void
SoftwareUpdaterApp::ReadyToRun()
{
fWorker = new WorkingLooper(fActionRequested);
// Argvs no longer accepted once the process starts
fArgvsAccepted = false;
fWorker = new WorkingLooper(fActionRequested, fVerbose);
}
void
SoftwareUpdaterApp::ArgvReceived(int32 argc, char **argv)
{
// Only one command allowed
if (argc > 2) {
fprintf(stderr, kUsage);
PostMessage(B_QUIT_REQUESTED);
if (!fArgvsAccepted) {
fputs(B_TRANSLATE("Argument variables are no longer accepted\n"),
stderr);
return;
} else if (argc == 2) {
fActionRequested = USER_SELECTION_NEEDED;
const char* command = argv[1];
if (strcmp("update", command) == 0)
fActionRequested = UPDATE;
else if (strcmp("check", command) == 0)
fActionRequested = UPDATE_CHECK_ONLY;
else if (strcmp("full-sync", command) == 0)
fActionRequested = FULLSYNC;
else
fprintf(stderr, kUsage);
}
int c;
while ((c = getopt_long(argc, argv, "hv", kLongOptions, NULL)) != -1) {
switch (c) {
case 0:
break;
case 'h':
fputs(kUsage, stdout);
exit(0);
break;
case 'v':
fVerbose = true;
break;
default:
fputs(kUsage, stderr);
exit(1);
break;
}
}
const char* command = "";
int32 argCount = argc - optind;
if (argCount == 0)
return;
else if (argCount > 1) {
fputs(kUsage, stderr);
exit(1);
} else
command = argv[optind];
fActionRequested = USER_SELECTION_NEEDED;
if (strcmp("update", command) == 0)
fActionRequested = UPDATE;
else if (strcmp("check", command) == 0)
fActionRequested = UPDATE_CHECK_ONLY;
else if (strcmp("full-sync", command) == 0)
fActionRequested = FULLSYNC;
else {
fputs(B_TRANSLATE_COMMENT("Unrecognized argument", "Error message"),
stderr);
fprintf(stderr, " \"%s\"\n", command);
fputs(kUsage, stderr);
}
}
@ -116,11 +166,6 @@ SoftwareUpdaterApp::MessageReceived(BMessage* message)
int
main(int argc, const char* const* argv)
{
if (argc > 2) {
fprintf(stderr, kUsage);
return 1;
}
SoftwareUpdaterApp app;
return app.Run();
}

View File

@ -29,6 +29,8 @@ private:
BMessenger fWindowMessenger;
bool fFinalQuitFlag;
update_type fActionRequested;
bool fVerbose;
bool fArgvsAccepted;
};

View File

@ -41,6 +41,7 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow()
fCurrentState(STATE_HEAD),
fWaitingSem(-1),
fWaitingForButton(false),
fUpdateConfirmed(false),
fUserCancelRequested(false),
fWarningAlertCount(0)
{
@ -68,6 +69,10 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow()
fScrollView = new BScrollView("scrollview", fListView, B_WILL_DRAW,
false, true);
fDetailsCheckbox = new BCheckBox("detailscheckbox",
B_TRANSLATE("Show more details"),
new BMessage(kMsgMoreDetailsToggle));
BFont font;
fHeaderView->GetFont(&font);
font.SetFace(B_BOLD_FACE);
@ -87,6 +92,10 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow()
.Add(fScrollView)
.End()
.AddStrut(B_USE_SMALL_SPACING)
.AddGroup(new BGroupView(B_HORIZONTAL))
.Add(fDetailsCheckbox)
.AddGlue()
.End()
.AddGroup(new BGroupView(B_HORIZONTAL))
.AddGlue()
.Add(fCancelButton)
@ -99,6 +108,7 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow()
fProgressLayoutItem = layout_item_for(fStatusBar);
fPackagesLayoutItem = layout_item_for(fScrollView);
fUpdateButtonLayoutItem = layout_item_for(fUpdateButton);
fDetailsCheckboxLayoutItem = layout_item_for(fDetailsCheckbox);
_SetState(STATE_DISPLAY_STATUS);
CenterOnScreen();
@ -186,7 +196,26 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message)
be_app->PostMessage(kMsgFinalQuit);
break;
}
if (!fUpdateConfirmed) {
// Downloads have not started yet, we will request to cancel
// without confirming
Lock();
fHeaderView->SetText(B_TRANSLATE("Cancelling updates"));
fDetailView->SetText(
B_TRANSLATE("Attempting to cancel the updates..."));
fCancelButton->SetEnabled(false);
Unlock();
fUserCancelRequested = true;
if (fWaitingForButton) {
fButtonResult = message->what;
delete_sem(fWaitingSem);
fWaitingSem = -1;
}
break;
}
// Confirm with the user to cancel
BAlert* alert = new BAlert("cancel request", B_TRANSLATE("Updates"
" have not been completed, are you sure you want to quit?"),
B_TRANSLATE("Quit"), B_TRANSLATE("Don't quit"), NULL,
@ -198,7 +227,7 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message)
case kMsgCancelResponse:
{
// Verify whether the cancel request was confirmed
// Verify whether the cancel alert was confirmed
int32 selection = -1;
message->FindInt32("which", &selection);
if (selection != 0)
@ -226,29 +255,19 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message)
fButtonResult = message->what;
delete_sem(fWaitingSem);
fWaitingSem = -1;
fUpdateConfirmed = true;
}
break;
}
case kMsgMoreDetailsToggle:
fListView->SetMoreDetails(fDetailsCheckbox->Value() != 0);
break;
case kMsgWarningDismissed:
fWarningAlertCount--;
break;
case kMsgNetworkAlert:
{
BAlert* alert = new BAlert("network_connection",
B_TRANSLATE_COMMENT("No active network connection was found",
"Alert message"),
B_TRANSLATE_COMMENT("Continue anyway", "Alert button label"),
B_TRANSLATE_COMMENT("Quit","Alert button label"),
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
int32 result = alert->Go();
BMessage reply;
reply.AddInt32(kKeyAlertResult, result);
message->SendReply(&reply);
break;
}
case kMsgGetUpdateType:
{
BString text(
@ -285,6 +304,24 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message)
break;
}
case kMsgNoRepositories:
{
BString text(
B_TRANSLATE_COMMENT(
"No remote repositories are available. Please verify that some"
" repositories are enabled using the Repositories preflet or"
" the \'pkgman\' command.", "Error message"));
BAlert* alert = new BAlert("repositories", text,
B_TRANSLATE_COMMENT("Quit", "Alert button label"),
B_TRANSLATE_COMMENT("Open Repositories","Alert button label"),
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
int32 result = alert->Go();
BMessage reply;
reply.AddInt32(kKeyAlertResult, result);
message->SendReply(&reply);
break;
}
default:
BWindow::MessageReceived(message);
}
@ -423,6 +460,7 @@ SoftwareUpdaterWindow::_SetState(uint32 state)
if (fCurrentState == STATE_HEAD) {
fProgressLayoutItem->SetVisible(false);
fPackagesLayoutItem->SetVisible(false);
fDetailsCheckboxLayoutItem->SetVisible(false);
}
fCurrentState = state;
@ -437,6 +475,7 @@ SoftwareUpdaterWindow::_SetState(uint32 state)
// Show at confirmation prompt, hide at final update
if (fCurrentState == STATE_GET_CONFIRMATION) {
fPackagesLayoutItem->SetVisible(true);
fDetailsCheckboxLayoutItem->SetVisible(true);
// Re-enable resizing
float defaultWidth = fDefaultRect.Width();
SetSizeLimits(defaultWidth, 9999,
@ -444,6 +483,7 @@ SoftwareUpdaterWindow::_SetState(uint32 state)
ResizeTo(defaultWidth, .75 * defaultWidth);
} else if (fCurrentState == STATE_FINAL_MESSAGE) {
fPackagesLayoutItem->SetVisible(false);
fDetailsCheckboxLayoutItem->SetVisible(false);
float defaultWidth = fDefaultRect.Width();
float defaultHeight = fDefaultRect.Height();
SetSizeLimits(defaultWidth, defaultWidth, defaultHeight,
@ -781,44 +821,11 @@ PackageListView::PackageListView()
fLastProgressItem(NULL),
fLastProgressValue(-1)
{
fMenu = new BPopUpMenu(B_EMPTY_STRING, false, false);
fDetailMenuItem = new BMenuItem("Show more details", new BMessage());
fMenu->AddItem(fDetailMenuItem);
SetExplicitMinSize(BSize(B_SIZE_UNSET, 40));
SetExplicitPreferredSize(BSize(B_SIZE_UNSET, 400));
}
void
PackageListView::AttachedToWindow()
{
BOutlineListView::AttachedToWindow();
fDetailMenuItem->SetTarget(this);
}
void
PackageListView::MessageReceived(BMessage* message)
{
switch(message->what)
{
case kMsgMoreDetailsOff:
case kMsgMoreDetailsOn:
{
fShowMoreDetails = message->what == kMsgMoreDetailsOn;
_SetItemHeights();
InvalidateLayout();
ResizeToPreferred();
break;
}
default:
BOutlineListView::MessageReceived(message);
}
}
void
PackageListView::FrameResized(float newWidth, float newHeight)
{
@ -833,31 +840,6 @@ PackageListView::FrameResized(float newWidth, float newHeight)
}
void
PackageListView::MouseDown(BPoint where)
{
BOutlineListView::MouseDown(where);
int32 button;
Looper()->CurrentMessage()->FindInt32("buttons", &button);
if (button & B_SECONDARY_MOUSE_BUTTON) {
if (fShowMoreDetails) {
fDetailMenuItem->SetMarked(true);
fDetailMenuItem->Message()->what = kMsgMoreDetailsOff;
} else {
fDetailMenuItem->SetMarked(false);
fDetailMenuItem->Message()->what = kMsgMoreDetailsOn;
}
// Offset point so cursor isn't over checkmark
ConvertToScreen(&where);
where.x -= 10;
where.y -= 10;
fMenu->Go(where, true, true, BRect(where.x - 2, where.y - 2,
where.x + 2, where.y + 2), true);
}
}
void
PackageListView::AddPackage(uint32 install_type, const char* name,
const char* cur_ver, const char* new_ver, const char* summary,
@ -989,6 +971,16 @@ PackageListView::ItemHeight()
}
void
PackageListView::SetMoreDetails(bool showMore)
{
fShowMoreDetails = showMore;
_SetItemHeights();
InvalidateLayout();
ResizeToPreferred();
}
void
PackageListView::_SetItemHeights()
{

View File

@ -11,12 +11,11 @@
#include <Button.h>
#include <CheckBox.h>
#include <GroupView.h>
#include <OutlineListView.h>
#include <MenuItem.h>
#include <NodeInfo.h>
#include <Point.h>
#include <PopUpMenu.h>
#include <ScrollView.h>
#include <StatusBar.h>
#include <StringView.h>
@ -106,10 +105,7 @@ private:
class PackageListView : public BOutlineListView {
public:
PackageListView();
void AttachedToWindow();
virtual void MessageReceived(BMessage*);
virtual void FrameResized(float newWidth, float newHeight);
virtual void MouseDown(BPoint where);
void AddPackage(uint32 install_type,
const char* name,
const char* cur_ver,
@ -121,6 +117,7 @@ public:
float percent);
void SortItems();
float ItemHeight();
void SetMoreDetails(bool showMore);
private:
void _SetItemHeights();
@ -129,8 +126,6 @@ private:
SuperItem* fSuperInstallItem;
SuperItem* fSuperUninstallItem;
bool fShowMoreDetails;
BPopUpMenu *fMenu;
BMenuItem *fDetailMenuItem;
PackageItem* fLastProgressItem;
int16 fLastProgressValue;
};
@ -174,15 +169,18 @@ private:
BStatusBar* fStatusBar;
PackageListView* fListView;
BScrollView* fScrollView;
BCheckBox* fDetailsCheckbox;
BLayoutItem* fDetailsLayoutItem;
BLayoutItem* fPackagesLayoutItem;
BLayoutItem* fProgressLayoutItem;
BLayoutItem* fUpdateButtonLayoutItem;
BLayoutItem* fDetailsCheckboxLayoutItem;
uint32 fCurrentState;
sem_id fWaitingSem;
bool fWaitingForButton;
uint32 fButtonResult;
bool fUpdateConfirmed;
bool fUserCancelRequested;
BInvoker fCancelAlertResponse;
int32 fWarningAlertCount;

View File

@ -23,10 +23,12 @@ using namespace BPackageKit;
using namespace BPackageKit::BManager::BPrivate;
UpdateAction::UpdateAction()
UpdateAction::UpdateAction(bool verbose)
:
fVerbose(verbose)
{
fUpdateManager = new(std::nothrow)
UpdateManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
UpdateManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, verbose);
}
@ -56,6 +58,7 @@ UpdateAction::Perform(update_type action_request)
fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES
| BPackageManager::B_REFRESH_REPOSITORIES);
fUpdateManager->CheckRepositories();
// fUpdateManager->SetDebugLevel(1);
if(action == UPDATE) {
@ -75,21 +78,24 @@ UpdateAction::Perform(update_type action_request)
ex.Message());
return ex.Error();
} catch (BAbortedByUserException ex) {
fprintf(stderr, "Updates aborted by user: %s\n",
ex.Message().String());
if (fVerbose)
fprintf(stderr, "Updates aborted by user: %s\n",
ex.Message().String());
// No need for a final message since user initiated cancel request
be_app->PostMessage(kMsgFinalQuit);
return B_OK;
} catch (BNothingToDoException ex) {
fprintf(stderr, "Nothing to do while updating packages : %s\n",
ex.Message().String());
if (fVerbose)
fprintf(stderr, "Nothing to do while updating packages : %s\n",
ex.Message().String());
fUpdateManager->FinalUpdate(B_TRANSLATE("No updates available"),
B_TRANSLATE("There were no updates found."));
return B_OK;
} catch (BException ex) {
fprintf(stderr, B_TRANSLATE(
if (fVerbose)
fprintf(stderr, B_TRANSLATE(
"Exception occurred while updating packages : %s\n"),
ex.Message().String());
ex.Message().String());
fUpdateManager->FinalUpdate(B_TRANSLATE("Updates did not complete"),
ex.Message());
return B_ERROR;

View File

@ -14,12 +14,13 @@
class UpdateAction {
public:
UpdateAction();
UpdateAction(bool verbose);
~UpdateAction();
status_t Perform(update_type action_request);
private:
UpdateManager* fUpdateManager;
bool fVerbose;
};

View File

@ -16,12 +16,14 @@
#include <unistd.h>
#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <Message.h>
#include <Messenger.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include <Notification.h>
#include <Roster.h>
#include <package/manager/Exceptions.h>
#include <package/solver/SolverPackage.h>
@ -36,14 +38,16 @@ using namespace BPackageKit::BManager::BPrivate;
#define B_TRANSLATION_CONTEXT "UpdateManager"
UpdateManager::UpdateManager(BPackageInstallationLocation location)
UpdateManager::UpdateManager(BPackageInstallationLocation location,
bool verbose)
:
BPackageManager(location, &fClientInstallationInterface, this),
BPackageManager::UserInteractionHandler(),
fClientInstallationInterface(),
fStatusWindow(NULL),
fCurrentStep(ACTION_STEP_INIT),
fChangesConfirmed(false)
fChangesConfirmed(false),
fVerbose(verbose)
{
fStatusWindow = new SoftwareUpdaterWindow();
_SetCurrentStep(ACTION_STEP_START);
@ -73,25 +77,9 @@ UpdateManager::CheckNetworkConnection()
}
}
// No network connection detected, display warning
int32 result = 0;
BMessenger messenger(fStatusWindow);
if (messenger.IsValid()) {
BMessage message(kMsgNetworkAlert);
BMessage reply;
messenger.SendMessage(&message, &reply);
reply.FindInt32(kKeyAlertResult, &result);
} else {
BAlert* alert = new BAlert("network_connection",
B_TRANSLATE_COMMENT("No active network connection was found",
"Alert message"),
B_TRANSLATE_COMMENT("Continue anyway", "Alert button label"),
B_TRANSLATE_COMMENT("Quit","Alert button label"),
NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
result = alert->Go();
}
if (result)
throw BAbortedByUserException();
// No network connection detected, cannot continue
throw BException(B_TRANSLATE_COMMENT(
"No active network connection was found", "Error message"));
}
@ -110,9 +98,36 @@ UpdateManager::GetUpdateType()
}
void
UpdateManager::CheckRepositories()
{
int32 count = fOtherRepositories.CountItems();
if (fVerbose)
printf("Remote repositories available: %" B_PRId32 "\n", count);
if (count == 0) {
BMessenger messenger(fStatusWindow);
if (messenger.IsValid()) {
BMessage message(kMsgNoRepositories);
BMessage reply;
messenger.SendMessage(&message, &reply);
int32 result;
reply.FindInt32(kKeyAlertResult, &result);
if (result == 1)
be_roster->Launch("application/x-vnd.Haiku-Repositories");
}
be_app->PostMessage(kMsgFinalQuit);
throw BException(B_TRANSLATE_COMMENT(
"No remote repositories are available", "Error message"));
}
}
void
UpdateManager::JobFailed(BSupportKit::BJob* job)
{
if (!fVerbose)
return;
BString error = job->ErrorString();
if (error.Length() > 0) {
error.ReplaceAll("\n", "\n*** ");
@ -124,7 +139,8 @@ UpdateManager::JobFailed(BSupportKit::BJob* job)
void
UpdateManager::JobAborted(BSupportKit::BJob* job)
{
printf("Job aborted\n");
if (fVerbose)
puts("Job aborted");
}
@ -146,67 +162,14 @@ UpdateManager::HandleProblems()
if (!fProblemWindow->Go(fSolver,installPackages, uninstallPackages))
throw BAbortedByUserException();
fProblemWindow->Hide();
/* int32 problemCount = fSolver->CountProblems();
for (int32 i = 0; i < problemCount; i++) {
// print problem and possible solutions
BSolverProblem* problem = fSolver->ProblemAt(i);
printf("problem %" B_PRId32 ": %s\n", i + 1,
problem->ToString().String());
int32 solutionCount = problem->CountSolutions();
for (int32 k = 0; k < solutionCount; k++) {
const BSolverProblemSolution* solution = problem->SolutionAt(k);
printf(" solution %" B_PRId32 ":\n", k + 1);
int32 elementCount = solution->CountElements();
for (int32 l = 0; l < elementCount; l++) {
const BSolverProblemSolutionElement* element
= solution->ElementAt(l);
printf(" - %s\n", element->ToString().String());
}
}
// let the user choose a solution
printf("Please select a solution, skip the problem for now or quit.\n");
for (;;) {
if (solutionCount > 1)
printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
else
printf("select [1/s/q]: ");
char buffer[32];
if (fgets(buffer, sizeof(buffer), stdin) == NULL
|| strcmp(buffer, "q\n") == 0) {
//exit(1);
}
if (strcmp(buffer, "s\n") == 0)
break;
char* end;
long selected = strtol(buffer, &end, 0);
if (end == buffer || *end != '\n' || selected < 1
|| selected > solutionCount) {
printf("*** invalid input\n");
continue;
}
status_t error = fSolver->SelectProblemSolution(problem,
problem->SolutionAt(selected - 1));
if (error != B_OK)
DIE(error, "failed to set solution");
break;
}
}*/
}
void
UpdateManager::ConfirmChanges(bool fromMostSpecific)
{
printf("The following changes will be made:\n");
if (fVerbose)
puts("The following changes will be made:");
int32 count = fInstalledRepositories.CountItems();
int32 upgradeCount = 0;
@ -223,9 +186,10 @@ UpdateManager::ConfirmChanges(bool fromMostSpecific)
installCount, uninstallCount);
}
printf("Upgrade count=%" B_PRId32 ", Install count=%" B_PRId32
", Uninstall count=%" B_PRId32 "\n",
upgradeCount, installCount, uninstallCount);
if (fVerbose)
printf("Upgrade count=%" B_PRId32 ", Install count=%" B_PRId32
", Uninstall count=%" B_PRId32 "\n",
upgradeCount, installCount, uninstallCount);
fChangesConfirmed = fStatusWindow->ConfirmUpdates();
if (!fChangesConfirmed)
@ -243,14 +207,16 @@ UpdateManager::Warn(status_t error, const char* format, ...)
char buffer[256];
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
if (error == B_OK)
printf("\n");
else
printf(": %s\n", strerror(error));
if (fVerbose) {
fputs(buffer, stderr);
if (error == B_OK)
puts("");
else
printf(": %s\n", strerror(error));
}
if (fStatusWindow != NULL) {
if (fStatusWindow->UserCancelRequested())
@ -275,7 +241,8 @@ UpdateManager::ProgressPackageDownloadStarted(const char* packageName)
fNewDownloadStarted = false;
}
printf("Downloading %s...\n", packageName);
if (fVerbose)
printf("Downloading %s...\n", packageName);
}
@ -295,49 +262,51 @@ UpdateManager::ProgressPackageDownloadActive(const char* packageName,
_UpdateDownloadProgress(NULL, packageName, completionValue * 100.0);
}
static const char* progressChars[] = {
"\xE2\x96\x8F",
"\xE2\x96\x8E",
"\xE2\x96\x8D",
"\xE2\x96\x8C",
"\xE2\x96\x8B",
"\xE2\x96\x8A",
"\xE2\x96\x89",
"\xE2\x96\x88",
};
int width = 70;
struct winsize winSize;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winSize) == 0
&& winSize.ws_col < 77) {
// We need 7 characters for the percent display
width = winSize.ws_col - 7;
}
int position;
int ipart = (int)(completionValue * width);
int fpart = (int)(((completionValue * width) - ipart) * 8);
printf("\r"); // return to the beginning of the line
for (position = 0; position < width; position++) {
if (position < ipart) {
// This part is fully downloaded, show a full block
printf(progressChars[7]);
} else if (position > ipart) {
// This part is not downloaded, show a space
printf(" ");
} else {
// This part is partially downloaded
printf(progressChars[fpart]);
if (fVerbose) {
static const char* progressChars[] = {
"\xE2\x96\x8F",
"\xE2\x96\x8E",
"\xE2\x96\x8D",
"\xE2\x96\x8C",
"\xE2\x96\x8B",
"\xE2\x96\x8A",
"\xE2\x96\x89",
"\xE2\x96\x88",
};
int width = 70;
struct winsize winSize;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winSize) == 0
&& winSize.ws_col < 77) {
// We need 7 characters for the percent display
width = winSize.ws_col - 7;
}
int position;
int ipart = (int)(completionValue * width);
int fpart = (int)(((completionValue * width) - ipart) * 8);
fputs("\r", stdout); // return to the beginning of the line
for (position = 0; position < width; position++) {
if (position < ipart) {
// This part is fully downloaded, show a full block
fputs(progressChars[7], stdout);
} else if (position > ipart) {
// This part is not downloaded, show a space
fputs(" ", stdout);
} else {
// This part is partially downloaded
fputs(progressChars[fpart], stdout);
}
}
// Also print the progress percentage
printf(" %3d%%", (int)(completionValue * 100));
fflush(stdout);
}
// Also print the progress percentage
printf(" %3d%%", (int)(completionValue * 100));
fflush(stdout);
}
@ -350,15 +319,17 @@ UpdateManager::ProgressPackageDownloadComplete(const char* packageName)
fPackageDownloadsCount++;
}
// Overwrite the progress bar with whitespace
printf("\r");
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
for (int i = 0; i < (w.ws_col); i++)
printf(" ");
printf("\r\x1b[1A"); // Go to previous line.
printf("Downloading %s...done.\n", packageName);
if (fVerbose) {
// Overwrite the progress bar with whitespace
fputs("\r", stdout);
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
for (int i = 0; i < (w.ws_col); i++)
fputs(" ", stdout);
fputs("\r\x1b[1A", stdout); // Go to previous line.
printf("Downloading %s...done.\n", packageName);
}
}
@ -369,14 +340,16 @@ UpdateManager::ProgressPackageChecksumStarted(const char* title)
if (fCurrentStep == ACTION_STEP_START)
_UpdateStatusWindow(NULL, title);
printf("%s...", title);
if (fVerbose)
printf("%s...", title);
}
void
UpdateManager::ProgressPackageChecksumComplete(const char* title)
{
printf("done.\n");
if (fVerbose)
puts("done.");
}
@ -388,7 +361,8 @@ UpdateManager::ProgressStartApplyingChanges(InstalledRepository& repository)
BString detail(B_TRANSLATE("Packages are being updated"));
fStatusWindow->UpdatesApplying(header.String(), detail.String());
printf("[%s] Applying changes ...\n", repository.Name().String());
if (fVerbose)
printf("[%s] Applying changes ...\n", repository.Name().String());
}
@ -402,30 +376,33 @@ UpdateManager::ProgressTransactionCommitted(InstalledRepository& repository,
"updates."));
_FinalUpdate(header.String(), detail.String());
const char* repositoryName = repository.Name().String();
if (fVerbose) {
const char* repositoryName = repository.Name().String();
int32 issueCount = result.CountIssues();
for (int32 i = 0; i < issueCount; i++) {
const BTransactionIssue* issue = result.IssueAt(i);
if (issue->PackageName().IsEmpty()) {
printf("[%s] warning: %s\n", repositoryName,
issue->ToString().String());
} else {
printf("[%s] warning: package %s: %s\n", repositoryName,
issue->PackageName().String(), issue->ToString().String());
int32 issueCount = result.CountIssues();
for (int32 i = 0; i < issueCount; i++) {
const BTransactionIssue* issue = result.IssueAt(i);
if (issue->PackageName().IsEmpty()) {
printf("[%s] warning: %s\n", repositoryName,
issue->ToString().String());
} else {
printf("[%s] warning: package %s: %s\n", repositoryName,
issue->PackageName().String(), issue->ToString().String());
}
}
printf("[%s] Changes applied. Old activation state backed up in \"%s\"\n",
repositoryName, result.OldStateDirectory().String());
printf("[%s] Cleaning up ...\n", repositoryName);
}
printf("[%s] Changes applied. Old activation state backed up in \"%s\"\n",
repositoryName, result.OldStateDirectory().String());
printf("[%s] Cleaning up ...\n", repositoryName);
}
void
UpdateManager::ProgressApplyingChangesDone(InstalledRepository& repository)
{
printf("[%s] Done.\n", repository.Name().String());
if (fVerbose)
printf("[%s] Done.\n", repository.Name().String());
}
@ -436,7 +413,8 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
if (!installationRepository.HasChanges())
return;
printf(" in %s:\n", installationRepository.Name().String());
if (fVerbose)
printf(" in %s:\n", installationRepository.Name().String());
PackageList& packagesToActivate
= installationRepository.PackagesToActivate();
@ -470,11 +448,12 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
int position = upgradedPackages.IndexOf(package->Info().Name());
if (position >= 0) {
printf(" upgrade package %s-%s to %s from %s\n",
package->Info().Name().String(),
upgradedPackageVersions.StringAt(position).String(),
package->Info().Version().ToString().String(),
repository.String());
if (fVerbose)
printf(" upgrade package %s-%s to %s from %s\n",
package->Info().Name().String(),
upgradedPackageVersions.StringAt(position).String(),
package->Info().Version().ToString().String(),
repository.String());
fStatusWindow->AddPackageInfo(PACKAGE_UPDATE,
package->Info().Name().String(),
upgradedPackageVersions.StringAt(position).String(),
@ -484,10 +463,11 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
package->Info().FileName().String());
upgradeCount++;
} else {
printf(" install package %s-%s from %s\n",
package->Info().Name().String(),
package->Info().Version().ToString().String(),
repository.String());
if (fVerbose)
printf(" install package %s-%s from %s\n",
package->Info().Name().String(),
package->Info().Version().ToString().String(),
repository.String());
fStatusWindow->AddPackageInfo(PACKAGE_INSTALL,
package->Info().Name().String(),
NULL,
@ -504,7 +484,9 @@ UpdateManager::_PrintResult(InstalledRepository& installationRepository,
i++) {
if (upgradedPackages.HasString(package->Info().Name()))
continue;
printf(" uninstall package %s\n", package->VersionedName().String());
if (fVerbose)
printf(" uninstall package %s\n",
package->VersionedName().String());
fStatusWindow->AddPackageInfo(PACKAGE_UNINSTALL,
package->Info().Name().String(),
package->Info().Version().ToString(),
@ -563,14 +545,16 @@ UpdateManager::_UpdateDownloadProgress(const char* header,
void
UpdateManager::_FinalUpdate(const char* header, const char* text)
{
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup("SoftwareUpdater");
notification.SetTitle(header);
notification.SetContent(text);
BBitmap icon(fStatusWindow->GetNotificationIcon());
if (icon.IsValid())
notification.SetIcon(&icon);
notification.Send();
if (!fStatusWindow->IsFront()) {
BNotification notification(B_INFORMATION_NOTIFICATION);
notification.SetGroup("SoftwareUpdater");
notification.SetTitle(header);
notification.SetContent(text);
BBitmap icon(fStatusWindow->GetNotificationIcon());
if (icon.IsValid())
notification.SetIcon(&icon);
notification.Send();
}
fStatusWindow->FinalUpdate(header, text);
}

View File

@ -29,11 +29,13 @@ class UpdateManager : public BPackageManager,
private BPackageManager::UserInteractionHandler {
public:
UpdateManager(
BPackageInstallationLocation location);
BPackageInstallationLocation location,
bool verbose);
~UpdateManager();
void CheckNetworkConnection();
update_type GetUpdateType();
void CheckRepositories();
virtual void JobFailed(BSupportKit::BJob* job);
virtual void JobAborted(BSupportKit::BJob* job);
void FinalUpdate(const char* header,
@ -91,6 +93,7 @@ private:
bool fNewDownloadStarted;
int32 fPackageDownloadsTotal;
int32 fPackageDownloadsCount;
bool fVerbose;
};

View File

@ -10,12 +10,13 @@
#include "WorkingLooper.h"
WorkingLooper::WorkingLooper(update_type action)
WorkingLooper::WorkingLooper(update_type action, bool verbose)
:
BLooper("WorkingLooper"),
fUpdateAction(NULL),
fCheckAction(NULL),
fActionRequested(action)
fActionRequested(action),
fVerbose(verbose)
{
Run();
PostMessage(kMsgStart);
@ -36,10 +37,10 @@ WorkingLooper::MessageReceived(BMessage* message)
case kMsgStart:
{
if (fActionRequested == UPDATE_CHECK_ONLY) {
fCheckAction = new CheckAction;
fCheckAction = new CheckAction(fVerbose);
fCheckAction->Perform();
} else {
fUpdateAction = new UpdateAction();
fUpdateAction = new UpdateAction(fVerbose);
fUpdateAction->Perform(fActionRequested);
}
break;

View File

@ -21,7 +21,7 @@ const uint32 kMsgStart = 'iSTA';
class WorkingLooper : public BLooper {
public:
WorkingLooper(update_type action);
WorkingLooper(update_type action, bool verbose);
~WorkingLooper();
void MessageReceived(BMessage* message);
@ -29,6 +29,7 @@ private:
UpdateAction* fUpdateAction;
CheckAction* fCheckAction;
update_type fActionRequested;
bool fVerbose;
};

View File

@ -46,12 +46,11 @@ static const uint32 kMsgCancel = 'iCAN';
static const uint32 kMsgCancelResponse = 'iCRE';
static const uint32 kMsgUpdateConfirmed = 'iCON';
static const uint32 kMsgWarningDismissed = 'iWDI';
static const uint32 kMsgNetworkAlert = 'iNAL';
static const uint32 kMsgGetUpdateType = 'iGUP';
static const uint32 kMsgNoRepositories = 'iNRE';
static const uint32 kMsgRegister = 'iREG';
static const uint32 kMsgFinalQuit = 'iFIN';
static const uint32 kMsgMoreDetailsOn = 'iDON';
static const uint32 kMsgMoreDetailsOff = 'iDOF';
static const uint32 kMsgMoreDetailsToggle = 'iDTO';
// Message data keys
#define kKeyHeader "key_header"