#!/bin/sh # # Script to automatically install all Wine Staging patches # # Copyright (C) 2015 Sebastian Lackner # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA # # Show usage information usage() {{ echo "" echo "Usage: ./patchinstall.sh [DESTDIR=path] [--all] [-W patchset] [patchset ...]" echo "" echo "Autogenerated script to apply all Wine Staging patches on your Wine" echo "source tree. This script replaces and enhances the old method of" echo "using a Makefile." echo "" echo "Configuration:" echo " DESTDIR=path Specify the path to the wine source tree" echo " --all Select all patches" echo " --force-autoconf Run autoreconf and tools/make_requests after each patch" echo " --help Display this help and exit" echo " --no-patchlist Do not apply patchlist (needed for 'wine --patches')" echo " --no-autoconf Do not run autoreconf and tools/make_requests" echo " -W patchset Exclude a specific patchset" echo "" echo "Backends:" echo " --backend=patch Use regular 'patch' utility to apply patches (default)" echo " --backend=epatch Use 'epatch' to apply patches (Gentoo only)" echo " --backend=git-am Use 'git am' to apply patches" echo " --backend=git-apply Use 'git apply' to apply patches" echo " --backend=stg Import the patches using stacked git" echo "" }} # Critical error, abort abort() {{ echo "ERROR: $1" >&2 exit 1 }} # Show a warning warning() {{ echo "WARNING: $1" >&2 }} {patch_helpers} # Default settings patch_enable_all 0 enable_patchlist=1 enable_autoconf=1 patchlist="/dev/null" backend="patch" enable=1 # Find location of patches patchdir="$(dirname "$(readlink -f "$0")")" if test ! -f "$patchdir/patchinstall.sh"; then if test -f ./patchinstall.sh; then patchdir="$(pwd)" else abort "Failed to find patch directory." fi fi # Parse commandline arguments if test "$#" -eq 0; then abort "No commandline arguments given, don't know what to do." fi while test "$#" -gt 0; do if patch_enable "$1" "$enable"; then shift enable=1 continue fi if test "$enable" -ne 1; then abort "Wrong use of -W commandline argument, expected patchname." fi case "$1" in DESTDIR=*) DESTDIR="${{1#*=}}" shift ;; --all) patch_enable_all 1 shift ;; --backend=*) backend="${{1#*=}}" shift ;; --force-autoconf) enable_autoconf=2 shift ;; --help) usage exit 0 ;; --no-patchlist) enable_patchlist=0 shift ;; --no-autoconf) enable_autoconf=0 shift ;; -W) enable=2 shift ;; *) abort "Unknown commandline argument $1" exit 1 esac done if test "$enable" -ne 1; then abort "Missing argument for -W, expected patchname." fi # Determine DESTDIR if not explicitly specified if test -z "$DESTDIR" -a -f ./tools/make_requests; then DESTDIR="$(pwd)" elif test ! -f "$DESTDIR/tools/make_requests"; then abort "DESTDIR does not point to the Wine source tree." fi # Change directory to DESTDIR, epatch depends on that if ! cd "$DESTDIR"; then abort "Unable to change directory to $DESTDIR." fi # Helper to update configure / the wineserver protocol if required if ! command -v diff >/dev/null 2>&1 || ! command -v grep >/dev/null 2>&1 || ! command -v cmp >/dev/null 2>&1; then update_configure () {{ autoreconf -f }} update_protocol () {{ ./tools/make_requests }} else update_configure () {{ file="./configure" if ! cp -a "$file" "$file.old"; then abort "failed to create $file.old" fi if ! autoreconf -f; then rm "$file.old" return 1 fi # Shifting by 62 bits is undefined behaviour when off_t is 32-bit, see also # https://launchpad.net/ubuntu/+source/autoconf/2.69-6 - the bug is still # present in some other distros (including Archlinux). large_off_old="^#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))$" large_off_new="#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))" sed -i'' -e "s|$large_off_old|$large_off_new|g" "$file" # Restore original timestamp when nothing changed if ! cmp "$file.old" "$file" >/dev/null; then rm "$file.old" else mv "$file.old" "$file" fi return 0 }} update_protocol () {{ file="./include/wine/server_protocol.h" if ! cp -a "$file" "$file.old"; then abort "failed to create $file.old" fi if ! ./tools/make_requests; then rm "$file.old" return 1 fi # Restore original timestamp when nothing changed if diff -u "$file.old" "$file" | grep -v "^[+-]#define SERVER_PROTOCOL_VERSION" | grep -v "^\(+++\|---\)" | grep -q "^[+-]"; then rm "$file.old" else mv "$file.old" "$file" fi return 0 }} fi # Most backends will try to use git, either directly or indirectly. # Unfortunately this does not work when "$DESTDIR" points to a # subdirectory of a git tree, which has the effect that no patches # are applied, but the exitcode is zero. To avoid broken builds we # will workaround this issue or abort. For more information see # https://github.com/wine-compholio/wine-staging/issues/7 test ! -d ".git" && git rev-parse --git-dir >/dev/null 2>&1 workaround_git_bug="$?" # Apply the patches using gitapply.sh, a small wrapper around 'patch' if test "$backend" = "patch"; then if test "$workaround_git_bug" -eq 0; then gitapply_args="--nogit" else gitapply_args="" fi if test "$enable_autoconf" -gt 1; then warning "Ignoring commandline argument --force-autoconf." enable_autoconf=1 fi patch_apply_file () {{ echo "Applying $1" if ! "$patchdir/gitapply.sh" $gitapply_args < "$1"; then abort "Failed to apply patch, aborting!" fi }} # 'epatch' backend - used on Gentoo elif test "$backend" = "epatch"; then if test "$workaround_git_bug" -eq 0; then gitapply_args="--nogit" else gitapply_args="" fi if ! command -v epatch >/dev/null 2>&1 || \ ! command -v ebegin >/dev/null 2>&1 || \ ! command -v eend >/dev/null 2>&1 || \ ! command -v die >/dev/null 2>&1; then abort "Shell functions epatch/ebegin/eend not found. You have to source this script from your ebuild." fi if test "$enable_autoconf" -gt 1; then warning "Ignoring commandline argument --force-autoconf." enable_autoconf=1 fi patch_apply_file () {{ shortname="$(basename "$1")" if grep -q "^GIT binary patch" "$1"; then ebegin "Applying $shortname" if ! "$patchdir/gitapply.sh" $gitapply_args < "$1"; then die "Failed Patch: $1!" fi eend else epatch "$1" # epatch calls die upon failure fi }} # GIT backend - apply patches using 'git am' elif test "$backend" = "git" -o "$backend" = "git-am"; then if test "$workaround_git_bug" -eq 0; then abort "Backend 'git-am' not possible when DESTDIR points to a git subdirectory." fi patch_apply_file () {{ echo "Applying $1" if ! git am "$1"; then abort "Failed to apply patch, aborting!" fi if test "$enable_autoconf" -gt 1; then do_commit=0 # Run 'autoreconf -f' if required if git show --pretty=format: --name-only | grep -q "^\(configure.ac\|aclocal.m4\)$"; then if ! update_configure; then abort "'autoreconf -f' failed." fi git add ./configure git add ./include/config.h.in do_commit=1 fi # Run './tools/make_requests' if required if git show --pretty=format: --name-only | grep -q "^server/"; then if ! update_protocol; then abort "'./tools/make_requests' failed." fi git add ./include/wine/server_protocol.h git add ./server/trace.c git add ./server/request.h do_commit=1 fi if test "$do_commit" -ne 0; then if ! git commit --amend --reuse-message HEAD; then abort "Failed to include autogenerated changes in commit." fi fi fi }} # Git apply backend elif test "$backend" = "git-apply"; then if test "$workaround_git_bug" -eq 0; then abort "Backend 'git-apply' not possible when DESTDIR points to a git subdirectory." fi if test "$enable_autoconf" -gt 1; then warning "Ignoring commandline argument --force-autoconf." enable_autoconf=1 fi patch_apply_file () {{ echo "Applying $1" if ! git apply "$1"; then abort "Failed to apply patch, aborting!" fi }} # Stacked GIT backend - import the patches (mainly for developers) elif test "$backend" = "stg"; then if test "$workaround_git_bug" -eq 0; then abort "Backend 'stg' not possible when DESTDIR points to a git subdirectory." fi # Only import the regular patches, no autogenerated ones - # moreover, don't run autoreconf or ./tools/make_requests. enable_patchlist=0 enable_autoconf=0 patch_apply_file () {{ echo "Applying $1" shortname="$(basename "$1")" if ! echo "staging/$shortname" | cat - "$1" | stg import; then abort "Failed to apply patch, aborting!" fi }} else abort "Selected backend $backend not supported." fi patch_apply () {{ patch_apply_file "$patchdir/$1" }} {patch_resolver} # If autoupdate is enabled then create a tempfile to keep track of all patches if test "$enable_patchlist" -eq 1; then if test "$enable_Staging" -eq 1; then patchlist=$(mktemp) if test ! -f "$patchlist"; then abort "Unable to create temporary file for patchlist." fi else warning "Skipping generation of patchlist because 'Staging' patchset is disabled." enable_patchlist=0 fi fi {patch_apply} if test "$enable_patchlist" -eq 1; then # Generate a temporary patch containing the patchlist and apply it patch_data=$(cat "$patchlist" | sort) if test ! -z "$patch_data"; then patch_lines=$(echo "$patch_data" | wc -l) patch_lines=$((${{patch_lines}}+21)) cat > "$patchlist" < Subject: Autogenerated patch list. diff --git a/libs/wine/config.c b/libs/wine/config.c index 5262c76..0a3182f 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c @@ -478,10 +478,${{patch_lines}} @@ const char *wine_get_version(void) return PACKAGE_VERSION; }} +static const struct +{{ + const char *author; + const char *subject; + int revision; +}} +wine_patch_data[] = +{{ ${{patch_data}} + {{ NULL, NULL, 0 }} +}}; + /* return the applied non-standard patches */ const void *wine_get_patches(void) {{ - return NULL; + return &wine_patch_data[0]; }} /* return the build id string */ EOF patch_apply_file "$patchlist" fi rm "$patchlist" fi if test "$enable_autoconf" -eq 1; then if ! update_configure; then abort "'autoreconf -f' failed." fi if ! update_protocol; then abort "'./tools/make_requests' failed." fi fi # Success exit 0