1#!/bin/bash 2# 3# Copyright (c) 2009-2010 Haiku, Inc. 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# 16DISCLAIMER="\ 17Disclaimer:\n\ 18 This is a temporary solution for installing OptionalPackages.\n\ 19 In time, there will be an official package manager.\n\ 20 See these URL's for information on the in-development package manager.\n\ 21 http://dev.haiku-os.org/wiki/PackageManagerIdeas\n\ 22 http://dev.haiku-os.org/wiki/PackageFormat\n\ 23 " 24 25USAGE="\ 26Usage: ./installoptionalpackage [<pkg> [<pkg> ...]]\n\ 27 or ./installoptionalpackage [-a|-s <pkg> [<pkg> ...]]\n\ 28 or ./installoptionalpackage [-f|-h|-l]\n\ 29\n\ 30Options:\n\ 31-a Add one or more packages and all dependencies\n\ 32-s Show the final list of packages that would be installed\n\ 33-f Remove cached data and list installable packages\n\ 34-h Print this help.\n\ 35-l List installable packages\n\ 36 " 37 38declare -A availablePackages 39declare availablePackagesKeys="" 40declare wantsToInstall="" 41declare alreadyInstalled="" 42# Some Packages cannot be installed, 43# as they require either the source code or compiled binaries 44declare packageIgnoreList="Bluetooth Development DevelopmentMin \ 45DevelopmentBase ICU-devel ICU MandatoryPackages UserlandFS \ 46WebPositive Welcome WifiFirmwareScriptData " 47 48 49function CreateInstallerScript() 50{ 51 # This function will create a secondary script, containing all of the 52 # information needed to install the optional package and its dependencies 53 54#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 55 cat << EOF > ${tmpDir}/install-optpkg.sh 56#!/bin/bash 57 58tmpDir=${tmpDir} 59HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]} 60isHybridBuild=${isHybridBuild} 61TARGET_ARCH=${TARGET_ARCH} 62HAIKU_IMAGE_HOST_NAME=`uname -n` 63#TODO: possibly add a CLI option to execute InstallSourceArchive 64HAIKU_INCLUDE_SOURCES=0 65$urlLine 66$sslPkgLine 67$sslUrlLine 68$webkitFileLine 69declare -a functionArgs 70expanderRulesFile=`finddir B_COMMON_DATA_DIRECTORY`/expander.rules 71if [ -f \${expanderRulesFile} ] ; then 72 expanderRulesFileExists=1 73fi 74 75 76function ParseFunctionArguments() 77{ 78 # ParseFunctionArguments <args> 79 # Parse arguments for Jam wrapper functions into an array. 80 IN="\$@" 81 OIFS=\$IFS 82 IFS=":" 83 84 local count=0 85 functionArgs=( ) 86 for x in \$IN 87 do 88 functionArgs[\${count}]="\${x}" 89 ((count++)) 90 done 91 IFS=\$OIFS 92} 93 94 95function TrimLeadingSpace() 96{ 97 # TrimLeadingSpace <variable name> 98 eval local text='\$'"\$1" 99 local _outvar="\$1" 100 101 local length=\${#text} 102 ((length--)) 103 if [ "\${text:0:1}" == ' ' ] ; then 104 text=\${text#' '} 105 fi 106 107 eval \$_outvar="'\$text'" 108} 109 110 111function TrimEndingSpace() 112{ 113 # TrimEndingSpace <variable name> 114 eval local text='\$'"\$1" 115 local _outvar="\$1" 116 117 local length=\${#text} 118 ((length--)) 119 if [ "\${text:\$length}" == ' ' ] ; then 120 text=\${text%' '} 121 fi 122 123 eval \$_outvar="'\$text'" 124} 125 126 127function Exit() 128{ 129 # Exit <message> 130 # Wrapper for Jam rule 131 echo "\$@" 132 exit 1 133} 134 135 136function InstallOptionalHaikuImagePackage() 137{ 138 # InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage 139 140 # Wrapper for Jam rule 141 echo "Installing \$1 ..." 142 cd \$tmpDir 143 144 archiveFile=\`echo \$3 | sed -s "s/http.*\///"\` 145 if ! [ -f \$archiveFile ] ; then 146 echo "Downloading \$3 ..." 147 # TODO : add some error handling for downloads 148 local attempt=1 149 while [ \`wget -nv \$3 ; echo \$? \` -ne 0 ]; do 150 if [ \$attempt -eq 5 ]; then 151 break 152 fi 153 (( attempt++ )) 154 echo "Download attempt #\$attempt failed. Retrying ..." 155 if [ -e \$archiveFile ]; then 156 rm \$archiveFile 157 fi 158 done 159 if [ \$attempt -ge 5 ]; then 160 if [ -e \$archiveFile ]; then 161 rm \$archiveFile 162 fi 163 Exit "Max download retries exceeded. Halting installation." 164 fi 165 fi 166 167 local dirTokens='/boot' 168 local count=4 169 local i=0 170 for possibleToken in "\$@" ; do 171 if [ \$i -lt \$count ] ; then 172 ((i++)) 173 else 174 ((i++)) 175 if [ "\$possibleToken" != ':' ] ; then 176 dirTokens=\${dirTokens}/\$possibleToken 177 else 178 break 179 fi 180 fi 181 done 182 echo "Extracting \$archiveFile ..." 183 extractDir="\${dirTokens}" 184 185 local errorMessage=" 186...Failed while extracting \$archiveFile 187You may need to manually clean up the partially extracted files. 188 " 189 case "\$archiveFile" in 190 *.zip) 191 unzip -q -o -d "\$extractDir" "\$archiveFile" \ 192 || Exit "\$errorMessage" 193 ;; 194 *.tgz|*.tar.gz) 195 tar -C "\$extractDir" -xf "\$archiveFile" \ 196 || Exit "\$errorMessage" 197 ;; 198 *) 199 echo "Unhandled archive extension in InstallOptionalHaikuImagePackage()" 200 exit 1 201 ;; 202 esac 203 204 if [ -f '/boot/.OptionalPackageDescription' ] ; then 205 rm '/boot/.OptionalPackageDescription' 206 fi 207 rm "\$archiveFile" 208} 209 210 211function InstallSourceArchive() 212{ 213 if [ \$HAIKU_INCLUDE_SOURCES -gt 0 ]; then 214 echo "InstallSourceArchive is not implemented." 215 fi 216} 217 218 219function AddSymlinkToHaikuImage() 220{ 221 # AddSymlinkToHaikuImage <dir tokens> : <link target> [ : <link name> ] 222 # Wrapper for Jam rule 223 ParseFunctionArguments "\$@" 224 225 local dirTokens="/boot/\${functionArgs[0]}" 226 TrimLeadingSpace dirTokens 227 TrimEndingSpace dirTokens 228 dirTokens=\${dirTokens//' '/\/} 229 230 local linkTarget="\${functionArgs[1]}" 231 TrimLeadingSpace linkTarget 232 TrimEndingSpace linkTarget 233 234 local linkName="\${functionArgs[2]}" 235 TrimLeadingSpace linkName 236 TrimEndingSpace linkName 237 238 mkdir -p "\${dirTokens}" 239 240 if [ "\${linkName}" == '' ] ; then 241 ln -sf "\${linkTarget}" -t "\${dirTokens}" 242 else 243 ln -sf "\${linkTarget}" "\${dirTokens}/\${linkName}" 244 fi 245} 246 247 248function AddUserToHaikuImage() 249{ 250 # AddUserToHaikuImage user : uid : gid : home : shell : realName 251 # Wrapper for Jam rule 252 ParseFunctionArguments "\$@" 253 254 local user=\${functionArgs[0]} 255 local uid=\${functionArgs[1]} 256 local gid=\${functionArgs[2]} 257 local home=\${functionArgs[3]} 258 local shell=\${functionArgs[4]} 259 local realName=\${functionArgs[5]} 260 261 passwdLine="\${user}:x:\${uid}:\${gid}:\${realName}:\${home}:\${shell}" 262 passwdLine=\${passwdLine//' :'/':'} 263 passwdLine=\${passwdLine//': '/':'} 264 265 local length=\${#passwdLine} 266 ((length--)) 267 if [ "\${passwdLine:\$length}" == ' ' ] ; then 268 passwdLine=\${passwdLine%' '} 269 fi 270 271 passwdFile="\`finddir B_COMMON_ETC_DIRECTORY\`/passwd" 272 touch \${passwdFile} 273 274 local userExists=1 275 while read line ; do 276 if [ "\${passwdLine}" == "\${line}" ] ; then 277 userExists=0 278 fi 279 done < \${passwdFile} 280 281 if [ \$userExists -ge 1 ] ; then 282 echo "\${passwdLine}" >> \${passwdFile} 283 fi 284} 285 286 287function AddExpanderRuleToHaikuImage() 288{ 289 # AddExpanderRuleToHaikuImage <mimetype> : <extension> : <list> : <extract> 290 # Wrapper for Jam rule 291 ParseFunctionArguments "\$@" 292 293 local mimetype=\${functionArgs[0]} 294 local extension=\${functionArgs[1]} 295 local list=\${functionArgs[2]} 296 local extract=\${functionArgs[3]} 297 298 # clean up the variables 299 TrimLeadingSpace mimetype 300 TrimEndingSpace mimetype 301 TrimLeadingSpace extension 302 TrimEndingSpace extension 303 TrimLeadingSpace list 304 TrimEndingSpace list 305 TrimLeadingSpace extract 306 TrimEndingSpace extract 307 local rule_raw="\${mimetype}\\t\${extension}\\t\${list}\\t\${extract}" 308 309 # reset this at every invocation 310 ruleFound= 311 312 if [ \${expanderRulesFileExists} ] ; then 313 # Check if a rule for the mimetype & extension exists. 314 while read line ; do 315 existing_rule=`echo \$line | awk '{ print \$1\$2 }'` 316 if [ "\${mimetype}\${extension}" == "\${existing_rule}" ] ; then 317 ruleFound=1 318 break 319 fi 320 done < "\${expanderRulesFile}" 321 fi 322 if ! [ \${expanderRulesFileExists} ] || ! [ \${ruleFound} ] ; then 323 # Either expander.rules does not exist or a rule for mimetype & 324 # extension does not exist. Output the new rule directly to it. 325 echo -e \${rule_raw} >> \${expanderRulesFile} 326 fi 327} 328 329 330EOF 331#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 332 cat ${tmpDir}/optpkg.stage2 >> ${tmpDir}/install-optpkg.sh 333 rm ${tmpDir}/optpkg.stage2 334} 335 336 337function ContainsSubstring() 338{ 339 # ContainsSubstring <stringToLookIn> <stringToLookFor> 340 local string="$1" 341 local substring="$2" 342 local newString=${string/${substring}/''} 343 if [ ${#string} -eq $((${#newString} + ${#substring})) ] ; then 344 return 0 345 fi 346 return 1 347} 348 349 350function ErrorExit() 351{ 352 echo $1 353 exit 1 354} 355 356 357function Init() 358{ 359 360 # Set up some directory paths 361 baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages 362 tmpDir=`finddir B_COMMON_TEMP_DIRECTORY` 363 libDir=`finddir B_SYSTEM_LIB_DIRECTORY` 364 365 installedPackagesFile="${baseDir}/InstalledPackages" 366 367 # Make sure these files are empty. 368 echo "" > ${tmpDir}/optpkg.jam 369 echo "" > ${tmpDir}/optpkg.stage1 370 371 if ! [ -d ${baseDir} ] ; then 372 mkdir -p ${baseDir} 373 fi 374 375 DetectSystemConfiguration 376 DownloadAllBuildFiles 377 ReadInstalledPackagesIntoMemory 378 ReadPackageNamesIntoMemory 379} 380 381 382function DownloadAllBuildFiles() 383{ 384 # DownloadAllBuildFiles 385 # Retreive the necessary jam files from svn. 386 local buildFiles="BuildFeatures OptionalPackageDependencies \ 387 OptionalPackages OptionalLibPackages" 388 for file in ${buildFiles} ; do 389 GetBuildFile ${file} 390 done 391 392} 393 394 395function GetBuildFile() 396{ 397 # GetBuildFile <file> 398 # Downloads files from Haiku's svn 399 local buildfile="$1" 400 if ! [ -f ${baseDir}/${buildfile} ] ; then 401 echo "Fetching ${buildfile} ..." 402 cd ${baseDir} 403 local baseURL=http://cgit.haiku-os.org/haiku/plain 404 local revisionTag=`uname -v | awk '{print $1}' | sed -e 's/-.*//'` 405 # the sed invocation above drops potential dirty markers off the 406 # revision tag 407 local url="${baseURL}/build/jam/${buildfile}?id=${revisionTag}" 408 wget -q ${url} -O ${buildfile} \ 409 || ErrorExit "...failed to download $buildfile" 410 fi 411} 412 413 414function DetectSystemConfiguration() 415{ 416 417 # Determine which GCC we're running 418 if [ -f "$libDir"/libsupc++.so ] ; then 419 HAIKU_GCC_VERSION[1]=4 420 else 421 HAIKU_GCC_VERSION[1]=2 422 fi 423 424 # Test for hybrid 425 if [ -d "$libDir"/gcc4 -a -d "$libDir"/gcc2 ]; then 426 echo "Sorry, but your build appears to be broken ..." 427 echo "Both gcc2 and gcc4 subdirs exist." 428 exit 1 429 elif [ -d "$libDir"/gcc4 -o -d "$libDir"/gcc2 ]; then 430 isHybridBuild=1 431 else 432 isHybridBuild="" 433 fi 434 435 # Determine the Architecture. 436 if [ `uname -m` == "BePC" ] ; then 437 TARGET_ARCH='x86' 438 elif [ `uname -m` == "x86_64" ] ; then 439 TARGET_ARCH='x86_64' 440 else 441 echo "Sorry, x86 only for now." 442 exit 1 443 fi 444} 445 446 447function ReadInstalledPackagesIntoMemory() 448{ 449 while read line ; do 450 alreadyInstalled="${alreadyInstalled} $line" 451 packageIgnoreList=${packageIgnoreList/"${line} "/' '} 452 done < ${installedPackagesFile} 453} 454 455 456function ReadPackageNamesIntoMemory() 457{ 458 local file="${baseDir}/OptionalPackageNames" 459 if ! [ -f ${file} ] ; then 460 GeneratePackageNames 461 fi 462 463 # read list into associative array 464 while read line ; do 465 local pkg=`echo ${line} | awk '{print $1}'` 466 local pkgDeps=${line/"${pkg} :"/} 467 availablePackages[${pkg}]="${pkgDeps}" 468 availablePackagesKeys="${availablePackagesKeys} ${pkg}" 469 done < ${file} 470} 471 472 473function GeneratePackageNames() 474{ 475 # GeneratePackageNames 476 # Creates a file containing available package names 477 # Each line shows a pakage and all of its recrusive dependencies 478 # "<pkg> : <dep1> <dep2> ..." 479 echo "Generating a list of Package Names ..." 480 481 local file="${baseDir}/OptionalPackageNames" 482 if [ -e "${file}" ]; then 483 rm "${file}" 484 fi 485 486 local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p' 487 sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${file}.temp 488 sed -n -e "$regExp" ${baseDir}/OptionalLibPackages >> ${file}.temp 489 while read line ; do 490 # in each non-filtered line, the 4th word is the optional package 491 local pkg=`echo ${line} | awk '{print $4}'` 492 493 nonRepeatingDeps="" 494 GetPackageDependencies "$pkg" 495 local lowerCasePkg=`echo ${pkg} | tr '[A-Z]' '[a-z]'` 496 if ! ContainsSubstring "${alreadyInstalled} " "${pkg} " ; then 497 if IsPackageAndDepsOkToInstall ${pkg} ; then 498 echo "${lowerCasePkg} : ${pkg} ${nonRepeatingDeps}" >> ${file} 499 fi 500 fi 501 502 done < ${file}.temp 503 rm ${file}.temp 504} 505 506 507function GetPackageDependencies() 508{ 509 # GetPackageDependencies <pkg> 510 511 # parse OptionalPackageDependencies for the single line that defines 512 # this optional package's dependencies. 513 local regExp="^OptionalPackageDependencies\ ${1}\ \:" 514 local inputFile="${baseDir}/OptionalPackageDependencies" 515 516 # print that single line 517 sed -n -e "/${regExp}\ /p" ${inputFile} > ${tmpDir}/optpkg.temp 518 519 # strip out "OptionalPackageDependencies PackageName :" 520 # this leaves "<dep1> .... ;" 521 tempDeps=`sed -e "s/${regExp}\ //" ${tmpDir}/optpkg.temp` 522 523 for foo in ${tempDeps%' ;'} ; do 524 # Prevent duplicate entries of the same dependency package. 525 if ! ContainsSubstring "${nonRepeatingDeps} " "${foo} " ; then 526 nonRepeatingDeps="$foo $nonRepeatingDeps " 527 nonRepeatingDeps="${nonRepeatingDeps// / }" 528 fi 529 done 530 531 # Recursively get the dependencies of these dependencies. 532 for dep in ${tempDeps%' ;'} ; do 533 GetPackageDependencies "$dep" 534 done 535 536} 537 538 539function IsPackageAndDepsOkToInstall() 540{ 541 # IsPackageAndDepsOkToInstall <pkg> 542 if ContainsSubstring "${packageIgnoreList}" "${1}"; then 543 #echo "...warning: ${1} cannot be installed" 544 return 1 545 fi 546 for foo in ${nonRepeatingDeps} ; do 547 if ContainsSubstring "${packageIgnoreList}" "${foo}"; then 548 #echo "...warning: ${1} cannot be installed because of ${foo}" 549 return 1 550 fi 551 done 552 return 0 553} 554 555 556function BuildListOfRequestedPackages() 557{ 558 if [ "$1" = '-a' ] || [ "$1" = '-s' ]; then 559 shift 560 fi 561 while [ $# -gt 0 ]; do 562 local lowerCase=`echo $1 | tr '[A-Z]' '[a-z]'` 563 wantsToInstall="${wantsToInstall} $lowerCase" 564 shift 565 done 566} 567 568 569function AddPackages() 570{ 571 # AddPackages 572 573 # If one or more packages can be installed, do it. 574 if BuildFinalListOfPackagesToInstall ; then 575 576 for package in ${packagesToInstall} ; do 577 # output the "if [ IsOptionalHaikuImagePackageAdded..." code block 578 local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}\ " 579 for inputFile in OptionalPackages OptionalLibPackages ; do 580 sed -n "/^$regExp/,/^\}/p" "${baseDir}/${inputFile}" >> ${tmpDir}/optpkg.jam 581 done 582 done 583 584 ConvertJamToBash "${tmpDir}/optpkg.jam" 585 rm "${tmpDir}/optpkg.jam" 586 CreateInstallerScript 587 sh ${tmpDir}/install-optpkg.sh 588 exitcode=$? 589 if [ $exitcode -gt 0 ]; then 590 ErrorExit "... something went wrong when installing packages." 591 fi 592 rm ${tmpDir}/install-optpkg.sh 593 594 # update files to account for the newly installed packages 595 alreadyInstalled="${alreadyInstalled} ${packagesToInstall} " 596 RecordInstalledPackages 597 GeneratePackageNames 598 echo "... done." 599 fi 600} 601 602 603function BuildFinalListOfPackagesToInstall() 604{ 605 # BuildFinalListOfPackagesToInstall 606 607 packagesToInstall="" 608 proceedWithInstallation=false 609 610 for desiredPackage in ${wantsToInstall}; do 611 if IsPackageNameValid $desiredPackage ; then 612 for item in ${availablePackages[${desiredPackage}]} ; do 613 if ! ContainsSubstring "${packagesToInstall}" "${item}" ; then 614 packagesToInstall="${packagesToInstall} ${item}" 615 fi 616 done 617 proceedWithInstallation=true 618 fi 619 done 620 # pad the variable 621 packagesToInstall="${packagesToInstall} " 622 # remove entries that are already installed 623 for skip in ${alreadyInstalled}; do 624 packagesToInstall=${packagesToInstall/"${skip} "/} 625 done 626 # strip double spaces 627 packagesToInstall=${packagesToInstall/" "/" "} 628 629 if ! [ ${#packagesToInstall} -gt 1 ]; then 630 echo "... no packages need to be installed." 631 echo "" 632 echo "If you wish to re-install a package, run these two commands" 633 echo " rm ${baseDir}/OptionalPackageNames" 634 echo " open $installedPackagesFile" 635 echo "and delete the line containing the package name(s)." 636 echo "" 637 proceedWithInstallation=false 638 fi 639 if ! $proceedWithInstallation ; then 640 echo 'Not proceeding with installation.' 641 return 1 642 fi 643 echo "To be installed: ${packagesToInstall}" 644 return 0 645} 646 647 648function IsPackageNameValid() 649{ 650 # IsPackageNameValid <name> 651 for name in ${availablePackagesKeys} ; do 652 if [ "$1" == "$name" ] ; then 653 return 0 654 fi 655 done 656 return 1 657} 658 659 660function RecordInstalledPackages() 661{ 662 echo -e ${alreadyInstalled} | tr '\ ' '\n' | sort > ${installedPackagesFile} 663} 664 665 666function ConvertJamToBash() 667{ 668 # ConvertJamToBash <input file> 669 # The main Jam-to-Bash conversion function. 670 local inputFile=$1 671 declare -a generatedBash 672 countGenBashLine=0 673 674 # Parse out some variable declarations 675 676 # TODO : add these following variables to the CreateInstallerScript 677 # TODO : parse HAIKU_ICU_GCC_2_PACKAGE 678 #local regExp='/^HAIKU_ICU_GCC_2_PACKAGE/p' 679 #icuGcc2PkgLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 680 #ConvertVariableDeclarationLines "$regExp" 'icuGcc2PkgLine' 681 682 # TODO : parse HAIKU_ICU_GCC_4_PACKAGE 683 #local regExp='/^HAIKU_ICU_GCC_4_PACKAGE/p' 684 #icuGcc4PkgLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 685 #ConvertVariableDeclarationLines "$regExp" 'icuGcc4PkgLine' 686 687 # TODO : parse HAIKU_ICU_DEVEL_PACKAGE 688 #local regExp='/^HAIKU_ICU_DEVEL_PACKAGE/p' 689 #icuDevelPkgLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 690 #ConvertVariableDeclarationLines "$regExp" 'icuDevelPkgLine' 691 692 # TODO : fix the regex 693 local regExp="/^\s*HAIKU_OPENSSL_PACKAGE = .*-gcc${HAIKU_GCC_VERSION[1]}-/p" 694 sslPkgLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 695 ConvertVariableDeclarationLines "$regExp" 'sslPkgLine' 696 697 # TODO : fix the regex 698 local regExp='/^HAIKU_OPENSSL_URL/p' 699 sslUrlLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 700 ConvertVariableDeclarationLines "$regExp" 'sslUrlLine' 701 702 # TODO : fix the regex 703 local regExp='/^HAIKU_WEBKIT_FILE/p' 704 webkitFileLine=`sed -n -e "$regExp" ${baseDir}/BuildFeatures` 705 ConvertVariableDeclarationLines "$regExp" 'webkitFileLine' 706 707 local regExp='/^local\ baseURL/p' 708 urlLine=`sed -n -e "$regExp" ${baseDir}/OptionalPackages` 709 urlLine=${urlLine/local\ /''} 710 ConvertVariableDeclarationLines "$regExp" 'urlLine' 711 712 # Convert the easy bits. 713 while read line ; do 714 line=${line/'Echo'/'echo'} 715 716 # TODO: add support for converting for loops. 717 # will need to introduce curly brace counting 718 ConvertIfStatements "$line" 719 ConvertVariables "$line" 720 #ReplaceComparators "$line" 721 722 line=${line/"IsOptionalHaikuImagePackageAdded"/'"SomeText" !='} 723 generatedBash[$countGenBashLine]=${line} 724 ((countGenBashLine++)) 725 done < ${tmpDir}/optpkg.jam 726 727 # output stage 1 generated code 728 local i=0 729 while [ $i -lt $countGenBashLine ] ; do 730 echo ${generatedBash[$i]} >> ${tmpDir}/optpkg.stage1 731 ((i++)) 732 done 733 734 # This converts multi-line jam statements into a single line. 735 # --- Start awk --- 736 awk ' 737 /InstallOptionalHaikuImagePackage/,/\;/{ 738 isRule=1; 739 if($0~/\;/) ORS="\n"; 740 else ORS=" "; print 741 } 742 /AddSymlinkToHaikuImage/,/\;/{ 743 isRule=1; 744 if($0~/\;/) ORS="\n"; 745 else ORS=" "; print 746 } 747 /AddUserToHaikuImage/,/\;/{ 748 isRule=1; 749 if($0~/\;/) ORS="\n"; 750 else ORS=" "; print 751 } 752 /AddExpanderRuleToHaikuImage/,/\;/{ 753 isRule=1; 754 if($0~/\;/) ORS="\n"; 755 else ORS=" "; print 756 } 757 /Exit/,/\;/{ 758 isRule=1; 759 if($0~/\;/) ORS="\n"; 760 else ORS=" "; print 761 } 762 { 763 if($1!='InstallOptionalHaikuImagePackage' && isRule!=1 && $1!="\;") 764 print $0 765 } 766 { isRule=0; } 767 ' ${tmpDir}/optpkg.stage1 > ${tmpDir}/optpkg.stage2 2>/dev/null 768 # --- End awk --- 769 rm ${tmpDir}/optpkg.stage1 770} 771 772 773function ConvertVariableDeclarationLines() 774{ 775 # ConvertVariableDeclarationLines <regex> <variable> 776 # One of the Jam-to-Bash conversion functions. 777 # Jam lines that define variables need to be parsed differently. 778 eval local input='$'"$2" 779 local regex="$1" 780 local _outvar="$2" 781 782 input=${input/\ =\ /=} 783 input=${input/\;/''} 784 input=${input//\(/'{'} 785 input=${input//\)/'}'} 786 787 eval $_outvar="'$input'" 788} 789 790 791function ConvertIfStatements() 792{ 793 # ConvertIfStatements <line> 794 # One of the Jam-to-Bash conversion functions. 795 line=${line//'} else {'/'else '} 796 line=${line//'} else if '/'elif '} 797 if ContainsSubstring "$line" "if " ; then 798 if ! ContainsSubstring "$line" "if [" ; then 799 line=${line/'if '/'if [ '} 800 fi 801 802 if ContainsSubstring "$line" '] {' ; then 803 line=${line/'{'/' ; then'} 804 elif ContainsSubstring "$line" '{' ; then 805 line=${line/'{'/' ] ; then'} 806 fi 807 808 for compound in '&&' '||' ; do 809 if ContainsSubstring "$line" "$compound" ; then 810 line=${line/"$compound"/"] $compound ["} 811 fi 812 done 813 ReplaceComparators "$line" 814 fi 815 # Assume all remaining closing braces are part of if statements 816 line=${line/'}'/'fi'} 817} 818 819 820function ConvertVariables() 821{ 822 # ConvertVariables 823 # One of the Jam-to-Bash conversion functions. 824 825 # NOTE: jam's variables are normally '$(VARIABLE)'. \n 826 # The issue is with '(' and ')', so let's replace them globally. 827 if ContainsSubstring "$line" '$(' ; then 828 line=${line//'('/'{'} 829 line=${line//')'/'}'} 830 fi 831} 832 833 834function ReplaceComparators() 835{ 836 # ReplaceComparators <line> 837 # One of the Jam-to-Bash conversion functions. 838 839 # Preserve string comparators for TARGET_ARCH. 840 if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then 841 line=${line//'>='/'-ge'} 842 line=${line//'<='/'-le'} 843 line=${line//'>'/'-gt'} 844 line=${line//'<'/'-lt'} 845 line=${line//'!='/'-ne'} 846 line=${line//'='/'-eq'} 847 fi 848} 849 850 851function DisplayUsage() 852{ 853 echo -e "$DISCLAIMER" 854 echo -e "$USAGE" 855} 856 857 858function RemoveCachedFiles() 859{ 860 # RemoveCachedFiles 861 echo "Removing cached files ..." 862 if [ -e ${baseDir}/OptionalPackageNames ]; then 863 rm ${baseDir}/OptionalPackageNames 864 fi 865 866 # Unset variables, which prevents duplicate entries. 867 declare -A availablePackages 868 declare availablePackagesKeys="" 869 870 # Reinitialize 871 Init 872} 873 874 875function ListPackages() 876{ 877 # ListPackages 878 echo "" 879 echo "Optional Packages that have been installed:" 880 echo ${alreadyInstalled} 881 882 echo "" 883 echo "" 884 echo "Installable Optional Packages:" 885 886 # single line: 887 echo ${availablePackagesKeys} 888 889 # one per line: 890 #for package in ${availablePackagesKeys} ; do 891 # echo ${package} 892 #done 893} 894 895 896# If no arguments were passed to the script, display its usage and exit. 897if [ "$#" -lt 1 ] ; then 898 DisplayUsage 899 exit 0 900else 901 Init 902fi 903 904# Support `installoptionalpackage <pkg> <pkg> ...` 905if [ "$1" != '-f' ] && [ "$1" != '-l' ] && [ "$1" != '-h' ] \ 906 && [ "$1" != '-s' ]; then 907 BuildListOfRequestedPackages $@ 908 AddPackages 909 exit 0 910fi 911 912# Parse the arguments given to the script. 913while getopts "as:fhl" opt; do 914 case $opt in 915 a) 916 BuildListOfRequestedPackages $@ 917 AddPackages 918 exit 0 919 ;; 920 f) 921 RemoveCachedFiles 922 ListPackages 923 exit 0 924 ;; 925 h) 926 DisplayUsage 927 exit 0 928 ;; 929 l) 930 ListPackages 931 exit 0 932 ;; 933 s) 934 BuildListOfRequestedPackages $@ 935 BuildFinalListOfPackagesToInstall 936 exit 0 937 ;; 938 \?) 939 echo "Invalid option: -$OPTARG" >&2 940 exit 1 941 ;; 942 :) 943 echo "Option -$OPTARG requires an argument." >&2 944 exit 1 945 ;; 946 esac 947done 948