Embulkの設定ファイルをincludeで共有化する方法


## まとめ

* Embulkの設定ファイルの中で同じ設定をしている部分を別ファイルにすることができます。
* 別のファイルにする設定ファイルは、``_テンプレート名.yml.liquid``という名前にします。
* 別の設定ファイルは、設定ファイルと同じディレクトリが起点ディレクトリになります。
* 読み込む設定ファイルは、サブディレクトリを作ることはできますが、親ディレクトリを``..``を使って参照することはできません。(セキュリティに関する配慮)
* 読み込み時に変数を設定することもできます。
* include先のファイル名にハイフンは使えません。(理由は調査中)

## 動機

Embulkを利用する頻度が増えてくる場合、次のような問題が生じます。

* 同じ設定内容を、複数のYAMLファイルに記述しなければいけない。
* 設定ファイルが肥大化して管理するのが大変だ

この問題は、Embulkに搭載されているテンプレートエンジンLiquidの機能で解決することができます。この機能は**Embulk 0.7.7**から利用できます。

## ファイル構成

設定ファイルは次のような構成にします。

```
.
|-- commons                      # <-- 読み込む設定ファイルを置くディレクトリ
|   `-- _conf_include.yml.liquid # <-- 読み込まれる設定ファイル
`-- conf.yml.liquid              # <-- メインの設定ファイル
```

* 設定ファイルの拡張子は、必ず``yml.liquid``という名前にします。

## 設定例

通常の設定ファイルで読み込みしたい部分を``{% include 'テンプレート名' %}``のように記述します。

下記の例では、Embulkの設定ファイルで、``conf_include``を読み込みする例です。

```yaml
{% include 'commons/conf_include' %} # <<-- これが読み込みする設定ファイルの指定です。
out:
  type: stdout
```

別ファイルに分離した設定ファイルは、``_テンプレート名.yml.liquid``という名前にします。
上記の例では、テンプレートのファイル名は、``commons/_conf_include.yml.liquid``になります。

```yaml
in:
  type: file
  path_prefix: /private/tmp/sample/csv/sample_
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    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}
```

## 変数渡し

Liquidは変数を設定することができるので、データベースのコネクション情報は共通だが出力するテーブル名が違うという場合には、変数名を利用することもできます。

## assignを使って変数を定義する方法

```yaml
{% assign file_prefix = '/tmp/sample/csv/sample' %} # <-- 変数設定
{% include 'commons/conf_include' with file_prefix %} # <<-- これが読み込みする設定ファイルの指定です。
out:
  type: stdout
```

```yaml
in:
  type: file
  path_prefix: {{ file_prefix }} # <-- 変数の展開
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    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}
```

### include時に変数を指定

include時に分離した設定ファイルに変数を指定することもできるようです。
次の例では、``path_prefix``と``compress_type``という二つの変数を定義しています。

```yaml
{% include 'commons/conf_include',
   path_prefix: '/tmp/sample/csv/sample',
   compress_type: 'gzip'  %} # <<-- これが読み込みする設定ファイルの指定です。
out:
  type: stdout
```

```yaml
in:
  type: file
  path_prefix: {{ path_prefix }} # <-- path_prefix変数を展開
  decoders:
  - {type: {{ compress_type }}}  # <-- compress_type変数を展開
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    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}
```

## その他Liquid表記方法

### 日付をダイナミックに指定する方法

```yaml:conf.yml.liquid
{% capture today %}{{ 'now' | date: '%Y%m%d' }}{% endcapture %}
in:
  type: file
  path_prefix: /private/tmp/sample/csv/sample_{{ today }}
  decoders:
  - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    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}
out: {type: stdout}
```

## if文による設定読み込み例

[[Embulk] DBの接続情報とクエリを環境変数とLiquidを使って上手に分割する方法](http://qiita.com/hiroysato/items/861e3689eef430f5e723) をみてください。

こちらの記事も参考になります。
[【Embulk】使い方あれこれ](https://qiita.com/da-sugi/items/13d4ead19c86d783ebb4)

## 日付の計算方法

[EmbulkのLiquidで日付計算をする](https://qiita.com/reflet/items/23af6a57264f3e061bcc)が参考になります。

## TODO

以下のことが未解決です。だれか教えて下さい。

* 変数をハッシュで指定する方法
* パラメータをダイナミックに定義する方法(日付以外)

## 参考

~~本文では紹介しておりませんが、if文等も多分つかえるんじゃないかと思っています。ぜひ試してみてください。~~

* [Liquid documentation from Shopify](https://docs.shopify.com/themes/liquid-documentation/basics)
* [Liquid for Designers](https://github.com/Shopify/liquid/wiki/Liquid-for-Designers)
* [複数変数の利用方法](https://docs.shopify.com/themes/liquid-documentation/tags/theme-tags#include)