Whamcloud - gitweb
r=adilger,nic
[fs/lustre-release.git] / build / lbuild
1 #!/bin/sh
2
3 TOPDIR=$PWD
4
5 # CVSROOT is inherited from the environment
6 KERNELDIR=
7 LINUX=
8 LUSTRE=
9 RELEASE=0
10 DO_SRC=0
11 DOWNLOAD=1
12 TAG=
13 TARGET=
14 TARGET_ARCHS=
15 CONFIGURE_FLAGS=
16 EXTERNAL_PATCHES=
17 EXTRA_VERSION=
18 STAGEDIR=
19
20 # from target file
21 KERNEL=
22 SERIES=
23 CONFIG=
24 VERSION=
25
26 RHBUILD=0
27 SUSEBUILD=0
28 LINUX26=0
29 SUSEBUILD=0
30
31 BASE_ARCHS=
32 BIGMEM_ARCHS=
33 BOOT_ARCHS=
34 JENSEN_ARCHS=
35 SMP_ARCHS=
36 BIGSMP_ARCHS=
37 PSERIES64_ARCHS=
38 UP_ARCHS=
39
40 DATE=$(date)
41
42 USE_DATESTAMP=1
43 RPMBUILD=
44
45 export CC=${CC:-gcc}
46
47 # Readlink is not present on some older distributions: emulate it.
48 readlink() {
49     local path=$1 ll
50
51     if [ -L "$path" ]; then
52         ll="$(LC_ALL=C ls -l "$path" 2> /dev/null)" &&
53         echo "${ll/* -> }"
54     else
55         return 1
56     fi
57 }
58
59 cleanup()
60 {
61     true
62 }
63
64 error()
65 {
66     [ "$1" ] && echo -e "\n${0##*/}: $1"
67 }
68
69 fatal()
70 {
71     cleanup
72     error "$2"
73     exit $1
74 }
75
76 is_release()
77 {
78     (( $RELEASE )) || return 0
79 }
80
81 list_targets()
82 {
83     echo -n "Available targets:"
84     for target in $TOPDIR/lustre/lustre/kernel_patches/targets/*.target ; do
85         target_file=${target##*/}
86         echo -n " ${target_file%%.target}"
87     done
88     echo
89 }
90
91 usage()
92 {
93     cat <<EOF
94 Usage: ${0##*/} [OPTION]... [-- <lustre configure options>]
95
96   -d CVSROOT
97     Specifies the CVS Root to use when pulling files from CVS.  The
98     environment variable \$CVSROOT is used if this option is not
99     present.
100
101   --external-patches=EXTERNAL_PATCHES
102     Directory similar to lustre/lustre/kernel_patches/ that lbuild should
103     look for seres and config files in before looking in the lustre
104     tree.
105
106   --extraversion=EXTRAVERSION
107     Text to use for the rpm release and kernel extraversion.
108
109   --kerneldir=KERNELDIR
110     Directory containing Linux source tarballs referenced by target
111     files.
112
113   --linux=LINUX
114     Directory of Linux kernel sources.  When this option is used, only
115     Lustre modules and userspace are built.
116
117   --lustre=LUSTRE
118     Path to an existing lustre source tarball to use instead of
119     pulling from CVS.
120
121   --nodownload
122     Do not try to download a kernel from ftp.lustre.org
123
124   --nosrc
125     Do not build a .src.rpm, a full kernel patch, or a patched kernel
126     tarball.
127
128   --publish
129     Unused.
130
131   --release
132     Specifies that the files generated do not include timestamps, and
133     that this is an official release.
134
135   --src
136     Build a .src.rpm, a full kernel patch, and a patched kernel tarball.
137
138   --stage=DIR
139     Directory used to stage packages for release.  RPMs will be placed
140     more or less in DIR/<target>-<arch>, and the tarball will be
141     placed in DIR.
142
143   --tag=TAG
144     A CVS branch/tag name to build from when pulling from CVS.
145
146   --target=TARGET
147     The name of the target to build.  The available targets are listed
148     below.
149
150   --target-archs=TARGET_ARCHS
151     A (space delimited) list of architectures to build.  By default,
152     all of the archs supported by the TARGET will be built, in
153     addition to a .src.rpm.  This option can limit those, for machines
154     that can only build certain archs or if you only want a certain
155     arch built (for testing, or a one-off kernel).
156
157     Also note that by using a non-"base" arch (eg, i386) only kernels
158     will be built - there will be no lustre-lite-utils package.
159
160   --disable-datestamp
161     Prevents the datestamp flag (-D) from being passed to cvs for 
162     checkouts. This is a workaround for a problem encountered when 
163     using lbuild with tinderbox.
164
165 EOF
166
167 #   list_targets
168
169     fatal "$1" "$2"
170 }
171
172 check_options()
173 {
174     if [ "$LUSTRE" ] ; then
175         [ -r "$LUSTRE" ] || \
176             usage 1 "Could not find Lustre source tarball '$LUSTRE'."
177     else
178         [ "$CVSROOT" ] || \
179             usage 1 "Either specify a CVS Root with -d, or a Lustre source tarball with --lustre."
180         [ "$TAG" ] || \
181             usage 1 "A branch/tag name must be specified with --tag when not building from a tarball."
182     fi
183
184     if [ -z "$LINUX" ] ; then
185         [ "$KERNELDIR" ] || \
186             usage 1 "A kernel directory must be specified with --kerneldir."
187
188         [ -d "$KERNELDIR" ] || \
189             usage 1 "$KERNELDIR is not a directory."
190
191         if ! (( $RELEASE )) ; then
192             [ "$TAG" ] || \
193                 usage 1 "When building a snapshot, a tag name must be used."
194         fi
195
196         [ "$TARGET" ] || usage 1 "A target must be specified with --target."
197 #       TARGET_FILE="$TOPDIR/lustre/kernel_patches/targets/$TARGET.target"
198 #       [ -r "$TARGET_FILE" ] || \
199 #               usage 1 "Target '$TARGET' was not found."
200     fi
201
202     case $TARGET in
203         2.6-rhel4)
204             CANONICAL_TARGET="rhel-2.6"
205             ;;
206         2.6-suse)
207             CANONICAL_TARGET="suse-2.6"
208             ;;
209         hp_pnnl-2.4)
210             CANONICAL_TARGET="hp-pnnl-2.4"
211             ;;
212         2.6-vanilla \
213             | suse-2.4.21-2 \
214             | rh-2.4 \
215             | rhel-2.4 \
216             | sles-2.4)
217                 CANONICAL_TARGET="$TARGET"
218                 ;;
219     esac
220
221     TIMESTAMP=$(date -d "$DATE" "+%Y%m%d%H%M")
222
223     RPMBUILD=$(which rpmbuild 2>/dev/null | head -1)
224     if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
225         RPMBUILD=$(which rpm 2>/dev/null | head -1)
226         if [ ! "$RPMBUILD" -o "$RPMBUILD" == "" ]; then
227             usage 1 "Could not find binary for making rpms (tried rpmbuild and rpm)."
228         fi
229     fi
230 }
231
232 uniqify()
233 {
234     echo $(echo "$*" | xargs -n 1 | sort -u)
235 }
236
237 load_target()
238 {
239     EXTRA_VERSION_save="$EXTRA_VERSION"
240     for patchesdir in "$EXTERNAL_PATCHES" "$TOPDIR/lustre/lustre/kernel_patches" ; do
241         TARGET_FILE="$patchesdir/targets/$TARGET.target"
242         [ -r "$TARGET_FILE" ] && break
243     done
244     [ -r "$TARGET_FILE" ] || \
245         fatal 1 "Target $TARGET was not found."
246
247     echo "Loading target config file $TARGET.target..." 
248
249     . "$TARGET_FILE"
250
251     [ "$KERNEL"  ] || fatal 1 "Target $TARGET did not specify a kernel."
252 #    [ "$SERIES"  ] || fatal 1 "Target $TARGET did not specify a kernel patch series."
253 #    [ "$CONFIG"  ] || fatal 1 "Target $TARGET did not specify a kernel config."
254     [ "$VERSION" ] || fatal 1 "Target $TARGET did not specify a kernel version."
255
256     if [ "$KERNELDIR" ] ; then
257         KERNEL_FILE="$KERNELDIR/$KERNEL"
258         if [ ! -r "$KERNELDIR/$KERNEL" ] ; then
259             if (( $DOWNLOAD )) ; then
260                 echo "Downloading http://ftp.lustre.org/kernels/$CANONICAL_TARGET/old/$KERNEL..."
261                 if ! wget -nv "http://ftp.lustre.org/kernels/$CANONICAL_TARGET/old/$KERNEL" \
262                     -O "$KERNELDIR/$KERNEL" ; then
263                     fatal 1 "Could not download target $TARGET's kernel file $KERNEL from ftp.lustre.org."
264                 fi
265             else
266                 fatal 1 "Target $TARGET's kernel file $KERNEL not found in kernel directory $KERNELDIR."
267             fi
268         fi
269     fi
270
271     if [ "$SERIES" ] ; then
272         for series in $SERIES ; do
273             for patchesdir in "$EXTERNAL_PATCHES" "$TOPDIR/lustre/lustre/kernel_patches" ; do
274                 [ -r "$patchesdir/series/$series" ] && continue 2
275             done
276             fatal 1 "Target $TARGET's series $SERIES could not be found.\nSearched:\n\t$EXTERNAL_PATCHES/series\n\t$TOPDIR/lustre/lustre/kernel_patches/series."
277         done
278     fi
279
280     CONFIG_FILE="$TOPDIR/lustre/lustre/kernel_patches/kernel_configs/$CONFIG"
281     [ -r "$CONFIG_FILE" ] || \
282         fatal 1 "Target $TARGET's config file $CONFIG missing from $TOPDIR/lustre/lustre/kernel_patches/kernel_configs/."
283
284     if [ "$EXTRA_VERSION_save" ] ; then
285         EXTRA_VERSION="$EXTRA_VERSION_save"
286     elif ! (( $RELEASE )) ; then
287         #remove the @VERSION@ (lustre version)
288         EXTRA_VERSION=$(echo $EXTRA_VERSION | sed -e "s/\(.*_lustre\)\..*/\1/")
289         EXTRA_VERSION="${EXTRA_VERSION}-${TAG}.${TIMESTAMP}"
290     fi
291     # EXTRA_VERSION=${EXTRA_VERSION//-/_}
292
293     ALL_ARCHS="$BASE_ARCHS $BIGMEM_ARCHS $BOOT_ARCHS $JENSEN_ARCHS $SMP_ARCHS $BIGSMP_ARCHS $PSERIES64_ARCHS $UP_ARCHS"
294
295     BUILD_ARCHS=
296     for arch in $(uniqify "$ALL_ARCHS") ; do
297         if [ -z "$TARGET_ARCHS" ] || echo "$TARGET_ARCHS" | grep "$arch" >/dev/null 2>/dev/null ; then
298             BUILD_ARCHS="$BUILD_ARCHS $arch"
299         fi
300     done
301     [ "$BUILD_ARCHS" ] || usage 1 "No available target archs to build."
302     echo "Building for: $BUILD_ARCHS"
303 }
304
305 tarflags()
306 {
307     case "$1" in
308         '')
309             fatal 1 "tarflags(): File name argument missing."
310             ;;
311         *.tar.gz | *.tgz)
312             echo 'zxf'
313             ;;
314         *.tar.bz2)
315             echo 'jxf'
316             ;;
317         *.tar)
318             echo 'xf'
319             ;;
320         *)
321             fatal 1 "tarflags(): Unrecognized tar extension in file: $1"
322             ;;
323     esac
324 }
325
326 untar()
327 {
328     echo "Untarring ${1##*/}..."
329     tar $(tarflags "$1") "$1"
330 }
331
332 unpack_lustre()
333 {
334     DIRNAME="lustre-$TAG-$TIMESTAMP"
335     if [ "$LUSTRE" ] ; then
336         untar "$LUSTRE"
337         [ -d lustre ] || ln -sf lustre* lustre
338     else
339         if [ "$USE_DATESTAMP" ]; then
340             DATESTAMP="-D '$DATE'"
341         else
342             DATESTAMP=""
343         fi          
344
345         cvs -d "$CVSROOT" -qz3 co $DATESTAMP -d "$DIRNAME" lustre || \
346             fatal 1 "There was an error checking out toplevel Lustre from CVS."
347         pushd "$DIRNAME" > /dev/null
348         ./lustrecvs "$TAG" || \
349             fatal 1 "There was an error checking out Lustre/Portals/Build from CVS."
350         echo "Creating lustre tarball..."
351         sh autogen.sh || fatal 1 "There was an error running autogen.sh."
352         ./configure --disable-{modules,utils,liblustre,tests,doc} || \
353             fatal 1 "There was an error running ./configure to create makefiles."
354         make dist || fatal 1 "There was an error running 'make dist'."
355         popd > /dev/null
356         fname=`basename $DIRNAME/lustre-*.tar.gz`
357         cp $DIRNAME/$fname . || fatal 1 "There was an error copying lustre tarball."
358         LUSTRE="$PWD/$fname"
359         ln -sf "$DIRNAME" lustre
360     fi
361 }
362
363 unpack_linux()
364 {
365     untar "$KERNEL_FILE"
366     [ -d linux ] || ln -sf linux* linux
367 }
368
369 patch_linux()
370 {
371     [ "$SERIES" ] || return 0
372     FULL_PATCH="$PWD/lustre-kernel-${TARGET}-${EXTRA_VERSION}.patch"
373     [ -f "$FULL_PATCH" ] && rm -f "$FULL_PATCH"
374     pushd linux >/dev/null
375     for series in $SERIES ; do
376         echo -n "Applying series $series:"
377         for patchesdir in "$EXTERNAL_PATCHES" "$TOPDIR/lustre/lustre/kernel_patches" ; do
378             [ -r "$patchesdir/series/$series" ] || continue
379             SERIES_FILE="$patchesdir/series/$series"
380             for patch in $(<"$SERIES_FILE") ; do
381                 echo -n " $patch"
382                 PATCH_FILE="$patchesdir/patches/$patch"
383                 [ -r "$PATCH_FILE" ] || \
384                     fatal 1 "Patch $patch does not exist in Lustre tree."
385                 cat "$PATCH_FILE" >> "$FULL_PATCH" || \
386                     fatal 1 "Error adding patch $patch to full patch."
387                 patch -s -p1 < "$PATCH_FILE" || fatal 1 "Error applying patch $patch."
388             done
389             break
390         done
391         echo
392     done
393     popd >/dev/null
394     echo "Full patch has been saved in ${FULL_PATCH##*/}."
395     echo "Replacing .config files..."
396     [ -d linux/configs ] || mkdir linux/configs || \
397         fatal 1 "Error creating configs directory."
398     rm -f linux/configs/*
399     copysuccess=0
400     for patchesdir in "$EXTERNAL_PATCHES" "lustre/lustre/kernel_patches" ; do
401         [ "$patchesdir" ] && \
402             cp -v $patchesdir/kernel_configs/kernel-${VERSION}-${TARGET}*.config linux/configs/ >/dev/null && copysuccess=1
403     done
404     [ "$copysuccess" = "1" ] || \
405         fatal 1 "Error copying in kernel configs."
406 }
407
408 pack_linux()
409 {
410     TARBALL="$(readlink linux)-$EXTRA_VERSION.tar.gz"
411     echo "Creating patched linux tarball $TARBALL..."
412     tar zcf "$TARBALL" "$(readlink linux)" \
413         --exclude "CVS" --exclude ".cvsignore" || \
414         --exclude "*.orig" --exclude "*~" --exclude "*.rej" || \
415         fatal 1 "Error creating patched Linux tarball."
416 }
417
418 clean_linux()
419 {
420     [ -d linux ] || return 0
421     echo "Cleaning linux..."
422     [ -L linux ] && rm -rf $(readlink linux)
423     rm -rf linux
424 }
425
426 prep_kernel_build()
427 {
428     # make .spec file
429     ENABLE_INIT_SCRIPTS=""
430     sed \
431         -e "s^@BASE_ARCHS@^$BASE_ARCHS^g" \
432         -e "s^@BIGMEM_ARCHS@^$BIGMEM_ARCHS^g" \
433         -e "s^@BIGSMP_ARCHS@^$BIGSMP_ARCHS^g" \
434         -e "s^@BOOT_ARCHS@^$BOOT_ARCHS^g" \
435         -e "s^@CONFIGURE_FLAGS@^$CONFIGURE_FLAGS^g" \
436         -e "s^@ENABLE_INIT_SCRIPTS@^$ENABLE_INIT_SCRIPTS^g" \
437         -e "s^@JENSEN_ARCHS@^$BOOT_ARCHS^g" \
438         -e "s^@KERNEL_EXTRA_VERSION@^$EXTRA_VERSION^g" \
439         -e "s^@KERNEL_RELEASE@^${EXTRA_VERSION//-/_}^g" \
440         -e "s^@KERNEL_SOURCE@^$KERNEL^g" \
441         -e "s^@KERNEL_VERSION@^$VERSION^g" \
442         -e "s^@LINUX26@^$LINUX26^g" \
443         -e "s^@LUSTRE_SOURCE@^${LUSTRE##*/}^g" \
444         -e "s^@LUSTRE_TARGET@^$TARGET^g" \
445         -e "s^@PSERIES64_ARCHS@^$PSERIES64_ARCHS^g" \
446         -e "s^@RHBUILD@^$RHBUILD^g" \
447         -e "s^@SMP_ARCHS@^$SMP_ARCHS^g" \
448         -e "s^@SUSEBUILD@^$SUSEBUILD^g" \
449         -e "s^@SUSEBUILD@^$SUSEBUILD^g" \
450         -e "s^@UP_ARCHS@^$UP_ARCHS^g" \
451         < $TOPDIR/lustre/build/lustre-kernel-2.4.spec.in \
452         > lustre-kernel-2.4.spec
453     [ -d SRPMS ] || mkdir SRPMS
454     [ -d RPMS ] || mkdir RPMS
455     [ -d BUILD ] || mkdir BUILD
456     [ -d SOURCES ] || mkdir SOURCES
457     for script in linux-{rhconfig.h,merge-config.awk,merge-modules.awk} \
458         suse-{functions.sh,post.sh,postun.sh,trigger-script.sh.in} \
459         sles8-{pre,post,postun,update_{INITRD_MODULES,rcfile_setting}}.sh ; do
460         cp $TOPDIR/lustre/build/$script SOURCES
461     done
462     cp "$LUSTRE" "$KERNEL_FILE" SOURCES
463     if [ "$EXTERNAL_PATCHES" -a -d "$EXTERNAL_PATCHES" ] ; then
464         tar zcf SOURCES/external-patches.tar.gz -C "$EXTERNAL_PATCHES" series targets patches kernel_configs
465     else
466         touch SOURCES/external-patches.tar.gz
467     fi
468 }
469
470 clean_lustre()
471 {
472     [ -d lustre ] || return 0
473     echo "Cleaning Lustre..."
474     [ -L lustre ] && rm -rf $(readlink lustre)
475     rm -rf lustre
476 }
477
478 build_kernel()
479 {
480     echo "Building kernel + Lustre RPMs for: $BUILD_ARCHS..."
481     targets=
482     for arch in $BUILD_ARCHS ; do
483         targets="--target $arch $targets"
484     done
485
486     $RPMBUILD $targets -bb lustre-kernel-2.4.spec \
487         --define "_topdir $TOPDIR" || \
488         fatal 1 "Error building rpms for $BUILD_ARCHS."
489
490     if (( $DO_SRC )) ; then
491         $RPMBUILD -bs lustre-kernel-2.4.spec \
492             --define "_topdir $TOPDIR" || \
493             fatal 1 "Error building .src.rpm."
494     fi
495 }
496
497 build_lustre()
498 {
499     [ -d SRPMS ] || mkdir SRPMS
500     [ -d RPMS ] || mkdir RPMS
501     [ -d BUILD ] || mkdir BUILD
502     [ -d SOURCES ] || mkdir SOURCES
503
504     cp "$LUSTRE" SOURCES
505
506     pushd lustre >/dev/null
507
508     echo "Building Lustre RPMs for: $BUILD_ARCHS..."
509     targets=
510     for arch in $BUILD_ARCHS ; do
511         targets="--target $arch $targets"
512     done
513
514     ./configure "--with-linux=${LINUX}" ${CONFIGURE_FLAGS}
515
516     $RPMBUILD $targets -bb build/lustre.spec \
517         --define "_topdir $TOPDIR" || \
518         fatal 1 "Error building rpms for $BUILD_ARCHS."
519
520     popd >/dev/null
521 }
522
523 stage()
524 {
525     [ -z "$STAGEDIR" ] && return
526
527     for arch in $BUILD_ARCHS ; do
528         rpmdir="${STAGEDIR}/${CANONICAL_TARGET}-${arch}"
529         echo "${0##*/}: Copying RPMs into ${rpmdir}"
530         mkdir -p "${rpmdir}"
531         cp -v RPMS/${arch}/*.rpm "${rpmdir}"
532         if [ -d RPMS/noarch ] ; then
533             cp -v RPMS/noarch/*.rpm "${rpmdir}"
534         fi
535     done
536
537     cp -v "$LUSTRE" "$STAGEDIR"
538 }
539
540 [ -r ~/.lbuildrc ] && . ~/.lbuildrc
541
542 options=$(getopt -o d:D:h -l disable-datestamp,external-patches:,extraversion:,kerneldir:,linux:,lustre:,nodownload,nosrc,publish,release,stage:,tag:,target:,target-archs:,with-linux: -- "$@")
543
544 if [ $? != 0 ] ; then
545     usage 1
546 fi
547
548 eval set -- "$options"
549     
550 while [ "$1" ] ; do
551     case "$1" in
552         '')
553             usage 1
554             ;;
555         -d)
556             CVSROOT=$2
557             shift 2
558             ;;
559         -D)
560             DATE=$2
561             shift 2
562             ;;
563         --external-patches)
564             EXTERNAL_PATCHES=$2
565             shift 2
566             ;;
567         --extraversion)
568             EXTRA_VERSION=$2
569             shift 2
570             ;;
571         --help | -h)
572             usage 0
573             ;;
574         --kerneldir)
575             KERNELDIR=$2
576             shift 2
577             ;;
578         --linux | --with-linux)
579             LINUX=$2
580             shift 2
581             ;;
582         --lustre)
583             LUSTRE=$2
584             shift 2
585             ;;
586         --nodownload)
587             DOWNLOAD=0
588             shift 1
589             ;;
590         --nosrc)
591             DO_SRC=0
592             shift 1
593             ;;
594         --publish)
595             shift
596             ;;
597         --release)
598             RELEASE=1
599             shift
600             ;;
601         --src)
602             DO_SRC=1
603             shift 1
604             ;;
605         --stage)
606             STAGEDIR=$2
607             shift 2
608             ;;
609         --tag)
610             TAG=$2
611             shift 2
612             ;;
613         --target)
614             TARGET=$2
615             shift 2
616             ;;
617         --target-archs)
618             TARGET_ARCHS=$2
619             shift 2
620             ;;
621         --disable-datestamp)
622             USE_DATESTAMP=
623             shift
624             ;;
625         --)
626             shift
627             CONFIGURE_FLAGS=$@
628             break
629             ;; 
630         *)
631             usage 1 "Unrecognized option: $1"
632             ;;
633     esac
634 done
635
636 check_options
637
638 unpack_lustre
639
640 # prep_build needs the .spec.in from the lustre source
641 if [ -z "$LINUX" ] ; then
642     load_target
643
644     if (( $DO_SRC )) ; then
645         unpack_linux
646         patch_linux
647         pack_linux
648         clean_linux
649     fi
650
651     prep_kernel_build
652     clean_lustre
653
654     build_kernel
655 else
656     build_lustre
657 fi
658
659 stage