Installer: CopyEngine: Externalize decision making
* Add interface EntryFilter, an instance of which can be passed to the CopyEngine. The object is asked whether to copy entries/clobber directories. * Move the _ShouldCopyEntry()/_ShouldClobberFolder() code to new WorkerThread::EntryFilter.
This commit is contained in:
parent
a601eaa9e1
commit
c2be967eb9
@ -19,7 +19,6 @@
|
||||
#include <String.h>
|
||||
#include <SymLink.h>
|
||||
|
||||
#include "InstallerDefs.h"
|
||||
#include "SemaphoreLocker.h"
|
||||
#include "ProgressReporter.h"
|
||||
|
||||
@ -27,7 +26,18 @@
|
||||
using std::nothrow;
|
||||
|
||||
|
||||
CopyEngine::CopyEngine(ProgressReporter* reporter)
|
||||
// #pragma mark - EntryFilter
|
||||
|
||||
|
||||
CopyEngine::EntryFilter::~EntryFilter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - CopyEngine
|
||||
|
||||
|
||||
CopyEngine::CopyEngine(ProgressReporter* reporter, EntryFilter* entryFilter)
|
||||
:
|
||||
fBufferQueue(),
|
||||
fWriterThread(-1),
|
||||
@ -48,7 +58,8 @@ CopyEngine::CopyEngine(ProgressReporter* reporter)
|
||||
fCurrentTargetFolder(NULL),
|
||||
fCurrentItem(NULL),
|
||||
|
||||
fProgressReporter(reporter)
|
||||
fProgressReporter(reporter),
|
||||
fEntryFilter(entryFilter)
|
||||
{
|
||||
fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
@ -97,19 +108,6 @@ CopyEngine::ResetTargets(const char* source)
|
||||
|
||||
fCurrentTargetFolder = NULL;
|
||||
fCurrentItem = NULL;
|
||||
|
||||
// init BEntry pointing to /var
|
||||
// There is no other way to retrieve the path to the var folder
|
||||
// on the source volume. Using find_directory() with
|
||||
// B_COMMON_VAR_DIRECTORY will only ever get the var folder on the
|
||||
// current /boot volume regardless of the volume of "source", which
|
||||
// makes sense, since passing a volume is meant to folders that are
|
||||
// volume specific, like "trash".
|
||||
BPath path(source);
|
||||
if (path.Append(kSwapFilePath) == B_OK)
|
||||
fSwapFileEntry.SetTo(path.Path());
|
||||
else
|
||||
fSwapFileEntry.Unset();
|
||||
}
|
||||
|
||||
|
||||
@ -244,8 +242,10 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level,
|
||||
if (ret < B_OK)
|
||||
return ret;
|
||||
|
||||
if (!_ShouldCopyEntry(entry, name, statInfo, level))
|
||||
if (fEntryFilter != NULL
|
||||
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(statInfo.st_mode)) {
|
||||
// handle recursive directory copy
|
||||
@ -315,8 +315,10 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
|
||||
struct stat statInfo;
|
||||
entry.GetStat(&statInfo);
|
||||
|
||||
if (!_ShouldCopyEntry(entry, name, statInfo, level))
|
||||
if (fEntryFilter != NULL
|
||||
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fItemsCopied++;
|
||||
fCurrentItem = name;
|
||||
@ -331,9 +333,11 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
|
||||
if (copy.Exists()) {
|
||||
ret = B_OK;
|
||||
if (copy.IsDirectory()) {
|
||||
if (_ShouldClobberFolder(name, statInfo, level))
|
||||
if (fEntryFilter
|
||||
&& fEntryFilter->ShouldClobberFolder(entry, name,
|
||||
statInfo, level)) {
|
||||
ret = _RemoveFolder(copy);
|
||||
else {
|
||||
} else {
|
||||
// Do not overwrite attributes on folders that exist.
|
||||
// This should work better when the install target
|
||||
// already contains a Haiku installation.
|
||||
@ -502,57 +506,6 @@ CopyEngine::_UpdateProgress()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CopyEngine::_ShouldCopyEntry(const BEntry& entry, const char* name,
|
||||
const struct stat& statInfo, int32 level) const
|
||||
{
|
||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||
if (strcmp(kPackagesDirectoryPath, name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp(kSourcesDirectoryPath, name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp("rr_moved", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (level == 1 && S_ISREG(statInfo.st_mode)) {
|
||||
if (strcmp("boot.catalog", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp("haiku-boot-floppy.image", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fSwapFileEntry == entry) {
|
||||
// current location of var
|
||||
printf("ignoring swap file\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CopyEngine::_ShouldClobberFolder(const char* name, const struct stat& statInfo,
|
||||
int32 level) const
|
||||
{
|
||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||
if (strcmp("system", name) == 0) {
|
||||
printf("clobbering '%s'.\n", name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
CopyEngine::_WriteThreadEntry(void* cookie)
|
||||
{
|
||||
|
@ -20,7 +20,11 @@ class ProgressReporter;
|
||||
|
||||
class CopyEngine {
|
||||
public:
|
||||
CopyEngine(ProgressReporter* reporter);
|
||||
class EntryFilter;
|
||||
|
||||
public:
|
||||
CopyEngine(ProgressReporter* reporter,
|
||||
EntryFilter* entryFilter);
|
||||
virtual ~CopyEngine();
|
||||
|
||||
void ResetTargets(const char* source);
|
||||
@ -42,15 +46,6 @@ private:
|
||||
const char* destination,
|
||||
int32& level, sem_id cancelSemaphore);
|
||||
|
||||
bool _ShouldCopyEntry(const BEntry& entry,
|
||||
const char* name,
|
||||
const struct stat& statInfo,
|
||||
int32 level) const;
|
||||
|
||||
bool _ShouldClobberFolder(const char* name,
|
||||
const struct stat& statInfo,
|
||||
int32 level) const;
|
||||
|
||||
status_t _RemoveFolder(BEntry& entry);
|
||||
|
||||
void _UpdateProgress();
|
||||
@ -107,10 +102,22 @@ private:
|
||||
const char* fCurrentItem;
|
||||
|
||||
ProgressReporter* fProgressReporter;
|
||||
EntryFilter* fEntryFilter;
|
||||
};
|
||||
|
||||
// TODO: Should be made into a list of BEntris to be ignored, perhaps.
|
||||
// settable by method...
|
||||
BEntry fSwapFileEntry;
|
||||
|
||||
class CopyEngine::EntryFilter {
|
||||
public:
|
||||
virtual ~EntryFilter();
|
||||
|
||||
virtual bool ShouldCopyEntry(const BEntry& entry,
|
||||
const char* name,
|
||||
const struct stat& statInfo,
|
||||
int32 level) const = 0;
|
||||
virtual bool ShouldClobberFolder(const BEntry& entry,
|
||||
const char* name,
|
||||
const struct stat& statInfo,
|
||||
int32 level) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -81,6 +81,81 @@ private:
|
||||
// #pragma mark - WorkerThread
|
||||
|
||||
|
||||
class WorkerThread::EntryFilter : public CopyEngine::EntryFilter {
|
||||
public:
|
||||
EntryFilter(const char* sourceDirectory)
|
||||
{
|
||||
// init BEntry pointing to /var
|
||||
// There is no other way to retrieve the path to the var folder
|
||||
// on the source volume. Using find_directory() with
|
||||
// B_COMMON_VAR_DIRECTORY will only ever get the var folder on the
|
||||
// current /boot volume regardless of the volume of "source", which
|
||||
// makes sense, since passing a volume is meant to folders that are
|
||||
// volume specific, like "trash".
|
||||
BPath path(sourceDirectory);
|
||||
if (path.Append(kSwapFilePath) == B_OK)
|
||||
fSwapFileEntry.SetTo(path.Path());
|
||||
else
|
||||
fSwapFileEntry.Unset();
|
||||
}
|
||||
|
||||
virtual bool ShouldCopyEntry(const BEntry& entry, const char* name,
|
||||
const struct stat& statInfo, int32 level) const
|
||||
{
|
||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||
if (strcmp(kPackagesDirectoryPath, name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp(kSourcesDirectoryPath, name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp("rr_moved", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (level == 1 && S_ISREG(statInfo.st_mode)) {
|
||||
if (strcmp("boot.catalog", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
if (strcmp("haiku-boot-floppy.image", name) == 0) {
|
||||
printf("ignoring '%s'.\n", name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fSwapFileEntry == entry) {
|
||||
// current location of var
|
||||
printf("ignoring swap file\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool ShouldClobberFolder(const BEntry& entry, const char* name,
|
||||
const struct stat& statInfo, int32 level) const
|
||||
{
|
||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||
if (strcmp("system", name) == 0) {
|
||||
printf("clobbering '%s'.\n", name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO: Should be made into a list of BEntris to be ignored, perhaps.
|
||||
// settable by method...
|
||||
BEntry fSwapFileEntry;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - WorkerThread
|
||||
|
||||
|
||||
WorkerThread::WorkerThread(InstallerWindow *window)
|
||||
:
|
||||
BLooper("copy_engine"),
|
||||
@ -266,11 +341,6 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
||||
const char* mountError = B_TRANSLATE("The disk can't be mounted. Please "
|
||||
"choose a different disk.");
|
||||
|
||||
BMessenger messenger(fWindow);
|
||||
ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE));
|
||||
CopyEngine engine(&reporter);
|
||||
BList unzipEngines;
|
||||
|
||||
PartitionMenuItem* targetItem = (PartitionMenuItem*)targetMenu->FindMarked();
|
||||
PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked();
|
||||
if (!srcItem || !targetItem) {
|
||||
@ -401,6 +471,13 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
||||
|
||||
// Begin actual installation
|
||||
|
||||
{
|
||||
BMessenger messenger(fWindow);
|
||||
ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE));
|
||||
EntryFilter entryFilter(srcDirectory.Path());
|
||||
CopyEngine engine(&reporter, &entryFilter);
|
||||
BList unzipEngines;
|
||||
|
||||
_LaunchInitScript(targetDirectory);
|
||||
|
||||
// Create the default indices which should always be present on a proper
|
||||
@ -480,6 +557,8 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
||||
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
BMessage statusMessage(MSG_RESET);
|
||||
if (err == B_CANCELED)
|
||||
|
@ -55,6 +55,10 @@ private:
|
||||
|
||||
void _SetStatusMessage(const char* status);
|
||||
|
||||
private:
|
||||
class EntryFilter;
|
||||
|
||||
private:
|
||||
InstallerWindow* fWindow;
|
||||
BDiskDeviceRoster fDDRoster;
|
||||
BList* fPackages;
|
||||
|
Loading…
Reference in New Issue
Block a user