カピバラ好きなエンジニアブログ

興味ある技術とか検証した内容を赴くままに書いていきます。カピバラの可愛さこそ至高。

Embulkのプラグインをデフォルト以外の場所へインストールする

Embulkは必要なプラグインをインストールして使用するのは周知のことだと思いますが、そのときプラグインを普通にインストールするだけだと、デフォルトではログインユーザのユーザフォルダ配下にインストールされるようになっています。

Embulkを実行するユーザとログインユーザが一致していれば問題ないですが、専用のユーザで実行させたい場合、ログインユーザフォルダ配下にインストールされても権限の関係で読み込みができずエラーになることがあります。

なので、今回は全ユーザがアクセス可能な場所にインストールする方法を試したいと思います。

手順的には以下のURLの『Using plugin bundle』の部分になります。
github.com

実施作業

準備

Embulkのインストールは以前の記事で既にやっているので割愛します。
capybara-engineer.hatenablog.com

インストールができたら、プラグインをインストールするフォルダを適当な場所に作成し移動します。
f:id:live-your-life-dd18:20200709211811p:plain

プラグインインストール

以下のコマンドでbundleディレクトリとプラグイン管理用の初期ファイルが作成されます。
インストールしたプラグインはこのフォルダ配下に格納され、実行時にはこのbundleフォルダを指定して実行します。

# embulk mkbundle  .\[bundle名]

コマンドの実行結果は以下のようになります。
f:id:live-your-life-dd18:20200709212633p:plain

作成したbundleフォルダ配下には1つのファイルと2つのフォルダが作成されており、インストールするプラグインはこのGemfileを使用して指定します。
f:id:live-your-life-dd18:20200709212759p:plain

Gemfileの中身はこのようになっています。

source 'https://rubygems.org/'

# No versions are specified for 'embulk' to use the gem embedded in embulk.jar.
# Note that prerelease versions (e.g. "0.9.0.beta") do not match the statement.
# Specify the exact prerelease version (like '= 0.9.0.beta') for prereleases.
gem 'embulk'

#
# 1. Use following syntax to specify versions of plugins
#    to install this bundle directory:
#
#gem 'embulk-output-mysql'                     # the latest version
#gem 'embulk-input-baz', '= 0.2.0'             # specific version
#gem 'embulk-input-xyz', '~> 0.3.0'            # latest major version
#gem 'embulk-output-postgresql', '>= 0.1.0'    # newer than specific version
#
#gem 'embulk-output-awesome', git: 'https://github.com/you/embulk-output-awesome.git', branch: 'master'
#

#
# 2. When you modify this file, run following command to
#    install plugins:
#
#   $ cd this_directory
#   $ embulk bundle
#

#
# 3. Then you can use plugins with -b, --bundle BUNDLE_PATH command:
#
#   $ embulk guess -b path/to/this/directory  ...
#   $ embulk run -b path/to/this/directory  ...
#   $ embulk preview -b path/to/this/directory  ...
#

このファイルの中で『gem 'embulk'』と記載されている箇所があるので、その下にインストールしたいプラグインを同じように書きます。

今回は簡単に検証したいので、Filterプラグインを1つだけ追加します。

~省略~
gem 'embulk'
gem 'embulk-filter-column'
~省略~

プラグインはこちら
 出力するカラムにフィルターをかけて必要なカラムだけ出力するようにします。
github.com

Gemfileに追加出来たら以下のコマンドを実行します。
この時に作成したbundleフォルダに移動するのを忘れないでください。

# cd .\test_bundle\
# embulk bundle

結果はこのようになります。
embulk-filter-columnがインストールされていることがログからわかります。
f:id:live-your-life-dd18:20200709214107p:plain

Embulkサンプルファイル実行

では、インストールができたので実際に実行していきます。
実行は以前の記事を参考にして、Embulk標準で準備されているサンプルファイルを使用します。
capybara-engineer.hatenablog.com

以下のコマンドでサンプルファイルを作成します。

# cd ..
# embulk example ./example

ファイルがいくつか作成されます。
f:id:live-your-life-dd18:20200709214820p:plain

Embulkに読み込まれるseed.ymlファイルを以下のように書き換えます
内容としては、出力するカラムをidとaccountのみにフィルターします。

in:
  type: file
  path_prefix: 'C:\work\embulk_sample\.\example\csv\sample_'
filters:
  - type: column
    columns:
      - {name: id, type: long}
      - {name: account, type: long}
out:
  type: stdout

以下のコマンドを実行して定義ファイルを生成します。
この時『-b』オプションを指定して、インストールしたbundleフォルダを指定しておきます。

# embulk guess  ./example/seed.yml -o config.yml -b .\test_bundle

正常に終わるとconfigファイルが作成されます。

Java HotSpot(TM) Client VM warning: TieredCompilation is disabled in this release.
2020-07-09 13:02:58.276 +0000: Embulk v0.9.23
2020-07-09 13:02:59.401 +0000 [WARN] (main): DEPRECATION: JRuby org.jruby.embed.ScriptingContainer is directly injected.
2020-07-09 13:03:02.104 +0000 [INFO] (main): BUNDLE_GEMFILE is being set: "C:\work\embulk_sample\.\test_bundle\Gemfile"
2020-07-09 13:03:02.119 +0000 [INFO] (main): Gem's home and path are being cleared.
2020-07-09 13:03:03.604 +0000 [INFO] (main): Started Embulk v0.9.23
2020-07-09 13:03:03.713 +0000 [INFO] (0001:guess): Listing local files at directory 'C:\work\embulk_sample\.\example\csv' filtering filename by prefix 'sample_'
2020-07-09 13:03:03.713 +0000 [INFO] (0001:guess): "follow_symlinks" is set false. Note that symbolic links to directories are skipped.
2020-07-09 13:03:03.713 +0000 [INFO] (0001:guess): Loading files [C:\work\embulk_sample\.\example\csv\sample_01.csv.gz]
2020-07-09 13:03:03.729 +0000 [INFO] (0001:guess): Try to read 32,768 bytes from input source
2020-07-09 13:03:04.026 +0000 [INFO] (0001:guess): Loaded plugin embulk (0.9.23)
2020-07-09 13:03:04.041 +0000 [INFO] (0001:guess): Loaded plugin embulk (0.9.23)
2020-07-09 13:03:04.088 +0000 [INFO] (0001:guess): Loaded plugin embulk (0.9.23)
2020-07-09 13:03:04.119 +0000 [INFO] (0001:guess): Loaded plugin embulk (0.9.23)
in:
  type: file
  path_prefix: C:\work\embulk_sample\.\example\csv\sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: LF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    null_string: 'NULL'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: id, type: long}
    - {name: account, type: long}
    - {name: time, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: purchase, type: timestamp, format: '%Y%m%d'}
    - {name: comment, type: string}
filters:
- type: column
  columns:
  - {name: id, type: long}
  - {name: account, type: long}
out: {type: stdout}

Created 'config.yml' file.

configファイルが作成できたら、同じく『-b』オプションを付けて以下のコマンドを実行します。
うまくいけば正常終了して、特定のカラムのデータのみ出力されるはずです。

# embulk run .\config.yml -b .\test_bundle

指定したカラムのみが表示されたので、filter-columnのプラグインも正常に動作していました。
f:id:live-your-life-dd18:20200709220422p:plain

余談

ちなみに先ほどの実行コマンドに『-b』オプションを付けずに実行するとどうなるかというと、以下のようにそんなプラグインがないとエラーになります。

2020-07-09 13:06:23.463 +0000: Embulk v0.9.23
2020-07-09 13:06:24.870 +0000 [WARN] (main): DEPRECATION: JRuby org.jruby.embed.ScriptingContainer is directly injected.
2020-07-09 13:06:27.839 +0000 [INFO] (main): Gem's home and path are set by default: "C:\Users\Administrator\.embulk\lib\gems"
2020-07-09 13:06:28.854 +0000 [INFO] (main): Started Embulk v0.9.23
org.embulk.config.ConfigException: FilterPlugin 'column' is not found.
org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown filter plugin 'column'. embulk/filter/column.rb is not installed. Run 'embulk gem search -rd embulk-filter' command to find plugins.
        at org.embulk.plugin.PluginManager.buildPluginNotFoundException(PluginManager.java:75)
        at org.embulk.plugin.PluginManager.newPluginWithoutWrapper(PluginManager.java:61)
        at org.embulk.plugin.PluginManager.newPlugin(PluginManager.java:28)
        at org.embulk.spi.ExecSession.newPlugin(ExecSession.java:162)
        at org.embulk.spi.util.Filters.newFilterPlugins(Filters.java:31)
        at org.embulk.exec.BulkLoader$ProcessPluginSet.<init>(BulkLoader.java:429)
        at org.embulk.exec.BulkLoader.doRun(BulkLoader.java:502)
        at org.embulk.exec.BulkLoader.access$000(BulkLoader.java:35)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:353)
        at org.embulk.exec.BulkLoader$1.run(BulkLoader.java:350)
        at org.embulk.spi.Exec.doWith(Exec.java:22)
        at org.embulk.exec.BulkLoader.run(BulkLoader.java:350)
        at org.embulk.EmbulkEmbed.run(EmbulkEmbed.java:242)
        at org.embulk.EmbulkRunner.runInternal(EmbulkRunner.java:291)
        at org.embulk.EmbulkRunner.run(EmbulkRunner.java:155)
        at org.embulk.cli.EmbulkRun.runSubcommand(EmbulkRun.java:431)
        at org.embulk.cli.EmbulkRun.run(EmbulkRun.java:90)
        at org.embulk.cli.Main.main(Main.java:64)
        Suppressed: org.embulk.plugin.PluginSourceNotMatchException
                at org.embulk.plugin.InjectedPluginSource.newPlugin(InjectedPluginSource.java:53)
                at org.embulk.plugin.PluginManager.newPluginWithoutWrapper(PluginManager.java:49)
                ... 16 more
        Suppressed: org.embulk.plugin.PluginSourceNotMatchException
                at org.embulk.plugin.maven.MavenPluginSource.newPlugin(MavenPluginSource.java:68)
                at org.embulk.plugin.PluginManager.newPluginWithoutWrapper(PluginManager.java:49)
                ... 16 more
        Suppressed: org.embulk.plugin.PluginSourceNotMatchException: org.jruby.embed.InvokeFailedException: org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown filter plugin 'column'. embulk/filter/column.rb is not installed. Run 'embulk gem search -rd embulk-filter' command to find plugins.
                at org.embulk.jruby.JRubyPluginSource.newPlugin(JRubyPluginSource.java:63)
                at org.embulk.plugin.PluginManager.newPluginWithoutWrapper(PluginManager.java:56)
                ... 16 more
        Caused by: org.jruby.embed.InvokeFailedException: org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown filter plugin 'column'. embulk/filter/column.rb is not installed. Run 'embulk gem search -rd embulk-filter' command to find plugins.
                at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.call(EmbedRubyObjectAdapterImpl.java:322)
                at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.callMethod(EmbedRubyObjectAdapterImpl.java:159)
                at org.jruby.embed.ScriptingContainer.callMethod(ScriptingContainer.java:1459)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                at java.lang.reflect.Method.invoke(Unknown Source)
                at org.embulk.jruby.ScriptingContainerDelegateImpl.callMethod(ScriptingContainerDelegateImpl.java:634)
                at org.embulk.jruby.LazyScriptingContainerDelegate.callMethod(LazyScriptingContainerDelegate.java:129)
                at org.embulk.jruby.JRubyPluginSource.newPlugin(JRubyPluginSource.java:61)
                ... 17 more
        Caused by: org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown filter plugin 'column'. embulk/filter/column.rb is not installed. Run 'embulk gem search -rd embulk-filter' command to find plugins.
                at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
                at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
                at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
                at java.lang.reflect.Constructor.newInstance(Unknown Source)
                at org.jruby.javasupport.proxy.JavaProxyConstructor.newInstanceImpl(JavaProxyConstructor.java:119)
                at org.jruby.javasupport.proxy.JavaProxyConstructor.newInstance(JavaProxyConstructor.java:205)
                at org.jruby.javasupport.Java$JCreateMethod.call(Java.java:618)
                at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
                at org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:739)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:278)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:79)
                at org.jruby.java.proxies.ConcreteJavaProxy$InitializeMethod.call(ConcreteJavaProxy.java:48)
                at org.jruby.ir.runtime.IRRuntimeHelpers.instanceSuper(IRRuntimeHelpers.java:984)
                at org.jruby.ir.instructions.InstanceSuperInstr.interpret(InstanceSuperInstr.java:69)
                at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:360)
                at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:74)
                at org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:84)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:328)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:165)
                at org.jruby.RubyClass.newInstance(RubyClass.java:1001)
                at org.jruby.RubyClass$INVOKER$i$newInstance.call(RubyClass$INVOKER$i$newInstance.gen)
                at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
                at org.jruby.java.proxies.ConcreteJavaProxy$NewMethod.call(ConcreteJavaProxy.java:158)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:318)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:155)
                at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:315)
                at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:74)
                at org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:84)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:179)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:165)
                at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:200)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:318)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:155)
                at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:315)
                at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:74)
                at org.jruby.ir.interpreter.InterpreterEngine.interpret(InterpreterEngine.java:90)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:214)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:200)
                at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:208)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:338)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:183)
                at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:324)
                at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:74)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
                at org.jruby.RubyClass.finvoke(RubyClass.java:522)
                at org.jruby.RubyBasicObject.send19(RubyBasicObject.java:1684)
                at org.jruby.RubyBasicObject$INVOKER$i$send19.call(RubyBasicObject$INVOKER$i$send19.gen)
                at org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:278)
                at org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:79)
                at org.jruby.ir.instructions.CallBase.interpret(CallBase.java:432)
                at org.jruby.ir.interpreter.InterpreterEngine.processCall(InterpreterEngine.java:360)
                at org.jruby.ir.interpreter.StartupInterpreterEngine.interpret(StartupInterpreterEngine.java:74)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.INTERPRET_METHOD(MixedModeIRMethod.java:109)
                at org.jruby.internal.runtime.methods.MixedModeIRMethod.call(MixedModeIRMethod.java:95)
                at org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:174)
                at org.jruby.RubyClass.finvoke(RubyClass.java:899)
                at org.jruby.runtime.Helpers.invoke(Helpers.java:430)
                at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.callEachType(EmbedRubyObjectAdapterImpl.java:356)
                at org.jruby.embed.internal.EmbedRubyObjectAdapterImpl.call(EmbedRubyObjectAdapterImpl.java:309)
                ... 26 more

Error: FilterPlugin 'column' is not found.
org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown filter plugin 'column'. embulk/filter/column.rb is not installed. Run 'embulk gem search -rd embulk-filter' command to find plugins.

以下のコマンドを実行するとfilter-columnのプラグインはインストールされていないことがわかります。

# embulk gem list

出力内容の「Gem plugin path」にもありますが、デフォルトはログインユーザ(=実行ユーザ)のユーザフォルダ配下を参照していることがわかります。
f:id:live-your-life-dd18:20200709220757p:plain

感想及び所感

以上、Embulkのプラグインをデフォルトフォルダ以外の場所にインストールする方法をやってみました。
Embulkを使い始めた時は特に気にしていなかったですが、インストール先によってアクセス権がなくてエラーが発生して...というのがあったので調べて初めてこの機能の存在を知りました。
もっと早く気づけばよかったです。。