source: pkgtools/makepkg

Last change on this file was e9865a1, checked in by Michał Wróbel <maw@…>, 9 years ago

new gitpaths approach

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