使用travis ci构建Cache Brew

时间:2016-10-08 08:06:56

标签: macos homebrew travis-ci

我有一个Travis CI osx版本,其中brew依赖关系必须从源代码构建。

我知道Travis具有cache功能,但它没有关于如何缓存brew构建或输出的任何文档。

如何在travis中缓存brew包?

6 个答案:

答案 0 :(得分:11)

您可以将brew缓存目录添加到travis缓存中:

cache:
  directories:
    - $HOME/Library/Caches/Homebrew

据我所知,travis不支持开箱即用的自制缓存。

答案 1 :(得分:9)

此处存在3个松散相关的独立问题:

  • 缓存下载的瓶子
  • 缓存本地制造的瓶子
  • 缓存自制的元数据

您不一定需要全部三个,所以请遵循适合您需要的任何部分。


缓存下载的瓶子

  • $HOME/Library/Caches/Homebrew添加到Travis的缓存(实际上,应该使用brew --cache检索此路径,但是不能在这里调用它)

    cache:
      directories:
        - $HOME/Library/Caches/Homebrew
    
  • brew cleanup阶段运行before_cache-否则,随着新软件包版本的发布,缓存将无限期增长

    before_cache:
      - brew cleanup
    

缓存本地制造的瓶子

full code太长,无法在此处列出,因此请提供算法。

这是上一节的补充。如果不使用它,则在安装时在 步骤中将本地瓶保存在Homebrew缓存之外的某个位置,并将其添加到下面的缓存中在下面的启动时步骤中使用适当的名称。

  • 安装时:

    • brew deps递归检查软件包的依赖关系
      • 如果您的环境无法使用用于包装的瓶子((bottled)输出中没有brew info <pkg>),请在--include-build中加入构建依赖项
    • 对于每个程序包和依赖项,

      • 如果已安装(brew list --versions <pkg>成功)和最新版本(brew outdated不存在),请跳过
      • 如果存在旧版本,请执行以下步骤you'll need to install the new version alongside the old one
        • brew unlink旧版本,如果它不是仅用于小桶([keg-only]输出中没有brew info
        • 使用brew install调用所有--force
      • 如果有瓶子,只需brew install就可以了
      • 如果没有瓶子,

        • 构建并安装with the following sequence

          brew install --build-bottle <pkg>
          brew bottle --json <pkg>
          brew uninstall --ignore-dependencies <pkg>
          brew install <bottle>
          

          (似乎没有任何官方方法来获取生成的瓶子和JSON文件的名称。我从brew bottle输出中获取了瓶子的名称,并从中推断出JSON文件名。)

        • 将瓶子信息添加到包装的公式中

          brew bottle --merge --write <json file>
          
        • brew --cache <pkg>

          指定的适当名称将瓶文件保存到Travis缓存中
          • 仅在添加瓶子信息后执行此操作-否则,您将获得到源包的路径。
          • (自制软件还会对$HOME/Library/Caches/Homebrew中的下载文件进行符号链接。您无需这样做。)
        • 保存JSON文件以供以后使用。确保将其位置添加到Travis缓存中。
  • 启动时:

    • 如果要去,brew update
    • 浏览已保存的.json文件。对于每一个,检查本地瓶子是否仍然合适(通过比较版本和重建编号;您可以为此数据解析brew info --json=v1 <pkg>brew info --json=v1 <bottle>的输出)。
      • 删除缓存的瓶子和.json(如果没有)
        • 由于此时您无法使用brew --cache来获取瓶子的路径,因此需要单独保存它。在撰写本文时,符号链接尚未保存在Travis的缓存中,因此我最终使用了保存路径的常规文件。
      • 如果是,则将瓶信息重新添加到上述公式中
        • 还不太可能在不更改版本的情况下更改公式中的下载URL,然后瓶子的预期缓存名称将更改,因为其中的哈希是下载URL的哈希。为此,请在添加信息后检查brew --cache <pkg>是否仍然指向您的瓶子。
  • before_cache

    • 如果您使用的是上一节中的brew cleanup,请在运行之前从缓存中保存本地构建的瓶子文件,因为cleanup可能会删除这次不需要的文件。 cleanup之后,恢复已删除的内容。

缓存自制的元数据

如果您运行brew update --verbose (并确保.travis.yml中没有秘密变量或您的Travis项目设置-brew仅在{{1 }}是tty)-您将看到完全构成Homebrew自更新操作的内容-因此应缓存的内容:

  • 将(实际上默认为stdout插入)放入实际上为rebase存储库的几个路径中:
    • git-自制程序本身
    • /usr/local/Homebrew-已安装的水龙头
  • 浏览分接头和缓存并迁移过时的位。由于Travis缓存内容是第二次被添加到现有目录结构中而不是被替换,因此,可能由于更新过程中删除但在新VM中又存在的文件而导致奇怪的操作和错误。我目睹的:
    • 将始终尝试将/usr/local/Homebrew/Library/Taps/*/*迁移到Taps/caskroom/homebrew-cask,并在Taps/homebrew/homebrew-cask上创建一个副本。如果被缓存,则该副本将在下次运行时导致“错误:文件存在”。
    • 将始终尝试将许多未提交的文件导入Taps/homebrew/homebrew-cask/homebrew-cask

因此,操作将是:

  • Taps/homebrew/homebrew-versions添加到Travis缓存

    • 添加 / usr / local / Cellar / usr / local / opt 是一个坏主意:首先,它们太大,在创建时会导致超时并上传缓存;其次,这是不安全的'cuz /usr/local/Homebrew脚本可能会影响系统的其他任意部分,因此每次应从(缓存的)瓶子安装新的软件包版本,而不是缓存结果。无论如何,安装瓶子只需要几秒钟。
  • postinstall之前:清理Homebrew代码库

    • 如果存在brew update,请删除Taps/caskroom/homebrew-cask目录
    • Taps/homebrew/homebrew-cask下找到所有git仓库(/usr/local/Homebrew,得到find -type d -name .git)并在每个仓库中运行dirname以摆脱Travis的剩余物
    • 也可以使用git clean -fxd从剩菜中清除Homebrew缓存(如果与上一节结合使用,请参阅此处以了解其他操作)-否则,{{1}中会出现很多错误}在“正在迁移缓存条目...” 阶段。
  • brew cleanup

    • 改为使用brew update -它会自动解决与带有瓶子信息的本地提交的任何可能的冲突
  • 重新添加本地瓶子时(如果与上一节结合使用):

    • 如果瓶子信息已经存在,请不要将其重新添加到公式中
    • 如果包装的版本已更改并且您的奶瓶信息已出现在公式中,请从公式中将其删除,然后brew update将结果删除。没有任何备用方法,因此您必须使用脚本来解析和编辑公式文件,并从brew update --merge表中删除相应的行。公式文件的路径是使用git commit检索的。
  • 安装时:

    • 如果使用第三方水龙头,请始终检查是否已安装该水龙头:

      bottle do
      • 由于符号链接未保存在Travis缓存中,因此可能不会记住引脚。但是,对它们进行检查也不会造成伤害:

        brew formula <pkg>
  • brew tap | grep -qxF <tap> || brew tap <tap>

    • 删除brew tap --list-pinned | grep -qxF <tap> || brew tap-pin <tap> (如果存在)

答案 2 :(得分:1)

要缓存实际已编译的依赖项而不是缓存源tarball或ccaching目标文件,请将相应软件包的Cellaropt目录添加到缓存中,并使用适当的before_install检查似乎可行很好。

您还可以添加所有/usr/local/Cellar//usr/local/opt/,但这将添加所有已安装的自制程序包,而不是仅添加所需的程序包。

依赖opensl,libevent和check的项目中的示例:

cache:
  directories:
    - /usr/local/Cellar/openssl
    - /usr/local/opt/openssl
    - /usr/local/Cellar/libevent
    - /usr/local/opt/libevent
    - /usr/local/Cellar/check
    - /usr/local/opt/check
before_install:
  - test -d /usr/local/opt/openssl/lib  || { rmdir /usr/local/opt/openssl; brew install openssl; }
  - test -d /usr/local/opt/libevent/lib || { rmdir /usr/local/opt/libevent; brew install libevent; }
  - test -d /usr/local/opt/check/lib    || { rmdir /usr/local/opt/check; brew install check; }

rmdir是必需的,因为TravisCI会创建缓存的目录(如果不存在),而brew install会失败,如果/usr/local/opt/$package是目录(与指向特定已安装目录的符号链接相反)版本)。出于同样的原因,test测试一个子目录,而不是主程序包目录。

请注意,这种方法要求您自己的项目能够提取/usr/local/opt中安装的依赖项。

答案 3 :(得分:0)

Homebrew允许您从源代码构建:

brew install --build-from-source [package-name]

如果你想为Travis缓存你的自制软件,我看到如何做到这一点的唯一方法就是创建一个你想要的自制依赖项的压缩版本,类似于this exampletravis.yml

答案 4 :(得分:0)

以下内容应缓存编译器结果:

cache:
  ccache: true
  directories:
    - $HOME/Library/Caches/Homebrew

在OSX上Travis目前似乎没有默认发布ccache =&gt;在使用ccache之前,还必须完成以下操作:

before_install: 
  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update        ; fi
   - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install ccache; fi

不可否认,已完成的构建仍未缓存。但是每个单独的计时器运行的构建结果都会导致,因此构建过程中至少有很大一部分可以算作“缓存”。

答案 5 :(得分:0)

要缓存brew update元数据,请only need to cache .git中的/usr/local/Homebrew文件夹

successful 'brew update' cache

其他人阅读的Travis配置:

cache:
  directories:
    - $HOME/Library/Caches/Homebrew
    - /usr/local/Homebrew
before_cache:
  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew cleanup; fi
# Credit https://discourse.brew.sh/t/best-practice-for-homebrew-on-travis-brew-update-is-5min-to-build-time/5215/9
# Cache only .git files under "/usr/local/Homebrew" so "brew update" does not take 5min every build
  - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then find /usr/local/Homebrew \! -regex ".+\.git.+" -delete; fi