Обновить пропатченную Joomla

Обновление Joomla - довольно тривиальная задача.

:!: Однако если ядро сайта или его компоненты были пропатчены, при обновлении эти патчи слетят. Как следствие - пропадет необходимый функционал или «поедет» верстка.

План работ:

  • найти измененные файлы для визуальной оценки
  • сделать патчи
  • обновить движок
  • «вклеить» обратно патчи (именно изменения, а не полностью заменить файлы)
  • разрулить конфликты

Для удобства ставим также git: git init.

См. также автоматическое обновление пропатченной версии Joomla

Как найти измененные файлы Joomla

Необходимо слить официальную «чистую» Джумлу той же версии, что и уже установленная. Вот прошлые версии Joomla, более старые - на следующих страницах. Нам необходим «Full Package». Для примера возьмем версию 3.3.6, распакуем и положим ее выше дерева документов в каталог tmp:

  • tmp/3.3.6-origin - распакованная «чистая» версия
  • public_html - наша рабочая установка

Найдем все отличия:

diff -qr -x '*.jpg' -x '*.png' -x '*.gif' -x '*.doc' -x '*.pdf' tmp/3.3.6-origin public_html > tmp/diff-files.txt
  • -q - только файлы с различиями (иначе будет длинный список «такой и такой файл одинаковы»)
  • -r - рекурсивно
  • -x - исключены графические файлы и документы, они не влияют на работу сайта, но если вы заменили иконки, не игнорируйте.

Полученный файл у меня занимал ~25 кб, 360 отличий, и имел примерно следующее содержимое:

Только в public_html/administrator/cache: com_modules
Только в public_html/administrator/cache: com_plugins
Файлы tmp/3.3.6-origin/administrator/components/com_content/config.xml и public_html/administrator/components/com_content/config.xml различаются
Файлы tmp/3.3.6-origin/templates/system/html/modules.php и public_html/templates/system/html/modules.php различаются

Принципиальных различий два: либо файл или папка отсутствуют, либо есть различия в файлах. Нас интересует только последнее (у меня оказалось 26).

Узнать, какие именно файлы изменялись, можно так: в файле ключевое слово, показывающее что файлы отличаются - «различаются» (в англ. версии - «differ»). Отфильтруем по нему и узнаем имена файлов:

cat tmp/diff-files.txt | grep 'различаются'

Создаем патчи

Коммитим в git все изменения, если это еще не сделано, и переключимся на другую ветку:

git add -A
git commit -m "Status Quo"
git checkout -b "Update"

Делаем бекап БД:

mysqldump dbname > tmp/status-quo.sql

Так мы всегда сможем вернуться к исходному состоянию «Статус-кво», а обновляться будем в ветке Update.

Теперь собственно создадим патчи:

diff -rup -x '*.jpg' -x '*.png' -x '*.gif' -x '*.doc' -x '*.pdf' tmp/3.3.6-origin public_html > tmp/patch.txt

Так как создаются контекстные патчи (окружаются «нетронутым» текстом, чтобы точно указать место самого патча), то их возможно применять и на обновленных файлах.

Обновление Джумлы

Обновляем Джумлу штатными средствами. Добавляем измененные файлы в git:

git add -A
git commit -m "обновление до 3.4.5"

Вклеиваем патчи обратно

Применяем патч:

patch -i tmp/patch.txt -p0 -l
  • -i - указываем путь к патчу
  • -p0 - отсекает часть пути к файлам из патча (0 - не отсекаем), если же перейти в public_html, то следует указать -p1

Если при вклейке патчей что-то пошло не так, и надо вернуться на момент обновления, то делаем:

git checkout .
git clean -f

:!: В процессе вклейки будут интерактивные вопросы:

patching file public_html/administrator/components/com_weblinks/sql/install.mysql.utf8.sql
Reversed (or previously applied) patch detected!  Assume -R? [n]

Это значит, что патч уже был применен. Фактически - файл не обновлялся, а мы его пытаемся «пропатчить» еще раз. И программа предлагает его отменить! Нажимаем n.

Отрыв вторую консоль, можно убедиться в том, что файл не был изменен обновлениями по его истории:

git log public_html/administrator/components/com_weblinks/sql/install.mysql.utf8.sql

Второй раз спросят:

Apply anyway? [n]

Нажимаем снова n, так как файл уже был пропатчен. Мне пришлось так отменять повторный патч два раза.

Разруливание конфликтов

Идеальная переклейка патчей не получилась, поэтому придется разруливать конфликты. Вот кусок истории:

Reversed (or previously applied) patch detected!  Assume -R? [n] n
Apply anyway? [n] n
Skipping patch.
1 out of 1 hunk ignored -- saving rejects to file public_html/administrator/components/com_weblinks/sql/install.mysql.utf8.sql.
rej
patching file public_html/administrator/manifests/libraries/joomla.xml
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file public_html/administrator/manifests/libraries/joomla.xml.rej
patching file public_html/administrator/templates/isis/css/template.css
patching file public_html/bin/keychain.php
patching file public_html/components/com_content/router.php
Hunk #1 succeeded at 284 with fuzz 2 (offset -3 lines).
patching file public_html/components/com_search/views/search/tmpl/default_results.php
patching file public_html/components/com_users/controllers/registration.php
Hunk #1 FAILED at 1
  • Skipping patch - применение патча пропущено (мы сами отменили повторное наложение)
  • 1 out of 1 hunk ignored -- saving rejects - часть патча не удалось наложить, так как не было найдено куда его вклеивать
  • Hunk #1 succeeded at 284 with fuzz 2 (offset -3 lines) - успешное наложение, но из трех строк окружающего контента совпала только одна (3-2)
  • patching file public_html/components/com_search/views/search/tmpl/default_results.php - полный успех

:!: Следует проконтролировать случаи «fuzz» - в моем примере вклейка произошла не в том месте, что сразу отразилось на внешнем виде сайта.

Проверяем внесенные изменения:

git diff

Если все устраивает в измененных файлах, добавляем изменения:

git add -u

Далее будем разбираться с самыми проблемными местами. Для этих целей создан ряд файлов. Проходимся вручную по нему и разруливаем конфликты.

  • .rej - собственно отклоненный патч, либо патчим вручную, либо вообще не применяем его
  • .origin - оригинальный файл, может отсутствовать, если патч вообще не был применен

Вообще могут быть случаи частичного применения изменений, в этом случае оригинальный файл правится, создается его копия .origin и отвергнутый патч .rej.

В конечном счете добавляем все правки и коммитим. Делаем финальную проверку сайта. В случае успеха мержим ветку Update в основную ветку.

Как автоматизировать этот процесс