* Merged changesets r32903, r32926, r32957, r32959, r32967, r32986 and r32987

(all the CommandPipe and Installer changes).
* Merged changeset r32968 (Haiku Guide).
* Merged changesets r32969, r32983, r32984 and r32992 (OptionalPackages).
* Merged changeset r32995 (Installer links fixes).
* Merged changeset r32996 (unzipping of packages at install time)
* Updated OptionalPackages warnings about packages that still need to be
  rebuilt.


git-svn-id: file:///srv/svn/repos/haiku/haiku/branches/releases/r1alpha1@32997 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-09-08 11:52:36 +00:00
parent db6309f854
commit 85d74e5f59
21 changed files with 1037 additions and 292 deletions

View File

@ -758,13 +758,18 @@ rule OptionalPackageDependencies package : dependencies
}
}
rule InstallOptionalHaikuImagePackage package : url : dirTokens
rule InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage
{
# download zip file
local zipFile = [ DownloadOptionalPackage $(package) : $(url) ] ;
# unzip onto image
UnzipArchiveToHaikuImage $(dirTokens) : $(zipFile) ;
if $(isCDPackage) = true || $(isCDPackage) = 1 && $(HAIKU_CD_NAME) {
# copy onto image
AddFilesToHaikuImage _packages_ : $(zipFile) ;
} else {
# unzip onto image
UnzipArchiveToHaikuImage $(dirTokens) : $(zipFile) ;
}
}
rule AddEntryToHaikuImageUserGroupFile file : entry

View File

@ -12,7 +12,7 @@ if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) {
# Available Optional Packages:
# APR - support libraries used for example by SVN
# APR - support libraries used for example by Subversion
# APR-util
# Beam - powerful native e-mail client
# BeBook - the classic BeOS API documentation
@ -81,26 +81,28 @@ local baseURL = http://haiku-files.org/files/optional-packages ;
# APR
if [ IsObsoleteOptionalHaikuImagePackageAdded APR ] {
if [ IsOptionalHaikuImagePackageAdded APR ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package APR available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage apr-1.3.8-r1a1-x86-gcc2-2009-08-29
: $(baseURL)/apr-1.3.8-r1a1-x86-gcc2-2009-08-29.zip
:
: true
;
}
}
# APR-util
if [ IsObsoleteOptionalHaikuImagePackageAdded APR-util ] {
if [ IsOptionalHaikuImagePackageAdded APR-util ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package APR-util available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage apr-util-1.3.9-r1a1-x86-gcc2-2009-08-29
: $(baseURL)/apr-util-1.3.9-r1a1-x86-gcc2-2009-08-29.zip
:
: true
;
}
}
@ -170,7 +172,7 @@ if [ IsOptionalHaikuImagePackageAdded BeOSCompatibility ] {
# BePDF
if [ IsObsoleteOptionalHaikuImagePackageAdded BePDF ] {
if [ IsOptionalHaikuImagePackageAdded BePDF ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package BePDF available for $(TARGET_ARCH)" ;
} else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) {
@ -210,7 +212,7 @@ if [ IsOptionalHaikuImagePackageAdded Bluetooth ] {
# CDRecord
if [ IsObsoleteOptionalHaikuImagePackageAdded CDRecord ] {
if [ IsOptionalHaikuImagePackageAdded CDRecord ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package CDRecord available for $(TARGET_ARCH)" ;
} else {
@ -255,6 +257,7 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded CLucene ] {
clucene-0.9.21svn-x86-gcc4-haiku-2009-08-11
: $(baseURL)/clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip
:
: true
;
}
}
@ -267,21 +270,22 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] {
} else {
InstallOptionalHaikuImagePackage curl-7.19.6-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/curl-7.19.6-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
# CVS
if [ IsObsoleteOptionalHaikuImagePackageAdded CVS ] {
if [ IsOptionalHaikuImagePackageAdded CVS ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package CVS available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage cvs-1.12.13-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/cvs-1.12.13-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
@ -291,18 +295,21 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded CVS ] {
if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
# autotools
InstallOptionalHaikuImagePackage autoconf-2.64-r1a1-x86-gcc2-2009-08-27
: $(baseURL)/autoconf-2.64-r1a1-x86-gcc2-2009-08-27.zip ;
: $(baseURL)/autoconf-2.64-r1a1-x86-gcc2-2009-08-27.zip
:
: true ;
InstallOptionalHaikuImagePackage automake-1.11-r1a1-x86-gcc2-2009-08-27
: $(baseURL)/automake-1.11-r1a1-x86-gcc2-2009-08-27.zip ;
: $(baseURL)/automake-1.11-r1a1-x86-gcc2-2009-08-27.zip
:
: true ;
InstallOptionalHaikuImagePackage libtool-2.2.6a-r1a1-x86-gcc2-2009-08-28
: $(baseURL)/libtool-2.2.6a-r1a1-x86-gcc2-2009-08-28.zip ;
: $(baseURL)/libtool-2.2.6a-r1a1-x86-gcc2-2009-08-28.zip
:
: true ;
InstallOptionalHaikuImagePackage texinfo-4.13a-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/texinfo-4.13a-r1a1-x86-gcc2-2009-08-30.zip ;
ObsoleteOptionalPackageWarning autoconf ;
ObsoleteOptionalPackageWarning automake ;
ObsoleteOptionalPackageWarning libtool ;
ObsoleteOptionalPackageWarning texinfo ;
: $(baseURL)/texinfo-4.13a-r1a1-x86-gcc2-2009-08-30.zip
:
: true ;
}
@ -446,6 +453,7 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
InstallOptionalHaikuImagePackage expat-2.0.1-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/expat-2.0.1-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
@ -482,27 +490,28 @@ if [ IsOptionalHaikuImagePackageAdded Git ] {
InstallOptionalHaikuImagePackage git-1.6.4.2-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/git-1.6.4.2-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
# KeymapSwitcher
if [ IsObsoleteOptionalHaikuImagePackageAdded KeymapSwitcher ] {
if [ IsOptionalHaikuImagePackageAdded KeymapSwitcher ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package KeymapSwitcher available for $(TARGET_ARCH)" ;
} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
InstallOptionalHaikuImagePackage
KeymapSwitcher-1.2.3-x86-gcc4-2009-05-31
: $(baseURL)/KeymapSwitcher-1.2.3-x86-gcc4-2009-05-31.zip
: $(baseURL)/KeymapSwitcher-1.2.3-x86-gcc4-2009-05-31.zip
:
;
AddSymlinkToHaikuImage home config be Desktop\ Applets
: /boot/common/bin/KeymapSwitcher ;
} else {
InstallOptionalHaikuImagePackage
KeymapSwitcher-1.2.3-x86-gcc2-2009-05-31
: $(baseURL)/KeymapSwitcher-1.2.3-x86-gcc2-2009-05-31.zip
KeymapSwitcher-1.2.4-r1a1-x86-gcc2-2009-09-06
: $(baseURL)/KeymapSwitcher-1.2.4-r1a1-x86-gcc2-2009-09-06.zip
:
;
AddSymlinkToHaikuImage home config be Desktop\ Applets
@ -512,12 +521,12 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded KeymapSwitcher ] {
# LibIconv
if [ IsObsoleteOptionalHaikuImagePackageAdded LibIconv ] {
if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package LibIconv available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage libiconv-1.13.1-x86-gcc2-2009-07-07
: $(baseURL)/libiconv-1.13.1-x86-gcc2-2009-07-07.zip
InstallOptionalHaikuImagePackage libiconv-1.13.1-r1a1-x86-gcc2-2009-09-08
: $(baseURL)/libiconv-1.13.1-r1a1-x86-gcc2-2009-09-08.zip
:
;
}
@ -525,7 +534,7 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded LibIconv ] {
# LibLayout library
if [ IsObsoleteOptionalHaikuImagePackageAdded LibLayout ] {
if [ IsOptionalHaikuImagePackageAdded LibLayout ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package LibLayout available for $(TARGET_ARCH)" ;
} else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) {
@ -540,13 +549,14 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded LibLayout ] {
# LibXML2
if [ IsObsoleteOptionalHaikuImagePackageAdded LibXML2 ] {
if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package LibXML2 available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage libxml2-2.7.3-git-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/libxml2-2.7.3-git-r1a1-x86-gcc2-2009-08-30.zip
InstallOptionalHaikuImagePackage libxml2-2.7.3-r1a1-x86-gcc2-2009-09-08
: $(baseURL)/libxml2-2.7.3-r1a1-x86-gcc2-2009-09-08.zip
:
: true
;
}
}
@ -577,13 +587,14 @@ if [ IsOptionalHaikuImagePackageAdded Mercurial ] {
InstallOptionalHaikuImagePackage mercurial-1.3.1-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/mercurial-1.3.1-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
# Nano
if [ IsObsoleteOptionalHaikuImagePackageAdded Nano ] {
if [ IsOptionalHaikuImagePackageAdded Nano ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Nano available for $(TARGET_ARCH)" ;
} else {
@ -596,13 +607,14 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded Nano ] {
# Neon
if [ IsObsoleteOptionalHaikuImagePackageAdded Neon ] {
if [ IsOptionalHaikuImagePackageAdded Neon ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Neon available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage neon-0.28.6-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/neon-0.28.6-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
@ -640,7 +652,7 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded OpenSound ] {
# OpenSSH
if [ IsObsoleteOptionalHaikuImagePackageAdded OpenSSH ] {
if [ IsOptionalHaikuImagePackageAdded OpenSSH ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package OpenSSH available for $(TARGET_ARCH)" ;
} else {
@ -674,7 +686,7 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded OpenSSL ] {
# P7zip
if [ IsObsoleteOptionalHaikuImagePackageAdded P7zip ] {
if [ IsOptionalHaikuImagePackageAdded P7zip ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package P7zip available for $(TARGET_ARCH)" ;
} else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) {
@ -699,7 +711,7 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded P7zip ] {
# Pe text editor
if [ IsObsoleteOptionalHaikuImagePackageAdded Pe ] {
if [ IsOptionalHaikuImagePackageAdded Pe ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Pe available for $(TARGET_ARCH)" ;
} else {
@ -729,26 +741,28 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded Perl ] {
InstallOptionalHaikuImagePackage perl-5.10.0-gcc2-2008-10-29
: $(baseURL)/perl-5.10.0-gcc2-2008-10-29.zip
:
: true
;
}
}
# Python
if [ IsObsoleteOptionalHaikuImagePackageAdded Python ] {
if [ IsOptionalHaikuImagePackageAdded Python ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Python available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage python-2.6.2-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/python-2.6.2-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
# Rsync
if [ IsObsoleteOptionalHaikuImagePackageAdded Rsync ] {
if [ IsOptionalHaikuImagePackageAdded Rsync ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Rsync available for $(TARGET_ARCH)" ;
} else {
@ -761,27 +775,28 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded Rsync ] {
# SQLite
if [ IsObsoleteOptionalHaikuImagePackageAdded SQLite ] {
if [ IsOptionalHaikuImagePackageAdded SQLite ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package SQLite available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage sqlite-3.6.17-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/sqlite-3.6.17-r1a1-x86-gcc2-2009-08-30.zip
:
: true
;
}
}
# Subversion
if [ IsObsoleteOptionalHaikuImagePackageAdded Subversion ] {
if [ IsOptionalHaikuImagePackageAdded Subversion ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Subversion available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage subversion-1.6.5-r1a1-x86-gcc2-2009-09-02
: $(baseURL)/subversion-1.6.5-r1a1-x86-gcc2-2009-09-02.zip
:
: true
;
}
}
@ -854,7 +869,7 @@ if [ IsOptionalHaikuImagePackageAdded UserlandFS ] {
# Vim
if [ IsObsoleteOptionalHaikuImagePackageAdded Vim ] {
if [ IsOptionalHaikuImagePackageAdded Vim ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Vim available for $(TARGET_ARCH)" ;
} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
@ -865,8 +880,8 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded Vim ] {
AddSymlinkToHaikuImage home config be Applications
: /boot/common/bin/gvim ;
} else {
InstallOptionalHaikuImagePackage vim-7.2-x86-gcc2-2009-05-31
: $(baseURL)/vim-7.2-x86-gcc2-2009-05-31.zip
InstallOptionalHaikuImagePackage vim-7.2-r1a1-x86-gcc2-2009-09-06
: $(baseURL)/vim-7.2-r1a1-x86-gcc2-2009-09-06.zip
:
;
AddSymlinkToHaikuImage home config be Applications
@ -950,13 +965,12 @@ if [ IsObsoleteOptionalHaikuImagePackageAdded WonderBrush ] {
# Yasm
if [ IsObsoleteOptionalHaikuImagePackageAdded Yasm ] {
if [ IsOptionalHaikuImagePackageAdded Yasm ] {
if $(TARGET_ARCH) != x86 {
Echo "No optional package Yasm available for $(TARGET_ARCH)" ;
} else {
InstallOptionalHaikuImagePackage yasm-0.8.0-r1a1-x86-gcc2-2009-08-30
: $(baseURL)/yasm-0.8.0-r1a1-x86-gcc2-2009-08-30.zip
:
;
}

View File

@ -51,7 +51,7 @@ width="64" height="64" />ActivityMonitor</h1>
<p>Below the graphics is a legend (hideable from the context menu). You can change their colors and that of the graph's background via drag&amp;drop from any color picker, e.g. from <span class="app">Icon-O-Matic</span>.</p>
<p>You can add more views from the <span class="menu">File</span> menu if it gets too crowded.</p>
<p>The <span class="menu">Settings</span> menu opens a panel where you can set the update interval.</p>
<p>Each view has it's own Replicator handle and can thus be arranged, for example, on the Desktop.</p>
<p>Each view has it's own <a href="../gui.html#replicants">Replicant</a> handle and can thus be arranged, for example, on the Desktop.</p>
</div>

View File

@ -45,7 +45,7 @@ width="64" height="64" />DeskCalc</h1>
</table>
<p><br/></p>
<p>DeskCalc is a simple calculator that nevertheless has some nice features that aren't apparent on first sight.</p>
<img src="../images/apps-images/deskcalc.png" alt="deskcalc.png" />
<img src="../../images/apps-images/deskcalc.png" alt="deskcalc.png" />
<ul>
<li><p>DeskCalc understands much more than its simple keypad suggests.<br />
Besides the operators <tt>+</tt>, <tt>-</tt>, <tt>*</tt>, <tt>/</tt>, <tt>%</tt>, <tt>^</tt> and the constants <tt>pi</tt> and <tt>e</tt> the following math functions are supported:<br />
@ -60,7 +60,7 @@ Also, be aware that <tt>.</tt> and <tt>,</tt> are both considered floating point
<tr><td><span class="menu">Audio Feedback</span></td><td></td><td>plays a sound when showing a result</td></tr>
<tr><td><span class="menu">Show Keypad</span></td><td></td><td>hides the keypad when deactivated</td></tr>
</table></li>
<li><p>You can resize the calculator until it fits your needs and then put it as Replicant onto the Desktop via drag&amp;drop of the symbol in the bottom right corner. Make sure <span class="menu">Show Replicants</span> is activated in the Deskbar.</p></li>
<li><p>You can resize the calculator until it fits your needs and then put it as <a href="../gui.html#replicants">Replicant</a> onto the Desktop via drag&amp;drop of the symbol in the bottom right corner. Make sure <span class="menu">Show Replicants</span> is activated in the Deskbar.</p></li>
<li><p>The keypad can be colored with a drag&amp;drop from any color well, e.g. from <span class="app">Icon-O-Matic</span>.</p></li>
<li><p>You can move up and down in a history of past calculations with <span class="key"></span><span class="key"></span>.</p></li>
<li><p>You can select DeskCalc's contents and drag&amp;drop it into any application. Or you drop it into a Tracker window or onto the Desktop and a text file with that clipping is created there.</p>

View File

@ -56,7 +56,8 @@
<tr><td valign="top"><a href="gui.html">Haiku's GUI</a><ul>
<li><a href="gui.html#open-save-panel">Open and save panels</a><br />
<a href="gui.html#open-save-shortcuts">- Keyboard shortcuts</a><br />
<a href="gui.html#favorites-recent">- Favorites and recent folders</a></li></ul></td>
<a href="gui.html#favorites-recent">- Favorites and recent folders</a></li>
<li><a href="gui.html#replicants">Replicants</a></li></ul></td>
<td valign="top">Learn about the basic elements of the graphical user interface.</td></tr>
<tr><td valign="top"><a href="workspaces.html">Workspaces</a><ul>
<li><a href="workspaces.html#applet">The Workspaces Applet</a></li>

View File

@ -60,7 +60,7 @@
<li><p><b>About This System...</b> - Shows some basic information of the system, licenses and the credits of the Haiku project.</p></li>
<li><p><b>Find...</b> - Opens the <a href="queries.html">Query</a> dialog.</p></li>
<li><p><b>Show Replicants</b> - Shows/hides the little Replicant widget you use to drag it around, remove or access its context menu.</p></li>
<li><p><b>Show Replicants</b> - Shows/hides the little <a href="gui.html#replicants">Replicant</a> widget you use to drag it around, remove or access its context menu.</p></li>
<li><p><b>Mount</b> - Offers the same options as when invoked by right-clicking the Desktop (see <a href="tracker.html#mounting-volumes">Mounting Volumes</a>).</p></li>
<li><p><b>Deskbar Settings</b></p>
<table summary="layout" border="0" cellpadding="2" cellspacing="0">

View File

@ -84,6 +84,15 @@ You can enter parent folders with the drop-down menu above the file listing.</p>
<p>To add a Favorite, you simply navigate to your destination and choose <span class="menu">Favorites | Add Current Folder</span>. From now on it will appear in every open/save panel. To remove a Favorite, choose <span class="menu">Favorites | Configure Favorites...</span> and delete its entry.<br />
All Favorites are kept in <span class="path">/boot/home/config/settings/Tracker/Go/</span>. So you might as well add and remove links to files and folders there directly.</p>
<h1>
<a href="#logo"><img src="../images/up.png" align="right" alt="index" border="0" class="noprint" /></a>
<a id="replicants" name="replicants">Replicants</a></h1>
<p>Replicants are small self-contained parts of applications that can be integrated into other programs. Provided Deskbar's option to <span class="menu">Show Replicants</span> is activated, you'll recognize a replicantable part of an appliction by its small handle, normally in the bottom right corner:</p>
<img src="../images/gui-images/replicant.png" alt="replicant.png" />
<p>The most prominent place that accepts Replicants is the Desktop: You simply drag&drop the little handle onto it. From now on it's part of the Desktop and the Replicant's originating app doesn't have to be started for it to work.<br />
A right-click on a Replicant handle offers a context menu to show the originating app's <span class="menu">About</span> window and to <span class="menu">Remove Replicant</span>.</p>
<p>Examples for replicatable applications are the graphs of the <a href="applications/activitymonitor.html">ActivityMonitor</a>, the <a href="workspaces.html">Workspaces applet</a> or <a href="applications/deskcalc.html">DeskCalc</a>.</p>
</div>
<div class="bottomnav">

View File

@ -51,7 +51,7 @@
<img src="images/workspaces-images/workspaces.png" alt="workspaces.png" />
<p>You find the Workspaces applet with the other <span class="menu">Desktop Applets</span> in the Deskbar. It shows a miniature version of all workspaces. There are several options available from the context menu of the applet's window, which are all pretty self-explaining.<br />
<span class="menu">Change Workspace Count...</span> will open the <a href="preferences/screen.html">Screen</a> preferences where you set the number of workspaces and their arrangement (how many rows and columns).</p>
<p>Since the applet is a Replicant, you can resize the window as desired and then drag&amp;drop it by its handle onto the desktop (make sure "<span class="menu">Show Replicants</span>" is activated in the Deskbar menu).</p>
<p>Since the applet is a <a href="gui.html#replicants">Replicant</a>, you can resize the window as desired and then drag&amp;drop it by its handle onto the desktop (make sure "<span class="menu">Show Replicants</span>" is activated in the Deskbar menu).</p>
<h2>
<a href="#logo"><img src="../images/up.png" align="right" alt="index" border="0" class="noprint" /></a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

View File

@ -22,63 +22,73 @@ class BString;
namespace BPrivate {
class BCommandPipe {
public:
public:
BCommandPipe();
virtual ~BCommandPipe();
status_t AddArg(const char* argv);
void PrintToStream() const;
// FlushArgs() deletes the commands while Close() explicity closes all
// pending pipe-ends
// Note: Internally FlushArgs() calls Close()
void FlushArgs();
void Close();
// You MUST NOT free/delete the strings in the array, but you MUST free
// just the array itself.
const char** Argv(int32& _argc) const;
// If you use these, you must explicitly call "close" for the parameters
// (outdes/errdes) when you are done with them!
thread_id Pipe(int* outdes, int* errdes) const;
thread_id Pipe(int* outdes) const;
thread_id PipeAll(int* outAndErrDes) const;
// (stdOut/stdErr) when you are done with them!
thread_id Pipe(int* stdOut, int* stdErr) const;
thread_id Pipe(int* stdOut) const;
thread_id PipeAll(int* stdOutAndErr) const;
// If you use these, you need NOT call "fclose" for the parameters
// (out/err) when you are done with them, also you need not do any
// allocation for these FILE* pointers, just use FILE* out = NULL
// and pass &out and so on...
thread_id PipeInto(FILE** _out, FILE** _err);
thread_id PipeInto(FILE** _outAndErr);
// Run() is a synchronous call, and waits till the command has finished
// executing RunAsync() is an asynchronous call that returns immediately
// after launching the command Neither of these bother about redirecting
// pipes for you to use
void Run();
void RunAsync();
// This function reads line-by-line from "file", cancels its reading
// when "*cancel" is true. It reports each line it has read to "target"
// using the supplied "_message" and string field name. "cancel" can be
// NULL
BString ReadLines(FILE* file, bool* cancel,
BMessenger& target, const BMessage& message,
const BString& stringFieldName);
// You need NOT free/delete the return array of strings
const char** Argv(int32& _argc) const;
// Reading the Pipe output
class LineReader {
public:
virtual ~LineReader() {}
virtual bool IsCanceled() = 0;
virtual status_t ReadLine(const BString& line) = 0;
// TODO: Add a Timeout() method.
};
// This function reads line-by-line from "file". It calls IsCanceled()
// on the passed LineReader instance for each byte read from file
// (currently). And it calls ReadLine() for each complete line.
status_t ReadLines(FILE* file, LineReader* lineReader);
// This method can be used to read the entire file into a BString.
BString ReadLines(FILE* file);
// Stardard append operators, if you use pointers to a BCommandPipe,
// you must use *pipe << "command"; and not pipe << "command" (as it
// will not compile that way)
BCommandPipe& operator<<(const char *arg);
BCommandPipe& operator<<(const char* arg);
BCommandPipe& operator<<(const BString& arg);
BCommandPipe& operator<<(const BCommandPipe& arg);
protected:
protected:
BList fArgList;
int fOutDes[2];
int fErrDes[2];
bool fOutDesOpen;
bool fErrDesOpen;
int fStdOut[2];
int fStdErr[2];
bool fStdOutOpen;
bool fStdErrOpen;
};
} // namespace BPrivate

View File

@ -19,54 +19,25 @@
#include <String.h>
#include <SymLink.h>
#include "AutoLocker.h"
#include "InstallerWindow.h"
// TODO: For PACKAGES_DIRECTORY and VAR_DIRECTORY, not so nice...
#include "SemaphoreLocker.h"
#include "ProgressReporter.h"
using std::nothrow;
// SemaphoreLocking
class SemaphoreLocking {
public:
inline bool Lock(sem_id* lockable)
{
return acquire_sem(*lockable) == B_OK;
}
inline void Unlock(sem_id* lockable)
{
release_sem(*lockable);
}
};
// SemaphoreLocker
class SemaphoreLocker : public AutoLocker<sem_id, SemaphoreLocking> {
public:
inline SemaphoreLocker(sem_id semaphore, bool alreadyLocked = false,
bool lockIfNotLocked = true)
:
AutoLocker<sem_id, SemaphoreLocking>(),
fSem(semaphore)
{
SetTo(&fSem, alreadyLocked, lockIfNotLocked);
}
private:
sem_id fSem;
};
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),
@ -78,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);
@ -105,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;
@ -125,12 +98,6 @@ CopyEngine::ResetTargets()
fCurrentTargetFolder = NULL;
fCurrentItem = NULL;
if (fMessage) {
BMessage message(*fMessage);
message.AddString("status", "Collecting copy information.");
fMessenger.SendMessage(&message);
}
}
@ -138,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;
}
@ -146,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);
}
@ -507,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);
}

View File

@ -15,13 +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();
@ -92,7 +91,9 @@ private:
volatile bool fQuitting;
off_t fBytesRead;
uint64 fLastBytesRead;
uint64 fItemsCopied;
uint64 fLastItemsCopied;
bigtime_t fTimeRead;
off_t fBytesWritten;
@ -104,9 +105,8 @@ private:
const char* fCurrentTargetFolder;
const char* fCurrentItem;
BMessenger fMessenger;
BMessage* fMessage;
ProgressReporter* fProgressReporter;
};
#endif // COPY_ENGINE_2_H
#endif // COPY_ENGINE_H

View File

@ -3,12 +3,14 @@ SubDir HAIKU_TOP src apps installer ;
UsePrivateHeaders shared storage tracker ;
SubDirHdrs [ FDirName $(HAIKU_TOP) src kits tracker ] ;
Application Installer :
Application Installer :
CopyEngine.cpp
InstallerApp.cpp
InstallerWindow.cpp
PackageViews.cpp
PartitionMenuItem.cpp
ProgressReporter.cpp
UnzipEngine.cpp
WorkerThread.cpp
: be tracker translation $(TARGET_LIBSTDC++)
: be tracker translation libshared.a $(TARGET_LIBSTDC++)
: Installer.rdef ;

View File

@ -0,0 +1,103 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "ProgressReporter.h"
#include <stdio.h>
ProgressReporter::ProgressReporter(const BMessenger& messenger,
BMessage* message)
:
fStartTime(0),
fBytesToWrite(0),
fBytesWritten(0),
fItemsToWrite(0),
fItemsWritten(0),
fMessenger(messenger),
fMessage(message)
{
}
ProgressReporter::~ProgressReporter()
{
delete fMessage;
}
void
ProgressReporter::Reset()
{
fBytesToWrite = 0;
fBytesWritten = 0;
fItemsToWrite = 0;
fItemsWritten = 0;
if (fMessage) {
BMessage message(*fMessage);
message.AddString("status", "Collecting copy information.");
fMessenger.SendMessage(&message);
}
}
void
ProgressReporter::AddItems(uint64 count, off_t bytes)
{
fBytesToWrite += bytes;
fItemsToWrite += count;
}
void
ProgressReporter::StartTimer()
{
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::ItemsWritten(uint64 items, off_t bytes,
const char* itemName, const char* targetFolder)
{
fItemsWritten += items;
fBytesWritten += bytes;
_UpdateProgress(itemName, targetFolder);
}
void
ProgressReporter::_UpdateProgress(const char* itemName,
const char* targetFolder)
{
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);
}

View File

@ -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 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:
bigtime_t fStartTime;
off_t fBytesToWrite;
off_t fBytesWritten;
uint64 fItemsToWrite;
uint64 fItemsWritten;
BMessenger fMessenger;
BMessage* fMessage;
};
#endif // PROGRESS_REPORTER_H

View File

@ -0,0 +1,41 @@
/*
* Copyright 2008-2009, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef _SEMAPHORE_LOCKER_H
#define _SEMAPHORE_LOCKER_H
#include "AutoLocker.h"
class SemaphoreLocking {
public:
inline bool Lock(sem_id* lockable)
{
return acquire_sem(*lockable) == B_OK;
}
inline void Unlock(sem_id* lockable)
{
release_sem(*lockable);
}
};
class SemaphoreLocker : public AutoLocker<sem_id, SemaphoreLocking> {
public:
inline SemaphoreLocker(sem_id semaphore, bool alreadyLocked = false,
bool lockIfNotLocked = true)
:
AutoLocker<sem_id, SemaphoreLocking>(),
fSem(semaphore)
{
SetTo(&fSem, alreadyLocked, lockIfNotLocked);
}
private:
sem_id fSem;
};
#endif // _SEMAPHORE_LOCKER_H

View File

@ -0,0 +1,355 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "UnzipEngine.h"
#include <new>
#include <stdio.h>
#include <string.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Node.h>
#include <Path.h>
#include <String.h>
#include "CommandPipe.h"
#include "SemaphoreLocker.h"
#include "ProgressReporter.h"
using std::nothrow;
UnzipEngine::UnzipEngine(ProgressReporter* reporter,
sem_id cancelSemaphore)
:
fPackage(""),
fRetrievingListing(false),
fBytesToUncompress(0),
fBytesUncompressed(0),
fLastBytesUncompressed(0),
fItemsToUncompress(0),
fItemsUncompressed(0),
fLastItemsUncompressed(0),
fProgressReporter(reporter),
fCancelSemaphore(cancelSemaphore)
{
}
UnzipEngine::~UnzipEngine()
{
}
status_t
UnzipEngine::SetTo(const char* pathToPackage, const char* destinationFolder)
{
fPackage = pathToPackage;
fDestinationFolder = destinationFolder;
fEntrySizeMap.Clear();
fBytesToUncompress = 0;
fBytesUncompressed = 0;
fLastBytesUncompressed = 0;
fItemsToUncompress = 0;
fItemsUncompressed = 0;
fLastItemsUncompressed = 0;
BPrivate::BCommandPipe commandPipe;
status_t ret = commandPipe.AddArg("unzip");
if (ret == B_OK)
ret = commandPipe.AddArg("-l");
if (ret == B_OK)
ret = commandPipe.AddArg(fPackage.String());
if (ret != B_OK)
return ret;
// Launch the unzip thread and start reading the stdout and stderr output.
FILE* stdOutAndErrPipe = NULL;
thread_id unzipThread = commandPipe.PipeInto(&stdOutAndErrPipe);
if (unzipThread < 0)
return (status_t)unzipThread;
fRetrievingListing = true;
ret = commandPipe.ReadLines(stdOutAndErrPipe, this);
fRetrievingListing = false;
printf("%llu items in %llu bytes\n", fItemsToUncompress,
fBytesToUncompress);
return ret;
}
status_t
UnzipEngine::UnzipPackage()
{
if (fItemsToUncompress == 0)
return B_NO_INIT;
BPrivate::BCommandPipe commandPipe;
status_t ret = commandPipe.AddArg("unzip");
if (ret == B_OK)
ret = commandPipe.AddArg("-o");
if (ret == B_OK)
ret = commandPipe.AddArg(fPackage.String());
if (ret == B_OK)
ret = commandPipe.AddArg("-d");
if (ret == B_OK)
ret = commandPipe.AddArg(fDestinationFolder.String());
if (ret != B_OK) {
fprintf(stderr, "Faild to construct argument list for unzip "
"process: %s\n", strerror(ret));
return ret;
}
// Launch the unzip thread and start reading the stdout and stderr output.
FILE* stdOutAndErrPipe = NULL;
thread_id unzipThread = commandPipe.PipeInto(&stdOutAndErrPipe);
if (unzipThread < 0)
return (status_t)unzipThread;
ret = commandPipe.ReadLines(stdOutAndErrPipe, this);
if (ret != B_OK) {
fprintf(stderr, "Piping the unzip process failed: %s\n",
strerror(ret));
return ret;
}
// Add the contents of a potentially existing .OptionalPackageDescription
// to the COPYRIGHTS attribute of AboutSystem.
BPath descriptionPath(fDestinationFolder.String(),
".OptionalPackageDescription");
ret = descriptionPath.InitCheck();
if (ret != B_OK) {
fprintf(stderr, "Failed to construct path to "
".OptionalPackageDescription: %s\n", strerror(ret));
return ret;
}
BEntry descriptionEntry(descriptionPath.Path());
if (!descriptionEntry.Exists())
return B_OK;
BFile descriptionFile(&descriptionEntry, B_READ_ONLY);
ret = descriptionFile.InitCheck();
if (ret != B_OK) {
fprintf(stderr, "Failed to construct file to "
".OptionalPackageDescription: %s\n", strerror(ret));
return ret;
}
BPath aboutSystemPath(fDestinationFolder.String(),
"system/apps/AboutSystem");
ret = aboutSystemPath.InitCheck();
if (ret != B_OK) {
fprintf(stderr, "Failed to construct path to AboutSystem: %s\n",
strerror(ret));
return ret;
}
BNode aboutSystemNode(aboutSystemPath.Path());
ret = aboutSystemNode.InitCheck();
if (ret != B_OK) {
fprintf(stderr, "Failed to construct node to AboutSystem: %s\n",
strerror(ret));
return ret;
}
const char* kCopyrightsAttrName = "COPYRIGHTS";
BString copyrightAttr;
ret = aboutSystemNode.ReadAttrString(kCopyrightsAttrName, &copyrightAttr);
if (ret != B_OK && ret != B_ENTRY_NOT_FOUND) {
fprintf(stderr, "Failed to read current COPYRIGHTS attribute from "
"AboutSystem: %s\n", strerror(ret));
return ret;
}
// Append the contents of the current optional package description to
// the existing COPYRIGHTS attribute from AboutSystem
size_t bufferSize = 2048;
char buffer[bufferSize + 1];
buffer[bufferSize] = '\0';
while (true) {
ssize_t read = descriptionFile.Read(buffer, bufferSize);
if (read > 0) {
int32 length = copyrightAttr.Length();
if (read < (ssize_t)bufferSize)
buffer[read] = '\0';
int32 bufferLength = strlen(buffer);
// Should be "read", but maybe we have a zero in the
// buffer in which case the next check would be fooled.
copyrightAttr << buffer;
if (copyrightAttr.Length() != length + bufferLength) {
fprintf(stderr, "Failed to append buffer to COPYRIGHTS "
"attribute.\n");
return B_NO_MEMORY;
}
} else
break;
}
if (copyrightAttr[copyrightAttr.Length() - 1] != '\n')
copyrightAttr << '\n\n';
else
copyrightAttr << '\n';
ret = aboutSystemNode.WriteAttrString(kCopyrightsAttrName, &copyrightAttr);
if (ret != B_OK && ret != B_ENTRY_NOT_FOUND) {
fprintf(stderr, "Failed to read current COPYRIGHTS attribute from "
"AboutSystem: %s\n", strerror(ret));
return ret;
}
// Don't leave the .OptionalPackageDescription behind.
descriptionFile.Unset();
descriptionEntry.Remove();
return B_OK;
}
// #pragma mark -
bool
UnzipEngine::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 %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;
}
}
}
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(), 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
UnzipEngine::_UpdateProgress(const char* item, const char* targetFolder)
{
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);
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef UNZIP_ENGINE_H
#define UNZIP_ENGINE_H
#include <stdio.h>
#include <Messenger.h>
#include <String.h>
#include "CommandPipe.h"
#include "HashMap.h"
#include "HashString.h"
class ProgressReporter;
class UnzipEngine : private BCommandPipe::LineReader {
public:
UnzipEngine(ProgressReporter* reporter,
sem_id cancelSemaphore = -1);
virtual ~UnzipEngine();
status_t SetTo(const char* pathToPackage,
const char* destinationFolder);
inline off_t BytesToUncompress() const
{ return fBytesToUncompress; }
inline uint64 ItemsToUncompress() const
{ return fItemsToUncompress; }
status_t UnzipPackage();
private:
// 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;
off_t fLastBytesUncompressed;
uint64 fItemsToUncompress;
uint64 fItemsUncompressed;
uint64 fLastItemsUncompressed;
ProgressReporter* fProgressReporter;
sem_id fCancelSemaphore;
};
#endif // UNZIP_ENGINE_H

View File

@ -27,6 +27,8 @@
#include "InstallerWindow.h"
#include "PackageViews.h"
#include "PartitionMenuItem.h"
#include "ProgressReporter.h"
#include "UnzipEngine.h"
//#define COPY_TRACE
@ -250,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();
@ -390,10 +394,13 @@ 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;
}
// Begin actuall installation
_LaunchInitScript(targetDirectory);
@ -416,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);
@ -436,6 +451,18 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
}
}
// 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<UnzipEngine*>(
unzipEngines.ItemAtFast(i));
if (err == B_OK)
err = engine->UnzipPackage();
delete engine;
}
if (err != B_OK)
goto error;
_LaunchFinishScript(targetDirectory);
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
@ -452,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)
{

View File

@ -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);

View File

@ -4,6 +4,7 @@
*
* Authors:
* Ramshankar, v.ramshankar@gmail.com
* Stephan Aßmus <superstippi@gmx.de>
*/
//! BCommandPipe class to handle reading shell output
@ -20,8 +21,9 @@
BCommandPipe::BCommandPipe()
: fOutDesOpen(false)
, fErrDesOpen(false)
:
fStdOutOpen(false),
fStdErrOpen(false)
{
}
@ -35,8 +37,19 @@ BCommandPipe::~BCommandPipe()
status_t
BCommandPipe::AddArg(const char* arg)
{
return (fArgList.AddItem(reinterpret_cast<void*>(strdup(arg))) == true ?
B_OK : B_ERROR);
if (arg == NULL || arg[0] == '\0')
return B_BAD_VALUE;
char* argCopy = strdup(arg);
if (argCopy == NULL)
return B_NO_MEMORY;
if (!fArgList.AddItem(reinterpret_cast<void*>(argCopy))) {
free(argCopy);
return B_NO_MEMORY;
}
return B_OK;
}
@ -44,7 +57,7 @@ void
BCommandPipe::PrintToStream() const
{
for (int32 i = 0L; i < fArgList.CountItems(); i++)
printf("%s ", (char*)fArgList.ItemAtFast(i));
printf("%s ", reinterpret_cast<char*>(fArgList.ItemAtFast(i)));
printf("\n");
}
@ -54,10 +67,10 @@ void
BCommandPipe::FlushArgs()
{
// Delete all arguments from the list
for (int32 i = 0; i < fArgList.CountItems(); i++)
free(fArgList.RemoveItem(0L));
for (int32 i = fArgList.CountItems() - 1; i >= 0; i--)
free(fArgList.ItemAtFast(i));
fArgList.MakeEmpty();
Close();
}
@ -65,29 +78,29 @@ BCommandPipe::FlushArgs()
void
BCommandPipe::Close()
{
if (fErrDesOpen) {
close(fErrDes[0]);
fErrDesOpen = false;
if (fStdErrOpen) {
close(fStdErr[0]);
fStdErrOpen = false;
}
if (fOutDesOpen) {
close(fOutDes[0]);
fOutDesOpen = false;
if (fStdOutOpen) {
close(fStdOut[0]);
fStdOutOpen = false;
}
}
const char**
BCommandPipe::Argv(int32& _argc) const
BCommandPipe::Argv(int32& argc) const
{
// *** Warning *** Freeing is left to caller!! Indicated in Header
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
// NOTE: Freeing is left to caller as indicated in the header!
argc = fArgList.CountItems();
const char** argv = reinterpret_cast<const char**>(
malloc((argc + 1) * sizeof(char*)));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[i] = reinterpret_cast<const char*>(fArgList.ItemAtFast(i));
argv[argc] = NULL;
_argc = argc;
return argv;
}
@ -96,88 +109,81 @@ BCommandPipe::Argv(int32& _argc) const
thread_id
BCommandPipe::PipeAll(int* outAndErrDes) const
BCommandPipe::PipeAll(int* stdOutAndErr) const
{
// This function pipes both stdout and stderr to the same filedescriptor
// (outdes)
int oldstdout;
int oldstderr;
pipe(outAndErrDes);
oldstdout = dup(STDOUT_FILENO);
oldstderr = dup(STDERR_FILENO);
// (stdOut)
int oldStdOut;
int oldStdErr;
pipe(stdOutAndErr);
oldStdOut = dup(STDOUT_FILENO);
oldStdErr = dup(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(outAndErrDes[1], STDOUT_FILENO);
dup2(outAndErrDes[1], STDERR_FILENO);
// TODO: This looks broken, using "stdOutAndErr[1]" twice!
dup2(stdOutAndErr[1], STDOUT_FILENO);
dup2(stdOutAndErr[1], STDERR_FILENO);
// Construct the argv vector
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[argc] = NULL;
int32 argc;
const char** argv = Argv(argc);
// Load the app image... and pass the args
thread_id appThread = load_image((int)argc, argv, const_cast<
const char**>(environ));
thread_id appThread = load_image((int)argc, argv,
const_cast<const char**>(environ));
dup2(oldstdout, STDOUT_FILENO);
dup2(oldstderr, STDERR_FILENO);
close(oldstdout);
close(oldstderr);
dup2(oldStdOut, STDOUT_FILENO);
dup2(oldStdErr, STDERR_FILENO);
close(oldStdOut);
close(oldStdErr);
free(argv);
delete[] argv;
return appThread;
}
thread_id
BCommandPipe::Pipe(int* outdes, int* errdes) const
BCommandPipe::Pipe(int* stdOut, int* stdErr) const
{
int oldstdout;
int oldstderr;
pipe(outdes);
pipe(errdes);
oldstdout = dup(STDOUT_FILENO);
oldstderr = dup(STDERR_FILENO);
int oldStdOut;
int oldStdErr;
pipe(stdOut);
pipe(stdErr);
oldStdOut = dup(STDOUT_FILENO);
oldStdErr = dup(STDERR_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(outdes[1], STDOUT_FILENO);
dup2(errdes[1], STDERR_FILENO);
dup2(stdOut[1], STDOUT_FILENO);
dup2(stdErr[1], STDERR_FILENO);
// Construct the argv vector
int32 argc = fArgList.CountItems();
const char **argv = (const char**)malloc((argc + 1) * sizeof(char*));
for (int32 i = 0; i < argc; i++)
argv[i] = (const char*)fArgList.ItemAtFast(i);
argv[argc] = NULL;
int32 argc;
const char** argv = Argv(argc);
// Load the app image... and pass the args
thread_id appThread = load_image((int)argc, argv, const_cast<
const char**>(environ));
dup2(oldstdout, STDOUT_FILENO);
dup2(oldstderr, STDERR_FILENO);
close(oldstdout);
close(oldstderr);
delete[] argv;
dup2(oldStdOut, STDOUT_FILENO);
dup2(oldStdErr, STDERR_FILENO);
close(oldStdOut);
close(oldStdErr);
free(argv);
return appThread;
}
thread_id
BCommandPipe::Pipe(int* outdes) const
BCommandPipe::Pipe(int* stdOut) const
{
// Redirects only output (stdout) to caller, stderr is closed
int errdes[2];
thread_id tid = Pipe(outdes, errdes);
close(errdes[0]);
close(errdes[1]);
int stdErr[2];
thread_id tid = Pipe(stdOut, stdErr);
close(stdErr[0]);
close(stdErr[1]);
return tid;
}
@ -186,19 +192,20 @@ thread_id
BCommandPipe::PipeInto(FILE** _out, FILE** _err)
{
Close();
thread_id tid = Pipe(fOutDes, fErrDes);
resume_thread(tid);
close(fErrDes[1]);
close(fOutDes[1]);
fOutDesOpen = true;
fErrDesOpen = true;
*_out = fdopen(fOutDes[0], "r");
*_err = fdopen(fErrDes[0], "r");
thread_id tid = Pipe(fStdOut, fStdErr);
if (tid >= 0)
resume_thread(tid);
close(fStdErr[1]);
close(fStdOut[1]);
fStdOutOpen = true;
fStdErrOpen = true;
*_out = fdopen(fStdOut[0], "r");
*_err = fdopen(fStdErr[0], "r");
return tid;
}
@ -207,17 +214,15 @@ thread_id
BCommandPipe::PipeInto(FILE** _outAndErr)
{
Close();
thread_id tid = PipeAll(fOutDes);
if (tid == B_ERROR || tid == B_NO_MEMORY)
return tid;
resume_thread(tid);
close(fOutDes[1]);
fOutDesOpen = true;
*_outAndErr = fdopen(fOutDes[0], "r");
thread_id tid = PipeAll(fStdOut);
if (tid >= 0)
resume_thread(tid);
close(fStdOut[1]);
fStdOutOpen = true;
*_outAndErr = fdopen(fStdOut[0], "r");
return tid;
}
@ -230,14 +235,14 @@ BCommandPipe::Run()
{
// Runs the command without bothering to redirect streams, this is similar
// to system() but uses pipes and wait_for_thread.... Synchronous.
int outdes[2], errdes[2];
int stdOut[2], stdErr[2];
status_t exitCode;
wait_for_thread(Pipe(outdes, errdes), &exitCode);
wait_for_thread(Pipe(stdOut, stdErr), &exitCode);
close(outdes[0]);
close(errdes[0]);
close(outdes[1]);
close(errdes[1]);
close(stdOut[0]);
close(stdErr[0]);
close(stdOut[1]);
close(stdErr[1]);
}
@ -256,69 +261,107 @@ BCommandPipe::RunAsync()
// #pragma mark -
BString
BCommandPipe::ReadLines(FILE* file, bool* cancel, BMessenger& target,
const BMessage& message, const BString& stringFieldName)
status_t
BCommandPipe::ReadLines(FILE* file, LineReader* lineReader)
{
// Reads output of file, line by line. The entire output is returned
// and as each line is being read "target" (if any) is informed,
// with "message" i.e. AddString (stringFieldName, <line read from pipe>)
// "cancel" cancels the reading process, when it becomes true (unless its
// waiting on fgetc()) and I don't know how to cancel the waiting fgetc()
// call.
BString result;
// Reads output of file, line by line. Each line is passed to lineReader
// for inspection, and the IsCanceled() method is repeatedly called.
if (file == NULL || lineReader == NULL)
return B_BAD_VALUE;
BString line;
BMessage updateMsg(message);
while (!feof(file)) {
if (cancel != NULL && *cancel == true)
break;
if (lineReader->IsCanceled())
return B_CANCELED;
unsigned char c = fgetc(file);
if (c != 255) {
// TODO: fgetc() blocks, is there a way to make it timeout?
if (c != 255)
line << (char)c;
result << (char)c;
}
if (c == '\n') {
updateMsg.RemoveName(stringFieldName.String());
updateMsg.AddString(stringFieldName.String(), line);
target.SendMessage(&updateMsg);
status_t ret = lineReader->ReadLine(line);
if (ret != B_OK)
return ret;
line = "";
}
}
return result;
return B_OK;
}
BCommandPipe&
BCommandPipe::operator<<(const char* _arg)
BString
BCommandPipe::ReadLines(FILE* file)
{
AddArg(_arg);
class AllLinesReader : public LineReader {
public:
AllLinesReader()
:
fResult("")
{
}
virtual bool IsCanceled()
{
return false;
}
virtual status_t ReadLine(const BString& line)
{
int lineLength = line.Length();
int resultLength = fResult.Length();
fResult << line;
if (fResult.Length() != lineLength + resultLength)
return B_NO_MEMORY;
return B_OK;
}
BString Result() const
{
return fResult;
}
private:
BString fResult;
} lineReader;
ReadLines(file, &lineReader);
return lineReader.Result();
}
// #pragma mark -
BCommandPipe&
BCommandPipe::operator<<(const char* arg)
{
AddArg(arg);
return *this;
}
BCommandPipe&
BCommandPipe::operator<<(const BString& _arg)
BCommandPipe::operator<<(const BString& arg)
{
AddArg(_arg.String());
AddArg(arg.String());
return *this;
}
BCommandPipe&
BCommandPipe::operator<<(const BCommandPipe& _arg)
BCommandPipe::operator<<(const BCommandPipe& arg)
{
int32 argc;
const char** argv = _arg.Argv(argc);
const char** argv = arg.Argv(argc);
for (int32 i = 0; i < argc; i++)
AddArg(argv[i]);
return *this;
}