diff --git a/src/apps/installer/CopyEngine.cpp b/src/apps/installer/CopyEngine.cpp index 43cde9a7e6..fb297f0df9 100644 --- a/src/apps/installer/CopyEngine.cpp +++ b/src/apps/installer/CopyEngine.cpp @@ -22,19 +22,22 @@ #include "InstallerWindow.h" // TODO: For PACKAGES_DIRECTORY and VAR_DIRECTORY, not so nice... #include "SemaphoreLocker.h" +#include "ProgressReporter.h" using std::nothrow; -CopyEngine::CopyEngine(const BMessenger& messenger, BMessage* message) +CopyEngine::CopyEngine(ProgressReporter* reporter) : fBufferQueue(), fWriterThread(-1), fQuitting(false), fBytesRead(0), + fLastBytesRead(0), fItemsCopied(0), + fLastItemsCopied(0), fTimeRead(0), fBytesWritten(0), @@ -46,8 +49,7 @@ CopyEngine::CopyEngine(const BMessenger& messenger, BMessage* message) fCurrentTargetFolder(NULL), fCurrentItem(NULL), - fMessenger(messenger), - fMessage(message) + fProgressReporter(reporter) { fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer", B_NORMAL_PRIORITY, this); @@ -73,16 +75,19 @@ CopyEngine::~CopyEngine() int32 exitValue; wait_for_thread(fWriterThread, &exitValue); } - - delete fMessage; } void CopyEngine::ResetTargets() { + // TODO: One could subtract the bytes/items which were added to the + // ProgressReporter before resetting them... + fBytesRead = 0; + fLastBytesRead = 0; fItemsCopied = 0; + fLastItemsCopied = 0; fTimeRead = 0; fBytesWritten = 0; @@ -93,12 +98,6 @@ CopyEngine::ResetTargets() fCurrentTargetFolder = NULL; fCurrentItem = NULL; - - if (fMessage) { - BMessage message(*fMessage); - message.AddString("status", "Collecting copy information."); - fMessenger.SendMessage(&message); - } } @@ -106,7 +105,10 @@ status_t CopyEngine::CollectTargets(const char* source, sem_id cancelSemaphore) { int32 level = 0; - return _CollectCopyInfo(source, level, cancelSemaphore); + status_t ret = _CollectCopyInfo(source, level, cancelSemaphore); + if (ret == B_OK && fProgressReporter != NULL) + fProgressReporter->AddItems(fItemsToCopy, fBytesToCopy); + return ret; } @@ -114,14 +116,6 @@ status_t CopyEngine::CopyFolder(const char* source, const char* destination, sem_id cancelSemaphore) { - printf("%lld bytes to read in %lld files\n", fBytesToCopy, fItemsToCopy); - - if (fMessage) { - BMessage message(*fMessage); - message.AddString("status", "Performing installation."); - fMessenger.SendMessage(&message); - } - int32 level = 0; return _CopyFolder(source, destination, level, cancelSemaphore); } @@ -475,16 +469,23 @@ CopyEngine::_RemoveFolder(BEntry& entry) void CopyEngine::_UpdateProgress() { - if (fMessage != NULL) { - BMessage message(*fMessage); - float progress = 100.0 * fBytesRead / fBytesToCopy; - message.AddFloat("progress", progress); - message.AddInt32("current", fItemsCopied); - message.AddInt32("maximum", fItemsToCopy); - message.AddString("item", fCurrentItem); - message.AddString("folder", fCurrentTargetFolder); - fMessenger.SendMessage(&message); + if (fProgressReporter == NULL) + return; + + uint64 items = 0; + if (fLastItemsCopied < fItemsCopied) { + items = fItemsCopied - fLastItemsCopied; + fLastItemsCopied = fItemsCopied; } + + off_t bytes = 0; + if (fLastBytesRead < fBytesRead) { + bytes = fBytesRead - fLastBytesRead; + fLastBytesRead = fBytesRead; + } + + fProgressReporter->ItemsWritten(items, bytes, fCurrentItem, + fCurrentTargetFolder); } diff --git a/src/apps/installer/CopyEngine.h b/src/apps/installer/CopyEngine.h index bda85ad7a4..1ad6552250 100644 --- a/src/apps/installer/CopyEngine.h +++ b/src/apps/installer/CopyEngine.h @@ -15,14 +15,12 @@ #include "BlockingQueue.h" class BFile; -class BMessage; -class BMessenger; +class ProgressReporter; class CopyEngine { public: - CopyEngine(const BMessenger& messenger, - BMessage* message); + CopyEngine(ProgressReporter* reporter); virtual ~CopyEngine(); void ResetTargets(); @@ -93,7 +91,9 @@ private: volatile bool fQuitting; off_t fBytesRead; + uint64 fLastBytesRead; uint64 fItemsCopied; + uint64 fLastItemsCopied; bigtime_t fTimeRead; off_t fBytesWritten; @@ -105,8 +105,7 @@ private: const char* fCurrentTargetFolder; const char* fCurrentItem; - BMessenger fMessenger; - BMessage* fMessage; + ProgressReporter* fProgressReporter; }; diff --git a/src/apps/installer/Jamfile b/src/apps/installer/Jamfile index 4dde40289e..bb6431a736 100644 --- a/src/apps/installer/Jamfile +++ b/src/apps/installer/Jamfile @@ -9,6 +9,7 @@ Application Installer : InstallerWindow.cpp PackageViews.cpp PartitionMenuItem.cpp + ProgressReporter.cpp UnzipEngine.cpp WorkerThread.cpp : be tracker translation libshared.a $(TARGET_LIBSTDC++) diff --git a/src/apps/installer/ProgressReporter.cpp b/src/apps/installer/ProgressReporter.cpp index 9bb538177c..5b451246a6 100644 --- a/src/apps/installer/ProgressReporter.cpp +++ b/src/apps/installer/ProgressReporter.cpp @@ -5,28 +5,19 @@ #include "ProgressReporter.h" -#include - -#include #include -#include - - -using std::nothrow; ProgressReporter::ProgressReporter(const BMessenger& messenger, BMessage* message) : - fBytesRead(0), - fItemsCopied(0), - fTimeRead(0), + fStartTime(0), + fBytesToWrite(0), fBytesWritten(0), - fTimeWritten(0), - fBytesToCopy(0), - fItemsToCopy(0), + fItemsToWrite(0), + fItemsWritten(0), fMessenger(messenger), fMessage(message) @@ -43,15 +34,11 @@ ProgressReporter::~ProgressReporter() void ProgressReporter::Reset() { - fBytesRead = 0; - fItemsCopied = 0; - fTimeRead = 0; - + fBytesToWrite = 0; fBytesWritten = 0; - fTimeWritten = 0; - fBytesToCopy = 0; - fItemsToCopy = 0; + fItemsToWrite = 0; + fItemsWritten = 0; if (fMessage) { BMessage message(*fMessage); @@ -64,22 +51,35 @@ ProgressReporter::Reset() void ProgressReporter::AddItems(uint64 count, off_t bytes) { - // TODO ... + fBytesToWrite += bytes; + fItemsToWrite += count; } void ProgressReporter::StartTimer() { - // TODO ... + fStartTime = system_time(); + + printf("%lld bytes to write in %lld files\n", fBytesToWrite, + fItemsToWrite); + + if (fMessage) { + BMessage message(*fMessage); + message.AddString("status", "Performing installation."); + fMessenger.SendMessage(&message); + } } void -ProgressReporter::ItemsCopied(uint64 items, off_t bytes, const char* itemName, - const char* targetFolder) +ProgressReporter::ItemsWritten(uint64 items, off_t bytes, + const char* itemName, const char* targetFolder) { - // TODO ... + fItemsWritten += items; + fBytesWritten += bytes; + + _UpdateProgress(itemName, targetFolder); } @@ -87,14 +87,17 @@ void ProgressReporter::_UpdateProgress(const char* itemName, const char* targetFolder) { - if (fMessage != NULL) { - BMessage message(*fMessage); - float progress = 100.0 * fBytesRead / fBytesToCopy; - message.AddFloat("progress", progress); - message.AddInt32("current", fItemsCopied); - message.AddInt32("maximum", fItemsToCopy); - message.AddString("item", itemName); - message.AddString("folder", targetFolder); - fMessenger.SendMessage(&message); - } + if (fMessage == NULL) + return; + + // TODO: Could add time to finish calculation here... + + BMessage message(*fMessage); + float progress = 100.0 * fBytesWritten / fBytesToWrite; + message.AddFloat("progress", progress); + message.AddInt32("current", fItemsWritten); + message.AddInt32("maximum", fItemsToWrite); + message.AddString("item", itemName); + message.AddString("folder", targetFolder); + fMessenger.SendMessage(&message); } diff --git a/src/apps/installer/ProgressReporter.h b/src/apps/installer/ProgressReporter.h index 2238244338..6d20d47925 100644 --- a/src/apps/installer/ProgressReporter.h +++ b/src/apps/installer/ProgressReporter.h @@ -21,24 +21,24 @@ public: void StartTimer(); - void ItemsCopied(uint64 items, off_t bytes, + void ItemsWritten(uint64 items, off_t bytes, const char* itemName, const char* targetFolder); + // TODO: Perhaps move cancelling here as well... + private: void _UpdateProgress(const char* itemName, const char* targetFolder); private: - off_t fBytesRead; - uint64 fItemsCopied; - bigtime_t fTimeRead; + bigtime_t fStartTime; + off_t fBytesToWrite; off_t fBytesWritten; - bigtime_t fTimeWritten; - off_t fBytesToCopy; - uint64 fItemsToCopy; + uint64 fItemsToWrite; + uint64 fItemsWritten; BMessenger fMessenger; BMessage* fMessage; diff --git a/src/apps/installer/UnzipEngine.cpp b/src/apps/installer/UnzipEngine.cpp index 4efef35e2a..89245cc42f 100644 --- a/src/apps/installer/UnzipEngine.cpp +++ b/src/apps/installer/UnzipEngine.cpp @@ -21,12 +21,13 @@ #include "CommandPipe.h" #include "SemaphoreLocker.h" +#include "ProgressReporter.h" using std::nothrow; -UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message, +UnzipEngine::UnzipEngine(ProgressReporter* reporter, sem_id cancelSemaphore) : fPackage(""), @@ -34,11 +35,12 @@ UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message, fBytesToUncompress(0), fBytesUncompressed(0), + fLastBytesUncompressed(0), fItemsToUncompress(0), fItemsUncompressed(0), + fLastItemsUncompressed(0), - fMessenger(messenger), - fMessage(message), + fProgressReporter(reporter), fCancelSemaphore(cancelSemaphore) { } @@ -46,7 +48,6 @@ UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message, UnzipEngine::~UnzipEngine() { - delete fMessage; } @@ -60,8 +61,10 @@ UnzipEngine::SetTo(const char* pathToPackage, const char* destinationFolder) fBytesToUncompress = 0; fBytesUncompressed = 0; + fLastBytesUncompressed = 0; fItemsToUncompress = 0; fItemsUncompressed = 0; + fLastItemsUncompressed = 0; BPrivate::BCommandPipe commandPipe; status_t ret = commandPipe.AddArg("unzip"); @@ -95,12 +98,6 @@ UnzipEngine::UnzipPackage() if (fItemsToUncompress == 0) return B_NO_INIT; - if (fMessage) { - BMessage message(*fMessage); - message.AddString("status", "Extracting package."); - fMessenger.SendMessage(&message); - } - BPrivate::BCommandPipe commandPipe; status_t ret = commandPipe.AddArg("unzip"); if (ret == B_OK) @@ -155,19 +152,6 @@ UnzipEngine::ReadLine(const BString& line) status_t UnzipEngine::_ReadLineListing(const BString& line) { -// static const char* kListingFormat = "%llu files, %llu bytes uncompressed, " -// "%llu bytes compressed: %f%%"; -// -// uint64 bytesCompressed; -// float compresssionRatio; -// if (sscanf(line.String(), kListingFormat, &fItemsToUncompress, -// &fBytesToUncompress, &bytesCompressed, &compresssionRatio) != 4) { -// fBytesToUncompress = 0; -// fItemsToUncompress = 0; -// fprintf(stderr, "error reading command output: %s\n", line.String()); -// return B_ERROR; -// } - static const char* kListingFormat = "%llu %s %s %s\n"; const char* string = line.String(); @@ -197,7 +181,7 @@ UnzipEngine::_ReadLineListing(const BString& line) if (destination.Append(itemPath.String()) == B_OK) { BEntry test(destination.Path()); if (test.Exists() && test.IsDirectory()) { - printf("ignoring %s\n", itemPath.String()); +// printf("ignoring %s\n", itemPath.String()); itemCount = 0; } } @@ -205,8 +189,8 @@ UnzipEngine::_ReadLineListing(const BString& line) fItemsToUncompress += itemCount; - printf("item %s with %llu bytes to %s\n", itemName.String(), - bytes, itemPath.String()); +// printf("item %s with %llu bytes to %s\n", itemName.String(), +// bytes, itemPath.String()); fEntrySizeMap.Put(itemName.String(), bytes); } else { @@ -243,8 +227,8 @@ UnzipEngine::_ReadLineExtract(const BString& line) fBytesUncompressed += bytes; } - printf("%llu extracted %s to %s (%llu)\n", fItemsUncompressed, - itemName.String(), itemPath.String(), bytes); +// printf("%llu extracted %s to %s (%llu)\n", fItemsUncompressed, +// itemName.String(), itemPath.String(), bytes); _UpdateProgress(itemName.String(), itemPath.String()); } else { @@ -258,14 +242,20 @@ UnzipEngine::_ReadLineExtract(const BString& line) void UnzipEngine::_UpdateProgress(const char* item, const char* targetFolder) { - if (fMessage != NULL) { - BMessage message(*fMessage); - float progress = 100.0 * fBytesUncompressed / fBytesToUncompress; - message.AddFloat("progress", progress); - message.AddInt32("current", fItemsUncompressed); - message.AddInt32("maximum", fItemsToUncompress); - message.AddString("item", item); - message.AddString("folder", targetFolder); - fMessenger.SendMessage(&message); + if (fProgressReporter == NULL) + return; + + uint64 items = 0; + if (fLastItemsUncompressed < fItemsUncompressed) { + items = fItemsUncompressed - fLastItemsUncompressed; + fLastItemsUncompressed = fItemsUncompressed; } + + off_t bytes = 0; + if (fLastBytesUncompressed < fBytesUncompressed) { + bytes = fBytesUncompressed - fLastBytesUncompressed; + fLastBytesUncompressed = fBytesUncompressed; + } + + fProgressReporter->ItemsWritten(items, bytes, item, targetFolder); } diff --git a/src/apps/installer/UnzipEngine.h b/src/apps/installer/UnzipEngine.h index 26162e1845..36eafdcc1a 100644 --- a/src/apps/installer/UnzipEngine.h +++ b/src/apps/installer/UnzipEngine.h @@ -15,14 +15,12 @@ #include "HashMap.h" #include "HashString.h" -class BMessage; -class BMessenger; +class ProgressReporter; class UnzipEngine : private BCommandPipe::LineReader { public: - UnzipEngine(const BMessenger& messenger, - BMessage* message, + UnzipEngine(ProgressReporter* reporter, sem_id cancelSemaphore = -1); virtual ~UnzipEngine(); @@ -59,11 +57,12 @@ private: off_t fBytesToUncompress; off_t fBytesUncompressed; + off_t fLastBytesUncompressed; uint64 fItemsToUncompress; uint64 fItemsUncompressed; + uint64 fLastItemsUncompressed; - BMessenger fMessenger; - BMessage* fMessage; + ProgressReporter* fProgressReporter; sem_id fCancelSemaphore; }; diff --git a/src/apps/installer/WorkerThread.cpp b/src/apps/installer/WorkerThread.cpp index 688387fd24..dd85124f69 100644 --- a/src/apps/installer/WorkerThread.cpp +++ b/src/apps/installer/WorkerThread.cpp @@ -27,6 +27,7 @@ #include "InstallerWindow.h" #include "PackageViews.h" #include "PartitionMenuItem.h" +#include "ProgressReporter.h" #include "UnzipEngine.h" @@ -251,7 +252,9 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) entry_ref testRef; BMessenger messenger(fWindow); - CopyEngine engine(messenger, new BMessage(MSG_STATUS_MESSAGE)); + ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE)); + CopyEngine engine(&reporter); + BList unzipEngines; PartitionMenuItem* targetItem = (PartitionMenuItem*)targetMenu->FindMarked(); PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked(); @@ -397,6 +400,7 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) goto error; } + // Begin actuall installation _LaunchInitScript(targetDirectory); @@ -419,6 +423,14 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) } } + // collect information about all zip packages + err = _ProcessZipPackages(srcDirectory.Path(), targetDirectory.Path(), + &reporter, unzipEngines); + if (err != B_OK) + goto error; + + reporter.StartTimer(); + // copy source volume err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), fCancelSemaphore); @@ -439,37 +451,17 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) } } -#if 0 - // extract zip packages - // TODO: Put those in the optional packages list view - // TODO: Implement mechanism to handle dependencies between these - // packages. (Selecting one will auto-select others.) - { - BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY); - BDirectory directory(pkgRootDir.Path()); - BEntry entry; - while (directory.GetNextEntry(&entry) == B_OK) { - char name[B_FILE_NAME_LENGTH]; - if (entry.GetName(name) != B_OK) - continue; - int nameLength = strlen(name); - if (nameLength <= 0) - continue; - char* nameExtension = name + nameLength - 4; -printf("inspecting %s (%s)\n", name, nameExtension); - if (strcasecmp(nameExtension, ".zip") != 0) - continue; - printf("found .zip package: %s\n", name); - - UnzipEngine unzipEngine(messenger, new BMessage(MSG_STATUS_MESSAGE), - fCancelSemaphore); - BPath path; - entry.GetPath(&path); - unzipEngine.SetTo(path.Path(), targetDirectory.Path()); - unzipEngine.UnzipPackage(); - } + // Extract all zip packages. If an error occured, delete the rest of + // the engines, but stop extracting. + for (int32 i = 0; i < unzipEngines.CountItems(); i++) { + UnzipEngine* engine = reinterpret_cast( + unzipEngines.ItemAtFast(i)); + if (err == B_OK) + err = engine->UnzipPackage(); + delete engine; } -#endif + if (err != B_OK) + goto error; _LaunchFinishScript(targetDirectory); @@ -487,6 +479,48 @@ error: } +status_t +WorkerThread::_ProcessZipPackages(const char* sourcePath, + const char* targetPath, ProgressReporter* reporter, BList& unzipEngines) +{ + // TODO: Put those in the optional packages list view + // TODO: Implement mechanism to handle dependencies between these + // packages. (Selecting one will auto-select others.) + BPath pkgRootDir(sourcePath, PACKAGES_DIRECTORY); + BDirectory directory(pkgRootDir.Path()); + BEntry entry; + while (directory.GetNextEntry(&entry) == B_OK) { + char name[B_FILE_NAME_LENGTH]; + if (entry.GetName(name) != B_OK) + continue; + int nameLength = strlen(name); + if (nameLength <= 0) + continue; + char* nameExtension = name + nameLength - 4; + if (strcasecmp(nameExtension, ".zip") != 0) + continue; + printf("found .zip package: %s\n", name); + + UnzipEngine* unzipEngine = new(std::nothrow) UnzipEngine(reporter, + fCancelSemaphore); + if (unzipEngine == NULL || !unzipEngines.AddItem(unzipEngine)) { + delete unzipEngine; + return B_NO_MEMORY; + } + BPath path; + entry.GetPath(&path); + status_t ret = unzipEngine->SetTo(path.Path(), targetPath); + if (ret != B_OK) + return ret; + + reporter->AddItems(unzipEngine->ItemsToUncompress(), + unzipEngine->BytesToUncompress()); + } + + return B_OK; +} + + void WorkerThread::_SetStatusMessage(const char *status) { diff --git a/src/apps/installer/WorkerThread.h b/src/apps/installer/WorkerThread.h index 25f58ed69e..3fc7e1cef3 100644 --- a/src/apps/installer/WorkerThread.h +++ b/src/apps/installer/WorkerThread.h @@ -16,6 +16,7 @@ class BList; class BMenu; class InstallerWindow; +class ProgressReporter; class WorkerThread : public BLooper { public: @@ -41,7 +42,12 @@ private: void _LaunchInitScript(BPath& path); void _LaunchFinishScript(BPath& path); - void _PerformInstall(BMenu* srcMenu, BMenu* dstMenu); + void _PerformInstall(BMenu* srcMenu, + BMenu* dstMenu); + status_t _ProcessZipPackages(const char* sourcePath, + const char* targetPath, + ProgressReporter* reporter, + BList& unzipEngines); void _SetStatusMessage(const char* status);