Ticket #4680: installOptionalPackage.sh

File installOptionalPackage.sh, 14.5 KB (added by mmadia, 10 years ago)

Added disclaimer

Line 
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 Optional Packages.
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.sh [-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 packageBlackList=( '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 ! IsPackageBlackListed ${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 IsPackageBlackListed()
275{
276 # IsPackageBlackListed <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 ${packageBlackList[*]} ; 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 IsPackageBlackListed "$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 Optional Packages.'
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