<commit_before>defmodule Mix.SCM.Git do
  @behaviour Mix.SCM
  @moduledoc false

  def fetchable? do
    true
  end

  def format(opts) do
    opts[:git]
  end

  def format_lock(opts) do
    case opts[:lock] do
      {:git, _, lock_rev, lock_opts} ->
        lock = String.slice(lock_rev, 0, 7)
        case Enum.find_value [:branch, :ref, :tag], &List.keyfind(lock_opts, &1, 0) do
          {:ref, _}  -> lock <> " (ref)"
          {key, val} -> lock <> " (#{key}: #{val})"
          nil        -> lock
        end
      _ ->
        nil
    end
  end

  def accepts_options(_app, opts) do
    opts =
      opts
      |> Keyword.put(:checkout, opts[:dest])
      |> sparse_opts()

    cond do
      gh = opts[:github] ->
        opts
        |> Keyword.delete(:github)
        |> Keyword.put(:git, "https://github.com/#{gh}.git")
        |> validate_git_options
      opts[:git] ->
        opts
        |> validate_git_options
      true ->
        nil
    end
  end

  def checked_out?(opts) do
    # Are we inside a Git repository?
    opts[:checkout]
    |> Path.join(".git/HEAD")
    |> File.regular?
  end

  def lock_status(opts) do
    assert_git!()
    lock = opts[:lock]

    cond do
      lock_rev = get_lock_rev(lock, opts) ->
        File.cd!(opts[:checkout], fn ->
          %{origin: origin, rev: rev} = get_rev_info()
          if get_lock_repo(lock) == origin and lock_rev == rev do
            :ok
          else
            :mismatch
          end
        end)
      is_nil(lock) ->
        :mismatch
      true ->
        :outdated
    end
  end

  def equal?(opts1, opts2) do
    opts1[:git] == opts2[:git] and
      get_lock_opts(opts1) == get_lock_opts(opts2)
  end

  def managers(_opts) do
    []
  end

  def checkout(opts) do
    assert_git!()
    path = opts[:checkout]
    File.rm_rf!(path)
    File.mkdir_p!(path)
    File.cd!(path, fn ->
      git!("init --quiet")
      git!("--git-dir=.git remote add origin \"#{opts[:git]}\"")
      checkout(path, opts)
    end)
  end

  def update(opts) do
    assert_git!()
    path = opts[:checkout]
    File.cd! path, fn -> checkout(path, opts) end
  end

  defp checkout(_path, opts) do
    # Set configuration
    sparse_toggle(opts)
    update_origin(opts[:git])

    # Fetch external data
    command = IO.iodata_to_binary(["--git-dir=.git fetch --force --quiet",
                                   progress_switch(git_version()),
                                   tags_switch(opts[:tag])])
    git!(command)

    # Migrate the git repo
    rev = get_lock_rev(opts[:lock], opts) || get_opts_rev(opts)
    git!("--git-dir=.git checkout --quiet #{rev}")

    if opts[:submodules] do
      git!("--git-dir=.git submodule update --init --recursive")
    end

    # Get the new repo lock
    get_lock(opts)
  end

  defp sparse_opts(opts) do
    if opts[:sparse] do
      dest = Path.join(opts[:dest], opts[:sparse])
      Keyword.put(opts, :dest, dest)
    else
      opts
    end
  end

  defp sparse_toggle(opts) do
    cond do
      sparse = opts[:sparse] ->
        sparse_check(git_version())
        git!("--git-dir=.git config core.sparsecheckout true")
        File.write!(".git/info/sparse-checkout", sparse)
      File.exists?(".git/info/sparse-checkout") ->
        File.write!(".git/info/sparse-checkout", "*")
        git!("--git-dir=.git read-tree -mu HEAD")
        git!("--git-dir=.git config core.sparsecheckout false")
        File.rm(".git/info/sparse-checkout")
      true ->
        :ok
    end
  end

  defp sparse_check(version) do
    unless {1, 7, 0} <= version do
      version = version |> Tuple.to_list |> Enum.join(".")
      Mix.raise "Git >= 1.7.0 is required to use sparse checkout. " <>
                "You are running version #{version}"
    end
  end

  defp progress_switch(version) when {1, 7, 1} <= version, do: " --progress"
  defp progress_switch(_),                                 do: ""<commit_msg>Minor refactoring in Mix.SCM.Git<commit_after>defmodule Mix.SCM.Git do
  @behaviour Mix.SCM
  @moduledoc false

  def fetchable? do
    true
  end

  def format(opts) do
    opts[:git]
  end

  def format_lock(opts) do
    case opts[:lock] do
      {:git, _, lock_rev, lock_opts} ->
        lock = String.slice(lock_rev, 0, 7)
        case Enum.find_value [:branch, :ref, :tag], &List.keyfind(lock_opts, &1, 0) do
          {:ref, _}  -> lock <> " (ref)"
          {key, val} -> lock <> " (#{key}: #{val})"
          nil        -> lock
        end
      _ ->
        nil
    end
  end

  def accepts_options(_app, opts) do
    opts =
      opts
      |> Keyword.put(:checkout, opts[:dest])
      |> sparse_opts()

    cond do
      gh = opts[:github] ->
        opts
        |> Keyword.delete(:github)
        |> Keyword.put(:git, "https://github.com/#{gh}.git")
        |> validate_git_options
      opts[:git] ->
        opts
        |> validate_git_options
      true ->
        nil
    end
  end

  def checked_out?(opts) do
    # Are we inside a Git repository?
    opts[:checkout]
    |> Path.join(".git/HEAD")
    |> File.regular?
  end

  def lock_status(opts) do
    assert_git!()
    lock = opts[:lock]

    cond do
      lock_rev = get_lock_rev(lock, opts) ->
        File.cd!(opts[:checkout], fn ->
          %{origin: origin, rev: rev} = get_rev_info()
          if get_lock_repo(lock) == origin and lock_rev == rev do
            :ok
          else
            :mismatch
          end
        end)
      is_nil(lock) ->
        :mismatch
      true ->
        :outdated
    end
  end

  def equal?(opts1, opts2) do
    opts1[:git] == opts2[:git] and
      get_lock_opts(opts1) == get_lock_opts(opts2)
  end

  def managers(_opts) do
    []
  end

  def checkout(opts) do
    assert_git!()
    path = opts[:checkout]
    File.rm_rf!(path)
    File.mkdir_p!(path)
    File.cd!(path, fn ->
      git!("init --quiet")
      git!("--git-dir=.git remote add origin \"#{opts[:git]}\"")
      checkout(path, opts)
    end)
  end

  def update(opts) do
    assert_git!()
    path = opts[:checkout]
    File.cd! path, fn -> checkout(path, opts) end
  end

  defp checkout(_path, opts) do
    # Set configuration
    sparse_toggle(opts)
    update_origin(opts[:git])

    # Fetch external data
    [
      "--git-dir=.git fetch --force --quiet",
      progress_switch(git_version()),
      tags_switch(opts[:tag])
    ]
    |> IO.iodata_to_binary()
    |> git!()

    # Migrate the git repo
    rev = get_lock_rev(opts[:lock], opts) || get_opts_rev(opts)
    git!("--git-dir=.git checkout --quiet #{rev}")

    if opts[:submodules] do
      git!("--git-dir=.git submodule update --init --recursive")
    end

    # Get the new repo lock
    get_lock(opts)
  end

  defp sparse_opts(opts) do
    if opts[:sparse] do
      dest = Path.join(opts[:dest], opts[:sparse])
      Keyword.put(opts, :dest, dest)
    else
      opts
    end
  end

  defp sparse_toggle(opts) do
    cond do
      sparse = opts[:sparse] ->
        sparse_check(git_version())
        git!("--git-dir=.git config core.sparsecheckout true")
        File.write!(".git/info/sparse-checkout", sparse)
      File.exists?(".git/info/sparse-checkout") ->
        File.write!(".git/info/sparse-checkout", "*")
        git!("--git-dir=.git read-tree -mu HEAD")
        git!("--git-dir=.git config core.sparsecheckout false")
        File.rm(".git/info/sparse-checkout")
      true ->
        :ok
    end
  end

  defp sparse_check(version) do
    unless {1, 7, 0} <= version do
      version = version |> Tuple.to_list |> Enum.join(".")
      Mix.raise "Git >= 1.7.0 is required to use sparse checkout. " <>
                "You are running version #{version}"
    end
  end

  defp progress_switch(version) do
    if {1, 7, 1} <= version, do: " --progress", else: ""
  end
{'fraction_non_alphanumeric': 0.14689192674748516, 'fraction_numerical': 0.004900696414753675, 'mean_word_length': 2.0376028202115157, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 67, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3919652', 'n_tokens_mistral': 2749, 'n_tokens_neox': 2628, 'n_words': 619}