embulk 0.6.16 → 0.6.17

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -45
  3. data/build.gradle +3 -3
  4. data/embulk-core/src/main/java/org/embulk/spi/Exec.java +6 -0
  5. data/embulk-core/src/main/java/org/embulk/spi/util/InputStreamFileInput.java +73 -1
  6. data/embulk-core/src/main/java/org/embulk/spi/util/InputStreamTransactionalFileInput.java +25 -0
  7. data/embulk-core/src/main/java/org/embulk/spi/util/Timestamps.java +53 -0
  8. data/embulk-docs/src/_static/embulk-logo.svg +133 -0
  9. data/embulk-docs/src/release.rst +1 -0
  10. data/embulk-docs/src/release/release-0.6.17.rst +39 -0
  11. data/embulk-standards/src/main/java/org/embulk/standards/CsvFormatterPlugin.java +2 -17
  12. data/embulk-standards/src/main/java/org/embulk/standards/CsvParserPlugin.java +3 -22
  13. data/embulk-standards/src/main/java/org/embulk/standards/GzipFileDecoderPlugin.java +2 -2
  14. data/embulk-standards/src/main/java/org/embulk/standards/GzipFileEncoderPlugin.java +0 -1
  15. data/embulk-standards/src/main/java/org/embulk/standards/LocalFileInputPlugin.java +18 -42
  16. data/embulk-standards/src/main/java/org/embulk/standards/LocalFileOutputPlugin.java +3 -3
  17. data/lib/embulk/command/embulk_new_plugin.rb +40 -14
  18. data/lib/embulk/command/embulk_run.rb +3 -3
  19. data/lib/embulk/data/new/README.md.erb +18 -17
  20. data/lib/embulk/data/new/java/build.gradle.erb +1 -1
  21. data/lib/embulk/data/new/java/decoder.java.erb +53 -9
  22. data/lib/embulk/data/new/java/encoder.java.erb +54 -8
  23. data/lib/embulk/data/new/java/file_input.java.erb +91 -12
  24. data/lib/embulk/data/new/java/file_output.java.erb +35 -8
  25. data/lib/embulk/data/new/java/filter.java.erb +16 -7
  26. data/lib/embulk/data/new/java/formatter.java.erb +16 -7
  27. data/lib/embulk/data/new/java/input.java.erb +18 -14
  28. data/lib/embulk/data/new/java/output.java.erb +16 -8
  29. data/lib/embulk/data/new/java/parser.java.erb +17 -8
  30. data/lib/embulk/data/new/java/plugin_loader.rb.erb +1 -1
  31. data/lib/embulk/data/new/java/test.java.erb +1 -1
  32. data/lib/embulk/data/new/ruby/filter.rb.erb +6 -4
  33. data/lib/embulk/data/new/ruby/formatter.rb.erb +6 -4
  34. data/lib/embulk/data/new/ruby/gemspec.erb +2 -2
  35. data/lib/embulk/data/new/ruby/input.rb.erb +6 -4
  36. data/lib/embulk/data/new/ruby/output.rb.erb +6 -4
  37. data/lib/embulk/data/new/ruby/parser.rb.erb +6 -4
  38. data/lib/embulk/file_input.rb +4 -0
  39. data/lib/embulk/file_output.rb +4 -0
  40. data/lib/embulk/version.rb +1 -1
  41. metadata +8 -4
@@ -4,6 +4,7 @@ Release Notes
4
4
  .. toctree::
5
5
  :maxdepth: 1
6
6
 
7
+ release/release-0.6.17
7
8
  release/release-0.6.16
8
9
  release/release-0.6.15
9
10
  release/release-0.6.14
@@ -0,0 +1,39 @@
1
+ Release 0.6.17
2
+ ==================================
3
+
4
+ General Changes
5
+ ------------------
6
+
7
+ * '-' in generated plugin name is replaed to '_'.
8
+
9
+ * Package name of generated java plugins changed from org.embulk.<category> to org.embulk.<category>.<plugin name>.
10
+
11
+ * Generated plugin templates use recommended utility classes by default.
12
+
13
+ * java-decode template generator uses InputStreamFileInput.
14
+
15
+ * java-encoder template generator uses FileOutputOutputStream.
16
+
17
+ * java-file-input template generator uses InputStreamTransactionalFileInput.
18
+
19
+ * guess method of generated java-input plugin returns empty config diff rather throwing an exception.
20
+
21
+
22
+ Java Plugin API
23
+ ------------------
24
+
25
+ * Added ``spi.Exec.getTransactionTime()``.
26
+ * Added ``spi.util.Timestamps`` utility class. This method is useful to create ``TimestampParser`` and ``TimestampFormatter`` which are configurable by users.
27
+ * Added ``spi.util.InputStreamFileInput.Opener`` interface to open single file.
28
+ * Added ``spi.util.InputStreamFileInput()`` with ``InputStream`` to use a pre-opend stream.
29
+ * Added ``spi.util.InputStreamTransactionalFileInput`` for convenience of ``FileInputPlugin``.
30
+
31
+ Ruby Plugin API
32
+ ------------------
33
+
34
+ * Added ``FileInput#to_java`` and ``FileOutput#to_java``.
35
+
36
+
37
+ Release Date
38
+ ------------------
39
+ 2015-07-17
@@ -21,6 +21,7 @@ import org.embulk.spi.PageReader;
21
21
  import org.embulk.spi.Exec;
22
22
  import org.embulk.spi.FileOutput;
23
23
  import org.embulk.spi.util.LineEncoder;
24
+ import org.embulk.spi.util.Timestamps;
24
25
 
25
26
  import org.embulk.spi.util.Newline;
26
27
  import java.util.Map;
@@ -101,29 +102,13 @@ public class CsvFormatterPlugin
101
102
  control.run(task.dump());
102
103
  }
103
104
 
104
- private TimestampFormatter[] newTimestampFormatters(
105
- TimestampFormatter.Task formatterTask, Schema schema,
106
- Map<String, TimestampColumnOption> columnOptions)
107
- {
108
- TimestampFormatter[] formatters = new TimestampFormatter[schema.getColumnCount()];
109
- int i = 0;
110
- for (Column column : schema.getColumns()) {
111
- if (column.getType() instanceof TimestampType) {
112
- Optional<TimestampColumnOption> option = Optional.fromNullable(columnOptions.get(column.getName()));
113
- formatters[i] = new TimestampFormatter(formatterTask, option);
114
- }
115
- i++;
116
- }
117
- return formatters;
118
- }
119
-
120
105
  @Override
121
106
  public PageOutput open(TaskSource taskSource, final Schema schema,
122
107
  FileOutput output)
123
108
  {
124
109
  final PluginTask task = taskSource.loadTask(PluginTask.class);
125
110
  final LineEncoder encoder = new LineEncoder(output, task);
126
- final TimestampFormatter[] timestampFormatters = newTimestampFormatters(task, schema, task.getColumnOptions());
111
+ final TimestampFormatter[] timestampFormatters = Timestamps.newTimestampColumnFormatters(task, schema, task.getColumnOptions());
127
112
  final char delimiter = task.getDelimiterChar();
128
113
  final QuotePolicy quotePolicy = task.getQuotePolicy();
129
114
  final char quote = task.getQuoteChar() != '\0' ? task.getQuoteChar() : '"';
@@ -9,7 +9,6 @@ import org.embulk.config.ConfigSource;
9
9
  import org.embulk.config.ConfigException;
10
10
  import org.embulk.config.TaskSource;
11
11
  import org.embulk.spi.type.TimestampType;
12
- import org.embulk.spi.time.TimestampFormat;
13
12
  import org.embulk.spi.time.TimestampParser;
14
13
  import org.embulk.spi.time.TimestampParseException;
15
14
  import org.embulk.spi.Column;
@@ -23,6 +22,7 @@ import org.embulk.spi.Exec;
23
22
  import org.embulk.spi.FileInput;
24
23
  import org.embulk.spi.PageOutput;
25
24
  import org.embulk.spi.util.LineDecoder;
25
+ import org.embulk.spi.util.Timestamps;
26
26
  import org.slf4j.Logger;
27
27
 
28
28
  public class CsvParserPlugin
@@ -90,10 +90,6 @@ public class CsvParserPlugin
90
90
  public boolean getAllowExtraColumns();
91
91
  }
92
92
 
93
- public interface TimestampColumnOption
94
- extends Task, TimestampParser.TimestampColumnOption
95
- { }
96
-
97
93
  private final Logger log;
98
94
 
99
95
  public CsvParserPlugin()
@@ -121,27 +117,12 @@ public class CsvParserPlugin
121
117
  control.run(task.dump(), task.getSchemaConfig().toSchema());
122
118
  }
123
119
 
124
- private TimestampParser[] newTimestampParsers(
125
- TimestampParser.Task parserTask, SchemaConfig schema)
126
- {
127
- TimestampParser[] parsers = new TimestampParser[schema.getColumnCount()];
128
- int i = 0;
129
- for (ColumnConfig column : schema.getColumns()) {
130
- if (column.getType() instanceof TimestampType) {
131
- TimestampColumnOption option = column.getOption().loadConfig(TimestampColumnOption.class);
132
- parsers[i] = new TimestampParser(parserTask, option);
133
- }
134
- i++;
135
- }
136
- return parsers;
137
- }
138
-
139
120
  @Override
140
121
  public void run(TaskSource taskSource, final Schema schema,
141
122
  FileInput input, PageOutput output)
142
123
  {
143
124
  PluginTask task = taskSource.loadTask(PluginTask.class);
144
- final TimestampParser[] timestampFormatters = newTimestampParsers(task, task.getSchemaConfig());
125
+ final TimestampParser[] timestampParsers = Timestamps.newTimestampColumnParsers(task, task.getSchemaConfig());
145
126
  LineDecoder lineDecoder = new LineDecoder(input, task);
146
127
  final CsvTokenizer tokenizer = new CsvTokenizer(lineDecoder, task);
147
128
  final String nullStringOrNull = task.getNullString().orNull();
@@ -225,7 +206,7 @@ public class CsvParserPlugin
225
206
  pageBuilder.setNull(column);
226
207
  } else {
227
208
  try {
228
- pageBuilder.setTimestamp(column, timestampFormatters[column.getIndex()].parse(v));
209
+ pageBuilder.setTimestamp(column, timestampParsers[column.getIndex()].parse(v));
229
210
  } catch (TimestampParseException e) {
230
211
  // TODO support default value
231
212
  throw new CsvRecordValidateException(e);
@@ -31,10 +31,10 @@ public class GzipFileDecoderPlugin
31
31
  }
32
32
 
33
33
  @Override
34
- public FileInput open(TaskSource taskSource, FileInput input)
34
+ public FileInput open(TaskSource taskSource, FileInput fileInput)
35
35
  {
36
36
  PluginTask task = taskSource.loadTask(PluginTask.class);
37
- final FileInputInputStream files = new FileInputInputStream(input);
37
+ final FileInputInputStream files = new FileInputInputStream(fileInput);
38
38
  return new InputStreamFileInput(
39
39
  task.getBufferAllocator(),
40
40
  new InputStreamFileInput.Provider() {
@@ -55,7 +55,6 @@ public class GzipFileEncoderPlugin
55
55
  this.def.setLevel(task.getLevel());
56
56
  }
57
57
  };
58
-
59
58
  }
60
59
 
61
60
  public void finish() throws IOException
@@ -28,7 +28,7 @@ import org.embulk.spi.BufferAllocator;
28
28
  import org.embulk.spi.Exec;
29
29
  import org.embulk.spi.FileInputPlugin;
30
30
  import org.embulk.spi.TransactionalFileInput;
31
- import org.embulk.spi.util.InputStreamFileInput;
31
+ import org.embulk.spi.util.InputStreamTransactionalFileInput;
32
32
  import org.slf4j.Logger;
33
33
 
34
34
  public class LocalFileInputPlugin
@@ -177,52 +177,28 @@ public class LocalFileInputPlugin
177
177
  @Override
178
178
  public TransactionalFileInput open(TaskSource taskSource, int taskIndex)
179
179
  {
180
- PluginTask task = taskSource.loadTask(PluginTask.class);
181
- return new LocalFileInput(task, taskIndex);
182
- }
180
+ final PluginTask task = taskSource.loadTask(PluginTask.class);
183
181
 
184
- public static class LocalFileInput
185
- extends InputStreamFileInput
186
- implements TransactionalFileInput
187
- {
188
- // TODO create single-file InputStreamFileInput utility
189
- private static class SingleFileProvider
190
- implements InputStreamFileInput.Provider
191
- {
192
- private final File file;
193
- private boolean opened = false;
182
+ final File file = new File(task.getFiles().get(taskIndex));
194
183
 
195
- public SingleFileProvider(File file)
196
- {
197
- this.file = file;
198
- }
184
+ return new InputStreamTransactionalFileInput(
185
+ task.getBufferAllocator(),
186
+ new InputStreamTransactionalFileInput.Opener() {
187
+ public InputStream open() throws IOException
188
+ {
189
+ return new FileInputStream(file);
190
+ }
191
+ })
192
+ {
193
+ @Override
194
+ public void abort()
195
+ { }
199
196
 
200
197
  @Override
201
- public InputStream openNext() throws IOException
198
+ public CommitReport commit()
202
199
  {
203
- if (opened) {
204
- return null;
205
- }
206
- opened = true;
207
- return new FileInputStream(file);
200
+ return Exec.newCommitReport();
208
201
  }
209
-
210
- @Override
211
- public void close() { }
212
- }
213
-
214
- public LocalFileInput(PluginTask task, int taskIndex)
215
- {
216
- super(task.getBufferAllocator(), new SingleFileProvider(new File(task.getFiles().get(taskIndex))));
217
- }
218
-
219
- @Override
220
- public void abort() { }
221
-
222
- @Override
223
- public CommitReport commit()
224
- {
225
- return Exec.newCommitReport();
226
- }
202
+ };
227
203
  }
228
204
  }
@@ -82,9 +82,8 @@ public class LocalFileOutputPlugin
82
82
  final String pathSuffix = task.getFileNameExtension();
83
83
  final String sequenceFormat = task.getSequenceFormat();
84
84
 
85
- final List<String> fileNames = new ArrayList<>();
86
-
87
85
  return new TransactionalFileOutput() {
86
+ private final List<String> fileNames = new ArrayList<>();
88
87
  private int fileIndex = 0;
89
88
  private FileOutputStream output = null;
90
89
 
@@ -134,7 +133,8 @@ public class LocalFileOutputPlugin
134
133
  closeFile();
135
134
  }
136
135
 
137
- public void abort() { }
136
+ public void abort()
137
+ { }
138
138
 
139
139
  public CommitReport commit()
140
140
  {
@@ -8,28 +8,35 @@ module Embulk
8
8
  embulk_category = :input if category == :file_input
9
9
  embulk_category = :output if category == :file_output
10
10
 
11
- project_name = "embulk-#{embulk_category}-#{name}"
11
+ name = name.gsub(/[^a-zA-Z0-9_]+/, '_') # replace '-' to '_'
12
+
13
+ full_project_name = "embulk-#{embulk_category}-#{name}"
12
14
  plugin_dir = "lib/embulk"
13
15
  plugin_path = "#{plugin_dir}/#{embulk_category}/#{name}.rb"
14
16
 
15
- if File.exist?(project_name)
16
- raise "./#{project_name} already exists. Please delete it first."
17
+ if File.exist?(full_project_name)
18
+ raise "./#{full_project_name} already exists. Please delete it first."
17
19
  end
18
- FileUtils.mkdir_p(project_name)
20
+ FileUtils.mkdir_p(full_project_name)
19
21
 
20
- puts "Creating #{project_name}/"
22
+ puts "Creating #{full_project_name}/"
21
23
 
22
24
  success = false
23
25
  begin
26
+ #
27
+ # Generate gemspec
28
+ #
24
29
  author = `git config user.name`.strip
25
30
  author = "YOUR_NAME" if author.empty?
26
31
  email = `git config user.email`.strip
27
32
  email = "YOUR_NAME" if email.empty?
28
33
 
29
- ruby_class_name = name.split('-').map {|a| a.capitalize }.join
30
- java_iface = category.to_s.split('_').map {|a| a.capitalize }.join
31
- java_class_name = name.split('-').map {|a| a.capitalize }.join + java_iface + "Plugin"
32
- display_name = name.split('-').map {|a| a.capitalize }.join(' ')
34
+ # variables used in erb templates
35
+ ruby_class_name = name.split('_').map {|a| a.capitalize }.join
36
+ java_iface_name = category.to_s.split('_').map {|a| a.capitalize }.join
37
+ java_class_name = name.split('_').map {|a| a.capitalize }.join + java_iface_name + "Plugin"
38
+ java_package_name = "org.embulk.#{embulk_category}.#{name}"
39
+ display_name = name.split('_').map {|a| a.capitalize }.join(' ')
33
40
  display_category = category.to_s.gsub('_', ' ')
34
41
 
35
42
  extra_guess_erb = {}
@@ -57,7 +64,10 @@ module Embulk
57
64
  description = %[#{display_name}]
58
65
  end
59
66
 
60
- pkg = Embulk::PackageData.new("new", project_name, binding())
67
+ #
68
+ # Generate project repository
69
+ #
70
+ pkg = Embulk::PackageData.new("new", full_project_name, binding())
61
71
 
62
72
  pkg.cp_erb("README.md.erb", "README.md")
63
73
  pkg.cp("LICENSE.txt", "LICENSE.txt")
@@ -67,7 +77,7 @@ module Embulk
67
77
  when :ruby
68
78
  pkg.cp("ruby/Rakefile", "Rakefile")
69
79
  pkg.cp("ruby/Gemfile", "Gemfile")
70
- pkg.cp_erb("ruby/gemspec.erb", "#{project_name}.gemspec")
80
+ pkg.cp_erb("ruby/gemspec.erb", "#{full_project_name}.gemspec")
71
81
  pkg.cp_erb("ruby/#{category}.rb.erb", plugin_path)
72
82
 
73
83
  when :java
@@ -78,18 +88,34 @@ module Embulk
78
88
  pkg.set_executable("gradlew")
79
89
  pkg.cp_erb("java/build.gradle.erb", "build.gradle")
80
90
  pkg.cp_erb("java/plugin_loader.rb.erb", plugin_path)
81
- pkg.cp_erb("java/#{category}.java.erb", "src/main/java/org/embulk/#{embulk_category}/#{java_class_name}.java")
82
- pkg.cp_erb("java/test.java.erb", "src/test/java/org/embulk/#{embulk_category}/Test#{java_class_name}.java")
91
+ pkg.cp_erb("java/#{category}.java.erb", "src/main/java/#{java_package_name.gsub(/\./, '/')}/#{java_class_name}.java")
92
+ pkg.cp_erb("java/test.java.erb", "src/test/java/#{java_package_name.gsub(/\./, '/')}/Test#{java_class_name}.java")
83
93
  end
84
94
 
85
95
  extra_guess_erb.each_pair do |erb,dest|
86
96
  pkg.cp_erb(erb, dest)
87
97
  end
88
98
 
99
+ puts ""
100
+ puts "Plugin template is successfully generated."
101
+
102
+ case language
103
+ when :ruby
104
+ puts "Next steps:"
105
+ puts ""
106
+ puts " $ cd #{full_project_name}"
107
+ puts " $ rake"
108
+ when :java
109
+ puts "Next steps:"
110
+ puts ""
111
+ puts " $ cd #{full_project_name}"
112
+ puts " $ ./gradlew package"
113
+ end
114
+
89
115
  success = true
90
116
  puts ""
91
117
  ensure
92
- FileUtils.rm_rf project_name unless success
118
+ FileUtils.rm_rf full_project_name unless success
93
119
  end
94
120
  end
95
121
  end
@@ -290,9 +290,9 @@ examples:
290
290
  puts ""
291
291
  puts "Run following subcommands to try embulk:"
292
292
  puts ""
293
- puts " 1. guess #{File.join(path, 'example.yml')} -o config.yml"
294
- puts " 2. preview config.yml"
295
- puts " 3. run config.yml"
293
+ puts " 1. embulk guess #{File.join(path, 'example.yml')} -o config.yml"
294
+ puts " 2. embulk preview config.yml"
295
+ puts " 3. embulk run config.yml"
296
296
  puts ""
297
297
 
298
298
  when :new
@@ -35,8 +35,9 @@ TODO: Write short description here.
35
35
 
36
36
  ## Configuration
37
37
 
38
- - **property1**: description (string, required)
39
- - **property2**: description (integer, default: default-value)
38
+ - **option1**: description (integer, required)
39
+ - **option2**: description (string, default: `"myvalue"`)
40
+ - **option3**: description (string, default: `null`)
40
41
 
41
42
  ## Example
42
43
 
@@ -45,46 +46,46 @@ TODO: Write short description here.
45
46
  %when :input, :file_input
46
47
  in:
47
48
  type: <%= name %>
48
- property1: example1
49
- property2: example2
49
+ option1: example1
50
+ option2: example2
50
51
  %when :output, :file_output
51
52
  out:
52
53
  type: <%= name %>
53
- property1: example1
54
- property2: example2
54
+ option1: example1
55
+ option2: example2
55
56
  %when :filter
56
57
  filters:
57
58
  - type: <%= name %>
58
- property1: example1
59
- property2: example2
59
+ option1: example1
60
+ option2: example2
60
61
  %when :parser
61
62
  in:
62
63
  type: any file input plugin type
63
64
  parser:
64
65
  type: <%= name %>
65
- property1: example1
66
- property2: example2
66
+ option1: example1
67
+ option2: example2
67
68
  %when :formatter
68
69
  out:
69
70
  type: any output input plugin type
70
71
  formatter:
71
72
  type: <%= name %>
72
- property1: example1
73
- property2: example2
73
+ option1: example1
74
+ option2: example2
74
75
  %when :decoder
75
76
  in:
76
77
  type: any output input plugin type
77
78
  decoders:
78
79
  - type: <%= name %>
79
- property1: example1
80
- property2: example2
80
+ option1: example1
81
+ option2: example2
81
82
  %when :encoder
82
83
  out:
83
84
  type: any output input plugin type
84
85
  encoders:
85
86
  - type: <%= name %>
86
- property1: example1
87
- property2: example2
87
+ option1: example1
88
+ option2: example2
88
89
  %end
89
90
  ```
90
91
 
@@ -93,7 +94,7 @@ out:
93
94
  (If guess supported) you don't have to write `<%= category %>:` section in the configuration file. After writing `in:` section, you can let embulk guess `<%= category %>:` section using this command:
94
95
 
95
96
  ```
96
- $ embulk gem install <%= project_name %>
97
+ $ embulk gem install <%= full_project_name %>
97
98
  $ embulk guess -g <%= name %> config.yml -o guessed.yml
98
99
  ```
99
100
  %end