Debugger: Add initial support for automatically installing packages.

DwarfLoadingStateHandler now attempts to locate a matching package for the
missing debug information file. If one is found, the user is prompted to
install it. The actual installation process is currently handled by calling
pkgman, but this will be adjusted in future commits to either rely on
HaikuDepot in the graphical case, or to integrate the requisite functionality
directly so that proper download/installation progress can be shown.

In any case, this completes the low level functionality for ticket #10138,
leaving mainly presentation issues.
This commit is contained in:
Rene Gollent 2014-06-15 16:40:31 -04:00
parent bbf320ecfe
commit 3fc9fd5624
2 changed files with 169 additions and 16 deletions

View File

@ -6,15 +6,32 @@
#include "DwarfLoadingStateHandler.h"
#include <sys/wait.h>
#include <Entry.h>
#include <Path.h>
#include <package/solver/Solver.h>
#include <package/solver/SolverPackage.h>
#include "AutoDeleter.h"
#include "DwarfFile.h"
#include "DwarfImageDebugInfoLoadingState.h"
#include "package/manager/PackageManager.h"
#include "Tracing.h"
#include "UserInterface.h"
using namespace BPackageKit;
using BPackageKit::BManager::BPrivate::BPackageManager;
enum {
USER_CHOICE_INSTALL_PACKAGE = 0,
USER_CHOICE_LOCATE_FILE ,
USER_CHOICE_SKIP
};
DwarfLoadingStateHandler::DwarfLoadingStateHandler()
:
ImageDebugLoadingStateHandler()
@ -50,24 +67,143 @@ DwarfLoadingStateHandler::HandleState(
DwarfFileLoadingState& fileState = dwarfState->GetFileState();
// TODO: if the image in question is packaged, query if it has a
// corresponding debug info package. If so, offer to install it and
// then locate the file automatically rather than forcing the user to
// locate the file manually.
BString message;
message.SetToFormat("The debug information file '%s' for image '%s' is "
"missing. Please locate it if possible.",
fileState.externalInfoFileName.String(), fileState.dwarfFile->Name());
int32 choice = interface->SynchronouslyAskUser("Debug info missing",
message.String(), "Locate", "Skip", NULL);
BString requiredPackage;
_GetMatchingDebugInfoPackage(fileState.externalInfoFileName,
requiredPackage);
if (choice == 0) {
entry_ref ref;
interface->SynchronouslyAskUserForFile(&ref);
BPath path(&ref);
if (path.InitCheck() == B_OK)
fileState.locatedExternalInfoPath = path.Path();
// loop so that the user has a chance to retry or locate the file manually
// in case package installation fails, e.g. due to transient download
// issues.
for (;;) {
int32 choice;
BString message;
if (interface->IsInteractive()) {
if (requiredPackage.IsEmpty()) {
message.SetToFormat("The debug information file '%s' for "
"image '%s' is missing. Would you like to locate the file "
"manually?", fileState.externalInfoFileName.String(),
fileState.dwarfFile->Name());
choice = interface->SynchronouslyAskUser("Debug info missing",
message.String(), "Locate", "Skip", NULL);
if (choice == 0)
choice = USER_CHOICE_LOCATE_FILE;
else if (choice == 1)
choice = USER_CHOICE_SKIP;
} else {
message.SetToFormat("The debug information file '%s' for "
"image '%s' is missing, but can be found in the package "
"'%s'. Would you like to install it, or locate the file "
"manually?", fileState.externalInfoFileName.String(),
fileState.dwarfFile->Name(), requiredPackage.String());
choice = interface->SynchronouslyAskUser("Debug info missing",
message.String(), "Install", "Locate", "Skip");
}
} else {
choice = requiredPackage.IsEmpty()
? USER_CHOICE_SKIP : USER_CHOICE_INSTALL_PACKAGE;
}
if (choice == USER_CHOICE_INSTALL_PACKAGE) {
// TODO: integrate the package installation functionality directly.
BString command;
command.SetToFormat("/bin/pkgman install -y %s",
requiredPackage.String());
int error = system(command.String());
if (interface->IsInteractive()) {
if (WIFEXITED(error)) {
error = WEXITSTATUS(error);
if (error == B_OK)
break;
message.SetToFormat("Package installation failed: %s.",
strerror(error));
interface->NotifyUser("Error", message.String(),
USER_NOTIFICATION_ERROR);
continue;
}
}
break;
} else if (choice == USER_CHOICE_LOCATE_FILE) {
entry_ref ref;
interface->SynchronouslyAskUserForFile(&ref);
BPath path(&ref);
if (path.InitCheck() == B_OK)
fileState.locatedExternalInfoPath = path.Path();
break;
} else
break;
}
fileState.state = DWARF_FILE_LOADING_STATE_USER_INPUT_PROVIDED;
}
status_t
DwarfLoadingStateHandler::_GetMatchingDebugInfoPackage(
const BString& debugFileName, BString& _packageName)
{
BString resolvableName;
BPackageVersion requiredVersion;
BPackageManager::ClientInstallationInterface clientInterface;
BPackageManager::UserInteractionHandler handler;
BPackageManager packageManager(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM,
&clientInterface, &handler);
packageManager.Init(BPackageManager::B_ADD_INSTALLED_REPOSITORIES
| BPackageManager::B_ADD_REMOTE_REPOSITORIES);
BObjectList<BSolverPackage> packages;
status_t error = _GetResolvableName(debugFileName, resolvableName,
requiredVersion);
if (error != B_OK)
return error;
error = packageManager.Solver()->FindPackages(resolvableName,
BSolver::B_FIND_IN_PROVIDES, packages);
if (error != B_OK)
return error;
else if (packages.CountItems() == 0)
return B_ENTRY_NOT_FOUND;
for (int32 i = 0; i < packages.CountItems(); i++) {
BSolverPackage* package = packages.ItemAt(i);
if (requiredVersion.Compare(package->Version()) == 0) {
_packageName = package->Name();
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
status_t
DwarfLoadingStateHandler::_GetResolvableName(const BString& debugFileName,
BString& _resolvableName, BPackageVersion& _resolvableVersion)
{
BString fileName;
BString packageName;
BString packageVersion;
int32 startIndex = 0;
int32 endIndex = debugFileName.FindFirst('(');
if (endIndex < 0)
return B_BAD_VALUE;
debugFileName.CopyInto(fileName, 0, endIndex);
startIndex = endIndex + 1;
endIndex = debugFileName.FindFirst('-', startIndex);
if (endIndex < 0)
return B_BAD_VALUE;
debugFileName.CopyInto(packageName, startIndex, endIndex - startIndex);
startIndex = endIndex + 1;
endIndex = debugFileName.FindFirst(')', startIndex);
if (endIndex < 0)
return B_BAD_VALUE;
debugFileName.CopyInto(packageVersion, startIndex,
endIndex - startIndex);
_resolvableName.SetToFormat("debuginfo:%s(%s)", fileName.String(), packageName.String());
return _resolvableVersion.SetTo(packageVersion);
}

View File

@ -9,6 +9,14 @@
#include "ImageDebugLoadingStateHandler.h"
namespace BPackageKit {
class BPackageVersion;
}
class BString;
class DwarfLoadingStateHandler : public ImageDebugLoadingStateHandler {
public:
DwarfLoadingStateHandler();
@ -21,6 +29,15 @@ public:
SpecificImageDebugInfoLoadingState* state,
UserInterface* interface);
private:
status_t _GetMatchingDebugInfoPackage(
const BString& debugFileName,
BString& _packageName);
status_t _GetResolvableName(const BString& debugFileName,
BString& _resolvableName,
BPackageKit::BPackageVersion&
_resolvableVersion);
};