× К оглавлению На главную Об авторе

Дата и время публикации:    

Проблемы и пути решения

1. Проблема

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

Исполнительная частью указанной системы автоматической сборки является BitBake, который построен по модульному принципу и обеспечивающий выполнение отдельных задач от получения исходного кода, формирования, конфигурирования, сборки и компиляции, до момента встраивания в образ пакета программного обеспечения. В частности, при выполнение процедуры получения и распаковки перечисленных типов, файлов BitBake выполняется обход множеств адресов в глобальной сети Интернет в части проекта.

Так, если посмотреть на историю выполнения задач пакета bash в журнала ${WORKDIR}/temp/log.task_order, как показано в дампе 1.1

Дамп 1.1

do_fetch (2147659): log.do_fetch.2147659
do_unpack (2190037): log.do_unpack.2190037
do_patch (2190070): log.do_patch.2190070
do_prepare_recipe_sysroot (2191975): log.do_prepare_recipe_sysroot.2191975
do_configure (2191984): log.do_configure.2191984
do_configure_ptest_base (2386449): log.do_configure_ptest_base.2386449
do_compile (2386451): log.do_compile.2386451
do_compile_ptest_base (2518079): log.do_compile_ptest_base.2518079
do_install (2518110): log.do_install.2518110
do_install_ptest_base (2675265): log.do_install_ptest_base.2675265
do_package (2675291): log.do_package.2675291
do_packagedata (2680344): log.do_packagedata.2680344
do_package_write_deb (3280021): log.do_package_write_deb.3280021
do_populate_lic (3352745): log.do_populate_lic.3352745
do_package_qa (3373350): log.do_package_qa.3373350
do_populate_sysroot (3417505): log.do_populate_sysroot.3417505

Первые две строчки, выделенные жирным, занимают сообщения о выполнении процедуры do_fetch() и do_unpack(), отвечающие за загрузку и распаковку исходного кода пакета bash в BitBake и соответствующих модулям fetch и unpack, методы задач которых определены в виде функций, реализуемыми написанными в стиле Python базовыми функциями base_do_fetch() и base_do_unpack() .

Соответстветственно, за загрузкой и распаковкой исходного кода пакета bash в BitBake отвечают модули fetch и unpack, реализация которых определены в виде базовых функций base_do_fetch() и base_do_unpack() и написанных в стиле Python .

Получение исходного кода пакета функцией base_do_fetch() производится согласно алгоритму, текст которого приводится в листинге 1.2

Листинг 1.2. Фрагмент файла base.bbclass базового слоя meta

...
144 addtask fetch
145 do_fetch[dirs] = "${DL_DIR}"
...
148 do_fetch[vardeps] += "SRCREV"
149 python base_do_fetch() {
150 
151     src_uri = (d.getVar('SRC_URI') or "").split()
152     if len(src_uri) == 0:
153        return
154
155    try:
156        fetcher = bb.fetch2.Fetch(src_uri, d)
157        fetcher.download()
158    except bb.fetch2.BBFetchException as e:
159        bb.fatal(str(e))
160 }
...

Как видно из листинга 1.2,

В строке 144, производится объявление директории DL_DIR куда будут складываться полученные файлы-архивы, файлов конфигурации, реализующие рекомендации безопасности файлов-заплаток, метаданных и т.п. файлов из локальных и удаленных источников.

В строке 148, к уже объявленным переменным, например такой как SRC_URI, добавляется SRCREV, которая будет использоваться для получения наиболее выгодной ревизии загружаемого из репозитария исходного кода.

В строках 149, … , 160 описан сам процесс загрузки, который заключается в извлечение значения src_uri из переменной 'SRC_URI' файла рецепта с расширением .bb, через символ пробела указывается все доступные адреса источников удаленных и локальных репозитариев. При этом, если посмотреть результат лексического разбора, как показано в дампе 1.3, то увидим, что src_uri является массивом адресов источников URI .

Листинг 1.2. Фрагмент файла base.bbclass базового слоя meta

['https://ftp.gnu.org/gnu/bash/bash-4.4.18.tar.gz;name=tarball', 
 'https://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-019;apply=yes;striplevel=0;name=patch019',
'https://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-020;apply=yes;striplevel=0;name=patch020', 'https://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-021;apply=yes;striplevel=0;name=patch021', 'https://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-022;apply=yes;striplevel=0;name=patch022', 'https://ftp.gnu.org/gnu/bash/bash-4.4-patches/bash44-023;apply=yes;striplevel=0;name=patch023', 'file://execute_cmd.patch;striplevel=0',
'file://mkbuiltins_have_stringize.patch', 
'file://build-tests.patch', 
'file://test-output.patch', 
'file://fix-run-coproc-run-heredoc-run-execscript-run-test-f.patch', 
'file://run-ptest', 
'file://fix-run-builtins.patch', 
'file://0001-help-fix-printf-format-security-warning.patch', 'file://pathexp-dep.patch']

Содержимое массива полностью соответствует BitBake переменной SRC_URI рецепта bash, объявление которой приводится в листинге 1.4

Листинг 1.4. фрагмент файла bash_4.4.18.bb рецепта recipes-extended/bash слоя meta

...
  6:
  7:SRC_URI = "${GNU_MIRROR}/bash/${BP}.tar.gz;name=tarball \
  8:           ${GNU_MIRROR}/bash/bash-4.4-patches/bash44-019;apply=yes;striplevel=0;name=patch019 \
  9:           ${GNU_MIRROR}/bash/bash-4.4-patches/bash44-020;apply=yes;striplevel=0;name=patch020 \
 10:           ${GNU_MIRROR}/bash/bash-4.4-patches/bash44-021;apply=yes;striplevel=0;name=patch021 \
 11:           ${GNU_MIRROR}/bash/bash-4.4-patches/bash44-022;apply=yes;striplevel=0;name=patch022 \
 12:           ${GNU_MIRROR}/bash/bash-4.4-patches/bash44-023;apply=yes;striplevel=0;name=patch023 \
 13:           file://execute_cmd.patch;striplevel=0 \
 14:           file://mkbuiltins_have_stringize.patch \
 15:           file://build-tests.patch \
 16:           file://test-output.patch \
 17:           file://fix-run-coproc-run-heredoc-run-execscript-run-test-f.patch \
 18:           file://run-ptest \
 19:           file://fix-run-builtins.patch \
 20:           file://0001-help-fix-printf-format-security-warning.patch \
 21:           file://pathexp-dep.patch \
 22:           "
...

Затем, проверяется в строках 156,157 листинга 1.2, что массив SRC_URI не является нулевым и в случае положительного результата проверки выполняется fetcher, который производит загрузку перечисленных файлов, перечисленных в нем. При этом функция base_do_fetch() может завершится с исключением и печатью на консоль сообщения с описанием случившейся ошибки.

Подобную реализацию имеет функция base_do_fetch(), которая показана в листинге 1.5 .

Листинг 1.5. Фрагмент файла base.bbclass базового слоя meta

...
165 addtask unpack after do_fetch
166 do_unpack[dirs] = "${WORKDIR}"
...
167 python base_do_unpack() {
168    src_uri = (d.getVar('SRC_URI') or "").split()
169    if len(src_uri) == 0:
170        return
171    try:
172        fetcher = bb.fetch2.Fetch(src_uri, d)
173        fetcher.unpack(d.getVar('WORKDIR'))
174    except bb.fetch2.BBFetchException as e:
175        bb.fatal(str(e))
176 }
...

При этом, если взглянуть в листинг 1.2 и листинг 1.5, различие состоит в том, что функция base_do_unpack() будет выполнена только после завершения с положительным результатом задачи fetch, объявление директории WORKDIR куда будут распаковываться и выкладываться файлы исходного кода, а так же использование fetcher метода unpack(), взамен download .

Функция download() которая является конечной реализацией всего зоопарка протоколов прикладного уровня стека TCP/IP и используется для получения исходного кода пакета следующие протоколы доступа к:

Таким образом, вся проблема состоит из правильного определение переменной 'SRC_URI' в файле рецепта с расширением .bb и ей подобных, таких как SRC_URI_git, SRC_URI_append_% и т.п.

2. Решение

Получение и распаковка

Несмотря на то, что базовая функция base_do_fetch() и base_do_unpack(), как уже упоминалось выше, описана в базовом классе первичного слоя meta, в основном она оперирует с методами глобальных BitBake переменных bb.fetch2.Fetch .

Как показывает жизнь, самым распространенным протоколами из всех перечисленных выше для получения пакетов являются file://, git://, https://, http:// и ftp:// . При этом нужно понимать, что последние два протокола http:// и ftp:// в ближайшем будущем могут потерять свою актуальность из-за проблем обеспечения безопасности получения данных.

2.1 Локальное получение (протокол file://)

Реализуется подмодулем в директории bitbake/lib/bb/fetch2. Адрес источника URI должен быть указан в виде абсолютного пути от корня файловой системы или относительный путь, при использование которого должна быть определена FILESPATH, являющейся тождественной по смыслу переменной $PATH командной оболочки, которая, в свою очередь ищет исполняемые файлы. В противном случае, FILESDIR будет использовать поиск соответствующих относительных файлов . Ниже, в листинге 2.1.1, приведены варианты объявления адресов URI .

Листинг 2.1.1

SRC_URI = "file://relativefile.patch"
SRC_URI = "file://relativefile.patch;this=ignored"
SRC_URI = "file:///Users/ich/very_important_software"

Пример объявления локального получения файлов по протоколу file:// для популярного пакета bzip2 приведен в листинге 2.1.2

Листинг 2.1.2

...
     SRC_URI = "http://downloads.yoctoproject.org/mirror/sources/${BP}.tar.gz \      
           file://fix-bunzip2-qt-returns-0-for-corrupt-archives.patch \         
           file://configure.ac;subdir=${BP} \
           file://Makefile.am;subdir=${BP} \
           file://run-ptest \
           file://CVE-2016-3189.patch \
           file://CVE-2019-12900.patch \
           file://fix-regression-CVE-2019-12900.patch \
           "           
...

В нем, показаны объявление относительных локальных путей файлов конфигурации configure.ac и Makefile.am, скрипта запуска тестов run-ptest, а также файлов-заплаток с расширением patch, которые находятся в том же самом месте, где и файл рецепта .bb .

2.2 Директория DL_DIR

Каждый локальный адрес источника URI должен начинаться с "file://" и являться абсолютным или относительным путем на сборочной машине, где находится скачиваемый файл.

При этом, если

В переменной DL_DIR указывается центральная директория от текущей рабочей сборочной директории builddir, окружение которой определяется скриптом oe-init-build-env, как показано в дампе 2.2.1

Дамп 2.2.1

$ . oe-init-build-env builddir
### Shell environment set up for builds. ###

You can now run 'bitbake '

Common targets are:
    core-image-minimal
    core-image-sato
    meta-toolchain
    meta-ide-support
    
You can also run generated qemu images with a command like 'runqemu qemux86'

BitBake сохраняет в директории DL_DIR все загружаемые файлы архивы исходного кода и конфигурации, также как реализующие рекомендации бюллетеней безопасности файлов-заплаток, метаданных и т.п. файлов, получаемых из удаленных и локальных репозитариев. За исключением, репозитариев системы контроля версий Git . В противном случае, если есть желание получать файлы архива исходного кода, именуемых часто tarball, из репозитраия Git, следует использовать переменную BB_GENERATE_MIRROR_TARBALLS, как показано в дампе 2.2.2

Дамп 2.2.2

SOURCE_MIRROR_URL ?= "file:///source_mirror/sources/"
INHERIT += "own-mirrors" 
BB_GENERATE_MIRROR_TARBALLS = "1"
BB_NO_NETWORK = "1"

Как видно из примера выше, определением в conf/local.conf: одной переменной BB_GENERATE_MIRROR_TARBALLS не отделаешься, т. к. нужно указать SOURCE_MIRROR_URL откуда будут браться в случае отказа от удаленного доступа к сети BB_NO_NETWORK . При этом нужно иметь архивы репозитариев, о которых будет рассказано ниже.

2.3 Семейство протоколов удаленного получения WGET (https://, http:// и ftp:// и ftps://)

Производится получение файлов из WEB и FTP с использованием утилиты WGET(1) . При этом сам исполняемый файл и разумные значения параметров по умолчанию прописываются в переменной FETCHCMD_wget или устанавливаются по умолчанию, как "/usr/bin/env wget -t 2 -T 30 --passive-ftp —no-check-certificate", в случае если она не была определена.

Кроме того, в строке адреса URI поддерживается параметр "downloadfilename", так же как и "name", которые позволяют различать имена загружаемых файлов во избежание конфликтов из-за множества встречающихся файлов с одним и тем же именем в DL_DIR. Пример определения параметра приводится в листинге 2.3.1

Листинг 2.3.1

...
SRC_URI = "${GNU_MIRROR}/aspell/aspell-${PV}.tar.gz;downloadfilename=test-aspell.tar.gz
...

В листинге 2.3.2, приведены варианты объявления адресов URL для популярного пакета bzip2, как показано в листинге 2.3.2

Листинг 2.3.2

...
     SRC_URI = "http://downloads.yoctoproject.org/mirror/sources/${BP}.tar.gz \      
           file://fix-bunzip2-qt-returns-0-for-corrupt-archives.patch \         
           file://configure.ac;subdir=${BP} \
           file://Makefile.am;subdir=${BP} \
           file://run-ptest \
           file://CVE-2016-3189.patch \
           file://CVE-2019-12900.patch \
           file://fix-regression-CVE-2019-12900.patch \
           "
...

2.4 Добавление файлов в переменную SRC_URI

При этом можно представить запись адресов источников URI следующим образом, как показано в листинге 2.4.1

Листинг 2.4.1

...
SRC_URI += "file://fix-bunzip2-qt-returns-0-for-corrupt-archives.patch"         
SRC_URI += "file://configure.ac;subdir=${BP}"
SRC_URI += "file://Makefile.am;subdir=${BP}"
SRC_URI += "file://run-ptest" 
SRC_URI += "file://CVE-2016-3189.patch"
SRC_URI += "file://CVE-2019-12900.patch"
SRC_URI += "file://fix-regression-CVE-2019-12900.patch"
...

Именно, так добавляются файлы c расширением .bbappend, как показано в дамп 2.4.2

Листинг 2.4.2

FILESEXTRAPATHS_prepend := "${THISDIR}:"
SRC_URI += "file://fix-bunzip2-qt-returns-0-for-corrupt-archives.patch"         
SRC_URI += "file://configure.ac;subdir=${BP}"
SRC_URI += "file://Makefile.am;subdir=${BP}"
SRC_URI += "file://run-ptest" 
SRC_URI += "file://CVE-2016-3189.patch"
SRC_URI += "file://CVE-2019-12900.patch"
SRC_URI += "file://fix-regression-CVE-2019-12900.patch"

В котором показано, как выглядел бы файл bzip2_%.bbappend в вашем meta-слое в случае необходимости добаваления дополнительных файлов метаданных, изменяющие правила конфигурации сборки исходного кода пакета, и/или накладывающие заплатки безопасности после выполнения функции do_unpack() .

В результате все загружаемые файлы архивов исходного кода, получаемые из удаленных источников по протоколам семейства WGET и Git, будут сохранены в директории DL_DIR на этапе выполнения функции do_fetch()/do_unpack(), имя которого состоит из имени пакета (переменная PN) и версии (переменная PV) cо следующие расширениями:

Так же, в директории DL_DIR будут сохранены и локальные файлы описываемые протоколом file:// .

2.5 Удаленное получение c Git репозитария

Производится получение "голого" репозитария из удаленного хранилища, управляемый системой контроля версиями и который сохраняется в виде отдельной поддиректории в директории GITDIR, а если она не определена в ${DL_DIR}/git2/* . При этом в переменной FETCHCMD_git может быть переопределен исполняемый файл, по умолчанию установлен /usr/bin/git . В листинге 2.5.1 приводится пример объявления SRC_URI, используемый в рецепте популярного пакета binutils .

Листинг 2.5.1

...
26:BRANCH ?= "binutils-2_32-branch"
27:
28:UPSTREAM_CHECK_GITTAGREGEX = "binutils-(?P\d+_(\d_?)*)"
29:
30:SRCREV ?= "b8c1f608db9ef3edd483d21a921d1fbedc71df6f"
31:BINUTILS_GIT_URI ?= "git://sourceware.org/git/binutils-gdb.git;branch=${BRANCH};protocol=git"
32:SRC_URI = "\
33:     ${BINUTILS_GIT_URI} \
...

Как показано в листинге 2.5.1, в строке 31 устанавливается переменная BINUTILS_GIT_URI, которая будет открывать перечисление адресов источников URI в строке 33 переменной SRC_URI . Так же хочется обратить внимание на переменную UPSTREAM_CHECK_GITTAGREGEX, которая заставит всегда проверять, что из репозитария Git была взята актуальная версия. Так же в строке 30 была указана SRCREV, которая позволяет извлекать более актуальную ревизию исходного кода, для указанной в строке 26, переменной BRANCH ветви "binutils-2_32-branch" .

Кроме того, в переменной BINUTILS_GIT_URI были указаны параметры branch и protocol после адресной строки URI через точку с запятой . Поэтому ниже будут перечислены самые ходовые и востребованные параметры используемые в модуле fetch2 для реализации протокола Git .

Параметр "branch"

Указывает на текущую используемую ветвь репозитария. По умалчанию ей является "master". Также в этом параметре можно указать несколько имен ветвей. При этом их число должно совпадать с ветвями, которые используются для определения SRC_REV для каждой ветви, как показывает правило 2.5.2

Правило 3.5.2


   SRC_URI="git://some.host/somepath;branch=branchX,branchY;name=nameX,nameY"
   SRCREV_nameX = "xxxxxxxxxxxxxxxxxxxx"
   SRCREV_nameY = "YYYYYYYYYYYYYYYYYYYY"

Параметр "tag"

По мимо явного указания имени ветви в Git существует возможность указывать ключевые точки в истории репозитария, которые, обычно, используются для обозначения так называемых поинт-релизов или промежуточных версий, например v1.0, v2.0 и т.д. По умолчанию указан "master" .

Параметр "protocol"

Протокол транспортного уровня стека tcp/ip, с помощью которого осуществляется доступ к репозитарию. Поддерживаются следующие протоколы "http", "https", "file", "ssh" и "rsync". По умолчанию установлен "git".

Параметр "name"

Кроме того, поддерживается параметр "name", для уточнения имени загружаемого репозитария .

2.6 Получение "Голого" репозитария

Бывает полезно, особенно в случае Yocto/poky, когда тянется большое количество исходных текстов и существует риск получения избыточности хранения одних и тех же данных, в подиректории .git рабочей директории и её корне. Поэтому проект Yocto/poky производит получение "голого" репозитария, как показано в дампе 2.6.1, и который содержит теже самые исходные данные, с ветлением и всеми ревизиями исходного кода .

Дамп 2.6.1

LANG=C git clone --bare --mirror https://github.com/rjaan/procps_ptree.git github.com.rjaan.procps_ptree.git --progress  

Как показано в дампе 2.6.1, использование опции --bare приводит к клонированию "голого" репозитария без рабочей директории, который затем запаковывают их в архивный файл .tar.gz согласно дампу 2.6.2 .

Дамп 2.6.2

cd github.com.rjaan.procps_ptree.git
tar -czf ${DL_DIR}/github.com.rjaan.procps_ptree.git.tar.gz .

При этом результаты получения и восстановления репозитария могут отличаться с теми, что были показаны выше в листинге 2.6.1, если будет выполнена git clone -b ${BRANCH} "голый " репозитарий будет содержать данные только для указанной ветви в переменной BRANCH .

2.7 Восстановление рабочей директории репозитария

Для получения рабочей директории проекта procps_ptree из "голого" репозитария следует внутри директории github.com.rjaan.procps_ptree.git создать поддиректорию .git и, затем, переместить всю конфигурацию HEAD в только что созданную директорию .git , как показано в дампе 2.7.1

Дамп 2.7.1

cd github.com.rjaan.procps_ptree.git/ && mkdir .git
mv config  .git/
mv FETCH_HEAD .git/
mv HEAD .git/
mv hooks/ .git/
mv logs/ .git/
mv objects/ .git/
mv packed-refs .git/
mv refs/ .git/

Для конвертирования "Голого" репозитария выполнить команду git config, как показано в дамп 2.7.2

Дамп 2.7.2

LANG=C git config --local --bool core.bare false

Для получения содержимого ветви "master" следует выполнить команду , как показано в дампе 2.7.3

Дамп 2.7.2

$ LANG=C git reset --hard
HEAD is now at b8d4e82 Update field secure in .travis.yml

Поэтому, все-таки производить слияние с "master" ветви, относящуюся к последней стабильной версии, как ранее писал в стратегиях управлением репозитарием.

3. Библиография

3.1 BitBake User manual. variable SRC_URI

3.2 BitBake User manual. variable fetchers

3.3 BitBake Mega manual

3.4 BitBake User manual. variable DL_DIR

3.5 BitBake User manual. variable FILESPATH

3.6 WiKi YoctoProject.Org. How do I

3.7 Howto use local mirror to build yocto filesystem from internal server

3.8 Howto convert bare git repository into normal

3.9 What is the difference between git init and git-init bare

Сайт разработан в соответствии с рекомендациями консорциума W3C для языка разметки HTML5.

Об авторе можно прочитать здесь.

Copyright © 2015-2019 Андрей Ржавсков