Package: git-buildpackage
Version: 0.6.0~git20120822
Severity: normal

Good day-

I've found that I occasionally need to pass arguments with spaces in
them to pbuilder through git-pbuilder. For example, say I needed to
create a new cowdancer build environment using the distribution
components "main" and "contrib" both (so, I would want to pass
'--components "main contrib"' to pbuilder). 

The way to pass extra arguments to pbuilder through git-pbuilder
(without using a .pbuilderrc) is with $GIT_PBUILDER_OPTIONS, so I would
try that:

    GIT_PBUILDER_OPTIONS='--components "main contrib"' \
    DIST=sid \
    BUILDER=cowbuilder \
        git-pbuilder create

Unfortunately, this fails with the error:

    E: too many parameters for create

Running the same command under bash -x sheds some extra light on the
problem:

    + set -e
    + BACKPORTS=http://backports.debian.org/debian-backports
    + default_BUILDER=pbuilder
    + default_DIST=pbuilder
    + default_BUILDER=pbuilder
    + case $default_BUILDER in
    + default_BUILDER=cowbuilder
    + case $default_BUILDER in
    + case $default_DIST in
    + default_DIST=
    + : cowbuilder
    + : cowbuilder
    + : sid
    + :
    + expr sid : '.*-backports$'
    + EXT=
    + '[' '!' -x /usr/sbin/cowbuilder ']'
    + OPTIONS='--components "main contrib"'
    + OUTPUT_DIR=../
    + '[' no '!=' '' ']'
    + case $BUILDER in
    + : /var/cache/pbuilder
    + : sid
    + '[' -n '' ']'
    + '[' sid = sid ']'
    + '[' -d /var/cache/pbuilder/base-sid.cow ']'
    + BASE=/var/cache/pbuilder/base.cow
    + OPTIONS='--components "main contrib" --basepath 
/var/cache/pbuilder/base.cow'
    + '[' '!' -d /var/cache/pbuilder/base.cow ']'
    + '[' create '!=' create ']'
    + '[' sid = etch ']'
    + '[' sid = ebo ']'
    + case $1 in
    + action=create
    + shift
    + '[' -f /home/paul/.pbuilderrc ']'
    + '[' no = '' ']'
    + '[' '' = -backports ']'
    + sudo cowbuilder --create --dist sid --components '"main' 'contrib"' 
--basepath /var/cache/pbuilder/base.cow
    E: too many parameters for create

As you can see, the quoting I used in GIT_PBUILDER_OPTIONS is not
respected, despite the language on the man page which seems to imply
that the contents of the variable will undergo additional shell
expansion inside git-pbuilder.

This is a difficult problem to fix within the confines of POSIX sh, but
if we switch to bash, we can make use of the fairly-decent array
functionality in order to keep better track of argument lists. I'm
attaching a patch which does this.

With the patch applied, the command shown above works correctly, and the
chroot environment is created as expected with the noted components.

I also have the given changes available in a git repo at

    https://github.com/thepaul/git-buildpackage.git

To browse the specific changes:

    https://github.com/thepaul/git-buildpackage/commit/cecf2ba5

Thank you for your consideration. Hope this helps-

p


-- System Information:
Debian Release: wheezy/sid
  APT prefers testing
  APT policy: (900, 'testing'), (50, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.2.0-4-amd64 (SMP w/1 CPU core)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages git-buildpackage depends on:
ii  devscripts       2.12.4
ii  git              1:1.8.0-1
ii  python           2.7.3~rc2-1
ii  python-dateutil  1.5+dfsg-0.1

Versions of packages git-buildpackage recommends:
ii  cowbuilder    0.70
ii  pristine-tar  1.25

Versions of packages git-buildpackage suggests:
pn  python-notify  <none>
ii  unzip          6.0-7

-- no debconf information
commit cecf2ba5359b9c3f251dd186c54634e8b04a3edd
Author: paul cannon <p...@spacemonkey.com>
Date:   Thu Nov 8 22:47:55 2012 -0700

    git-pbuilder: use arrays to handle lists of args
    
    ..so that arguments intended for pbuilder or debbuild can have spaces or
    other special characters in them. There was previously no way to
    accomplish this, since git-pbuilder only knows how to split the
    pbuilder-options environment variable on $IFS, without any sort of
    lexing (in its defense, sh/bash makes it a pain).
    
    Change-Id: I869fc00b3ef5c46ee32b6bbd008a0a2c49c8f5ea

diff --git a/bin/git-pbuilder b/bin/git-pbuilder
index fc0f48c..7f0d80f 100644
--- a/bin/git-pbuilder
+++ b/bin/git-pbuilder
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 # $Id: git-pbuilder,v 1.27 2012/01/13 04:12:35 eagle Exp $
 #
 # git-pbuilder -- Wrapper around pbuilder for git-buildpackage
@@ -75,7 +75,8 @@ if [ ! -x /usr/sbin/"$BUILDER" ]; then
 fi
 
 # Default options come from the environment.
-OPTIONS="$GIT_PBUILDER_OPTIONS"
+# eval GIT_PBUILDER_OPTIONS into an array, as some arguments may have quoting
+eval "OPTIONS=( $GIT_PBUILDER_OPTIONS )"
 OUTPUT_DIR="${GIT_PBUILDER_OUTPUT_DIR:-../}"
 
 # How we handle options depends on what type of builder we're using.  Ignore
@@ -94,7 +95,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             : ${DIST:=sid}
             if [ -n "$ARCH" ] ; then
                 BASE="$PBUILDER_BASE/base-$DIST$EXT-$ARCH.tgz"
-                OPTIONS="$OPTIONS --architecture $ARCH"
+                OPTIONS+=( --architecture "$ARCH" )
             elif [ "$DIST" = 'sid' ] ; then
                 if [ -f "$PBUILDER_BASE/base-sid.tgz" ] ; then
                     BASE="$PBUILDER_BASE/base-sid.tgz"
@@ -104,7 +105,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             else
                 BASE="$PBUILDER_BASE/base-$DIST$EXT.tgz"
             fi
-            OPTIONS="$OPTIONS --basetgz $BASE"
+            OPTIONS+=( --basetgz "$BASE" )
 
             # Make sure the base tarball exists.
             if [ ! -f "$BASE" ] && [ "$1" != "create" ]; then
@@ -115,7 +116,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             # Set --debian-etch-workaround if DIST is etch.  Assume that
             # everything else is new enough that it will be fine.
             if [ "$DIST" = 'etch' ] || [ "$DIST" = 'ebo' ] ; then
-                OPTIONS="$OPTIONS --debian-etch-workaround"
+                OPTIONS+=( --debian-etch-workaround )
             fi
             ;;
     
@@ -131,7 +132,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             : ${DIST:=sid}
             if [ -n "$ARCH" ] ; then
                 BASE="$COWBUILDER_BASE/base-$DIST$EXT-$ARCH.cow"
-                OPTIONS="$OPTIONS --architecture $ARCH"
+                OPTIONS+=( --architecture "$ARCH" )
             elif [ "$DIST" = 'sid' ] ; then
                 if [ -d "$COWBUILDER_BASE/base-sid.cow" ] ; then
                     BASE="$COWBUILDER_BASE/base-sid.cow"
@@ -141,7 +142,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             else
                 BASE="$COWBUILDER_BASE/base-$DIST$EXT.cow"
             fi
-            OPTIONS="$OPTIONS --basepath $BASE"
+            OPTIONS+=( --basepath "$BASE" )
     
             # Make sure the base directory exists.
             if [ ! -d "$BASE" ] && [ "$1" != "create" ]; then
@@ -152,7 +153,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
             # Set --debian-etch-workaround if DIST is etch.  Assume that
             # everything else is new enough that it will be fine.
             if [ "$DIST" = 'etch' ] || [ "$DIST" = 'ebo' ] ; then
-                OPTIONS="$OPTIONS --debian-etch-workaround"
+                OPTIONS+=( --debian-etch-workaround )
             fi
             ;;
     
@@ -171,7 +172,7 @@ if [ no != "$GIT_PBUILDER_AUTOCONF" ] ; then
                 echo "Cannot read configuration file $QEMUCONFIG" >&2
                 exit 1
             fi
-            OPTIONS="$OPTIONS --config $QEMUCONFIG"
+            OPTIONS+=( --config "$QEMUCONFIG" )
             ;;
     
         *)
@@ -194,19 +195,19 @@ update|create|login)
     # it.  Instead, check if the user has a .pbuilderrc and, if so, explicitly
     # add it as a configuration file.
     if [ -f "$HOME/.pbuilderrc" ] ; then
-        OPTIONS="$OPTIONS --configfile $HOME/.pbuilderrc"
+        OPTIONS+=( --configfile "$HOME/.pbuilderrc" )
     fi
 
     # Run the builder.
     if [ no = "$GIT_PBUILDER_AUTOCONF" ] ; then
-        sudo "$BUILDER" --"$action" $OPTIONS "$@"
+        sudo "$BUILDER" --"$action" "${OPTIONS[@]}" "$@"
     else
         if [ "$EXT" = '-backports' ] ; then
             OTHERMIRROR="deb $BACKPORTS $DIST$EXT main"
             sudo "$BUILDER" --"$action" --dist "$DIST" \
-                --othermirror "$OTHERMIRROR" $OPTIONS "$@"
+                --othermirror "$OTHERMIRROR" "${OPTIONS[@]}" "$@"
         else
-            sudo "$BUILDER" --"$action" --dist "$DIST" $OPTIONS "$@"
+            sudo "$BUILDER" --"$action" --dist "$DIST" "${OPTIONS[@]}" "$@"
         fi
     fi
     exit $?
@@ -235,18 +236,27 @@ fi
 # or -I flags unless we're using source format 1.0.
 if [ ! -f debian/source/format ] || grep -qs '^1.0' debian/source/format ; then
     echo 'Source format 1.0 detected, adding exclude flags'
-    DEBBUILDOPTS="-i'(?:^|/)\\.git(attributes)?(?:\$|/.*\$)' -I.git $*"
+    DEBBUILDOPTS="-i'(?:^|/)\\.git(attributes)?(?:\$|/.*\$)' -I.git"
 else
-    DEBBUILDOPTS="$*"
+    DEBBUILDOPTS=""
 fi
 
+shell_quote () {
+    echo "$1" | sed -e "s/'/'\"'\"'/g" -e "1 s/^/'/" -e "\$ s/\$/'/"
+}
+
+for arg in "$@"; do
+    DEBBUILDOPTS+=" $(shell_quote "$arg")"
+done
+
 # Now we can finally run pdebuild.  The quoting here is tricky, but this
 # seems to pass everything through properly.
 if [ no = "$GIT_PBUILDER_AUTOCONF" ] ; then
-    pdebuild --pbuilder "$BUILDER" --debbuildopts "$DEBBUILDOPTS" -- $OPTIONS
+    pdebuild --pbuilder "$BUILDER" --debbuildopts "$DEBBUILDOPTS" -- \
+        "${OPTIONS[@]}"
 else
     pdebuild --buildresult $OUTPUT_DIR --pbuilder "$BUILDER" \
-        --debbuildopts "$DEBBUILDOPTS" -- $OPTIONS
+        --debbuildopts "$DEBBUILDOPTS" -- "${OPTIONS[@]}"
 fi
 status="$?"
 if [ -n "`ls ../*_source.changes`" ] ; then

Reply via email to