<commit_before>defmodule Mix.Tasks.Escriptize do
  use Mix.Task
  use Bitwise, only_operators: true

  @shortdoc "Generates an escript for the project"
  @recursive true

  @moduledoc ~S"""
  Generates an escript for the project.

  ## Command line options

  * `--force` - forces compilation regardless of modification times

  * `--no-compile` - skips compilation to .beam files

  ## Configuration

  The following option must be specified in your `mix.exs`:

  * `:escript_main_module` - the module to be invoked once the escript starts.
    The module must contain a function named `main/1` that will receive the
    command line arguments as binaries;

  The remaining options can be specified to further customize the escript:

  * `:escript_name` - the name of the generated escript.
     Defaults to app name;

  * `:escript_path` - the path to write the escript to.
     Defaults to app name;

  * `:escript_app` - the app to start with the escript.
     Defaults to app name. Set it to `nil` if no application should
     be started.

  * `:escript_embed_elixir` - if `true` embed elixir in the escript file.
     Defaults to `true`.

  * `:escript_embed_extra_apps` - embed additional Elixir applications.
     if `:escript_embed_elixir` is `true`.
     Defaults to `[]`.

  * `:escript_shebang` - shebang interpreter directive used to execute the escript.
     Defaults to "#! /usr/bin/env escript\n".

  * `:escript_comment` - comment line to follow shebang directive in the escript.
     Defaults to "%%\n"

  * `:escript_emu_args` - emulator arguments to embed in the escript file.
     Defaults to "%%!\n".

  """
  def run(args) do
    {opts, _, _} = OptionParser.parse(args, switches: [force: :boolean, no_compile: :boolean])

    # Require the project to be available
    Mix.Project.get!

    unless opts[:no_compile] do
      Mix.Task.run :compile, args
    end

    escriptize(Mix.Project.config, opts[:force])
  end

  defp escriptize(project, force) do
    script_name  = project[:escript_name] || project[:app]
    filename     = project[:escript_path] || atom_to_binary(script_name)
    main         = project[:escript_main_module]
    embed        = Keyword.get(project, :escript_embed_elixir, true)
    app          = Keyword.get(project, :escript_app, project[:app])
    files        = project_files()

    cond do
      !script_name ->
        raise Mix.Error, message: "Could not generate escript, no name given, " <>
          "set :escript_name or :app in the project settings"

      !main ->
        raise Mix.Error, message: "Could not generate escript, please set :escript_main_module " <>
          "in your project configuration to a module that implements main/1"

      force || Mix.Utils.stale?(files, [filename]) ->
        tuples = gen_main(script_name, main, app) ++ to_tuples(files)
        tuples = tuples ++ deps_tuples()

        if embed do
          extra_apps = project[:escript_embed_extra_apps] || []
          tuples = Enum.reduce [:elixir|extra_apps], tuples, fn(app, acc) ->
            app_tuples(app) ++ acc
          end
        end

        # We might get duplicate tuples in umbrella projects from applications<commit_msg>Added check to raise an error if escript_main_module cannot be loaded<commit_after>defmodule Mix.Tasks.Escriptize do
  use Mix.Task
  use Bitwise, only_operators: true

  @shortdoc "Generates an escript for the project"
  @recursive true

  @moduledoc ~S"""
  Generates an escript for the project.

  ## Command line options

  * `--force` - forces compilation regardless of modification times

  * `--no-compile` - skips compilation to .beam files

  ## Configuration

  The following option must be specified in your `mix.exs`:

  * `:escript_main_module` - the module to be invoked once the escript starts.
    The module must contain a function named `main/1` that will receive the
    command line arguments as binaries;

  The remaining options can be specified to further customize the escript:

  * `:escript_name` - the name of the generated escript.
     Defaults to app name;

  * `:escript_path` - the path to write the escript to.
     Defaults to app name;

  * `:escript_app` - the app to start with the escript.
     Defaults to app name. Set it to `nil` if no application should
     be started.

  * `:escript_embed_elixir` - if `true` embed elixir in the escript file.
     Defaults to `true`.

  * `:escript_embed_extra_apps` - embed additional Elixir applications.
     if `:escript_embed_elixir` is `true`.
     Defaults to `[]`.

  * `:escript_shebang` - shebang interpreter directive used to execute the escript.
     Defaults to "#! /usr/bin/env escript\n".

  * `:escript_comment` - comment line to follow shebang directive in the escript.
     Defaults to "%%\n"

  * `:escript_emu_args` - emulator arguments to embed in the escript file.
     Defaults to "%%!\n".

  """
  def run(args) do
    {opts, _, _} = OptionParser.parse(args, switches: [force: :boolean, no_compile: :boolean])

    # Require the project to be available
    Mix.Project.get!

    unless opts[:no_compile] do
      Mix.Task.run :compile, args
    end

    escriptize(Mix.Project.config, opts[:force])
  end

  defp escriptize(project, force) do
    script_name  = project[:escript_name] || project[:app]
    filename     = project[:escript_path] || atom_to_binary(script_name)
    main         = project[:escript_main_module]
    embed        = Keyword.get(project, :escript_embed_elixir, true)
    app          = Keyword.get(project, :escript_app, project[:app])
    files        = project_files()

    cond do
      !script_name ->
        raise Mix.Error, message: "Could not generate escript, no name given, " <>
          "set :escript_name or :app in the project settings"

      !main or !Code.ensure_loaded?(main)->
        raise Mix.Error, message: "Could not generate escript, please set :escript_main_module " <>
          "in your project configuration to a module that implements main/1"

      force || Mix.Utils.stale?(files, [filename]) ->
        tuples = gen_main(script_name, main, app) ++ to_tuples(files)
        tuples = tuples ++ deps_tuples()

        if embed do
          extra_apps = project[:escript_embed_extra_apps] || []
          tuples = Enum.reduce [:elixir|extra_apps], tuples, fn(app, acc) ->
            app_tuples(app) ++ acc
          end
        end

        # We might get duplicate tuples in umbrella projects from applications
{'fraction_non_alphanumeric': 0.09682416731216112, 'fraction_numerical': 0.0006196746707978311, 'mean_word_length': 2.958307786633967, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, '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': '5507443', 'n_tokens_mistral': 2021, 'n_tokens_neox': 1923, 'n_words': 658}