Petalinux不使用本地缓存downloads目录
两个不同用户在同一台Linux服务器上使用petalinux-build --sdk分别编译各自的工程时,一个用户报告unfs3这个包下载错误。
原因是本地离线缓存downloads目录里的这个包权限设置不正确,只有创建这个包的用户才有读权限。将其它用户也加入读权限之后,问题消失。
将downloads目录下其它一个包,例如git2_github.com.ninja-build.ninja.git.tar.gz,的权限更改为其它用户不具有读权限,可以重现问题。Petalinux-config设置了PREMIRROR_URL和BB_NO_NETWORK=1,构建成功时日志只显示Trying PREMIRROR,而构建失败的日志只显示了Trying Upstream,也就是从网络获取。
Fetch调用的是 components/yocto/layers/core/bitbake/lib/bb/fetch2 里面的脚本。
在__init__.py里加入打印,测试多次发现,失败日志显示的内容是交替变化的。一种是显示 build/downloads/git2/github.com.ninja-build.ninja.git目录不存在,这里会尝试从PREMIRRORS下载。一种是这个目录存在,就要检查donestamp文件,也就是build/downloads/git/github.com.ninja-build.ninja.git.done这个文件,这时不存在,就不会尝试PREMIRRORS,而是尝试Upstreams。
- 最初,donestamp文件和git目录都是不存在的。运行do_fetch任务后,成功从本地离线目录下载到文件。解压时创建了git目录,但是由于权限问题出错。donestamp文件和下载的文件会被删除,git目录不会被删除。
- 再将运行do_fetch任务,尝试从Upstreams下载,没有联网所以出错,git目录也被删除。从而,满足步骤1的条件进入了循环。
原因是这个包是git协议,步骤1中虽然是从本地缓存目录下载文件,却使用的是git.py里download方法调用runfetchcmd来进行解压,并且没有设置cleanup,tar解压失败后没有删除相应文件。try_mirror_url这个函数有可能同时调用ud.method.download和ud.method.download,失败时却只调用了ud.method.clean,没有调用origud.method.clean。
git.py里重新实现了try_premirror这个方法,如果没有设置BB_FETCH_PREMIRRORONLY,且目标git目录已经存在,就不会尝试PREMIRROR,而是直接从Upstreams下载。这也就解释了步骤2中的行为。
详细的函数调用流程如下。
- 调用Fetch.download。因为原始的URL是git协议,所以此时FetchData中的FetchMethod类为Git。
- Fetch.download调用Git.try_premirror检查是否需要从PREMIRROR下载,因为Git类实现了try_premirror。
- 如果尝试从PREMIRROR下载,Fetch.download则调用FetchMethod.try_mirrors,因为Git类没有实现try_mirrors。
- FetchMethod.try_mirrors调用静态函数try_mirrors。
- try_mirrors先调用build_mirroruris,根据PREMIRRORS和原始git构造出可能的新的url和FetchData。依次针对所有的新url和FetchData,调用静态函数try_mirror_url。
- try_mirror_url首先尝试使用新FetchData中的method成员来调用download方法。对应在这个例子中,新FetchData中method成员就对应到Local类,Local.download只做一些检查,不会操作文件。
- try_mirror_url在某些条件下会再尝试使用原有method的download方法。在这个例子中会调用Git.download。
- Git.dowload会调用runfetchcmd来解压文件。因为文件权限问题,产生了异常。
- try_mirror_url中处理这个异常时调用了新FetchData中method成员的clean方法,没有调用原有method的clean方法。