embulk 0.7.4 → 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
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: cd162b183e5e14cb42b36d7bed695fe530ff41a1
4
- data.tar.gz: 86f9a9b4d6913adbf9cc758781e5dab4bf793c25
3
+ metadata.gz: 0fc04e8ab92c677b7c5891a2818354f81da3ef70
4
+ data.tar.gz: 4a43292bb55fec0d3d981089572e574dcafa525d
5
5
  SHA512:
6
- metadata.gz: ff68ce1bb8e18e10e7e171a48b19c18cac2c52c9759d1db2116ec0180f7360b33432e1e78fe1e80717c229afc253852010b4fbc2ddcf1406ea8613b97fbde1de
7
- data.tar.gz: fa257fa73c6f538e4ea390adf8d9a276404333ed787da9496e19ce9b007eb0d790186ebd4dbb1ada64afdf4a245590a6b7f268100e539f1ac9879c7898ab77c5
6
+ metadata.gz: 122d1f4632210c5d807d3301fdab9046a509420e9557caff224696f35a1f21eac9731dade238044fd36f70e0b24e382b276e3da4165f680d76875a8a7d399440
7
+ data.tar.gz: 6a671967d0c53640f977e286d0dd874712454af12ba361a7d6db85599be510da2bfdd67bc685803e0d5426b8b8b7f17e2e01c1aa3172f23c55635b8e1af8697e
@@ -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
@@ -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
 
@@ -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
@@ -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
@@ -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: ruby
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: jruby-jars
@@ -121,8 +121,8 @@ files:
121
121
  - classpath/bval-jsr303-0.5.jar
122
122
  - classpath/commons-beanutils-core-1.8.3.jar
123
123
  - classpath/commons-lang3-3.1.jar
124
- - classpath/embulk-core-0.7.4.jar
125
- - classpath/embulk-standards-0.7.4.jar
124
+ - classpath/embulk-core-0.7.5.jar
125
+ - classpath/embulk-standards-0.7.5.jar
126
126
  - classpath/guava-18.0.jar
127
127
  - classpath/guice-4.0.jar
128
128
  - classpath/guice-multibindings-4.0.jar
@@ -177,6 +177,7 @@ files:
177
177
  - embulk-core/src/main/java/org/embulk/config/UserDataException.java
178
178
  - embulk-core/src/main/java/org/embulk/config/UserDataExceptions.java
179
179
  - embulk-core/src/main/java/org/embulk/exec/BulkLoader.java
180
+ - embulk-core/src/main/java/org/embulk/exec/ConfigurableGuessInputPlugin.java
180
181
  - embulk-core/src/main/java/org/embulk/exec/ExecModule.java
181
182
  - embulk-core/src/main/java/org/embulk/exec/ExecutionInterruptedException.java
182
183
  - embulk-core/src/main/java/org/embulk/exec/ExecutionResult.java
@@ -410,6 +411,7 @@ files:
410
411
  - embulk-docs/src/release/release-0.6.24.rst
411
412
  - embulk-docs/src/release/release-0.6.25.rst
412
413
  - embulk-docs/src/release/release-0.6.26.rst
414
+ - embulk-docs/src/release/release-0.6.27.rst
413
415
  - embulk-docs/src/release/release-0.6.3.rst
414
416
  - embulk-docs/src/release/release-0.6.4.rst
415
417
  - embulk-docs/src/release/release-0.6.5.rst
@@ -422,6 +424,7 @@ files:
422
424
  - embulk-docs/src/release/release-0.7.2.rst
423
425
  - embulk-docs/src/release/release-0.7.3.rst
424
426
  - embulk-docs/src/release/release-0.7.4.rst
427
+ - embulk-docs/src/release/release-0.7.5.rst
425
428
  - embulk-standards/build.gradle
426
429
  - embulk-standards/src/main/java/org/embulk/standards/CsvFormatterPlugin.java
427
430
  - embulk-standards/src/main/java/org/embulk/standards/CsvParserPlugin.java