<commit_before># encoding: utf-8

module Nanoc3::CLI::Commands

  class Compile < Cri::Command

    def name
      'compile'
    end

    def aliases
      []
    end

    def short_desc
      'compile items of this site'
    end

    def long_desc
      'Compile all items of the current site. If an identifier is given, ' +
      'only the item with the given identifier will be compiled. ' +
      "\n\n" +
      'By default, only item that are outdated will be compiled. This can ' +
      'speed up the compilation process quite a bit, but items that include ' +
      'content from other items may have to be recompiled manually. In ' +
      'order to compile items even when they are outdated, use the --force option.'
    end

    def usage
      "nanoc3 compile [options] [identifier]"
    end

    def option_definitions
      [
        # --all
        {
          :long => 'all', :short => 'a', :argument => :forbidden,
          :desc => 'alias for --force (DEPRECATED)'
        },
        # --force
        {
          :long => 'force', :short => 'f', :argument => :forbidden,
          :desc => 'compile items even when they are not outdated'
        }
      ]
    end

    def run(options, arguments)
      # Make sure we are in a nanoc site directory
      puts "Loading site data..."
      @base.require_site
      @base.site.load_data

      # Check presence of --all option
      if options.has_key?(:all)
        $stderr.puts "Warning: the --all option is deprecated; please use --force instead."
      end

      # Find item(s) to compile
      if arguments.size == 0
        item = nil
      elsif arguments.size == 1
        # Find item
        identifier = arguments[0].cleaned_identifier
        item = @base.site.items.find { |item| item.identifier == identifier }

        # Ensure item
        if item.nil?
          $stderr.puts "Unknown item: #{identifier}"
          exit 1
        end
      end

      # Give feedback
      puts "Compiling #{item.nil? ? 'site' : 'item'}..."

      # Initialize profiling stuff
      time_before = Time.now
      @filter_times ||= {}
      @times_stack  ||= []
      setup_notifications

      # Compile
      @base.site.compiler.run(
        item,
        :force => options.has_key?(:all) || options.has_key?(:force)
      )

      # Find reps
      reps = @base.site.items.map  { |i| i.reps }.flatten

      # Show skipped reps
      reps.select { |r| !r.compiled? }.each do |rep|
        next if rep.raw_path.nil?
        duration = @rep_times[rep.raw_path]
        Nanoc3::CLI::Logger.instance.file(:high, :skip, rep.raw_path, duration)
      end

      # Show diff
      write_diff_for(reps)

      # Give general feedback
      puts
      puts "No items were modified." unless reps.any? { |r| r.modified? }
      puts "#{item.nil? ? 'Site' : 'Item'} compiled in #{format('%.2f', Time.now - time_before)}s."

      if options.has_key?(:verbose)
        print_state_feedback(reps)
        print_profiling_feedback(reps)
      end
    end

  private

    def setup_notifications
      Nanoc3::NotificationCenter.on(:compilation_started) do |rep|
        rep_compilation_started(rep)
      end
      Nanoc3::NotificationCenter.on(:compilation_ended) do |rep|
        rep_compilation_ended(rep)
      end
      Nanoc3::NotificationCenter.on(:filtering_started) do |rep, filter_name|
        rep_filtering_started(rep, filter_name)
      end
      Nanoc3::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
        rep_filtering_ended(rep, filter_name)
      end
    end

    def write_diff_for(reps)
      full_diff = ''
      reps.each do |rep|
        diff = rep.diff
        next if diff.nil?

        # Fix header
        diff.sub!(/^--- .*/,    '--- ' + rep.raw_path)
        diff.sub!(/^\+\+\+ .*/, '+++ ' + rep.raw_path)

        # Add
        full_diff << diff
      end

      # Write
      File.open('output.diff', 'w') { |io| io.write(full_diff) }
    end

    def print_state_feedback(reps)
      # Categorise reps
      rest              = reps
      created, rest     = *rest.partition { |r| r.created? }
      modified, rest    = *rest.partition { |r| r.modified? }
      skipped, rest     = *rest.partition { |r| !r.compiled? }
      not_written, rest = *rest.partition { |r| r.compiled? && !r.written? }
      identical         = rest<commit_msg>made compile command not write output.diff when diffs are disabled<commit_after># encoding: utf-8

module Nanoc3::CLI::Commands

  class Compile < Cri::Command

    def name
      'compile'
    end

    def aliases
      []
    end

    def short_desc
      'compile items of this site'
    end

    def long_desc
      'Compile all items of the current site. If an identifier is given, ' +
      'only the item with the given identifier will be compiled. ' +
      "\n\n" +
      'By default, only item that are outdated will be compiled. This can ' +
      'speed up the compilation process quite a bit, but items that include ' +
      'content from other items may have to be recompiled manually. In ' +
      'order to compile items even when they are outdated, use the --force option.'
    end

    def usage
      "nanoc3 compile [options] [identifier]"
    end

    def option_definitions
      [
        # --all
        {
          :long => 'all', :short => 'a', :argument => :forbidden,
          :desc => 'alias for --force (DEPRECATED)'
        },
        # --force
        {
          :long => 'force', :short => 'f', :argument => :forbidden,
          :desc => 'compile items even when they are not outdated'
        }
      ]
    end

    def run(options, arguments)
      # Make sure we are in a nanoc site directory
      puts "Loading site data..."
      @base.require_site
      @base.site.load_data

      # Check presence of --all option
      if options.has_key?(:all)
        $stderr.puts "Warning: the --all option is deprecated; please use --force instead."
      end

      # Find item(s) to compile
      if arguments.size == 0
        item = nil
      elsif arguments.size == 1
        # Find item
        identifier = arguments[0].cleaned_identifier
        item = @base.site.items.find { |item| item.identifier == identifier }

        # Ensure item
        if item.nil?
          $stderr.puts "Unknown item: #{identifier}"
          exit 1
        end
      end

      # Give feedback
      puts "Compiling #{item.nil? ? 'site' : 'item'}..."

      # Initialize profiling stuff
      time_before = Time.now
      @filter_times ||= {}
      @times_stack  ||= []
      setup_notifications

      # Compile
      @base.site.compiler.run(
        item,
        :force => options.has_key?(:all) || options.has_key?(:force)
      )

      # Find reps
      reps = @base.site.items.map  { |i| i.reps }.flatten

      # Show skipped reps
      reps.select { |r| !r.compiled? }.each do |rep|
        next if rep.raw_path.nil?
        duration = @rep_times[rep.raw_path]
        Nanoc3::CLI::Logger.instance.file(:high, :skip, rep.raw_path, duration)
      end

      # Show diff
      write_diff_for(reps)

      # Give general feedback
      puts
      puts "No items were modified." unless reps.any? { |r| r.modified? }
      puts "#{item.nil? ? 'Site' : 'Item'} compiled in #{format('%.2f', Time.now - time_before)}s."

      if options.has_key?(:verbose)
        print_state_feedback(reps)
        print_profiling_feedback(reps)
      end
    end

  private

    def setup_notifications
      Nanoc3::NotificationCenter.on(:compilation_started) do |rep|
        rep_compilation_started(rep)
      end
      Nanoc3::NotificationCenter.on(:compilation_ended) do |rep|
        rep_compilation_ended(rep)
      end
      Nanoc3::NotificationCenter.on(:filtering_started) do |rep, filter_name|
        rep_filtering_started(rep, filter_name)
      end
      Nanoc3::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
        rep_filtering_ended(rep, filter_name)
      end
    end

    def write_diff_for(reps)
      # Delete diff
      FileUtils.rm('output.diff') if File.file?('output.diff')

      # Don’t generate diffs when diffs are disabled
      return if !@base.site.config[:enable_output_diff]

      # Generate diff
      full_diff = ''
      reps.each do |rep|
        diff = rep.diff
        next if diff.nil?

        # Fix header
        diff.sub!(/^--- .*/,    '--- ' + rep.raw_path)
        diff.sub!(/^\+\+\+ .*/, '+++ ' + rep.raw_path)

        # Add
        full_diff << diff
      end

      # Write
      File.open('output.diff', 'w') { |io| io.write(full_diff) }
    end

    def print_state_feedback(reps)
      # Categorise reps
      rest              = reps
      created, rest     = *rest.partition { |r| r.created? }
      modified, rest    = *rest.partition { |r| r.modified? }
      skipped, rest     = *rest.partition { |r| !r.compiled? }
      not_written, rest = *rest.partition { |r| r.compiled? && !r.written? }
      identical         = rest
{'fraction_non_alphanumeric': 0.1171936096525528, 'fraction_numerical': 0.002904703385096637, 'mean_word_length': 2.0356052899287893, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7229400', 'n_tokens_mistral': 2834, 'n_tokens_neox': 2733, 'n_words': 759}