Дата и время публикации:
Проблемы и пути решения
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 и используется для получения исходного кода пакета следующие протоколы доступа к:
- file:// локальным местам хранения файлов-архива (именуемые часто TAR-боллы), файлов-заплаток, конфигурационных файлов и содержащие метаданные.
- bzr:// репозитарию системы контроля версий c Bazaar.
- git:// репозитарию системы контроля версий Git.
- osc:// репозитарию системы контроля версий OSC(Сервис сборки OpenSUSE),
- repo:// репозитарию Repo, являющийся дополнением Git .
- http(s):// удаленным местам хранения файлов-архива и т.п. по протоколу HTTP(S).
- ftp:// удаленным местам хранения файлов-архива и т.п. по протоколу FTP
- cvs:// репозитариям системы контроля версий CVS
- hg:// репозитариям системы контроля версий HG, известный как Mercurial
- p4:// репозитариям системы контроля версий p4
- ssh:// удаленным местам хранения файлов-архива и т.п. по протоколу безопасной командной оболочки (SSH)
- svn:// удаленным местам хранения файлов-архива и т.п. репозитария системы контроля версий SVN
Таким образом, вся проблема состоит из правильного определение переменной '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://" и являться абсолютным или относительным путем на сборочной машине, где находится скачиваемый файл.
При этом, если
- имя файла является относительным путем, содержимое переменной FILESPATH содержит пути поиска, где следует искать скачиваемый файл в первую очередь;
- файл не может быть найден по указанным путям в FILESPATH, BitBake считает, что он доступен в директории, определенной в DL_DIR .
В переменной 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о следующие расширениями:
- gzip: .tar.gz, .tgz (в случае ограничений файловой системы на длину расширения), .tar.gzip;
- bzip2: .tar.bz2, .tar.bzip2, .tbz2, .tb2, .tbz
- ZIP: .zip .
Так же, в директории 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.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