Marilyn Perry's Notes On Drupal's Package Manager, Composer
The Composer code package manager, together with the Packagist code repository maintain Drupal project code coherence.
The Composer code package dependency manager, together with the Packagist code repository maintain Drupal project code coherence. The code package manager Composer, much like other package manager such as vcpkg, apt, yum, homebrew, and npm, enables developers to maintain compatibility and coherence among the many, often hundreds, of code module components deployed within a Drupal digital experience project.
Among the important aspects of using the Composer package manager is remembering that Composer is not Drupal and Drupal and not Composer. In other words, the Composer package manager isn't actually aware of Drupal. The the Composer package manager's job is to provide code module deployment services, maintaining module version compatibility while and by doing so.
Adding and removing code packages to and from a Drupal project, and checking for updates available for code modules already installed within a Drupal project, is a frequent enough task that it is worthwhile to create a shell script that performs several ancillary tasks in addition to actually running the composer code update command. Consequently, some years ago, it became time to create a linux bash shell script for this purpose. I gave the script the obvious name: drupalcodeupdate.sh. Over the course of several years I've updated this simple script a bit.
#!/bin/bash
#----------------------------------
#
# drupal code update script (interactive, with dry run)
#
# usage:
#
# drupalcodeupdate.sh
#
# assumptions:
#
# - This script assumes the existence of a local php.ini config file at ~/php.ini (the user's home directory)
# - the ~/php.ini much contain: allow_url_fopen = On
# - This script assumes that drush is installed in the drupal site's vendor/bin/ directory
# - without any arguments this script assumes that the drupal code update should occur in the current directory and should perform a dry-run first
#
#
#
# notes:
# - Drupal (8,9,10) doesn't run correctly when the php - allow_url_fopen = On - is set.
# - However composer needs - allow_url_fopen = On - in order do download files from the web.
# Consequently, a server running Drupal needs multiple local php.ini files.
#
# version changes:
# 0.05 - added -s or --silent command line argument logic
# 0.06 - added -m or --major command line argument logic
#
#----------------------------------
# Updated May 12, 2019 - 0.06
# Updated January 4, 2022 - 0.07
# Updated January 8, 2023 - 0.08
# Copyright 2014-2024 by Marilyn Perry https://www.marilynperry.com/
#----------------------------------
#
# This work is licensed via the GNU General Public License version 2 (GPLv2).
# See https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html for more information.
#
#----------------------------------
# reset the bash internal elapsed time variable to be able to time the script (to see time calcs at end of script)
SECONDS=0
# retrieve just the script base script name without path (if any)
szScriptName=$(basename "$0")
# create a basic usage info string
szUsageText="usage: $szScriptName [ -s | --silent ] [ -m | --major ] [ szFullyQualifiedDrupalSiteDirectory ] "
# store some defaults
# save the start directory for convenience
szStartingDirectory=$PWD
# set the default drupal directory to the starting/current directory
szDrupalDirectory=$PWD
# by default the script runs in interactive mode - meaning it executes update dry-run and asks the user if they want to continue
bInteractive="true"
# by default the script runs in interactive mode - meaning it executes update dry-run and asks the user if they want to continue
bMajorUpdate="false"
# startup output info
szDateAndTime=$(date +%Y.%m.%d-%H.%M.%S)
echo "$szScriptName"
echo "$szScriptName - execution beginning at: $szDateAndTime"
echo "$szScriptName - execution beginning in directory: $szStartingDirectory"
# check the command line for arguments that request silent operation and/or major update operation and enable those options if present
if [ $# -gt 0 ]; then
if [[ $1 = "-s" || $1 = "--silent" || $1 = "-m" || $1 = "--major" ]]; then
if [[ $1 = "-s" || $1 = "--silent" ]]; then
bInteractive="false"
# move to the next command line argument if any
shift
elif [[ $1 = "-m" || $1 = "--major" ]]; then
bMajorUpdate="true"
# move to the next command line argument if any
shift
fi
fi
fi
# again check the command line for arguments the request silent operation and/or major update operation and enable those if present
if [ $# -gt 0 ]; then
if [[ $1 = "-s" || $1 = "--silent" || $1 = "-m" || $1 = "--major" ]]; then
if [[ $1 = "-s" || $1 = "--silent" ]]; then
bInteractive="false"
# move to the next command line argument if any
shift
elif [[ $1 = "-m" || $1 = "--major" ]]; then
bMajorUpdate="true"
# move to the next command line argument if any
shift
fi
fi
fi
# again check the command line for a drupal directory this time, which may also be present without or with any of the option flags
# check for an additional command line argument
if [ $# -gt 0 ]; then
if [[ (${#1} -gt 0) && (-d $1) ]]; then
# the argument, must be a fully qualified directory where the drupal code update should occur - length greater than zero and is a directory (no additional arg checks performed)
szDrupalDirectory=$1
# shift/move to the next command line argument $1 (currently only one, so no more left)
shift
fi
fi
# perform a command line argument sanity check
if [ $# -gt 0 ]; then
# something has gone wrong because all arguments should have been processed
echo "$szScriptName - error - too many command line arguments"
echo "$szUsageText"
exit 1
fi
#
# THIS IS THE BEGINNING OF THE CORE COMMAND EXECUTION SECTION OF THIS SCRIPT
#
# change to the drupal base (docroot) website directory
cd $szDrupalDirectory
if [[ $bInteractive = "true" ]]; then
# run composer update dry run to see which code packages would be updated in an actual composer update
echo "$szScriptName - running - php -c ~/php.ini composer.phar update --dry-run"
php -c ~/php.ini composer.phar update --with-all-dependencies --dry-run
echo "$szScriptName"
# find out if the user wants to complete the update
while true; do
read -p "$szScriptName - Do you want to perform the drupal code update? (y/n)" answer
case $answer in
[Yy]* ) break;;
[Nn]* ) echo "$szScriptName - Exiting without performing drupal code update(s)."; cd $szStartingDirectory; exit 1;;
* ) echo " "; echo "You must respond with a (Y/y) yes or (N/n) no answer."; echo " ";;
esac
done
fi
# fi - end interative == true branch
# put the website into maintenance mode
echo "$szScriptName - putting the website into maintenance mode"
echo "$szScriptName - running - php -c ./php.ini vendor/bin/drush state:set system.maintenance_mode 1"
php -c ./php.ini vendor/bin/drush state:set system.maintenance_mode 1
# for a major update e.g. (or 10.x.x) 9.x.x to 9.y.y - such as 9.5.x to 9.6.x - then remove all the /vendor /core contents and delete the composer.lock file
# during a major all of the /vendor /core directories and other composer controlled packages are all rebuilt from scratch because of no composer.lock file
if [[ $bMajorUpdate = "true" ]]; then
# remove all the files from the /core /vendor directories
echo "$szScriptName - running - remove all contents from /core and /vendor directories"
/bin/rm -f -r $szDrupalDirectory/vendor/.[^.]*
/bin/rm -f -r $szDrupalDirectory/vendor/*
/bin/rm -f -r $szDrupalDirectory/core/.[^.]*
/bin/rm -f -r $szDrupalDirectory/core/*
# remove the composer.lock file
echo "$szScriptName - running - delete the composer.lock file"
/bin/rm -f -r $szDrupalDirectory/composer.lock
fi
# fi - end major update == true branch
# run composer update to download and place the updated code packages
echo "$szScriptName - running - php -c ~/php.ini composer.phar update --with-all-dependencies"
php -c ~/php.ini composer.phar update --with-all-dependencies
# add any database updates to the drupal database that any updated module has requested. The -n and -y mean do it without user interaction
echo "$szScriptName - running - php -c ~/php.ini vendor/bin/drush -n -y updb"
php -c ~/php.ini vendor/bin/drush -n -y updb
# clear and rebuild the drupal 8 cache. The -n and -y mean do it without user interaction
echo "$szScriptName - running - php -c ~/php.ini vendor/bin/drush -n -y cr"
php -c ~/php.ini vendor/bin/drush -n -y cr
# take the website out of maintenance mode
echo "$szScriptName - taking the website out of maintenance mode and back online"
echo "$szScriptName - running - php -c ./php.ini vendor/bin/drush state:set system.maintenance_mode 0"
php -c ./php.ini vendor/bin/drush state:set system.maintenance_mode 0
# restore the starting directory
cd $szStartingDirectory
# get the updated internal bash shell elapsed time
nDuration=$SECONDS
echo "$szScriptName - elapsed execution time - $(($nDuration / 60)) minute(s) and $(($nDuration % 60)) second(s)."
# debugging and cron completion output
szFullDateAndTime=$(date +%Y.%m.%d-%H.%M.%S)
echo "$szScriptName - execution complete at: $szFullDateAndTime"
echo "$szScriptName"
# return a success code to the shell environment
exit 0
#----------------------------------
#--end of file---------------------
There are times when it's necessary run the shell script above several times daily, sometimes several times an hour if new and/or additional code modules are being added to or removed from a Drupal project. Hopefully, most apparent among the tasks this script performs is to check for the updates to the Drupal core code package itself.
Thank you for visiting this website, my personal website, and enjoying the information and content shared here at www.marilynperry.com. Marilyn Perry







