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:
Ingo Weinhold
2013-06-02 15:16:26 +02:00
parent a601eaa9e1
commit c2be967eb9
4 changed files with 132 additions and 89 deletions
+24 -71
View File
@@ -19,7 +19,6 @@
#include <String.h> #include <String.h>
#include <SymLink.h> #include <SymLink.h>
#include "InstallerDefs.h"
#include "SemaphoreLocker.h" #include "SemaphoreLocker.h"
#include "ProgressReporter.h" #include "ProgressReporter.h"
@@ -27,7 +26,18 @@
using std::nothrow; using std::nothrow;
CopyEngine::CopyEngine(ProgressReporter* reporter) // #pragma mark - EntryFilter
CopyEngine::EntryFilter::~EntryFilter()
{
}
// #pragma mark - CopyEngine
CopyEngine::CopyEngine(ProgressReporter* reporter, EntryFilter* entryFilter)
: :
fBufferQueue(), fBufferQueue(),
fWriterThread(-1), fWriterThread(-1),
@@ -48,7 +58,8 @@ CopyEngine::CopyEngine(ProgressReporter* reporter)
fCurrentTargetFolder(NULL), fCurrentTargetFolder(NULL),
fCurrentItem(NULL), fCurrentItem(NULL),
fProgressReporter(reporter) fProgressReporter(reporter),
fEntryFilter(entryFilter)
{ {
fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer", fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer",
B_NORMAL_PRIORITY, this); B_NORMAL_PRIORITY, this);
@@ -97,19 +108,6 @@ CopyEngine::ResetTargets(const char* source)
fCurrentTargetFolder = NULL; fCurrentTargetFolder = NULL;
fCurrentItem = 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) if (ret < B_OK)
return ret; return ret;
if (!_ShouldCopyEntry(entry, name, statInfo, level)) if (fEntryFilter != NULL
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
continue; continue;
}
if (S_ISDIR(statInfo.st_mode)) { if (S_ISDIR(statInfo.st_mode)) {
// handle recursive directory copy // handle recursive directory copy
@@ -315,8 +315,10 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
struct stat statInfo; struct stat statInfo;
entry.GetStat(&statInfo); entry.GetStat(&statInfo);
if (!_ShouldCopyEntry(entry, name, statInfo, level)) if (fEntryFilter != NULL
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
continue; continue;
}
fItemsCopied++; fItemsCopied++;
fCurrentItem = name; fCurrentItem = name;
@@ -331,9 +333,11 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
if (copy.Exists()) { if (copy.Exists()) {
ret = B_OK; ret = B_OK;
if (copy.IsDirectory()) { if (copy.IsDirectory()) {
if (_ShouldClobberFolder(name, statInfo, level)) if (fEntryFilter
&& fEntryFilter->ShouldClobberFolder(entry, name,
statInfo, level)) {
ret = _RemoveFolder(copy); ret = _RemoveFolder(copy);
else { } else {
// Do not overwrite attributes on folders that exist. // Do not overwrite attributes on folders that exist.
// This should work better when the install target // This should work better when the install target
// already contains a Haiku installation. // 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 int32
CopyEngine::_WriteThreadEntry(void* cookie) CopyEngine::_WriteThreadEntry(void* cookie)
{ {
+20 -13
View File
@@ -20,7 +20,11 @@ class ProgressReporter;
class CopyEngine { class CopyEngine {
public: public:
CopyEngine(ProgressReporter* reporter); class EntryFilter;
public:
CopyEngine(ProgressReporter* reporter,
EntryFilter* entryFilter);
virtual ~CopyEngine(); virtual ~CopyEngine();
void ResetTargets(const char* source); void ResetTargets(const char* source);
@@ -42,15 +46,6 @@ private:
const char* destination, const char* destination,
int32& level, sem_id cancelSemaphore); 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); status_t _RemoveFolder(BEntry& entry);
void _UpdateProgress(); void _UpdateProgress();
@@ -107,10 +102,22 @@ private:
const char* fCurrentItem; const char* fCurrentItem;
ProgressReporter* fProgressReporter; ProgressReporter* fProgressReporter;
EntryFilter* fEntryFilter;
};
// TODO: Should be made into a list of BEntris to be ignored, perhaps.
// settable by method... class CopyEngine::EntryFilter {
BEntry fSwapFileEntry; 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;
}; };
+84 -5
View File
@@ -81,6 +81,81 @@ private:
// #pragma mark - WorkerThread // #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) WorkerThread::WorkerThread(InstallerWindow *window)
: :
BLooper("copy_engine"), 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 " const char* mountError = B_TRANSLATE("The disk can't be mounted. Please "
"choose a different disk."); "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* targetItem = (PartitionMenuItem*)targetMenu->FindMarked();
PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked(); PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked();
if (!srcItem || !targetItem) { if (!srcItem || !targetItem) {
@@ -401,6 +471,13 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
// Begin actual installation // 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); _LaunchInitScript(targetDirectory);
// Create the default indices which should always be present on a proper // 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); BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
return; return;
}
error: error:
BMessage statusMessage(MSG_RESET); BMessage statusMessage(MSG_RESET);
if (err == B_CANCELED) if (err == B_CANCELED)
+4
View File
@@ -55,6 +55,10 @@ private:
void _SetStatusMessage(const char* status); void _SetStatusMessage(const char* status);
private:
class EntryFilter;
private:
InstallerWindow* fWindow; InstallerWindow* fWindow;
BDiskDeviceRoster fDDRoster; BDiskDeviceRoster fDDRoster;
BList* fPackages; BList* fPackages;