* 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:
parent
148077d71e
commit
41974e4319
|
@ -9,6 +9,7 @@ Application Installer :
|
|||
InstallerWindow.cpp
|
||||
PackageViews.cpp
|
||||
PartitionMenuItem.cpp
|
||||
UnzipEngine.cpp
|
||||
WorkerThread.cpp
|
||||
: be tracker translation $(TARGET_LIBSTDC++)
|
||||
: be tracker translation libshared.a $(TARGET_LIBSTDC++)
|
||||
: Installer.rdef ;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
|
||||
* 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
|
||||
* 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
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2008-2009, Stephan Aßmus <superstippi@gmx.de>
|
||||
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
|
||||
* All rights reserved. Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
@ -26,20 +26,20 @@
|
|||
using std::nothrow;
|
||||
|
||||
|
||||
UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message)
|
||||
UnzipEngine::UnzipEngine(const BMessenger& messenger, BMessage* message,
|
||||
sem_id cancelSemaphore)
|
||||
:
|
||||
fPackage(""),
|
||||
fRetrievingListing(false),
|
||||
|
||||
fBytesToUncompress(0),
|
||||
fBytesUncompressed(0),
|
||||
fItemsToUncompress(0),
|
||||
fItemsUncompressed(0),
|
||||
|
||||
fCurrentTargetFolder(NULL),
|
||||
fCurrentItem(NULL),
|
||||
|
||||
fMessenger(messenger),
|
||||
fMessage(message)
|
||||
fMessage(message),
|
||||
fCancelSemaphore(cancelSemaphore)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -51,16 +51,22 @@ UnzipEngine::~UnzipEngine()
|
|||
|
||||
|
||||
status_t
|
||||
UnzipEngine::SetTo(const char* pathToPackage)
|
||||
UnzipEngine::SetTo(const char* pathToPackage, const char* destinationFolder)
|
||||
{
|
||||
fPackage = pathToPackage;
|
||||
fDestinationFolder = destinationFolder;
|
||||
|
||||
fEntrySizeMap.Clear();
|
||||
|
||||
fBytesToUncompress = 0;
|
||||
fBytesUncompressed = 0;
|
||||
fItemsToUncompress = 0;
|
||||
fItemsUncompressed = 0;
|
||||
|
||||
BPrivate::BCommandPipe commandPipe;
|
||||
status_t ret = commandPipe.AddArg("unzip");
|
||||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg("-Z");
|
||||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg("-t");
|
||||
ret = commandPipe.AddArg("-l");
|
||||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg(fPackage.String());
|
||||
if (ret != B_OK)
|
||||
|
@ -72,30 +78,19 @@ UnzipEngine::SetTo(const char* pathToPackage)
|
|||
if (unzipThread < 0)
|
||||
return (status_t)unzipThread;
|
||||
|
||||
BString result = commandPipe.ReadLines(stdOutAndErrPipe);
|
||||
static const char* kListingFormat = "%llu files, %llu bytes uncompressed, "
|
||||
"%llu bytes compressed: %f%%";
|
||||
fRetrievingListing = true;
|
||||
ret = commandPipe.ReadLines(stdOutAndErrPipe, this);
|
||||
fRetrievingListing = false;
|
||||
|
||||
uint64 bytesCompressed;
|
||||
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,
|
||||
printf("%llu items in %llu bytes\n", fItemsToUncompress,
|
||||
fBytesToUncompress);
|
||||
|
||||
return B_OK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
UnzipEngine::UnzipPackage(const char* destinationFolder,
|
||||
sem_id cancelSemaphore)
|
||||
UnzipEngine::UnzipPackage()
|
||||
{
|
||||
if (fItemsToUncompress == 0)
|
||||
return B_NO_INIT;
|
||||
|
@ -115,7 +110,7 @@ UnzipEngine::UnzipPackage(const char* destinationFolder,
|
|||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg("-d");
|
||||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg(destinationFolder);
|
||||
ret = commandPipe.AddArg(fDestinationFolder.String());
|
||||
if (ret == B_OK)
|
||||
ret = commandPipe.AddArg("-x");
|
||||
if (ret == B_OK)
|
||||
|
@ -129,87 +124,139 @@ UnzipEngine::UnzipPackage(const char* destinationFolder,
|
|||
if (unzipThread < 0)
|
||||
return (status_t)unzipThread;
|
||||
|
||||
return _ReadFromPipe(stdOutAndErrPipe, commandPipe, cancelSemaphore);
|
||||
return commandPipe.ReadLines(stdOutAndErrPipe, this);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
UnzipEngine::_ReadFromPipe(FILE* stdOutAndErrPipe,
|
||||
BPrivate::BCommandPipe& commandPipe, sem_id cancelSemaphore)
|
||||
bool
|
||||
UnzipEngine::IsCanceled()
|
||||
{
|
||||
class LineReader : public BPrivate::BCommandPipe::LineReader {
|
||||
public:
|
||||
LineReader(sem_id cancelSemaphore, off_t bytesToUncompress,
|
||||
uint64 itemsToUncompress, BMessenger& messenger,
|
||||
const BMessage* message)
|
||||
:
|
||||
fCancelSemaphore(cancelSemaphore),
|
||||
|
||||
fBytesToUncompress(itemsToUncompress),
|
||||
fBytesUncompressed(0),
|
||||
fItemsToUncompress(itemsToUncompress),
|
||||
fItemsUncompressed(0),
|
||||
|
||||
fMessenger(messenger),
|
||||
fMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool IsCanceled()
|
||||
{
|
||||
if (fCancelSemaphore < 0)
|
||||
return false;
|
||||
|
||||
SemaphoreLocker locker(fCancelSemaphore);
|
||||
return !locker.IsLocked();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
UnzipEngine::ReadLine(const BString& line)
|
||||
{
|
||||
if (fRetrievingListing)
|
||||
return _ReadLineListing(line);
|
||||
else
|
||||
return _ReadLineExtract(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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual status_t ReadLine(const BString& line)
|
||||
{
|
||||
fItemsToUncompress += itemCount;
|
||||
|
||||
printf("item %s with %llu bytes to %s\n", itemName.String(),
|
||||
bytes, itemPath.String());
|
||||
|
||||
fEntrySizeMap.Put(itemName.String(), bytes);
|
||||
} else {
|
||||
// printf("listing not understood: %s", string);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
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(), kInflatingFormat, &item) == 1
|
||||
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);
|
||||
printf("extracted %s to %s\n", itemName.String(),
|
||||
itemPath.String());
|
||||
|
||||
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());
|
||||
// printf("ignored: %s", line.String());
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
sem_id fCancelSemaphore;
|
||||
|
||||
off_t fBytesToUncompress;
|
||||
off_t fBytesUncompressed;
|
||||
uint64 fItemsToUncompress;
|
||||
uint64 fItemsUncompressed;
|
||||
|
||||
BMessenger& fMessenger;
|
||||
const BMessage* fMessage;
|
||||
};
|
||||
|
||||
LineReader lineReader(cancelSemaphore, fBytesToUncompress,
|
||||
fItemsToUncompress, fMessenger, fMessage);
|
||||
|
||||
return commandPipe.ReadLines(stdOutAndErrPipe, &lineReader);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UnzipEngine::_UpdateProgress()
|
||||
UnzipEngine::_UpdateProgress(const char* item, const char* targetFolder)
|
||||
{
|
||||
if (fMessage != NULL) {
|
||||
BMessage message(*fMessage);
|
||||
|
@ -217,8 +264,8 @@ UnzipEngine::_UpdateProgress()
|
|||
message.AddFloat("progress", progress);
|
||||
message.AddInt32("current", fItemsUncompressed);
|
||||
message.AddInt32("maximum", fItemsToUncompress);
|
||||
message.AddString("item", fCurrentItem);
|
||||
message.AddString("folder", fCurrentTargetFolder);
|
||||
message.AddString("item", item);
|
||||
message.AddString("folder", targetFolder);
|
||||
fMessenger.SendMessage(&message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,43 +11,60 @@
|
|||
#include <Messenger.h>
|
||||
#include <String.h>
|
||||
|
||||
namespace BPrivate {
|
||||
class BCommandPipe;
|
||||
}
|
||||
#include "CommandPipe.h"
|
||||
#include "HashMap.h"
|
||||
#include "HashString.h"
|
||||
|
||||
class BMessage;
|
||||
class BMessenger;
|
||||
|
||||
|
||||
class UnzipEngine {
|
||||
class UnzipEngine : private BCommandPipe::LineReader {
|
||||
public:
|
||||
UnzipEngine(const BMessenger& messenger,
|
||||
BMessage* message);
|
||||
BMessage* message,
|
||||
sem_id cancelSemaphore = -1);
|
||||
virtual ~UnzipEngine();
|
||||
|
||||
status_t SetTo(const char* pathToPackage);
|
||||
status_t SetTo(const char* pathToPackage,
|
||||
const char* destinationFolder);
|
||||
|
||||
status_t UnzipPackage(const char* destinationFolder,
|
||||
sem_id cancelSemaphore = -1);
|
||||
inline off_t BytesToUncompress() const
|
||||
{ return fBytesToUncompress; }
|
||||
inline uint64 ItemsToUncompress() const
|
||||
{ return fItemsToUncompress; }
|
||||
|
||||
status_t UnzipPackage();
|
||||
|
||||
private:
|
||||
status_t _ReadFromPipe(FILE* stdOutAndErrPipe,
|
||||
BPrivate::BCommandPipe& commandPipe,
|
||||
sem_id cancelSemaphore);
|
||||
void _UpdateProgress();
|
||||
// BCommandPipe::LineReader
|
||||
friend class BCommandPipe;
|
||||
|
||||
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:
|
||||
BString fPackage;
|
||||
BString fDestinationFolder;
|
||||
bool fRetrievingListing;
|
||||
|
||||
typedef HashMap<HashString, off_t> EntrySizeMap;
|
||||
EntrySizeMap fEntrySizeMap;
|
||||
|
||||
off_t fBytesToUncompress;
|
||||
off_t fBytesUncompressed;
|
||||
uint64 fItemsToUncompress;
|
||||
uint64 fItemsUncompressed;
|
||||
|
||||
const char* fCurrentTargetFolder;
|
||||
const char* fCurrentItem;
|
||||
|
||||
BMessenger fMessenger;
|
||||
BMessage* fMessage;
|
||||
sem_id fCancelSemaphore;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "InstallerWindow.h"
|
||||
#include "PackageViews.h"
|
||||
#include "PartitionMenuItem.h"
|
||||
#include "UnzipEngine.h"
|
||||
|
||||
|
||||
//#define COPY_TRACE
|
||||
|
@ -390,6 +391,8 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
|||
"version.",
|
||||
"Install Anyway", "Cancel", 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;
|
||||
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);
|
||||
|
||||
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
|
||||
|
|
Loading…
Reference in New Issue