我对我的C项目使用以下Github操作工作流。工作流大约在40秒内完成,但其中一半以上的时间用于安装valgrind
软件包及其依赖项。
我相信缓存可以帮助我加快工作流程。我不介意多等几秒钟,但这似乎是对GitHub资源的毫无意义的浪费。
name: C Workflow
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: make
run: make
- name: valgrind
run: |
sudo apt-get install -y valgrind
valgrind -v --leak-check=full --show-leak-kinds=all ./bin
运行sudo apt get install-y valgrind
安装以下软件包:
gdb
gdbserver
libbabeltrace1
libc6-dbg
libipt1
valgrind
我知道Actions支持缓存特定的目录(已经有一些回答了SO问题和文章),但是我不确定apt安装的所有不同的包最终会在哪里。我假设/bin/
或/usr/bin/
不是受安装包影响的唯一目录。
是否有一种优雅的方法来缓存已安装的系统包,以便将来运行工作流?
更新:我创建了一个GitHub操作,作为这个解决方案,代码更少,优化更好。缓存新内容
这个解决方案类似于大多数投票。我尝试了建议的解决方案,但它不适合我,因为我正在安装tex live-latex
和pandoc
,它有许多依赖关系和子依赖关系。
我创建了一个可以帮助很多人的解决方案。一种情况是当你安装了几个包(apt安装
),另一种解决方案是当你制作了一个程序,并且需要一段时间。
解决方案:
find
创建容器中所有文件的列表
make
programs,无论您想缓存什么
find
创建容器中所有文件的列表
diff
获取新创建的文件
操作/cache@v2
/
什么时候用这个?
实施:
>
我的操作的登录页:工作流。
释放yml
name: CI - Release books
on:
release:
types: [ released ]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
id: cache-packages
with:
path: ${{ runner.temp }}/cache-linux
key: ${{ runner.os }}-cache-packages-v2.1
- name: Install packages
if: steps.cache-packages.outputs.cache-hit != 'true'
env:
SOURCE: ${{ runner.temp }}/cache-linux
run: |
set +xv
echo "# --------------------------------------------------------"
echo "# Action environment variables"
echo "github.workspace: ${{ github.workspace }}"
echo "runner.workspace: ${{ runner.workspace }}"
echo "runner.os: ${{ runner.os }}"
echo "runner.temp: ${{ runner.temp }}"
echo "# --------------------------------------------------------"
echo "# Where am I?"
pwd
echo "SOURCE: ${SOURCE}"
ls -lha /
sudo du -h -d 1 / 2> /dev/null || true
echo "# --------------------------------------------------------"
echo "# APT update"
sudo apt update
echo "# --------------------------------------------------------"
echo "# Set up snapshot"
mkdir -p "${{ runner.temp }}"/snapshots/
echo "# --------------------------------------------------------"
echo "# Install tools"
sudo rm -f /var/lib/apt/lists/lock
#sudo apt install -y vim bash-completion
echo "# --------------------------------------------------------"
echo "# Take first snapshot"
sudo find / \
-type f,l \
-not \( -path "/sys*" -prune \) \
-not \( -path "/proc*" -prune \) \
-not \( -path "/mnt*" -prune \) \
-not \( -path "/dev*" -prune \) \
-not \( -path "/run*" -prune \) \
-not \( -path "/etc/mtab*" -prune \) \
-not \( -path "/var/cache/apt/archives*" -prune \) \
-not \( -path "/tmp*" -prune \) \
-not \( -path "/var/tmp*" -prune \) \
-not \( -path "/var/backups*" \) \
-not \( -path "/boot*" -prune \) \
-not \( -path "/vmlinuz*" -prune \) \
> "${{ runner.temp }}"/snapshots/snapshot_01.txt 2> /dev/null \
|| true
echo "# --------------------------------------------------------"
echo "# Install pandoc and dependencies"
sudo apt install -y texlive-latex-extra wget
wget -q https://github.com/jgm/pandoc/releases/download/2.11.2/pandoc-2.11.2-1-amd64.deb
sudo dpkg -i pandoc-2.11.2-1-amd64.deb
rm -f pandoc-2.11.2-1-amd64.deb
echo "# --------------------------------------------------------"
echo "# Take second snapshot"
sudo find / \
-type f,l \
-not \( -path "/sys*" -prune \) \
-not \( -path "/proc*" -prune \) \
-not \( -path "/mnt*" -prune \) \
-not \( -path "/dev*" -prune \) \
-not \( -path "/run*" -prune \) \
-not \( -path "/etc/mtab*" -prune \) \
-not \( -path "/var/cache/apt/archives*" -prune \) \
-not \( -path "/tmp*" -prune \) \
-not \( -path "/var/tmp*" -prune \) \
-not \( -path "/var/backups*" \) \
-not \( -path "/boot*" -prune \) \
-not \( -path "/vmlinuz*" -prune \) \
> "${{ runner.temp }}"/snapshots/snapshot_02.txt 2> /dev/null \
|| true
echo "# --------------------------------------------------------"
echo "# Filter new files"
diff -C 1 \
--color=always \
"${{ runner.temp }}"/snapshots/snapshot_01.txt \
"${{ runner.temp }}"/snapshots/snapshot_02.txt \
| grep -E "^\+" \
| sed -E s/..// \
> "${{ runner.temp }}"/snapshots/snapshot_new_files.txt
< "${{ runner.temp }}"/snapshots/snapshot_new_files.txt wc -l
ls -lha "${{ runner.temp }}"/snapshots/
echo "# --------------------------------------------------------"
echo "# Make cache directory"
rm -fR "${SOURCE}"
mkdir -p "${SOURCE}"
while IFS= read -r LINE
do
sudo cp -a --parent "${LINE}" "${SOURCE}"
done < "${{ runner.temp }}"/snapshots/snapshot_new_files.txt
ls -lha "${SOURCE}"
echo ""
sudo du -sh "${SOURCE}" || true
echo "# --------------------------------------------------------"
- name: Copy cached packages
if: steps.cache-packages.outputs.cache-hit == 'true'
env:
SOURCE: ${{ runner.temp }}/cache-linux
run: |
echo "# --------------------------------------------------------"
echo "# Using Cached packages"
ls -lha "${SOURCE}"
sudo cp --force --recursive "${SOURCE}"/. /
echo "# --------------------------------------------------------"
- name: Generate release files and commit in GitHub
run: |
echo "# --------------------------------------------------------"
echo "# Generating release files"
git fetch --all
git pull --rebase origin main
git checkout main
cd ./src/programming-from-the-ground-up
./make.sh
cd ../../
ls -lha release/
git config --global user.name 'Israel Roldan'
git config --global user.email 'israel.alberto.rv@gmail.com'
git add .
git status
git commit -m "Automated Release."
git push
git status
echo "# --------------------------------------------------------"
解释部分代码:
这里是操作缓存,指示一个键
,它将生成一次,并在以后的执行中进行比较。路径是生成缓存压缩文件的文件所在的目录。
- uses: actions/cache@v2
id: cache-packages
with:
path: ${{ runner.temp }}/cache-linux
key: ${{ runner.os }}-cache-packages-v2.1
如果退出缓存命中
则对键
缓存的有条件搜索为“true”。
if: steps.cache-packages.outputs.cache-hit != 'true'
if: steps.cache-packages.outputs.cache-hit == 'true'
这并不重要,但是当第一次执行du
命令时,Linux索引所有的文件(5~8分钟),然后当我们使用fine
时,只需要大约50秒就可以得到所有的文件文件。如果你愿意,你可以删除这一行。
带后缀的命令| | true
防止出现2
sudo du -h -d 1 / 2> /dev/null || true
这是神奇的部分,使用
查找
生成实际文件的列表,排除一些目录来优化缓存文件夹。它也将在安装和make
程序后执行。在下一个快照中,文件名应该是不同的snapshot_02.txt
。
sudo find / \
-type f,l \
-not \( -path "/sys*" -prune \) \
-not \( -path "/proc*" -prune \) \
-not \( -path "/mnt*" -prune \) \
-not \( -path "/dev*" -prune \) \
-not \( -path "/run*" -prune \) \
-not \( -path "/etc/mtab*" -prune \) \
-not \( -path "/var/cache/apt/archives*" -prune \) \
-not \( -path "/tmp*" -prune \) \
-not \( -path "/var/tmp*" -prune \) \
-not \( -path "/var/backups*" \) \
-not \( -path "/boot*" -prune \) \
-not \( -path "/vmlinuz*" -prune \) \
> "${{ runner.temp }}"/snapshots/snapshot_01.txt 2> /dev/null \
|| true
安装一些软件包并
pandoc
。
sudo apt install -y texlive-latex-extra wget
wget -q https://github.com/jgm/pandoc/releases/download/2.11.2/pandoc-2.11.2-1-amd64.deb
sudo dpkg -i pandoc-2.11.2-1-amd64.deb
rm -f pandoc-2.11.2-1-amd64.deb
使用添加的新文件生成文本文件,这些文件也可以是符号文件。
diff -C 1 \
"${{ runner.temp }}"/snapshots/snapshot_01.txt \
"${{ runner.temp }}"/snapshots/snapshot_02.txt \
| grep -E "^\+" \
| sed -E s/..// \
> "${{ runner.temp }}"/snapshots/snapshot_new_files.txt
最后,将所有文件复制到缓存目录中,作为存档保存原始信息。
while IFS= read -r LINE
do
sudo cp -a --parent "${LINE}" "${SOURCE}"
done < "${{ runner.temp }}"/snapshots/snapshot_new_files.txt
步骤将所有缓存文件复制到主路径
/
。
- name: Copy cached packages
if: steps.cache-packages.outputs.cache-hit == 'true'
env:
SOURCE: ${{ runner.temp }}/cache-linux
run: |
echo "# --------------------------------------------------------"
echo "# Using Cached packages"
ls -lha "${SOURCE}"
sudo cp --force --recursive "${SOURCE}"/. /
echo "# --------------------------------------------------------"
这一步就是我使用缓存生成的安装包的地方,
/制作sh
脚本使用pandoc
进行一些转换。正如我提到的,您可以创建使用缓存好处的其他步骤,也可以创建不使用缓存的其他步骤。
- name: Generate release files and commit in GitHub
run: |
echo "# --------------------------------------------------------"
echo "# Generating release files"
cd ./src/programming-from-the-ground-up
./make.sh
您可以使用预先安装的valgrind
创建docker映像,并在该映像上运行您的工作流。
创建一个Dockerfile
,内容如下:
FROM ubuntu
RUN apt-get install -y valgrind
构建它并将其推送到dockerhub:
docker build -t natiiix/valgrind .
docker push natiiix/valgrind
然后将以下内容用作您的工作流程:
name: C Workflow
on: [push, pull_request]
jobs:
build:
container: natiiix/valgrind
steps:
- uses: actions/checkout@v1
- name: make
run: make
- name: valgrind
run: valgrind -v --leak-check=full --show-leak-kinds=all ./bin
完全未经测试,但你明白了。
这个答案的目的是展示如何使用github操作进行缓存。不一定要展示如何缓存valgrind
,它确实展示了这一点,但更多的是展示并非所有东西都可以/应该缓存,缓存和恢复缓存与重新安装依赖关系的权衡需要考虑在内。
您将使用操作/cache
操作来执行此操作。
添加它作为一个步骤(在您需要使用valgrind之前):
- name: Cache valgrind
uses: actions/cache@v2
id: cache-valgrind
with:
path: "~/valgrind"
key: ${{secrets.VALGRIND_VERSION}}
下一步应尝试安装缓存版本(如果有),或从存储库安装:
- name: Install valgrind
env:
CACHE_HIT: ${{steps.cache-valgrind.outputs.cache-hit}}
VALGRIND_VERSION: ${{secrets.VALGRIND_VERSION}}
run: |
if [[ "$CACHE_HIT" == 'true' ]]; then
sudo cp --verbose --force --recursive ~/valgrind/* /
else
sudo apt-get install --yes valgrind="$VALGRIND_VERSION"
mkdir -p ~/valgrind
sudo dpkg -L valgrind | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/
fi
设置VALGRIND_VERSION
秘密为输出:
apt-cache policy valgrind | grep -oP '(?<=Candidate:\s)(.+)'
这将允许您在发布新版本时仅通过更改secret的值使缓存无效。
dpkg-L valgrind
用于列出使用sudo apt get install valgrind
时安装的所有文件。
我们现在可以使用这个命令将所有依赖项复制到缓存文件夹中:
dpkg -L valgrind | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/
除了复制valgrind
的所有组件之外,可能还需要复制依赖项(例如在本例中的libc
),但是我不建议继续沿着这条路走,因为依赖链只是从那里生长出来的。准确地说,复制最终有一个适合valgrind运行的环境所需的依赖关系如下:
要复制所有这些依赖项,可以使用与上面相同的语法:
for dep in libc6 libgcc1 gcc-8-base; do
dpkg -L $dep | while IFS= read -r f; do if test -f $f; then echo $f; fi; done | xargs cp --parents --target-directory ~/valgrind/
done
当安装valgrind
首先需要简单地运行sudo apt-get安装valgrind
时,所有这些工作真的值得麻烦吗?如果您的目标是加快构建过程,那么您还必须考虑恢复(下载和提取)缓存所需的时间,而不是简单地再次运行命令来安装valgrind
。
最后要恢复缓存,假设它存储在/tmp/valgrind
,您可以使用以下命令:
cp --force --recursive /tmp/valgrind/* /
它基本上将所有文件从缓存复制到根分区。
除了上面的过程之外,我还有一个“缓存valgrind”的示例,通过从源代码安装和编译它。现在缓存的大小约为63MB(压缩),仍然需要单独安装libc
,这样做有违目的。
注意:这个问题的另一个答案是,通过使用一个依赖于预先安装的依赖项的容器,我认为可以更安全地缓存依赖关系。最好的部分是,您可以使用操作使这些容器保持最新。
参考文献:
我正在建立一个“类缓存”,我想稍后调用类。 主要的目标是,我不希望每次需要类实例时都扫描上下文。 首先要评估缓存,我将缓存方法@AutoWired放在@RestController中,这会很好地工作。在调用rest方法时填充缓存。 完成之后,我将@AutoWired对象移动到@Service中,创建一个方法来自填充缓存。但这不起作用。调用@PostConstructor方法时不填充缓存。 如何使用
我对docker相当陌生,正试图通过写自己的图像来学习,目前,正在阅读docker in action(ISBN:1633430235) 我的代码: 图书代码: 然而,在这两个代码中,我都得到了一个无法定位的包eror和一个none-zeero代码: apt-get update'返回一个非零代码:100 这将成功地下载,但一旦它开始安装git,我得到同样的错误。这个 3)在https://doc
令人惊讶的是,很难在网上找到关于这个的具体信息。 是否可以将结果缓存在Spring webflow中? 例如:我可以使用rest服务,然后使用mongodb作为主数据库,redis作为缓存吗。所以,当请求通过时,它会检查缓存,如果请求的结果不在缓存中,它会查询mongodb? 如果你有链接等只是把它们作为一个评论,和Il阅读他们并回答自己的问题。 谢谢
我正在用 我正在使用 我已经查看了Picturefill的演示,甚至还有一个与我使用的方式非常接近的示例 有没有其他人遇到过这种情况,或者对如何修复它有什么建议?如果我使用src而不是srcset,这似乎是可行的,但我知道不建议将src与Picturefill一起使用,因为它会在不支持srcset的浏览器中导致双重下载。
我建立了一个进步的网络应用,https://www.tavest.com.我不明白为什么我的服务人员也被缓存在Chrome中?https://www.tavest.com/service-worker-tavest.js因此,当我更改服务人员时,chrome没有检测到更改,因此服务人员没有更新。 尽管我刷新了很多次页面,它仍然是一样的。然而,在Mozilla中,它工作得很好。这是我安装服务人员的代
在我的项目中,我使用了一个@Cacheable注释ia一个服务方法,它返回涉及书籍和一些标记的计算结果,我想在一个@Controller类方法中退出缓存,该方法将一本新书添加到数据库中,因为这本新书将是新计算所必需的。 服务类:@Cacheable("metas") 控制器类:@RequestMapping@CacheEvict(value=“metas”,allEntries=true)
我有一个使用服务人员和缓存API的应用程序。Service Worker中使用的缓存名称包含GIT修订版(哈希),因此每次发布时,都会使用新缓存,删除旧缓存。这是为了百分之百地确保用户总是能够获得最新的源代码(这种情况对于预期的发布计划来说很好)。 我使用的是每天运行几次的Selenium Java(WebDriver)测试(比如GIT repo发生变化时),我希望确保每个新的GIT版本都能正确地
我为我的网站创建了一个AMP页面,在我的桌面浏览器上运行正常,在我的手机上测试正常,如果某些字段为空或无效,提交错误将正确显示错误消息,并且在成功提交时,它将正确显示提交成功消息。 当我将页面提交给Google缓存amp页面时,我再次测试了表单,这次它没有显示错误或成功消息。但如果表单提交有效,它将向我发送电子邮件,但不会显示成功消息。 表单html代码: PHP页面: