Ticket #4680: installoptionalpackage.patch

File installoptionalpackage.patch, 16.0 KB (added by mmadia, 14 years ago)

adds script to HAIKU_TOP data bin, installs to system bin

  • build/jam/HaikuImage

     
    292292
    293293SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ;
    294294AddFilesToHaikuImage system bin         : which ;
     295SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ;
     296AddFilesToHaikuImage system bin         : installoptionalpackage ;
    295297
    296298AddSymlinkToHaikuImage system bin : bash : sh ;
    297299AddSymlinkToHaikuImage system bin : trash : untrash ;
  • data/bin/installoptionalpackage

     
     1#!/bin/sh
     2#
     3# Copyright (c) 2009 Haiku Inc. All rights reserved.
     4# Distributed under the terms of the MIT License.
     5#
     6# Authors:
     7#       Matt Madia, mattmadia@gmail.com
     8#
     9# Synopsis:
     10#   Provides a controlled mechanism for end-users to install certain pre-built
     11#   OptionalPackages. The script will determine the host information: the
     12#   default GCC, availability of secondary GCC libs, and revision. Using this
     13#   information, the user will be limited to the appropriate OptionalPackages
     14#   that were available for that specific revision.
     15#
     16# Disclaimer:
     17#   This is a temporary solution for installing OptionalPackages.
     18#   In time, there will be an official package manager.
     19#   See these URL's for info on the in-development package manager.
     20#     http://dev.haiku-os.org/wiki/PackageManagerIdeas
     21#     http://dev.haiku-os.org/wiki/PackageFormat
     22#
     23# Usage: ./installoptionalpackage [-l] [-a]
     24# -l      List installable packages
     25# -a      Add a package and all of its dependencies
     26
     27
     28declare -a packagesToInstall   
     29declare -a availablePackages
     30# Some Packages cannot be installed,
     31# as they require either the source code or compiled binaries
     32declare -a packageIgnoreList=( 'Bluetooth' 'Development' 'DevelopmentMin' \
     33    'DevelopmentBase' 'P7zip' 'UserlandFS' 'Welcome')
     34
     35
     36function CreateInstallerScript()
     37{
     38    # This function will create a secondary script, containing all of the
     39    # information needed to install the optional package and its dependencies
     40
     41#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     42    cat << EOF > ${tmpDir}/install-optpkg.sh
     43#!/bin/sh
     44
     45tmpDir=${tmpDir}
     46HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]}
     47isHybridBuild=${isHybridBuild}
     48TARGET_ARCH=${TARGET_ARCH}
     49HAIKU_IMAGE_HOST_NAME=`uname -n`
     50$urlLine
     51$sslPkgLine
     52$sslUrlLine
     53declare -a functionArgs
     54
     55
     56function ParseFunctionArguments()
     57{
     58    # ParseFunctionArguments <args>
     59    # Parse arguments for Jam wrapper functions into an array.
     60    IN="\$@"
     61    OIFS=\$IFS
     62    IFS=":"
     63   
     64    local count=0
     65    functionArgs=( )
     66    for x in \$IN
     67    do
     68        functionArgs[\${count}]="\${x}"
     69        ((count++))
     70    done
     71    IFS=\$OIFS
     72}
     73
     74
     75function TrimLeadingSpace()
     76{
     77    # TrimLeadingSpace <variable name>
     78    eval local text='\$'"\$1"
     79    local _outvar="\$1"
     80
     81    local length=\${#text}
     82    ((length--))
     83    if [ "\${text:0:1}" == ' ' ] ; then
     84        text=\${text#' '}
     85    fi
     86
     87    eval \$_outvar="'\$text'"
     88}
     89
     90
     91function TrimEndingSpace()
     92{
     93    # TrimEndingSpace <variable name>
     94    eval local text='\$'"\$1"
     95    local _outvar="\$1"
     96
     97    local length=\${#text}
     98    ((length--))
     99    if [ "\${text:\$length}" == ' ' ] ; then
     100        text=\${text%' '}
     101    fi
     102
     103    eval \$_outvar="'\$text'"
     104}
     105
     106
     107function Exit()
     108{
     109    # Exit <message>
     110    # Wrapper for Jam rule
     111    echo "\$@"
     112    exit 1
     113}
     114
     115
     116function InstallOptionalHaikuImagePackage()
     117{
     118    # InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage
     119    # Wrapper for Jam rule
     120    echo "Installing \$1 ..."
     121    cd \$tmpDir
     122   
     123    zipFile=\`echo \$3 | sed -s "s/http.*\///"\`
     124    if ! [ -f \$zipFile ] ; then
     125        echo "Downloading \$3 ..."
     126        wget -nv \$3
     127    fi
     128   
     129    local dirTokens='/boot'
     130    local count=4
     131    local i=0
     132    for possibleToken in "\$@" ; do
     133        if [ \$i -lt \$count ] ; then
     134            ((i++))
     135        else
     136            ((i++))
     137            if [ "\$possibleToken" != ':' ] ; then         
     138                dirTokens=\${dirTokens}/\$possibleToken
     139            else
     140                break
     141            fi
     142        fi
     143    done
     144    echo "Unzipping \$zipFile ..."
     145    unzipDir="\${dirTokens}"
     146    unzip -q -d "\$unzipDir" "\$zipFile"
     147    # TODO should .OptionalPackageDescription be added to AboutSystem?
     148    if [ -f '/boot/.OptionalPackageDescription' ] ; then
     149        rm '/boot/.OptionalPackageDescription'
     150    fi
     151    rm "\$zipFile"
     152}
     153
     154
     155function AddSymlinkToHaikuImage()
     156{
     157    # AddSymlinkToHaikuImage <dir tokens> : <link target> [ : <link name> ]
     158    # Wrapper for Jam rule
     159    ParseFunctionArguments "\$@"
     160   
     161    local dirTokens="/boot/\${functionArgs[0]}"
     162    TrimLeadingSpace dirTokens
     163    TrimEndingSpace dirTokens
     164    dirTokens=\${dirTokens//' '/\/}
     165   
     166    local linkTarget="\${functionArgs[1]}"
     167    TrimLeadingSpace linkTarget
     168    TrimEndingSpace linkTarget
     169   
     170    local linkName="\${functionArgs[2]}"
     171    TrimLeadingSpace linkName
     172    TrimEndingSpace linkName
     173           
     174    if [ "\${linkName}" == '' ] ; then
     175        ln -sf "\${linkTarget}" -t "\${dirTokens}"
     176    else
     177        ln -sf "\${linkTarget}" "\${dirTokens}/\${linkName}"
     178    fi
     179}
     180
     181
     182function AddUserToHaikuImage()
     183{
     184    # AddUserToHaikuImage user : uid : gid : home : shell : realName
     185    # Wrapper for Jam rule 
     186    ParseFunctionArguments "\$@"
     187   
     188    local user=\${functionArgs[0]}
     189    local uid=\${functionArgs[1]}
     190    local gid=\${functionArgs[2]}
     191    local home=\${functionArgs[3]}
     192    local shell=\${functionArgs[4]}
     193    local realName=\${functionArgs[5]}
     194   
     195    passwdLine="\${user}:x:\${uid}:\${gid}:\${realName}:\${home}:\${shell}"
     196    passwdLine=\${passwdLine//' :'/':'}
     197    passwdLine=\${passwdLine//': '/':'}
     198   
     199    local length=\${#passwdLine}
     200    ((length--))
     201    if [ "\${passwdLine:\$length}" == ' ' ] ; then
     202        passwdLine=\${passwdLine%' '}
     203    fi
     204   
     205    passwdFile="\`finddir B_COMMON_ETC_DIRECTORY\`/passwd"
     206    touch \${passwdFile}
     207   
     208    local userExists=1
     209    while read line ; do
     210        if [ "\${passwdLine}" == "\${line}" ] ; then
     211            userExists=0
     212        fi
     213    done < \${passwdFile}
     214   
     215    if [ \$userExists -ge 1 ] ; then
     216        echo "\${passwdLine}" >> \${passwdFile}
     217    fi
     218}
     219
     220
     221EOF
     222#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     223    cat ${tmpDir}/optpkg.stage2 >> ${tmpDir}/install-optpkg.sh
     224    rm ${tmpDir}/optpkg.stage2
     225}
     226
     227
     228function GetBuildFile()
     229{
     230    # GetBuildFile <file>
     231    # Downloads files from Haiku's svn
     232    if ! [ -f ${baseDir}/${1} ] ; then
     233        echo "Fetching ${1} ..."
     234        cd ${baseDir}
     235        local baseURL=http://dev.haiku-os.org/export/
     236        local revision=`uname -v | awk '{print $1}' | sed -e 's/r//'`
     237        wget ${baseURL}${revision}/haiku/trunk/build/jam/${file} &> /dev/null
     238    fi
     239}
     240
     241
     242function GeneratePackageNames()
     243{
     244    # GeneratePackageNames
     245    # Creates a file containing available package names
     246    local outfile="${baseDir}/OptionalPackageNames"
     247   
     248    if ! [ -f ${outfile} ] ; then
     249        echo "Generating a list of Package Names ..."
     250       
     251        touch ${outfile}
     252        local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p'
     253        sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${outfile}.temp
     254        while read line ; do
     255            local pkg=`echo ${line} | awk '{print $4}'`
     256           
     257            if ! IspackageIgnoreListed ${pkg} ; then
     258                echo ${pkg} >> ${outfile}
     259            fi
     260           
     261        done < ${outfile}.temp
     262        rm ${outfile}.temp
     263    fi
     264   
     265    # read list into array
     266    local count=0
     267    while read line ; do
     268        availablePackages[$count]=$line
     269        ((count++))
     270    done < ${outfile}
     271}
     272
     273
     274function IspackageIgnoreListed()
     275{
     276    # IspackageIgnoreListed <pkg>
     277    # Check if this package or any of its deps cannot be installed
     278   
     279    GetPackageDependencies ${1}
     280   
     281    local mustIgnore=1
     282    for ignoreThisPackage in ${packageIgnoreList[*]} ; do
     283        if [ ${1} == ${ignoreThisPackage} ] ; then
     284            mustIgnore=0
     285            break
     286        else
     287            for dep in ${tempDeps} ; do
     288                if [ ${dep} == ${ignoreThisPackage} ] ; then
     289                    mustIgnore=0
     290                    break
     291                fi
     292            done
     293        fi
     294    done
     295    return $mustIgnore
     296}
     297
     298
     299function IsPackageNameValid()
     300{
     301    # IsPackageNameValid <name>
     302    if IspackageIgnoreListed "$1" ; then   
     303        echo "Due to limitations, the package \"$1\" cannot be installed."
     304        exit 1
     305    fi
     306   
     307    local packageExists=1
     308    for name in ${availablePackages[*]} ; do
     309        if [ "$1" == "$name" ] ; then
     310            packageExists=0
     311            packagesToInstall[0]=${1}
     312            GetPackageDependencies "$1"
     313                       
     314            # move deps into packagesToInstall
     315            if [ ${#tempDeps} -gt 0 ] ; then
     316                for dep in ${tempDeps} ; do
     317                    if [ ';' == "$dep" ] ; then
     318                        break
     319                    fi
     320                    gPDi=${#packagesToInstall[@]}
     321                    ((gPDi++))
     322                    packagesToInstall[$gPDi]=${dep}
     323                    GetPackageDependencies ${dep}
     324                done
     325            fi
     326            echo "Packages to be installed:"
     327            echo "    ${packagesToInstall[*]}"
     328            return 0
     329        fi
     330    done
     331   
     332    if [ $packageExists -gt 0 ] ; then
     333        echo "Package \"$1\" does not exist."
     334        echo ''
     335        exit 1
     336    fi
     337    return 1
     338}
     339
     340
     341function GetPackageDependencies()
     342{
     343    # getPackageDependecies <pkg>
     344    # parse OptionalPackageDependencies for <pkg>'s dependencies
     345    local regExp="^OptionalPackageDependencies\ ${1}"
     346    local inputFile="${baseDir}/OptionalPackageDependencies"
     347    sed -n -e "/${regExp}\ /p" ${inputFile} > ${tmpDir}/optpkg.temp
     348    tempDeps=`sed -e "s/${regExp}\ :\ //" ${tmpDir}/optpkg.temp`
     349    rm ${tmpDir}/optpkg.temp
     350}
     351
     352
     353function ContainsSubstring()
     354{
     355    # ContainsSubstring <stringToLookIn> <stringToLookFor>
     356    local newString=${1/${2}/''}
     357    if [ ${#1} -eq `expr ${#newString} + ${#2}` ] ; then
     358        return 0
     359    fi
     360    return 1
     361}
     362
     363function ReplaceComparators()
     364{
     365    # ReplaceComparators <line>
     366    # One of the Jam-to-Bash conversion functions.
     367   
     368    # Preserve string comparators for TARGET_ARCH.
     369    if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then
     370        line=${line//'>='/'-ge'}
     371        line=${line//'<='/'-le'}
     372        line=${line//'>'/'-gt'}
     373        line=${line//'<'/'-lt'}
     374        line=${line//'!='/'-ne'}
     375    fi
     376}
     377
     378
     379function ConvertVariables()
     380{
     381    # ConvertVariables
     382    # One of the Jam-to-Bash conversion functions.
     383    # NOTE: jam's variables are normally '$(VARIABLE)'. \n
     384    #       The issue is with '(' and ')', so let's replace them globally.
     385   
     386    if ContainsSubstring "$line" '$(' ; then
     387        line=${line//'('/'{'}
     388        line=${line//')'/'}'}
     389    fi
     390}
     391
     392
     393function ConvertVariableDeclarationLines()
     394{
     395    # ConvertVariableDeclarationLines <regex> <variable>
     396    # One of the Jam-to-Bash conversion functions.
     397    # Jam lines that define variables need to be parsed differently.
     398    eval local input='$'"$2"
     399    local regex="$1"
     400    local _outvar="$2"
     401   
     402    input=${input/\ =\ /=}
     403    input=${input/\;/''}
     404    input=${input//\(/'{'}
     405    input=${input//\)/'}'}
     406   
     407    eval $_outvar="'$input'"
     408}
     409
     410
     411
     412function ConvertIfStatements()
     413{
     414    # ConvertIfStatements <line>   
     415    # One of the Jam-to-Bash conversion functions.
     416    line=${line//'} else {'/'else '}
     417    line=${line//'} else if '/'elif '}
     418    if ContainsSubstring "$line" "if " ; then
     419        if ! ContainsSubstring "$line" "if [" ; then
     420            line=${line/'if '/'if [ '}
     421        fi
     422       
     423        if ContainsSubstring "$line" '] {' ; then
     424            line=${line/'{'/' ; then'}
     425        elif ContainsSubstring "$line" '{' ; then
     426            line=${line/'{'/' ] ; then'}
     427        fi
     428       
     429        for compound in '&&' '||' ; do
     430            if ContainsSubstring "$line" "$compound" ; then
     431                line=${line/"$compound"/"] $compound ["}
     432            fi
     433        done
     434    fi
     435    # Assume all remaining closing braces are part of if statements
     436    line=${line/'}'/'fi'}
     437}
     438
     439
     440function ConvertJamToBash()
     441{
     442    # ConvertJamToBash <input file>
     443    # The main Jam-to-Bash conversion function.
     444    local inputFile=$1
     445    declare -a generatedBash
     446    countGenBashLine=0
     447   
     448    # Parse out some variable declarations
     449    local regExp='/^HAIKU_OPENSSL_PACKAGE/p'
     450    sslPkgLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
     451    ConvertVariableDeclarationLines "$regExp" 'sslPkgLine'
     452       
     453    local regExp='/^HAIKU_OPENSSL_URL/p'
     454    sslUrlLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
     455    ConvertVariableDeclarationLines "$regExp" 'sslUrlLine'
     456   
     457    local regExp='/^local\ baseURL/p'
     458    urlLine=`sed -n -e "$regExp" ${baseDir}/OptionalPackages`
     459    urlLine=${urlLine/local\ /''}
     460    ConvertVariableDeclarationLines "$regExp" 'urlLine'
     461   
     462    # Convert the easy bits.
     463    while read line ; do
     464        line=${line/'Echo'/'echo'}
     465       
     466        ConvertIfStatements "$line"
     467        ConvertVariables "$line"
     468        ReplaceComparators "$line"
     469       
     470        line=${line/"IsOptionalHaikuImagePackageAdded"/'"SomeText" !='}
     471        generatedBash[$countGenBashLine]=${line}
     472        ((countGenBashLine++))
     473    done < ${tmpDir}/optpkg.jam
     474   
     475    # output stage 1 generated code
     476    local i=0
     477    while [ $i -lt $countGenBashLine ] ; do
     478        echo ${generatedBash[$i]} >> ${tmpDir}/optpkg.stage1
     479        ((i++))
     480    done
     481   
     482    # This converts multi-line jam statements into a single line.
     483    # --- Start awk ---
     484    awk '
     485        /InstallOptionalHaikuImagePackage/,/\;/{
     486            ruleFound=1;
     487            if($0~/\;/) ORS="\n";
     488            else ORS=" "; print
     489        }
     490        /AddSymlinkToHaikuImage/,/\;/{
     491            ruleFound=1;
     492            if($0~/\;/) ORS="\n";
     493            else ORS=" "; print
     494        }
     495        /AddUserToHaikuImage/,/\;/{
     496            ruleFound=1;
     497            if($0~/\;/) ORS="\n";
     498            else ORS=" "; print
     499        }
     500        /Exit/,/\;/{
     501            ruleFound=1;
     502            if($0~/\;/) ORS="\n";
     503            else ORS=" "; print
     504        }       
     505        {
     506            if($1!='InstallOptionalHaikuImagePackage' && ruleFound!=1 && $1!="\;")
     507            print $0
     508        }
     509        { ruleFound=0; }
     510        ' ${tmpDir}/optpkg.stage1 > ${tmpDir}/optpkg.stage2 2>/dev/null
     511    # --- End awk ---
     512    rm ${tmpDir}/optpkg.stage1
     513}
     514
     515
     516function ListPackages()
     517{
     518    # ListPackages
     519    echo "Available Optional Packages:"
     520    for package in ${availablePackages[*]} ; do
     521        echo ${package}
     522    done
     523}
     524
     525
     526function AddPackage()
     527{
     528    # AddPackage <name>
     529    if IsPackageNameValid $1  ; then
     530        for package in ${packagesToInstall[*]} ; do
     531            local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}"
     532            local inputFile="${baseDir}/OptionalPackages"
     533            sed -n "/^$regExp/,/^\}/p" ${inputFile} >> ${tmpDir}/optpkg.jam
     534        done
     535        ConvertJamToBash "${tmpDir}/optpkg.jam"
     536        rm "${tmpDir}/optpkg.jam"
     537    CreateInstallerScript
     538    sh ${tmpDir}/install-optpkg.sh
     539    rm ${tmpDir}/install-optpkg.sh
     540    fi
     541}
     542
     543
     544function DisplayUsage()
     545{
     546    echo ''
     547    echo 'Disclaimer:'
     548    echo '  This is a temporary solution for installing OptionalPackages.'
     549    echo '  In time, there will be an official package manager.'
     550    echo "  See these URL's for info on the in-development package manager."
     551    echo '    http://dev.haiku-os.org/wiki/PackageManagerIdeas'
     552    echo '    http://dev.haiku-os.org/wiki/PackageFormat'
     553    echo ''
     554    echo "Usage: $0 [-l] [-a]"
     555    echo "-l    List installable packages"
     556    echo "-a    Add a package and all of its dependencies"
     557    echo ''
     558}
     559
     560
     561function DetectSystemConfiguration()
     562{
     563    # Determine which GCC we're running and if we're a hybrid
     564    if [ -d "$libDir"/gcc4 ] ; then
     565        HAIKU_GCC_VERSION[1]=2
     566        isHybridBuild=1
     567    elif [ -d "$libDir"/gcc2 ] ; then
     568        HAIKU_GCC_VERSION[1]=4
     569        isHybridBuild=1
     570    elif [ -f "$libDir"/libsupc++.so ] ; then
     571        HAIKU_GCC_VERSION[1]=4
     572        isHybridBuild=0
     573    else
     574        HAIKU_GCC_VERSION[1]=2
     575        isHybridBuild=0
     576    fi
     577
     578    # Determine the Architecture.
     579    if [ `uname -m` == "BePC" ] ; then
     580        TARGET_ARCH='x86'
     581    fi
     582}
     583
     584function Init()
     585{
     586   
     587    # Set up some directory paths
     588    baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages
     589    tmpDir=`finddir B_COMMON_TEMP_DIRECTORY`
     590    libDir=`finddir B_SYSTEM_LIB_DIRECTORY`
     591
     592    # Make sure these files are empty.
     593    echo "" > ${tmpDir}/optpkg.jam
     594    echo "" > ${tmpDir}/optpkg.stage1
     595   
     596   
     597    if ! [ -d ${baseDir} ] ; then
     598        mkdir -p ${baseDir}
     599    fi
     600   
     601    # Retreive the necessary jam files from svn.
     602    local buildFiles=( 'OptionalPackages' 'OptionalPackageDependencies' \
     603        'OptionalBuildFeatures')
     604    for file in ${buildFiles[*]} ; do
     605        GetBuildFile ${file}
     606    done
     607
     608    DetectSystemConfiguration
     609    GeneratePackageNames
     610}
     611
     612
     613# If no arguments were passed to the script, display its usage and exit.
     614if [ "$#" -lt 1 ] ; then
     615    DisplayUsage
     616    exit 0
     617else
     618    Init
     619fi
     620
     621# Parse the arguments given to the script.
     622while getopts "a:lh" opt; do
     623    case $opt in
     624        a)
     625            AddPackage $OPTARG
     626            exit 0
     627            ;;
     628        h)
     629            DisplayUsage
     630            exit 0
     631            ;;
     632        l)
     633            ListPackages
     634            exit 0
     635            ;;
     636        \?)
     637            echo "Invalid option: -$OPTARG" >&2
     638            exit 1
     639            ;;
     640        :)
     641            echo "Option -$OPTARG requires an argument." >&2
     642            exit 1
     643            ;;
     644    esac
     645done