embulk 0.6.11 → 0.6.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d45b70ffc7ebef537906a3f471d74f83d40f18ab
4
- data.tar.gz: 792c390284e3b949d84b4b9860941620ba6d3f2a
3
+ metadata.gz: c73174238cf469f8b78f7e7225d35e2ae9c5d0c0
4
+ data.tar.gz: c3cb6c769f05c1ed0d636b84232018e97a0a955b
5
5
  SHA512:
6
- metadata.gz: c297663fe08c2c1a83d68942facc2c00801fceab5acdf90a12dcef36b37eac272e10964ddf4f2dd6d869adab6cdeca9bc8925d763f51a6b27feac5c43b78ea65
7
- data.tar.gz: ea1a1b4a7c3df3a6f61cb52f2487050d1f2b2a8abf1bf2616b9ee97b2f1d493e2a3b6135f1e32e3d5a0edf40d2a135615be309294e2bc7bdfd6a15c1808a8238
6
+ metadata.gz: 1c17333b98eb2d249a909d4b7603718090a8d0cd4fc8bb087b7c4c3ad712cf05c7e2db4c51bd0947004fc40d0f0052e3eeac33bb569116e16031d5a0aa256809
7
+ data.tar.gz: c439b2981678bcb6698173e535f63baa72411f78e1099b89888a25bd96c758f8d9947622b78cc2506b9369d1086da9598a59a462fa5d15ce6c5569fd06602dca
data/.travis.yml CHANGED
@@ -8,7 +8,7 @@ sudo: false
8
8
  install:
9
9
  - pip install --user sphinx
10
10
  script:
11
- - ./gradlew check rubyTest
11
+ - ./gradlew --info check rubyTest
12
12
  after_success:
13
13
  - PATH="$HOME/.local/bin:$PATH" ./embulk-docs/push-gh-pages.sh
14
14
  env:
data/README.md CHANGED
@@ -126,7 +126,7 @@ If the transaction fails, embulk stores state some states to the yaml file. You
126
126
  embulk run config.yml -r resume-state.yml
127
127
  ```
128
128
 
129
- If you giveup to resume the transaction, you can use `embulk cleanup` subcommand to delete intermediate data:
129
+ If you give up on resuming the transaction, you can use `embulk cleanup` subcommand to delete intermediate data:
130
130
 
131
131
  ```
132
132
  embulk cleanup config.yml -r resume-state.yml
data/build.gradle CHANGED
@@ -11,7 +11,7 @@ def release_projects = [project(":embulk-core"), project(":embulk-standards")]
11
11
 
12
12
  allprojects {
13
13
  group = 'org.embulk'
14
- version = '0.6.11'
14
+ version = '0.6.12'
15
15
 
16
16
  ext {
17
17
  jrubyVersion = '1.7.19'
@@ -21,9 +21,8 @@ dependencies {
21
21
  compile 'com.fasterxml.jackson.datatype:jackson-datatype-guava:2.5.3'
22
22
  compile 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.5.3'
23
23
  compile 'com.fasterxml.jackson.module:jackson-module-guice:2.5.3'
24
- compile 'log4j:log4j:1.2.17'
24
+ compile 'ch.qos.logback:logback-classic:1.1.3'
25
25
  compile 'org.slf4j:slf4j-api:1.7.10'
26
- compile 'org.slf4j:slf4j-log4j12:1.7.10'
27
26
  compile 'org.jruby:jruby-complete:' + project.jrubyVersion
28
27
  compile 'com.google.code.findbugs:annotations:3.0.0'
29
28
  compile 'org.yaml:snakeyaml:1.14'
@@ -32,6 +31,7 @@ dependencies {
32
31
  compile 'io.airlift:slice:0.9'
33
32
  compile 'joda-time:joda-time:2.7'
34
33
  compile 'io.netty:netty-buffer:5.0.0.Alpha1'
34
+ compile 'org.fusesource.jansi:jansi:1.11'
35
35
 
36
36
  // for embulk/guess/charset.rb
37
37
  compile 'com.ibm.icu:icu4j:54.1.1'
@@ -139,7 +139,7 @@ public class GuessExecutor
139
139
  ConfigSource originalConfig = config.deepCopy().merge(lastGuessed);
140
140
  ConfigSource guessInputConfig = originalConfig.deepCopy();
141
141
  guessInputConfig.getNestedOrSetEmpty("parser")
142
- .set("type", "system_guess") // override in.parser.type so that FileInputPlugin creates GuessParserPlugin
142
+ .set("type", "system_guess") // override in.parser.type so that FileInputRunner.run uses GuessParserPlugin
143
143
  .set("guess_plugins", guessPlugins)
144
144
  .set("orig_config", originalConfig);
145
145
 
@@ -153,7 +153,6 @@ public class GuessExecutor
153
153
  if (taskCount == 0) {
154
154
  throw new NoSampleException("No input files to guess");
155
155
  }
156
- // TODO repeat runwith taskIndex++ if NoSampleException happens
157
156
  input.run(inputTaskSource, null, 0, new PageOutput() {
158
157
  @Override
159
158
  public void add(Page page)
@@ -170,6 +169,7 @@ public class GuessExecutor
170
169
  throw new AssertionError("Guess executor must throw GuessedNoticeError");
171
170
  }
172
171
  });
172
+
173
173
  throw new AssertionError("Guess executor must throw GuessedNoticeError");
174
174
 
175
175
  } catch (GuessedNoticeError error) {
@@ -319,6 +319,7 @@ public class GuessExecutor
319
319
 
320
320
  private static Buffer getFirstBuffer(FileInput input)
321
321
  {
322
+ // The first buffer is created by SamplingParserPlugin. See FileInputRunner.guess.
322
323
  RuntimeException decodeException = null;
323
324
  try {
324
325
  while (input.nextFile()) {
@@ -3,7 +3,11 @@ package org.embulk.exec;
3
3
  import java.util.Properties;
4
4
  import org.slf4j.ILoggerFactory;
5
5
  import org.slf4j.LoggerFactory;
6
- import org.apache.log4j.PropertyConfigurator;
6
+ import ch.qos.logback.classic.Level;
7
+ import ch.qos.logback.classic.Logger;
8
+ import ch.qos.logback.classic.LoggerContext;
9
+ import ch.qos.logback.classic.joran.JoranConfigurator;
10
+ import ch.qos.logback.core.joran.spi.JoranException;
7
11
  import com.google.inject.Inject;
8
12
  import com.google.inject.Provider;
9
13
  import org.embulk.config.ConfigSource;
@@ -14,13 +18,9 @@ public class LoggerProvider
14
18
  @Inject
15
19
  public LoggerProvider(@ForSystemConfig ConfigSource systemConfig)
16
20
  {
17
- // TODO system config
18
- Properties prop = new Properties();
19
-
20
21
  final String level;
21
22
  String logLevel = systemConfig.get(String.class, "log_level", "info"); // here can't use loadConfig because ModelManager uses LoggerProvider
22
23
  switch (logLevel) {
23
- case "fatal": level = "FATAL"; break;
24
24
  case "error": level = "ERROR"; break;
25
25
  case "warn": level = "WARN"; break;
26
26
  case "info": level = "INFO"; break;
@@ -28,16 +28,30 @@ public class LoggerProvider
28
28
  case "trace": level = "TRACE"; break;
29
29
  default:
30
30
  throw new IllegalArgumentException(String.format(
31
- "System property embulk.logLevel=%s is invalid. Available levels are fatal, error, warn, info, debug and trace.", logLevel));
31
+ "System property embulk.logLevel=%s is invalid. Available levels are error, warn, info, debug and trace.", logLevel));
32
32
  }
33
33
 
34
- prop.setProperty("log4j.rootLogger", level+",root");
35
- prop.setProperty("log4j.appender.root", "org.apache.log4j.ConsoleAppender");
36
- prop.setProperty("log4j.appender.root.layout", "org.apache.log4j.PatternLayout");
37
- prop.setProperty("log4j.appender.root.layout.ConversionPattern", "%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%p] (%t): %m%n");
34
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
35
+ JoranConfigurator configurator = new JoranConfigurator();
36
+ configurator.setContext(context);
37
+ context.reset();
38
38
 
39
- // TODO
40
- PropertyConfigurator.configure(prop);
39
+ String name;
40
+ if (System.console() != null) {
41
+ name = "/embulk/logback-color.xml";
42
+ } else {
43
+ name = "/embulk/logback-console.xml";
44
+ }
45
+ try {
46
+ configurator.doConfigure(getClass().getResource(name));
47
+ } catch (JoranException ex) {
48
+ throw new RuntimeException(ex);
49
+ }
50
+
51
+ org.slf4j.Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
52
+ if (logger instanceof Logger) {
53
+ ((Logger) logger).setLevel(Level.toLevel(level.toUpperCase(), Level.DEBUG));
54
+ }
41
55
  }
42
56
 
43
57
  public ILoggerFactory get()
@@ -2,6 +2,7 @@ package org.embulk.exec;
2
2
 
3
3
  import java.util.List;
4
4
  import com.google.inject.Inject;
5
+ import com.google.common.base.Preconditions;
5
6
  import org.embulk.config.TaskSource;
6
7
  import org.embulk.config.ConfigSource;
7
8
  import org.embulk.config.CommitReport;
@@ -24,31 +25,9 @@ import static org.embulk.spi.util.Inputs.each;
24
25
  public class SamplingParserPlugin
25
26
  implements ParserPlugin
26
27
  {
27
- private final int maxSampleSize;
28
-
29
- @Inject
30
- public SamplingParserPlugin(@ForSystemConfig ConfigSource systemConfig)
31
- {
32
- this.maxSampleSize = 32*1024; // TODO get sample syze from system config
33
- }
34
-
35
- @Override
36
- public void transaction(ConfigSource config, ParserPlugin.Control control)
37
- {
38
- control.run(Exec.newTaskSource(), null);
39
- }
40
-
41
- @Override
42
- public void run(TaskSource taskSource, Schema schema,
43
- FileInput input, PageOutput output)
44
- {
45
- Buffer buffer = getSample(input, maxSampleSize);
46
- throw new SampledNoticeError(buffer);
47
- }
48
-
49
28
  public static Buffer runFileInputSampling(final FileInputRunner runner, ConfigSource inputConfig)
50
29
  {
51
- // override in.parser.type so that FileInputRunner creates GuessParserPlugin
30
+ // override in.parser.type so that FileInputRunner creates SamplingParserPlugin
52
31
  ConfigSource samplingInputConfig = inputConfig.deepCopy();
53
32
  samplingInputConfig.getNestedOrSetEmpty("parser").set("type", "system_sampling");
54
33
  samplingInputConfig.set("decoders", null);
@@ -60,19 +39,24 @@ public class SamplingParserPlugin
60
39
  if (taskCount == 0) {
61
40
  throw new NoSampleException("No input files to read sample data");
62
41
  }
63
- // TODO repeat runwith taskIndex++ if NoSampleException happens
64
- runner.run(taskSource, schema, 0, new PageOutput() {
65
- @Override
66
- public void add(Page page)
67
- {
68
- throw new RuntimeException("Input plugin must be a FileInputPlugin to guess parser configuration"); // TODO exception class
69
- }
42
+ for (int taskIndex=0; taskIndex < taskCount; taskIndex++) {
43
+ try {
44
+ runner.run(taskSource, schema, taskIndex, new PageOutput() {
45
+ @Override
46
+ public void add(Page page)
47
+ {
48
+ throw new RuntimeException("Input plugin must be a FileInputPlugin to guess parser configuration"); // TODO exception class
49
+ }
70
50
 
71
- public void finish() { }
51
+ public void finish() { }
72
52
 
73
- public void close() { }
74
- });
75
- throw new NoSampleException("No input files to guess parser configuration");
53
+ public void close() { }
54
+ });
55
+ } catch (NotEnoughSampleError ex) {
56
+ continue;
57
+ }
58
+ }
59
+ throw new NoSampleException("All input files are smaller than minimum sampling size"); // TODO include minSampleSize in message
76
60
  }
77
61
  });
78
62
  throw new AssertionError("SamplingParserPlugin must throw SampledNoticeError");
@@ -81,29 +65,6 @@ public class SamplingParserPlugin
81
65
  }
82
66
  }
83
67
 
84
- private static Buffer getSample(FileInput fileInput, int maxSampleSize)
85
- {
86
- if (!fileInput.nextFile()) {
87
- // no input files
88
- return Buffer.EMPTY;
89
- }
90
-
91
- Buffer sample = Buffer.allocate(maxSampleSize);
92
- int sampleSize = 0;
93
-
94
- for (Buffer buffer : each(fileInput)) {
95
- int size = Math.min(buffer.limit(), sample.capacity() - sampleSize);
96
- sample.setBytes(sampleSize, buffer, 0, size);
97
- sampleSize += size;
98
- buffer.release();
99
- if (sampleSize >= maxSampleSize) {
100
- break;
101
- }
102
- }
103
- sample.limit(sampleSize);
104
- return sample;
105
- }
106
-
107
68
  public static class SampledNoticeError
108
69
  extends Error
109
70
  {
@@ -119,4 +80,59 @@ public class SamplingParserPlugin
119
80
  return sample;
120
81
  }
121
82
  }
83
+
84
+ public static class NotEnoughSampleError
85
+ extends Error
86
+ { }
87
+
88
+ private final int minSampleSize;
89
+ private final int sampleSize;
90
+
91
+ @Inject
92
+ public SamplingParserPlugin(@ForSystemConfig ConfigSource systemConfig)
93
+ {
94
+ this.minSampleSize = 40; // empty gzip file is 33 bytes. // TODO get sample size from system config
95
+ this.sampleSize = 32*1024; // TODO get sample size from system config
96
+ Preconditions.checkArgument(minSampleSize < sampleSize, "minSampleSize must be smaller than sampleSize");
97
+ }
98
+
99
+ @Override
100
+ public void transaction(ConfigSource config, ParserPlugin.Control control)
101
+ {
102
+ control.run(Exec.newTaskSource(), null);
103
+ }
104
+
105
+ @Override
106
+ public void run(TaskSource taskSource, Schema schema,
107
+ FileInput input, PageOutput output)
108
+ {
109
+ Buffer buffer = readSample(input, sampleSize);
110
+ if (buffer.limit() < minSampleSize) {
111
+ throw new NotEnoughSampleError();
112
+ }
113
+ throw new SampledNoticeError(buffer);
114
+ }
115
+
116
+ private static Buffer readSample(FileInput fileInput, int sampleSize)
117
+ {
118
+ if (!fileInput.nextFile()) {
119
+ // no input files
120
+ return Buffer.EMPTY;
121
+ }
122
+
123
+ Buffer sample = Buffer.allocate(sampleSize);
124
+ int offset = 0;
125
+
126
+ for (Buffer buffer : each(fileInput)) {
127
+ int size = Math.min(buffer.limit(), sample.capacity() - offset);
128
+ sample.setBytes(offset, buffer, 0, size);
129
+ offset += size;
130
+ buffer.release();
131
+ if (offset >= sampleSize) {
132
+ break;
133
+ }
134
+ }
135
+ sample.limit(offset);
136
+ return sample;
137
+ }
122
138
  }
@@ -4,6 +4,7 @@ import java.util.List;
4
4
  import java.util.ArrayList;
5
5
  import java.util.Set;
6
6
  import java.io.File;
7
+ import org.slf4j.ILoggerFactory;
7
8
  import com.google.common.collect.ImmutableSet;
8
9
  import com.google.inject.Module;
9
10
  import com.google.inject.Binder;
@@ -98,6 +99,14 @@ public class JRubyScriptingModule
98
99
  // load embulk.rb
99
100
  jruby.runScriptlet("require 'embulk'");
100
101
 
102
+ // initialize logger
103
+ jruby.callMethod(
104
+ jruby.runScriptlet("Embulk"),
105
+ "logger=",
106
+ jruby.callMethod(
107
+ jruby.runScriptlet("Embulk::Logger"),
108
+ "new", injector.getInstance(ILoggerFactory.class).getLogger("ruby")));
109
+
101
110
  return jruby;
102
111
  }
103
112
 
@@ -89,7 +89,7 @@ public class Exec
89
89
  return session().newTaskSource();
90
90
  }
91
91
 
92
- public boolean isPreview()
92
+ public static boolean isPreview()
93
93
  {
94
94
  return session().isPreview();
95
95
  }
@@ -3,4 +3,8 @@ package org.embulk.spi.time;
3
3
  public class TimestampParseException
4
4
  extends Exception
5
5
  {
6
+ public TimestampParseException(String message)
7
+ {
8
+ super(message);
9
+ }
6
10
  }
@@ -54,7 +54,7 @@ public class TimestampParser
54
54
  // TODO cache parsed zone?
55
55
  timeZone = parseDateTimeZone(zone);
56
56
  if (timeZone == null) {
57
- throw new TimestampParseException();
57
+ throw new TimestampParseException("Invalid time zone name '" + text + "'");
58
58
  }
59
59
  }
60
60
 
@@ -0,0 +1,72 @@
1
+ <configuration>
2
+ <appender name="console-error" class="ch.qos.logback.core.ConsoleAppender">
3
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
4
+ <level>ERROR</level>
5
+ <onMatch>ACCEPT</onMatch>
6
+ <onMismatch>DENY</onMismatch>
7
+ </filter>
8
+ <withJansi>true</withJansi>
9
+ <encoder>
10
+ <pattern>%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n)</pattern>
11
+ </encoder>
12
+ </appender>
13
+
14
+ <appender name="console-warn" class="ch.qos.logback.core.ConsoleAppender">
15
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
16
+ <level>WARN</level>
17
+ <onMatch>ACCEPT</onMatch>
18
+ <onMismatch>DENY</onMismatch>
19
+ </filter>
20
+ <withJansi>true</withJansi>
21
+ <encoder>
22
+ <pattern>%yellow(%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n)</pattern>
23
+ </encoder>
24
+ </appender>
25
+
26
+ <appender name="console-info" class="ch.qos.logback.core.ConsoleAppender">
27
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
28
+ <level>INFO</level>
29
+ <onMatch>ACCEPT</onMatch>
30
+ <onMismatch>DENY</onMismatch>
31
+ </filter>
32
+ <withJansi>true</withJansi>
33
+ <encoder>
34
+ <pattern>%green(%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n)</pattern>
35
+ </encoder>
36
+ </appender>
37
+
38
+ <appender name="console-debug" class="ch.qos.logback.core.ConsoleAppender">
39
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
40
+ <level>DEBUG</level>
41
+ <onMatch>ACCEPT</onMatch>
42
+ <onMismatch>DENY</onMismatch>
43
+ </filter>
44
+ <withJansi>true</withJansi>
45
+ <encoder>
46
+ <pattern>%white(%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n)</pattern>
47
+ </encoder>
48
+ </appender>
49
+
50
+ <appender name="console-trace" class="ch.qos.logback.core.ConsoleAppender">
51
+ <filter class="ch.qos.logback.classic.filter.LevelFilter">
52
+ <level>TRACE</level>
53
+ <onMatch>ACCEPT</onMatch>
54
+ <onMismatch>DENY</onMismatch>
55
+ </filter>
56
+ <withJansi>true</withJansi>
57
+ <encoder>
58
+ <pattern>%blue(%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n)</pattern>
59
+ </encoder>
60
+ </appender>
61
+
62
+ <logger name="io.netty.util" level="INFO"/>
63
+ <logger name="io.netty.buffer" level="INFO"/>
64
+
65
+ <root>
66
+ <appender-ref ref="console-error"/>
67
+ <appender-ref ref="console-warn"/>
68
+ <appender-ref ref="console-info"/>
69
+ <appender-ref ref="console-debug"/>
70
+ <appender-ref ref="console-trace"/>
71
+ </root>
72
+ </configuration>
@@ -0,0 +1,14 @@
1
+ <configuration>
2
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
3
+ <encoder>
4
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n</pattern>
5
+ </encoder>
6
+ </appender>
7
+
8
+ <logger name="io.netty.util" level="INFO"/>
9
+ <logger name="io.netty.buffer" level="INFO"/>
10
+
11
+ <root>
12
+ <appender-ref ref="console"/>
13
+ </root>
14
+ </configuration>
@@ -0,0 +1,25 @@
1
+ <configuration>
2
+ <property name="embulk.logFile" value="embulk.log" />
3
+
4
+ <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
5
+ <file>${embulk.logFile}</file>
6
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
7
+ <maxFileSize>5kB</maxFileSize>
8
+ </triggeringPolicy>
9
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
10
+ <fileNamePattern>${embulk.logFile}.%i</fileNamePattern>
11
+ <minIndex>1</minIndex>
12
+ <maxIndex>5</maxIndex>
13
+ </rollingPolicy>
14
+ <encoder>
15
+ <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS Z} [%level] (%thread\): %m%n</pattern>
16
+ </encoder>
17
+ </appender>
18
+
19
+ <logger name="io.netty.util" level="INFO"/>
20
+ <logger name="io.netty.buffer" level="INFO"/>
21
+
22
+ <root>
23
+ <appender-ref ref="file"/>
24
+ </root>
25
+ </configuration>
@@ -4,6 +4,7 @@ Release Notes
4
4
  .. toctree::
5
5
  :maxdepth: 1
6
6
 
7
+ release/release-0.6.12
7
8
  release/release-0.6.11
8
9
  release/release-0.6.10
9
10
  release/release-0.6.9
@@ -0,0 +1,31 @@
1
+ Release 0.6.12
2
+ ==================================
3
+
4
+ Plugin API
5
+ ------------------
6
+
7
+ * Plugins can use both ``config[:key]`` (``task[:key]``) and ``config['key']`` (``task['key']``).
8
+ * Added ``Embulk.logger`` for Ruby plugins
9
+
10
+
11
+ Built-in plugins
12
+ ------------------
13
+
14
+ * ``guess-csv`` plugin does not raise exceptions when a file has only 1 line
15
+ * ``parser-csv`` shows number of lines using 1-origin indexing rather than 0-origin
16
+
17
+
18
+ General Changes
19
+ ------------------
20
+
21
+ * Guessing skips files smaller than 40 bytes so that guessing works when there is an empty file at the beginning.
22
+ * Uses ANSI color for log messages
23
+ * Uses logback instead of log4j for logging backend
24
+ * Added ``spi.Exec.isPreview()`` as an alias of ``spi.Exec.session().isPreview()``
25
+ * Plugin template for Ruby uses Xxx instead of XxxInputPlugin for the class name so that class name matches with file name.
26
+ * When parsing timestamp fails, exception message includes the original text (@yyamano++)
27
+
28
+
29
+ Release Date
30
+ ------------------
31
+ 2015-06-22
@@ -53,7 +53,8 @@ public class CsvTokenizer
53
53
 
54
54
  public long getCurrentLineNumber()
55
55
  {
56
- return lineNumber;
56
+ // returns actual line number. Internally, lineNumber starts at 0.
57
+ return lineNumber + 1;
57
58
  }
58
59
 
59
60
  // returns skipped line
data/lib/embulk.rb CHANGED
@@ -9,8 +9,9 @@ module Embulk
9
9
  end
10
10
  end
11
11
 
12
+ require 'embulk/logger'
12
13
  require 'embulk/error'
13
- require 'embulk/plugin'
14
14
  require 'embulk/buffer'
15
15
  require 'embulk/data_source'
16
+ require 'embulk/plugin'
16
17
  end
@@ -26,7 +26,7 @@ module Embulk
26
26
  email = `git config user.email`.strip
27
27
  email = "YOUR_NAME" if email.empty?
28
28
 
29
- ruby_class_name = name.split('-').map {|a| a.capitalize }.join + category.to_s.split('_').map {|a| a.capitalize }.join + "Plugin"
29
+ ruby_class_name = name.split('-').map {|a| a.capitalize }.join
30
30
  java_iface = category.to_s.split('_').map {|a| a.capitalize }.join
31
31
  java_class_name = name.split('-').map {|a| a.capitalize }.join + java_iface + "Plugin"
32
32
  display_name = name.split('-').map {|a| a.capitalize }.join(' ')
@@ -68,7 +68,7 @@ module Embulk
68
68
 
69
69
  when :run
70
70
  op.banner = "Usage: run <config.yml>"
71
- op.on('-l', '--log-level LEVEL', 'Log level (fatal, error, warn, info, debug or trace)') do |level|
71
+ op.on('-l', '--log-level LEVEL', 'Log level (error, warn, info, debug or trace)') do |level|
72
72
  options[:logLevel] = level
73
73
  end
74
74
  op.on('-L', '--load PATH', 'Add a local plugin path') do |plugin_path|
@@ -90,7 +90,7 @@ module Embulk
90
90
 
91
91
  when :cleanup
92
92
  op.banner = "Usage: cleanup <config.yml>"
93
- op.on('-l', '--log-level LEVEL', 'Log level (fatal, error, warn, info, debug or trace)') do |level|
93
+ op.on('-l', '--log-level LEVEL', 'Log level (error, warn, info, debug or trace)') do |level|
94
94
  options[:logLevel] = level
95
95
  end
96
96
  op.on('-L', '--load PATH', 'Add a local plugin path') do |plugin_path|
@@ -109,7 +109,7 @@ module Embulk
109
109
 
110
110
  when :preview
111
111
  op.banner = "Usage: preview <config.yml>"
112
- op.on('-l', '--log-level LEVEL', 'Log level (fatal, error, warn, info, debug or trace)') do |level|
112
+ op.on('-l', '--log-level LEVEL', 'Log level (error, warn, info, debug or trace)') do |level|
113
113
  options[:logLevel] = level
114
114
  end
115
115
  op.on('-L', '--load PATH', 'Add a local plugin path') do |plugin_path|
@@ -128,7 +128,7 @@ module Embulk
128
128
 
129
129
  when :guess
130
130
  op.banner = "Usage: guess <partial-config.yml>"
131
- op.on('-l', '--log-level LEVEL', 'Log level (fatal, error, warn, info, debug or trace)') do |level|
131
+ op.on('-l', '--log-level LEVEL', 'Log level (error, warn, info, debug or trace)') do |level|
132
132
  options[:logLevel] = level
133
133
  end
134
134
  op.on('-o', '--output PATH', 'Path to a file to write the guessed configuration') do |path|
@@ -1,7 +1,141 @@
1
1
  module Embulk
2
2
  require 'json'
3
3
 
4
+ module Impl
5
+ # copied from https://github.com/intridea/hashie/blob/da232547c29673a0d7a79c7bf2670f1ea76813ed/lib/hashie/extensions/indifferent_access.rb
6
+ module IndifferentAccess
7
+ def self.included(base)
8
+ #Hashie::Extensions::Dash::IndifferentAccess::ClassMethods.tap do |extension|
9
+ # base.extend(extension) if base <= Hashie::Dash && !base.singleton_class.included_modules.include?(extension)
10
+ #end
11
+
12
+ base.class_eval do
13
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
14
+ alias_method :[]=, :indifferent_writer
15
+ alias_method :store, :indifferent_writer
16
+ %w(default update replace fetch delete key? values_at).each do |m|
17
+ alias_method "regular_#{m}", m unless method_defined?("regular_#{m}")
18
+ alias_method m, "indifferent_#{m}"
19
+ end
20
+
21
+ %w(include? member? has_key?).each do |key_alias|
22
+ alias_method key_alias, :indifferent_key?
23
+ end
24
+
25
+ class << self
26
+ def [](*)
27
+ super.convert!
28
+ end
29
+
30
+ def try_convert(*)
31
+ (hash = super) && self[hash]
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.inject!(hash)
38
+ (class << hash; self; end).send :include, IndifferentAccess
39
+ hash.convert!
40
+ end
41
+
42
+ # Injects indifferent access into a duplicate of the hash
43
+ # provided. See #inject!
44
+ def self.inject(hash)
45
+ inject!(hash.dup)
46
+ end
47
+
48
+ def convert_key(key)
49
+ key.to_s
50
+ end
51
+
52
+ def convert!
53
+ keys.each do |k|
54
+ regular_writer convert_key(k), indifferent_value(regular_delete(k))
55
+ end
56
+ self
57
+ end
58
+
59
+ def indifferent_value(value)
60
+ if hash_lacking_indifference?(value)
61
+ IndifferentAccess.inject!(value)
62
+ elsif value.is_a?(::Array)
63
+ value.replace(value.map { |e| indifferent_value(e) })
64
+ else
65
+ value
66
+ end
67
+ end
68
+
69
+ def indifferent_default(key = nil)
70
+ return self[convert_key(key)] if key?(key)
71
+ regular_default(key)
72
+ end
73
+
74
+ def indifferent_update(other_hash)
75
+ return regular_update(other_hash) if hash_with_indifference?(other_hash)
76
+ other_hash.each_pair do |k, v|
77
+ self[k] = v
78
+ end
79
+ end
80
+
81
+ def indifferent_writer(key, value)
82
+ regular_writer convert_key(key), indifferent_value(value)
83
+ end
84
+
85
+ def indifferent_fetch(key, *args, &block)
86
+ regular_fetch convert_key(key), *args, &block
87
+ end
88
+
89
+ def indifferent_delete(key)
90
+ regular_delete convert_key(key)
91
+ end
92
+
93
+ def indifferent_key?(key)
94
+ regular_key? convert_key(key)
95
+ end
96
+
97
+ def indifferent_values_at(*indices)
98
+ indices.map { |i| self[i] }
99
+ end
100
+
101
+ def indifferent_access?
102
+ true
103
+ end
104
+
105
+ def indifferent_replace(other_hash)
106
+ (keys - other_hash.keys).each { |key| delete(key) }
107
+ other_hash.each { |key, value| self[key] = value }
108
+ self
109
+ end
110
+
111
+ protected
112
+
113
+ def hash_lacking_indifference?(other)
114
+ other.is_a?(::Hash) &&
115
+ !(other.respond_to?(:indifferent_access?) &&
116
+ other.indifferent_access?)
117
+ end
118
+
119
+ def hash_with_indifference?(other)
120
+ other.is_a?(::Hash) &&
121
+ other.respond_to?(:indifferent_access?) &&
122
+ other.indifferent_access?
123
+ end
124
+ end
125
+ end
126
+
4
127
  class DataSource < Hash
128
+ include Impl::IndifferentAccess
129
+
130
+ def initialize(hash={}, default=nil, &block)
131
+ if default.nil?
132
+ super(&block)
133
+ else
134
+ super(default)
135
+ end
136
+ hash.each {|key,value| self[key] = value }
137
+ end
138
+
5
139
  def param(key, type, options={})
6
140
  if self.has_key?(key)
7
141
  v = self[key]
@@ -68,7 +68,7 @@ module Embulk
68
68
  comment_line_marker, sample_records = guess_comment_line_marker(sample_records)
69
69
 
70
70
  first_types = SchemaGuess.types_from_array_records(sample_records[0, 1])
71
- other_types = SchemaGuess.types_from_array_records(sample_records[1..-1])
71
+ other_types = SchemaGuess.types_from_array_records(sample_records[1..-1] || [])
72
72
 
73
73
  if first_types.size <= 1 || other_types.size <= 1
74
74
  # guess failed
@@ -26,7 +26,7 @@ module Embulk
26
26
  def strptimeUsec(text)
27
27
  hash = Date._strptime(text, @format_string)
28
28
  unless hash
29
- raise Java::TimestampParseException.new
29
+ raise Java::TimestampParseException.new("Failed to parse '" + text + "'")
30
30
  end
31
31
 
32
32
  if seconds = hash[:seconds]
@@ -0,0 +1,152 @@
1
+
2
+ module Embulk
3
+ require 'logger'
4
+
5
+ class Logger
6
+ def initialize(*args)
7
+ if args.length == 1
8
+ a = args[0]
9
+ if a.is_a?(Adapter)
10
+ @logger = a
11
+ elsif a.is_a?(::Logger)
12
+ @logger = StandardLoggerAdapter.new(a)
13
+ elsif Embulk.java? && (org.slf4j.Logger rescue nil) && a.is_a?(org.slf4j.Logger)
14
+ @logger = Slf4jAdapter.new(a)
15
+ else
16
+ @logger = StandardLoggerAdapter.new(*args)
17
+ end
18
+ else
19
+ @logger = StandardLoggerAdapter.new(*args)
20
+ end
21
+ end
22
+
23
+ module Adapter
24
+ end
25
+
26
+ def error(message=nil, &block) @logger.error(message, &block) end
27
+ def warn(message=nil, &block) @logger.warn(message, &block) end
28
+ def info(message=nil, &block) @logger.info(message, &block) end
29
+ def debug(message=nil, &block) @logger.debug(message, &block) end
30
+ def trace(message=nil, &block) @logger.trace(message, &block) end
31
+
32
+ def error?() @logger.error? end
33
+ def warn?() @logger.warn? end
34
+ def info?() @logger.info? end
35
+ def debug?() @logger.debug? end
36
+ def trace?() @logger.trace? end
37
+ end
38
+
39
+ class StandardLoggerAdapter < ::Logger
40
+ include Logger::Adapter
41
+
42
+ def initialize(*args)
43
+ super
44
+ if Embulk.java?
45
+ self.formatter = lambda do |severity,datetime,progname,message|
46
+ "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%3N %z")} [#{severity}] (#{java.lang.Thread.currentThread.name}): #{message}\n"
47
+ end
48
+ else
49
+ self.formatter = lambda do |severity,datetime,progname,message|
50
+ "#{datetime.strftime("%Y-%m-%d %H:%M:%S.%3N %z")} [#{severity}]: #{message}\n"
51
+ end
52
+ end
53
+ end
54
+
55
+ def trace(message, &block)
56
+ debug(message, &block)
57
+ end
58
+
59
+ def trace?
60
+ debug?
61
+ end
62
+ end
63
+
64
+ class Slf4jAdapter
65
+ include Logger::Adapter
66
+
67
+ def initialize(logger)
68
+ @logger = logger
69
+ end
70
+
71
+ def error(message, &block)
72
+ if block
73
+ if @logger.isErrorEnabled
74
+ @logger.error(block.call)
75
+ end
76
+ else
77
+ @logger.error(message)
78
+ end
79
+ end
80
+
81
+ def warn(message, &block)
82
+ if block
83
+ if @logger.isWarnEnabled
84
+ @logger.warn(block.call)
85
+ end
86
+ else
87
+ @logger.warn(message)
88
+ end
89
+ end
90
+
91
+ def info(message, &block)
92
+ if block
93
+ if @logger.isInfoEnabled
94
+ @logger.info(block.call)
95
+ end
96
+ else
97
+ @logger.info(message)
98
+ end
99
+ end
100
+
101
+ def debug(message, &block)
102
+ if block
103
+ if @logger.isDebugEnabled
104
+ @logger.debug(block.call)
105
+ end
106
+ else
107
+ @logger.debug(message)
108
+ end
109
+ end
110
+
111
+ def trace(message, &block)
112
+ if block
113
+ if @logger.isTraceEnabled
114
+ @logger.trace(block.call)
115
+ end
116
+ else
117
+ @logger.trace(message)
118
+ end
119
+ end
120
+
121
+ def fatal?
122
+ @logger.isErrorEnabled()
123
+ end
124
+
125
+ def error?
126
+ @logger.isErrorEnabled()
127
+ end
128
+
129
+ def warn?
130
+ @logger.isWarnEnabled()
131
+ end
132
+
133
+ def debug?
134
+ @logger.isDebugEnabled()
135
+ end
136
+
137
+ def trace?
138
+ @logger.isTraceEnabled()
139
+ end
140
+ end
141
+
142
+ def self.logger
143
+ @@logger
144
+ end
145
+
146
+ def self.logger=(logger)
147
+ @@logger = logger
148
+ end
149
+
150
+ # default logger
151
+ @@logger = Logger.new(STDOUT)
152
+ end
@@ -1,6 +1,7 @@
1
1
 
2
2
  module Embulk
3
3
  require 'embulk/error'
4
+ require 'embulk/logger'
4
5
 
5
6
  class PluginRegistry
6
7
  def initialize(category, search_prefix)
@@ -80,10 +81,9 @@ module Embulk
80
81
  end
81
82
 
82
83
  def show_loaded_gems
83
- # TODO use logger
84
84
  Gem.loaded_specs.each do |name,spec|
85
85
  if !@loaded_gems[name] && name =~ /^embulk/
86
- puts "#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%3N %z")}: Loaded plugin #{name} (#{spec.version})"
86
+ Embulk.logger.info "Loaded plugin #{name} (#{spec.version})"
87
87
  @loaded_gems[name] = true
88
88
  end
89
89
  end
@@ -1,3 +1,3 @@
1
1
  module Embulk
2
- VERSION = '0.6.11'
2
+ VERSION = '0.6.12'
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.6.11
4
+ version: 0.6.12
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-05-31 00:00:00.000000000 Z
11
+ date: 2015-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -232,6 +232,9 @@ files:
232
232
  - embulk-core/src/main/java/org/embulk/spi/util/Pages.java
233
233
  - embulk-core/src/main/java/org/embulk/spi/util/ResumableInputStream.java
234
234
  - embulk-core/src/main/java/org/embulk/spi/util/RetryExecutor.java
235
+ - embulk-core/src/main/resources/embulk/logback-color.xml
236
+ - embulk-core/src/main/resources/embulk/logback-console.xml
237
+ - embulk-core/src/main/resources/embulk/logback-file.xml
235
238
  - embulk-core/src/test/java/org/embulk/EmbulkTestRuntime.java
236
239
  - embulk-core/src/test/java/org/embulk/GuiceBinder.java
237
240
  - embulk-core/src/test/java/org/embulk/RandomManager.java
@@ -297,6 +300,7 @@ files:
297
300
  - embulk-docs/src/release/release-0.6.1.rst
298
301
  - embulk-docs/src/release/release-0.6.10.rst
299
302
  - embulk-docs/src/release/release-0.6.11.rst
303
+ - embulk-docs/src/release/release-0.6.12.rst
300
304
  - embulk-docs/src/release/release-0.6.2.rst
301
305
  - embulk-docs/src/release/release-0.6.3.rst
302
306
  - embulk-docs/src/release/release-0.6.4.rst
@@ -394,6 +398,7 @@ files:
394
398
  - lib/embulk/java/imports.rb
395
399
  - lib/embulk/java/time_helper.rb
396
400
  - lib/embulk/java_plugin.rb
401
+ - lib/embulk/logger.rb
397
402
  - lib/embulk/output_plugin.rb
398
403
  - lib/embulk/page.rb
399
404
  - lib/embulk/page_builder.rb
@@ -412,8 +417,8 @@ files:
412
417
  - classpath/bval-jsr303-0.5.jar
413
418
  - classpath/commons-beanutils-core-1.8.3.jar
414
419
  - classpath/commons-lang3-3.1.jar
415
- - classpath/embulk-core-0.6.11.jar
416
- - classpath/embulk-standards-0.6.11.jar
420
+ - classpath/embulk-core-0.6.12.jar
421
+ - classpath/embulk-standards-0.6.12.jar
417
422
  - classpath/guava-18.0.jar
418
423
  - classpath/guice-4.0.jar
419
424
  - classpath/guice-multibindings-4.0.jar
@@ -424,14 +429,15 @@ files:
424
429
  - classpath/jackson-datatype-guava-2.5.3.jar
425
430
  - classpath/jackson-datatype-joda-2.5.3.jar
426
431
  - classpath/jackson-module-guice-2.5.3.jar
432
+ - classpath/jansi-1.11.jar
427
433
  - classpath/javax.inject-1.jar
428
434
  - classpath/joda-time-2.7.jar
429
435
  - classpath/jruby-complete-1.7.19.jar
430
- - classpath/log4j-1.2.17.jar
436
+ - classpath/logback-classic-1.1.3.jar
437
+ - classpath/logback-core-1.1.3.jar
431
438
  - classpath/netty-buffer-5.0.0.Alpha1.jar
432
439
  - classpath/netty-common-5.0.0.Alpha1.jar
433
440
  - classpath/slf4j-api-1.7.10.jar
434
- - classpath/slf4j-log4j12-1.7.10.jar
435
441
  - classpath/slice-0.9.jar
436
442
  - classpath/snakeyaml-1.14.jar
437
443
  - classpath/validation-api-1.1.0.Final.jar