* Changed the UnzipEngine to be a BCommandPipe::LineReader itself, this

simplified the code somewhat (maintaining of state).
* UnzipEngine does a more complete parsing of the .zip contents and maintains
  a hashmap of item names to byte size entries. During unzipping later on, this
  allows to know how many bytes were unzipped for the given item.
* Test whether folders from the .zip already exists, and exclude them from the
  item count, since unzip will not report creating folders that already
  existed.
* Added the unzipping of packages in the _package_ folder to WorkerThread, but
  it is currently commented out to keep Installer in a working state. It would
  work, but the problem is that the progress bar would reset itself at the
  moment (for every package).
* Started a ProgressReporter class that will later be used by all CopyEngine and
  UnzipEngine instances. This is work in progress and not yet part of the build.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32959 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-09-06 10:26:51 +00:00
parent 148077d71e
commit 41974e4319
6 changed files with 353 additions and 105 deletions
+3 -2
View File
@@ -3,12 +3,13 @@ SubDir HAIKU_TOP src apps installer ;
UsePrivateHeaders shared storage tracker ; UsePrivateHeaders shared storage tracker ;
SubDirHdrs [ FDirName $(HAIKU_TOP) src kits tracker ] ; SubDirHdrs [ FDirName $(HAIKU_TOP) src kits tracker ] ;
Application Installer : Application Installer :
CopyEngine.cpp CopyEngine.cpp
InstallerApp.cpp InstallerApp.cpp
InstallerWindow.cpp InstallerWindow.cpp
PackageViews.cpp PackageViews.cpp
PartitionMenuItem.cpp PartitionMenuItem.cpp
UnzipEngine.cpp
WorkerThread.cpp WorkerThread.cpp
: be tracker translation $(TARGET_LIBSTDC++) : be tracker translation libshared.a $(TARGET_LIBSTDC++)
: Installer.rdef ; : Installer.rdef ;
+100
View File
@@ -0,0 +1,100 @@
/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ProgressReporter.h"
#include <new>
#include <math.h>
#include <stdio.h>
#include <string.h>
using std::nothrow;
ProgressReporter::ProgressReporter(const BMessenger& messenger,
BMessage* message)
:
fBytesRead(0),
fItemsCopied(0),
fTimeRead(0),
fBytesWritten(0),
fTimeWritten(0),
fBytesToCopy(0),
fItemsToCopy(0),
fMessenger(messenger),
fMessage(message)
{
}
ProgressReporter::~ProgressReporter()
{
delete fMessage;
}
void
ProgressReporter::Reset()
{
fBytesRead = 0;
fItemsCopied = 0;
fTimeRead = 0;
fBytesWritten = 0;
fTimeWritten = 0;
fBytesToCopy = 0;
fItemsToCopy = 0;
if (fMessage) {
BMessage message(*fMessage);
message.AddString("status", "Collecting copy information.");
fMessenger.SendMessage(&message);
}
}
void
ProgressReporter::AddItems(uint64 count, off_t bytes)
{
// TODO ...
}
void
ProgressReporter::StartTimer()
{
// TODO ...
}
void
ProgressReporter::ItemsCopied(uint64 items, off_t bytes, const char* itemName,
const char* targetFolder)
{
// TODO ...
}
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);
}
}
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PROGRESS_REPORTER_H
#define PROGRESS_REPORTER_H
#include <Messenger.h>
class ProgressReporter {
public:
ProgressReporter(const BMessenger& messenger,
BMessage* message);
virtual ~ProgressReporter();
void Reset();
void AddItems(uint64 count, off_t bytes);
void StartTimer();
void ItemsCopied(uint64 items, off_t bytes,
const char* itemName,
const char* targetFolder);
private:
void _UpdateProgress(const char* itemName,
const char* targetFolder);
private:
off_t fBytesRead;
uint64 fItemsCopied;
bigtime_t fTimeRead;
off_t fBytesWritten;
bigtime_t fTimeWritten;
off_t fBytesToCopy;
uint64 fItemsToCopy;
BMessenger fMessenger;
BMessage* fMessage;
};
#endif // PROGRESS_REPORTER_H
+135 -88
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2008-2009, Stephan Aßmus <[email protected]> * Copyright 2009, Stephan Aßmus <[email protected]>
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -26,20 +26,20 @@
using std::nothrow; using std::nothrow;
UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message) UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message,
sem_id cancelSemaphore)
: :
fPackage(""), fPackage(""),
fRetrievingListing(false),
fBytesToUncompress(0), fBytesToUncompress(0),
fBytesUncompressed(0), fBytesUncompressed(0),
fItemsToUncompress(0), fItemsToUncompress(0),
fItemsUncompressed(0), fItemsUncompressed(0),
fCurrentTargetFolder(NULL),
fCurrentItem(NULL),
fMessenger(messenger), fMessenger(messenger),
fMessage(message) fMessage(message),
fCancelSemaphore(cancelSemaphore)
{ {
} }
@@ -51,16 +51,22 @@ UnzipEngine::~UnzipEngine()
status_t status_t
UnzipEngine::SetTo(const char* pathToPackage) UnzipEngine::SetTo(const char* pathToPackage, const char* destinationFolder)
{ {
fPackage = pathToPackage; fPackage = pathToPackage;
fDestinationFolder = destinationFolder;
fEntrySizeMap.Clear();
fBytesToUncompress = 0;
fBytesUncompressed = 0;
fItemsToUncompress = 0;
fItemsUncompressed = 0;
BPrivate::BCommandPipe commandPipe; BPrivate::BCommandPipe commandPipe;
status_t ret = commandPipe.AddArg("unzip"); status_t ret = commandPipe.AddArg("unzip");
if (ret == B_OK) if (ret == B_OK)
ret = commandPipe.AddArg("-Z"); ret = commandPipe.AddArg("-l");
if (ret == B_OK)
ret = commandPipe.AddArg("-t");
if (ret == B_OK) if (ret == B_OK)
ret = commandPipe.AddArg(fPackage.String()); ret = commandPipe.AddArg(fPackage.String());
if (ret != B_OK) if (ret != B_OK)
@@ -72,30 +78,19 @@ UnzipEngine::SetTo(const char* pathToPackage)
if (unzipThread < 0) if (unzipThread < 0)
return (status_t)unzipThread; return (status_t)unzipThread;
BString result = commandPipe.ReadLines(stdOutAndErrPipe); fRetrievingListing = true;
static const char* kListingFormat = "%llu files, %llu bytes uncompressed, " ret = commandPipe.ReadLines(stdOutAndErrPipe, this);
"%llu bytes compressed: %f%%"; fRetrievingListing = false;
uint64 bytesCompressed; printf("%llu items in %llu bytes\n", fItemsToUncompress,
float compresssionRatio;
if (sscanf(result.String(), kListingFormat, &fItemsToUncompress,
&fBytesToUncompress, &bytesCompressed, &compresssionRatio) != 4) {
fBytesToUncompress = 0;
fItemsToUncompress = 0;
fprintf(stderr, "error reading command output: %s\n", result.String());
return B_ERROR;
}
printf("%s: %llu items in %llu bytes\n", pathToPackage, fItemsToUncompress,
fBytesToUncompress); fBytesToUncompress);
return B_OK; return ret;
} }
status_t status_t
UnzipEngine::UnzipPackage(const char* destinationFolder, UnzipEngine::UnzipPackage()
sem_id cancelSemaphore)
{ {
if (fItemsToUncompress == 0) if (fItemsToUncompress == 0)
return B_NO_INIT; return B_NO_INIT;
@@ -115,7 +110,7 @@ UnzipEngine::UnzipPackage(const char* destinationFolder,
if (ret == B_OK) if (ret == B_OK)
ret = commandPipe.AddArg("-d"); ret = commandPipe.AddArg("-d");
if (ret == B_OK) if (ret == B_OK)
ret = commandPipe.AddArg(destinationFolder); ret = commandPipe.AddArg(fDestinationFolder.String());
if (ret == B_OK) if (ret == B_OK)
ret = commandPipe.AddArg("-x"); ret = commandPipe.AddArg("-x");
if (ret == B_OK) if (ret == B_OK)
@@ -129,87 +124,139 @@ UnzipEngine::UnzipPackage(const char* destinationFolder,
if (unzipThread < 0) if (unzipThread < 0)
return (status_t)unzipThread; return (status_t)unzipThread;
return _ReadFromPipe(stdOutAndErrPipe, commandPipe, cancelSemaphore); return commandPipe.ReadLines(stdOutAndErrPipe, this);
} }
// #pragma mark - // #pragma mark -
status_t bool
UnzipEngine::_ReadFromPipe(FILE* stdOutAndErrPipe, UnzipEngine::IsCanceled()
BPrivate::BCommandPipe& commandPipe, sem_id cancelSemaphore)
{ {
class LineReader : public BPrivate::BCommandPipe::LineReader { if (fCancelSemaphore < 0)
public: return false;
LineReader(sem_id cancelSemaphore, off_t bytesToUncompress,
uint64 itemsToUncompress, BMessenger& messenger,
const BMessage* message)
:
fCancelSemaphore(cancelSemaphore),
fBytesToUncompress(itemsToUncompress), SemaphoreLocker locker(fCancelSemaphore);
fBytesUncompressed(0), return !locker.IsLocked();
fItemsToUncompress(itemsToUncompress), }
fItemsUncompressed(0),
fMessenger(messenger),
fMessage(message)
{
}
virtual bool IsCanceled() status_t
{ UnzipEngine::ReadLine(const BString& line)
if (fCancelSemaphore < 0) {
return false; if (fRetrievingListing)
return _ReadLineListing(line);
else
return _ReadLineExtract(line);
}
SemaphoreLocker locker(fCancelSemaphore);
return !locker.IsLocked();
}
virtual status_t ReadLine(const BString& line) status_t
{ UnzipEngine::_ReadLineListing(const BString& line)
char item[1024]; {
char linkTarget[256]; // static const char* kListingFormat = "%llu files, %llu bytes uncompressed, "
const char* kInflatingFormat = " inflating: %s\n"; // "%llu bytes compressed: %f%%";
const char* kLinkingFormat = " linking: %s -> %s\n"; //
if (sscanf(line.String(), kInflatingFormat, &item) == 1 // uint64 bytesCompressed;
|| sscanf(line.String(), kLinkingFormat, &item, // float compresssionRatio;
&linkTarget) == 2) { // if (sscanf(line.String(), kListingFormat, &fItemsToUncompress,
BString itemPath(item); // &fBytesToUncompress, &bytesCompressed, &compresssionRatio) != 4) {
int pos = itemPath.FindLast('/'); // fBytesToUncompress = 0;
BString itemName = itemPath.String() + pos + 1; // fItemsToUncompress = 0;
itemPath.Truncate(pos); // fprintf(stderr, "error reading command output: %s\n", line.String());
printf("extracted %s to %s\n", itemName.String(), // return B_ERROR;
itemPath.String()); // }
} else {
printf("ignored: %s", line.String()); static const char* kListingFormat = "%llu %s %s %s\n";
const char* string = line.String();
while (string[0] == ' ')
string++;
uint64 bytes;
char date[16];
char time[16];
char path[1024];
if (sscanf(string, kListingFormat, &bytes, &date, &time, &path) == 4) {
fBytesToUncompress += bytes;
BString itemPath(path);
BString itemName(path);
int leafPos = itemPath.FindLast('/');
if (leafPos >= 0)
itemName = itemPath.String() + leafPos + 1;
// We check if the target folder exists and don't increment
// the item count in that case. Unzip won't report on folders that did
// not need to be created. This may mess up our current item count.
uint32 itemCount = 1;
if (bytes == 0 && itemName.Length() == 0) {
// a folder?
BPath destination(fDestinationFolder.String());
if (destination.Append(itemPath.String()) == B_OK) {
BEntry test(destination.Path());
if (test.Exists() && test.IsDirectory()) {
printf("ignoring %s\n", itemPath.String());
itemCount = 0;
}
} }
return B_OK;
} }
private: fItemsToUncompress += itemCount;
sem_id fCancelSemaphore;
off_t fBytesToUncompress; printf("item %s with %llu bytes to %s\n", itemName.String(),
off_t fBytesUncompressed; bytes, itemPath.String());
uint64 fItemsToUncompress;
uint64 fItemsUncompressed;
BMessenger& fMessenger; fEntrySizeMap.Put(itemName.String(), bytes);
const BMessage* fMessage; } else {
}; // printf("listing not understood: %s", string);
}
LineReader lineReader(cancelSemaphore, fBytesToUncompress, return B_OK;
fItemsToUncompress, fMessenger, fMessage); }
return commandPipe.ReadLines(stdOutAndErrPipe, &lineReader);
status_t
UnzipEngine::_ReadLineExtract(const BString& line)
{
char item[1024];
char linkTarget[256];
const char* kCreatingFormat = " creating: %s\n";
const char* kInflatingFormat = " inflating: %s\n";
const char* kLinkingFormat = " linking: %s -> %s\n";
if (sscanf(line.String(), kCreatingFormat, &item) == 1
|| sscanf(line.String(), kInflatingFormat, &item) == 1
|| sscanf(line.String(), kLinkingFormat, &item,
&linkTarget) == 2) {
fItemsUncompressed++;
BString itemPath(item);
int pos = itemPath.FindLast('/');
BString itemName = itemPath.String() + pos + 1;
itemPath.Truncate(pos);
off_t bytes = 0;
if (fEntrySizeMap.ContainsKey(itemName.String())) {
bytes = fEntrySizeMap.Get(itemName.String());
fBytesUncompressed += bytes;
}
printf("%llu extracted %s to %s (%llu)\n", fItemsUncompressed,
itemName.String(), itemPath.String(), bytes);
_UpdateProgress(itemName.String(), itemPath.String());
} else {
// printf("ignored: %s", line.String());
}
return B_OK;
} }
void void
UnzipEngine::_UpdateProgress() UnzipEngine::_UpdateProgress(const char* item, const char* targetFolder)
{ {
if (fMessage != NULL) { if (fMessage != NULL) {
BMessage message(*fMessage); BMessage message(*fMessage);
@@ -217,8 +264,8 @@ UnzipEngine::_UpdateProgress()
message.AddFloat("progress", progress); message.AddFloat("progress", progress);
message.AddInt32("current", fItemsUncompressed); message.AddInt32("current", fItemsUncompressed);
message.AddInt32("maximum", fItemsToUncompress); message.AddInt32("maximum", fItemsToUncompress);
message.AddString("item", fCurrentItem); message.AddString("item", item);
message.AddString("folder", fCurrentTargetFolder); message.AddString("folder", targetFolder);
fMessenger.SendMessage(&message); fMessenger.SendMessage(&message);
} }
} }
+32 -15
View File
@@ -11,43 +11,60 @@
#include <Messenger.h> #include <Messenger.h>
#include <String.h> #include <String.h>
namespace BPrivate { #include "CommandPipe.h"
class BCommandPipe; #include "HashMap.h"
} #include "HashString.h"
class BMessage; class BMessage;
class BMessenger; class BMessenger;
class UnzipEngine { class UnzipEngine : private BCommandPipe::LineReader {
public: public:
UnzipEngine(const BMessenger& messenger, UnzipEngine(const BMessenger& messenger,
BMessage* message); BMessage* message,
sem_id cancelSemaphore = -1);
virtual ~UnzipEngine(); virtual ~UnzipEngine();
status_t SetTo(const char* pathToPackage); status_t SetTo(const char* pathToPackage,
const char* destinationFolder);
status_t UnzipPackage(const char* destinationFolder, inline off_t BytesToUncompress() const
sem_id cancelSemaphore = -1); { return fBytesToUncompress; }
inline uint64 ItemsToUncompress() const
{ return fItemsToUncompress; }
status_t UnzipPackage();
private: private:
status_t _ReadFromPipe(FILE* stdOutAndErrPipe, // BCommandPipe::LineReader
BPrivate::BCommandPipe& commandPipe, friend class BCommandPipe;
sem_id cancelSemaphore);
void _UpdateProgress(); virtual bool IsCanceled();
virtual status_t ReadLine(const BString& line);
status_t _ReadLineListing(const BString& line);
status_t _ReadLineExtract(const BString& line);
void _UpdateProgress(const char* item,
const char* targetFolder);
private: private:
BString fPackage; BString fPackage;
BString fDestinationFolder;
bool fRetrievingListing;
typedef HashMap<HashString, off_t> EntrySizeMap;
EntrySizeMap fEntrySizeMap;
off_t fBytesToUncompress; off_t fBytesToUncompress;
off_t fBytesUncompressed; off_t fBytesUncompressed;
uint64 fItemsToUncompress; uint64 fItemsToUncompress;
uint64 fItemsUncompressed; uint64 fItemsUncompressed;
const char* fCurrentTargetFolder;
const char* fCurrentItem;
BMessenger fMessenger; BMessenger fMessenger;
BMessage* fMessage; BMessage* fMessage;
sem_id fCancelSemaphore;
}; };
+35
View File
@@ -27,6 +27,7 @@
#include "InstallerWindow.h" #include "InstallerWindow.h"
#include "PackageViews.h" #include "PackageViews.h"
#include "PartitionMenuItem.h" #include "PartitionMenuItem.h"
#include "UnzipEngine.h"
//#define COPY_TRACE //#define COPY_TRACE
@@ -390,6 +391,8 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
"version.", "version.",
"Install Anyway", "Cancel", 0, "Install Anyway", "Cancel", 0,
B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) {
// TODO: Would be cool to offer the option here to clean additional
// folders at the user's choice (like /boot/common and /boot/develop).
err = B_CANCELED; err = B_CANCELED;
goto error; goto error;
} }
@@ -436,6 +439,38 @@ 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();
}
}
#endif
_LaunchFinishScript(targetDirectory); _LaunchFinishScript(targetDirectory);
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED); BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);