{"id":6095,"date":"2024-06-03T09:00:00","date_gmt":"2024-06-03T08:00:00","guid":{"rendered":"https:\/\/www.blaess.fr\/christophe\/?p=6095"},"modified":"2024-06-03T06:40:37","modified_gmt":"2024-06-03T05:40:37","slug":"utiliser-git-lfs-avec-yocto-kirkstone-scarthgap","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2024\/06\/03\/utiliser-git-lfs-avec-yocto-kirkstone-scarthgap\/","title":{"rendered":"Utiliser Git LFS avec Yocto Kirkstone\/Scarthgap"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">La fonctionnalit\u00e9 LFS (<em>Large File Support<\/em>) permet de superviser avec <code>git<\/code> des fichiers volumineux en \u00e9vitant les t\u00e9l\u00e9chargements longs. Lors d&rsquo;une op\u00e9ration <code>git clone<\/code>, le fichier original est remplac\u00e9 par un fichier de r\u00e9f\u00e9rence beaucoup plus petit. Le remplacement inverse par le contenu initial n&rsquo;a lieu que sur demande explicite.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Les anciennes versions de Yocto Project \u00e9taient capable d&rsquo;extraire automatiquement les contenus LFS, mais il semble que cette fonctionnalit\u00e9 ait disparue depuis la branche Kirkstone de Poky. Nous pouvons y rem\u00e9dier assez simple en appelant explicitement <code>git lfs pull<\/code> dans une recette. Toutefois, l&rsquo;\u00e9criture de la fonction n\u00e9cessaire n&rsquo;est pas intuitive et s&rsquo;av\u00e8re plut\u00f4t int\u00e9ressante.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Cr\u00e9ation d&rsquo;un repository utilisant Git LFS.<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Je commence par cr\u00e9er un <em>repository<\/em> <code>git<\/code> local, dans lequel je cr\u00e9e un fichier d&rsquo;un gigagoctet de donn\u00e9es al\u00e9atoires.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>mkdir  git-lfs-and-yocto-project<\/strong>\n\n$ <strong>cd  git-lfs-and-yocto-project\/<\/strong>\n\n$ <strong>git  init<\/strong>\nInitialized empty Git repository in \/home\/cpb\/git-lfs-and-yocto-project\/.git\/\n\n$ <strong>dd  if=\/dev\/urandom  of=my-large-file  bs=1G  count=1<\/strong>\n1+0 records in\n1+0 records out\n1073741824 bytes (1,1 GB, 1,0 GiB) copied, 3,35781 s, 320 MB\/s<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le package <code>git-lfs<\/code> est install\u00e9 au pr\u00e9alable sur ma machine, je vais l&rsquo;initialiser dans ce r\u00e9pertoire.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>git  lfs install<\/strong>\nUpdated git hooks.\nGit LFS initialized.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je demande \u00e0 <code>git lfs<\/code> de prendre en charge ce fichier, ce qui va cr\u00e9er un fichier  <code>.gitattributes<\/code> que j&rsquo;ajoute au suivi de <code>git<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>git  lfs  track  my-large-file<\/strong>\nTracking \"my-large-file\"\n\n$ <strong>ls  -a<\/strong>\n.  ..  .git  .gitattributes  my-large-file\n\n$ <strong>cat  .gitattributes <\/strong>\nmy-large-file filter=lfs diff=lfs merge=lfs -text\n\n$ <strong>git  add  .gitattributes <\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je peux alors ajouter puis commiter le fichier d&rsquo;un gigaoctet comme habituellement&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>git  add  my-large-file <\/strong>\n\n$ <strong>git  commit  my-large-file  -m 'Adding a very interesting large file'<\/strong>\n&#91;master (root-commit) 3625817] Adding a very interesting large file\n 1 file changed, 3 insertions(+)\n create mode 100644 my-large-file\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Enfin, je pousse le <em>repository<\/em> vers un d\u00e9p\u00f4t Github cr\u00e9\u00e9 pour l&rsquo;occasion.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>git  remote  add origin  git@github.com:cpb-\/git-lfs-and-yocto-project.git<\/strong>\n\n$ <strong>git  push  -u  origin master<\/strong>\nUploading LFS objects: 100% (1\/1), 1.1 GB | 9.4 MB\/s, done.                                                                                                   \nEnumerating objects: 3, done.\nCounting objects: 100% (3\/3), done.\nDelta compression using up to 12 threads\nCompressing objects: 100% (2\/2), done.\nWriting objects: 100% (3\/3), 353 bytes | 353.00 KiB\/s, done.\nTotal 3 (delta 0), reused 0 (delta 0), pack-reused 0\nTo github.com:cpb-\/git-lfs-and-yocto-project.git\n * &#91;new branch]      master -&gt; master\nBranch 'master' set up to track remote branch 'master' from 'origin'.\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pour v\u00e9rifier que <code>git lfs<\/code> est bien en oeuvre, je supprime le r\u00e9pertoire et je clone le <em>repository<\/em> depuis Github.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>cd  ..<\/strong>\n\n$ <strong>rm  -rf  git-lfs-and-yocto-project\/<\/strong>\n\n$ <strong>git  clone  https:\/\/github.com\/cpb-\/git-lfs-and-yocto-project.git<\/strong>\nCloning into 'git-lfs-and-yocto-project'...\nremote: Enumerating objects: 3, done.\nremote: Counting objects: 100% (3\/3), done.\nremote: Compressing objects: 100% (2\/2), done.\nremote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0\nReceiving objects: 100% (3\/3), done.\n\n$ <strong>cd  git-lfs-and-yocto-project\/<\/strong>\n\n$ <strong>ls  -l<\/strong>\ntotal 4\n-rw-rw-r-- 1 cpb cpb 135 juin   1 08:03 my-large-file\n\n$ <strong>cat  my-large-file <\/strong>\nversion https:\/\/git-lfs.github.com\/spec\/v1\noid sha256:1c8e5f10aa5e18b3d6aebaee0d5122f8e674057dbd52a8854cad49c929621681\nsize 1073741824\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Pour obtenir le contenu r\u00e9el de mon fichier, je dois le demander explicitement \u00e0 <code>git lfs<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>git  lfs  pull<\/strong>\nDownloading LFS objects: 100% (1\/1), 1.1 GB | 37 MB\/s                                                                                                         \n\n$ <strong>ls  -l<\/strong>\ntotal 1048580\n-rw-rw-r-- 1 cpb cpb 1073741824 juin   1 08:08 my-large-file<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Si vous souhaitez faire le test vous-m\u00eame, l&rsquo;URL <a href=\"https:\/\/github.com\/cpb-\/git-lfs-and-yocto-project.git\">https:\/\/github.com\/cpb-\/git-lfs-and-yocto-project.git<\/a> est accessible publiquement pendant quelques temps. N\u00e9anmoins je ne la conserverai pas ind\u00e9finiment car elle consomme inutilement du volume de stockage dans mon espace Github LFS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Git LFS et Yocto Project<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Pour faire mes essais, je vais construire rapidement un environnement de <em>build<\/em> minimal pour Yocto<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>mkdir  layers<\/strong>\n\n$ <strong>cd  layers\/<\/strong>\n\n$ <strong>git  clone git:\/\/git.yoctoproject.org\/poky  -b  scarthgap<\/strong>\nCloning into 'poky'...\nremote: Enumerating objects: 647916, done.\nremote: Total 647916 (delta 0), reused 0 (delta 0), pack-reused 647916\nReceiving objects: 100% (647916\/647916), 205.39 MiB | 45.10 MiB\/s, done.\nResolving deltas: 100% (471176\/471176), done.\n\n$ <strong>cd  ..<\/strong>\n\n$ <strong>mkdir  builds<\/strong>\n\n$ <strong>source  layers\/poky\/oe-init-build-env  builds\/build-test<\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je cr\u00e9e un layer sp\u00e9cifique pour pouvoir y d\u00e9velopper ma recette<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake-layers  create-layer ..\/..\/layers\/meta-test<\/strong>\nNOTE: Starting bitbake server...\nAdd your new layer with 'bitbake-layers add-layer ..\/..\/layers\/meta-test'\n\n$ <strong>bitbake-layers  add-layer ..\/..\/layers\/meta-test<\/strong>\nNOTE: Starting bitbake server...\n\n$ <strong>mkdir  -p  ..\/..\/layers\/meta-test\/recipes-test\/git-lfs-test<\/strong><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et je cr\u00e9e une recette qui t\u00e9l\u00e9charge notre d\u00e9pot pour copier le fichier sur la cible<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>cat ..\/..\/layers\/meta-test\/recipes-test\/git-lfs-test\/git-lfs-test.bb<\/strong>\n\nSUMMARY = \"Small recipe to test `git lfs` downloading\"\nLICENSE = \"MIT\"\nLIC_FILES_CHKSUM = \"file:\/\/${COMMON_LICENSE_DIR}\/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302\"\n\nSRC_URI += \"git:\/\/github.com\/cpb-\/git-lfs-and-yocto-project;protocol=https;branch=master\"\nSRCREV = \"${AUTOREV}\"\nS = \"${WORKDIR}\"\n\ninherit allarch\n\ndo_install() {\n        install -d ${D}\/data\n        install -m 0644 ${S}\/my-large-file ${D}\/data\n}\n\nFILES:${PN} += \"data\/my-large-file\"\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Je lance un <em>build<\/em> pour produire le r\u00e9sultat de cette recette&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake  git-lfs-test<\/strong>\nLoading cache: 100% |###########################################################| Time: 0:00:00\nLoaded 1878 entries from dependency cache.\nParsing recipes: 100% |##########################################################| Time: 0:00:00\nParsing of 923 .bb files complete (922 cached, 1 parsed). 1879 targets, 47 skipped, 0 masked, 0 errors.\nNOTE: Resolving any missing task queue dependencies\n\nBuild Configuration:\nBB_VERSION           = \"2.8.0\"\nBUILD_SYS            = \"x86_64-linux\"\nNATIVELSBSTRING      = \"universal\"\nTARGET_SYS           = \"x86_64-poky-linux\"\nMACHINE              = \"qemux86-64\"\nDISTRO               = \"poky\"\nDISTRO_VERSION       = \"5.0.1\"\nTUNE_FEATURES        = \"m64 core2\"\nTARGET_FPU           = \"\"\nmeta                 \nmeta-poky            \nmeta-yocto-bsp       = \"scarthgap:c5df9c829a549ca002c36afd6bdf23639831502e\"\nmeta-test            = \"&lt;unknown&gt;:&lt;unknown&gt;\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Au bout de quelques minutes je peux regarder le contenu du r\u00e9pertoire <code>image<\/code> de la recette <code>git-lfs-test<\/code> correspondant au contenu \u00e0 copier sur la cible.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>ls  tmp\/work\/all-poky-linux\/git-lfs-test\/1.0\/image\/data\/ -l<\/strong>\ntotal 4\n-rw-r--r-- 1 cpb cpb 135 juin 1 09:50 my-large-file<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Le fichier ne fait que 135 octets, il s&rsquo;agit juste de la r\u00e9f\u00e9rence LFS, pas du contenu r\u00e9el du fichier. Pour obtenir ce contenu, je dois appeler <code>git lfs pull<\/code> dans une fonction de ma recette.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Supposons que ce contenu soit n\u00e9cessaire pour la phase l&rsquo;\u00e9tape <code>do_compile<\/code> et que nous ne puissions pas nous contenter de l&rsquo;ajouter au d\u00e9but de <code>do_install<\/code>. La premi\u00e8re id\u00e9e est g\u00e9n\u00e9ralement de vouloir \u00e9crire un <code>do_fetch:append()<\/code> toutefois cela ne fonctionne pas, l&rsquo;\u00e9tape <code>do_fetch()<\/code> se contente de remplir le r\u00e9pertoire <code>downloads<\/code>. En effet&nbsp;: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake  -c cleanall  git-lfs-test<\/strong>\n  &#91;...]\n$ <strong>bitbake  -c fetch git-lfs-test<\/strong>\n  &#91;...]\n$ <strong>ls  tmp\/work\/all-poky-linux\/git-lfs-test\/1.0\/<\/strong>\nrecipe-sysroot  recipe-sysroot-native  temp\n\n$ <strong>ls  downloads\/git2\/<\/strong>\ngithub.com.cpb-.git-lfs-and-yocto-project       \ngithub.com.cpb-.git-lfs-and-yocto-project.done\n &#91;...]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nous allons plut\u00f4t ajouter notre code apr\u00e8s le d\u00e9ploiement du d\u00e9p\u00f4t Git dans le r\u00e9pertoire de travail, l&rsquo;\u00e9tape <code>do_unpack<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake  -c unpack  git-lfs-test<\/strong>\n &#91;...]\n$ <strong>ls  tmp\/work\/all-poky-linux\/git-lfs-test\/1.0\/git<\/strong>\nmy-large-file<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Par habitude, j&rsquo;aurais tendance \u00e0 ajouter dans ma recette une fonction&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>do_unpack:append() {\n        git -C ${S} lfs pull\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Toutefois, cela \u00e9choue avec une erreur&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TabError: inconsistent use of tabs and spaces in indentation\n\nERROR: Parsing halted due to errors, see error messages above<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">La fonction <code>do_unpack()<\/code> d&rsquo;origine est en effet \u00e9crite en Python. Notre extension ne peut s&rsquo;\u00e9crire qu&rsquo;en Python \u00e9galement. Bien s\u00fbr on pourrait se d\u00e9brouiller avec <code>os.system()<\/code>, mais si le script \u00e0 ex\u00e9cuter \u00e9tait plus compliqu\u00e9, nous aurions des difficult\u00e9s \u00e0 le traduire int\u00e9gralement en Python.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Une autre solution est d\u00e9crire une nouvelle fonction que l&rsquo;on ins\u00e8re dans la cha\u00eene de tra\u00eetements de Bitbake. Cette fonction peut contenir des commandes <em>shell<\/em> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>do_git_lfs() {\n        git -C ${S} lfs pull\n}\naddtask git_lfs after do_unpack before do_patch\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">L&rsquo;erreur est moins compr\u00e9hensible a priori:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>error: failed to fetch some objects from 'https:\/\/github.com\/cpb-\/git-lfs-and-yocto-project.git\/info\/lfs'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Impossible d&rsquo;acc\u00e9der \u00e0 Github&nbsp;! En creusant un peu, on s&rsquo;aper\u00e7oit que le code de notre fonction n&rsquo;a pas acc\u00e8s du tout au r\u00e9seau. Il existe en effet des <em>flags<\/em> qui permettent de configurer l&rsquo;environnement dans lequel la fonction est ex\u00e9cut\u00e9e (voir le paragraphe <a href=\"https:\/\/docs.yoctoproject.org\/bitbake\/2.8\/bitbake-user-manual\/bitbake-user-manual-metadata.html#variable-flags\" target=\"_blank\" rel=\"noreferrer noopener\">Variable Flags<\/a> dans la documentation de Bitbake pour plus de d\u00e9tails). Il nous faut activer le <em>flag<\/em> \u00ab\u00a0<em>network<\/em>\u00a0\u00bb en ajoutant la ligne suivante apr\u00e8s la ligne <code>addtask<\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>do_git_lfs&#91;network] = \"1\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Cette fois, enfin nous obtenons le r\u00e9sultat d\u00e9sir\u00e9&nbsp;: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake git-lfs-test<\/strong>\n  &#91;...]\n\n$ <strong>ls -l tmp\/work\/all-poky-linux\/git-lfs-test\/1.0\/image\/data\/<\/strong>\ntotal 1048580\n-rw-r--r-- 1 cpb cpb 1073741824 juin   1 13:32 my-large-file<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c0 noter&nbsp;: il est possible de pr\u00e9ciser \u00e9galement dans quel repertoire doit s&rsquo;ex\u00e9cuter une fonction. Nous pouvons ainsi \u00e9viter l&rsquo;option <code>-C ${S}<\/code> de <code>git<\/code>. Au final, ma recette devient&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SUMMARY = \"Small recipe to test `git lfs` downloading\"\nLICENSE = \"MIT\"\nLIC_FILES_CHKSUM = \"file:\/\/${COMMON_LICENSE_DIR}\/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302\"\n\nSRC_URI += \"git:\/\/github.com\/cpb-\/git-lfs-and-yocto-project;protocol=https;branch=master\"\nSRCREV = \"${AUTOREV}\"\n\nS = \"${WORKDIR}\/git\"\n\ninherit allarch<strong>\n\ndo_git_lfs() {\n        git lfs pull\n}\naddtask git_lfs after do_unpack before do_patch<\/strong>\n<strong>do_git_lfs&#91;network] = \"1\"\ndo_git_lfs&#91;dirs] = \"${S}\"<\/strong>\n\ndo_install() {\n        install -d ${D}\/data\n        install -m 0644 ${S}\/my-large-file ${D}\/data\n}\n\nFILES:${PN} += \"data\/my-large-file\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">L&rsquo;utilisation de <em>repositories<\/em> LFS de <code>git<\/code> avec Yocto Project n&rsquo;est pas tr\u00e8s compliqu\u00e9e, il suffit de rajouter les quelques lignes ci-dessus. N\u00e9anmoins les \u00e9tapes ne sont pas tr\u00e8s intuitives.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Merci \u00e0 mon ami Alexandre Grosset pour m&rsquo;avoir pos\u00e9 ce probl\u00e8me et aid\u00e9 \u00e0 le r\u00e9soudre.<\/p>","protected":false},"excerpt":{"rendered":"<p>La fonctionnalit&eacute; LFS (Large File Support) permet de superviser avec git des fichiers volumineux en &eacute;vitant les t&eacute;l&eacute;chargements longs. Lors d&rsquo;une op&eacute;ration git clone, le fichier original est remplac&eacute; par un fichier de r&eacute;f&eacute;rence beaucoup plus petit. Le remplacement inverse par le contenu initial n&rsquo;a lieu que sur demande explicite. Les anciennes versions de Yocto [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-6095","post","type-post","status-publish","format-standard","hentry","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6095","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=6095"}],"version-history":[{"count":16,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6095\/revisions"}],"predecessor-version":[{"id":6124,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6095\/revisions\/6124"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=6095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=6095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=6095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}