Clone/download 来自 GitHub 存储库的特定文件
Clone/download specific files from a GitHub repository
在 GitHub 上有一个名为 platform_frameworks_base 的 Git 存储库,其中包含部分 Android 源代码。
我编写了一个应用程序来回复该项目的所有 .aidl 文件,因此它会在第一次启动时将它们全部下载。
到目前为止,我是通过从项目根目录下载文件 Android.bp,从该文件中提取所有以 .aidl 结尾的文件路径,然后一个一个地显式下载它们来做到这一点的。
例如,如果我找到这个文件路径:
media/java/android/media/IAudioService.aidl
我知道我可以这样下载:
wget https://raw.githubusercontent.com/aosp-mirror/platform_frameworks_base/android-10.0.0_r47/media/java/android/media/IAudioService.aidl
在 Android 10(git 标签:android-10.0.0_r47
)之前都可以正常工作。
从 Android 11(例如 git 标签:android-11.0.0_r33
)开始,文件路径使用通配符而不是完整路径。看到这个 Android.bp.
它现在仅包含 wildcard/glob 个文件路径,例如:
media/java/**/*.aidl
location/java/**/*.aidl
等...
我目前的“解决方案”:
克隆 repo(仅我们关心的分支的最后一次提交):
git clone --depth=1 -b android-11.0.0_r33 https://github.com/aosp-mirror/platform_frameworks_base.git
从 Android.bp.
中提取 wildcard/glob 路径
cat Android.bp | grep '\.aidl"' | cut -d'"' -f2
查找与 wildcard/glob 路径匹配的所有文件。
例如shopt -s globstar && echo media/java/**/*.aidl
但是下载过程需要很长时间,因为存储库包含超过 千兆字节 的二进制文件。即使我只是克隆了我关心的分支的最后一次提交。
现在我的实际问题是:
我怎样才能只下载我真正关心的 .aidl
个文件? (理想情况下不解析 GitHub 中每个文件夹的 HTML。)
或者
我如何 download/clone 没有所有二进制文件的存储库? (可能无法使用 git?)
编辑:
我尝试使用 GitHub API 递归遍历所有目录,但我立即收到 API 超出速率限制的错误:
g_aidlFiles=""
# Recursively go through all directories and the paths to all found .aidl files in the global g_aidlFile variable
GetAidlFilesFromGithub() {
l_dirUrl="${1-}"
if [ "$l_dirUrl" == "" ]; then
echo "ERROR: Directory URL not provided in GetAidlFilesFromGithub"
exit 1
fi
echo "l_dirUrl: ${l_dirUrl}"
l_rawRes="$(curl -s -i $l_dirUrl)"
l_statusCode="$(echo "$l_rawRes" | grep HTTP | head -1 | cut -d' ' -f2)"
l_resBody="$(echo "$l_rawRes" | sed '1,/^\s*$/d')"
if [[ $l_statusCode == 4* ]] || [[ $l_statusCode == 5* ]]; then
echo "ERROR: Request failed!"
echo "Response status: $l_statusCode"
echo "Reponse body:"
echo "$l_resBody"
exit 1
fi
l_currentDirJson="$(echo "$l_resBody")"
if [ "$l_currentDirJson" == "" ]; then
echo "ERROR: l_currentDirJson is empty"
exit 1
fi
l_newAidlFiles="$(echo "$l_currentDirJson" | jq '.[] | select(.type=="file") | select(.path | endswith(".aidl")) | .path')"
if [ "$l_newAidlFiles" != "" ]; then
echo "l_newAidlFiles: ${l_newAidlFiles}"
g_aidlFiles="${g_aidlFiles}\n${l_newAidlFiles}"
fi
l_subDirUrls="$(echo "$l_currentDirJson" | jq '.[] | select(.type=="dir") | .url')"
if [ "$l_subDirUrls" != "" ]; then
echo "$l_subDirUrls" | while IFS= read -r l_subDirUrl ; do
(GetAidlFilesFromGithub "$l_subDirUrl")
done
else
echo "No subdirs found."
fi
}
GetAidlFilesFromGithub "https://api.github.com/repos/aosp-mirror/platform_frameworks_base/contents?ref=android-11.0.0_r33"
据我了解,我的所有用户都必须创建一个 GitHub 帐户并创建一个 OAUTH 机密以提高限制。这绝对不是我的选择。我希望我的应用程序易于使用。
您可以使用 GitHub API 代码搜索端点来获取路径,然后使用您的 wget raw.githubusercontent 方法下载它们:
apiurlbase='https://api.github.com/search/code?per_page=100&q=repo:aosp-mirror/platform_frameworks_base+extension:aidl'
dlurlbase='https://raw.githubusercontent.com/aosp-mirror/platform_frameworks_base/android-10.0.0_r47/'
apiurl1="$apiurlbase+path:/media/java/"
apiurl2="$apiurlbase+path:/location/java/"
for apiurl in "$apiurl1" "$apiurl2"; do
page=1
while paths=$(
curl -s "$apiurl&page=$page" | grep '"path": ' | grep -o '[^"]\+\.aidl'
); do
# do your stuff with the $paths
page=$(($page + 1))
done
done
不幸的是,GitHub API 代码搜索端点仅搜索默认分支(在本例中为 master),而您想要 android-10.0.0_r47 标签。 android-10.0.0_r47 中可能有文件,但 master 中没有,此代码不会找到并下载这些文件。
另一种解决方案是对您感兴趣的每个标签进行最小限度的克隆,然后使用 git ls-tree 获取每个标签的路径,例如,
for tag in 'android-10.0.0_r47' 'android-11.0.0_r33'; do
git clone --branch "$tag" --depth=1 --bare --no-checkout \
--filter=blob:limit=0 git@github.com:aosp-mirror/platform_frameworks_base.git
# only a 1.8M download
mv platform_frameworks_base.git "$tag"
cd "$tag"
paths=$(git ls-tree -r HEAD --name-only | grep '\.aidl$')
# do your stuff with the paths
cd ..
done
如果这是供自己使用,我可能不会使用这两种方法。我只会克隆整个巨大的 repo 一次,然后在本地使用它,例如
if [ -e platform_frameworks_base ]; then
cd platform_frameworks_base
git pull
else
git clone git@github.com:aosp-mirror/platform_frameworks_base.git
cd platform_frameworks_base
fi
tags=$(git tag | grep '^android')
for tag in $tags; do
git checkout $tag
paths=$(git ls-tree -r HEAD --name-only | grep '\.aidl$')
# do your stuff with the paths
done
在这种情况下,我会维护一个文本文件,该文件在每次提交前自动更新为最新的 repo 文件树。
脚本应该易于编写并且可以快速 运行 因为所有这些都是在本地发生的。它可以通过引入新的工作流程来手动调用,也可以集成到您的 test/CI 自动化流程中。
那么您就知道在您的最终用户应用程序中要做什么了,先下载这个文件,用 Android.bp
过滤掉它,然后用 Github 原始内容链接提取你想要的文件.
不确定这是否是您想要的:
#!/usr/bin/env bash
get_github_file_list(){
local user= repo= branch=
curl -s "https://api.github.com/repos/$user/$repo/git/trees/$branch?recursive=1"
}
get_github_file_list aosp-mirror platform_frameworks_base android-11.0.0_r33 |\
jq -r '.tree|map(.path|select(test("\.aidl")))[]'
由于存储库位于支持过滤器的 GitHub 上,最简单的方法可能是使用其过滤器支持。
git clone --no-checkout --depth=1 --filter=blob:none \
https://github.com/aosp-mirror/platform_frameworks_base
cd platform_frameworks_base
git reset -q -- \*.aidl
git checkout-index -a
这可能需要相当多的技巧才能将文件打包发送,而不是产生的一次获取一个文件。
例如,而不是 blob:none
说 blob:limit=16384
,这让大多数人都在前面。
要在您自己的代码中执行此操作而不依赖 Git 安装,您需要实施 git 协议。 Here's the online intro with pointers to the actual Git docs。这并不难,你来回发送文本行,直到服务器吐出你想要的大量数据,然后你从中挑选。您不需要使用 https,github 支持纯 git 协议。尝试 运行 使用 GIT_TRACE=1 GIT_PACKET_TRACE=1
的克隆命令。
在 GitHub 上有一个名为 platform_frameworks_base 的 Git 存储库,其中包含部分 Android 源代码。
我编写了一个应用程序来回复该项目的所有 .aidl 文件,因此它会在第一次启动时将它们全部下载。
到目前为止,我是通过从项目根目录下载文件 Android.bp,从该文件中提取所有以 .aidl 结尾的文件路径,然后一个一个地显式下载它们来做到这一点的。
例如,如果我找到这个文件路径:
media/java/android/media/IAudioService.aidl
我知道我可以这样下载:
wget https://raw.githubusercontent.com/aosp-mirror/platform_frameworks_base/android-10.0.0_r47/media/java/android/media/IAudioService.aidl
在 Android 10(git 标签:android-10.0.0_r47
)之前都可以正常工作。
从 Android 11(例如 git 标签:android-11.0.0_r33
)开始,文件路径使用通配符而不是完整路径。看到这个 Android.bp.
它现在仅包含 wildcard/glob 个文件路径,例如:
media/java/**/*.aidl
location/java/**/*.aidl
等...
我目前的“解决方案”:
克隆 repo(仅我们关心的分支的最后一次提交):
git clone --depth=1 -b android-11.0.0_r33 https://github.com/aosp-mirror/platform_frameworks_base.git
从 Android.bp.
中提取 wildcard/glob 路径cat Android.bp | grep '\.aidl"' | cut -d'"' -f2
查找与 wildcard/glob 路径匹配的所有文件。
例如
shopt -s globstar && echo media/java/**/*.aidl
但是下载过程需要很长时间,因为存储库包含超过 千兆字节 的二进制文件。即使我只是克隆了我关心的分支的最后一次提交。
现在我的实际问题是:
我怎样才能只下载我真正关心的 .aidl
个文件? (理想情况下不解析 GitHub 中每个文件夹的 HTML。)
或者
我如何 download/clone 没有所有二进制文件的存储库? (可能无法使用 git?)
编辑:
我尝试使用 GitHub API 递归遍历所有目录,但我立即收到 API 超出速率限制的错误:
g_aidlFiles=""
# Recursively go through all directories and the paths to all found .aidl files in the global g_aidlFile variable
GetAidlFilesFromGithub() {
l_dirUrl="${1-}"
if [ "$l_dirUrl" == "" ]; then
echo "ERROR: Directory URL not provided in GetAidlFilesFromGithub"
exit 1
fi
echo "l_dirUrl: ${l_dirUrl}"
l_rawRes="$(curl -s -i $l_dirUrl)"
l_statusCode="$(echo "$l_rawRes" | grep HTTP | head -1 | cut -d' ' -f2)"
l_resBody="$(echo "$l_rawRes" | sed '1,/^\s*$/d')"
if [[ $l_statusCode == 4* ]] || [[ $l_statusCode == 5* ]]; then
echo "ERROR: Request failed!"
echo "Response status: $l_statusCode"
echo "Reponse body:"
echo "$l_resBody"
exit 1
fi
l_currentDirJson="$(echo "$l_resBody")"
if [ "$l_currentDirJson" == "" ]; then
echo "ERROR: l_currentDirJson is empty"
exit 1
fi
l_newAidlFiles="$(echo "$l_currentDirJson" | jq '.[] | select(.type=="file") | select(.path | endswith(".aidl")) | .path')"
if [ "$l_newAidlFiles" != "" ]; then
echo "l_newAidlFiles: ${l_newAidlFiles}"
g_aidlFiles="${g_aidlFiles}\n${l_newAidlFiles}"
fi
l_subDirUrls="$(echo "$l_currentDirJson" | jq '.[] | select(.type=="dir") | .url')"
if [ "$l_subDirUrls" != "" ]; then
echo "$l_subDirUrls" | while IFS= read -r l_subDirUrl ; do
(GetAidlFilesFromGithub "$l_subDirUrl")
done
else
echo "No subdirs found."
fi
}
GetAidlFilesFromGithub "https://api.github.com/repos/aosp-mirror/platform_frameworks_base/contents?ref=android-11.0.0_r33"
据我了解,我的所有用户都必须创建一个 GitHub 帐户并创建一个 OAUTH 机密以提高限制。这绝对不是我的选择。我希望我的应用程序易于使用。
您可以使用 GitHub API 代码搜索端点来获取路径,然后使用您的 wget raw.githubusercontent 方法下载它们:
apiurlbase='https://api.github.com/search/code?per_page=100&q=repo:aosp-mirror/platform_frameworks_base+extension:aidl'
dlurlbase='https://raw.githubusercontent.com/aosp-mirror/platform_frameworks_base/android-10.0.0_r47/'
apiurl1="$apiurlbase+path:/media/java/"
apiurl2="$apiurlbase+path:/location/java/"
for apiurl in "$apiurl1" "$apiurl2"; do
page=1
while paths=$(
curl -s "$apiurl&page=$page" | grep '"path": ' | grep -o '[^"]\+\.aidl'
); do
# do your stuff with the $paths
page=$(($page + 1))
done
done
不幸的是,GitHub API 代码搜索端点仅搜索默认分支(在本例中为 master),而您想要 android-10.0.0_r47 标签。 android-10.0.0_r47 中可能有文件,但 master 中没有,此代码不会找到并下载这些文件。
另一种解决方案是对您感兴趣的每个标签进行最小限度的克隆,然后使用 git ls-tree 获取每个标签的路径,例如,
for tag in 'android-10.0.0_r47' 'android-11.0.0_r33'; do
git clone --branch "$tag" --depth=1 --bare --no-checkout \
--filter=blob:limit=0 git@github.com:aosp-mirror/platform_frameworks_base.git
# only a 1.8M download
mv platform_frameworks_base.git "$tag"
cd "$tag"
paths=$(git ls-tree -r HEAD --name-only | grep '\.aidl$')
# do your stuff with the paths
cd ..
done
如果这是供自己使用,我可能不会使用这两种方法。我只会克隆整个巨大的 repo 一次,然后在本地使用它,例如
if [ -e platform_frameworks_base ]; then
cd platform_frameworks_base
git pull
else
git clone git@github.com:aosp-mirror/platform_frameworks_base.git
cd platform_frameworks_base
fi
tags=$(git tag | grep '^android')
for tag in $tags; do
git checkout $tag
paths=$(git ls-tree -r HEAD --name-only | grep '\.aidl$')
# do your stuff with the paths
done
在这种情况下,我会维护一个文本文件,该文件在每次提交前自动更新为最新的 repo 文件树。
脚本应该易于编写并且可以快速 运行 因为所有这些都是在本地发生的。它可以通过引入新的工作流程来手动调用,也可以集成到您的 test/CI 自动化流程中。
那么您就知道在您的最终用户应用程序中要做什么了,先下载这个文件,用 Android.bp
过滤掉它,然后用 Github 原始内容链接提取你想要的文件.
不确定这是否是您想要的:
#!/usr/bin/env bash
get_github_file_list(){
local user= repo= branch=
curl -s "https://api.github.com/repos/$user/$repo/git/trees/$branch?recursive=1"
}
get_github_file_list aosp-mirror platform_frameworks_base android-11.0.0_r33 |\
jq -r '.tree|map(.path|select(test("\.aidl")))[]'
由于存储库位于支持过滤器的 GitHub 上,最简单的方法可能是使用其过滤器支持。
git clone --no-checkout --depth=1 --filter=blob:none \
https://github.com/aosp-mirror/platform_frameworks_base
cd platform_frameworks_base
git reset -q -- \*.aidl
git checkout-index -a
这可能需要相当多的技巧才能将文件打包发送,而不是产生的一次获取一个文件。
例如,而不是 blob:none
说 blob:limit=16384
,这让大多数人都在前面。
要在您自己的代码中执行此操作而不依赖 Git 安装,您需要实施 git 协议。 Here's the online intro with pointers to the actual Git docs。这并不难,你来回发送文本行,直到服务器吐出你想要的大量数据,然后你从中挑选。您不需要使用 https,github 支持纯 git 协议。尝试 运行 使用 GIT_TRACE=1 GIT_PACKET_TRACE=1
的克隆命令。