lib/envirobly/git/commit.rb



# frozen_string_literal: true

require "time"
require "open3"

class Envirobly::Git::Commit < Envirobly::Git
  EXECUTABLE_FILE_MODE = "100755"
  SYMLINK_FILE_MODE = "120000"

  attr_reader :working_dir

  def initialize(ref, working_dir: Dir.getwd)
    @ref = ref
    super working_dir
  end

  def exists?
    git(%(cat-file -t #{@ref})).stdout.strip == "commit"
  end

  def ref
    @normalized_ref ||= git(%(rev-parse #{@ref})).stdout.strip
  end

  def short_ref
    @short_ref ||= ref[0..6]
  end

  def message
    git(%(log #{@ref} -n1 --pretty=%B)).stdout.strip
  end

  def time
    Time.parse git(%(log #{@ref} -n1 --date=iso --pretty=format:"%ad")).stdout
  end

  def file_exists?(path)
    git(%(cat-file -t #{@ref}:#{path})).stdout.strip == "blob"
  end

  def dir_exists?(path)
    suffix = path.end_with?("/") ? nil : "/"
    git(%(cat-file -t #{@ref}:#{path}#{suffix})).stdout.strip == "tree"
  end

  def file_content(path)
    git(%(show #{@ref}:#{path})).stdout
  end

  def object_tree(ref: @ref, chdir: @working_dir)
    @object_tree ||= begin
      objects = {}
      objects[chdir] = []

      git(%(ls-tree -r #{ref}), chdir:).stdout.lines.each do |line|
        mode, type, object_hash, path = line.split(/\s+/)

        next if path.start_with?("#{Envirobly::Config::DIR}/")

        if type == "commit"
          objects.merge! object_tree(ref: object_hash, chdir: File.join(chdir, path))
        else
          objects[chdir] << [ mode, type, object_hash, path ]
        end
      end

      objects
    end
  end

  def object_tree_checksum
    digestable = object_tree.values.flatten.to_json
    @object_tree_checksum ||= Digest::SHA256.hexdigest(digestable)
  end

  # @deprecated
  def objects_with_checksum_at(path)
    git(%{ls-tree #{@ref} --format='%(objectname) %(path)' #{path}}).stdout.lines.map(&:chomp).
      reject { _1.split(" ").last == Envirobly::Config::DIR }
  end
end