escript가 번거롭다면 mix run으로 인자를 넘겨 실행하기

2 minute read

어떤 상황에서 이런 걸 고민하게 됐는가?

인용구를 일정 주기로 트윗하는 tbot-800.ex 프로젝트 진행할 때, 필요하다. 두 단계로 이뤄진다. 인용구를 트윗할 수 있게 가공하고 그 가공한 인용구를 일정 주기로 트윗하게 된다. 인용구를 가공하는 단계는 커맨드라인으로 인자를 넘겨 결과물을 만들어내면 된다. 이런 커맨드라인 툴을 만들어야 한다면 escript가 좋은 방법이다. 하지만 바이너리만 배포하는 상황이 아니라 소스코드가 있는 상황에서 인자를 넘겨 실행하는 거라 번거롭다고 생각했다.

일단 escript를 안 쓸 거지만 어떤 건지는 알아보자.

escript 는 뭔가?

An escript is an executable that can be invoked from the command line. An escript can run on any machine that has Erlang/OTP installed and by default does not require Elixir to be installed, as Elixir is embedded as part of the escript.

mix escript.build — Mix v1.16.0-dev - hexdocs.pm

커맨드라인에서 호출할 수 있는 실행 파일이다. erlang 런타임을 포함하는 게 아니라서 erlang이 설치되어 있어야 한다.

escript: [main_module: MyApp.CLI]

mix.exs 파일에 escript 엔트리 포인트(entry point)가 될 모듈을 정의해 줘야 한다. 그 후에 mix escript.build 를 호출하면 실행할 수 있는 escript 파일이 만들어진다.

인용구를 빌드에 escript 를 사용한다면 mix escript.build 를 호출해서 escript 파일을 만들고 이후에 인자를 넘겨서 호출해야 한다.

mix run -e 태스크(task)로 엔트리 포인트 함수를 인자와 함께 호출

mix run 태스크는 elixir 애플리케이션을 실행한다. 특정 코드를 평가(evaluate)할 수 있는 옵션이 있다. 이걸 사용하면 escript 를 사용하지 않고 커맨드라인에서 인자와 함께 호출할 수 있다.

Code to be executed can also be passed inline with the -e option:

mix run -e “DbUtils.delete_old_records()” – arg1 arg2 arg3

In both cases, the command-line arguments for the script or expression are available in System.argv/0. This mirror the command line interface in the elixir executable.

mix run — Mix v1.16.0-dev - hexdocs.pm

-e 옵션을 사용해서 엔트리 포인트 함수를 실행하고 -- 문자 뒤에 인자를 넘겨주면 된다.

Guideline 10:

The first – argument that is not an option-argument should be accepted as a delimiter indicating the end of options. Any following arguments should be treated as operands, even if they begin with the ’-’ character.

Utility Conventions - pubs.opengroup.org

-- 구분자(delimiter)는 옵션이 끝나고 뒤에는 인자가 시작된다는 걸 알려준다. 주로 옵션으로 취급하는 걸 막으려고 사용한다.

사용 예

sp:tbot-800.ex 프로젝트에서 사용했다. 우선 엔트리 포인트 함수 구현이 필요하다.

defmodule Builder do
  def run() do
    {args, []} =
      OptionParser.parse!(System.argv(),
        strict: [
          source_path: :string,
          twitter_account: :string,
          html_host_base_url: :string,
          ga4_measurement_id: :string,
          output_tweet_items_path: :string,
          output_html_root_dir: :string
        ]
      )

    build(
      source_loader_func(args[:source_path]),
      args[:twitter_account],
      args[:html_host_base_url],
      args[:ga4_measurement_id],
      tweet_items_writer_func(args[:output_tweet_items_path]),
      html_root_dir_maker_func(args[:output_html_root_dir]),
      html_file_writer_func(args[:output_html_root_dir])
    )
  end
end

mix run -e 로 실행할 함수 호출 뒤에 넘긴 인자는 System.argv() 함수로 가져올 수 있다. 해당 인자를 OptionParser 모듈을 사용해 파싱해서 사용한다.

이제 mix run 태스크로 실행하면 된다.

mix run -e "Builder.run" -- \
    --source-path $1\
    --twitter-account $2\
    --html-host-base-url $3\
    --ga4-measurement-id $4\
    --output-tweet-items-path $5\
    --output-html-root-dir $6

OptionParser 모듈로 인자를 파싱하기 때문에 옵션 이름을 붙일 수 있다. script/quote-build 스크립트를 만들어서 쉽게 호출할 수 있게 했다. 인자 개수는 여전하지만.

링크