* Recursive dependencies are now correctly handled, so Subversion and BeHappy

should now be able to be installed gracefully. This fixes ticket #5248.
* Enhancement of the -a parameter, so that it accepts multiple packages at once.
  Multiple packages have to be included in double quotes, due to the way getopts
  handles options. This fixes ticket #5315.
* Thanks mmadia for this patch!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35327 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Colin Günther
2010-01-28 11:25:25 +00:00
parent e054bfbf08
commit 8a249cd5ad
+291 -262
View File
@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/bash
# #
# Copyright (c) 2009 Haiku Inc. All rights reserved. # Copyright (c) 2009-2010 Haiku Inc. All rights reserved.
# Distributed under the terms of the MIT License. # Distributed under the terms of the MIT License.
# #
# Authors: # Authors:
@@ -20,17 +20,17 @@
# http://dev.haiku-os.org/wiki/PackageManagerIdeas # http://dev.haiku-os.org/wiki/PackageManagerIdeas
# http://dev.haiku-os.org/wiki/PackageFormat # http://dev.haiku-os.org/wiki/PackageFormat
# #
# Usage: ./installoptionalpackage [-l] [-a] # Usage: ./installoptionalpackage [-l] [-a "<pkg> [<pkg> ...]"]
# -l List installable packages # -l List installable packages
# -a Add a package and all of its dependencies # -a Add one or more packages and all dependencies
declare -a packagesToInstall declare -A availablePackages
declare -a availablePackages declare availablePackagesKeys=""
# Some Packages cannot be installed, # Some Packages cannot be installed,
# as they require either the source code or compiled binaries # as they require either the source code or compiled binaries
declare -a packageIgnoreList=( 'Bluetooth' 'Development' 'DevelopmentMin' \ declare packageIgnoreList='Bluetooth Development DevelopmentMin \
'DevelopmentBase' 'NetFS' 'P7zip' 'UserlandFS' 'Welcome') DevelopmentBase P7zip UserlandFS Welcome Wifi-ipw2100+fw Wifi-iprowifi2200+fw'
function CreateInstallerScript() function CreateInstallerScript()
@@ -40,7 +40,7 @@ function CreateInstallerScript()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cat << EOF > ${tmpDir}/install-optpkg.sh cat << EOF > ${tmpDir}/install-optpkg.sh
#!/bin/sh #!/bin/bash
tmpDir=${tmpDir} tmpDir=${tmpDir}
HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]} HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]}
@@ -143,8 +143,8 @@ function InstallOptionalHaikuImagePackage()
done done
echo "Unzipping \$zipFile ..." echo "Unzipping \$zipFile ..."
unzipDir="\${dirTokens}" unzipDir="\${dirTokens}"
unzip -q -d "\$unzipDir" "\$zipFile" unzip -q -o -d "\$unzipDir" "\$zipFile"
# TODO should .OptionalPackageDescription be added to AboutSystem?
if [ -f '/boot/.OptionalPackageDescription' ] ; then if [ -f '/boot/.OptionalPackageDescription' ] ; then
rm '/boot/.OptionalPackageDescription' rm '/boot/.OptionalPackageDescription'
fi fi
@@ -170,7 +170,9 @@ function AddSymlinkToHaikuImage()
local linkName="\${functionArgs[2]}" local linkName="\${functionArgs[2]}"
TrimLeadingSpace linkName TrimLeadingSpace linkName
TrimEndingSpace linkName TrimEndingSpace linkName
mkdir -p "${dirTokens}"
if [ "\${linkName}" == '' ] ; then if [ "\${linkName}" == '' ] ; then
ln -sf "\${linkTarget}" -t "\${dirTokens}" ln -sf "\${linkTarget}" -t "\${dirTokens}"
else else
@@ -225,218 +227,230 @@ EOF
} }
function ContainsSubstring()
{
# ContainsSubstring <stringToLookIn> <stringToLookFor>
local string="$1"
local substring="$2"
local newString=${string/${substring}/''}
if [ ${#string} -eq `expr ${#newString} + ${#substring}` ] ; then
return 0
fi
return 1
}
function Init()
{
# Set up some directory paths
baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages
tmpDir=`finddir B_COMMON_TEMP_DIRECTORY`
libDir=`finddir B_SYSTEM_LIB_DIRECTORY`
# Make sure these files are empty.
echo "" > ${tmpDir}/optpkg.jam
echo "" > ${tmpDir}/optpkg.stage1
if ! [ -d ${baseDir} ] ; then
mkdir -p ${baseDir}
fi
# Retreive the necessary jam files from svn.
local buildFiles="OptionalPackages OptionalPackageDependencies \
OptionalBuildFeatures"
for file in ${buildFiles} ; do
GetBuildFile ${file}
done
DetectSystemConfiguration
ReadPackageNamesIntoMemory
}
function GetBuildFile() function GetBuildFile()
{ {
# GetBuildFile <file> # GetBuildFile <file>
# Downloads files from Haiku's svn # Downloads files from Haiku's svn
if ! [ -f ${baseDir}/${1} ] ; then local buildfile="$1"
echo "Fetching ${1} ..." if ! [ -f ${baseDir}/${buildfile} ] ; then
echo "Fetching ${buildfile} ..."
cd ${baseDir} cd ${baseDir}
local baseURL=http://dev.haiku-os.org/export/ local baseURL=http://dev.haiku-os.org/export/
local revision=`uname -v | awk '{print $1}' | sed -e 's/r//'` local revision=`uname -v | awk '{print $1}' | sed -e 's/r//'`
wget ${baseURL}${revision}/haiku/trunk/build/jam/${file} 2>&1 > /dev/null local url="${baseURL}${revision}/haiku/trunk/build/jam/${buildfile}"
wget -nv ${url} 2>&1 > /dev/null
fi fi
} }
function DetectSystemConfiguration()
{
# Determine which GCC we're running and if we're a hybrid
if [ -d "$libDir"/gcc4 ] ; then
HAIKU_GCC_VERSION[1]=2
isHybridBuild=1
elif [ -d "$libDir"/gcc2 ] ; then
HAIKU_GCC_VERSION[1]=4
isHybridBuild=1
elif [ -f "$libDir"/libsupc++.so ] ; then
HAIKU_GCC_VERSION[1]=4
isHybridBuild=0
else
HAIKU_GCC_VERSION[1]=2
isHybridBuild=0
fi
# Determine the Architecture.
if [ `uname -m` == "BePC" ] ; then
TARGET_ARCH='x86'
fi
}
function ReadPackageNamesIntoMemory()
{
local file="${baseDir}/OptionalPackageNames"
if ! [ -f ${file} ] ; then
GeneratePackageNames
fi
# read list into associative array
while read line ; do
local pkg=`echo ${line} | awk '{print $1}'`
local pkgDeps=${line/':'/}
availablePackages[${pkg}]="${pkgDeps}"
availablePackagesKeys="${availablePackagesKeys} ${pkg}"
done < ${file}
}
function GeneratePackageNames() function GeneratePackageNames()
{ {
# GeneratePackageNames # GeneratePackageNames
# Creates a file containing available package names # Creates a file containing available package names
local outfile="${baseDir}/OptionalPackageNames" # Each line shows a pakage and all of its recrusive dependencies
# "<pkg> : <dep1> <dep2> ..."
echo "Generating a list of Package Names ..."
if ! [ -f ${outfile} ] ; then local file="${baseDir}/OptionalPackageNames"
echo "Generating a list of Package Names ..." touch ${file}
touch ${outfile}
local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p'
sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${outfile}.temp
while read line ; do
local pkg=`echo ${line} | awk '{print $4}'`
if ! IspackageIgnoreListed ${pkg} ; then
echo ${pkg} >> ${outfile}
fi
done < ${outfile}.temp
rm ${outfile}.temp
fi
# read list into array local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p'
local count=0 sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${file}.temp
while read line ; do while read line ; do
availablePackages[$count]=$line # in each non-filtered line, the 4th word is the optional package
((count++)) local pkg=`echo ${line} | awk '{print $4}'`
done < ${outfile}
nonRepeatingDeps=""
GetPackageDependencies "$pkg"
if IsPackageAndDepsOkToInstall ${pkg} ; then
echo "${pkg} : ${nonRepeatingDeps}" >> ${file}
fi
done < ${file}.temp
rm ${file}.temp
} }
function IspackageIgnoreListed() function GetPackageDependencies()
{ {
# IspackageIgnoreListed <pkg> # GetPackageDependencies <pkg>
# Check if this package or any of its deps cannot be installed
GetPackageDependencies ${1} # parse OptionalPackageDependencies for the single line that defines
# this optional package's dependencies.
local regExp="^OptionalPackageDependencies\ ${1}\ \:"
local inputFile="${baseDir}/OptionalPackageDependencies"
local mustIgnore=1 # print that single line
for ignoreThisPackage in ${packageIgnoreList[*]} ; do sed -n -e "/${regExp}\ /p" ${inputFile} > ${tmpDir}/optpkg.temp
if [ ${1} == ${ignoreThisPackage} ] ; then
mustIgnore=0 # strip out "OptionalPackageDependencies PackageName :"
break # this leaves "<dep1> .... ;"
else tempDeps=`sed -e "s/${regExp}\ //" ${tmpDir}/optpkg.temp`
for dep in ${tempDeps} ; do
if [ ${dep} == ${ignoreThisPackage} ] ; then for foo in ${tempDeps%' ;'} ; do
mustIgnore=0 # Prevent duplicate entries of the same dependency package.
break if ! ContainsSubstring "${nonRepeatingDeps} " "${foo} " ; then
fi nonRepeatingDeps="$foo $nonRepeatingDeps "
done nonRepeatingDeps="${nonRepeatingDeps// / }"
fi
done
# Recursively get the dependencies of these dependencies.
for dep in ${tempDeps%' ;'} ; do
GetPackageDependencies "$dep"
done
}
function IsPackageAndDepsOkToInstall()
{
# IsPackageAndDepsOkToInstall <pkg>
if ContainsSubstring "${packageIgnoreList}" "${1}"; then
echo "...warning: ${1} cannot be installed"
return 1
fi
for foo in ${nonRepeatingDeps} ; do
if ContainsSubstring "${packageIgnoreList}" "${foo}"; then
echo "...warning: ${1} cannot be installed because of ${foo}"
return 1
fi fi
done done
return $mustIgnore return 0
}
function AddPackage()
{
# AddPackage <name>
packagesToInstall=""
proceedWithInstallation=false
for desiredPackage in ${1}; do
if IsPackageNameValid $desiredPackage ; then
for item in ${availablePackages[${desiredPackage}]} ; do
if ! ContainsSubstring "${packagesToInstall}" "${item}" ; then
packagesToInstall="${packagesToInstall} ${item}"
fi
done
proceedWithInstallation=true
fi
done
# If one or more packages can be installed, do it.
if $proceedWithInstallation ; then
echo "To be installed: ${packagesToInstall}"
for package in ${packagesToInstall} ; do
# output the "if [ IsOptionalHaikuImagePackageAdded..." code block
local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}"
local inputFile="${baseDir}/OptionalPackages"
sed -n "/^$regExp/,/^\}/p" ${inputFile} >> ${tmpDir}/optpkg.jam
done
ConvertJamToBash "${tmpDir}/optpkg.jam"
rm "${tmpDir}/optpkg.jam"
CreateInstallerScript
sh ${tmpDir}/install-optpkg.sh
rm ${tmpDir}/install-optpkg.sh
fi
} }
function IsPackageNameValid() function IsPackageNameValid()
{ {
# IsPackageNameValid <name> # IsPackageNameValid <name>
if IspackageIgnoreListed "$1" ; then for name in ${availablePackagesKeys} ; do
echo "Due to limitations, the package \"$1\" cannot be installed."
exit 1
fi
local packageExists=1
for name in ${availablePackages[*]} ; do
if [ "$1" == "$name" ] ; then if [ "$1" == "$name" ] ; then
packageExists=0
packagesToInstall[0]=${1}
GetPackageDependencies "$1"
# move deps into packagesToInstall
if [ ${#tempDeps} -gt 0 ] ; then
for dep in ${tempDeps} ; do
if [ ';' == "$dep" ] ; then
break
fi
gPDi=${#packagesToInstall[@]}
((gPDi++))
packagesToInstall[$gPDi]=${dep}
GetPackageDependencies ${dep}
done
fi
echo "Packages to be installed:"
echo " ${packagesToInstall[*]}"
return 0 return 0
fi fi
done done
if [ $packageExists -gt 0 ] ; then
echo "Package \"$1\" does not exist."
echo ''
exit 1
fi
return 1 return 1
} }
function GetPackageDependencies()
{
# getPackageDependecies <pkg>
# parse OptionalPackageDependencies for <pkg>'s dependencies
local regExp="^OptionalPackageDependencies\ ${1}"
local inputFile="${baseDir}/OptionalPackageDependencies"
sed -n -e "/${regExp}\ /p" ${inputFile} > ${tmpDir}/optpkg.temp
tempDeps=`sed -e "s/${regExp}\ :\ //" ${tmpDir}/optpkg.temp`
rm ${tmpDir}/optpkg.temp
}
function ContainsSubstring()
{
# ContainsSubstring <stringToLookIn> <stringToLookFor>
local newString=${1/${2}/''}
if [ ${#1} -eq `expr ${#newString} + ${#2}` ] ; then
return 0
fi
return 1
}
function ReplaceComparators()
{
# ReplaceComparators <line>
# One of the Jam-to-Bash conversion functions.
# Preserve string comparators for TARGET_ARCH.
if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then
line=${line//'>='/'-ge'}
line=${line//'<='/'-le'}
line=${line//'>'/'-gt'}
line=${line//'<'/'-lt'}
line=${line//'!='/'-ne'}
fi
}
function ConvertVariables()
{
# ConvertVariables
# One of the Jam-to-Bash conversion functions.
# NOTE: jam's variables are normally '$(VARIABLE)'. \n
# The issue is with '(' and ')', so let's replace them globally.
if ContainsSubstring "$line" '$(' ; then
line=${line//'('/'{'}
line=${line//')'/'}'}
fi
}
function ConvertVariableDeclarationLines()
{
# ConvertVariableDeclarationLines <regex> <variable>
# One of the Jam-to-Bash conversion functions.
# Jam lines that define variables need to be parsed differently.
eval local input='$'"$2"
local regex="$1"
local _outvar="$2"
input=${input/\ =\ /=}
input=${input/\;/''}
input=${input//\(/'{'}
input=${input//\)/'}'}
eval $_outvar="'$input'"
}
function ConvertIfStatements()
{
# ConvertIfStatements <line>
# One of the Jam-to-Bash conversion functions.
line=${line//'} else {'/'else '}
line=${line//'} else if '/'elif '}
if ContainsSubstring "$line" "if " ; then
if ! ContainsSubstring "$line" "if [" ; then
line=${line/'if '/'if [ '}
fi
if ContainsSubstring "$line" '] {' ; then
line=${line/'{'/' ; then'}
elif ContainsSubstring "$line" '{' ; then
line=${line/'{'/' ] ; then'}
fi
for compound in '&&' '||' ; do
if ContainsSubstring "$line" "$compound" ; then
line=${line/"$compound"/"] $compound ["}
fi
done
fi
# Assume all remaining closing braces are part of if statements
line=${line/'}'/'fi'}
}
function ConvertJamToBash() function ConvertJamToBash()
{ {
# ConvertJamToBash <input file> # ConvertJamToBash <input file>
@@ -513,100 +527,115 @@ function ConvertJamToBash()
} }
function ListPackages() function ConvertVariableDeclarationLines()
{ {
# ListPackages # ConvertVariableDeclarationLines <regex> <variable>
echo "Available Optional Packages:" # One of the Jam-to-Bash conversion functions.
for package in ${availablePackages[*]} ; do # Jam lines that define variables need to be parsed differently.
echo ${package} eval local input='$'"$2"
done local regex="$1"
local _outvar="$2"
input=${input/\ =\ /=}
input=${input/\;/''}
input=${input//\(/'{'}
input=${input//\)/'}'}
eval $_outvar="'$input'"
} }
function AddPackage() function ConvertIfStatements()
{ {
# AddPackage <name> # ConvertIfStatements <line>
if IsPackageNameValid $1 ; then # One of the Jam-to-Bash conversion functions.
for package in ${packagesToInstall[*]} ; do line=${line//'} else {'/'else '}
local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}" line=${line//'} else if '/'elif '}
local inputFile="${baseDir}/OptionalPackages" if ContainsSubstring "$line" "if " ; then
sed -n "/^$regExp/,/^\}/p" ${inputFile} >> ${tmpDir}/optpkg.jam if ! ContainsSubstring "$line" "if [" ; then
line=${line/'if '/'if [ '}
fi
if ContainsSubstring "$line" '] {' ; then
line=${line/'{'/' ; then'}
elif ContainsSubstring "$line" '{' ; then
line=${line/'{'/' ] ; then'}
fi
for compound in '&&' '||' ; do
if ContainsSubstring "$line" "$compound" ; then
line=${line/"$compound"/"] $compound ["}
fi
done done
ConvertJamToBash "${tmpDir}/optpkg.jam" fi
rm "${tmpDir}/optpkg.jam" # Assume all remaining closing braces are part of if statements
CreateInstallerScript line=${line/'}'/'fi'}
sh ${tmpDir}/install-optpkg.sh }
rm ${tmpDir}/install-optpkg.sh
function ConvertVariables()
{
# ConvertVariables
# One of the Jam-to-Bash conversion functions.
# NOTE: jam's variables are normally '$(VARIABLE)'. \n
# The issue is with '(' and ')', so let's replace them globally.
if ContainsSubstring "$line" '$(' ; then
line=${line//'('/'{'}
line=${line//')'/'}'}
fi
}
function ReplaceComparators()
{
# ReplaceComparators <line>
# One of the Jam-to-Bash conversion functions.
# Preserve string comparators for TARGET_ARCH.
if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then
line=${line//'>='/'-ge'}
line=${line//'<='/'-le'}
line=${line//'>'/'-gt'}
line=${line//'<'/'-lt'}
line=${line//'!='/'-ne'}
fi fi
} }
function DisplayUsage() function DisplayUsage()
{ {
echo '' cat << EOF
echo 'Disclaimer:'
echo ' This is a temporary solution for installing OptionalPackages.' Disclaimer:
echo ' In time, there will be an official package manager.' This is a temporary solution for installing OptionalPackages.
echo " See these URL's for info on the in-development package manager." In time, there will be an official package manager.
echo ' http://dev.haiku-os.org/wiki/PackageManagerIdeas' See these URL's for information on the in-development package manager.
echo ' http://dev.haiku-os.org/wiki/PackageFormat' http://dev.haiku-os.org/wiki/PackageManagerIdeas
echo '' http://dev.haiku-os.org/wiki/PackageFormat
echo "Usage: $0 [-l] [-a]"
echo "-l List installable packages" Usage: ./installoptionalpackage [-l] [-a "<pkg> [<pkg> ...]"]
echo "-a Add a package and all of its dependencies" -l List installable packages
echo '' -a Add one or more packages and all dependencies
EOF
} }
function DetectSystemConfiguration() function ListPackages()
{
# Determine which GCC we're running and if we're a hybrid
if [ -d "$libDir"/gcc4 ] ; then
HAIKU_GCC_VERSION[1]=2
isHybridBuild=1
elif [ -d "$libDir"/gcc2 ] ; then
HAIKU_GCC_VERSION[1]=4
isHybridBuild=1
elif [ -f "$libDir"/libsupc++.so ] ; then
HAIKU_GCC_VERSION[1]=4
isHybridBuild=0
else
HAIKU_GCC_VERSION[1]=2
isHybridBuild=0
fi
# Determine the Architecture.
if [ `uname -m` == "BePC" ] ; then
TARGET_ARCH='x86'
fi
}
function Init()
{ {
# ListPackages
echo ""
echo ""
echo "Available Optional Packages:"
# Set up some directory paths # single line:
baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages echo ${availablePackagesKeys}
tmpDir=`finddir B_COMMON_TEMP_DIRECTORY`
libDir=`finddir B_SYSTEM_LIB_DIRECTORY`
# Make sure these files are empty.
echo "" > ${tmpDir}/optpkg.jam
echo "" > ${tmpDir}/optpkg.stage1
# one per line:
if ! [ -d ${baseDir} ] ; then #for package in ${availablePackagesKeys} ; do
mkdir -p ${baseDir} # echo ${package}
fi #done
# Retreive the necessary jam files from svn.
local buildFiles=( 'OptionalPackages' 'OptionalPackageDependencies' \
'OptionalBuildFeatures')
for file in ${buildFiles[*]} ; do
GetBuildFile ${file}
done
DetectSystemConfiguration
GeneratePackageNames
} }
@@ -622,7 +651,7 @@ fi
while getopts "a:lh" opt; do while getopts "a:lh" opt; do
case $opt in case $opt in
a) a)
AddPackage $OPTARG AddPackage "$OPTARG"
exit 0 exit 0
;; ;;
h) h)