embulk 0.8.26-java → 0.8.27-java

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: 67e9c5003f422b52f56fd7347f77dda2ea07d86e
4
- data.tar.gz: ac13f8e09bcc9998ba716fc96e6e98e0546605ef
3
+ metadata.gz: 61453ab9514646a642d390b971aeca9cb45ea066
4
+ data.tar.gz: 6c034da535e1687bcf3f6f9a75f12557b73d1f17
5
5
  SHA512:
6
- metadata.gz: 6a275c7189877da26bed04a116dab321b0bf5d9c8f378143aa743c2fa05ae0806fb8d27eabaad76c6bdd7b06971a1b8f5ea2aa8a52152aa7e67a129545e417bc
7
- data.tar.gz: 6ce56d2cfec57fc2db846f7be7aaf5209e30ac5180b28f0d9930f7cebd333f614e443dcb1e57b49bc58683e4b1a595239809bbe50d4915f9bd21e5d59597abb7
6
+ metadata.gz: 10c5d683990626cbe25dcfc6dcdc5f967d74d7420743f6c33ba1a1997765156b5e4ee1a0914737baa4f1ba80206864e404941b309e1b1efb9c05e2efae293c87
7
+ data.tar.gz: 9f21b019c2752622b0108b649859fbb1a39ea2420c2381e71df50ec683ee7f9a742fe0038096a5e6cf0e294fe5068ddf6f32ca8ee9e71bfd6f83cc01167b5027
@@ -11,12 +11,12 @@ apply plugin: "com.github.jruby-gradle.jar"
11
11
  apply plugin: 'com.jfrog.bintray'
12
12
  apply plugin: 'com.github.johnrengelman.shadow'
13
13
 
14
- def java_projects = [project(":embulk-core"), project(":embulk-standards"), project(":embulk-cli"), project(":embulk-test")]
15
- def release_projects = [project(":embulk-core"), project(":embulk-standards"), project(":embulk-test")]
14
+ def java_projects = [project(":embulk-core"), project(":embulk-standards"), project(":embulk-cli"), project(":embulk-test"), project(":embulk-jruby-strptime")]
15
+ def release_projects = [project(":embulk-core"), project(":embulk-standards"), project(":embulk-test"), project(":embulk-jruby-strptime")]
16
16
 
17
17
  allprojects {
18
18
  group = 'org.embulk'
19
- version = '0.8.26'
19
+ version = '0.8.27'
20
20
 
21
21
  ext {
22
22
  jrubyVersion = '9.1.5.0'
@@ -28,6 +28,7 @@ allprojects {
28
28
 
29
29
  test {
30
30
  maxHeapSize = "1536m"
31
+ forkEvery = 1 // test processes are forked by each test class (default is 0)
31
32
  }
32
33
 
33
34
  //
@@ -16,6 +16,8 @@ import com.github.jrubygradle.JRubyPrepare
16
16
 
17
17
  // determine which dependencies have updates: $ gradle dependencyUpdates
18
18
  dependencies {
19
+ compile project(':embulk-jruby-strptime')
20
+
19
21
  compile 'org.embulk:guice-bootstrap:0.1.1'
20
22
  compile 'com.google.guava:guava:18.0'
21
23
  compile 'com.google.inject:guice:4.0'
@@ -1,18 +1,24 @@
1
1
  package org.embulk.spi.time;
2
2
 
3
+ import com.google.common.annotations.VisibleForTesting;
4
+ import com.google.common.base.Optional;
5
+ import java.text.ParseException;
6
+ import java.text.SimpleDateFormat;
7
+ import java.util.Calendar;
3
8
  import java.util.Date;
9
+ import java.util.List;
4
10
  import java.util.Locale;
5
11
  import java.util.TimeZone;
6
- import java.util.Calendar;
7
- import java.text.SimpleDateFormat;
8
- import java.text.ParseException;
9
- import org.joda.time.DateTimeZone;
10
- import com.google.common.base.Optional;
11
- import org.jruby.embed.ScriptingContainer;
12
12
  import org.embulk.config.Config;
13
- import org.embulk.config.ConfigInject;
14
13
  import org.embulk.config.ConfigDefault;
15
14
  import org.embulk.config.ConfigException;
15
+ import org.embulk.config.ConfigInject;
16
+ import org.embulk.spi.time.StrptimeParser.FormatBag;
17
+ import org.joda.time.DateTime;
18
+ import org.joda.time.DateTimeZone;
19
+ import org.jruby.embed.ScriptingContainer;
20
+
21
+ import static com.google.common.base.Strings.isNullOrEmpty;
16
22
  import static org.embulk.spi.time.TimestampFormat.parseDateTimeZone;
17
23
 
18
24
  public class TimestampParser
@@ -62,8 +68,11 @@ public class TimestampParser
62
68
  public Optional<String> getDate();
63
69
  }
64
70
 
65
- private final JRubyTimeParserHelper helper;
66
71
  private final DateTimeZone defaultTimeZone;
72
+ private final String format;
73
+ private final StrptimeParser parser;
74
+ private final Calendar calendar;
75
+ private final List<StrptimeToken> compiledPattern;
67
76
 
68
77
  @Deprecated
69
78
  public TimestampParser(String format, ParserTask task)
@@ -71,9 +80,11 @@ public class TimestampParser
71
80
  this(task.getJRuby(), format, task.getDefaultTimeZone());
72
81
  }
73
82
 
74
- TimestampParser(Task task)
83
+ @VisibleForTesting
84
+ static TimestampParser createTimestampParserForTesting(Task task)
85
+
75
86
  {
76
- this(task.getJRuby(), task.getDefaultTimestampFormat(), task.getDefaultTimeZone(), task.getDefaultDate());
87
+ return new TimestampParser(task.getJRuby(), task.getDefaultTimestampFormat(), task.getDefaultTimeZone(), task.getDefaultDate());
77
88
  }
78
89
 
79
90
  public TimestampParser(Task task, TimestampColumnOption columnOption)
@@ -91,7 +102,11 @@ public class TimestampParser
91
102
 
92
103
  public TimestampParser(ScriptingContainer jruby, String format, DateTimeZone defaultTimeZone, String defaultDate)
93
104
  {
94
- JRubyTimeParserHelperFactory helperFactory = (JRubyTimeParserHelperFactory) jruby.runScriptlet("Embulk::Java::TimeParserHelper::Factory.new");
105
+ // TODO get default current time from ExecTask.getExecTimestamp
106
+ this.format = format;
107
+ this.parser = new StrptimeParser();
108
+ this.compiledPattern = this.parser.compilePattern(format);
109
+ this.defaultTimeZone = defaultTimeZone;
95
110
 
96
111
  // calculate default date
97
112
  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
@@ -103,15 +118,8 @@ public class TimestampParser
103
118
  catch (ParseException ex) {
104
119
  throw new ConfigException("Invalid date format. Expected yyyy-MM-dd: " + defaultDate);
105
120
  }
106
- Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
107
- cal.setTime(utc);
108
- int year = cal.get(Calendar.YEAR);
109
- int month = cal.get(Calendar.MONTH) + 1;
110
- int day = cal.get(Calendar.DAY_OF_MONTH);
111
-
112
- // TODO get default current time from ExecTask.getExecTimestamp
113
- this.helper = (JRubyTimeParserHelper) helperFactory.newInstance(format, year, month, day, 0, 0, 0, 0); // TODO default time zone
114
- this.defaultTimeZone = defaultTimeZone;
121
+ this.calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
122
+ this.calendar.setTime(utc);
115
123
  }
116
124
 
117
125
  public DateTimeZone getDefaultTimeZone()
@@ -121,10 +129,21 @@ public class TimestampParser
121
129
 
122
130
  public Timestamp parse(String text) throws TimestampParseException
123
131
  {
124
- long localUsec = helper.strptimeUsec(text);
125
- String zone = helper.getZone();
132
+ if (isNullOrEmpty(text)) {
133
+ throw new TimestampParseException("text is null or empty string.");
134
+ }
135
+
136
+ final FormatBag bag = parser.parse(compiledPattern, text);
137
+ if (bag == null) {
138
+ throw new TimestampParseException("Cannot parse '" + text + "' by '" + format + "'");
139
+ }
140
+ bag.setYearIfNotSet(calendar.get(Calendar.YEAR));
141
+ bag.setMonthIfNotSet(calendar.get(Calendar.MONTH) + 1);
142
+ bag.setMdayIfNotSet(calendar.get(Calendar.DAY_OF_MONTH));
126
143
 
127
- DateTimeZone timeZone = defaultTimeZone;
144
+ final LocalTime local = createLocalTimeFromFormatBag(bag);
145
+ final String zone = local.getZone();
146
+ final DateTimeZone timeZone;
128
147
  if (zone != null) {
129
148
  // TODO cache parsed zone?
130
149
  timeZone = parseDateTimeZone(zone);
@@ -132,11 +151,91 @@ public class TimestampParser
132
151
  throw new TimestampParseException("Invalid time zone name '" + text + "'");
133
152
  }
134
153
  }
154
+ else {
155
+ timeZone = defaultTimeZone;
156
+ }
135
157
 
136
- long localSec = localUsec / 1000000;
137
- long usec = localUsec % 1000000;
138
- long sec = timeZone.convertLocalToUTC(localSec*1000, false) / 1000;
158
+ final long sec = timeZone.convertLocalToUTC(local.getSeconds() * 1000, false) / 1000;
159
+ return Timestamp.ofEpochSecond(sec, local.getNsecFraction());
160
+ }
139
161
 
140
- return Timestamp.ofEpochSecond(sec, usec * 1000);
162
+ public LocalTime createLocalTimeFromFormatBag(FormatBag bag)
163
+ {
164
+ final long secFractionNsec;
165
+ if (FormatBag.has(bag.getSecFraction())) {
166
+ secFractionNsec = bag.getSecFraction() * (int)Math.pow(10, 9 - bag.getSecFractionSize());
167
+ }
168
+ else {
169
+ secFractionNsec = 0;
170
+ }
171
+
172
+ final long sec;
173
+ if (bag.hasSeconds()) {
174
+ if (FormatBag.has(bag.getSecondsSize())) {
175
+ sec = bag.getSeconds() / (int)Math.pow(10, bag.getSecondsSize());
176
+ }
177
+ else { // int
178
+ sec = bag.getSeconds();
179
+ }
180
+
181
+ } else {
182
+ final int year;
183
+ if (FormatBag.has(bag.getYear())) {
184
+ year = bag.getYear();
185
+ }
186
+ else {
187
+ year = 1970;
188
+ }
189
+
190
+ // set up with min this and then add to allow rolling over
191
+ DateTime dt = new DateTime(year, 1, 1, 0, 0, 0, 0, DateTimeZone.UTC);
192
+ if (FormatBag.has(bag.getMon())) {
193
+ dt = dt.plusMonths(bag.getMon() - 1);
194
+ }
195
+ if (FormatBag.has(bag.getMDay())) {
196
+ dt = dt.plusDays(bag.getMDay() - 1);
197
+ }
198
+ if (FormatBag.has(bag.getHour())) {
199
+ dt = dt.plusHours(bag.getHour());
200
+ }
201
+ if (FormatBag.has(bag.getMin())) {
202
+ dt = dt.plusMinutes(bag.getMin());
203
+ }
204
+ if (FormatBag.has(bag.getSec())) {
205
+ dt = dt.plusSeconds(bag.getSec());
206
+ }
207
+ sec = dt.getMillis() / 1000;
208
+ }
209
+
210
+ return new LocalTime(sec, secFractionNsec, bag.getZone());
211
+ }
212
+
213
+ private static class LocalTime
214
+ {
215
+ private final long seconds;
216
+ private final long nsecFraction;
217
+ private final String zone; // +0900, JST, UTC
218
+
219
+ public LocalTime(long seconds, long nsecFraction, String zone)
220
+ {
221
+ this.seconds = seconds;
222
+ this.nsecFraction = nsecFraction;
223
+ this.zone = zone;
224
+ }
225
+
226
+ public long getSeconds()
227
+ {
228
+ return seconds;
229
+ }
230
+
231
+ public long getNsecFraction()
232
+ {
233
+ return nsecFraction;
234
+ }
235
+
236
+ public String getZone()
237
+ {
238
+ return zone;
239
+ }
141
240
  }
142
241
  }
@@ -42,7 +42,7 @@ public class TestTimestampFormatterParser
42
42
  .set("default_timestamp_format", "%Y-%m-%d %H:%M:%S %z"); // %Z is OS-dependent
43
43
  ParserTestTask task = config.loadConfig(ParserTestTask.class);
44
44
 
45
- TimestampParser parser = new TimestampParser(task);
45
+ TimestampParser parser = TimestampParser.createTimestampParserForTesting(task);
46
46
  assertEquals(Timestamp.ofEpochSecond(1416365189, 0), parser.parse("2014-11-19 02:46:29 +0000"));
47
47
  }
48
48
 
@@ -57,7 +57,7 @@ public class TestTimestampFormatterParser
57
57
  assertEquals("1416365189", formatter.format(Timestamp.ofEpochSecond(1416365189)));
58
58
 
59
59
  ParserTestTask ptask = config.loadConfig(ParserTestTask.class);
60
- TimestampParser parser = new TimestampParser(ptask);
60
+ TimestampParser parser = TimestampParser.createTimestampParserForTesting(ptask);
61
61
  assertEquals(Timestamp.ofEpochSecond(1416365189), parser.parse("1416365189"));
62
62
  }
63
63
 
@@ -69,7 +69,7 @@ public class TestTimestampFormatterParser
69
69
  .set("default_date", "2016-02-03");
70
70
 
71
71
  ParserTestTask ptask = config.loadConfig(ParserTestTask.class);
72
- TimestampParser parser = new TimestampParser(ptask);
72
+ TimestampParser parser = TimestampParser.createTimestampParserForTesting(ptask);
73
73
  assertEquals(Timestamp.ofEpochSecond(1454467589, 0), parser.parse("02:46:29 +0000"));
74
74
  }
75
75
  }
@@ -4,6 +4,7 @@ Release Notes
4
4
  .. toctree::
5
5
  :maxdepth: 1
6
6
 
7
+ release/release-0.8.27
7
8
  release/release-0.8.26
8
9
  release/release-0.8.25
9
10
  release/release-0.8.24
@@ -0,0 +1,15 @@
1
+ Release 0.8.27
2
+ ==================================
3
+
4
+ General Changes
5
+ ------------------
6
+
7
+ * Add Java timestamp parser [#611]
8
+ * Add the test for the timestamp parser [#712]
9
+ * Fix build.gradle to set forkEvery=1 to improve CI build stability [#714]
10
+ * Fix Javadoc in embulk-jruby-strptime classes to avoid Javadoc errors [#719]
11
+
12
+
13
+ Release Date
14
+ ------------------
15
+ 2017-07-09
@@ -0,0 +1,3 @@
1
+ dependencies {
2
+ compile 'org.jruby:jruby-complete:' + project.jrubyVersion
3
+ }
@@ -0,0 +1,121 @@
1
+ package org.embulk.spi.time;
2
+
3
+ import org.jruby.runtime.ThreadContext;
4
+
5
+ import java.util.HashMap;
6
+ import java.util.List;
7
+
8
+ import static org.embulk.spi.time.StrptimeParser.FormatBag.has;
9
+ import static org.jruby.RubyRational.newRationalCanonicalize;
10
+
11
+ /**
12
+ * This class has {@code StrptimeParser} and provides methods that are calls from JRuby.
13
+ *
14
+ * TODO
15
+ * This class is tentatively required for executing test/mri/date/test_date_strptime.rb
16
+ * (#617). The {@code StrptimeParser} and {@code RubyDateParser} will be merged into
17
+ * JRuby (jruby/jruby#4591). embulk-jruby-strptime is removed when Embulk start using
18
+ * the JRuby that bundles embulk-jruby-strptime.
19
+ */
20
+ public class RubyDateParser
21
+ {
22
+ private final StrptimeParser strptimeParser;
23
+
24
+ public RubyDateParser()
25
+ {
26
+ this.strptimeParser = new StrptimeParser();
27
+ }
28
+
29
+ /**
30
+ * Date._strptime method in JRuby 9.1.5.0's lib/ruby/stdlib/date/format.rb is replaced
31
+ * with this method. This is Java implementation of date__strptime method in MRI 2.3.1's
32
+ * ext/date/date_strptime.c.
33
+ * @see <a href="https://github.com/jruby/jruby/blob/036ce39f0476d4bd718e23e64caff36bb50b8dbc/lib/ruby/stdlib/date/format.rb">format.rb</a>
34
+ * @see <a href="https://github.com/ruby/ruby/blob/394fa89c67722d35bdda89f10c7de5c304a5efb1/ext/date/date_strptime.c">date_strptime.c</a>
35
+ */
36
+ public HashMap<String, Object> parse(ThreadContext context, final String format, final String text)
37
+ {
38
+ final List<StrptimeToken> compiledPattern = strptimeParser.compilePattern(format);
39
+ final StrptimeParser.FormatBag bag = strptimeParser.parse(compiledPattern, text);
40
+ if (bag != null) {
41
+ return convertFormatBagToHash(context, bag);
42
+ }
43
+ else {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ private HashMap<String, Object> convertFormatBagToHash(ThreadContext context, StrptimeParser.FormatBag bag)
49
+ {
50
+ final HashMap<String, Object> map = new HashMap<>();
51
+
52
+ if (has(bag.getMDay())) {
53
+ map.put("mday", bag.getMDay());
54
+ }
55
+ if (has(bag.getWDay())) {
56
+ map.put("wday", bag.getWDay());
57
+ }
58
+ if (has(bag.getCWDay())) {
59
+ map.put("cwday", bag.getCWDay());
60
+ }
61
+ if (has(bag.getYDay())) {
62
+ map.put("yday", bag.getYDay());
63
+ }
64
+ if (has(bag.getCWeek())) {
65
+ map.put("cweek", bag.getCWeek());
66
+ }
67
+ if (has(bag.getCWYear())) {
68
+ map.put("cwyear", bag.getCWYear());
69
+ }
70
+ if (has(bag.getMin())) {
71
+ map.put("min", bag.getMin());
72
+ }
73
+ if (has(bag.getMon())) {
74
+ map.put("mon", bag.getMon());
75
+ }
76
+ if (has(bag.getHour())) {
77
+ map.put("hour", bag.getHour());
78
+ }
79
+ if (has(bag.getYear())) {
80
+ map.put("year", bag.getYear());
81
+ }
82
+ if (has(bag.getSec())) {
83
+ map.put("sec", bag.getSec());
84
+ }
85
+ if (has(bag.getWNum0())) {
86
+ map.put("wnum0", bag.getWNum0());
87
+ }
88
+ if (has(bag.getWNum1())) {
89
+ map.put("wnum1", bag.getWNum1());
90
+ }
91
+ if (bag.getZone() != null) {
92
+ map.put("zone", bag.getZone());
93
+ int offset = TimeZoneConverter.dateZoneToDiff(bag.getZone());
94
+ if (offset != Integer.MIN_VALUE) {
95
+ map.put("offset", offset);
96
+ }
97
+ }
98
+ if (has(bag.getSecFraction())) {
99
+ map.put("sec_fraction", newRationalCanonicalize(context, bag.getSecFraction(), (long)Math.pow(10, bag.getSecFractionSize())));
100
+ }
101
+ if (bag.hasSeconds()) {
102
+ if (has(bag.getSecondsSize())) {
103
+ map.put("seconds", newRationalCanonicalize(context, bag.getSeconds(), (long) Math.pow(10, bag.getSecondsSize())));
104
+ }
105
+ else {
106
+ map.put("seconds", bag.getSeconds());
107
+ }
108
+ }
109
+ if (has(bag.getMerid())) {
110
+ map.put("_merid", bag.getMerid());
111
+ }
112
+ if (has(bag.getCent())) {
113
+ map.put("_cent", bag.getCent());
114
+ }
115
+ if (bag.getLeftover() != null) {
116
+ map.put("leftover", bag.getLeftover());
117
+ }
118
+
119
+ return map;
120
+ }
121
+ }
@@ -0,0 +1,53 @@
1
+ package org.embulk.spi.time;
2
+
3
+ /**
4
+ * This class is ported from org.jruby.util.RubyDateFormatter.Format in JRuby
5
+ * 9.1.5.0 and modified for StrptimeParser under EPL.
6
+ * @see <a href="https://github.com/jruby/jruby/blob/036ce39f0476d4bd718e23e64caff36bb50b8dbc/core/src/main/java/org/jruby/util/RubyDateFormatter.java>RubyDateFormatter.java</a>.
7
+ *
8
+ * TODO
9
+ * This class is tentatively required for {@code StrptimeParser} class.
10
+ * The {@code StrptimeParser} and {@code RubyDateParser} will be merged into JRuby
11
+ * (jruby/jruby#4591). embulk-jruby-strptime is removed when Embulk start using
12
+ * the JRuby that bundles embulk-jruby-strptime.
13
+ */
14
+ enum StrptimeFormat
15
+ {
16
+ FORMAT_STRING, // raw string, no formatting
17
+ FORMAT_SPECIAL, // composition of other formats
18
+
19
+ FORMAT_WEEK_LONG, // %A
20
+ FORMAT_WEEK_SHORT, // %a
21
+ FORMAT_MONTH_LONG, // %B
22
+ FORMAT_MONTH_SHORT, // %b, %h
23
+ FORMAT_CENTURY, // %C
24
+ FORMAT_DAY, // %d
25
+ FORMAT_DAY_S, // %e
26
+ FORMAT_WEEKYEAR, // %G
27
+ FORMAT_WEEKYEAR_SHORT, // %g
28
+ FORMAT_HOUR, // %H
29
+ FORMAT_HOUR_M, // %I
30
+ FORMAT_DAY_YEAR, // %j
31
+ FORMAT_HOUR_BLANK, // %k
32
+ FORMAT_MILLISEC, // %L
33
+ FORMAT_HOUR_S, // %l
34
+ FORMAT_MINUTES, // %M
35
+ FORMAT_MONTH, // %m
36
+ FORMAT_NANOSEC, // %N
37
+ FORMAT_MERIDIAN_LOWER_CASE, // %P
38
+ FORMAT_MERIDIAN, // %p
39
+ FORMAT_MICROSEC_EPOCH, // %Q Only for Date/DateTime from here
40
+ FORMAT_SECONDS, // %S
41
+ FORMAT_EPOCH, // %s
42
+ FORMAT_WEEK_YEAR_S, // %U
43
+ FORMAT_DAY_WEEK2, // %u
44
+ FORMAT_WEEK_WEEKYEAR, // %V
45
+ FORMAT_WEEK_YEAR_M, // %W
46
+ FORMAT_DAY_WEEK, // %w
47
+ FORMAT_YEAR_LONG, // %Y
48
+ FORMAT_YEAR_SHORT, // %y
49
+
50
+ FORMAT_COLON_ZONE_OFF, // %z, %:z, %::z, %:::z must be given number of colons as data
51
+
52
+ FORMAT_ZONE_ID; // %Z Change between Time and Date
53
+ }