pkgman: Move some classes into own file for reuse

Namely RepositoryBuilder and PackageInfoErrorListener.
This commit is contained in:
Ingo Weinhold 2013-04-10 14:41:30 +02:00
parent 483d49968d
commit 5776551d3d
6 changed files with 277 additions and 167 deletions

View File

@ -5,12 +5,14 @@ UsePrivateHeaders shared support ;
BinCommand pkgman :
command_add_repo.cpp
command_drop_repo.cpp
command_resolve_dependencies.cpp
command_list_repos.cpp
command_refresh.cpp
command_resolve_dependencies.cpp
DecisionProvider.cpp
JobStateListener.cpp
PackageInfoErrorListener.cpp
pkgman.cpp
RepositoryBuilder.cpp
:
package be
$(TARGET_LIBSUPC++)

View File

@ -0,0 +1,27 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include "PackageInfoErrorListener.h"
#include <stdio.h>
PackageInfoErrorListener::PackageInfoErrorListener(const BString& errorContext)
:
fErrorContext(errorContext)
{
}
void
PackageInfoErrorListener::OnError(const BString& message, int line, int column)
{
fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
fErrorContext.String(), line, column, message.String());
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#ifndef PACKAGE_INFO_ERROR_LISTENER_H
#define PACKAGE_INFO_ERROR_LISTENER_H
#include <package/PackageInfo.h>
using namespace BPackageKit;
class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
public:
PackageInfoErrorListener(
const BString& errorContext);
virtual void OnError(const BString& message, int line,
int column);
private:
BString fErrorContext;
};
#endif // PACKAGE_INFO_ERROR_LISTENER_H

View File

@ -0,0 +1,158 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#include "RepositoryBuilder.h"
#include <errno.h>
#include <dirent.h>
#include <Entry.h>
#include <Path.h>
#include <AutoDeleter.h>
#include "PackageInfoErrorListener.h"
#include "pkgman.h"
RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
const BString& name, const BString& errorName)
:
fRepository(repository),
fErrorName(errorName.IsEmpty() ? name : errorName),
fPackagePaths(NULL)
{
status_t error = fRepository.SetTo(name);
if (error != B_OK)
DIE(error, "failed to init %s repository", fErrorName.String());
}
RepositoryBuilder&
RepositoryBuilder::SetPackagePathMap(PackagePathMap* packagePaths)
{
fPackagePaths = packagePaths;
return *this;
}
RepositoryBuilder&
RepositoryBuilder::AddPackage(const BPackageInfo& info,
const char* packageErrorName, BSolverPackage** _package)
{
status_t error = fRepository.AddPackage(info, _package);
if (error != B_OK) {
DIE(error, "failed to add %s to %s repository",
packageErrorName != NULL
? packageErrorName
: (BString("package ") << info.Name()).String(),
fErrorName.String());
}
return *this;
}
RepositoryBuilder&
RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
{
// read a package info from the (HPKG or package info) file
BPackageInfo packageInfo;
size_t pathLength = strlen(path);
status_t error;
if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
// a package file
error = packageInfo.ReadFromPackageFile(path);
} else {
// a package info file (supposedly)
PackageInfoErrorListener errorListener(
"Error: failed to read package info");
error = packageInfo.ReadFromConfigFile(BEntry(path),
&errorListener);
}
if (error != B_OK)
DIE(errno, "failed to read package info from \"%s\"", path);
// add the package
BSolverPackage* package;
AddPackage(packageInfo, path, &package);
// enter the package path in the path map, if given
if (fPackagePaths != NULL)
(*fPackagePaths)[package] = path;
if (_package != NULL)
*_package = package;
return *this;
}
RepositoryBuilder&
RepositoryBuilder::AddPackages(BPackageInstallationLocation location,
const char* locationErrorName)
{
status_t error = fRepository.AddPackages(location);
if (error != B_OK) {
DIE(error, "failed to add %s packages to %s repository",
locationErrorName, fErrorName.String());
}
return *this;
}
RepositoryBuilder&
RepositoryBuilder::AddPackagesDirectory(const char* path)
{
// open directory
DIR* dir = opendir(path);
if (dir == NULL)
DIE(errno, "failed to open package directory \"%s\"", path);
CObjectDeleter<DIR, int> dirCloser(dir, &closedir);
// iterate through directory entries
while (dirent* entry = readdir(dir)) {
// skip "." and ".."
const char* name = entry->d_name;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
// stat() the entry and skip any non-file
BPath entryPath;
status_t error = entryPath.SetTo(path, name);
if (error != B_OK)
DIE(errno, "failed to construct path");
struct stat st;
if (lstat(entryPath.Path(), &st) != 0)
DIE(errno, "failed to stat() %s", entryPath.Path());
if (!S_ISREG(st.st_mode))
continue;
AddPackage(entryPath.Path());
}
return *this;
}
RepositoryBuilder&
RepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
{
fRepository.SetInstalled(isInstalled);
status_t error = solver->AddRepository(&fRepository);
if (error != B_OK) {
DIE(error, "failed to add %s repository to solver",
fErrorName.String());
}
return *this;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2013, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Ingo Weinhold <ingo_weinhold@gmx.de>
*/
#ifndef REPOSITORY_BUILDER_H
#define REPOSITORY_BUILDER_H
#include <map>
#include <package/PackageInfo.h>
#include <package/solver/Solver.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverRepository.h>
using namespace BPackageKit;
typedef std::map<BSolverPackage*, BString> PackagePathMap;
class RepositoryBuilder {
private:
typedef RepositoryBuilder Builder;
public:
RepositoryBuilder(BSolverRepository& repository,
const BString& name,
const BString& errorName = BString());
RepositoryBuilder& SetPackagePathMap(PackagePathMap* packagePaths);
RepositoryBuilder& AddPackage(const BPackageInfo& info,
const char* packageErrorName = NULL,
BSolverPackage** _package = NULL);
RepositoryBuilder& AddPackage(const char* path,
BSolverPackage** _package = NULL);
RepositoryBuilder& AddPackages(
BPackageInstallationLocation location,
const char* locationErrorName);
RepositoryBuilder& AddPackagesDirectory(const char* path);
RepositoryBuilder& AddToSolver(BSolver* solver,
bool isInstalled = false);
private:
BSolverRepository& fRepository;
BString fErrorName;
PackagePathMap* fPackagePaths;
};
#endif // REPOSITORY_BUILDER_H

View File

@ -7,31 +7,21 @@
*/
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <map>
#include <Entry.h>
#include <File.h>
#include <Path.h>
#include <package/PackageInfo.h>
#include <package/solver/Solver.h>
#include <package/solver/SolverPackage.h>
#include <package/solver/SolverPackageSpecifier.h>
#include <package/solver/SolverPackageSpecifierList.h>
#include <package/solver/SolverProblem.h>
#include <package/solver/SolverRepository.h>
#include <package/solver/SolverResult.h>
#include <AutoDeleter.h>
#include "pkgman.h"
#include "RepositoryBuilder.h"
// TODO: internationalization!
@ -40,9 +30,6 @@
using namespace BPackageKit;
typedef std::map<BSolverPackage*, BString> PackagePathMap;
static const char* kCommandUsage =
"Usage: %s resolve-dependencies <package> <repository> [ <priority> ] ...\n"
"Resolves and lists all packages a given package depends on. Fails, if\n"
@ -71,158 +58,6 @@ print_command_usage_and_exit(bool error)
}
struct PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
public:
PackageInfoErrorListener(const BString& errorContext)
:
fErrorContext(errorContext)
{
}
virtual void OnError(const BString& message, int line, int column)
{
fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
fErrorContext.String(), line, column, message.String());
}
private:
BString fErrorContext;
};
struct RepositoryBuilder {
RepositoryBuilder(BSolverRepository& repository, const BString& name,
const BString& errorName = BString())
:
fRepository(repository),
fErrorName(errorName.IsEmpty() ? name : errorName),
fPackagePaths(NULL)
{
status_t error = fRepository.SetTo(name);
if (error != B_OK)
DIE(error, "failed to init %s repository", fErrorName.String());
}
RepositoryBuilder& SetPackagePathMap(PackagePathMap* packagePaths)
{
fPackagePaths = packagePaths;
return *this;
}
RepositoryBuilder& AddPackage(const BPackageInfo& info,
const char* packageErrorName = NULL, BSolverPackage** _package = NULL)
{
status_t error = fRepository.AddPackage(info, _package);
if (error != B_OK) {
DIE(error, "failed to add %s to %s repository",
packageErrorName != NULL
? packageErrorName
: (BString("package ") << info.Name()).String(),
fErrorName.String());
}
return *this;
}
RepositoryBuilder& AddPackage(const char* path,
BSolverPackage** _package = NULL)
{
// read a package info from the (HPKG or package info) file
BPackageInfo packageInfo;
size_t pathLength = strlen(path);
status_t error;
if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
// a package file
error = packageInfo.ReadFromPackageFile(path);
} else {
// a package info file (supposedly)
PackageInfoErrorListener errorListener(
"Error: failed to read package info");
error = packageInfo.ReadFromConfigFile(BEntry(path),
&errorListener);
}
if (error != B_OK)
DIE(errno, "failed to read package info from \"%s\"", path);
// add the package
BSolverPackage* package;
AddPackage(packageInfo, path, &package);
// enter the package path in the path map, if given
if (fPackagePaths != NULL)
(*fPackagePaths)[package] = path;
if (_package != NULL)
*_package = package;
return *this;
}
RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
const char* locationErrorName)
{
status_t error = fRepository.AddPackages(location);
if (error != B_OK) {
DIE(error, "failed to add %s packages to %s repository",
locationErrorName, fErrorName.String());
}
return *this;
}
RepositoryBuilder& AddPackagesDirectory(const char* path)
{
// open directory
DIR* dir = opendir(path);
if (dir == NULL)
DIE(errno, "failed to open package directory \"%s\"", path);
CObjectDeleter<DIR, int> dirCloser(dir, &closedir);
// iterate through directory entries
while (dirent* entry = readdir(dir)) {
// skip "." and ".."
const char* name = entry->d_name;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
// stat() the entry and skip any non-file
BPath entryPath;
status_t error = entryPath.SetTo(path, name);
if (error != B_OK)
DIE(errno, "failed to construct path");
struct stat st;
if (lstat(entryPath.Path(), &st) != 0)
DIE(errno, "failed to stat() %s", entryPath.Path());
if (!S_ISREG(st.st_mode))
continue;
AddPackage(entryPath.Path());
}
return *this;
}
RepositoryBuilder& AddToSolver(BSolver* solver, bool isInstalled = false)
{
fRepository.SetInstalled(isInstalled);
status_t error = solver->AddRepository(&fRepository);
if (error != B_OK) {
DIE(error, "failed to add %s repository to solver",
fErrorName.String());
}
return *this;
}
private:
BSolverRepository& fRepository;
BString fErrorName;
PackagePathMap* fPackagePaths;
};
static void
check_problems(BSolver* solver, const char* errorContext)
{