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: