diff --git a/mediawiki.mk b/mediawiki.mk index 3109495..c91ee55 100644 --- a/mediawiki.mk +++ b/mediawiki.mk @@ -1,536 +1,536 @@ # Set up MediaWiki on the remote host # Copyright (C) 2020 NicheWork, LLC # 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 3 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 . currentDir := $(notdir $(patsubst %/,%,$(dir $(abspath \ $(lastword $(MAKEFILE_LIST)))))) include $(if $(findstring ${currentDir}/composer.mk,$(MAKEFILE_LIST)),, \ ${currentDir}/composer.mk) include $(if $(findstring ${currentDir}/cmds.mk,$(MAKEFILE_LIST)),, \ ${currentDir}/cmds.mk) include $(if $(findstring ${currentDir}/pkg.mk,$(MAKEFILE_LIST)),, \ ${currentDir}/pkg.mk) include $(if $(findstring ${currentDir}/lamp.mk,$(MAKEFILE_LIST)),, \ ${currentDir}/lamp.mk) phpMWContainer ?= mediawiki containerRepo ?= localhost perconaContainer ?= docker.io/library/percona perconaTag ?= latest dbPort ?= 3306 mwBranch ?= master lsDir ?= conf/LocalSettings.d compLocalJson ?= conf/composer.local.json selectedExtensions ?= +# Where things are installed +REMOTE_HOST ?= + # Root of WMF repos gerritHead ?= https://gerrit.wikimedia.org/r # git repo to use for MW mwCoreRepo ?= ${gerritHead}/mediawiki/core # localPath: test -d ${MW_INSTALL_PATH} || mkdir -p ${MW_INSTALL_PATH} # Checkout MediaWiki checkoutMediaWiki: verifyGit verifyRemotePath localPath test -e ${MW_INSTALL_PATH}/.git || \ git clone -b ${mwBranch} ${mwCoreRepo} ${MW_INSTALL_PATH} test -d html || mkdir html test -L html/w || ln -s ../mediawiki html/w touch $@ -# Where things are installed -REMOTE_HOST ?= - # Run composer update in MW_INSTALL_PATH mwComposerUpdate: composer cd ${MW_INSTALL_PATH} && \ ${php} ${topDir}/composer update --no-interaction --no-dev -conf/LocalSettings.php: conf - test -f $@ || cp LocalSettings.php $@ +conf/LocalSettings.php: conf verifyCompLocalJson + test -f $@ || cp ${currentDir}/assets/LocalSettings.php $@ ${make} symlinkConf dir=mediawiki file=LocalSettings.php dumpDB: pv test -n "${sqlDump}" || ( \ echo You need to set sqlDump. && \ exit 1 ) export running=`${dockerCmd} ps -f ancestor=${perconaContainer} \ --format='{{.ID}}' -f status=running` && \ test -n "$$running" || ( \ echo ${perconaContainer} is not running. && \ exit 1 ) echo Dumping ${MW_DB_NAME} to ${sqlDump} echo ============================================================== mysqldump -h${MW_DB_SERVER} -u${MW_DB_USER} -p${MW_DB_PASSWORD} \ ${MW_DB_NAME} | pv > ${sqlDump} # Populate local DB (usually test) with remote DB data remote syncDB: export sqlDump=wiki-dump-$(shell date +%Y-%m-%d-%M:%H).sql && \ ${make} dumpDB sqlDump=$$sqlDump && \ ${make} doRemote stdIn=$$sqlDump \ cmd='sudo mysql ${MW_DB_NAME}' # getBasePhpMWContainer: /usr/bin/buildah export id=$(shell buildah containers --filter 'name=${phpMWContainer}' \ --format "{{.ContainerID}}") && \ test -n "$$id" || \ buildah from --name "mediawiki" \ docker.io/php:${PHP_DOT_VER}-apache && \ echo $@ complete. buildPhpMWContainer: getBasePhpMWContainer export id=$(shell buildah images --json | \ jq -r 'map( select( any( \ .names[]; contains( "${containerRepo}/${phpMWContainer}" ) \ ) ) | .id )[]') && \ test -n "$$id" || ( \ export container=$(shell buildah containers \ --filter 'name=${phpMWContainer}' \ --format '{{.ContainerID}}') && \ buildah run $$container apt update && \ buildah run $$container apt install -y libzip-dev && \ buildah run $$container pecl install zip-1.19.0 || true && \ buildah run $$container docker-php-ext-enable zip || true && \ buildah commit $$container ${containerRepo}/${phpMWContainer} ) echo $@ complete. # Start local PHP container for MediaWiki startContainer: buildPhpMWContainer ${dockerCmd} run -d -p "80:80" -v "${topDir}:/var/www" \ ${phpMWContainer} # stopAContainer: test -n "${container}" || ( \ echo "Please set container!" && \ exit 10 ) export running=$(shell ${dockerCmd} ps --format='{{.ID}}' \ -f status=running -f ancestor=${container}) && \ test -n "$$running" || \ echo ${indent}${container} is not running. && \ test -z "$$running" || ( \ echo ${indent}Stopping ${container}... && \ ${dockerCmd} rm -f $$running ) # Stop local MW container stopContainer: ${make} stopAContainer container=${phpMWContainer} # Stop local Percona container stopPerconaContainer: ${make} stopAContainer container=${perconaContainer} # Start local Percona container startPerconaContainer: export running=`${dockerCmd} ps -f ancestor=${perconaContainer} \ --format='{{.ID}}' -f status=running` && \ test -z "$$running" || \ echo "${indent}${perconaContainer} is running ($$running)." && \ test -n "$$running" || ( \ echo ${indent}Starting ${perconaContainer}... && \ ${dockerCmd} run -d -p "${dbPort}:${dbPort}" \ -e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \ ${perconaContainer}:${perconaTag} ) # installMediaWiki: conf/LocalSettings.php mediawiki/vendor/autoload.php \ verifyWikiUserName verifyMWSitename verifyWikiUserPass verifyScriptPath rm -f conf/LocalSettings.php ${php} ${MW_INSTALL_PATH}/maintenance/install.php --pass=${WIKIUSER_PASS} \ --dbname=${MW_DB_NAME} --dbuser=${MW_DB_USER} \ --dbpass=${MW_DB_PASSWORD} --installdbpass=${MYSQL_ROOT_PASSWORD} \ --dbserver=${MW_DB_SERVER} --installdbuser=root \ --scriptpath=${MW_SCRIPT_PATH} ${MW_SITENAME} ${WIKIUSER_NAME} ${make} symlinkConf dir=mediawiki file=LocalSettings.php # Install Mediawiki on remote host deployMediaWiki: checkoutMediaWiki mwComposerUpdate installMediaWiki .PHONY: install-skin-% install-skin-%: verifyLSDir export name=$(subst install-skin-,,$@) && \ test -d mediawiki/skins/$$name -a \ -f ${lsDir}/skins-$$name.php || ( \ echo installing skin $$name && \ ${make} skin-$$name ) && ( \ echo $$name is installed ) .PHONY: skin-% skin-%: ${make} install-skin branch=${mwBranch} name=$(subst skin-,,$@) \ repo=$(or ${repo},${gerritHead}/mediawiki/skins/$(subst skin-,,$@)) .PHONY: remove-extension-% remove-extension-%: echo ${indent}Removing old installation of $(subst remove-extension-,,$@) rm -rf .git/modules/conf/extensions/$(subst remove-extension-,,$@) \ conf/extensions/$(subst remove-extension-,,$@) \ mediawiki/extensions/$(subst remove-extension-,,$@) \ ${lsDir}/$(subst remove-,,$@).php .PHONY: redeploy-extension-% redeploy-extension-%: ${make} $(subst redeploy-,remove-,$@) ${make} $(subst redeploy-,,$@) .PHONY: extension-% extension-%: ${make} install-extension branch=${mwBranch} name=$(subst extension-,,$@) \ repo=$(or ${repo},${gerritHead}/mediawiki/extensions/$(subst extension-,,$@)) .PHONY: install-ext-% install-ext-%: verifyLSDir export name=$(subst install-ext-,,$@) && \ test -d mediawiki/extensions/$$name -a \ -f ${lsDir}/extension-$$name.php || ( \ echo ${indent}installing extension $$name && \ ${make} extension-$$name ) && ( \ echo ${indent}$$name is installed ) spongeMergeInstallExtension: sponge install-extension verifyCompLocalJson export json="`jq -r -M . < ${compLocalJson}`" && \ export extCompPath="extensions/${name}/composer.json" && \ export exists="`echo $$json | jq \ \"contains({extra:{\\\"merge-plugin\\\":{include: \ [\\\"$$extCompPath\\\"]}}})\"`" && \ export requires="`echo $$json | jq \ \"contains({require:{\\\"${compID}\\\":\\\"\\\"}})\"`" && \ test "$$requires" = "false" || ( \ echo "You asked for to merge the composer.json file for $$name but" \ "it is already in the composer requires." && \ exit 2 ) && \ test "$$exists" = "true" || ( \ echo ${indent}Adding $$name to composer.local.json for merge. && \ echo $$json | \ jq ".extra[\"merge-plugin\"].include += [ \"$$extCompPath\" ]" | \ sponge ${compLocalJson} ) # .PHONY: install-extension install-extension: stem=extension install-extension: loc=conf/extensions/${name} install-extension: conf/extensions enableStem # .PHONY: install-skin install-skin: stem=skin install-skin: loc=conf/skins/${name} install-skin: conf/skins enableStem # Install and enable an extension using require_once .PHONY: legacy-extension legacy-extension: verifyLSDir test -f ${lsDir}/${stem}-${name}.php || ( \ ( echo ' \ ${lsDir}/${stem}-${name}.php ) ${make} install-extension branch=${mwBranch} \ name=${name} \ repo=${gerritHead}/mediawiki/extensions/${name} # Install an extension using composer .PHONY: install-composer-extension install-composer-extension: verifyCompLocalJson jq sponge echo ${indent}Installing ${stem} "${name}" ${make} install-extension tag=${tag} branch=${branch} name=${name} \ repo=${repo} echo ${indent}updating composer.local.json for ${stem} "${name}" jq '.["require"]["${compID}"]="${compVer}"' ${compLocalJson} | \ sponge ${compLocalJson} rm -f composerUpdateNotNeeded # .PHONY: enableStem enableStem: loc=conf/${stem}s/${name} enableStem: verifyName updateRepo verifyStem echo ${indent}$@ for ${name} ${stem} ${make} LocalSettingsAddWf name=${name} stem=${stem} .PHONY: verifyStem verifyStem: test -n "${stem}" || ( \ echo "Choose a stem!"; \ exit 1 ) .PHONY: verifyName verifyName: verifyStem test -n "${name}" || ( \ echo A name must be specified for this ${stem}!; \ exit 1 ) ensureRemoteOrigin: url=$(or ${repo},${gerritHead}/mediawiki/extensions/${name}) ensureRemoteOrigin: verifyName verifyGit test -d mediawiki/${stem}s/${name} || ( \ echo ${indent}$@ for ${url} at ${loc} && \ export origin=`cd ${loc} && ${git} remote get-url origin` && \ test -z "$$origin" -a "$$origin" = "${url}" || ( \ echo ${indent}Updating url for the ${name} ${stem} \(${url}\). && \ cd ${loc} && ${git} remote set-url origin ${url} ) ) .PHONY: updateRepo updateRepo: verifyName checkoutAndLinkGit ensureRemoteOrigin verifyGit # don't do this if it is in MediaWiki repo already test -d mediawiki/${stem}s/${name} || ( \ test ! -n "${tag}" -o ! -n "${branch}" || ( \ echo -n Do not specify both tag \(${tag}\) and branch; \ echo " "\(${branch}\) for ${name}! && \ exit 1 \ ) && \ echo ${indent}Updating repo for ${name} in ${loc} && \ ( \ cd ${loc} && ${git} reset --hard && ${git} status -s | \ awk '/^\?\?/ {print $2}' | xargs rm -rf; \ ${git} fetch origin \ ) ) ${make} maybeEnsureBranch branch=${branch} stem=${stem} name=${name} \ loc=${loc} ${make} maybeEnsureTag tag=${tag} stem=${stem} name=${name} \ loc=${loc} echo ${indent}Handling any submodules cd ${loc} && ${git} submodule update --init --recursive test ! -e mediawiki/${stem}s/${name} -o -e ${loc} || \ test ! -e ${loc} || \ ln -s ../../mediawiki/${stem}s/${name} ${loc} test ! -d ${loc} || \ test ! -L mediawiki/${stem}s/${name} || \ ln -s ../../conf/${stem}s/${name} mediawiki/${stem}s/${name} ${make} maybePatch stem=${stem} name=${name} diffFile=${stem}-${name}-${tag}.diff ${make} maybePatch stem=${stem} name=${name} diffFile=${stem}-${name}-${branch}.diff ${make} maybePatch stem=${stem} name=${name} diffFile=${stem}-${name}.diff .PHONY: maybePatch maybePatch: test ! -f patches/${diffFile} || ( \ echo ${indent}Patching ${name} with ${diffFile} && \ cd ${loc} && \ git am ${topDir}/patches/${diffFile} ) .PHONY: checkoutAndLinkGit checkoutAndLinkGit: verifyName verifyGit echo ${indent}Handling the ${name} ${stem} test -e mediawiki/${stem}s/${name} || ( \ ${make} doClone linkLoc=${linkLoc} loc=conf/${stem}s/${name} \ name=${name} stem=${stem} \ repo=$(or ${repo},${gerritHead}/mediawiki/extensions/${name}) && \ ${make} maybeUpdateSubmodules loc=conf/${stem}s/${name} ) doClone: test ! -n "${DESTRUCTIVE}" -o ! -d ${loc} || \ rm -rf ${loc} echo ${indent}Cloning ${name} into ${stem}s && \ ${git} submodule add -f ${repo} ${loc} maybeUpdateSubmodules: verifyGit # Add any submodules test -e ${loc}/.gitmodules || ( \ cd ${loc} && ${git} ${gitSsl} submodule update --init ) .PHONY: maybeEnsureBranch maybeEnsureBranch: verifyGit test -z "${branch}" || ( \ echo ${indent}Ensuring ${name} ${stem} is on ${branch} && \ cd ${loc} && ${git} fetch && \ test $$(${git} branch | awk '/^\*/ {print $$2}') = "${branch}" || \ ${git} ${gitSsl} checkout ${branch} ) .PHONY: maybeEnsureTag maybeEnsureTag: verifyGit test -z "${tag}" || ( \ echo ${indent}Ensuring ${name} ${stem} is on the tag ${tag} && \ cd ${loc} && ${git} ${gitSsl} fetch && \ ${git} checkout ${tag} ) verifyLSDir: test -n "${lsDir}" || ( \ echo "Please set lsDir!" ; \ exit 1 ) ${make} ${lsDir} .PHONY: LocalSettingsAddWf LocalSettingsAddWf: verifyName verifyLSDir conf/LocalSettings.php echo ${indent}$@ for ${stem} ${name} test -d "${lsDir}" || \ mkdir -p ${lsDir} # Lucky us, PHP is case-insensitive for function names, so we # call wfLoadskin() and wfLoadextension() test -f ${lsDir}/${stem}-${name}.php || ( \ ( echo ' ${lsDir}/${stem}-${name}.php ) .PHONY: installExtensions installExtensions: export bail='' && \ for ext in ${selectedExtensions} ; do \ test -n "$$bail" || \ ${make} install-ext-$$ext || bail=$$ext ; \ done ; \ test -n "$$bail" && ( \ echo "Failed on $$bail!" && \ exit 2 ) || \ true .PHONY: verifyMWINSTALL verifyMWINSTALL: test -f ${MW_INSTALL_PATH}/maintenance/update.php || ( \ echo Please set MW_INSTALL_PATH! MW_INSTALL_PATH is currently && \ echo ${MW_INSTALL_PATH} and maintenance/update.php is not there! && \ echo && exit 1 ) ${SMW_CONF_FILE_DIR}: test -n "${SMW_CONF_FILE_DIR}" || ( \ echo Please set SMW_CONF_FILE_DIR. ; \ exit 1 ) mkdir -p ${SMW_CONF_FILE_DIR} ${SMW_CONF_FILE_DIR}/.smw.json: ${SMW_CONF_FILE_DIR} echo '{}' | tee $@ > /dev/null .PHONY: verifySMWjson verifySMWjson: ${SMW_CONF_FILE_DIR}/.smw.json test `id -u ${WEB_USER}` -eq `stat -c %u ${SMW_CONF_FILE_DIR}` -a \ `id -u ${WEB_USER}` -eq `stat -c %u $<` || ( \ echo ${indent}sudo chown ${WEB_USER} ${SMW_CONF_FILE_DIR} $< && \ sudo chown ${WEB_USER} ${SMW_CONF_FILE_DIR} $< ) .PHONY: cleanupUsers cleanupUsers: ${make} logStart section=$@ test ! -f ${MW_INSTALL_PATH}/maintenance/cleanupUsersWithNoId.php || ( \ sudo -u ${WEB_USER} ${php} \ ${MW_INSTALL_PATH}/maintenance/cleanupUsersWithNoId.php -p noid ) ${make} logStop section=$@ # .PHONY: rebuildData rebuildData: composerUpdate dbVerify${MW_DB_TYPE} verifyMWINSTALL verifySMWjson ${make} logStart section=$@ sudo -u ${WEB_USER} ${php} \ ${MW_INSTALL_PATH}/extensions/SemanticMediaWiki/maintenance/rebuildData.php --v ${make} logStop section=$@ # .PHONY: updatePhp updatePhp: composerUpdate dbVerify${MW_DB_TYPE} verifyMWINSTALL verifySMWjson ${make} logStart section=$@ sudo -u ${WEB_USER} ${php} ${MW_INSTALL_PATH}/maintenance/update.php \ ${verboseUpdatePhp} --quick ${make} logStop section=$@ .PHONY: composerInstall composerInstall: composer cd ${MW_INSTALL_PATH} && ${php} ${topDir}/composer install .PHONY: composerUpdate composerUpdate: composer verifyMWINSTALL ${make} logStart section=$@ cd ${MW_INSTALL_PATH} && ${php} ${topDir}/composer update --no-interaction ${make} logStop section=$@ # conf ${lsDir}: test -d $@ || ( \ echo ${indent}Creating $@... && \ mkdir -p $@ ) .PHONY: conf/composer.local.json -conf/composer.local.json: conf/LocalSettings.php +conf/composer.local.json: test ! -L mediawiki/composer.local.json -a \ -f mediawiki/composer.local.json && \ mv mediawiki/composer.local.json $@ || true ${make} symlinkConf dir=mediawiki file=composer.local.json - export json="`cat $@ 2>/dev/null| jq -r -M . 2>/dev/null`" || true && \ - test -n "$$json" || \ - json='{}' && \ - echo $$json | jq '.require += { "vlucas/phpdotenv": "~4" }' | sponge $@ .PHONY: conf/composer.lock conf/composer.lock: conf/composer.local.json test ! -L mediawiki/composer.lock -a -f mediawiki/composer.lock && \ mv mediawiki/composer.lock $@ || true ${make} symlinkConf dir=mediawiki file=composer.lock test -f $@ || ${make} composerInstall .PHONY: conf/extensions conf/extensions: conf test -d $@ || mkdir -p $@ for i in mediawiki/extensions/*; do \ ext=`basename $$i` && \ test -f $$i -o -L $@/$$ext || \ ln -s ../../$$i $@; \ done .PHONY: conf/skins conf/skins: conf test -d $@ || mkdir -p $@ for i in mediawiki/skins/*; do \ ext=`basename $$i` && \ test -f $$i || \ ln -s ../../$$i $@/$$ext; \ done .PHONY: conf/vendor conf/vendor: conf test -d $@ || mkdir -p $@ .PHONY: verifyGit verifyGit: test -n "${git}" || ( echo Please install git and set \$$\{git\}; exit 2 ) ${git} --help > /dev/null || ( echo Please ensure ${git} is git.; exit 2 ) .PHONY: verifyCompLocalJson verifyCompLocalJson: - test -n "${compLocalJson}" || ( echo Please set \$$compLocalJson; exit 2 ) + test "${compLocalJson}" = "conf/composer.local.json" || ( \ + echo Please do not change \$$compLocalJson; exit 2 ) test ! -e "${compLocalJson}" || test -f ${compLocalJson} || ( \ echo ${compLocalJson} is not a file; exit 2 ) - test -f "${compLocalJson}" || echo '{}' > ${compLocalJson} - test -L mediawiki/composer.local.json || ln -s ../${compLocalJson} mediawiki/composer.local.json + ${make} ${compLocalJson} + export json="`cat $@ 2>/dev/null| jq -r -M . 2>/dev/null`" || true && \ + test -n "$$json" || \ + json='{}' && \ + echo $$json | jq '.require += { "vlucas/phpdotenv": "~4" }' | sponge $@ .PHONY: verifyWikiUserName verifyWikiUserName: - test -n "${WIKIUSER_NAME}" || ( \ - echo "Please set WIKIUSER_NAME!" ; \ - exit 1 ) + test -n "${WIKIUSER_NAME}" || ( \ + echo "Please set WIKIUSER_NAME!" ; \ + exit 1 ) .PHONY: verifyWikiUserPass verifyWikiUserPass: - test -n "${WIKIUSER_PASS}" || ( \ - echo "Please set WIKIUSER_PASS!" ; \ - exit 1 ) + test -n "${WIKIUSER_PASS}" || ( \ + echo "Please set WIKIUSER_PASS!" ; \ + exit 1 ) .PHONY: verifyMWSitename verifyMWSitename: test -n "${MW_SITENAME}" || ( \ echo "Please set MW_SITENAME!" ; \ exit 1 ) .PHONY: verifyScriptPath verifyScriptPath: test -n "${MW_SCRIPT_PATH}" || ( \ echo "Please set MW_SCRIPT_PATH!" ; \ exit 1 )