diff --git a/src/apps/softwareupdater/Jamfile b/src/apps/softwareupdater/Jamfile index bdea8f0286..4fd6d404da 100644 --- a/src/apps/softwareupdater/Jamfile +++ b/src/apps/softwareupdater/Jamfile @@ -1,11 +1,10 @@ SubDir HAIKU_TOP src apps softwareupdater ; -UsePrivateHeaders interface shared ; - Application SoftwareUpdater : SoftwareUpdaterApp.cpp SoftwareUpdaterWindow.cpp StripeView.cpp - : be localestub tracker translation [ TargetLibsupc++ ] + UpdateManager.cpp + : be localestub package translation [ TargetLibsupc++ ] : SoftwareUpdater.rdef ; diff --git a/src/apps/softwareupdater/SoftwareUpdaterWindow.cpp b/src/apps/softwareupdater/SoftwareUpdaterWindow.cpp index 43c38f28e7..a1856cdccf 100644 --- a/src/apps/softwareupdater/SoftwareUpdaterWindow.cpp +++ b/src/apps/softwareupdater/SoftwareUpdaterWindow.cpp @@ -12,16 +12,17 @@ #include #include #include -#include #include #include #include #include #include +#include +#include +#include #include #include #include -#include #undef B_TRANSLATION_CONTEXT @@ -32,13 +33,25 @@ const uint32 kMsgUpdate = 'iUPD'; const uint32 kMsgExit = 'iEXT'; +using namespace BPackageKit; + + SoftwareUpdaterWindow::SoftwareUpdaterWindow() : BWindow(BRect(0, 0, 0, 300), "Software Update", B_TITLED_WINDOW, B_AUTO_UPDATE_SIZE_LIMITS | B_NOT_ZOOMABLE), - fStripeView(NULL) +// fUpdateManager(NULL), + fStripeView(NULL), + fHeaderView(NULL), + fDetailView(NULL), + fUpdateButton(NULL), + fCancelButton(NULL) { - uint32 updatesAvailable = 45; + fUpdateManager = new UpdateManager( + BPackageKit::B_PACKAGE_INSTALLATION_LOCATION_HOME); + fUpdateManager->SetDebugLevel(10); + fUpdateManager->Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES + | BPackageManager::B_ADD_REMOTE_REPOSITORIES); BBitmap* icon = new BBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32); team_info teamInfo; @@ -49,40 +62,23 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow() fStripeView = new StripeView(icon); - BButton* updateButton = new BButton("Update now", + BButton* fUpdateButton = new BButton("Update now", new BMessage(kMsgUpdate)); + fUpdateButton->Hide(); - BButton* exitButton = new BButton("Cancel", + BButton* fCancelButton = new BButton("Cancel", new BMessage(kMsgExit)); - // Form text based on updates available - BStringView* headerView; - BStringView* detailView; - - if (updatesAvailable > 0) { - headerView = new BStringView("header", - "Software updates are available.", B_WILL_DRAW); - char detailString[1024]; - snprintf(detailString, 1024, "There are %" B_PRIu32 " updates available" - " for your system.", updatesAvailable); - detailView = new BStringView("detail", detailString, B_WILL_DRAW); - updateButton->MakeDefault(true); - } else { - headerView = new BStringView("header", - "Your system is up to date.", B_WILL_DRAW); - detailView = new BStringView("detail", - "No updates are available at this time.", - B_WILL_DRAW); - updateButton->Hide(); - exitButton->SetLabel("Quit"); - exitButton->MakeDefault(true); - } + fHeaderView = new BStringView("header", + "Checking for updates...", B_WILL_DRAW); + fDetailView = new BStringView("detail", "Contacting software repositories" + " to check for package updates.", B_WILL_DRAW); BFont font; - headerView->GetFont(&font); + fHeaderView->GetFont(&font); font.SetFace(B_BOLD_FACE); font.SetSize(font.Size() * 1.5); - headerView->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE + fHeaderView->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE | B_FONT_FLAGS); BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0) @@ -90,13 +86,13 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow() .AddGroup(B_VERTICAL, B_USE_SMALL_SPACING) .SetInsets(0, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) - .Add(headerView) - .Add(detailView) + .Add(fHeaderView) + .Add(fDetailView) .AddStrut(B_USE_DEFAULT_SPACING) .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) .AddGlue() - .Add(exitButton) - .Add(updateButton) + .Add(fCancelButton) + .Add(fUpdateButton) .End() .End() .AddGlue() @@ -104,6 +100,9 @@ SoftwareUpdaterWindow::SoftwareUpdaterWindow() ; CenterOnScreen(); Show(); + + // Refresh our repos and update UI + _Refresh(); } @@ -133,3 +132,45 @@ SoftwareUpdaterWindow::MessageReceived(BMessage* message) BWindow::MessageReceived(message); } } + + +void +SoftwareUpdaterWindow::_Error(const char* error) +{ + fHeaderView->SetText("Error encountered!"); + fDetailView->SetText(error); + fUpdateButton->Hide(); + fCancelButton->Show(); +} + +void +SoftwareUpdaterWindow::_Refresh() +{ + BPackageRoster roster; + BStringList repoNames(20); + + status_t result = roster.GetRepositoryNames(repoNames); + if (result != B_OK) { + _Error("Unable to obtain repository names."); + return; + } + + for (int i = 0; i < repoNames.CountStrings(); i++) { + const BString& repoName = repoNames.StringAt(i); + BRepositoryConfig repoConfig; + result = roster.GetRepositoryConfig(repoName, &repoConfig); + if (result != B_OK) { + printf("Skipping '%s' repo due to unknown config\n", + repoName.String()); + continue; + } + /* + BRefreshRepositoryRequest request(context, repoConfig); + result = request.Process(); + if (result != B_OK) { + printf("Skipping %s repo due to unreachable repo"); + continue; + } + */ + } +} diff --git a/src/apps/softwareupdater/SoftwareUpdaterWindow.h b/src/apps/softwareupdater/SoftwareUpdaterWindow.h index fb3d979b76..a0776b1de2 100644 --- a/src/apps/softwareupdater/SoftwareUpdaterWindow.h +++ b/src/apps/softwareupdater/SoftwareUpdaterWindow.h @@ -9,11 +9,13 @@ #define _SOFTWARE_UPDATER_WINDOW_H +#include #include -#include +#include #include #include "StripeView.h" +#include "UpdateManager.h" class SoftwareUpdaterWindow : public BWindow { @@ -25,8 +27,17 @@ public: void MessageReceived(BMessage* message); private: + void _Error(const char* error); + void _Refresh(); + + UpdateManager* fUpdateManager; StripeView* fStripeView; app_info* fAppInfo; + + BStringView* fHeaderView; + BStringView* fDetailView; + BButton* fUpdateButton; + BButton* fCancelButton; }; diff --git a/src/apps/softwareupdater/UpdateManager.cpp b/src/apps/softwareupdater/UpdateManager.cpp new file mode 100644 index 0000000000..8242a9d2e3 --- /dev/null +++ b/src/apps/softwareupdater/UpdateManager.cpp @@ -0,0 +1,345 @@ +/* + * Copyright 2013-2015, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler + * Rene Gollent + * Ingo Weinhold + */ + + +#include "UpdateManager.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace BPackageKit; + + +UpdateManager::UpdateManager(BPackageInstallationLocation location) + : + BPackageManager(location, &fClientInstallationInterface, this), + BPackageManager::UserInteractionHandler(), + fClientInstallationInterface() +{ +} + + +UpdateManager::~UpdateManager() +{ +} + + +void +UpdateManager::JobFailed(BSupportKit::BJob* job) +{ + BString error = job->ErrorString(); + if (error.Length() > 0) { + error.ReplaceAll("\n", "\n*** "); + fprintf(stderr, "%s", error.String()); + } +} + + +void +UpdateManager::JobAborted(BSupportKit::BJob* job) +{ + //DIE(job->Result(), "aborted"); +} + + +void +UpdateManager::HandleProblems() +{ + 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"); + + int32 count = fInstalledRepositories.CountItems(); + if (fromMostSpecific) { + for (int32 i = count - 1; i >= 0; i--) + _PrintResult(*fInstalledRepositories.ItemAt(i)); + } else { + for (int32 i = 0; i < count; i++) + _PrintResult(*fInstalledRepositories.ItemAt(i)); + } + + /* + if (!fDecisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "yes", + "no", "yes")) { + //exit(1); + } + */ +} + + +void +UpdateManager::Warn(status_t error, const char* format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + if (error == B_OK) + printf("\n"); + else + printf(": %s\n", strerror(error)); +} + + +void +UpdateManager::ProgressPackageDownloadStarted(const char* packageName) +{ + printf("Downloading %s...\n", packageName); +} + + +void +UpdateManager::ProgressPackageDownloadActive(const char* packageName, + float completionPercentage, off_t bytes, off_t totalBytes) +{ + return; + /* + if (!fInteractive) + return; + + 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)(completionPercentage * width); + int fpart = (int)(((completionPercentage * 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]); + } + } + + // Also print the progress percentage + printf(" %3d%%", (int)(completionPercentage * 100)); + + fflush(stdout); + */ +} + + +void +UpdateManager::ProgressPackageDownloadComplete(const char* packageName) +{ + // 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); +} + + +void +UpdateManager::ProgressPackageChecksumStarted(const char* title) +{ + printf("%s...", title); +} + + +void +UpdateManager::ProgressPackageChecksumComplete(const char* title) +{ + printf("done.\n"); +} + + +void +UpdateManager::ProgressStartApplyingChanges(InstalledRepository& repository) +{ + printf("[%s] Applying changes ...\n", repository.Name().String()); +} + + +void +UpdateManager::ProgressTransactionCommitted(InstalledRepository& repository, + const BCommitTransactionResult& result) +{ + 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()); + } + } + + 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()); +} + + +void +UpdateManager::_PrintResult(InstalledRepository& installationRepository) +{ + if (!installationRepository.HasChanges()) + return; + + printf(" in %s:\n", installationRepository.Name().String()); + + PackageList& packagesToActivate + = installationRepository.PackagesToActivate(); + PackageList& packagesToDeactivate + = installationRepository.PackagesToDeactivate(); + + BStringList upgradedPackages; + BStringList upgradedPackageVersions; + for (int32 i = 0; + BSolverPackage* installPackage = packagesToActivate.ItemAt(i); + i++) { + for (int32 j = 0; + BSolverPackage* uninstallPackage = packagesToDeactivate.ItemAt(j); + j++) { + if (installPackage->Info().Name() == uninstallPackage->Info().Name()) { + upgradedPackages.Add(installPackage->Info().Name()); + upgradedPackageVersions.Add(uninstallPackage->Info().Version().ToString()); + break; + } + } + } + + for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i); + i++) { + BString repository; + if (dynamic_cast(package->Repository()) != NULL) + repository = "local file"; + else + repository.SetToFormat("repository %s", package->Repository()->Name().String()); + + 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()); + } else { + printf(" install package %s-%s from %s\n", + package->Info().Name().String(), + package->Info().Version().ToString().String(), + repository.String()); + } + } + + for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i); + i++) { + if (upgradedPackages.HasString(package->Info().Name())) + continue; + printf(" uninstall package %s\n", package->VersionedName().String()); + } +} diff --git a/src/apps/softwareupdater/UpdateManager.h b/src/apps/softwareupdater/UpdateManager.h new file mode 100644 index 0000000000..efef0bb48c --- /dev/null +++ b/src/apps/softwareupdater/UpdateManager.h @@ -0,0 +1,71 @@ +/* + * Copyright 2013-2015, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Ingo Weinhold + * Rene Gollent + */ +#ifndef UPDATE_MANAGER_H +#define UPDATE_MANAGER_H + + +#include +#include + + +//using namespace BPackageKit; +using BPackageKit::BPrivate::BDaemonClient; +using BPackageKit::BManager::BPrivate::BPackageManager; + + +class UpdateManager : public BPackageManager, + private BPackageManager::UserInteractionHandler { +public: + UpdateManager( + BPackageKit::BPackageInstallationLocation location); + ~UpdateManager(); + + virtual void JobFailed(BSupportKit::BJob* job); + virtual void JobAborted(BSupportKit::BJob* job); + +private: + // UserInteractionHandler + virtual void HandleProblems(); + virtual void ConfirmChanges(bool fromMostSpecific); + + virtual void Warn(status_t error, const char* format, ...); + + + virtual void ProgressPackageDownloadStarted( + const char* packageName); + virtual void ProgressPackageDownloadActive( + const char* packageName, + float completionPercentage, + off_t bytes, off_t totalBytes); + virtual void ProgressPackageDownloadComplete( + const char* packageName); + virtual void ProgressPackageChecksumStarted( + const char* packageName); + virtual void ProgressPackageChecksumComplete( + const char* packageName); + + virtual void ProgressStartApplyingChanges( + InstalledRepository& repository); + virtual void ProgressTransactionCommitted( + InstalledRepository& repository, + const BPackageKit::BCommitTransactionResult& result); + virtual void ProgressApplyingChangesDone( + InstalledRepository& repository); + +private: + void _PrintResult(InstalledRepository& + installationRepository); + +private: + BPackageManager::ClientInstallationInterface + fClientInstallationInterface; +}; + + +#endif // UPDATE_MANAGER_H