LoginSignup
2
0

More than 3 years have passed since last update.

Timex利用コードをコマンド化すると実行時エラーが出る 〜オマージュ〜 (Elixir)

Last updated at Posted at 2020-01-12

(この記事は @piacerex さんのTimex利用コードをコマンド化すると実行時エラーが出るのオマージュです)

今回は、Timexを使うコードを、escriptでコマンド化した際、実行時エラーが出るのを回避する方法を解説 :alarm_clock:

escriptでのコマンド化についても、軽く解説します

私の記事ですが、Slack Workflowの申請内容を一覧(CSV)にする(with Elixir) を書いているときに同じエラーが発生しましたので回避策を個別にまとめておきます

> elixir -v
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Elixir 1.9.4 (compiled with Erlang/OTP 22)

escriptでElixirコードをコマンド化

まず、メインモジュールにmain()関数を追加します

コンソールから呼び出したときは、この関数が呼ばれます

lib/sample.ex
defmodule Sample do
  def main(_args \\ []), do: IO.puts("Hello, world!")
end

mix.exsの「def project」配下にescript利用を追記し、「defp escript」にメインモジュールのモジュール名を追加します(ここではElixirプロジェクト名を「sample」としています(> mix new sample で作成))

mix.exs
defmodule Sample.MixProject do
  use Mix.Project

  def project do
    [
    
      escript: escript(), 
      deps: deps()
    ]
  end

  defp escript() do
    [main_module: Sample]
  end

escriptでコマンド化します

> mix escript.build

コンソールでの実行は、以下の通りです

> escript sample

Windows以外だと、以下でも実行できます

% chmod 755 ./sample
% ./sample

Timex利用コードのコマンド化で実行時エラーが出る

Timexモジュールを導入します

mix.exs
defmodule Sample.Mixfile do
 …
  defp deps do
 …
    {:timex, "~> 3.6"}, 
 …
> mix deps.get

せっかくなのでTimexを使ってみましょう

lib/sample.ex
defmodule Sample do
  def main(_args \\ []),
    do:
      Timex.now()
      |> Timex.local()
      |> Timex.format!("{YYYY}-{0M}-{0D} {h24}:{0m}:{0s}")
      |> IO.puts()
end

コマンド化して実行すると、以下エラーが出ます

> mix escript.build
> escript sample

13:41:51.198 [info]  Application tzdata exited: exited in: Tzdata.App.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (MatchError) no match of right hand side value: {:error, {:shutdown, {:failed_to_start_child, Tzdata.EtsHolder, {%ArgumentError{message: "unknown application: :tzdata"}, [{Application, :app_dir, 1, [file: 'lib/application.ex', line: 699]}, {Application, :app_dir, 2, [file: 'lib/application.ex', line: 726]}, {Tzdata.EtsHolder, :release_dir, 0, [file: 'lib/tzdata/ets_holder.ex', line: 123]}, {Tzdata.EtsHolder, :make_sure_a_release_dir_exists, 0, [file: 'lib/tzdata/ets_holder.ex', line: 101]}, {Tzdata.EtsHolder, :make_sure_a_release_is_on_file, 0, [file: 'lib/tzdata/ets_holder.ex', line: 77]}, {Tzdata.EtsHolder, :init, 1, [file: 'lib/tzdata/ets_holder.ex', line: 16]}, {:gen_server, :init_it, 2, [file: 'gen_server.erl', line: 374]}, {:gen_server, :init_it, 6, [file: 'gen_server.erl', line: 342]}]}}}}
            (tzdata) lib/tzdata/tzdata_app.ex:17: Tzdata.App.start/2
            (kernel) application_master.erl:277: :application_master.start_it_old/4

これを回避するには、tzdataモジュールに.etsファイルの場所をお知らせしておきます(元ネタはこちら

Timextzdataに依存しています)

> iex -S mix
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex> Tzdata.Util.data_dir
"c:/Users/torifuku/elixirProjects/sample/_build/dev/lib/tzdata/priv"

Tzdata.Util.data_dirで出力された内容をconfig/config.exs(このファイルがなければ作ります)に設定します

config/config.exs
use Mix.Config

config :tzdata,
       :data_dir,
       "c:/Users/torifuku/elixirProjects/sample/_build/dev/lib/tzdata/priv"

ビルドし直して、実行すると、エラーが出なくなります :grinning:

> mix escript.build
> escript sample
2020-01-12 15:58:19

一応これで解決はしますが、スマートじゃないのでもっとよい方法がありましたらコメントいただけますとうれしいです:bow:

補足

  • {:tzdata, "== 0.1.8", override: true}でバージョン固定するやり方は、Elixirが1.9.4だとコンパイルエラーがでていました
== Compilation error in file lib/tzdata/period_builder.ex ==
** (CompileError) lib/tzdata/period_builder.ex:60: undefined function from_standard_time_year/0
    (elixir) src/elixir_locals.erl:108: :elixir_locals."-ensure_no_undefined_local/3-lc$^0/1-0-"/2
    (elixir) src/elixir_locals.erl:109: anonymous fn/3 in :elixir_locals.ensure_no_undefined_local/3
    (stdlib) erl_eval.erl:680: :erl_eval.do_apply/6
could not compile dependency :tzdata, "mix compile" failed. You can recompile this dependency with "mix deps.compile tzdata", update it with "mix deps.update tzdata" or clean it with "mix deps.clean tzdata"
  • 参考にさせていただいた @piacerex さんの記事は2016年のアドベントカレンダーですものね
  • そんな前からElixirに注目されていたということに改めて敬意を表します
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0