Ticket #5315: installoptionalpackage-Improvements.patch

File installoptionalpackage-Improvements.patch, 17.3 KB (added by mmadia, 14 years ago)
  • data/bin/installoptionalpackage

     
    1 #!/bin/sh
     1#!/bin/bash
    22#
    3 # Copyright (c) 2009 Haiku Inc. All rights reserved.
     3# Copyright (c) 2009-2010 Haiku Inc. All rights reserved.
    44# Distributed under the terms of the MIT License.
    55#
    66# Authors:
     
    2020#     http://dev.haiku-os.org/wiki/PackageManagerIdeas
    2121#     http://dev.haiku-os.org/wiki/PackageFormat
    2222#
    23 # Usage: ./installoptionalpackage [-l] [-a]
     23# Usage: ./installoptionalpackage [-l] [-a "<pkg> [<pkg> ...]"]
    2424# -l      List installable packages
    25 # -a      Add a package and all of its dependencies
     25# -a      Add one or more packages and all dependencies
    2626
    2727
    28 declare -a packagesToInstall   
    29 declare -a availablePackages
     28declare -A availablePackages
     29declare availablePackagesKeys=""
    3030# Some Packages cannot be installed,
    3131# as they require either the source code or compiled binaries
    32 declare -a packageIgnoreList=( 'Bluetooth' 'Development' 'DevelopmentMin' \
    33     'DevelopmentBase' 'NetFS' 'P7zip' 'UserlandFS' 'Welcome')
     32declare packageIgnoreList='Bluetooth Development DevelopmentMin \
     33DevelopmentBase P7zip UserlandFS Welcome Wifi-ipw2100+fw Wifi-iprowifi2200+fw'
    3434
    3535
    3636function CreateInstallerScript()
     
    4040
    4141#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    4242    cat << EOF > ${tmpDir}/install-optpkg.sh
    43 #!/bin/sh
     43#!/bin/bash
    4444
    4545tmpDir=${tmpDir}
    4646HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]}
     
    143143    done
    144144    echo "Unzipping \$zipFile ..."
    145145    unzipDir="\${dirTokens}"
    146     unzip -q -d "\$unzipDir" "\$zipFile"
    147     # TODO should .OptionalPackageDescription be added to AboutSystem?
     146    unzip -q -o  -d "\$unzipDir" "\$zipFile"
     147   
    148148    if [ -f '/boot/.OptionalPackageDescription' ] ; then
    149149        rm '/boot/.OptionalPackageDescription'
    150150    fi
     
    170170    local linkName="\${functionArgs[2]}"
    171171    TrimLeadingSpace linkName
    172172    TrimEndingSpace linkName
    173            
     173   
     174    mkdir -p "${dirTokens}"
     175   
    174176    if [ "\${linkName}" == '' ] ; then
    175177        ln -sf "\${linkTarget}" -t "\${dirTokens}"
    176178    else
     
    225227}
    226228
    227229
     230function ContainsSubstring()
     231{
     232    # ContainsSubstring <stringToLookIn> <stringToLookFor>
     233    local string="$1"
     234    local substring="$2"
     235    local newString=${string/${substring}/''}
     236    if [ ${#string} -eq `expr ${#newString} + ${#substring}` ] ; then
     237        return 0
     238    fi
     239    return 1
     240}
     241
     242
     243function Init()
     244{
     245   
     246    # Set up some directory paths
     247    baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages
     248    tmpDir=`finddir B_COMMON_TEMP_DIRECTORY`
     249    libDir=`finddir B_SYSTEM_LIB_DIRECTORY`
     250
     251    # Make sure these files are empty.
     252    echo "" > ${tmpDir}/optpkg.jam
     253    echo "" > ${tmpDir}/optpkg.stage1
     254   
     255    if ! [ -d ${baseDir} ] ; then
     256        mkdir -p ${baseDir}
     257    fi
     258   
     259    # Retreive the necessary jam files from svn.
     260    local buildFiles="OptionalPackages OptionalPackageDependencies \
     261        OptionalBuildFeatures"
     262    for file in ${buildFiles} ; do
     263        GetBuildFile ${file}
     264    done
     265
     266    DetectSystemConfiguration
     267    ReadPackageNamesIntoMemory
     268}
     269
     270
    228271function GetBuildFile()
    229272{
    230273    # GetBuildFile <file>
    231     # Downloads files from Haiku's svn
    232     if ! [ -f ${baseDir}/${1} ] ; then
    233         echo "Fetching ${1} ..."
     274    # Downloads files from Haiku's svn
     275    local buildfile="$1"
     276    if ! [ -f ${baseDir}/${buildfile} ] ; then
     277        echo "Fetching ${buildfile} ..."
    234278        cd ${baseDir}
    235279        local baseURL=http://dev.haiku-os.org/export/
    236280        local revision=`uname -v | awk '{print $1}' | sed -e 's/r//'`
    237         wget ${baseURL}${revision}/haiku/trunk/build/jam/${file} 2>&1 > /dev/null
     281        local url="${baseURL}${revision}/haiku/trunk/build/jam/${buildfile}"
     282        wget -nv ${url} 2>&1 > /dev/null
    238283    fi
    239284}
    240285
    241286
    242 function GeneratePackageNames()
     287function DetectSystemConfiguration()
    243288{
    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}
     289    # Determine which GCC we're running and if we're a hybrid
     290    if [ -d "$libDir"/gcc4 ] ; then
     291        HAIKU_GCC_VERSION[1]=2
     292        isHybridBuild=1
     293    elif [ -d "$libDir"/gcc2 ] ; then
     294        HAIKU_GCC_VERSION[1]=4
     295        isHybridBuild=1
     296    elif [ -f "$libDir"/libsupc++.so ] ; then
     297        HAIKU_GCC_VERSION[1]=4
     298        isHybridBuild=0
     299    else
     300        HAIKU_GCC_VERSION[1]=2
     301        isHybridBuild=0
     302    fi
     303
     304    # Determine the Architecture.
     305    if [ `uname -m` == "BePC" ] ; then
     306        TARGET_ARCH='x86'
     307    fi
    271308}
    272309
    273310
    274 function IspackageIgnoreListed()
     311function ReadPackageNamesIntoMemory()
    275312{
    276     # IspackageIgnoreListed <pkg>
    277     # Check if this package or any of its deps cannot be installed
     313    local file="${baseDir}/OptionalPackageNames"
     314    if ! [ -f ${file} ] ; then
     315        GeneratePackageNames
     316    fi
    278317   
    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
     318    # read list into associative array
     319    while read line ; do
     320        local pkg=`echo ${line} | awk '{print $1}'`
     321        local pkgDeps=${line/':'/}
     322        availablePackages[${pkg}]="${pkgDeps}"
     323        availablePackagesKeys="${availablePackagesKeys} ${pkg}"
     324    done < ${file}
    296325}
    297326
    298327
    299 function IsPackageNameValid()
     328function GeneratePackageNames()
    300329{
    301     # IsPackageNameValid <name>
    302     if IspackageIgnoreListed "$1" ; then   
    303         echo "Due to limitations, the package \"$1\" cannot be installed."
    304         exit 1
    305     fi
     330    # GeneratePackageNames
     331    # Creates a file containing available package names
     332    # Each line shows a pakage and all of its recrusive dependencies
     333    # "<pkg> : <dep1> <dep2> ..."
     334    echo "Generating a list of Package Names ..."
    306335   
    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
     336    local file="${baseDir}/OptionalPackageNames"
     337    touch ${file}
     338   
     339    local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p'
     340    sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${file}.temp
     341    while read line ; do
     342        # in each non-filtered line, the 4th word is the optional package
     343        local pkg=`echo ${line} | awk '{print $4}'`
     344       
     345        nonRepeatingDeps=""
     346        GetPackageDependencies "$pkg"
     347        if IsPackageAndDepsOkToInstall ${pkg} ; then
     348            echo "${pkg} : ${nonRepeatingDeps}"  >> ${file}
    329349        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
     350       
     351    done < ${file}.temp
     352    rm ${file}.temp
    338353}
    339354
    340355
    341356function GetPackageDependencies()
    342357{
    343     # getPackageDependecies <pkg>
    344     # parse OptionalPackageDependencies for <pkg>'s dependencies
    345     local regExp="^OptionalPackageDependencies\ ${1}"
     358    # GetPackageDependencies <pkg>
     359   
     360    # parse OptionalPackageDependencies for the single line that defines
     361    # this optional package's dependencies.
     362    local regExp="^OptionalPackageDependencies\ ${1}\ \:"
    346363    local inputFile="${baseDir}/OptionalPackageDependencies"
     364   
     365    # print that single line
    347366    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 
    353 function 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 
    363 function ReplaceComparators()
    364 {
    365     # ReplaceComparators <line>
    366     # One of the Jam-to-Bash conversion functions.
    367367   
    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
     368    # strip out "OptionalPackageDependencies PackageName :"
     369    # this leaves "<dep1> .... ;"
     370    tempDeps=`sed -e "s/${regExp}\ //" ${tmpDir}/optpkg.temp`
     371   
     372    for foo in ${tempDeps%' ;'} ; do
     373        # Prevent duplicate entries of the same dependency package.
     374        if ! ContainsSubstring "${nonRepeatingDeps} " "${foo} " ; then
     375            nonRepeatingDeps="$foo $nonRepeatingDeps "
     376            nonRepeatingDeps="${nonRepeatingDeps//  / }"
     377        fi
     378    done
     379   
     380    # Recursively get the dependencies of these dependencies.
     381    for dep in ${tempDeps%' ;'} ; do
     382        GetPackageDependencies "$dep"
     383    done
     384   
    376385}
    377386
    378387
    379 function ConvertVariables()
     388function IsPackageAndDepsOkToInstall()
    380389{
    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//')'/'}'}
     390    # IsPackageAndDepsOkToInstall <pkg>
     391    if ContainsSubstring "${packageIgnoreList}" "${1}"; then
     392        echo "...warning: ${1} cannot be installed"
     393        return 1
    389394    fi
     395    for foo in ${nonRepeatingDeps} ; do
     396        if ContainsSubstring "${packageIgnoreList}" "${foo}"; then
     397            echo "...warning: ${1} cannot be installed because of ${foo}"
     398            return 1
     399        fi
     400    done
     401    return 0
    390402}
    391403
    392404
    393 function ConvertVariableDeclarationLines()
     405function AddPackage()
    394406{
    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"
     407    # AddPackage <name>
     408    packagesToInstall=""
     409    proceedWithInstallation=false
    401410   
    402     input=${input/\ =\ /=}
    403     input=${input/\;/''}
    404     input=${input//\(/'{'}
    405     input=${input//\)/'}'}
     411    for desiredPackage in ${1}; do
     412        if IsPackageNameValid $desiredPackage  ; then
     413            for item in ${availablePackages[${desiredPackage}]} ; do
     414                if ! ContainsSubstring "${packagesToInstall}" "${item}" ; then
     415                    packagesToInstall="${packagesToInstall} ${item}"
     416                fi
     417            done
     418            proceedWithInstallation=true
     419        fi
     420    done
    406421   
    407     eval $_outvar="'$input'"
     422    # If one or more packages can be installed, do it.
     423    if $proceedWithInstallation  ; then
     424        echo "To be installed: ${packagesToInstall}"
     425       
     426        for package in ${packagesToInstall} ; do
     427            # output the "if [ IsOptionalHaikuImagePackageAdded..." code block
     428            local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}"
     429            local inputFile="${baseDir}/OptionalPackages"
     430            sed -n "/^$regExp/,/^\}/p" ${inputFile} >> ${tmpDir}/optpkg.jam
     431        done
     432       
     433        ConvertJamToBash "${tmpDir}/optpkg.jam"
     434        rm "${tmpDir}/optpkg.jam"
     435    CreateInstallerScript
     436    sh ${tmpDir}/install-optpkg.sh
     437    rm ${tmpDir}/install-optpkg.sh
     438    fi
    408439}
    409440
    410441
    411 
    412 function ConvertIfStatements()
     442function IsPackageNameValid()
    413443{
    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 [ '}
     444    # IsPackageNameValid <name>
     445    for name in ${availablePackagesKeys} ; do
     446        if [ "$1" == "$name" ] ; then
     447            return 0
    421448        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'}
     449    done
     450    return 1
    437451}
    438452
    439453
     
    513527}
    514528
    515529
    516 function ListPackages()
     530function ConvertVariableDeclarationLines()
    517531{
    518     # ListPackages
    519     echo "Available Optional Packages:"
    520     for package in ${availablePackages[*]} ; do
    521         echo ${package}
    522     done
     532    # ConvertVariableDeclarationLines <regex> <variable>
     533    # One of the Jam-to-Bash conversion functions.
     534    # Jam lines that define variables need to be parsed differently.
     535    eval local input='$'"$2"
     536    local regex="$1"
     537    local _outvar="$2"
     538   
     539    input=${input/\ =\ /=}
     540    input=${input/\;/''}
     541    input=${input//\(/'{'}
     542    input=${input//\)/'}'}
     543   
     544    eval $_outvar="'$input'"
    523545}
    524546
    525547
    526 function AddPackage()
     548function ConvertIfStatements()
    527549{
    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
     550    # ConvertIfStatements <line>   
     551    # One of the Jam-to-Bash conversion functions.
     552    line=${line//'} else {'/'else '}
     553    line=${line//'} else if '/'elif '}
     554    if ContainsSubstring "$line" "if " ; then
     555        if ! ContainsSubstring "$line" "if [" ; then
     556            line=${line/'if '/'if [ '}
     557        fi
     558       
     559        if ContainsSubstring "$line" '] {' ; then
     560            line=${line/'{'/' ; then'}
     561        elif ContainsSubstring "$line" '{' ; then
     562            line=${line/'{'/' ] ; then'}
     563        fi
     564       
     565        for compound in '&&' '||' ; do
     566            if ContainsSubstring "$line" "$compound" ; then
     567                line=${line/"$compound"/"] $compound ["}
     568            fi
    534569        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
    540570    fi
     571    # Assume all remaining closing braces are part of if statements
     572    line=${line/'}'/'fi'}
    541573}
    542574
    543575
    544 function DisplayUsage()
     576function ConvertVariables()
    545577{
    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 ''
     578    # ConvertVariables
     579    # One of the Jam-to-Bash conversion functions.
     580   
     581    # NOTE: jam's variables are normally '$(VARIABLE)'. \n
     582    #       The issue is with '(' and ')', so let's replace them globally.
     583    if ContainsSubstring "$line" '$(' ; then
     584        line=${line//'('/'{'}
     585        line=${line//')'/'}'}
     586    fi
    558587}
    559588
    560589
    561 function DetectSystemConfiguration()
     590function ReplaceComparators()
    562591{
    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
     592    # ReplaceComparators <line>
     593    # One of the Jam-to-Bash conversion functions.
     594   
     595    # Preserve string comparators for TARGET_ARCH.
     596    if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then
     597        line=${line//'>='/'-ge'}
     598        line=${line//'<='/'-le'}
     599        line=${line//'>'/'-gt'}
     600        line=${line//'<'/'-lt'}
     601        line=${line//'!='/'-ne'}
    576602    fi
     603}
    577604
    578     # Determine the Architecture.
    579     if [ `uname -m` == "BePC" ] ; then
    580         TARGET_ARCH='x86'
    581     fi
     605
     606function DisplayUsage()
     607{
     608    cat << EOF
     609
     610Disclaimer:
     611  This is a temporary solution for installing OptionalPackages.
     612  In time, there will be an official package manager.
     613  See these URL's for information on the in-development package manager.
     614    http://dev.haiku-os.org/wiki/PackageManagerIdeas
     615    http://dev.haiku-os.org/wiki/PackageFormat
     616
     617Usage: ./installoptionalpackage [-l] [-a "<pkg> [<pkg> ...]"]
     618-l      List installable packages
     619-a      Add one or more packages and all dependencies
     620
     621EOF
    582622}
    583623
    584 function Init()
     624
     625function ListPackages()
    585626{
     627    # ListPackages
     628    echo ""
     629    echo ""
     630    echo "Available Optional Packages:"
    586631   
    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
     632    # single line:
     633    echo ${availablePackagesKeys}
    595634   
    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
     635    # one per line:
     636    #for package in ${availablePackagesKeys} ; do
     637    #   echo ${package}
     638    #done
    610639}
    611640
    612641
     
    622651while getopts "a:lh" opt; do
    623652    case $opt in
    624653        a)
    625             AddPackage $OPTARG
     654            AddPackage "$OPTARG"
    626655            exit 0
    627656            ;;
    628657        h)