<commit_before># -*- coding: UTF-8 -*-
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require "digest/sha2"

require "chef-dk/policyfile/storage_config"
require "chef-dk/policyfile/cookbook_locks"
require "chef-dk/policyfile/solution_dependencies"
require "chef-dk/ui"

module ChefDK

  class PolicyfileLock

    class InstallReport

      attr_reader :ui
      attr_reader :policyfile_lock

      def initialize(ui: nil, policyfile_lock: nil)
        @ui = ui
        @policyfile_lock = policyfile_lock

        @cookbook_name_width = nil
        @cookbook_version_width = nil
      end

      def installing_fixed_version_cookbook(cookbook_spec)
        verb = cookbook_spec.installed? ? "Using     " : "Installing"
        ui.msg("#{verb} #{format_fixed_version_cookbook(cookbook_spec)}")
      end

      def installing_cookbook(cookbook_lock)
        verb = cookbook_lock.installed? ? "Using     " : "Installing"
        ui.msg("#{verb} #{format_cookbook(cookbook_lock)}")
      end

      private

      def format_cookbook(cookbook_lock)
        "#{cookbook_lock.name.ljust(cookbook_name_width)} #{cookbook_lock.version.to_s.ljust(cookbook_version_width)}"
      end

      def cookbook_name_width
        policyfile_lock.cookbook_locks.map { |name, _| name.size }.max
      end

      def cookbook_version_width
        policyfile_lock.cookbook_locks.map { |_, lock| lock.version.size }.max
      end
    end

    RUN_LIST_ITEM_FORMAT = /\Arecipe\[[^\s]+::[^\s]+\]\Z/

    def self.build(storage_config)
      lock = new(storage_config)
      yield lock
      lock
    end

    def self.build_from_compiler(compiler, storage_config)
      lock = new(storage_config)
      lock.build_from_compiler(compiler)
      lock
    end

    include Policyfile::StorageConfigDelegation

    attr_accessor :name
    attr_accessor :run_list
    attr_accessor :named_run_lists
    attr_accessor :default_attributes
    attr_accessor :override_attributes

    attr_reader :solution_dependencies

    attr_reader :storage_config

    attr_reader :cookbook_locks

    attr_reader :included_policy_locks

    attr_reader :install_report

    def initialize(storage_config, ui: nil)
      @name = nil
      @run_list = []
      @named_run_lists = {}
      @cookbook_locks = {}
      @relative_paths_root = Dir.pwd
      @storage_config = storage_config
      @ui = ui || UI.null

      @default_attributes = {}
      @override_attributes = {}

      @solution_dependencies = Policyfile::SolutionDependencies.new

      @included_policy_locks = []

      @install_report = InstallReport.new(ui: @ui, policyfile_lock: self)
    end

    def lock_data_for(cookbook_name)
      @cookbook_locks[cookbook_name]
    end

    def cached_cookbook(name)
      cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
      yield cached_cookbook if block_given?
      @cookbook_locks[name] = cached_cookbook
    end

    def local_cookbook(name)
      local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
      yield local_cookbook if block_given?
      @cookbook_locks[name] = local_cookbook
    end

    def dependencies
      yield solution_dependencies
    end

    def to_lock
      {}.tap do |lock|
        lock["revision_id"] = revision_id
        lock["name"] = name
        lock["run_list"] = run_list
        lock["named_run_lists"] = named_run_lists unless named_run_lists.empty?
        lock["cookbook_locks"] = cookbook_locks_for_lockfile
        lock["default_attributes"] = default_attributes
        lock["override_attributes"] = override_attributes
        lock["solution_dependencies"] = solution_dependencies.to_lock
        lock["included_policy_locks"] = included_policy_locks
      end
    end

    # Returns a fingerprint of the PolicyfileLock by computing the SHA1 hash of
    # #canonical_revision_string
    def revision_id
      Digest::SHA256.new.hexdigest(canonical_revision_string)
    end

    # Generates a string representation of the lock data in a specialized
    # format suitable for generating a checksum of the lock itself. Only data
    # that modifies the behavior of a chef-client using the lockfile is
    # included in this format; for example, a modification to the source
    # options in a `Policyfile.rb` that yields identical code (such as
    # switching to a github fork at the same revision) will not cause a change
    # in the PolicyfileLock's canonical_revision_string.
    #
    # This format is intended to be used only for generating an identifier for
    # a particular revision of a PolicyfileLock. It should not be used as a
    # serialization format, and is not guaranteed to be a stable interface.<commit_msg>Move included_policy_locks up in the json<commit_after># -*- coding: UTF-8 -*-
#
# Copyright:: Copyright (c) 2014 Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require "digest/sha2"

require "chef-dk/policyfile/storage_config"
require "chef-dk/policyfile/cookbook_locks"
require "chef-dk/policyfile/solution_dependencies"
require "chef-dk/ui"

module ChefDK

  class PolicyfileLock

    class InstallReport

      attr_reader :ui
      attr_reader :policyfile_lock

      def initialize(ui: nil, policyfile_lock: nil)
        @ui = ui
        @policyfile_lock = policyfile_lock

        @cookbook_name_width = nil
        @cookbook_version_width = nil
      end

      def installing_fixed_version_cookbook(cookbook_spec)
        verb = cookbook_spec.installed? ? "Using     " : "Installing"
        ui.msg("#{verb} #{format_fixed_version_cookbook(cookbook_spec)}")
      end

      def installing_cookbook(cookbook_lock)
        verb = cookbook_lock.installed? ? "Using     " : "Installing"
        ui.msg("#{verb} #{format_cookbook(cookbook_lock)}")
      end

      private

      def format_cookbook(cookbook_lock)
        "#{cookbook_lock.name.ljust(cookbook_name_width)} #{cookbook_lock.version.to_s.ljust(cookbook_version_width)}"
      end

      def cookbook_name_width
        policyfile_lock.cookbook_locks.map { |name, _| name.size }.max
      end

      def cookbook_version_width
        policyfile_lock.cookbook_locks.map { |_, lock| lock.version.size }.max
      end
    end

    RUN_LIST_ITEM_FORMAT = /\Arecipe\[[^\s]+::[^\s]+\]\Z/

    def self.build(storage_config)
      lock = new(storage_config)
      yield lock
      lock
    end

    def self.build_from_compiler(compiler, storage_config)
      lock = new(storage_config)
      lock.build_from_compiler(compiler)
      lock
    end

    include Policyfile::StorageConfigDelegation

    attr_accessor :name
    attr_accessor :run_list
    attr_accessor :named_run_lists
    attr_accessor :default_attributes
    attr_accessor :override_attributes

    attr_reader :solution_dependencies

    attr_reader :storage_config

    attr_reader :cookbook_locks

    attr_reader :included_policy_locks

    attr_reader :install_report

    def initialize(storage_config, ui: nil)
      @name = nil
      @run_list = []
      @named_run_lists = {}
      @cookbook_locks = {}
      @relative_paths_root = Dir.pwd
      @storage_config = storage_config
      @ui = ui || UI.null

      @default_attributes = {}
      @override_attributes = {}

      @solution_dependencies = Policyfile::SolutionDependencies.new

      @included_policy_locks = []

      @install_report = InstallReport.new(ui: @ui, policyfile_lock: self)
    end

    def lock_data_for(cookbook_name)
      @cookbook_locks[cookbook_name]
    end

    def cached_cookbook(name)
      cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
      yield cached_cookbook if block_given?
      @cookbook_locks[name] = cached_cookbook
    end

    def local_cookbook(name)
      local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
      yield local_cookbook if block_given?
      @cookbook_locks[name] = local_cookbook
    end

    def dependencies
      yield solution_dependencies
    end

    def to_lock
      {}.tap do |lock|
        lock["revision_id"] = revision_id
        lock["name"] = name
        lock["run_list"] = run_list
        lock["named_run_lists"] = named_run_lists unless named_run_lists.empty?
        lock["included_policy_locks"] = included_policy_locks
        lock["cookbook_locks"] = cookbook_locks_for_lockfile
        lock["default_attributes"] = default_attributes
        lock["override_attributes"] = override_attributes
        lock["solution_dependencies"] = solution_dependencies.to_lock
      end
    end

    # Returns a fingerprint of the PolicyfileLock by computing the SHA1 hash of
    # #canonical_revision_string
    def revision_id
      Digest::SHA256.new.hexdigest(canonical_revision_string)
    end

    # Generates a string representation of the lock data in a specialized
    # format suitable for generating a checksum of the lock itself. Only data
    # that modifies the behavior of a chef-client using the lockfile is
    # included in this format; for example, a modification to the source
    # options in a `Policyfile.rb` that yields identical code (such as
    # switching to a github fork at the same revision) will not cause a change
    # in the PolicyfileLock's canonical_revision_string.
    #
    # This format is intended to be used only for generating an identifier for
    # a particular revision of a PolicyfileLock. It should not be used as a
    # serialization format, and is not guaranteed to be a stable interface.
{'fraction_non_alphanumeric': 0.07692307692307693, 'fraction_numerical': 0.003024003024003024, 'mean_word_length': 3.2846153846153845, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4487578', 'n_tokens_mistral': 3212, 'n_tokens_neox': 3030, 'n_words': 844}