如果已使用 CRLF 行结尾签出模板文件,则让 Vagrant+Chef 运行 退出

Have Vagrant+Chef run bail out if template files have been checked out with CRLF line endings

当 Windows 开发人员从我的 Git 存储库 with Git's autocrlf set to true 中查看食谱时,我一直被一个恼人的陷阱所困扰。当他们 运行 vagrant up 启动一个 Linux 虚拟机时, 食谱文件被映射到带有 CRLF 行结尾的虚拟机,这会导致 no end of obscure 错误shell 和其他 POSIX 实用程序 尝试对已复制到 VM 中的(现在无效的)模板文件进行操作。

解决方法很简单:将 autocrlf 设置更改为 inputfalse.

后重新克隆存储库

我的问题是,当你有错误的行尾时,唯一的症状是在奇怪的地方出现错误,这绝不表明行尾有问题。

我怎样才能让 Chef† 检查错误的行结尾,比如说,菜谱模板文件并在找到时抛出错误? 我认为一个简单的 Ruby 对给定文件中的行结尾进行断言的代码段,我可以将其放在菜谱的顶部。

注意:在我的回购的特定情况下,步骤顺序是:

  1. 开发人员签出存储库
  2. 开发人员 运行s vagrant up
  3. Vagrant 在虚拟机中启动 Chef运行
  4. 最后,repo 的构建脚本 运行s 在虚拟机中

† 或者 repo 中包含的任何其他内容

Rubocop can be used to enforce unix style line endings (among many other things).

例如(从命令行,在来宾中):

gem install rubocop
rubocop --only Style/EndOfLine  # only check line endings

或者可以在 chef 本身的上下文中使用类似以下食谱的内容来完成:

chef_gem 'rubocop'

ruby_block 'check line endings' do
  block do
    # It's probably better to call rubo cop code directly, rather than
    # shelling out, but that can be an exercise for the reader ;-)
    rubocop_cmd = Mixlib::ShellOut.new(
      'rubocop --only Style/EndOfLine',
      :cwd => 'dir_to_check'
    )
    rubocop_cmd.run_command

    # Raise an exception if it didn't exit with 0.
    rubocop_cmd.error!
  end
end

未捕获的异常将导致厨师 运行 退出。

这是一个 Ruby 片段,您可以将其放入任何 Chef 食谱中:

def cookbook_supporting_files(*cookbooks)
  cookbooks = cookbooks.map {|name| run_context.cookbook_collection[name]}

  cookbooks.flat_map do |cb|
    (cb.manifest[:files] + cb.manifest[:templates]) \
      .map {|f| ::File.join(cb.root_dir, f['path']) }
  end
end

def dos_eol?(f)
  ::File.open(f, 'rb').read(4096).include? "\r\n"
end

cookbook_supporting_files(cookbook_name).each do |f|
  if dos_eol? f
    raise "Cookbook template '#{f}' contains CRLF line endings"
  end
end

这将检查上述代码段所在的任何说明书中存在的说明书文件和模板的行尾。

如果你想用相同的片段检查其他食谱,只需替换:

cookbook_supporting_files(cookbook_name)

您要查看的食谱列表:

cookbook_supporting_files('some_cookbook', 'another_cookbook')