Initial import
authorAntonio Ospite <ao2@ao2.it>
Mon, 5 Jun 2017 13:13:28 +0000 (15:13 +0200)
committerAntonio Ospite <ao2@ao2.it>
Thu, 22 Jun 2017 08:30:10 +0000 (10:30 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.txt [new file with mode: 0644]
TODO [new file with mode: 0644]
drin.in [new file with mode: 0644]
drin.rst [new file with mode: 0644]
libexec/bootstrap.sh [new file with mode: 0755]
libexec/clean.sh [new file with mode: 0755]
libexec/create-profile.sh [new file with mode: 0755]
libexec/new.sh [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0c56601
--- /dev/null
@@ -0,0 +1,2 @@
+drin
+drin.1
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..49a32a6
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+# Packagers may want to override this!
+prefix ?= /usr/local
+
+LIBEXEC_DIR ?= $(prefix)/share/drin/libexec
+BIN_DIR := $(prefix)/bin
+MAN_DIR := $(prefix)/share/man
+
+.PHONY: all local installdocs install clean
+
+all: drin
+
+drin: drin.in
+       sed -e 's#@libexec@#$(LIBEXEC_DIR)#g' $< > $@ \
+         && chmod +x $@
+
+# Useful during development to run the script from the working directory
+local: LIBEXEC_DIR := $(PWD)/libexec
+local: clean drin
+       touch drin.in
+
+installdocs: drin.1
+       install -d $(DESTDIR)$(MAN_DIR)/man1
+       install -m644 drin.1 $(DESTDIR)$(MAN_DIR)/man1
+
+install: drin installdocs
+       install -d $(DESTDIR)$(LIBEXEC_DIR)
+       install -m755 libexec/*.sh $(DESTDIR)$(LIBEXEC_DIR)
+       install -d $(DESTDIR)$(BIN_DIR)
+       install -m755 $< $(DESTDIR)$(BIN_DIR)
+
+clean:
+       rm -f drin drin.1
+
+%.1: %.rst
+       rst2man $< > $@
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..b9d03c9
--- /dev/null
@@ -0,0 +1,15 @@
+Helper commands to create and install new Drupal projects.
+See the 'drin.rst' file for more info.
+
+To test the commands locally, execute `make local` and run `./drin`.
+
+Dependencies:
+  - bash
+  - composer
+  - git
+  - sudo
+
+The shell script template was inspired by
+http://agateau.com/2014/template-for-shell-based-command-line-scripts/
+
+Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..e77aa2a
--- /dev/null
+++ b/TODO
@@ -0,0 +1,7 @@
+- add bash-completion files to autocomplete subcommands names
+
+And maybe:
+  - add a --destdir=<directory> option to the 'create-profile' command
+  - in the 'new' command, set up a local composer repository like shown in
+    https://github.com/drupal-composer/drupal-project/issues/249
+  - add a --vanilla option to the 'new' command to skip any patching
diff --git a/drin.in b/drin.in
new file mode 100644 (file)
index 0000000..4ba7583
--- /dev/null
+++ b/drin.in
@@ -0,0 +1,67 @@
+#!/bin/bash
+# drin - helper tools to initialize Drupal projects
+#
+# Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+PROGNAME=$(basename $0)
+LIBEXEC="@libexec@"
+
+usage() {
+  cat <<EOF
+usage: $PROGNAME [--help] [sub-command]
+
+Helper tools to initialize Drupal projects.
+
+Options:
+  -h, --help          display this usage message and exit
+
+Sub-commands:
+EOF
+
+  for subcommand in ${LIBEXEC}/*.sh;
+  do
+    echo "  $(basename $subcommand .sh)"
+  done
+}
+
+[ $# -eq 0 ] && { usage 1>&2 && exit 1; }
+
+while [ $# -gt 0 ];
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -*)
+      echo "Error: Unknown option '${1}'" 1>&2
+      ;;
+    *)
+      subcommand="${LIBEXEC}/${1}.sh"
+      if [ ! -x "$subcommand" ]; then
+        echo "Error: '${1}' is not a known subcommand." 1>&2
+        echo "Run '${PROGNAME} --help' for a list of known subcommands." 1>&2
+        exit 1
+      else
+        shift
+        exec $subcommand "$@"
+      fi
+      ;;
+  esac
+  shift
+done
diff --git a/drin.rst b/drin.rst
new file mode 100644 (file)
index 0000000..ed21253
--- /dev/null
+++ b/drin.rst
@@ -0,0 +1,102 @@
+======
+ drin
+======
+
+-----------------
+Drupal init tools
+-----------------
+
+:Author: Antonio Ospite <ao2@ao2.it>
+:Date:   2017-06-20
+:Copyright: GPLv2+
+:Manual section: 1
+:Manual group: General Commands Manual
+
+SYNOPSIS
+========
+
+*drin* <options> [sub-command]
+
+DESCRIPTION
+===========
+
+Helper commands to create and install new Drupal projects.
+
+When setting up a new Drupal project with drupal-composer/drupal-project drush
+and drupal-console are not available yet and some repetitive tasks can use
+a nicer command line interface.
+
+These scripts are especially useful when setting up projects in user web
+directories[1].
+
+[1] http://httpd.apache.org/docs/current/howto/public_html.html
+
+
+OPTIONS
+=======
+
+Available options:
+
+  **-h**, **--help**
+    this help
+
+
+Available sub-commands:
+
+  ``new`` `[-h|--help]` `<destdir>` `[composer options (e.g. --devel)]`
+    Create a new Drupal project in the `destdir` directory.
+
+  ``bootstrap`` `[--devel|-h|--help]"`
+    Bootstrap a Drupal project, using settings from a `bootstrap.conf` file.
+
+  ``clean`` `[-h|--help]`
+    Cleanup the project, removing all the installed files.
+
+  ``create-profile`` `[-h|--help]` `<title>` `<machine_name>`
+    Create an installation profile from the installed project.
+
+
+EXAMPLES OF USE
+===============
+
+Create and install a new Drupal project:
+
+::
+
+  cd ~/public_html
+  drin new drupal_test_site
+  cd drupal_test_site
+  $EDITOR bootstrap.conf
+  drin bootstrap --devel
+
+
+Create an installation profile from the currently installed project:
+
+::
+
+  drin create-profile "Test Profile" test_profile
+
+
+Clean and rebuild the whole project to verify that installing from scratch works:
+
+::
+
+  drin clean
+  drin bootstrap
+
+
+SEE ALSO
+========
+
+* drupal-composer/drupal-project: https://github.com/drupal-composer/drupal-project
+* drush: https://github.com/drush-ops/drush
+* drupal-console: https://github.com/hechoendrupal/drupal-console
+
+.. _drupal-composer/drupal-project: https://github.com/drupal-composer/drupal-project
+.. _drush: https://github.com/drush-ops/drush
+.. _drupal-console: https://github.com/hechoendrupal/drupal-console
+
+BUGS
+====
+
+None known.
diff --git a/libexec/bootstrap.sh b/libexec/bootstrap.sh
new file mode 100755 (executable)
index 0000000..3b52f26
--- /dev/null
@@ -0,0 +1,180 @@
+#!/bin/bash
+# Bootstrap a Drupal project
+#
+# Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+usage() {
+  cat <<EOF
+usage: drin $(basename $0 .sh) [--devel|-h|--help]
+
+Bootstrap a Drupal project, using settings from a 'bootstrap.conf' file.
+
+Options:
+  --devel             install drupal/devel and use a settings.local.php file
+  -h, --help          display this usage message and exit
+
+EOF
+}
+
+while [ $# -gt 0 ];
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    --devel)
+      DEVEL_MODE="true"
+      ;;
+    -*)
+      echo "Error: Unknown option '${1}'" 1>&2
+      ;;
+  esac
+  shift
+done
+
+. bootstrap.conf
+
+declare -p DB_NAME
+declare -p DB_USER
+declare -p DB_PASS
+
+declare -p ACCOUNT_NAME
+declare -p ACCOUNT_PASS
+declare -p ACCOUNT_MAIL
+
+declare -p SITE_NAME
+declare -p SITE_MAIL
+declare -p SITE_BASE_PATH
+
+declare -p TRUSTED_HOSTS
+
+declare -p WEB_SERVER_GROUP
+
+[ "x$INSTALLATION_PROFILE" = "x" ] && { echo "INSTALLATION_PROFILE not specified, using the \"standard\" profile!"; INSTALLATION_PROFILE="standard"; }
+
+if [ "x$MYSQL_ROOT_PASSWORD" = "x" ];
+then
+  read -s -p "MySQL root password: " MYSQL_ROOT_PASSWORD
+  echo
+fi
+
+SITE_LOCAL_PATH="${PWD}/web"
+
+command -v composer &> /dev/null || { echo "Aborting, 'composer' not available." 1>&2; exit 1; }
+command -v git &> /dev/null || { echo "Aborting, 'git' not available." 1>&2; exit 1; }
+
+[ -d "$SITE_LOCAL_PATH" ] || composer install
+
+# TODO check if the commands are available
+DRUSH="${PWD}/vendor/bin/drush"
+DRUPAL_CONSOLE="${PWD}/vendor/bin/drupal"
+
+[ -x "$DRUSH" ] || { echo "Aborting, '$DRUSH' not available." 1>&2; exit 1; }
+[ -x "$DRUPAL_CONSOLE" ] || { echo "Aborting, '$DRUPAL_CONSOLE' not available." 1>&2; exit 1; }
+
+# This becomes unnecessary if the installation profile gets pulled in by
+# composer.json, like suggested in
+# https://github.com/drupal-composer/drupal-project/issues/249
+if ! echo $INSTALLATION_PROFILE | egrep -q "^(minimal|standard)$";
+then
+  if [ -d $SITE_LOCAL_PATH/profiles/$INSTALLATION_PROFILE ];
+  then
+    echo "Installation profile '$INSTALLATION_PROFILE' already there."
+  else
+    cp -a $INSTALLATION_PROFILE $SITE_LOCAL_PATH/profiles
+  fi
+fi
+
+pushd "$SITE_LOCAL_PATH"
+
+$DRUSH --verbose --yes \
+  site-install \
+  --db-su=root \
+  --db-su-pw="$MYSQL_ROOT_PASSWORD" \
+  --db-url="mysql://${DB_USER}:${DB_PASS}@localhost/${DB_NAME}" \
+  --site-name="$SITE_NAME" \
+  --site-mail="$SITE_MAIL" \
+  --account-name="$ACCOUNT_NAME" \
+  --account-pass="$ACCOUNT_PASS" \
+  --account-mail="$ACCOUNT_MAIL" \
+  "$INSTALLATION_PROFILE"
+
+if $DRUSH pm-info --fields=status locale | grep -q enabled;
+then
+  # This is necessary for multi-language sites, it fixes some issues like:
+  #   "The Translation source field needs to be installed."
+  $DRUSH --yes entity-updates
+
+  # Update translations of contrib modules
+  $DRUSH --yes locale-update
+fi
+
+# This fixes permissions when installing under $HOME/public_html/
+chmod 775 sites/default/files
+sudo chgrp -R "$WEB_SERVER_GROUP" sites/default/files
+
+[ -d ../config/sync ] && sudo chgrp -R "$WEB_SERVER_GROUP" ../config/sync
+
+# Enables clean URLs
+sed -i "s@# RewriteBase /drupal\$@RewriteBase ${SITE_BASE_PATH}@" .htaccess
+
+chmod 644 sites/default/settings.php
+
+# Add some basic settings to settings.php
+if ! grep -q "^\\\$settings\['trusted_host_patterns'\] =" sites/default/settings.php;
+then
+  echo "\$settings['trusted_host_patterns'] = [" >> sites/default/settings.php
+  for host in "${TRUSTED_HOSTS[@]}"
+  do
+    echo "  '^${host}\$'," >> sites/default/settings.php
+  done
+  echo "];" >> sites/default/settings.php
+fi
+
+if [ "$DEVEL_MODE" = "true" ];
+then
+  # NOTE: don't run composer under web/ but in the project dir
+  composer --working-dir=../ require drupal/devel
+  $DRUSH --yes en devel
+
+  chmod 755 sites/default
+  cp sites/example.settings.local.php sites/default/settings.local.php
+  chmod 444 sites/default/settings.local.php
+  chmod 555 sites/default
+
+  if ! grep -q "^include \$app_root . '/' . \$site_path . '/settings.local.php';" sites/default/settings.php;
+  then
+    echo "include \$app_root . '/' . \$site_path . '/settings.local.php';" >> sites/default/settings.php
+  fi
+fi
+
+chmod 444 sites/default/settings.php
+
+# If using a git checkout of Drupal core, set up a diff alias.
+#
+# This is useful because the Automated Test infrastructure of drupal.org does
+# not expect patches to be created from a split core directory.
+if [ -d core/.git ];
+then
+  git -C core/ config --local alias.core-diff "diff --src-prefix=a/core/ --dst-prefix=b/core/"
+  echo "Added a 'git core-diff' to the drupal/core repository clone."
+  echo "This command helps creating core patches ready for upstream."
+fi
+
+popd
diff --git a/libexec/clean.sh b/libexec/clean.sh
new file mode 100755 (executable)
index 0000000..34ef55e
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+# Clean up a Drupal project directory
+#
+# Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+usage() {
+  cat <<EOF
+usage: drin $(basename $0 .sh) [-h|--help]
+
+Cleanup the project, removing all the installed files.
+
+Options:
+  -h, --help          display this usage message and exit
+EOF
+}
+
+while [ $# -gt 0 ];
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -*)
+      echo "Error: Unknown option '${1}'" 1>&2
+      ;;
+  esac
+  shift
+done
+
+CONFIRMATION_STRING="YESIAMSURE"
+
+echo "WARNING! This removes any files in the config/ web/ and vendor/ directories."
+echo "Are you sure you want to continue?"
+echo
+read -p "Type ${CONFIRMATION_STRING} to confirm: " INPUT
+
+run() {
+  echo $*
+  $*
+}
+
+[ "$INPUT" = "$CONFIRMATION_STRING" ] && run sudo rm -rf config/ web/ vendor/ composer.lock
diff --git a/libexec/create-profile.sh b/libexec/create-profile.sh
new file mode 100755 (executable)
index 0000000..96020b3
--- /dev/null
@@ -0,0 +1,116 @@
+#!/bin/bash
+# Create a Drupal installation profile
+#
+# Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+usage() {
+  cat <<EOF
+usage: drin $(basename $0 .sh) [-h|--help] <title> <machine_name>
+
+Create an installation profile from the installed project.
+
+Options:
+  -h, --help          display this usage message and exit
+EOF
+}
+
+while [ $# -gt 0 ];
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -*)
+      echo "Error: Unknown option '${1}'" 1>&2
+      ;;
+    *)
+      break
+      ;;
+  esac
+  shift
+done
+
+
+[ "x$1" = "x" -o  "x$2" = "x" ] && { usage 1>&2; exit 1; }
+
+PROFILE_TITLE="$1"
+PROFILE_MACHINE_NAME="$2"
+
+WEB_ROOT="${PWD}/web"
+
+[ -d "$WEB_ROOT" ] || { echo "Aborting, run this command from the Drupal project directory." 1>&2; exit 1; }
+
+PROJECT_ROOT="$PWD"
+
+DRUPAL_CONSOLE="${PROJECT_ROOT}/vendor/bin/drupal"
+DRUSH="${PROJECT_ROOT}/vendor/bin/drush"
+
+[ -x "$DRUSH" ] || { echo "Aborting, '$DRUSH' not available." 1>&2; exit 1; }
+[ -x "$DRUPAL_CONSOLE" ] || { echo "Aborting, '$DRUPAL_CONSOLE' not available." 1>&2; exit 1; }
+
+[ -d "${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}" ] && { echo "Aborting, ${PROJECT_ROOT}/${PROFILE_MACHINE_NAME} already exists." 1>&2; exit 1; }
+
+pushd "$WEB_ROOT"
+
+# The list of modules and themes could also be obtained by exporting the
+# configuration first and then looking at: config/install/core.extension.yml
+# like this:
+#
+#  sed -e '/module:/,/^[^ ]/!d;//d' -e 's/^[ ]*\(.*\):.*$/\1/' config/install/core.extension.yml
+#
+# or
+#
+#  $DRUPAL_CONSOLE yaml:get:value "$PWD/$PROFILE_MACHINE_NAME/config/install/core.extension.yml" dependencies
+#
+# However getting them before exporting the configuration and generating the
+# profile is cleaner.
+#
+ENABLED_MODULES="$($DRUSH pm-list --type=module --status=enabled --pipe | tr '\n' ',')"
+ENABLED_THEMES="$($DRUSH pm-list --type=theme --status=enabled --pipe | tr '\n' ',')"
+
+rm -rf "${WEB_ROOT}/profiles/$PROFILE_MACHINE_NAME"
+$DRUPAL_CONSOLE generate:profile \
+  --profile="$PROFILE_TITLE" \
+  --machine-name="$PROFILE_MACHINE_NAME" \
+  --description="Drupal installation profile for $PROFILE_TITLE" \
+  --dependencies=$ENABLED_MODULES \
+  --themes=$ENABLED_THEMES \
+  --no-interaction
+cp -a "${WEB_ROOT}/profiles/${PROFILE_MACHINE_NAME}" "$PROJECT_ROOT"
+
+# Basically do what's suggested in the "Configuration" section here:
+# https://www.drupal.org/docs/8/creating-distributions/how-to-write-a-drupal-8-installation-profile
+$DRUPAL_CONSOLE config:export --directory="${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}/config/install" --remove-uuid --remove-config-hash
+rm "${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}/config/install/core.extension.yml"
+
+# The reference to the core version could be removed, but this is not strictly necessary
+#find "${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}/config/install" -type f -exec sed -i -e '/^_core: {  }/d' {} \;
+
+# Since the profile generated by `$DRUPAL_CONSOLE generate:profile` calls in
+# the standard profile, some duplicated config files could be removed in the
+# new profile, but that's not strictly necessary either.
+#fdupes -f -1 "${WEB_ROOT}/core/profiles/standard/config/install/" "${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}/config/install/" | xargs rm
+
+# Export the default content if the default_content module is there
+if echo $ENABLED_MODULES | grep -q default_content;
+then
+  $DRUSH default-content-export-references --folder="${PROJECT_ROOT}/${PROFILE_MACHINE_NAME}/content" node
+fi
+
+popd
diff --git a/libexec/new.sh b/libexec/new.sh
new file mode 100755 (executable)
index 0000000..012c3cb
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/bash
+# Create a new Drupal project
+#
+# Copyright (C) 2017  Antonio Ospite <ao2@ao2.it>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set -e
+
+usage() {
+  cat <<EOF
+usage: drin $(basename $0 .sh) [-h|--help] <destdir>
+
+Create a new Drupal project in the 'destdir' directory.
+
+Options:
+  -h, --help          display this usage message and exit
+EOF
+}
+
+while [ $# -gt 0 ];
+do
+  case "$1" in
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    -*)
+      echo "Error: Unknown option '${1}'" 1>&2
+      ;;
+    *)
+      break
+      ;;
+  esac
+  shift
+done
+
+[ "x$1" = "x" ] && { usage 1>&2; exit 1; }
+
+[ -d "$1" ] && { echo "Aborting, project directory already exists." 1>&2; exit 1; }
+
+DESTDIR="$1"
+
+command -v composer &> /dev/null || { echo "Aborting, 'composer' not available." 1>&2; exit 1; }
+command -v git &> /dev/null || { echo "Aborting, 'git' not available." 1>&2; exit 1; }
+
+# Create a new project keeping the VCS metadata so it's easier to bring in
+# updates to drupal-composer/drupal-project itself.
+echo "Creating a new Drupal project..."
+composer create-project drupal-composer/drupal-project:8.x-dev@dev "$DESTDIR" --keep-vcs --stability dev --no-interaction
+
+pushd "$DESTDIR"
+
+git remote rename origin upstream
+git checkout -b master
+echo >> .gitignore
+echo "# Ignore the configuration for the bootstrap script" >> .gitignore
+echo "bootstrap.conf" >> .gitignore
+
+# Add some patches, use sed until composer can do that from the command line
+# (e.g. composer config ...)
+sed -i -e 's@"extra": {@"extra": {\
+        "patches-file": "composer.patches.json",@' composer.json
+
+cat > composer.patches.json <<EOF
+{
+  "patches": {
+    "drupal/core": {
+      "drupal-do_not_disable_MultiViews_htaccess": "https://www.drupal.org/files/issues/drupal-do_not_disable_MultiViews_htaccess-2619250-24.patch"
+    }
+  }
+}
+EOF
+
+# Apply the patches
+composer update
+
+# Add a template config file for the bootstrap script
+cat > bootstrap.conf <<EOF
+#DB_NAME="drupal_test_database"
+#DB_USER="drupal_test_user"
+#DB_PASS="drupal_test_password"
+
+#ACCOUNT_NAME="admin"
+#ACCOUNT_PASS="admin"
+#ACCOUNT_MAIL="admin@example.com"
+
+#SITE_NAME="example"
+#SITE_MAIL="admin@example.com"
+
+#SITE_BASE_PATH="/~${USER}/$(basename "${PWD}")/web"
+
+#WEB_SERVER_GROUP="www-data"
+
+#INSTALLATION_PROFILE="standard"
+
+#TRUSTED_HOSTS=(
+#  "localhost"
+#  "ip4-localhost"
+#  "ip6-localhost"
+#  )
+
+#MYSQL_ROOT_PASSWORD="password"
+EOF
+
+echo
+echo "Uncomment and customize the values in the bootstrap.conf file."
+echo "Make sure that access to '$PWD' is restricted by the web server."
+
+popd