embulk 0.8.26-java → 0.8.27-java

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.
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
+ }