<commit_before>require 'rexml/document'

class Compile
  attr_accessor :token, :user,
                :root_resource_path, :resources, 
                :compiler, :output_format
  attr_reader   :output_files, :log_files, :unique_id,
                :status, :error_type, :error_message,
                :bibtex_ran, :makeindex_ran

  POSSIBLE_COMPILER_OUTPUT_FORMATS = {
    :pdflatex => ['pdf'],
    :latex    => ['dvi', 'pdf', 'ps']
  }

  def compiler
    @compiler ||= 'pdflatex'
  end

  def output_format
    @output_format ||= 'pdf'
  end

  def initialize(attributes = {})
    self.root_resource_path = attributes[:root_resource_path]
    self.token = attributes[:token]
    
    self.compiler = attributes[:compiler]
    self.output_format = attributes[:output_format]

    self.resources = []
    for resource in attributes[:resources].to_a
      self.resources << Resource.new(
        resource[:path],
        resource[:modified_date],
        resource[:content],
        resource[:url],
        self
      )
    end
    
    @output_files = []
    @log_files = []
    @status = :unprocessed
    @bibtex_ran = false
    @makeindex_ran = false
  end

  def compile
    @start_time = Time.now
    validate_compile
    write_resources_to_disk
    do_compile
    convert_to_output_format
    move_compiled_files_to_public_dir
    @status = :success
  rescue CLSI::CompileError => e
    @status = :failure
    @error_type = e.class.name.demodulize
    @error_message = e.message
  ensure
    move_log_files_to_public_dir
    write_response_to_public_dir
    remove_compile_directory
    record_in_compile_log
  end

  def validate_compile
    if self.user.blank?
      self.user = User.find_by_token(self.token)
      raise CLSI::InvalidToken, 'user does not exist' if self.user.nil?
    end
    
    unless POSSIBLE_COMPILER_OUTPUT_FORMATS.has_key?(self.compiler.to_sym)
      raise CLSI::UnknownCompiler, "#{self.compiler} is not a valid compiler"
    end
    
    unless POSSIBLE_COMPILER_OUTPUT_FORMATS[self.compiler.to_sym].include?(self.output_format)
      raise CLSI::ImpossibleOutputFormat, "#{self.compiler} cannot produce #{self.output_format} output"
    end
  end
  
  def unique_id
    @unique_id ||= generate_unique_string
  end
  
  def compile_directory
    @compile_directory ||= File.join(LATEX_COMPILE_DIR, self.unique_id)
  end
  
  def to_xml
    xml = Builder::XmlMarkup.new
    xml.instruct!

    xml.compile do
      xml.compile_id(self.unique_id)
      
      if self.status == :failure
        xml.status('failure')
        xml.error do
          xml.type self.error_type
          xml.message self.error_message
        end
      else
        xml.status(self.status.to_s)
      end
   
      unless self.output_files.empty?
        xml.output do
          for file in self.output_files
            xml.file(:url => file.url, :type => file.type, :mimetype => file.mimetype)
          end
        end
      end
  
      unless self.log_files.empty?
        xml.logs do
          for file in self.log_files
            xml.file(:url => file.url, :type => file.type, :mimetype => file.mimetype)
          end
        end
      end
    end
  end

private

  def write_resources_to_disk
    File.umask(0002)
    
    for resource in self.resources.to_a
      resource.write_to_disk
    end
  end

  def do_compile
    run_compiler
    
    aux_file_content = read_aux_files
    if aux_file_content.include? '\\citation' or aux_file_content.include? '\\bibdata' or aux_file_content.include? '\\bibstyle'
      modify_aux_files
      run_bibtex
      run_latex_again = true
      @bibtex_ran = true
    end
    
    if File.exist?(File.join(compile_directory, 'output.idx'))
      run_makeindex
      run_latex_again = true
      @makeindex_ran = true
    end
    
    log_content = read_log
    if log_content.include?('There were undefined references') or log_content.include?('There were undefined citations') or run_latex_again
      run_compiler
    end
    
    log_content = read_log
    if log_content.include?('There were undefined references') or log_content.include?('There were undefined citations')
      run_compiler
    end
  end<commit_msg>Included more conditions for running hte compiler multiple times<commit_after>require 'rexml/document'

class Compile
  attr_accessor :token, :user,
                :root_resource_path, :resources, 
                :compiler, :output_format
  attr_reader   :output_files, :log_files, :unique_id,
                :status, :error_type, :error_message,
                :bibtex_ran, :makeindex_ran

  POSSIBLE_COMPILER_OUTPUT_FORMATS = {
    :pdflatex => ['pdf'],
    :latex    => ['dvi', 'pdf', 'ps']
  }

  def compiler
    @compiler ||= 'pdflatex'
  end

  def output_format
    @output_format ||= 'pdf'
  end

  def initialize(attributes = {})
    self.root_resource_path = attributes[:root_resource_path]
    self.token = attributes[:token]
    
    self.compiler = attributes[:compiler]
    self.output_format = attributes[:output_format]

    self.resources = []
    for resource in attributes[:resources].to_a
      self.resources << Resource.new(
        resource[:path],
        resource[:modified_date],
        resource[:content],
        resource[:url],
        self
      )
    end
    
    @output_files = []
    @log_files = []
    @status = :unprocessed
    @bibtex_ran = false
    @makeindex_ran = false
  end

  def compile
    @start_time = Time.now
    validate_compile
    write_resources_to_disk
    do_compile
    convert_to_output_format
    move_compiled_files_to_public_dir
    @status = :success
  rescue CLSI::CompileError => e
    @status = :failure
    @error_type = e.class.name.demodulize
    @error_message = e.message
  ensure
    move_log_files_to_public_dir
    write_response_to_public_dir
    remove_compile_directory
    record_in_compile_log
  end

  def validate_compile
    if self.user.blank?
      self.user = User.find_by_token(self.token)
      raise CLSI::InvalidToken, 'user does not exist' if self.user.nil?
    end
    
    unless POSSIBLE_COMPILER_OUTPUT_FORMATS.has_key?(self.compiler.to_sym)
      raise CLSI::UnknownCompiler, "#{self.compiler} is not a valid compiler"
    end
    
    unless POSSIBLE_COMPILER_OUTPUT_FORMATS[self.compiler.to_sym].include?(self.output_format)
      raise CLSI::ImpossibleOutputFormat, "#{self.compiler} cannot produce #{self.output_format} output"
    end
  end
  
  def unique_id
    @unique_id ||= generate_unique_string
  end
  
  def compile_directory
    @compile_directory ||= File.join(LATEX_COMPILE_DIR, self.unique_id)
  end
  
  def to_xml
    xml = Builder::XmlMarkup.new
    xml.instruct!

    xml.compile do
      xml.compile_id(self.unique_id)
      
      if self.status == :failure
        xml.status('failure')
        xml.error do
          xml.type self.error_type
          xml.message self.error_message
        end
      else
        xml.status(self.status.to_s)
      end
   
      unless self.output_files.empty?
        xml.output do
          for file in self.output_files
            xml.file(:url => file.url, :type => file.type, :mimetype => file.mimetype)
          end
        end
      end
  
      unless self.log_files.empty?
        xml.logs do
          for file in self.log_files
            xml.file(:url => file.url, :type => file.type, :mimetype => file.mimetype)
          end
        end
      end
    end
  end

private

  def write_resources_to_disk
    File.umask(0002)
    
    for resource in self.resources.to_a
      resource.write_to_disk
    end
  end

  def do_compile
    run_compiler
    
    aux_file_content = read_aux_files
    if aux_file_content.include? '\\citation' or aux_file_content.include? '\\bibdata' or aux_file_content.include? '\\bibstyle'
      modify_aux_files
      run_bibtex
      run_latex_again = true
      @bibtex_ran = true
    end
    
    if File.exist?(File.join(compile_directory, 'output.idx'))
      run_makeindex
      run_latex_again = true
      @makeindex_ran = true
    end
    
    if log_complains_about_references? or run_latex_again
      run_compiler
    end
    
    if log_complains_about_references?
      run_compiler
    end
  end

  def log_complains_about_references?
    log_content = read_log
    log_content.include?('There were undefined references') ||
    log_content.include?('There were undefined citations') ||
    log_content.include?('LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.') ||
    log_content.include?('LaTeX Warning: Citation') ||
    log_content.include?('No file output.toc')
  end
{'fraction_non_alphanumeric': 0.08828996282527882, 'fraction_numerical': 0.0009293680297397769, 'mean_word_length': 2.6172268907563025, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 30}, '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': '6847665', 'n_tokens_mistral': 2798, 'n_tokens_neox': 2733, 'n_words': 565}