embulk 0.6.21 → 0.6.22

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/build.gradle +27 -15
  4. data/embulk-core/build.gradle +17 -1
  5. data/embulk-core/src/main/java/org/embulk/EmbulkEmbed.java +216 -0
  6. data/embulk-core/src/main/java/org/embulk/EmbulkService.java +13 -7
  7. data/embulk-core/src/main/java/org/embulk/command/LiquidTemplate.java +8 -0
  8. data/embulk-core/src/main/java/org/embulk/command/Runner.java +63 -27
  9. data/embulk-core/src/main/java/org/embulk/config/ConfigLoader.java +5 -0
  10. data/embulk-core/src/main/java/org/embulk/config/DataSourceImpl.java +3 -3
  11. data/embulk-core/src/main/java/org/embulk/exec/ExecModule.java +1 -1
  12. data/embulk-core/src/main/java/org/embulk/exec/PooledBufferAllocator.java +3 -1
  13. data/embulk-core/src/main/java/org/embulk/guice/Bootstrap.java +150 -0
  14. data/embulk-core/src/main/java/org/embulk/guice/CloseableInjector.java +22 -0
  15. data/embulk-core/src/main/java/org/embulk/guice/CloseableInjectorProxy.java +47 -0
  16. data/embulk-core/src/main/java/org/embulk/guice/InjectorProxy.java +145 -0
  17. data/embulk-core/src/main/java/org/embulk/guice/LifeCycleManager.java +187 -0
  18. data/embulk-core/src/main/java/org/embulk/guice/LifeCycleMethods.java +89 -0
  19. data/embulk-core/src/main/java/org/embulk/guice/LifeCycleMethodsMap.java +38 -0
  20. data/embulk-core/src/main/java/org/embulk/guice/LifeCycleModule.java +97 -0
  21. data/embulk-core/src/main/java/org/embulk/spi/TempFileSpace.java +41 -7
  22. data/embulk-docs/build.gradle +3 -2
  23. data/embulk-docs/src/built-in.rst +30 -1
  24. data/embulk-docs/src/index.rst +1 -1
  25. data/embulk-docs/src/release.rst +1 -0
  26. data/embulk-docs/src/release/release-0.6.22.rst +26 -0
  27. data/gradle/wrapper/gradle-wrapper.jar +0 -0
  28. data/gradle/wrapper/gradle-wrapper.properties +2 -2
  29. data/lib/embulk/command/embulk_run.rb +11 -5
  30. data/lib/embulk/data_source.rb +28 -8
  31. data/lib/embulk/error.rb +7 -1
  32. data/lib/embulk/gems.rb +29 -0
  33. data/lib/embulk/java/bootstrap.rb +4 -0
  34. data/lib/embulk/java/liquid_helper.rb +17 -0
  35. data/lib/embulk/version.rb +1 -1
  36. data/test/helper.rb +11 -2
  37. metadata +46 -33
@@ -0,0 +1,89 @@
1
+ /*
2
+ * Copyright 2010 Proofpoint, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /*
17
+ * Copyright 2015 Sadayuki Furuhashi
18
+ */
19
+ package org.embulk.guice;
20
+
21
+ import com.google.common.collect.ArrayListMultimap;
22
+ import com.google.common.collect.Lists;
23
+ import com.google.common.collect.Multimap;
24
+
25
+ import javax.annotation.PostConstruct;
26
+ import javax.annotation.PreDestroy;
27
+ import java.lang.annotation.Annotation;
28
+ import java.lang.reflect.Method;
29
+ import java.util.Collection;
30
+ import java.util.HashSet;
31
+ import java.util.Set;
32
+
33
+ class LifeCycleMethods
34
+ {
35
+ private final Multimap<Class<? extends Annotation>, Method> methodMap = ArrayListMultimap.create();
36
+
37
+ LifeCycleMethods(Class<?> clazz)
38
+ {
39
+ addLifeCycleMethods(clazz, new HashSet<String>(), new HashSet<String>());
40
+ }
41
+
42
+ boolean hasFor(Class<? extends Annotation> annotation)
43
+ {
44
+ Collection<Method> methods = methodMap.get(annotation);
45
+ return (methods != null) && (methods.size() > 0);
46
+ }
47
+
48
+ Collection<Method> methodsFor(Class<? extends Annotation> annotation)
49
+ {
50
+ Collection<Method> methods = methodMap.get(annotation);
51
+ return (methods != null) ? methods : Lists.<Method>newArrayList();
52
+ }
53
+
54
+ private void addLifeCycleMethods(Class<?> clazz, Set<String> usedConstructNames, Set<String> usedDestroyNames)
55
+ {
56
+ if (clazz == null) {
57
+ return;
58
+ }
59
+
60
+ for (Method method : clazz.getDeclaredMethods()) {
61
+ if (method.isSynthetic() || method.isBridge()) {
62
+ continue;
63
+ }
64
+
65
+ processMethod(method, PostConstruct.class, usedConstructNames);
66
+ processMethod(method, PreDestroy.class, usedDestroyNames);
67
+ }
68
+
69
+ addLifeCycleMethods(clazz.getSuperclass(), usedConstructNames, usedDestroyNames);
70
+ for (Class<?> face : clazz.getInterfaces()) {
71
+ addLifeCycleMethods(face, usedConstructNames, usedDestroyNames);
72
+ }
73
+ }
74
+
75
+ private void processMethod(Method method, Class<? extends Annotation> annotationClass, Set<String> usedSet)
76
+ {
77
+ if (method.isAnnotationPresent(annotationClass)) {
78
+ if (!usedSet.contains(method.getName())) {
79
+ if (method.getParameterTypes().length != 0) {
80
+ throw new UnsupportedOperationException(String.format("@PostConstruct/@PreDestroy methods cannot have arguments: %s", method.getDeclaringClass().getName() + "." + method.getName() + "(...)"));
81
+ }
82
+
83
+ method.setAccessible(true);
84
+ usedSet.add(method.getName());
85
+ methodMap.put(annotationClass, method);
86
+ }
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,38 @@
1
+ /*
2
+ * Copyright 2010 Proofpoint, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /*
17
+ * Copyright 2015 Sadayuki Furuhashi
18
+ */
19
+ package org.embulk.guice;
20
+
21
+ import com.google.common.collect.Maps;
22
+
23
+ import java.util.Map;
24
+
25
+ class LifeCycleMethodsMap
26
+ {
27
+ private final Map<Class<?>, LifeCycleMethods> map = Maps.newHashMap();
28
+
29
+ synchronized LifeCycleMethods get(Class<?> clazz)
30
+ {
31
+ LifeCycleMethods methods = map.get(clazz);
32
+ if (methods == null) {
33
+ methods = new LifeCycleMethods(clazz);
34
+ map.put(clazz, methods);
35
+ }
36
+ return methods;
37
+ }
38
+ }
@@ -0,0 +1,97 @@
1
+ /*
2
+ * Copyright 2010 Proofpoint, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /*
17
+ * Copyright 2015 Sadayuki Furuhashi
18
+ */
19
+ package org.embulk.guice;
20
+
21
+ import com.google.common.collect.Lists;
22
+ import com.google.inject.Binder;
23
+ import com.google.inject.Module;
24
+ import com.google.inject.Provides;
25
+ import com.google.inject.Singleton;
26
+ import com.google.inject.TypeLiteral;
27
+ import com.google.inject.spi.InjectionListener;
28
+ import com.google.inject.spi.TypeEncounter;
29
+ import com.google.inject.spi.TypeListener;
30
+
31
+ import javax.annotation.PostConstruct;
32
+ import javax.annotation.PreDestroy;
33
+ import java.util.List;
34
+ import java.util.concurrent.atomic.AtomicReference;
35
+
36
+ import static com.google.inject.matcher.Matchers.any;
37
+
38
+ /**
39
+ * Guice module for binding the LifeCycle manager
40
+ */
41
+ public class LifeCycleModule implements Module
42
+ {
43
+ private final List<Object> injectedInstances = Lists.newArrayList();
44
+ private final LifeCycleMethodsMap lifeCycleMethodsMap = new LifeCycleMethodsMap();
45
+ private final AtomicReference<LifeCycleManager> lifeCycleManagerRef = new AtomicReference<LifeCycleManager>(null);
46
+
47
+ @Override
48
+ public void configure(Binder binder)
49
+ {
50
+ binder.disableCircularProxies();
51
+
52
+ binder.bindListener(any(), new TypeListener()
53
+ {
54
+ @Override
55
+ public <T> void hear(TypeLiteral<T> type, TypeEncounter<T> encounter)
56
+ {
57
+ encounter.register(new InjectionListener<T>()
58
+ {
59
+ @Override
60
+ public void afterInjection(T obj)
61
+ {
62
+ if (isLifeCycleClass(obj.getClass())) {
63
+ LifeCycleManager lifeCycleManager = lifeCycleManagerRef.get();
64
+ if (lifeCycleManager != null) {
65
+ try {
66
+ lifeCycleManager.addInstance(obj);
67
+ }
68
+ catch (Exception e) {
69
+ throw new Error(e);
70
+ }
71
+ }
72
+ else {
73
+ injectedInstances.add(obj);
74
+ }
75
+ }
76
+ }
77
+ });
78
+ }
79
+ });
80
+ }
81
+
82
+ @Provides
83
+ @Singleton
84
+ public LifeCycleManager getServerManager()
85
+ throws Exception
86
+ {
87
+ LifeCycleManager lifeCycleManager = new LifeCycleManager(injectedInstances, lifeCycleMethodsMap);
88
+ lifeCycleManagerRef.set(lifeCycleManager);
89
+ return lifeCycleManager;
90
+ }
91
+
92
+ private boolean isLifeCycleClass(Class<?> clazz)
93
+ {
94
+ LifeCycleMethods methods = lifeCycleMethodsMap.get(clazz);
95
+ return methods.hasFor(PostConstruct.class) || methods.hasFor(PreDestroy.class);
96
+ }
97
+ }
@@ -3,6 +3,11 @@ package org.embulk.spi;
3
3
  import java.util.List;
4
4
  import java.util.ArrayList;
5
5
  import java.util.Collections;
6
+ import java.nio.file.Files;
7
+ import java.nio.file.Path;
8
+ import java.nio.file.SimpleFileVisitor;
9
+ import java.nio.file.attribute.BasicFileAttributes;
10
+ import java.nio.file.FileVisitResult;
6
11
  import java.io.File;
7
12
  import java.io.IOException;
8
13
  import com.google.common.base.Preconditions;
@@ -43,14 +48,43 @@ public class TempFileSpace
43
48
 
44
49
  public void cleanup()
45
50
  {
46
- File[] files = dir.listFiles();
47
- if (files != null) {
48
- for (File e : files) {
49
- e.delete();
50
- // TODO delete directory recursively
51
- }
51
+ try {
52
+ deleteFilesIfExistsRecursively(dir);
53
+ }
54
+ catch (IOException ex) {
55
+ // ignore IOException
52
56
  }
53
- dir.delete();
54
57
  dirCreated = false;
55
58
  }
59
+
60
+ private void deleteFilesIfExistsRecursively(File dir)
61
+ throws IOException
62
+ {
63
+ Files.walkFileTree(dir.toPath(), new SimpleFileVisitor<Path>()
64
+ {
65
+ @Override
66
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
67
+ {
68
+ try {
69
+ Files.deleteIfExists(file);
70
+ }
71
+ catch (IOException ex) {
72
+ // ignore IOException
73
+ }
74
+ return FileVisitResult.CONTINUE;
75
+ }
76
+
77
+ @Override
78
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc)
79
+ {
80
+ try {
81
+ Files.deleteIfExists(dir);
82
+ }
83
+ catch (IOException ex) {
84
+ // ignore IOException
85
+ }
86
+ return FileVisitResult.CONTINUE;
87
+ }
88
+ });
89
+ }
56
90
  }
@@ -23,8 +23,9 @@ task javadoc_html(type: Copy, dependsOn: [':embulk-core:javadoc']) {
23
23
 
24
24
  task rdoc_html(type: JRubyExec) {
25
25
  workingDir '..'
26
- jrubyArgs '-ryard', '-eYARD::CLI::Yardoc.run(*ARGV)', '--', '-o', 'embulk-docs/build/html/rdoc'
27
- script 'lib'
26
+ jrubyArgs '-ryard', '-eYARD::CLI::Yardoc.run(*ARGV)'
27
+ script './lib/embulk/version.rb' // dummy
28
+ scriptArgs 'lib', '-o', 'embulk-docs/build/html/rdoc'
28
29
  }
29
30
 
30
31
  task site(type: Copy, dependsOn: ['sphinx_html', 'rdoc_html', 'javadoc_html']) {
@@ -59,6 +59,35 @@ A configuration file consists of following sections:
59
59
  In many cases, what you need to write is **in:**, **out**: and **formatter** sections only because ``guess`` command guesses **parser** and **decoder** options for you. See also the `Quick Start <https://github.com/embulk/embulk#quick-start>`_.
60
60
 
61
61
 
62
+ Using variables
63
+ ~~~~~~~~~~~~~~~~~~
64
+
65
+ You can embed environment variables in configuration file using `Liquid template engine <http://liquidmarkup.org/>`_ (This is experimental feature. Behavior might change or be removed in future releases).
66
+
67
+ To use template engine, configuration file name must end with ``.yml.liquid``.
68
+
69
+ Environment variables are set to ``env`` variable.
70
+
71
+ .. code-block:: yaml
72
+
73
+ in:
74
+ type: file
75
+ path_prefix: {{ env.path_prefix }}
76
+ decoders:
77
+ - {type: gzip}
78
+ parser:
79
+ ...
80
+ out:
81
+ type: postgresql
82
+ host: {{ env.pg_host }}
83
+ port: {{ env.pg_port }}
84
+ user: {{ env.pg_user }}
85
+ password: "{{ env.pg_password }}"
86
+ database: embulk_load
87
+ mode: insert
88
+ table: {{ env.pg_table }}
89
+
90
+
62
91
  Local file input plugin
63
92
  ------------------
64
93
 
@@ -248,7 +277,7 @@ Options
248
277
  +====================+==========+===================================================+============================+
249
278
  | path\_prefix | string | Path prefix of the output files | required |
250
279
  +--------------------+----------+---------------------------------------------------+----------------------------+
251
- | sequence\_format | string | Format of the sequence number of the output files | ``%03d.%02d.`` by default |
280
+ | sequence\_format | string | Format of the sequence number of the output files | ``%03d.%02d.`` by default |
252
281
  +--------------------+----------+---------------------------------------------------+----------------------------+
253
282
  | file\_ext | string | Path suffix of the output files (e.g. ``"csv"``) | required |
254
283
  +--------------------+----------+---------------------------------------------------+----------------------------+
@@ -62,7 +62,7 @@ Documents
62
62
  * `Executor plugins <http://www.embulk.org/plugins/#executor>`_
63
63
 
64
64
  .. toctree::
65
- :maxdepth: 2
65
+ :maxdepth: 3
66
66
 
67
67
  built-in
68
68
 
@@ -4,6 +4,7 @@ Release Notes
4
4
  .. toctree::
5
5
  :maxdepth: 1
6
6
 
7
+ release/release-0.6.22
7
8
  release/release-0.6.21
8
9
  release/release-0.6.20
9
10
  release/release-0.6.19
@@ -0,0 +1,26 @@
1
+ Release 0.6.22
2
+ ==================================
3
+
4
+ General Changes
5
+ ------------------
6
+
7
+ * Added experimental support for Liquid template engine of configuration files. If configuration file name ends with ``.yml.liquid``, embulk runs embeds variables using Liquid template engine.
8
+
9
+ Ruby Plugin API
10
+ ------------------
11
+
12
+ * Added ``Embulk.require_classpath`` method to initialize plugin test environment (@cosmo0920++)
13
+ * ``Embulk::ConfigError`` extends ``org.embulk.config.ConfigException``.
14
+ * ``Embulk::DataSource`` raises ``Embulk::ConfigError`` instead of StandardError.
15
+
16
+ Java Plugin API
17
+ ------------------
18
+
19
+ * Added ``org.embulk.EmbulkEmbed`` to embed Embulk in an applications as a library.
20
+ * Added ``ConfigLoader.newConfigSource`` to create an empty ConfigSource.
21
+ * ``TempFileSpace.cleanup`` deletes files and directories recursively (@cosmo0920++)
22
+
23
+
24
+ Release Date
25
+ ------------------
26
+ 2015-08-11
@@ -1,6 +1,6 @@
1
- #Wed Feb 04 13:46:12 PST 2015
1
+ #Tue Aug 11 00:26:20 PDT 2015
2
2
  distributionBase=GRADLE_USER_HOME
3
3
  distributionPath=wrapper/dists
4
4
  zipStoreBase=GRADLE_USER_HOME
5
5
  zipStorePath=wrapper/dists
6
- distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
6
+ distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip
@@ -206,6 +206,8 @@ examples:
206
206
  args = 0..0
207
207
 
208
208
  when :gem
209
+ require 'embulk/gems'
210
+ Embulk.add_embedded_gem_path
209
211
  require 'rubygems/gem_runner'
210
212
  Gem::GemRunner.new.run argv
211
213
  exit 0
@@ -357,11 +359,7 @@ examples:
357
359
  java.lang.Class.forName('org.embulk.command.Runner')
358
360
  rescue java.lang.ClassNotFoundException
359
361
  # load classpath
360
- classpath_dir = Embulk.home('classpath')
361
- jars = Dir.entries(classpath_dir).select {|f| f =~ /\.jar$/ }.sort
362
- jars.each do |jar|
363
- require File.join(classpath_dir, jar)
364
- end
362
+ Embulk.require_classpath
365
363
  end
366
364
 
367
365
  setup_plugin_paths(plugin_paths)
@@ -390,6 +388,14 @@ examples:
390
388
  end
391
389
  end
392
390
 
391
+ def self.require_classpath
392
+ classpath_dir = Embulk.home("classpath")
393
+ jars = Dir.entries(classpath_dir).select{|f| f =~ /\.jar$/ }.sort
394
+ jars.each do |jar|
395
+ require File.join(classpath_dir, jar)
396
+ end
397
+ end
398
+
393
399
  def self.default_gem_home
394
400
  if RUBY_PLATFORM =~ /java/i
395
401
  user_home = java.lang.System.properties["user.home"]
@@ -142,31 +142,51 @@ module Embulk
142
142
  value =
143
143
  case type
144
144
  when :integer
145
- Integer(v)
145
+ begin
146
+ Integer(v)
147
+ rescue => e
148
+ raise ConfigError, e
149
+ end
146
150
  when :float
147
- Float(v)
151
+ begin
152
+ Float(v)
153
+ rescue => e
154
+ raise ConfigError, e
155
+ end
148
156
  when :string
149
- String(v).dup
157
+ begin
158
+ String(v).dup
159
+ rescue => e
160
+ raise ConfigError, e
161
+ end
150
162
  when :bool
151
- !!v # TODO validation
163
+ begin
164
+ !!v # TODO validation
165
+ rescue => e
166
+ raise ConfigError, e
167
+ end
152
168
  when :hash
153
- raise ArgumentError, "Invalid value for :hash" unless v.is_a?(Hash)
169
+ raise ConfigError, "Invalid value for :hash" unless v.is_a?(Hash)
154
170
  DataSource.new.merge!(v)
155
171
  when :array
156
- raise ArgumentError, "Invalid value for :array" unless v.is_a?(Array)
172
+ raise ConfigError, "Invalid value for :array" unless v.is_a?(Array)
157
173
  v.dup
158
174
  else
159
175
  unless type.respond_to?(:load)
160
176
  raise ArgumentError, "Unknown type #{type.to_s.dump}"
161
177
  end
162
- type.load(v)
178
+ begin
179
+ type.load(v)
180
+ rescue => e
181
+ raise ConfigError, e
182
+ end
163
183
  end
164
184
 
165
185
  elsif options.has_key?(:default)
166
186
  value = options[:default]
167
187
 
168
188
  else
169
- raise "Required field #{key.to_s.dump} is not set"
189
+ raise ConfigError, "Required field #{key.to_s.dump} is not set"
170
190
  end
171
191
 
172
192
  return value