[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

dpkg-source: prototype script



The script below is my prototype for extracting and building new
format source archives, as have been discussed on and off here on this
list.

The new format has a number of advantages:
 * Integrates a real copy of the original source, so that to build
   a new source package (which used to consist of tar and diff) you
   don't have to download the original source from anywhere.
 * Doesn't encourage people to patch an already-patched source.
 * Only one file per package.

The new format source archive is a .tar.gz file containing the
undebianised source (repackaged slightly) and a `unified' format patch
to apply to turn the undebianised into the debianised source.

As an example, the hello-1.3-4 package, when put into a new format
source archive, is a tarfile looking like this:
 -rw-rw-r-- ijackson/ijackson 8773 Feb 27 18:14 1996 hello-1.3-4.diff
 drwxrwsr-x ijackson/ijackson    0 Feb 26 03:14 1996 hello-1.3.orig/
 -rw-rw-r-- ijackson/ijackson 5207 Feb 26 03:14 1996 hello-1.3.orig/hello.c
 ...

The first file must be named <package>-<version>-<revision>.diff, and
the rest of the tarfile must start with the directory
<package>-<version>.orig (and be entirely contained within that
directory, though the script below doesn't check that).  The original
source has to be made to fit into in this subdirectory (usually by
unpacking it from its original form in whatever way appropriate, and
then renaming the directory to the required form).

People who naively unpack this using tar will see what's going on and
correctly apply the diff to the package.  However, the dpkg-source
script (which will be part of dpkg) should be used by most people, and
definitely by package maintainers.

You say `dpkg-source --unpack hello-1.3-4.tar.gz' and it creates two
directories, hello-1.3 and hello-1.3.orig, containing the debianised
and upstream sources respectively.

You can then edit the hello-1.3 directory as much as you like, and
later say `dpkg-source --build hello-1.3 4'.  This will create the
source package hello-1.3-4.tar.gz, containing the diff and the
contents of the .orig directory.

Questions:
 * Please comment on the details of this proposal.
 * Please try out the script and comment on it.
 * What about written-for-Debian packages ?  Should they be a plain
   gzipped tarfile ?  If so, what checks should dpkg-source do before
   unpacking such a plain gzipped tarfile ?  If not, what `magic'
   should be in the tarfile for dpkg-source to look for ?
 * How do we make sure that package maintainers do (make it easy for
   them to) preserve their modifications from one upstream version to
   the next ?  The usual way to do this is to apply the debian diff to
   the new package and sort out the conflicts by hand.

Wishlist for the script:
 * Check that the source package doesn't contain any files not in the
   subdirectory specified, and doesn't contain any `..' directory
   components.
 * Work with written-for-Debian sources.

Ian.

#!/bin/sh
#

unset GZIP
set -e

ec=1
trap 'rm -f -- "$tmpfile $tmpfile2"; exit $ec' 0

display-usage () {
	cat <<'END'
Usage:
 dpkg-source --unpack <package>-<version>-<revision>.tar.gz
   (Creates <package>-<version>/* and <package>-<version>.orig/*.)
 dpkg-source --build <directory> <revision>
   (Uses <directory> and <directory>.orig to build <directory>-<revision>.tar.gz;
    <directory> is usually <package>-<version>.)
Both use the files
 <package>-<version>-<revision>.diff
 <package>-<version>-<revision>.tar
END
}

signal-error () { echo >&2 "$0: $*"; exit 1; }
bad-usage () { echo >&2 "$0: bad usage: $*"; display-usage; exit 1; }
corrupted () { echo >&2 "$0: corrupted archive: $*"; exit 1; }

if [ "x$1" = x--build ]
then
	[ $# = 3 ] || bad-usage '--build takes a <directory> and a <revision>'
	directory="$2"
	revstring="-$3"
	test -d "$directory" || signal-error "<directory> is not a directory"
	test -d "$directory.orig" || signal-error "<directory> is not a directory"
	tmpfile="$directory$revstring.diff"
	tar="$directory$revstring.tar"
	rm -f -- "$tmpfile"
	set +e
	diff -aruN -- "$directory.orig" "$directory" >"$tmpfile"
	set -e
	test $? = 0 -o $? = 1 || exit 1
	tar -cf "$tar" -- "$tmpfile" "$directory.orig"
	gzip -9f -- "$tar"
	rm -- "$tmpfile"
elif [ "x$1" = x--unpack ]
then
	[ $# = 2 ] || bad-usage '--unpack takes a <pkg>-<ver>-<rev>.tar.gz'
	tar="$2"
	tmpfile="`basename \"$tar\"`.dpkg-src-tmp"
	rm -f -- "$tmpfile"
	gunzip -f <"$tar" >"$tmpfile"
	firstname="`tar -tf $tmpfile | sed -n 1p`"
	case "$firstname" in */*) corrupted "first entry contains slash" ;; esac
	secondname="`tar -tf $tmpfile | sed -n 2p`"
	revision="`echo \"x$firstname\" | sed -e 's/\.diff$//; s/^x.*-//'`"
	basename="`echo \"x$secondname\" | sed -e 's/^x//; s,\.orig/\?$,,'`"
	tmpfile2="$basename-$revision.diff"
	test "x$firstname" = "x$basename-$revision.diff" || \
		corrupted "expected $firstname to be $basename-$revision.diff"
	test "x$secondname" = "x$basename.orig/" \
	  -o "x$secondname" = "x$basename.orig" || \
		corrupted "expected $secondname to be $basename.orig"
	rm -rf -- "$basename" "$basename.orig" "$tmpfile2"
	tar -xf "$tmpfile"
	mv "$basename.orig" "$basename"
	rm -- "$tmpfile2"
	tar -xf "$tmpfile"
	srcext=.dpkg-src-orig
	patch -d "$basename" -p1 -s -u -t -F 0 -b $srcext <"$tmpfile2"
	find "./$basename" -name '*'$srcext -print0 >"$tmpfile"
	xargs <"$tmpfile" -0r rm --
	rm -- "$tmpfile" "$tmpfile2"
else
	bad-usage 'no --build or --unpack'
fi
ec=0


Reply to: