source: pkgtools/makepkg @ b25fc75

Last change on this file since b25fc75 was b25fc75, checked in by Paweł Foremski <pjf@…>, 11 years ago

various minor improvements

  • Property mode set to 100755
File size: 15.4 KB
Line 
1#!/bin/bash
2#
3# makepkg - Lintrack package build tool
4# stripped down, cleaned up and feature enhanced version for Lintrack
5#
6# Copyright (C) 2002-2004 Judd Vinet <jvinet@zeroflux.org>
7# Copyright (C) 2005-2009 ASN Sp. z o.o.
8#
9# Authors: Pawel Foremski <pjf@asn.pl>
10#          Michał Wróbel <maw@asn.pl>
11#
12# This program is free software; you can redistribute it and/or modify it under
13# the terms of the GNU General Public License as published by the Free Software
14# Foundation; either version 2 of the License, or (at your option) any later
15# version.
16#
17# This program is distributed in the hope that it will be useful, but WITHOUT
18# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19# FOR A PARTICULAR PURPOSE.     See the GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License along with
22# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23# Place - Suite 330, Boston, MA 02111-1307, USA.
24#
25
26myver='0.3'
27startdir="`pwd`"
28FB_PKGDEST=${FB_PKGDEST:-$startdir}
29original_args="$@"
30
31### SUBROUTINES ###
32plain() { echo "  $1" >&2; }
33msg() { echo "==> $1" >&2; }
34warning() { echo "==> WARNING: $1" >&2; }
35error() { echo "==> ERROR: $1" >&2; msg "Aborting..."; exit ${2:-1}; }
36
37strip_url() { echo $1 | sed 's|^.*://.*/||g'; }
38
39function usage()
40{
41        cat <<-EOF
42        Lintrack package builder, version $myver
43        Usage: makepkg [options]
44
45        Options:
46          -e, --noextract  Use existing src/ dir
47          -d, --debug      Set \$DEBUG=1 and export to PKGBUILD
48          -o, --nobuild    Download and extract files only
49          -P, --pack       Just make a package of ./pkg/ directory
50          -F <fixrel>      Make a fixrel>1 package of ./pkg/ directory and
51                           FIX-<fixrel> script in main package directory
52                           Hint: you may use <fixrel>=2-big too
53          -w <destdir>     Write package to <destdir> (instead of FB_PKGDEST)
54          -D, --describe   Just print name and version of the package
55          -h, --help       This help
56          -v, --version    Show version information and exit
57        EOF
58}
59
60function version()
61{
62        cat <<-EOF
63        makepkg (Fakebox) $myver
64       
65        Copyright (C) 2005-2009 ASN Sp. z o.o.
66        Copyright (C) 2002-2004 by Judd Vinet <jvinet@zeroflux.org>
67       
68        Authors: Michał Wróbel <maw@asn.pl>
69                 Paweł Foremski <pjf@asn.pl>
70       
71        This is free software; see the source for copying conditions. There is NO
72        warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
73        EOF
74}
75
76# some useful functions imported from dqd installer
77function name_base() { echo $1 | sed -e 's/\/$//' -e 's/.*\///'; }
78function name_dir() { echo $1 | sed -e 's/\/$//' -e 's/\/[^\/]*$//'; }
79
80function realpath()
81{
82        # this parses '~' symbols
83        eval "path=\"\`echo $1\`\""
84
85        if [ "${path:0:1}" = '/' ]; then
86                        curdir=
87        else
88                        curdir="`pwd`"
89        fi
90
91        for part in `echo "$path" | sed -e 's/\// /g'`; do
92                if [ "$part" = '.' ]; then
93                        continue
94                elif [ "$part" = '..' ]; then
95                        curdir="`name_dir $curdir`"
96                elif [ -n "$part" ]; then
97                        curdir="$curdir/$part"
98                fi
99        done
100
101        if [ -z "$curdir" ]; then
102                echo '/'
103        else
104                echo $curdir
105        fi
106}
107
108#
109# commonly used operations
110#
111
112## apply patches from given dir in .
113# @param $1 patch source [$startdir/patches]
114# @param $2 options to "patch" [-p1]
115function patches()
116{
117        local patchopts="${2:--p1}"
118
119        if [ "$NOEXTRACT" = "1" ]; then
120                warning "Skipping source patchning - using existing src/ tree"
121                return
122        fi
123
124        for file in ${1:-$startdir/patches}/*.diff*; do
125                msg "patching with `basename $file`"
126                case "${file##*.}" in
127                        bz2)  bunzip2 -c $file | patch $patchopts || return 1;;
128                        gz)   gunzip -c $file | patch $patchopts || return 1;;
129                        diff) cat $file | patch $patchopts || return 1;;
130                        *)    warning "Unsupported extension: ${file##*.} - skipping patch";;
131                esac
132        done
133}
134
135function files()
136{
137        cp -a ${1:-$startdir/files/*} ${2:-$startdir/pkg/} || return 1
138        find ${2:-$startdir/pkg/} -type f -name .gitignore -exec rm '{}' \;
139}
140
141## builds a package from current dir
142function build_package()
143{
144        local pkgdst files perm ppath pmode puser pgroup file
145
146        case "$1" in
147                "big")
148                        msg "Building big package"; suffix="-big" ;;
149                "small")
150                        msg "Building a stripped-down version of package"; suffix="" ;;
151                *)
152                        warning "Don't know how to build \"$1\" package"; return ;;
153        esac
154
155        msg "  Generating .FILELIST file..."
156        tar cvf /dev/null * | sort > .FILELIST
157
158        # size and time changes, so do it here
159        msg "  Generating .PKGINFO file..."
160        (
161                echo "# Generated by makepkg $myver (Fakebox)"
162                echo "# `date`"
163                echo "pkgname=\"$pkgname\""
164                echo "pkgver=\"$pkgver-$pkgrel-1${suffix}\""
165                echo "builddate=\"`date -u '+%a %b %e %H:%M:%S %Y'`\""
166                echo "packager=\"${PACKAGER:-Lintrack (http://www.lintrack.org/)}\""
167                echo "size=\"`du -cb . | tail -n 1 | awk '{print \$1}'`\""
168
169                [ -n "$CARCH" ] && echo "arch=\"$CARCH\""
170        ) > .PKGINFO
171
172        msg "  Compressing..."
173        pkgdst="$FB_PKGDEST/$pkgname-$pkgver-$pkgrel-1${suffix}.pkg.tar"
174        files="* .PKGINFO .FILELIST"
175        [ -f .INSTALL ] && files="$files .INSTALL"
176
177        #
178        # Below we implement a flexible way to define final file permissions and ownership by passing us
179        # the $perms array of which each element is in the following format: 'path mode user group'
180        #
181        # Implementation is hackish, but this is caused by no option/way in GNU tar to specify a list
182        # for file permissions and ownership.
183        #
184
185        # tar all files except listed ones, as root:root
186        for perm in "${perms[@]}"; do
187                set $perm
188                echo "${1%%/}"
189                [ -d "$1" ] && echo "${1%%/}/*"
190        done \
191                | tr ' ' '\n' \
192                | tar -c --owner 0 --group 0 -f "$pkgdst" -X - $files \
193                2> /dev/null
194
195        # now add the rest with requested perms
196        for perm in "${perms[@]}"; do
197                set $perm
198                ppath="$1"; pmode="$2"; puser="$3"; pgroup="$4"
199                tar -r --mode "$pmode" --owner "$puser" --group "$pgroup" -f "$pkgdst" $ppath
200        done
201
202        # finally, gzip
203        gzip -9f "$pkgdst"
204}
205
206
207### MAIN ###
208export LC_ALL=""
209export LANG=""
210
211# options
212NOEXTRACT=0
213NOBUILD=0
214JUSTPACK=0
215FIXREL=1
216
217ARGLIST=$@
218while [ "$#" -ne "0" ]; do
219        case $1 in
220                --debug)     export DEBUG=1 ;;
221                --noextract) NOEXTRACT=1 ;;
222                --nobuild)   NOBUILD=1 ;;
223                --pack)      JUSTPACK=1 ;;
224                --describe)  DESCRIBE=1 ;;
225                --help)      usage; exit 0 ;;
226                --version)   version; exit 0 ;;
227                --*)         usage; exit 1 ;;
228                -*)
229                        while getopts "dDehoP:w:vF:-" opt; do
230                                case $opt in
231                                        d) export DEBUG=1 ;;
232                                        D) DESCRIBE=1 ;;
233                                        e) NOEXTRACT=1 ;;
234                                        h) usage; exit 0 ;;
235                                        v) version; exit 0 ;;
236                                        o) NOBUILD=1 ;;
237                                        P) JUSTPACK=1 ;;
238                                        w) FB_PKGDEST=$OPTARG ;;
239                                        F) FIXREL=$OPTARG ;;
240                                        -) OPTIND=0; break ;;
241                                        *) usage; exit 1 ;;
242                                esac
243                        done
244                        ;;
245                *) true ;;
246        esac
247        shift
248done
249
250# convert a (possibly) relative path to absolute
251FB_PKGDEST="`realpath $FB_PKGDEST`"
252mkdir -p $FB_PKGDEST
253
254# unset special variables
255unset pkgname pkgver pkgrel md5sums source install build smalldel perms pkg_done
256umask 0022
257
258# default to nop
259pkg_done() { true; }
260customize_small() { true; }
261
262### prepare to build
263BUILDSCRIPT="./PKGBUILD"
264if [ ! -f "$BUILDSCRIPT" ]; then
265        msg "$BUILDSCRIPT does not exist in cwd. Searching in parent directories..."
266        while [ ! "`pwd`" = "/" ]; do
267                cd ..
268                [ -f "$BUILDSCRIPT" ] && break
269        done
270
271        [ ! -f "$BUILDSCRIPT" ] && error "Couldn't find $BUILDSCRIPT"
272        msg "$BUILDSCRIPT found in `pwd`."
273        startdir=`pwd`
274fi
275source $BUILDSCRIPT
276
277if [ -n "$gitpaths" ]; then
278        # scan and extend gitpaths and gitfiles
279        gitfiles=""
280        for gitpath in $gitpaths; do
281                git_repo=`readlink -f ./\`git rev-parse --show-cdup\``
282                eval `{
283                        echo \$gitpath
284                        git ls-tree --name-only -r HEAD \$gitpath
285                } | {
286                        while read file; do
287                                [ -h \$file ] || continue
288                                [ -e \`readlink \$file\` ] || continue
289                                t=\`readlink -f \$file\`
290                                if [[ "\${t#\$git_repo}" !=  "\$t" ]]; then
291                                        if [ -d $t ]; then
292                                                gitpaths="\$gitpaths \$t"
293                                        else
294                                                gitfiles="\$gitfiles \$t"
295                                        fi
296                                fi
297                        done
298                        echo "gitpaths=\"\$gitpaths\""
299                        echo "gitfiles=\"\$gitfiles\""
300                }`
301        done
302
303        # get their revs in HEAD
304        head=`git log --pretty=format:%H -n1 $gitpaths $gitfiles`
305        { [[ $? -eq 0 ]] && [[ -n "$head" ]]; } \
306                || error "cannot build the pkgver variable (git commit needed?)"
307
308        pkgver=`git describe --all --always $head | sed -re 's/^[^0-9]*//' -e 's/-/_/g' -e 's;/;_;g'`
309        dirty="`git diff-index --name-only --relative $head $gitpaths $gitfiles`"
310
311        # do the same locally on every gitpath, because it can be a submodule
312        for dir in $gitpaths; do
313                [ "$dir" = "." ] && continue
314                # XXX this should be a fully recursive operation, i.e. we should explicitly look for
315                # submodules and then for subsubmodules, etc. instead of blindly trying all gitpaths
316                for this in `(
317                        cd $dir
318                        git_repo=\`readlink -f ./\\\`git rev-parse --show-cdup\\\`\`
319                        git ls-tree --name-only -r HEAD . | {
320                                while read file; do
321                                        [ -h \$file ] || continue
322                                        [ -e \`readlink \$file\` ] || continue
323                                        t=\`readlink -f \$file\`
324                                        [[ "\${t#\$git_repo}" !=  "\$t" ]] || continue
325                                        echo \$t
326                                done
327                        } | xargs git diff-index --name-only --relative HEAD .
328                )`; do
329                        dirty="$dirty $dir/$this"
330                done
331        done
332
333        if [ -n "$dirty" ]; then
334                lastmod=`echo "$dirty" | xargs ls -lRL --full-time 2>/dev/null \
335                        | awk '{if (NF>=9) {print $6" "$7" "$8}}' | sort | tail -n1`
336                pkgver=${pkgver}_`date +%Y.%m.%d_%H.%M.%S -d "$lastmod"`
337
338                # $dirty probably has a lot of duplicates, so let's get rid of them
339                for i in $dirty; do
340                        readlink -f $i
341                done | sort -u | while read file; do
342                        echo "$file is dirty" >&2
343                done
344        fi
345
346        pkgrel=1
347        msg "pkgver-pkgrel set to $pkgver-$pkgrel"
348fi
349
350[ `echo $pkgver | grep '-'` ] && error "pkgver is not allowed to contain hyphens."
351[ `echo $pkgrel | grep '-'` ] && error "pkgrel is not allowed to contain hyphens."
352
353if [ "$DESCRIBE" = "1" ]; then
354        echo $pkgname-$pkgver-$pkgrel-$FIXREL
355        exit
356fi
357
358msg "Making package: $pkgname-$pkgver-$pkgrel-$FIXREL (`date`)"
359cd $startdir
360
361# handle special cases
362if [ "$JUSTPACK" = "1" ]; then
363        cd pkg/
364        build_package small
365        msg "Done"
366        exit 0
367elif [ "$FIXREL" != "1" ]; then
368        msg "Creating a fixrel package..."
369        cd pkg/
370
371        files="*"
372        [ -f ../FIX-$FIXREL ] && {
373                msg "  Copying FIX-$FIXREL script"
374                cp ../FIX-$FIXREL .FIX
375                files="$files .FIX"
376        }
377
378        msg "  Compressing..."
379        tar -cP --owner 0 --group 0 $files | gzip -9 \
380                > "$FB_PKGDEST/$pkgname-$pkgver-$pkgrel-$FIXREL.pkg.tar.gz"
381
382        msg "Done"
383        exit 0
384fi
385
386# retrieve sources
387msg "Retrieving sources..."
388mkdir -p $FB_PKGDW
389cd $FB_PKGDW
390
391for netfile in ${source[@]}; do
392        file=`strip_url $netfile`
393
394        if [ -f $file ]; then
395                msg "    Found $file in sources dir"
396        else
397                [ -z "$FB_FTPAGENT" ] && error "FB_FTPAGENT is not configured."
398                ftpclient=`echo $FB_FTPAGENT | awk {'print $1'}`
399                [ -z "`which $ftpclient 2> /dev/null`" ] && error "ftpclient `basename $ftpclient` is not installed."
400
401                proto=`echo $netfile | sed 's|://.*||'`
402                [ "$proto" != "ftp" -a "$proto" != "http" -a "$proto" != "https" ] && \
403                        error "$netfile was not found in the build directory and is not a proper URL."
404
405                msg "    Downloading $file"
406                $FB_FTPAGENT $netfile 2>&1
407                [ ! -f $file ] && error "Failed to download $file"
408        fi
409done
410
411if [ "$NOEXTRACT" = "1" ]; then
412        warning "Skipping source extraction and integrity checks -- using existing src/ dir"
413else
414        warning "Deleting existing src/ dir -- consult -e option"
415        rm -fr $startdir/src
416        mkdir -p $startdir/src
417
418        # MD5 validation
419        if [ ${#md5sums[@]} -ne ${#source[@]} ]; then
420                error "MD5 sums are missing or incomplete. Cannot verify source integrity."
421        elif [ `type -p md5sum` ]; then
422                msg "Validating source files with MD5 sums"
423                errors=0
424                idx=0
425                for netfile in ${source[@]}; do
426                        file=`strip_url $netfile`
427                        echo -n "    $file ... "
428                        echo "${md5sums[$idx]}  $file" | md5sum -c - >/dev/null
429                        if [ $? -ne 0 ]; then
430                                echo "FAILED"
431                                errors=1
432                        else
433                                echo "Passed"
434                        fi
435                        let idx++
436                done
437
438                [ $errors -gt 0 ] && error "One or more files did not pass the validity check!"
439        else
440                warning "The md5sum program is missing. Cannot verify source files!"
441                sleep 1
442        fi
443
444        msg "Extracting sources..."
445        cd $startdir/src
446
447        for netfile in ${source[@]}; do
448                unziphack=0
449                file=`strip_url $netfile`
450                unset cmd
451                case $file in
452                        *.tar.gz|*.tar.Z|*.tgz)
453                                cmd="tar --use-compress-program=gzip -xf $FB_PKGDW/$file" ;;
454                        *.tar.bz2)
455                                cmd="tar --use-compress-program=bzip2 -xf $FB_PKGDW/$file" ;;
456                        *.tar)  cmd="tar -xf $FB_PKGDW/$file" ;;
457                        *.zip)  unziphack=1; cmd="unzip -qqo $FB_PKGDW/$file" ;;
458                        *.gz)   cmd="zcat $FB_PKGDW/$file > ${file%.gz}" ;;
459                        *.bz2)  cmd="bzcat $FB_PKGDW/$file > ${file%.bz2}" ;;
460                        *)      cmd="cp $FB_PKGDW/$file ${file}" ;;
461                esac
462
463                if [ "$cmd" != "" ]; then
464                        msg "    $cmd"
465                        $cmd || {
466                                # unzip will return a 1 as a warning, it is not an error
467                                [ "$unziphack" != "1" -o $? -ne 1 ] && error "Failed to extract $file"
468                        }
469                fi
470        done
471fi
472
473# check for existing pkg directory
474[ -d $startdir/pkg ] && { msg "Removing existing pkg/ directory..."; rm -rf $startdir/pkg; }
475mkdir -p $startdir/pkg
476
477[ "$NOBUILD" = "1" ] && { msg "Sources are ready."; exit 0; }
478
479### build
480msg "Starting build()..."
481cd $startdir/src
482build 2>&1
483[ $? -gt 0 ] && error "Build failed" 2
484
485### let's package it
486cd $startdir/pkg
487
488# check for an install script
489[ -f ../INSTALL ] && { msg "Copying install script..."; cp ../INSTALL .INSTALL; }
490
491### do tasks for big and small packages
492msg "Fixing permissions"
493chmod -R u+w .
494
495if [ -d usr/share/man ]; then
496        msg "Moving usr/share/man files to usr/man"
497        mkdir -p usr/man
498        cp -a usr/share/man/* usr/man/
499        rm -rf usr/share/man
500fi
501
502msg "Compressing man pages..."
503find ./{usr{,/local,/share},opt/*}/man -type f 2>/dev/null | while read i ; do
504        ext="${i##*.}"
505        fn="${i##*/}"
506
507        if [ "$ext" != "gz" -a "$ext" != "bz2" ]; then
508                # update symlinks to this manpage
509                find ./{usr{,/local,/share},opt/*}/man -lname "$fn" 2> /dev/null | while read ln ; do
510                        rm -f "$ln"
511                        ln -sf "${fn}.gz" "${ln}.gz"
512                done
513                # compress the original
514                gzip -9 "$i"
515        fi
516done
517
518# remove empty directories, if needed
519[ -d usr/share ] && [ -z "`ls -1 usr/share`" ] && rm -r usr/share
520[ -d usr/lib ] && [ -z "`ls -1 usr/lib`" ] && rm -r usr/lib
521
522msg "Removing CVS and .svn dirs..."
523find . -type d -name "CVS" -exec rm -rf {} \; 2> /dev/null
524find . -type d -name ".svn" -exec rm -rf {} \; 2> /dev/null
525
526### build big package
527build_package big
528
529### build normal package
530msg "Removing unnecessary files"
531rm -rf usr/info usr/share/info
532rm -rf usr/doc usr/share/doc
533rm -rf usr/docs usr/share/docs
534rm -rf usr/share/locale
535rm -fr usr/man
536rm -rf usr/lib/pkgconfig
537rm -fr usr/include
538
539msg "Removing static libraries"
540find -name '*.a' -exec rm {} \;
541
542# remove empty dir, if needed
543[ -d usr/lib ] && [ -z "`ls -1 usr/lib`" ] && rm -r usr/lib
544
545msg "Stripping debugging symbols from kernel modules..."
546find ./lib/modules -type f -name "*.o" -or -name "*.ko" \
547        -exec strip -g '{}' \; 2>&1 \
548        | grep -v "No such file" | grep -v "format not recognized"
549
550msg "Stripping debugging symbols from libraries..."
551find ./{,usr,usr/local,opt/*}/lib -type f \
552        -not -name "*.dll" -not -name "*.exe" -not -name "*.o" -not -name "*.ko" \
553        -exec strip -s '{}' \; 2>&1 \
554        | grep -v "No such file" | grep -v "format not recognized"
555
556msg "Stripping symbols from binaries..."
557find ./{,usr,usr/local,opt/*}/{bin,sbin} -type f \
558        -not -name "*.dll" -not -name "*.exe" \
559        -exec strip -s '{}' \; 2>&1 \
560        | grep -v "No such file" | grep -v "format not recognized"
561
562# remove requested files and dirs
563for delme in "${smalldel[@]}"; do
564        if echo "$delme" | egrep -q '^/'; then
565                warning "Not deleting '$delme', as it's given as an absolute path and can harm your system"
566                continue
567        fi
568        msg "Removing $delme"
569        rm -fr $delme
570done
571
572customize_small
573
574build_package small
575
576### DONE
577cd $startdir
578
579msg "Finished making: $pkgname (`date`)"
580echo "$FB_PKGDEST/$pkgname-$pkgver-$pkgrel-1-big.pkg.tar.gz"
581
582pkg_done
583
584exit 0
585
586# vim: textwidth=100
Note: See TracBrowser for help on using the repository browser.