openSUSE / obs-build

OBS build script, can be used with OBS or stand alone
GNU General Public License v2.0
132 stars 184 forks source link

obs-docker-support should be ported to POSIX shell #804

Open fcrozat opened 2 years ago

fcrozat commented 2 years ago

Dockerfile support in obs-build relies on bash being present on the build container used (as obs-docker-support is written for bash and not POSIX shell).

This breaks building Dockerfile based on opensuse busybox image (and potentially other images not shipping bash).

fcrozat commented 2 years ago

Might interest @dirkmueller

dirkmueller commented 2 years ago

I'm currently fixing things for using, not for building. for building without bash is a whole new challenge imho.

this script in particular.

possible bashism in obs-docker-support line 39 (bash arrays, ${name[0|*|@]}):
            globalopts[${#globalopts[@]}]="$1"
possible bashism in obs-docker-support line 51 (bash arrays, ${name[0|*|@]}):
        /usr/bin/zypper -D $LOCAL_REPOS_D "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 57 (${[@|*]#[#]pat} or ${[@|*]%[%]pat}):
        exec /usr/bin/zypper "${globalopts[@]}" "$cmd" -C "${@%/*.repo}"
possible bashism in obs-docker-support line 57 (bash arrays, ${name[0|*|@]}):
        exec /usr/bin/zypper "${globalopts[@]}" "$cmd" -C "${@%/*.repo}"
possible bashism in obs-docker-support line 64 (bash arrays, ${name[0|*|@]}):
        exec /usr/bin/zypper "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 96 (bash arrays, ${name[0|*|@]}):
            globalopts[${#globalopts[@]}]="$1"
possible bashism in obs-docker-support line 111 (bash arrays, ${name[0|*|@]}):
        /usr/bin/apt-get -o Dir::Etc::SourceList=$LOCAL_APTREPOS_D/obssource -o Dir::Etc::SourceParts=$LOCAL_APTREPOS_D --allow-unauthenticated "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 117 (bash arrays, ${name[0|*|@]}):
        exec /usr/bin/apt-get "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 128 (bash arrays, ${name[0|*|@]}):
            globalopts[${#globalopts[@]}]="$1"
possible bashism in obs-docker-support line 140 (bash arrays, ${name[0|*|@]}):
        /usr/bin/dnf --setopt=reposdir=$LOCAL_REPOS_D "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 146 (bash arrays, ${name[0|*|@]}):
        exec /usr/bin/dnf "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 157 (bash arrays, ${name[0|*|@]}):
            globalopts[${#globalopts[@]}]="$1"
possible bashism in obs-docker-support line 169 (bash arrays, ${name[0|*|@]}):
        /usr/bin/yum --setopt=reposdir=$LOCAL_REPOS_D "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 175 (bash arrays, ${name[0|*|@]}):
        exec /usr/bin/yum "${globalopts[@]}" "$cmd" "$@"
possible bashism in obs-docker-support line 191 (bash arrays, ${name[0|*|@]}):
                cmd[${#cmd[@]}]="file:$DATA_DIR/build-webcache/$urlsha256"
possible bashism in obs-docker-support line 193 (bash arrays, ${name[0|*|@]}):
                cmd[${#cmd[@]}]="localhost:80/build-webcache/$urlsha256"
possible bashism in obs-docker-support line 203 (bash arrays, ${name[0|*|@]}):
            cmd[${#cmd[@]}]="$1"
possible bashism in obs-docker-support line 209 (bash arrays, ${name[0|*|@]}):
        cmd[${#cmd[@]}]="-o"
possible bashism in obs-docker-support line 210 (bash arrays, ${name[0|*|@]}):
        cmd[${#cmd[@]}]="$oname"
possible bashism in obs-docker-support line 212 (bash arrays, ${name[0|*|@]}):
    exec /usr/bin/curl "${cmd[@]}"
possible bashism in obs-docker-support line 241 (echo -e):
            (echo -n -e "PUT /$n HTTP/1.1\r\nContent-Length: $(wc -c < /tmp/packages)\r\n\r\n" | cat - /tmp/packages && read -t 600 ans ; case "$ans" in *\ 200\ *) ;; *) echo "$ans" >&2 ;; esac) <>/dev/tcp/localhost/80 1>&0
possible bashism in obs-docker-support line 241 (read with option other than -r):
            (echo -n -e "PUT /$n HTTP/1.1\r\nContent-Length: $(wc -c < /tmp/packages)\r\n\r\n" | cat - /tmp/packages && read -t 600 ans ; case "$ans" in *\ 200\ *) ;; *) echo "$ans" >&2 ;; esac) <>/dev/tcp/localhost/80 1>&0
possible bashism in obs-docker-support line 241 (/dev/(tcp|udp)):
            (echo -n -e "PUT /$n HTTP/1.1\r\nContent-Length: $(wc -c < /tmp/packages)\r\n\r\n" | cat - /tmp/packages && read -t 600 ans ; case "$ans" in *\ 200\ *) ;; *) echo "$ans" >&2 ;; esac) <>/dev/tcp/localhost/80 1>&0
coolo commented 2 years ago

If you wanted this to be portable you would avoid shell to begin with and write it in a compiled programming language. Perhaps you can interest ... Alberto :)

aplanas commented 2 years ago

cc: @aplanas

mlschroe commented 2 years ago

I tried that a couple of weeks ago but not having array support makes things super ugly.

dirkmueller commented 2 years ago

If you wanted this to be portable you would avoid shell to begin with and write it in a compiled programming language. Perhaps you can interest ... Alberto :)

a compiled language makes multiple architecture support and cross compiling not really any easier.

@fcrozat can you give a self contained example that you'd like to see working? maybe we can find a shortcut by fixing only the breaking cases.

fcrozat commented 2 years ago

I was trying to build https://github.com/fcrozat/rclone-container/blob/master/Dockerfile.busybox on OBS (I've switched to another base container for now..)

coolo commented 2 years ago

The problem here is that the obs-docker-support shouldn't even run on your target, but within the builder. Because obs-docker-support fails to add a zypper repo - which you don't even want in your target.

coolo commented 2 years ago

If you remove the bashisms by brute force you see what it's trying to do:

[   15s] [1/3] STEP 1/4: FROM opensuse/busybox AS target
[   15s] [1/3] STEP 2/4: COPY .obs-docker-support /usr/local/sbin/obs-docker-support
[   15s] [1/3] STEP 3/4: RUN obs-docker-support --install
[   16s] [1/3] STEP 4/4: RUN obs-docker-support --uninstall

Pretty useless if you ask me. So possibly not copying obs-docker-support into the target if there are no zypper actions is the easier goal

coolo commented 2 years ago

Or split obs-docker-support --install from the remains. I.e. make it 2 scripts. If you need zypper/apt-get you will need to have bash as well.

mlschroe commented 2 years ago

obs-docker-support does more than intercept zypper.

mlschroe commented 2 years ago

I wonder if just changing the shebang to /bin/sh would be enough.

coolo commented 2 years ago

No, busybox-sh also takes offense on the cmd=() and globalopts=() declarations

coolo commented 2 years ago

https://github.com/openSUSE/obs-build/pull/806 pushes it a little further

mlschroe commented 2 years ago

(Unrelated: currently you need to use zypper --installroot=/tmp/chroot to make the parsing work. I'll add support to make it also work without the =)

coolo commented 2 years ago

And btw: the way you copy the chroot, you will have glibc and busybox in both the base layer and in your rclone layer.

fcrozat commented 2 years ago

And btw: the way you copy the chroot, you will have glibc and busybox in both the base layer and in your rclone layer.

thanks, I'll try to fix that (I was initially using BCI micro image, which doesn't have busybox)

coolo commented 2 years ago

Just for PoC this saves 12MB in the final layer without impacting the actual container image:

RUN mkdir /tmp/newroot
RUN for f in usr/bin/rclone usr/lib/sysimage/rpm/Index.db usr/lib/sysimage/rpm/Packages.db usr/share/licenses/rclone/COPYING; do mkdir -p /tmp/newroot/$(dirname $f); cp -a /tmp/chroot/$f /tmp/newroot/$f; done