<commit_before>require "yaml"
require "open3"
require "stringio"

require "hbc/utils/file"

UPDATE_CMD = "brew uninstall --force brew-cask; brew untap phinze/cask; brew untap caskroom/cask; brew update; brew cleanup; brew cask cleanup".freeze
ISSUES_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze

# monkeypatch Object - not a great idea
class Object
  def utf8_inspect
    return inspect unless defined?(Encoding)
    return map(&:utf8_inspect) if respond_to?(:map)
    inspect.force_encoding("UTF-8").sub(%r{\A"(.*)"\Z}, '\1')
  end
end

class Buffer < StringIO
  def initialize(tty = false)
    super()
    @tty = tty
  end

  def tty?
    @tty
  end
end

# global methods

def odebug(title, *sput)
  return unless Hbc.respond_to?(:debug)
  return unless Hbc.debug
  puts Formatter.headline(title, color: :magenta)
  puts sput unless sput.empty?
end

module Hbc
  module Utils
    def self.which(cmd, path = ENV["PATH"])
      unless File.basename(cmd) == cmd.to_s
        # cmd contains a directory element
        cmd_pn = Pathname(cmd)
        return nil unless cmd_pn.absolute?
        return resolve_executable(cmd_pn)
      end
      path.split(File::PATH_SEPARATOR).each do |elt|
        fq_cmd = Pathname(elt).expand_path.join(cmd)
        resolved = resolve_executable fq_cmd
        return resolved if resolved
      end
      nil
    end

    def self.resolve_executable(cmd)
      cmd_pn = Pathname(cmd)
      return nil unless cmd_pn.exist?
      return nil unless cmd_pn.executable?
      begin
        cmd_pn = Pathname(cmd_pn.realpath)
      rescue RuntimeError
        return nil
      end
      return nil unless cmd_pn.file?
      cmd_pn
    end

    def self.gain_permissions_remove(path, command: SystemCommand)
      if path.respond_to?(:rmtree) && path.exist?
        gain_permissions(path, ["-R"], command, &:rmtree)
      elsif File.symlink?(path)
        gain_permissions(path, ["-h"], command, &FileUtils.method(:rm_f))
      end
    end

    def self.gain_permissions(path, command_args, command)
      tried_permissions = false
      tried_ownership = false
      begin
        yield path
      rescue StandardError
        # in case of permissions problems
        unless tried_permissions
          # TODO: Better handling for the case where path is a symlink.
          #       The -h and -R flags cannot be combined, and behavior is
          #       dependent on whether the file argument has a trailing
          #       slash.  This should do the right thing, but is fragile.
          command.run("/usr/bin/chflags",
                      must_succeed: false,
                      args:         command_args + ["--", "000", path])
          command.run("/bin/chmod",
                      must_succeed: false,
                      args:         command_args + ["--", "u+rwx", path])
          command.run("/bin/chmod",
                      must_succeed: false,
                      args:         command_args + ["-N", path])
          tried_permissions = true
          retry # rmtree
        end
        unless tried_ownership
          # in case of ownership problems
          # TODO: Further examine files to see if ownership is the problem
          #       before using sudo+chown
          ohai "Using sudo to gain ownership of path '#{path}'"
          command.run("/usr/sbin/chown",
                      args: command_args + ["--", current_user, path],
                      sudo: true)
          tried_ownership = true
          # retry chflags/chmod after chown
          tried_permissions = false
          retry # rmtree
        end
      end
    end

    def self.current_user
      Etc.getpwuid(Process.euid).name
    end

    # paths that "look" descendant (textually) will still
    # return false unless both the given paths exist
    def self.file_is_descendant(file, dir)
      file = Pathname.new(file)
      dir  = Pathname.new(dir)
      return false unless file.exist? && dir.exist?
      unless dir.directory?
        onoe "Argument must be a directory: '#{dir}'"
        return false
      end
      unless file.absolute? && dir.absolute?
        onoe "Both arguments must be absolute: '#{file}', '#{dir}'"
        return false
      end
      while file.parent != file
        return true if File.identical?(file, dir)
        file = file.parent
      end
      false
    end

    def self.path_occupied?(path)
      File.exist?(path) || File.symlink?(path)
    end

    def self.error_message_with_suggestions
      <<-EOS.undent
        Most likely, this means you have an outdated version of Homebrew-Cask. Please run:
          #{UPDATE_CMD}

        If this doesn’t fix the problem, please report this bug:
          #{Formatter.url(ISSUES_URL)}

      EOS
    end

    def self.method_missing_message(method, token, section = nil)
      poo = []
      poo << "Unexpected method '#{method}' called"
      poo << "during #{section}" if section
      poo << "on Cask #{token}."

      opoo(poo.join(" ") + "\n" + error_message_with_suggestions)
    end

    def self.nowstamp_metadata_path(container_path)
      @timenow ||= Time.now.gmtime
      if container_path.respond_to?(:join)
        precision = 3
        timestamp = @timenow.strftime("%Y%m%d%H%M%S")
        fraction = format("%.#{precision}f", @timenow.to_f - @timenow.to_i)[1..-1]<commit_msg>updated cmd to point to prebug steps url<commit_after>require "yaml"
require "open3"
require "stringio"

require "hbc/utils/file"

PREBUG_URL = "https://github.com/caskroom/homebrew-cask/blob/master/doc/reporting_bugs/pre_bug_report.md".freeze
ISSUES_URL = "https://github.com/caskroom/homebrew-cask#reporting-bugs".freeze

# monkeypatch Object - not a great idea
class Object
  def utf8_inspect
    return inspect unless defined?(Encoding)
    return map(&:utf8_inspect) if respond_to?(:map)
    inspect.force_encoding("UTF-8").sub(%r{\A"(.*)"\Z}, '\1')
  end
end

class Buffer < StringIO
  def initialize(tty = false)
    super()
    @tty = tty
  end

  def tty?
    @tty
  end
end

# global methods

def odebug(title, *sput)
  return unless Hbc.respond_to?(:debug)
  return unless Hbc.debug
  puts Formatter.headline(title, color: :magenta)
  puts sput unless sput.empty?
end

module Hbc
  module Utils
    def self.which(cmd, path = ENV["PATH"])
      unless File.basename(cmd) == cmd.to_s
        # cmd contains a directory element
        cmd_pn = Pathname(cmd)
        return nil unless cmd_pn.absolute?
        return resolve_executable(cmd_pn)
      end
      path.split(File::PATH_SEPARATOR).each do |elt|
        fq_cmd = Pathname(elt).expand_path.join(cmd)
        resolved = resolve_executable fq_cmd
        return resolved if resolved
      end
      nil
    end

    def self.resolve_executable(cmd)
      cmd_pn = Pathname(cmd)
      return nil unless cmd_pn.exist?
      return nil unless cmd_pn.executable?
      begin
        cmd_pn = Pathname(cmd_pn.realpath)
      rescue RuntimeError
        return nil
      end
      return nil unless cmd_pn.file?
      cmd_pn
    end

    def self.gain_permissions_remove(path, command: SystemCommand)
      if path.respond_to?(:rmtree) && path.exist?
        gain_permissions(path, ["-R"], command, &:rmtree)
      elsif File.symlink?(path)
        gain_permissions(path, ["-h"], command, &FileUtils.method(:rm_f))
      end
    end

    def self.gain_permissions(path, command_args, command)
      tried_permissions = false
      tried_ownership = false
      begin
        yield path
      rescue StandardError
        # in case of permissions problems
        unless tried_permissions
          # TODO: Better handling for the case where path is a symlink.
          #       The -h and -R flags cannot be combined, and behavior is
          #       dependent on whether the file argument has a trailing
          #       slash.  This should do the right thing, but is fragile.
          command.run("/usr/bin/chflags",
                      must_succeed: false,
                      args:         command_args + ["--", "000", path])
          command.run("/bin/chmod",
                      must_succeed: false,
                      args:         command_args + ["--", "u+rwx", path])
          command.run("/bin/chmod",
                      must_succeed: false,
                      args:         command_args + ["-N", path])
          tried_permissions = true
          retry # rmtree
        end
        unless tried_ownership
          # in case of ownership problems
          # TODO: Further examine files to see if ownership is the problem
          #       before using sudo+chown
          ohai "Using sudo to gain ownership of path '#{path}'"
          command.run("/usr/sbin/chown",
                      args: command_args + ["--", current_user, path],
                      sudo: true)
          tried_ownership = true
          # retry chflags/chmod after chown
          tried_permissions = false
          retry # rmtree
        end
      end
    end

    def self.current_user
      Etc.getpwuid(Process.euid).name
    end

    # paths that "look" descendant (textually) will still
    # return false unless both the given paths exist
    def self.file_is_descendant(file, dir)
      file = Pathname.new(file)
      dir  = Pathname.new(dir)
      return false unless file.exist? && dir.exist?
      unless dir.directory?
        onoe "Argument must be a directory: '#{dir}'"
        return false
      end
      unless file.absolute? && dir.absolute?
        onoe "Both arguments must be absolute: '#{file}', '#{dir}'"
        return false
      end
      while file.parent != file
        return true if File.identical?(file, dir)
        file = file.parent
      end
      false
    end

    def self.path_occupied?(path)
      File.exist?(path) || File.symlink?(path)
    end

    def self.error_message_with_suggestions
      <<-EOS.undent

        Try following the instuctions here: 
          #{Formatter.url(PREBUG_URL)}

        If this doesn’t fix the problem, please report this bug:
          #{Formatter.url(ISSUES_URL)}

      EOS
    end

    def self.method_missing_message(method, token, section = nil)
      poo = []
      poo << "Unexpected method '#{method}' called"
      poo << "during #{section}" if section
      poo << "on Cask #{token}."

      opoo(poo.join(" ") + "\n" + error_message_with_suggestions)
    end

    def self.nowstamp_metadata_path(container_path)
      @timenow ||= Time.now.gmtime
      if container_path.respond_to?(:join)
        precision = 3
        timestamp = @timenow.strftime("%Y%m%d%H%M%S")
        fraction = format("%.#{precision}f", @timenow.to_f - @timenow.to_i)[1..-1]
{'fraction_non_alphanumeric': 0.09946564169869691, 'fraction_numerical': 0.0020624355488890974, 'mean_word_length': 2.1825775656324584, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 3, 'https://': 3, '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': '2477009', 'n_tokens_mistral': 3264, 'n_tokens_neox': 3216, 'n_words': 884}