<commit_before>module Dapp
  module Builder
    # Chef
    class Chef < Base
      LOCAL_COOKBOOK_CHECKSUM_PATTERNS = %w(
        attributes/**/*
        recipes/**/*
        files/**/*
        templates/**/*
      ).freeze

      DEFAULT_CHEFDK_IMAGE = 'dappdeps/chefdk:0.17.3-1'.freeze # TODO: config, DSL, DEFAULT_CHEFDK_IMAGE

      [:infra_install, :infra_setup, :install, :setup].each do |stage|
        define_method("#{stage}_checksum") { stage_cookbooks_checksum(stage) }

        define_method("#{stage}?") { !stage_empty?(stage) }

        define_method("#{stage}") do |image|
          unless stage_empty?(stage)
            image.add_volumes_from(chefdk_container)
            image.add_command 'export PATH=/.dapp/deps/chefdk/bin:$PATH',
                              "export DAPP_BUILD_STAGE=#{stage}"

            image.add_volume "#{stage_build_path(stage)}:#{container_stage_build_path(stage)}:ro"
            image.add_command ['chef-solo',
                               '--legacy-mode',
                               "-c #{container_stage_config_path(stage)}",
                               "-o #{stage_cookbooks_runlist(stage).join(',')}"].join(' ')
          end
        end
      end

      def chef_cookbooks_checksum
        stage_cookbooks_checksum(:chef_cookbooks)
      end

      def chef_cookbooks(image)
        image.add_volume "#{cookbooks_vendor_path}:#{application.container_dapp_path('chef_vendored_cookbooks')}"
        image.add_command(
          'mkdir -p /usr/share/dapp/chef_repo',
          ["cp -a #{application.container_dapp_path('chef_vendored_cookbooks')} ",
           '/usr/share/dapp/chef_repo/cookbooks'].join
        )
      end

      private

      def enabled_modules
        application.config._chef._modules
      end

      def enabled_recipes
        application.config._chef._recipes
      end

      def project_name
        cookbook_metadata.name
      end

      def berksfile_path
        application.home_path('Berksfile')
      end

      def berksfile_lock_path
        application.home_path('Berksfile.lock')
      end

      def berksfile
        @berksfile ||= Berksfile.new(application.home_path, berksfile_path)
      end

      def cookbook_metadata_path
        application.home_path('metadata.rb')
      end

      def cookbook_metadata
        @cookbook_metadata ||= CookbookMetadata.new(cookbook_metadata_path)
      end

      def berksfile_lock_checksum
        application.hashsum berksfile_lock_path.read if berksfile_lock_path.exist?
      end

      def stage_cookbooks_checksum_path(stage)
        application.build_path("#{cookbooks_checksum}.#{stage}.checksum")
      end

      def stage_cookbooks_checksum(stage)
        if stage_cookbooks_checksum_path(stage).exist?
          stage_cookbooks_checksum_path(stage).read.strip
        else
          checksum = if stage == :chef_cookbooks
                       cookbooks_checksum
                     else
                       paths = Dir[stage_cookbooks_path(stage, '**/*')].map(&Pathname.method(:new))

                       application.hashsum [
                         application.paths_content_hashsum(paths),
                         *paths.map { |p| p.relative_path_from(stage_cookbooks_path(stage)).to_s }.sort,
                         *enabled_modules,
                         stage == :infra_install ? chefdk_image : nil
                       ].compact
                     end

          stage_cookbooks_checksum_path(stage).write "#{checksum}\n"
          checksum
        end
      end

      def cookbooks_checksum
        @cookbooks_checksum ||= begin
          paths = berksfile
            .local_cookbooks
            .values
            .map { |cookbook| cookbook[:path] }
            .product(LOCAL_COOKBOOK_CHECKSUM_PATTERNS)
            .map { |cb, dir| Dir[cb.join(dir)] }
            .flatten
            .map(&Pathname.method(:new))

          application.hashsum [
            application.paths_content_hashsum(paths),
            *paths.map { |p| p.relative_path_from(berksfile.home_path).to_s }.sort,
            berksfile_lock_checksum,
            *enabled_modules
          ]<commit_msg>Chef cookbooks checksum += enabled recipes<commit_after>module Dapp
  module Builder
    # Chef
    class Chef < Base
      LOCAL_COOKBOOK_CHECKSUM_PATTERNS = %w(
        attributes/**/*
        recipes/**/*
        files/**/*
        templates/**/*
      ).freeze

      DEFAULT_CHEFDK_IMAGE = 'dappdeps/chefdk:0.17.3-1'.freeze # TODO: config, DSL, DEFAULT_CHEFDK_IMAGE

      [:infra_install, :infra_setup, :install, :setup].each do |stage|
        define_method("#{stage}_checksum") { stage_cookbooks_checksum(stage) }

        define_method("#{stage}?") { !stage_empty?(stage) }

        define_method("#{stage}") do |image|
          unless stage_empty?(stage)
            image.add_volumes_from(chefdk_container)
            image.add_command 'export PATH=/.dapp/deps/chefdk/bin:$PATH',
                              "export DAPP_BUILD_STAGE=#{stage}"

            image.add_volume "#{stage_build_path(stage)}:#{container_stage_build_path(stage)}:ro"
            image.add_command ['chef-solo',
                               '--legacy-mode',
                               "-c #{container_stage_config_path(stage)}",
                               "-o #{stage_cookbooks_runlist(stage).join(',')}"].join(' ')
          end
        end
      end

      def chef_cookbooks_checksum
        stage_cookbooks_checksum(:chef_cookbooks)
      end

      def chef_cookbooks(image)
        image.add_volume "#{cookbooks_vendor_path}:#{application.container_dapp_path('chef_vendored_cookbooks')}"
        image.add_command(
          'mkdir -p /usr/share/dapp/chef_repo',
          ["cp -a #{application.container_dapp_path('chef_vendored_cookbooks')} ",
           '/usr/share/dapp/chef_repo/cookbooks'].join
        )
      end

      private

      def enabled_modules
        application.config._chef._modules
      end

      def enabled_recipes
        application.config._chef._recipes
      end

      def project_name
        cookbook_metadata.name
      end

      def berksfile_path
        application.home_path('Berksfile')
      end

      def berksfile_lock_path
        application.home_path('Berksfile.lock')
      end

      def berksfile
        @berksfile ||= Berksfile.new(application.home_path, berksfile_path)
      end

      def cookbook_metadata_path
        application.home_path('metadata.rb')
      end

      def cookbook_metadata
        @cookbook_metadata ||= CookbookMetadata.new(cookbook_metadata_path)
      end

      def berksfile_lock_checksum
        application.hashsum berksfile_lock_path.read if berksfile_lock_path.exist?
      end

      def stage_cookbooks_checksum_path(stage)
        application.build_path("#{cookbooks_checksum}.#{stage}.checksum")
      end

      def stage_cookbooks_checksum(stage)
        if stage_cookbooks_checksum_path(stage).exist?
          stage_cookbooks_checksum_path(stage).read.strip
        else
          checksum = if stage == :chef_cookbooks
                       cookbooks_checksum
                     else
                       paths = Dir[stage_cookbooks_path(stage, '**/*')].map(&Pathname.method(:new))

                       application.hashsum [
                         application.paths_content_hashsum(paths),
                         *paths.map { |p| p.relative_path_from(stage_cookbooks_path(stage)).to_s }.sort,
                         *enabled_modules,
                         stage == :infra_install ? chefdk_image : nil
                       ].compact
                     end

          stage_cookbooks_checksum_path(stage).write "#{checksum}\n"
          checksum
        end
      end

      def cookbooks_checksum
        @cookbooks_checksum ||= begin
          paths = berksfile
            .local_cookbooks
            .values
            .map { |cookbook| cookbook[:path] }
            .product(LOCAL_COOKBOOK_CHECKSUM_PATTERNS)
            .map { |cb, dir| Dir[cb.join(dir)] }
            .flatten
            .map(&Pathname.method(:new))

          application.hashsum [
            application.paths_content_hashsum(paths),
            *paths.map { |p| p.relative_path_from(berksfile.home_path).to_s }.sort,
            berksfile_lock_checksum,
            *enabled_recipes,
            *enabled_modules
          ]
{'fraction_non_alphanumeric': 0.09889193375431908, 'fraction_numerical': 0.0011914690813773384, 'mean_word_length': 1.9692253272019808, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7115815', 'n_tokens_mistral': 2527, 'n_tokens_neox': 2435, 'n_words': 359}