embulk 0.6.16 → 0.6.17

Sign up to get free protection for your applications and to get access to all the features.
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