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:
parent
bbf320ecfe
commit
3fc9fd5624
@ -6,15 +6,32 @@
|
|||||||
|
|
||||||
#include "DwarfLoadingStateHandler.h"
|
#include "DwarfLoadingStateHandler.h"
|
||||||
|
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include <Entry.h>
|
#include <Entry.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
|
#include <package/solver/Solver.h>
|
||||||
|
#include <package/solver/SolverPackage.h>
|
||||||
|
|
||||||
|
#include "AutoDeleter.h"
|
||||||
#include "DwarfFile.h"
|
#include "DwarfFile.h"
|
||||||
#include "DwarfImageDebugInfoLoadingState.h"
|
#include "DwarfImageDebugInfoLoadingState.h"
|
||||||
|
#include "package/manager/PackageManager.h"
|
||||||
#include "Tracing.h"
|
#include "Tracing.h"
|
||||||
#include "UserInterface.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()
|
DwarfLoadingStateHandler::DwarfLoadingStateHandler()
|
||||||
:
|
:
|
||||||
ImageDebugLoadingStateHandler()
|
ImageDebugLoadingStateHandler()
|
||||||
@ -50,24 +67,143 @@ DwarfLoadingStateHandler::HandleState(
|
|||||||
|
|
||||||
DwarfFileLoadingState& fileState = dwarfState->GetFileState();
|
DwarfFileLoadingState& fileState = dwarfState->GetFileState();
|
||||||
|
|
||||||
// TODO: if the image in question is packaged, query if it has a
|
BString requiredPackage;
|
||||||
// corresponding debug info package. If so, offer to install it and
|
_GetMatchingDebugInfoPackage(fileState.externalInfoFileName,
|
||||||
// then locate the file automatically rather than forcing the user to
|
requiredPackage);
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (choice == 0) {
|
// 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;
|
entry_ref ref;
|
||||||
interface->SynchronouslyAskUserForFile(&ref);
|
interface->SynchronouslyAskUserForFile(&ref);
|
||||||
BPath path(&ref);
|
BPath path(&ref);
|
||||||
if (path.InitCheck() == B_OK)
|
if (path.InitCheck() == B_OK)
|
||||||
fileState.locatedExternalInfoPath = path.Path();
|
fileState.locatedExternalInfoPath = path.Path();
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fileState.state = DWARF_FILE_LOADING_STATE_USER_INPUT_PROVIDED;
|
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);
|
||||||
|
}
|
||||||
|
@ -9,6 +9,14 @@
|
|||||||
#include "ImageDebugLoadingStateHandler.h"
|
#include "ImageDebugLoadingStateHandler.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPackageKit {
|
||||||
|
class BPackageVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class BString;
|
||||||
|
|
||||||
|
|
||||||
class DwarfLoadingStateHandler : public ImageDebugLoadingStateHandler {
|
class DwarfLoadingStateHandler : public ImageDebugLoadingStateHandler {
|
||||||
public:
|
public:
|
||||||
DwarfLoadingStateHandler();
|
DwarfLoadingStateHandler();
|
||||||
@ -21,6 +29,15 @@ public:
|
|||||||
SpecificImageDebugInfoLoadingState* state,
|
SpecificImageDebugInfoLoadingState* state,
|
||||||
UserInterface* interface);
|
UserInterface* interface);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _GetMatchingDebugInfoPackage(
|
||||||
|
const BString& debugFileName,
|
||||||
|
BString& _packageName);
|
||||||
|
|
||||||
|
status_t _GetResolvableName(const BString& debugFileName,
|
||||||
|
BString& _resolvableName,
|
||||||
|
BPackageKit::BPackageVersion&
|
||||||
|
_resolvableVersion);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user