embulk 0.7.4-java → 0.7.5-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +7 -0
  4. data/build.gradle +3 -2
  5. data/embulk-core/src/main/java/org/embulk/EmbulkEmbed.java +1 -1
  6. data/embulk-core/src/main/java/org/embulk/config/CommitReport.java +3 -0
  7. data/embulk-core/src/main/java/org/embulk/config/ConfigDiff.java +3 -0
  8. data/embulk-core/src/main/java/org/embulk/config/ConfigSource.java +3 -0
  9. data/embulk-core/src/main/java/org/embulk/config/DataSource.java +2 -0
  10. data/embulk-core/src/main/java/org/embulk/config/DataSourceImpl.java +12 -0
  11. data/embulk-core/src/main/java/org/embulk/config/TaskReport.java +3 -0
  12. data/embulk-core/src/main/java/org/embulk/config/TaskSource.java +3 -0
  13. data/embulk-core/src/main/java/org/embulk/exec/ConfigurableGuessInputPlugin.java +9 -0
  14. data/embulk-core/src/main/java/org/embulk/exec/GuessExecutor.java +11 -5
  15. data/embulk-core/src/main/java/org/embulk/jruby/JRubyScriptingModule.java +0 -1
  16. data/embulk-core/src/main/java/org/embulk/spi/FileInputRunner.java +8 -2
  17. data/embulk-core/src/main/java/org/embulk/spi/time/Timestamp.java +5 -5
  18. data/embulk-core/src/test/java/org/embulk/spi/util/TestLineDecoder.java +125 -20
  19. data/embulk-docs/src/index.rst +4 -0
  20. data/embulk-docs/src/recipe/scheduled-csv-load-to-elasticsearch-kibana4.rst +7 -0
  21. data/embulk-docs/src/release.rst +2 -0
  22. data/embulk-docs/src/release/release-0.6.27.rst +11 -0
  23. data/embulk-docs/src/release/release-0.7.5.rst +22 -0
  24. data/embulk-standards/src/main/java/org/embulk/standards/CsvParserPlugin.java +3 -4
  25. data/embulk-standards/src/main/java/org/embulk/standards/CsvTokenizer.java +13 -4
  26. data/lib/embulk.rb +4 -18
  27. data/lib/embulk/command/embulk_new_plugin.rb +2 -2
  28. data/lib/embulk/command/embulk_run.rb +5 -3
  29. data/lib/embulk/command/embulk_selfupdate.rb +3 -2
  30. data/lib/embulk/data/new/gitignore.erb +4 -0
  31. data/lib/embulk/data/new/java/decoder.java.erb +2 -2
  32. data/lib/embulk/data/new/java/encoder.java.erb +2 -2
  33. data/lib/embulk/data/new/java/file_input.java.erb +2 -2
  34. data/lib/embulk/data/new/java/file_output.java.erb +2 -2
  35. data/lib/embulk/data/new/java/filter.java.erb +2 -2
  36. data/lib/embulk/data/new/java/formatter.java.erb +2 -2
  37. data/lib/embulk/data/new/java/input.java.erb +2 -2
  38. data/lib/embulk/data/new/java/output.java.erb +2 -2
  39. data/lib/embulk/data/new/java/parser.java.erb +2 -2
  40. data/lib/embulk/data/package_data.rb +10 -5
  41. data/lib/embulk/guess/csv.rb +17 -1
  42. data/lib/embulk/logger.rb +2 -2
  43. data/lib/embulk/runner.rb +1 -1
  44. data/lib/embulk/version.rb +1 -1
  45. metadata +7 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a30e0a1ff4c4748f58b0539ec4c6b9e47acb850b
4
- data.tar.gz: 3b6ca27d414f7c07be5d202dce02dc633d0f4438
3
+ metadata.gz: 63f5bc3b3bb2ba976677b032b93b0cb74d42a320
4
+ data.tar.gz: a0e9978b430cbca4901d709691fabbb5950981eb
5
5
  SHA512:
6
- metadata.gz: 16685804e873f6982886ada5f52f3dfb28b52de7adb98da4db8dcc42f09895c85e09235f02bf21d4413ebd0c60d9aa066d3213ae11802b00cb8b9e17e10fe3ad
7
- data.tar.gz: 6a4f2599c7855ad4db74f7e4b91335689820062d3a098a21411e81756d43bd52d329646c4b656bcbca240dd64704c716d5b7bb9cedba0c7fefc23736695e0d4c
6
+ metadata.gz: 56244b996db3d9381cbf9ef601458f361a36faa607f804ade930b41a489070cf968e61a9084a9841ab9d5954c785adbda6f68b388662b187da253b5802cd1460
7
+ data.tar.gz: 5fa872f8a6f9485e639831ae099429c8e47697638cd746647befc88a5bbe2d07ac3849b77d514b9dcd2621d0811c0e074f33385b61cf15a892c4bca797cc727f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- embulk (0.7.0)
4
+ embulk (0.7.4)
5
5
  jruby-jars (= 9.0.0.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -129,6 +129,13 @@ Following command updates embulk itself to the latest released version.
129
129
  embulk selfupdate
130
130
  ```
131
131
 
132
+ Following command updates embulk itself to the specific released version.
133
+
134
+ ```sh
135
+ embulk selfupdate x.y.z
136
+ ```
137
+
138
+
132
139
  ## Embulk Development
133
140
 
134
141
  ### Build
data/build.gradle CHANGED
@@ -16,7 +16,7 @@ def release_projects = [project(":embulk-core"), project(":embulk-standards")]
16
16
 
17
17
  allprojects {
18
18
  group = 'org.embulk'
19
- version = '0.7.4'
19
+ version = '0.7.5'
20
20
 
21
21
  ext {
22
22
  jrubyVersion = '9.0.0.0'
@@ -88,10 +88,11 @@ subprojects {
88
88
  jcenter()
89
89
  }
90
90
 
91
- compileJava.options.encoding = 'UTF-8' // source encoding
92
91
  sourceCompatibility = 1.7
93
92
  targetCompatibility = 1.7
94
93
 
94
+ def defaultEncoding = 'UTF-8'
95
+ [compileJava, compileTestJava]*.options*.encoding = defaultEncoding
95
96
  dependencies {
96
97
  testCompile 'junit:junit:4.12'
97
98
  }
@@ -224,7 +224,7 @@ public class EmbulkEmbed
224
224
 
225
225
  private ExecSession newExecSession(ConfigSource config)
226
226
  {
227
- ConfigSource execConfig = config.deepCopy().getNestedOrSetEmpty("exec");
227
+ ConfigSource execConfig = config.deepCopy().getNestedOrGetEmpty("exec");
228
228
  return ExecSession.builder(injector).fromExecConfig(execConfig).build();
229
229
  }
230
230
 
@@ -13,6 +13,9 @@ public interface CommitReport
13
13
  @Override
14
14
  CommitReport getNestedOrSetEmpty(String attrName);
15
15
 
16
+ @Override
17
+ CommitReport getNestedOrGetEmpty(String attrName);
18
+
16
19
  @Override
17
20
  CommitReport set(String attrName, Object v);
18
21
 
@@ -9,6 +9,9 @@ public interface ConfigDiff
9
9
  @Override
10
10
  ConfigDiff getNestedOrSetEmpty(String attrName);
11
11
 
12
+ @Override
13
+ ConfigDiff getNestedOrGetEmpty(String attrName);
14
+
12
15
  @Override
13
16
  ConfigDiff set(String attrName, Object v);
14
17
 
@@ -11,6 +11,9 @@ public interface ConfigSource
11
11
  @Override
12
12
  ConfigSource getNestedOrSetEmpty(String attrName);
13
13
 
14
+ @Override
15
+ ConfigSource getNestedOrGetEmpty(String attrName);
16
+
14
17
  @Override
15
18
  ConfigSource set(String attrName, Object v);
16
19
 
@@ -23,6 +23,8 @@ public interface DataSource
23
23
 
24
24
  DataSource getNestedOrSetEmpty(String attrName);
25
25
 
26
+ DataSource getNestedOrGetEmpty(String attrName);
27
+
26
28
  DataSource set(String attrName, Object v);
27
29
 
28
30
  DataSource setNested(String attrName, DataSource v);
@@ -114,6 +114,18 @@ public class DataSourceImpl
114
114
  return newInstance(model, (ObjectNode) json);
115
115
  }
116
116
 
117
+ @Override
118
+ public DataSourceImpl getNestedOrGetEmpty(String attrName)
119
+ {
120
+ JsonNode json = data.get(attrName);
121
+ if (json == null) {
122
+ json = data.objectNode();
123
+ } else if (!json.isObject()) {
124
+ throw new ConfigException("Attribute "+attrName+" must be an object");
125
+ }
126
+ return newInstance(model, (ObjectNode) json);
127
+ }
128
+
117
129
  @Override
118
130
  public DataSourceImpl set(String attrName, Object v)
119
131
  {
@@ -9,6 +9,9 @@ public interface TaskReport
9
9
  @Override
10
10
  TaskReport getNestedOrSetEmpty(String attrName);
11
11
 
12
+ @Override
13
+ TaskReport getNestedOrGetEmpty(String attrName);
14
+
12
15
  @Override
13
16
  TaskReport set(String attrName, Object v);
14
17
 
@@ -11,6 +11,9 @@ public interface TaskSource
11
11
  @Override
12
12
  TaskSource getNestedOrSetEmpty(String attrName);
13
13
 
14
+ @Override
15
+ TaskSource getNestedOrGetEmpty(String attrName);
16
+
14
17
  @Override
15
18
  TaskSource set(String attrName, Object v);
16
19
 
@@ -0,0 +1,9 @@
1
+ package org.embulk.exec;
2
+
3
+ import org.embulk.config.ConfigSource;
4
+ import org.embulk.config.ConfigDiff;
5
+
6
+ public interface ConfigurableGuessInputPlugin
7
+ {
8
+ ConfigDiff guess(ConfigSource execConfig, ConfigSource config);
9
+ }
@@ -98,15 +98,21 @@ public class GuessExecutor
98
98
  private ConfigDiff doGuess(ConfigSource config)
99
99
  {
100
100
  ConfigSource inputConfig = config.getNested("in");
101
+ ConfigSource execConfig = config.getNestedOrGetEmpty("exec");
101
102
 
102
103
  InputPlugin input = newInputPlugin(inputConfig);
103
104
 
104
105
  ConfigDiff inputGuessed;
105
- try {
106
- inputGuessed = input.guess(inputConfig);
107
- } catch (AbstractMethodError ex) {
108
- // for backward compatibility with embulk v0.4 interface
109
- throw new UnsupportedOperationException(input.getClass().getSimpleName()+".guess(ConfigSource) is not implemented. This input plugin does not support guessing.");
106
+ if (input instanceof ConfigurableGuessInputPlugin) {
107
+ inputGuessed = ((ConfigurableGuessInputPlugin) input).guess(execConfig, inputConfig);
108
+ }
109
+ else {
110
+ try {
111
+ inputGuessed = input.guess(inputConfig);
112
+ } catch (AbstractMethodError ex) {
113
+ // for backward compatibility with embulk v0.4 interface
114
+ throw new UnsupportedOperationException(input.getClass().getSimpleName()+".guess(ConfigSource) is not implemented. This input plugin does not support guessing.");
115
+ }
110
116
  }
111
117
 
112
118
  ConfigDiff wrapped = Exec.newConfigDiff();
@@ -62,7 +62,6 @@ public class JRubyScriptingModule
62
62
  {
63
63
  LocalContextScope scope = (useGlobalRubyRuntime ? LocalContextScope.SINGLETON : LocalContextScope.SINGLETHREAD);
64
64
  ScriptingContainer jruby = new ScriptingContainer(scope);
65
- jruby.setCompatVersion(CompatVersion.RUBY1_9);
66
65
 
67
66
  // Search embulk/java/bootstrap.rb from a $LOAD_PATH.
68
67
  // $LOAD_PATH is set by lib/embulk/command/embulk_run.rb if Embulk starts
@@ -14,10 +14,11 @@ import org.embulk.plugin.compat.PluginWrappers;
14
14
  import org.embulk.spi.util.Decoders;
15
15
  import org.embulk.exec.GuessExecutor;
16
16
  import org.embulk.exec.SamplingParserPlugin;
17
+ import org.embulk.exec.ConfigurableGuessInputPlugin;
17
18
  import org.embulk.exec.NoSampleException;
18
19
 
19
20
  public class FileInputRunner
20
- implements InputPlugin
21
+ implements InputPlugin, ConfigurableGuessInputPlugin
21
22
  {
22
23
  private final FileInputPlugin fileInputPlugin;
23
24
 
@@ -75,6 +76,11 @@ public class FileInputRunner
75
76
 
76
77
  @Override
77
78
  public ConfigDiff guess(ConfigSource config)
79
+ {
80
+ return guess(Exec.newConfigSource(), config);
81
+ }
82
+
83
+ public ConfigDiff guess(ConfigSource execConfig, ConfigSource config)
78
84
  {
79
85
  Buffer sample = SamplingParserPlugin.runFileInputSampling(this, config);
80
86
  if (sample.limit() == 0) {
@@ -82,7 +88,7 @@ public class FileInputRunner
82
88
  }
83
89
 
84
90
  GuessExecutor guessExecutor = Exec.getInjector().getInstance(GuessExecutor.class);
85
- return guessExecutor.guessParserConfig(sample, config, Exec.session().getSessionExecConfig());
91
+ return guessExecutor.guessParserConfig(sample, config, execConfig);
86
92
  }
87
93
 
88
94
  private class RunnerControl
@@ -11,10 +11,10 @@ import org.jruby.RubyTime;
11
11
  public class Timestamp
12
12
  implements Comparable<Timestamp>
13
13
  {
14
- private final static DateTimeFormatter TO_STRING_FORMATTER_SECONDS = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss z").withZoneUTC();
15
- private final static DateTimeFormatter TO_STRING_FORMATTER_MILLIS = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS z").withZoneUTC();
14
+ private final static DateTimeFormatter TO_STRING_FORMATTER_SECONDS = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss ").withZoneUTC();
15
+ private final static DateTimeFormatter TO_STRING_FORMATTER_MILLIS = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS ").withZoneUTC();
16
16
  private final static DateTimeFormatter TO_STRING_FORMATTER_CUSTOM = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss").withZoneUTC();
17
- private static final Pattern FROM_STRING_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})(?:\\.(\\d{1,9}))? UTC");
17
+ private static final Pattern FROM_STRING_PATTERN = Pattern.compile("(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2})(?:\\.(\\d{1,9}))? (?:UTC|\\+?00\\:?00)");
18
18
 
19
19
  private final long seconds;
20
20
  private final int nano;
@@ -107,10 +107,10 @@ public class Timestamp
107
107
  public String toString()
108
108
  {
109
109
  if (nano == 0) {
110
- return TO_STRING_FORMATTER_SECONDS.print(getEpochSecond() * 1000);
110
+ return TO_STRING_FORMATTER_SECONDS.print(getEpochSecond() * 1000) + "UTC";
111
111
 
112
112
  } else if (nano % 1000000 == 0) {
113
- return TO_STRING_FORMATTER_MILLIS.print(toEpochMilli());
113
+ return TO_STRING_FORMATTER_MILLIS.print(toEpochMilli()) + "UTC";
114
114
 
115
115
  } else {
116
116
  StringBuffer sb = new StringBuffer();
@@ -4,6 +4,7 @@ import java.util.List;
4
4
  import java.util.ArrayList;
5
5
  import java.nio.ByteBuffer;
6
6
  import java.nio.charset.Charset;
7
+ import java.nio.charset.StandardCharsets;
7
8
  import java.nio.charset.UnsupportedCharsetException;
8
9
  import com.google.common.collect.ImmutableList;
9
10
  import org.junit.Rule;
@@ -26,7 +27,7 @@ public class TestLineDecoder
26
27
  {
27
28
  ConfigSource config = Exec.newConfigSource();
28
29
  LineDecoder.DecoderTask task = config.loadConfig(LineDecoder.DecoderTask.class);
29
- assertEquals(Charset.forName("utf-8"), task.getCharset());
30
+ assertEquals(StandardCharsets.UTF_8, task.getCharset());
30
31
  assertEquals(Newline.CRLF, task.getNewline());
31
32
  }
32
33
 
@@ -37,22 +38,22 @@ public class TestLineDecoder
37
38
  .set("charset", "utf-16")
38
39
  .set("newline", "CRLF");
39
40
  LineDecoder.DecoderTask task = config.loadConfig(LineDecoder.DecoderTask.class);
40
- assertEquals(Charset.forName("utf-16"), task.getCharset());
41
+ assertEquals(StandardCharsets.UTF_16, task.getCharset());
41
42
  assertEquals(Newline.CRLF, task.getNewline());
42
43
  }
43
44
 
44
- private static LineDecoder.DecoderTask getExampleConfig()
45
+ private static LineDecoder.DecoderTask getExampleConfig(Charset charset, Newline newline)
45
46
  {
46
47
  ConfigSource config = Exec.newConfigSource()
47
- .set("charset", "utf-8")
48
- .set("newline", "LF");
48
+ .set("charset", charset)
49
+ .set("newline", newline);
49
50
  return config.loadConfig(LineDecoder.DecoderTask.class);
50
51
  }
51
52
 
52
53
  private static LineDecoder newDecoder(Charset charset, Newline newline, List<Buffer> buffers)
53
54
  {
54
55
  ListFileInput input = new ListFileInput(ImmutableList.of(buffers));
55
- return new LineDecoder(input, getExampleConfig());
56
+ return new LineDecoder(input, getExampleConfig(charset, newline));
56
57
  }
57
58
 
58
59
  private static List<String> doDecode(Charset charset, Newline newline, List<Buffer> buffers)
@@ -70,10 +71,8 @@ public class TestLineDecoder
70
71
  return builder.build();
71
72
  }
72
73
 
73
- private static List<Buffer> bufferList(String charsetName, String... sources) throws UnsupportedCharsetException
74
+ private static List<Buffer> bufferList(Charset charset, String... sources) throws UnsupportedCharsetException
74
75
  {
75
- Charset charset = Charset.forName(charsetName);
76
-
77
76
  List<Buffer> buffers = new ArrayList<Buffer>();
78
77
  for (String source : sources) {
79
78
  ByteBuffer buffer = charset.encode(source);
@@ -87,8 +86,8 @@ public class TestLineDecoder
87
86
  public void testDecodeBasicAscii() throws Exception
88
87
  {
89
88
  List<String> decoded = doDecode(
90
- Charset.forName("utf-8"), Newline.LF,
91
- bufferList("utf-8", "test1\ntest2\ntest3\n"));
89
+ StandardCharsets.UTF_8, Newline.LF,
90
+ bufferList(StandardCharsets.UTF_8, "test1\ntest2\ntest3\n"));
92
91
  assertEquals(ImmutableList.of("test1", "test2", "test3"), decoded);
93
92
  }
94
93
 
@@ -96,8 +95,8 @@ public class TestLineDecoder
96
95
  public void testDecodeBasicAsciiCRLF() throws Exception
97
96
  {
98
97
  List<String> decoded = doDecode(
99
- Charset.forName("utf-8"), Newline.CRLF,
100
- bufferList("utf-8", "test1\r\ntest2\r\ntest3\r\n"));
98
+ StandardCharsets.UTF_8, Newline.CRLF,
99
+ bufferList(StandardCharsets.UTF_8, "test1\r\ntest2\r\ntest3\r\n"));
101
100
  assertEquals(ImmutableList.of("test1", "test2", "test3"), decoded);
102
101
  }
103
102
 
@@ -105,8 +104,8 @@ public class TestLineDecoder
105
104
  public void testDecodeBasicAsciiTail() throws Exception
106
105
  {
107
106
  List<String> decoded = doDecode(
108
- Charset.forName("utf-8"), Newline.LF,
109
- bufferList("utf-8", "test1"));
107
+ StandardCharsets.UTF_8, Newline.LF,
108
+ bufferList(StandardCharsets.UTF_8, "test1"));
110
109
  assertEquals(ImmutableList.of("test1"), decoded);
111
110
  }
112
111
 
@@ -114,8 +113,8 @@ public class TestLineDecoder
114
113
  public void testDecodeChunksLF() throws Exception
115
114
  {
116
115
  List<String> decoded = doDecode(
117
- Charset.forName("utf-8"), Newline.LF,
118
- bufferList("utf-8", "t", "1", "\n", "t", "2"));
116
+ StandardCharsets.UTF_8, Newline.LF,
117
+ bufferList(StandardCharsets.UTF_8, "t", "1", "\n", "t", "2"));
119
118
  assertEquals(ImmutableList.of("t1", "t2"), decoded);
120
119
  }
121
120
 
@@ -123,10 +122,116 @@ public class TestLineDecoder
123
122
  public void testDecodeChunksCRLF() throws Exception
124
123
  {
125
124
  List<String> decoded = doDecode(
126
- Charset.forName("utf-8"), Newline.CRLF,
127
- bufferList("utf-8", "t", "1", "\r\n", "t", "2", "\r", "\n", "t3"));
125
+ StandardCharsets.UTF_8, Newline.CRLF,
126
+ bufferList(StandardCharsets.UTF_8, "t", "1", "\r\n", "t", "2", "\r", "\n", "t3"));
128
127
  assertEquals(ImmutableList.of("t1", "t2", "t3"), decoded);
129
128
  }
130
129
 
131
- // TODO test multibytes
130
+ @Test
131
+ public void testDecodeBasicUTF8() throws Exception
132
+ {
133
+ List<String> decoded = doDecode(
134
+ StandardCharsets.UTF_8, Newline.LF,
135
+ bufferList(StandardCharsets.UTF_8, "てすと1\nテスト2\nてすと3\n"));
136
+ assertEquals(ImmutableList.of("てすと1", "テスト2", "てすと3"), decoded);
137
+ }
138
+
139
+ @Test
140
+ public void testDecodeBasicUTF8Tail() throws Exception
141
+ {
142
+ List<String> decoded = doDecode(
143
+ StandardCharsets.UTF_8, Newline.LF,
144
+ bufferList(StandardCharsets.UTF_8, "てすと1"));
145
+ assertEquals(ImmutableList.of("てすと1"), decoded);
146
+ }
147
+
148
+ @Test
149
+ public void testDecodeChunksUTF8LF() throws Exception
150
+ {
151
+ List<String> decoded = doDecode(
152
+ StandardCharsets.UTF_8, Newline.LF,
153
+ bufferList(StandardCharsets.UTF_8, "て", "1", "\n", "す", "2"));
154
+ assertEquals(ImmutableList.of("て1", "す2"), decoded);
155
+ }
156
+
157
+ @Test
158
+ public void testDecodeChunksUTF8CRLF() throws Exception
159
+ {
160
+ List<String> decoded = doDecode(
161
+ StandardCharsets.UTF_8, Newline.CRLF,
162
+ bufferList(StandardCharsets.UTF_8, "て", "1", "\r\n", "す", "2", "\r", "\n", "と3"));
163
+ assertEquals(ImmutableList.of("て1", "す2", "と3"), decoded);
164
+ }
165
+
166
+ @Test
167
+ public void testDecodeBasicUTF16LE() throws Exception
168
+ {
169
+ List<String> decoded = doDecode(
170
+ StandardCharsets.UTF_16LE, Newline.LF,
171
+ bufferList(StandardCharsets.UTF_16LE, "てすと1\nテスト2\nてすと3\n"));
172
+ assertEquals(ImmutableList.of("てすと1", "テスト2", "てすと3"), decoded);
173
+ }
174
+
175
+ @Test
176
+ public void testDecodeBasicUTF16LETail() throws Exception
177
+ {
178
+ List<String> decoded = doDecode(
179
+ StandardCharsets.UTF_16LE, Newline.LF,
180
+ bufferList(StandardCharsets.UTF_16LE, "てすと1"));
181
+ assertEquals(ImmutableList.of("てすと1"), decoded);
182
+ }
183
+
184
+ @Test
185
+ public void testDecodeChunksUTF16LELF() throws Exception
186
+ {
187
+ List<String> decoded = doDecode(
188
+ StandardCharsets.UTF_16LE, Newline.LF,
189
+ bufferList(StandardCharsets.UTF_16LE, "て", "1", "\n", "す", "2"));
190
+ assertEquals(ImmutableList.of("て1", "す2"), decoded);
191
+ }
192
+
193
+ @Test
194
+ public void testDecodeChunksUTF16LECRLF() throws Exception
195
+ {
196
+ List<String> decoded = doDecode(
197
+ StandardCharsets.UTF_16LE, Newline.CRLF,
198
+ bufferList(StandardCharsets.UTF_16LE, "て", "1", "\r\n", "す", "2", "\r", "\n", "と3"));
199
+ assertEquals(ImmutableList.of("て1", "す2", "と3"), decoded);
200
+ }
201
+
202
+ @Test
203
+ public void testDecodeBasicMS932() throws Exception
204
+ {
205
+ List<String> decoded = doDecode(
206
+ Charset.forName("ms932"), Newline.LF,
207
+ bufferList(Charset.forName("ms932"), "てすと1\nテスト2\nてすと3\n"));
208
+ assertEquals(ImmutableList.of("てすと1", "テスト2", "てすと3"), decoded);
209
+ }
210
+
211
+ @Test
212
+ public void testDecodeBasicMS932Tail() throws Exception
213
+ {
214
+ List<String> decoded = doDecode(
215
+ Charset.forName("ms932"), Newline.LF,
216
+ bufferList(Charset.forName("ms932"), "てすと1"));
217
+ assertEquals(ImmutableList.of("てすと1"), decoded);
218
+ }
219
+
220
+ @Test
221
+ public void testDecodeChunksMS932LF() throws Exception
222
+ {
223
+ List<String> decoded = doDecode(
224
+ Charset.forName("ms932"), Newline.LF,
225
+ bufferList(Charset.forName("ms932"), "て", "1", "\n", "す", "2"));
226
+ assertEquals(ImmutableList.of("て1", "す2"), decoded);
227
+ }
228
+
229
+ @Test
230
+ public void testDecodeChunksMS932CRLF() throws Exception
231
+ {
232
+ List<String> decoded = doDecode(
233
+ Charset.forName("ms932"), Newline.CRLF,
234
+ bufferList(Charset.forName("ms932"), "て", "1", "\r\n", "す", "2", "\r", "\n", "と3"));
235
+ assertEquals(ImmutableList.of("て1", "す2", "と3"), decoded);
236
+ }
132
237
  }
@@ -55,10 +55,14 @@ Documents
55
55
 
56
56
  * `File parser plugins <http://www.embulk.org/plugins/#file-parser>`_
57
57
 
58
+ * `File decoder plugins <http://www.embulk.org/plugins/#file-decoder>`_
59
+
58
60
  * `File formatter plugins <http://www.embulk.org/plugins/#file-formatter>`_
59
61
 
60
62
  * `Filter plugins <http://www.embulk.org/plugins/#filter>`_
61
63
 
64
+ * `File encoder plugins <http://www.embulk.org/plugins/#file-encoder>`_
65
+
62
66
  * `Executor plugins <http://www.embulk.org/plugins/#executor>`_
63
67
 
64
68
  .. toctree::
@@ -126,6 +126,13 @@ The generated config-complete.yml file should include complete information as fo
126
126
  nodes:
127
127
  - {host: localhost}
128
128
 
129
+ Note: If the CSV file contains timestamp in local time zone, set default_timezone parameter to parser config as following (since time zone is assumed as UTC by default).
130
+
131
+ .. code-block:: yaml
132
+
133
+ parser:
134
+ default_timezone: 'Asia/Tokyo'
135
+
129
136
  Now, you can run the bulk loading:
130
137
 
131
138
  .. code-block:: console
@@ -4,11 +4,13 @@ Release Notes
4
4
  .. toctree::
5
5
  :maxdepth: 1
6
6
 
7
+ release/release-0.7.5
7
8
  release/release-0.7.4
8
9
  release/release-0.7.3
9
10
  release/release-0.7.2
10
11
  release/release-0.7.1
11
12
  release/release-0.7.0
13
+ release/release-0.6.27
12
14
  release/release-0.6.26
13
15
  release/release-0.6.25
14
16
  release/release-0.6.24
@@ -0,0 +1,11 @@
1
+ Release 0.6.27
2
+ ==================================
3
+
4
+ Built-in plugins
5
+ ------------------
6
+
7
+ * Backported fix of ``CsvTokenizer.InvalidValueException`` error handling problem in ``parser-csv`` plugin
8
+
9
+ Release Date
10
+ ------------------
11
+ 2015-09-30
@@ -0,0 +1,22 @@
1
+ Release 0.7.5
2
+ ==================================
3
+
4
+ General Changes
5
+ ------------------
6
+
7
+ * ``guess`` uses guess plugins configured at ``guess_plugins: [string]`` in ``exec:`` section in addition to ``-g, --guess NAMES`` command line argument.
8
+ * ``guess`` doesn't create unnecessary ``exec:`` section.
9
+ * Fixed timestamp deserialization error happens when a bulkload fails and cleanup runs.
10
+ * Fixed permissions of files generated by ``new`` command.
11
+
12
+
13
+ Built-in plugins
14
+ ------------------
15
+
16
+ * ``guess-csv``: Guesses header line as much as possible when all column types are string or boolean
17
+ * ``parser-csv``: Fixed line number shown in 'Skipped line' warning message
18
+
19
+
20
+ Release Date
21
+ ------------------
22
+ 2015-10-01
@@ -229,8 +229,7 @@ public class CsvParserPlugin
229
229
  {
230
230
  PluginTask task = taskSource.loadTask(PluginTask.class);
231
231
  final TimestampParser[] timestampParsers = Timestamps.newTimestampColumnParsers(task, task.getSchemaConfig());
232
- LineDecoder lineDecoder = new LineDecoder(input, task);
233
- final CsvTokenizer tokenizer = new CsvTokenizer(lineDecoder, task);
232
+ final CsvTokenizer tokenizer = new CsvTokenizer(new LineDecoder(input, task), task);
234
233
  final String nullStringOrNull = task.getNullString().orNull();
235
234
  final boolean allowOptionalColumns = task.getAllowOptionalColumns();
236
235
  final boolean allowExtraColumns = task.getAllowExtraColumns();
@@ -241,7 +240,7 @@ public class CsvParserPlugin
241
240
  while (tokenizer.nextFile()) {
242
241
  // skip the header lines for each file
243
242
  for (; skipHeaderLines > 0; skipHeaderLines--) {
244
- if (lineDecoder.poll() == null) {
243
+ if (!tokenizer.skipHeaderLine()) {
245
244
  break;
246
245
  }
247
246
  }
@@ -356,8 +355,8 @@ public class CsvParserPlugin
356
355
  pageBuilder.addRecord();
357
356
 
358
357
  } catch (CsvTokenizer.InvalidFormatException | CsvTokenizer.InvalidValueException | CsvRecordValidateException e) {
359
- long lineNumber = tokenizer.getCurrentLineNumber();
360
358
  String skippedLine = tokenizer.skipCurrentLine();
359
+ long lineNumber = tokenizer.getCurrentLineNumber();
361
360
  if (stopOnInvalidRecord) {
362
361
  throw new DataException(String.format("Invalid record at line %d: %s", lineNumber, skippedLine), e);
363
362
  }
@@ -56,8 +56,16 @@ public class CsvTokenizer
56
56
 
57
57
  public long getCurrentLineNumber()
58
58
  {
59
- // returns actual line number. Internally, lineNumber starts at 0.
60
- return lineNumber + 1;
59
+ return lineNumber;
60
+ }
61
+
62
+ public boolean skipHeaderLine()
63
+ {
64
+ boolean skipped = input.poll() != null;
65
+ if (skipped) {
66
+ lineNumber++;
67
+ }
68
+ return skipped;
61
69
  }
62
70
 
63
71
  // returns skipped line
@@ -70,10 +78,11 @@ public class CsvTokenizer
70
78
  // recover lines of quoted value
71
79
  skippedLine = quotedValueLines.remove(0); // TODO optimize performance
72
80
  unreadLines.addAll(quotedValueLines);
81
+ lineNumber -= quotedValueLines.size();
73
82
  if (line != null) {
74
83
  unreadLines.add(line);
84
+ lineNumber -= 1;
75
85
  }
76
- lineNumber -= quotedValueLines.size();
77
86
  quotedValueLines.clear();
78
87
  }
79
88
  recordState = RecordState.END;
@@ -305,7 +314,7 @@ public class CsvTokenizer
305
314
  // column has trailing spaces and quoted. TODO should this be rejected?
306
315
 
307
316
  } else {
308
- throw new InvalidValueException(String.format("Unexpected extra character (%c) after quoted value in %s", c, line));
317
+ throw new InvalidValueException(String.format("Unexpected extra character '%c' after quoted value in '%s'", c, line));
309
318
  }
310
319
  break;
311
320
 
data/lib/embulk.rb CHANGED
@@ -1,14 +1,4 @@
1
1
  module Embulk
2
- if RUBY_PLATFORM =~ /java/i
3
- def self.java?
4
- true
5
- end
6
- else
7
- def self.java?
8
- false
9
- end
10
- end
11
-
12
2
  # logger should be setup first
13
3
  require 'embulk/logger'
14
4
 
@@ -29,19 +19,15 @@ module Embulk
29
19
 
30
20
  def self.require_classpath
31
21
  if __FILE__.include?("!")
32
- # single jar
33
- jar, resource = __FILE__.split("!", 2)
34
- begin
35
- require File.expand_path(jar)
36
- rescue LoadError
37
- # TODO fails if jar doesn't end with ".rb" or ".jar" but ignorable
38
- end
22
+ # single jar. __FILE__ should point path/to/embulk.jar!/embulk.rb
23
+ # which means that embulk.jar is already loaded in this JVM.
39
24
 
40
25
  elsif __FILE__ =~ /^classpath:/
41
26
  # already in classpath
42
27
 
43
28
  else
44
- # gem package
29
+ # gem package. __FILE__ should point path/to/embulk/lib/embulk.rb
30
+ # that requires here to load ../classpath/*.jar to start EmbulkEmbed.
45
31
  gem_root = File.expand_path('..', File.dirname(__FILE__))
46
32
  classpath_dir = File.join(gem_root, "classpath")
47
33
  jars = Dir.entries(classpath_dir).select{|f| f =~ /\.jar$/ }.sort
@@ -26,9 +26,9 @@ module Embulk
26
26
  #
27
27
  # Generate gemspec
28
28
  #
29
- author = `git config user.name`.strip
29
+ author = `git config user.name`.strip rescue ""
30
30
  author = "YOUR_NAME" if author.empty?
31
- email = `git config user.email`.strip
31
+ email = `git config user.email`.strip rescue ""
32
32
  email = "YOUR_NAME" if email.empty?
33
33
 
34
34
  # variables used in erb templates
@@ -130,7 +130,7 @@ module Embulk
130
130
  elsif File.exists?('Gemfile')
131
131
  bundle_path = '.'
132
132
  else
133
- system_exit "'#{path}' already exists. You already ran 'embulk bundle new'. Please remove it, or run \"cd #{path}\" and \"embulk bundle\" instead"
133
+ system_exit "'#{gemfile_path}' already exists. You already ran 'embulk bundle new'. Please remove it, or run \"cd #{gemfile_path}\" and \"embulk bundle\" instead"
134
134
  end
135
135
 
136
136
  run_bundler(argv)
@@ -262,12 +262,14 @@ examples:
262
262
  else
263
263
  require 'json'
264
264
 
265
- Embulk.setup(options.delete(:system_config))
266
-
267
265
  setup_plugin_paths(plugin_paths)
268
266
  setup_load_paths(load_paths)
269
267
  setup_classpaths(classpaths)
270
268
 
269
+ # call setup after setup_classpaths to allow users to overwrite
270
+ # embulk classes
271
+ Embulk.setup(options.delete(:system_config))
272
+
271
273
  begin
272
274
  case subcmd
273
275
  when :guess
@@ -29,8 +29,9 @@ module Embulk
29
29
  puts "Checking the latest version..."
30
30
  target_version = check_latest_version
31
31
 
32
- if Gem::Version.new(target_version) <= Gem::Version.new(Embulk::VERSION)
33
- puts "Already up-to-date. #{target_version} is the latest version."
32
+ current_version = Gem::Version.new(Embulk::VERSION)
33
+ if Gem::Version.new(target_version) <= current_version
34
+ puts "Already up-to-date. #{current_version} is the latest version."
34
35
  return
35
36
  end
36
37
 
@@ -7,6 +7,10 @@
7
7
  /classpath/
8
8
  build/
9
9
  .idea
10
+ /.settings/
11
+ /.metadata/
12
+ .classpath
13
+ .project
10
14
  %elsif language == :ruby
11
15
  /.bundle/
12
16
  /Gemfile.lock
@@ -26,12 +26,12 @@ public class <%= java_class_name %>
26
26
  public int getOption1();
27
27
 
28
28
  // configuration option 2 (optional string, null is not allowed)
29
- @Config("optoin2")
29
+ @Config("option2")
30
30
  @ConfigDefault("\"myvalue\"")
31
31
  public String getOption2();
32
32
 
33
33
  // configuration option 3 (optional string, null is allowed)
34
- @Config("optoin3")
34
+ @Config("option3")
35
35
  @ConfigDefault("null")
36
36
  public Optional<String> getOption3();
37
37
 
@@ -26,12 +26,12 @@ public class <%= java_class_name %>
26
26
  public int getOption1();
27
27
 
28
28
  // configuration option 2 (optional string, null is not allowed)
29
- @Config("optoin2")
29
+ @Config("option2")
30
30
  @ConfigDefault("\"myvalue\"")
31
31
  public String getOption2();
32
32
 
33
33
  // configuration option 3 (optional string, null is allowed)
34
- @Config("optoin3")
34
+ @Config("option3")
35
35
  @ConfigDefault("null")
36
36
  public Optional<String> getOption3();
37
37
 
@@ -29,12 +29,12 @@ public class <%= java_class_name %>
29
29
  public int getOption1();
30
30
 
31
31
  // configuration option 2 (optional string, null is not allowed)
32
- @Config("optoin2")
32
+ @Config("option2")
33
33
  @ConfigDefault("\"myvalue\"")
34
34
  public String getOption2();
35
35
 
36
36
  // configuration option 3 (optional string, null is allowed)
37
- @Config("optoin3")
37
+ @Config("option3")
38
38
  @ConfigDefault("null")
39
39
  public Optional<String> getOption3();
40
40
 
@@ -24,12 +24,12 @@ public class <%= java_class_name %>
24
24
  public int getOption1();
25
25
 
26
26
  // configuration option 2 (optional string, null is not allowed)
27
- @Config("optoin2")
27
+ @Config("option2")
28
28
  @ConfigDefault("\"myvalue\"")
29
29
  public String getOption2();
30
30
 
31
31
  // configuration option 3 (optional string, null is allowed)
32
- @Config("optoin3")
32
+ @Config("option3")
33
33
  @ConfigDefault("null")
34
34
  public Optional<String> getOption3();
35
35
 
@@ -23,12 +23,12 @@ public class <%= java_class_name %>
23
23
  public int getOption1();
24
24
 
25
25
  // configuration option 2 (optional string, null is not allowed)
26
- @Config("optoin2")
26
+ @Config("option2")
27
27
  @ConfigDefault("\"myvalue\"")
28
28
  public String getOption2();
29
29
 
30
30
  // configuration option 3 (optional string, null is allowed)
31
- @Config("optoin3")
31
+ @Config("option3")
32
32
  @ConfigDefault("null")
33
33
  public Optional<String> getOption3();
34
34
  }
@@ -23,12 +23,12 @@ public class <%= java_class_name %>
23
23
  public int getOption1();
24
24
 
25
25
  // configuration option 2 (optional string, null is not allowed)
26
- @Config("optoin2")
26
+ @Config("option2")
27
27
  @ConfigDefault("\"myvalue\"")
28
28
  public String getOption2();
29
29
 
30
30
  // configuration option 3 (optional string, null is allowed)
31
- @Config("optoin3")
31
+ @Config("option3")
32
32
  @ConfigDefault("null")
33
33
  public Optional<String> getOption3();
34
34
  }
@@ -26,12 +26,12 @@ public class <%= java_class_name %>
26
26
  public int getOption1();
27
27
 
28
28
  // configuration option 2 (optional string, null is not allowed)
29
- @Config("optoin2")
29
+ @Config("option2")
30
30
  @ConfigDefault("\"myvalue\"")
31
31
  public String getOption2();
32
32
 
33
33
  // configuration option 3 (optional string, null is allowed)
34
- @Config("optoin3")
34
+ @Config("option3")
35
35
  @ConfigDefault("null")
36
36
  public Optional<String> getOption3();
37
37
 
@@ -26,12 +26,12 @@ public class <%= java_class_name %>
26
26
  public int getOption1();
27
27
 
28
28
  // configuration option 2 (optional string, null is not allowed)
29
- @Config("optoin2")
29
+ @Config("option2")
30
30
  @ConfigDefault("\"myvalue\"")
31
31
  public String getOption2();
32
32
 
33
33
  // configuration option 3 (optional string, null is allowed)
34
- @Config("optoin3")
34
+ @Config("option3")
35
35
  @ConfigDefault("null")
36
36
  public Optional<String> getOption3();
37
37
  }
@@ -24,12 +24,12 @@ public class <%= java_class_name %>
24
24
  public int getOption1();
25
25
 
26
26
  // configuration option 2 (optional string, null is not allowed)
27
- @Config("optoin2")
27
+ @Config("option2")
28
28
  @ConfigDefault("\"myvalue\"")
29
29
  public String getOption2();
30
30
 
31
31
  // configuration option 3 (optional string, null is allowed)
32
- @Config("optoin3")
32
+ @Config("option3")
33
33
  @ConfigDefault("null")
34
34
  public Optional<String> getOption3();
35
35
 
@@ -26,13 +26,17 @@ module Embulk
26
26
  end
27
27
 
28
28
  def cp(src, dest_name)
29
- path = dest_path_message(dest_name)
30
- FileUtils.cp path(src), path
29
+ dest = dest_path_message(dest_name)
30
+ File.open(dest, "wb") do |dst_io|
31
+ File.open(path(src), "rb") do |src_io|
32
+ FileUtils.copy_stream src_io, dst_io
33
+ end
34
+ end
31
35
  end
32
36
 
33
37
  def cp_erb(src, dest_name)
34
- path = dest_path_message(dest_name)
35
- File.open(path, "w") {|f| f.write erb(src) }
38
+ dest = dest_path_message(dest_name)
39
+ File.open(dest, "wb") {|f| f.write erb(src) }
36
40
  end
37
41
 
38
42
  def dest_path(dest_name)
@@ -47,7 +51,8 @@ module Embulk
47
51
  end
48
52
 
49
53
  def set_executable(dest_name)
50
- File.chmod(0755, dest_path(dest_name))
54
+ dest = dest_path(dest_name)
55
+ File.chmod(File.stat(dest).mode | 0111, dest)
51
56
  end
52
57
  end
53
58
 
@@ -123,7 +123,7 @@ module Embulk
123
123
  end
124
124
  end
125
125
 
126
- header_line = (first_types != other_types && first_types.all? {|t| ["string", "boolean"].include?(t) })
126
+ header_line = (first_types != other_types && first_types.all? {|t| ["string", "boolean"].include?(t) }) || guess_string_header_line(sample_records)
127
127
 
128
128
  if header_line
129
129
  parser_guessed["skip_header_lines"] = skip_header_lines + 1
@@ -305,6 +305,22 @@ module Embulk
305
305
  end
306
306
  end
307
307
 
308
+ def guess_string_header_line(sample_records)
309
+ first = sample_records.first
310
+ first.count.times do |column_index|
311
+ lengths = sample_records.map {|row| row[column_index] }.compact.map {|v| v.to_s.size }
312
+ if lengths.size > 2
313
+ if array_variance(lengths[1..-1]) <= 0.2
314
+ avg = array_avg(lengths[1..-1])
315
+ if avg == 0.0 ? lengths[0] > 1 : (avg - lengths[0]).abs / avg > 0.7
316
+ return true
317
+ end
318
+ end
319
+ end
320
+ end
321
+ return false
322
+ end
323
+
308
324
  def array_sum(array)
309
325
  array.inject(0) {|r,i| r += i }
310
326
  end
data/lib/embulk/logger.rb CHANGED
@@ -12,7 +12,7 @@ module Embulk
12
12
  @logger = a
13
13
  elsif a.is_a?(::Logger)
14
14
  @logger = StandardLoggerAdapter.new(a)
15
- elsif Embulk.java? && (org.slf4j.Logger rescue nil) && a.is_a?(org.slf4j.Logger)
15
+ elsif RUBY_PLATFORM =~ /java/i && (org.slf4j.Logger rescue nil) && a.is_a?(org.slf4j.Logger)
16
16
  @logger = Slf4jAdapter.new(a)
17
17
  else
18
18
  @logger = StandardLoggerAdapter.new(*args)
@@ -43,7 +43,7 @@ module Embulk
43
43
 
44
44
  def initialize(*args)
45
45
  super
46
- if Embulk.java?
46
+ if RUBY_PLATFORM =~ /java/i
47
47
  self.formatter = lambda do |severity,datetime,progname,message|
48
48
  "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%3N %z")} [#{severity}] (#{java.lang.Thread.currentThread.name}): #{message}\n"
49
49
  end
data/lib/embulk/runner.rb CHANGED
@@ -117,7 +117,7 @@ module Embulk
117
117
  when /\.yml$/
118
118
  @embed.newConfigLoader.fromYamlString File.read(config)
119
119
  else
120
- raise ConfigError, "Unsupported file extension. Supported file extensions are .yml and .yml.liquid: #{config}"
120
+ raise ConfigError.new("Unsupported file extension. Supported file extensions are .yml and .yml.liquid: #{config}")
121
121
  end
122
122
 
123
123
  when Hash, DataSource
@@ -1,3 +1,3 @@
1
1
  module Embulk
2
- VERSION = '0.7.4'
2
+ VERSION = '0.7.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.4
4
+ version: 0.7.5
5
5
  platform: java
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-30 00:00:00.000000000 Z
11
+ date: 2015-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -133,8 +133,8 @@ files:
133
133
  - classpath/bval-jsr303-0.5.jar
134
134
  - classpath/commons-beanutils-core-1.8.3.jar
135
135
  - classpath/commons-lang3-3.1.jar
136
- - classpath/embulk-core-0.7.4.jar
137
- - classpath/embulk-standards-0.7.4.jar
136
+ - classpath/embulk-core-0.7.5.jar
137
+ - classpath/embulk-standards-0.7.5.jar
138
138
  - classpath/guava-18.0.jar
139
139
  - classpath/guice-4.0.jar
140
140
  - classpath/guice-multibindings-4.0.jar
@@ -189,6 +189,7 @@ files:
189
189
  - embulk-core/src/main/java/org/embulk/config/UserDataException.java
190
190
  - embulk-core/src/main/java/org/embulk/config/UserDataExceptions.java
191
191
  - embulk-core/src/main/java/org/embulk/exec/BulkLoader.java
192
+ - embulk-core/src/main/java/org/embulk/exec/ConfigurableGuessInputPlugin.java
192
193
  - embulk-core/src/main/java/org/embulk/exec/ExecModule.java
193
194
  - embulk-core/src/main/java/org/embulk/exec/ExecutionInterruptedException.java
194
195
  - embulk-core/src/main/java/org/embulk/exec/ExecutionResult.java
@@ -422,6 +423,7 @@ files:
422
423
  - embulk-docs/src/release/release-0.6.24.rst
423
424
  - embulk-docs/src/release/release-0.6.25.rst
424
425
  - embulk-docs/src/release/release-0.6.26.rst
426
+ - embulk-docs/src/release/release-0.6.27.rst
425
427
  - embulk-docs/src/release/release-0.6.3.rst
426
428
  - embulk-docs/src/release/release-0.6.4.rst
427
429
  - embulk-docs/src/release/release-0.6.5.rst
@@ -434,6 +436,7 @@ files:
434
436
  - embulk-docs/src/release/release-0.7.2.rst
435
437
  - embulk-docs/src/release/release-0.7.3.rst
436
438
  - embulk-docs/src/release/release-0.7.4.rst
439
+ - embulk-docs/src/release/release-0.7.5.rst
437
440
  - embulk-standards/build.gradle
438
441
  - embulk-standards/src/main/java/org/embulk/standards/CsvFormatterPlugin.java
439
442
  - embulk-standards/src/main/java/org/embulk/standards/CsvParserPlugin.java