Vsos JAVA WIP

Материал из Rosalab Wiki
Перейти к: навигация, поиск

Эта страница описывает процесс первичной сборки множества Java-пакетов в платформе rosa2019.1. Актуальна на июль 2020 года.

Ситуация и задача

Старый стек Java времен платформы rosa2016.1 для сборки выкачивает бинарные артефакты из maven-репозитория. Такое положение вещей недопустимо для обеспечения самодостаточной самопересобираемости репозитория, а на платформах rosa2019.x интернет в сборочнице выключен, такая сборка невозможна.

В связи с этим на ABF была создана группа https://abf.io/vsos_java, в которую была импортирована немалая часть Java-стека из Fedora. Стек начинается с двух пакетов:
- java-1.8-openjdk (сама явомашина), версия 1.8 пока основная, java-11-openjdk тоже существует и при необходимости применяется как компилятор для некоторых java-пакетов
- javapackage(s)-tools (генераторы Requires, Provides RPM и макросы для сборки java-пакетов)

Типовая проблема сборки — сильная закольцованность зависимостей: пакет А для сборки требует пакет Б, а пакет Б для сборки требует пакет А, также часто пакет требует сам себя для сборки. Эта проблема бутстрапа явостека решается так: в репозиторий по SSH (доступ по SSH к нужной директории есть у mikhailnov и slava86) подкладываются бинарные rpm-пакеты из Fedora, затем собираются родные пакеты rosa, и специальный скрипт удаляет (перемещает в ../__REMOVED) fc-пакеты, которые уже собраны в варианте для Росы. Вот этот скрипт mvjava.sh:

#!/bin/bash
_main(){
for i in $(ls *.fc3*.rpm *.fc2*.rpm | sort -u); do
 fc_name=$(rpm -qp --qf '%{NAME}' $i 2>/dev/null);
 for j in $(ls | grep -E "^${fc_name}.*-.*rosa2019\.1.*\.rpm$") ; do
	rosa_name=$(rpm -qp --qf '%{NAME}' $j 2>/dev/null)
	mkdir -p ../___REMOVED/
	if [ "$fc_name" = "$rosa_name" ]; then mv -v $i $i ../___REMOVED/ ; fi
 done
done
}
pushd скрыто/repository/rosa2019.1/x86_64/main/release
_main
popd

После прохода скрипта запускается пересоздание метаданных репозитория, либо в настройках репозитория, либо перепубликацией какого-нибудь пакета. Почти все пакеты noarch, сборка производится пока только для одной архитектуры — x86_64, затем сокпируем пакеты и пересоберем их.

В репозиторий были подложены почти все java-пакеты из Fedora, многие не используются, но пока лежат, многие были уже пересобраны в родном варианте, а fc перемещены в ../__REMOVED.

Если какой-то пакет из fc требует зависимостей, которые в Росе называются по-другому, то вставляем Provides в соответствующий родной пакет (важно: сразу и в 2019.1, и в 2019.05). Пример: https://abf.io/import/fonts-ttf-dejavu/commit/6270ee611ce8bedaefa6ee1b84f7904ceb5edfdd (в пределах разумного).

Периодически запускается массовая пересборка всех пакетов (https://abf.io/platforms/vsos_java_personal/mass_builds), а nginx на сервере настроен на логирование пакетов, скачиваемых из репозитория vsos_java_personal. По этому логу определяем список fc-пакетов, которые были использованы, их импортируем в SRPM, пытаемся собрать, повторяем процесс.

В будущем, вероятно, отошлем в Fedora Java Special Interest Group наши правки и патчи, чтобы помочь проекту Fedora привести java-стек в лучшее состояние, чем сейчас, и чтобы в будущем заимствовать обновления из Fedora. Для упрощения дальнейших завимствований diff спеков Федоры и Росы должен оставаться минимальным. Обычно только удаляем %changelog (он не используется в Росе) и добавляем тег "Group: Development/Java".

Для подключения репозитория создать файл /etc/yum.repos.d/vsos_java.repo

[vsos_java_rosa2019.1]
name=vsos_java_rosa2019.1
baseurl=http://abf-downloads.rosalinux.ru/vsos_java_personal/repository/rosa2019.1/x86_64/main/release
enabled=1
gpgcheck=0

Задача: обеспечить самопересобираемость репозитория vsos_java полностью на пакетах rosa, без fc-пакетов.

Типовые проблемы сборки и их решения

Причины проблем

В Fedora, похоже, люди, которые занимались java, куда-то ушли, в результате многие пакеты не пересобирались несколкьо релизов и лежат в просто бинарном виде от предыдущих релизов (например, пакеты с суффиксом fc30 в репозитории fc32), либо были выкинуты из репозитория по причине непересобираемости и отсутствия мейнтейнера. Было выкинуто очень многое. Часть из этого мы по тем или иным причинам собираем у себя, чиня и/или костылируя сборку. Многие пакеты нужны только как сборочные зависимости для дргуих пакетов.

Также для java характерно ломать совместимость между мажорными версиями, а во многие проектах необходимые версии жестко прописаны в зависимостях maven/ant/gradle, поэтому просто так пакеты не обновляем мажорно, одно обновление поломает слишком многое. Т.е. обновить, например, с 8.1 до 8.3, обычно нормально, а вот с 8 до 9 ­— нет. В Fedora, похоже, часть пакетов обновили, потом пошла цепная реакция по разваливанию репозитория.

Не находит зависимость

Вариант 1

Некоторые пакеты собраны с --with=jp_minimal, Requires могут быть завернуты в %if %{with jp_minimal}. Маловероятно.

Вариант 2

Хочет java 11 для сборки. Прописать ее в BuildRequires. Пример: https://abf.io/vsos_java/byteman/commit/b477da6ae345ba98969263ed400250ba0333c616

Вариант 3

Править xml-файлы с зависимостями, пример: https://abf.io/vsos_java/takari-lifecycle/blob/4b48f0a439/0004-FTBFS-switch-to-modern-xmlunit.patch

Вариант 4

Править зависимости с помощью макросов %pom_*, иногда там просто ненужные зависимости, без которых сборка идет, иногда зависимости переименовывались, примеры: https://abf.io/vsos_java/maven-site-plugin/commit/9cff5f930d172f5116c86fb61d03bf5870c9c865
https://abf.io/vsos_java/findbugs/commit/9537f6ca3381458a36ad1584a8ecbd71f7be9767

Падает на этапе тестов

Добавить ключ -f к %mvn_build или починить по-нормальному.

Падает с руганью, что класс не переопределяет метод

Пример ошибки:

 org.springframework.mock.web.MockServletContext is not abstract and does not override abstract method
 setResponseCharacterEncoding(java.lang.String) in javax.servlet.ServletContext

Иногда требуется, чтобы в классе были переопределены все методы родительского класса. В новой версии сборочной зависимости, откуда класс наследуется, появляются новые методы, а они не переопределены, сборка падает. Решается добавлением заглушек с переопределением вновь появившихся функций, прототипы функций легко гуглятся, прототип должен совпадать с исходным (JLS 8.4.2, https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2), иногда требуется добавить "import <...>", чтобы подгрузить "типы".

Примеры:
https://abf.io/vsos_java/springframework/blob/82b3428a81/0001-Fix-building-with-Servlet-4.x.patch
https://abf.io/vsos_java/infinispan/blob/632e87228d/0001-Fix-building-with-jboss-marshalling-1.4.patch
https://abf.io/vsos_java/infinispan/blob/632e87228d/0002-Fix-building-with-Lucene-7.patch

Видео (скринкаст) с исправлением сборки пакета hornetq: https://youtu.be/Yt62_gVi9S8

Несовместим с новой версией зависимости

Идем в апстрим, ищем проблемный файл (он мог быть перемещен, иногда проще склонировать git и воспользоваться find), смотрим git history и git blame, в веб-морде Github это удобно делать, часто находим решением, которое бекпортируем, т.е. клонируем git, git checkout тег_с_версией (его узнаем так: git tag | grep версия), вносим правки, git diff или git commit -a + git format-patch -1, прикладываем к пакету. Иногда прокатит просто взятие коммиты с git и прикладывание патчем или git cherry-pick. Если ничего не находим, чешим затылок, пытаемся исправить.

Примеры:
https://abf.io/vsos_java/eclipse-webtools/commit/9abc9d41c16f2818eb976ba88f7ad9fe439c4d9f
https://abf.io/vsos_java/jersey/commit/bc0f5d0b8bad91e63cadba1181676f60312b4256
https://abf.io/vsos_java/hibernate/commit/cc6f937c190670655d98408eea05205fd0aaed1e
https://abf.io/vsos_java/shrinkwrap-resolver/commit/894243e67be87e3f70c4e912f0136275b8e71ad2

Иногда нужно переназначить одну и ту же функцию с разными аргументами, пример:
https://abf.io/vsos_java/aries-util/blob/75b6388e39/0001-Fix-building-with-modern-org.osgi.service.log.patch
В данном случае в документации https://docs.osgi.org/javadoc/osgi.cmpn/7.0.0/org/osgi/service/log/LoggerFactory.html видно, что есть getLogger() с разными аргументами. Каждый вариант должен быть переназначен. В процессе попыток исправить возникала ошибка:

 name clash: <L>getLogger(org.osgi.framework.Bundle,java.lang.String,java.lang.Class<L>) in org.apache.aries.util.log.Logger and
 <L>getLogger(org.osgi.framework.Bundle,java.lang.String,java.lang.Class<L>) in org.osgi.service.log.LoggerFactory have the same
 erasure, yet neither overrides the other

Она была связана с тем, что тип Logger есть в разных местах, поэтому пришлось прописать тип не Logger, а org.osgi.service.log.Logger, чтобы указать не на "ближайший" Logger, а на нужный.

Ошибка сборки из-за невалидного HTML в комментариях

Можно попробовать отключить сборку javadocs (%mvn_build --skip-javadoc) или запатчить, пример: https://abf.io/vsos_java/hibernate3/blob/70327f75f2/0001-Fix-invalid-HTML.patch

Не видит установленный пакет

Пример ошибки:

 error: package org.mozilla.javascript does not exist
 <...>
 error: cannot find symbol

При этом в коде проблемного файла написано:

 import org.mozilla.javascript.Context;
 import org.mozilla.javascript.EvaluatorException;
 import org.mozilla.javascript.Function;
 <...>

В Java import позволяет лишь вместо org.mozilla.javascript.Contex.XXX писать просто XXX, это не что-то типа подгрузки модуля в отличие от import в Python. Решается добавлением пути к нужному jar в переменную окружения $CLASSPATH, которую читает компилятор javac. Сделать это можно с помощью утилиты build-classpath из javapackages-tools, пример:

 export CLASSPATH="$(build-classpath apache-commons-logging xalan-j2 rhino)"

При этом эта команда выдает:

 $ build-classpath apache-commons-logging xalan-j2 rhino
 /usr/share/java/apache-commons-logging.jar:/usr/share/java/xalan-j2.jar:/usr/share/java/rhino.jar

В данном случае org.mozilla.javascript — это /usr/share/java/rhino.jar, его не было в $CLASSPATH и возникала ошибка выше. Пример исправления: https://abf.io/vsos_java/bsf/commit/f035865ae8832ece284ef45ee4b77743dcc3ec4e
Также полезная статья: https://wiki.debian.org/Java/Packaging/Ant

Генератор зависимостей RPM падает из-за неразрешимых артефактов

/usr/lib/rpm/maven.req (пакет javapackages-local) может выдавать ошибку такого плана:

 Unable to generate requires on unresolvable artifacts: org.apache.lucene:lucene-solr-grandparent:pom:5.5.0

из-за чего падает сборка пакета

Пример костылирования. Создаем копию генератора, из которой убираем падение при неразрешимом артефакте, используем его. Затем собираем пакет еще раз, когда пакет уже есть в репозитории, добавив его самого в сборочные зависимости.

%bcond_with bootstrap
%if %{with bootstrap}
# "Unable to generate requires on unresolvable artifacts: org.apache.lucene:lucene-solr-grandparent:pom:5.5.0"
%global __maven_requires %(if [ -e /usr/lib/rpm/maven.req ] ; then tmp=$(mktemp --suffix=_%{name}.%{version}.%{release}); cp /usr/lib/rpm/maven.req $tmp && chmod +x $tmp && echo $tmp ; else echo %{?__maven_requires} ; fi)
# see sed command in the end of %%install
%endif
<...>
%if %{without bootstrap}
# dep from itself
BuildRequires:  mvn(org.apache.lucene:lucene-solr-grandparent:pom:5.5.0)
%endif
<...>
%if %{with bootstrap}
# Do not throw an exception on unresolvable artefact (dependency from itself)
sed -i -e 's,if unresolvable:,if False:,g' "$(ls /tmp/*_%{name}.%{version}.%{release} -t | head -n 1)"
%endif

Первую сборку запускаем с "--with=bootstrap" в доп. параметрах, вторую без доп. параметров.