mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 07:18:40 +01:00
* 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:
parent
db6309f854
commit
85d74e5f59
@ -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
|
||||
|
@ -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
|
||||
|
||||
:
|
||||
;
|
||||
}
|
||||
|
@ -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&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>
|
||||
|
||||
|
@ -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&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&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&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&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>
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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&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&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>
|
||||
|
BIN
docs/userguide/images/gui-images/replicant.png
Normal file
BIN
docs/userguide/images/gui-images/replicant.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 602 B |
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ;
|
||||
|
103
src/apps/installer/ProgressReporter.cpp
Normal file
103
src/apps/installer/ProgressReporter.cpp
Normal 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);
|
||||
}
|
48
src/apps/installer/ProgressReporter.h
Normal file
48
src/apps/installer/ProgressReporter.h
Normal 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
|
41
src/apps/installer/SemaphoreLocker.h
Normal file
41
src/apps/installer/SemaphoreLocker.h
Normal 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
|
355
src/apps/installer/UnzipEngine.cpp
Normal file
355
src/apps/installer/UnzipEngine.cpp
Normal 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, ©rightAttr);
|
||||
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, ©rightAttr);
|
||||
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);
|
||||
}
|
70
src/apps/installer/UnzipEngine.h
Normal file
70
src/apps/installer/UnzipEngine.h
Normal 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
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user