embulk-output-s3 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +13 -13
- data/LICENSE.txt +0 -0
- data/README.md +60 -60
- data/build.gradle +77 -77
- data/config/checkstyle/checkstyle.xml +128 -128
- data/config/checkstyle/default.xml +108 -108
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +6 -6
- data/gradlew +0 -0
- data/lib/embulk/output/s3.rb +0 -0
- data/settings.gradle +1 -1
- data/src/main/java/org/embulk/output/S3FileOutputPlugin.java +298 -301
- data/src/test/java/org/embulk/output/TestS3FileOutputPlugin.java +0 -0
- metadata +7 -7
@@ -1,108 +1,108 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<!DOCTYPE module PUBLIC
|
3
|
-
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
4
|
-
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
5
|
-
<!--
|
6
|
-
This is a subset of ./checkstyle.xml which allows some loose styles
|
7
|
-
-->
|
8
|
-
<module name="Checker">
|
9
|
-
<module name="FileTabCharacter"/>
|
10
|
-
<module name="NewlineAtEndOfFile">
|
11
|
-
<property name="lineSeparator" value="lf"/>
|
12
|
-
</module>
|
13
|
-
<module name="RegexpMultiline">
|
14
|
-
<property name="format" value="\r"/>
|
15
|
-
<property name="message" value="Line contains carriage return"/>
|
16
|
-
</module>
|
17
|
-
<module name="RegexpMultiline">
|
18
|
-
<property name="format" value=" \n"/>
|
19
|
-
<property name="message" value="Line has trailing whitespace"/>
|
20
|
-
</module>
|
21
|
-
<module name="RegexpMultiline">
|
22
|
-
<property name="format" value="\n\n\n"/>
|
23
|
-
<property name="message" value="Multiple consecutive blank lines"/>
|
24
|
-
</module>
|
25
|
-
<module name="RegexpMultiline">
|
26
|
-
<property name="format" value="\n\n\Z"/>
|
27
|
-
<property name="message" value="Blank line before end of file"/>
|
28
|
-
</module>
|
29
|
-
|
30
|
-
<module name="TreeWalker">
|
31
|
-
<module name="EmptyBlock">
|
32
|
-
<property name="option" value="text"/>
|
33
|
-
<property name="tokens" value="
|
34
|
-
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF,
|
35
|
-
LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT"/>
|
36
|
-
</module>
|
37
|
-
<module name="EmptyStatement"/>
|
38
|
-
<module name="EmptyForInitializerPad"/>
|
39
|
-
<module name="EmptyForIteratorPad">
|
40
|
-
<property name="option" value="space"/>
|
41
|
-
</module>
|
42
|
-
<module name="MethodParamPad">
|
43
|
-
<property name="allowLineBreaks" value="true"/>
|
44
|
-
<property name="option" value="nospace"/>
|
45
|
-
</module>
|
46
|
-
<module name="ParenPad"/>
|
47
|
-
<module name="TypecastParenPad"/>
|
48
|
-
<module name="NeedBraces"/>
|
49
|
-
<module name="LeftCurly">
|
50
|
-
<property name="option" value="nl"/>
|
51
|
-
<property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, METHOD_DEF"/>
|
52
|
-
</module>
|
53
|
-
<module name="LeftCurly">
|
54
|
-
<property name="option" value="eol"/>
|
55
|
-
<property name="tokens" value="
|
56
|
-
LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR,
|
57
|
-
LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE"/>
|
58
|
-
</module>
|
59
|
-
<module name="RightCurly">
|
60
|
-
<property name="option" value="alone"/>
|
61
|
-
</module>
|
62
|
-
<module name="GenericWhitespace"/>
|
63
|
-
<module name="WhitespaceAfter"/>
|
64
|
-
<module name="NoWhitespaceBefore"/>
|
65
|
-
|
66
|
-
<module name="UpperEll"/>
|
67
|
-
<module name="DefaultComesLast"/>
|
68
|
-
<module name="ArrayTypeStyle"/>
|
69
|
-
<module name="MultipleVariableDeclarations"/>
|
70
|
-
<module name="ModifierOrder"/>
|
71
|
-
<module name="OneStatementPerLine"/>
|
72
|
-
<module name="StringLiteralEquality"/>
|
73
|
-
<module name="MutableException"/>
|
74
|
-
<module name="EqualsHashCode"/>
|
75
|
-
<module name="InnerAssignment"/>
|
76
|
-
<module name="InterfaceIsType"/>
|
77
|
-
<module name="HideUtilityClassConstructor"/>
|
78
|
-
|
79
|
-
<module name="MemberName"/>
|
80
|
-
<module name="LocalVariableName"/>
|
81
|
-
<module name="LocalFinalVariableName"/>
|
82
|
-
<module name="TypeName"/>
|
83
|
-
<module name="PackageName"/>
|
84
|
-
<module name="ParameterName"/>
|
85
|
-
<module name="StaticVariableName"/>
|
86
|
-
<module name="ClassTypeParameterName">
|
87
|
-
<property name="format" value="^[A-Z][0-9]?$"/>
|
88
|
-
</module>
|
89
|
-
<module name="MethodTypeParameterName">
|
90
|
-
<property name="format" value="^[A-Z][0-9]?$"/>
|
91
|
-
</module>
|
92
|
-
|
93
|
-
<module name="WhitespaceAround">
|
94
|
-
<property name="allowEmptyConstructors" value="true"/>
|
95
|
-
<property name="allowEmptyMethods" value="true"/>
|
96
|
-
<property name="ignoreEnhancedForColon" value="false"/>
|
97
|
-
<property name="tokens" value="
|
98
|
-
ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
|
99
|
-
BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LE,
|
100
|
-
LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
101
|
-
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
102
|
-
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE,
|
103
|
-
LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL,
|
104
|
-
PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN,
|
105
|
-
STAR, STAR_ASSIGN, TYPE_EXTENSION_AND"/>
|
106
|
-
</module>
|
107
|
-
</module>
|
108
|
-
</module>
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE module PUBLIC
|
3
|
+
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
4
|
+
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
5
|
+
<!--
|
6
|
+
This is a subset of ./checkstyle.xml which allows some loose styles
|
7
|
+
-->
|
8
|
+
<module name="Checker">
|
9
|
+
<module name="FileTabCharacter"/>
|
10
|
+
<module name="NewlineAtEndOfFile">
|
11
|
+
<property name="lineSeparator" value="lf"/>
|
12
|
+
</module>
|
13
|
+
<module name="RegexpMultiline">
|
14
|
+
<property name="format" value="\r"/>
|
15
|
+
<property name="message" value="Line contains carriage return"/>
|
16
|
+
</module>
|
17
|
+
<module name="RegexpMultiline">
|
18
|
+
<property name="format" value=" \n"/>
|
19
|
+
<property name="message" value="Line has trailing whitespace"/>
|
20
|
+
</module>
|
21
|
+
<module name="RegexpMultiline">
|
22
|
+
<property name="format" value="\n\n\n"/>
|
23
|
+
<property name="message" value="Multiple consecutive blank lines"/>
|
24
|
+
</module>
|
25
|
+
<module name="RegexpMultiline">
|
26
|
+
<property name="format" value="\n\n\Z"/>
|
27
|
+
<property name="message" value="Blank line before end of file"/>
|
28
|
+
</module>
|
29
|
+
|
30
|
+
<module name="TreeWalker">
|
31
|
+
<module name="EmptyBlock">
|
32
|
+
<property name="option" value="text"/>
|
33
|
+
<property name="tokens" value="
|
34
|
+
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF,
|
35
|
+
LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT"/>
|
36
|
+
</module>
|
37
|
+
<module name="EmptyStatement"/>
|
38
|
+
<module name="EmptyForInitializerPad"/>
|
39
|
+
<module name="EmptyForIteratorPad">
|
40
|
+
<property name="option" value="space"/>
|
41
|
+
</module>
|
42
|
+
<module name="MethodParamPad">
|
43
|
+
<property name="allowLineBreaks" value="true"/>
|
44
|
+
<property name="option" value="nospace"/>
|
45
|
+
</module>
|
46
|
+
<module name="ParenPad"/>
|
47
|
+
<module name="TypecastParenPad"/>
|
48
|
+
<module name="NeedBraces"/>
|
49
|
+
<module name="LeftCurly">
|
50
|
+
<property name="option" value="nl"/>
|
51
|
+
<property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, METHOD_DEF"/>
|
52
|
+
</module>
|
53
|
+
<module name="LeftCurly">
|
54
|
+
<property name="option" value="eol"/>
|
55
|
+
<property name="tokens" value="
|
56
|
+
LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR,
|
57
|
+
LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE"/>
|
58
|
+
</module>
|
59
|
+
<module name="RightCurly">
|
60
|
+
<property name="option" value="alone"/>
|
61
|
+
</module>
|
62
|
+
<module name="GenericWhitespace"/>
|
63
|
+
<module name="WhitespaceAfter"/>
|
64
|
+
<module name="NoWhitespaceBefore"/>
|
65
|
+
|
66
|
+
<module name="UpperEll"/>
|
67
|
+
<module name="DefaultComesLast"/>
|
68
|
+
<module name="ArrayTypeStyle"/>
|
69
|
+
<module name="MultipleVariableDeclarations"/>
|
70
|
+
<module name="ModifierOrder"/>
|
71
|
+
<module name="OneStatementPerLine"/>
|
72
|
+
<module name="StringLiteralEquality"/>
|
73
|
+
<module name="MutableException"/>
|
74
|
+
<module name="EqualsHashCode"/>
|
75
|
+
<module name="InnerAssignment"/>
|
76
|
+
<module name="InterfaceIsType"/>
|
77
|
+
<module name="HideUtilityClassConstructor"/>
|
78
|
+
|
79
|
+
<module name="MemberName"/>
|
80
|
+
<module name="LocalVariableName"/>
|
81
|
+
<module name="LocalFinalVariableName"/>
|
82
|
+
<module name="TypeName"/>
|
83
|
+
<module name="PackageName"/>
|
84
|
+
<module name="ParameterName"/>
|
85
|
+
<module name="StaticVariableName"/>
|
86
|
+
<module name="ClassTypeParameterName">
|
87
|
+
<property name="format" value="^[A-Z][0-9]?$"/>
|
88
|
+
</module>
|
89
|
+
<module name="MethodTypeParameterName">
|
90
|
+
<property name="format" value="^[A-Z][0-9]?$"/>
|
91
|
+
</module>
|
92
|
+
|
93
|
+
<module name="WhitespaceAround">
|
94
|
+
<property name="allowEmptyConstructors" value="true"/>
|
95
|
+
<property name="allowEmptyMethods" value="true"/>
|
96
|
+
<property name="ignoreEnhancedForColon" value="false"/>
|
97
|
+
<property name="tokens" value="
|
98
|
+
ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
|
99
|
+
BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LE,
|
100
|
+
LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
|
101
|
+
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
|
102
|
+
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE,
|
103
|
+
LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL,
|
104
|
+
PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN,
|
105
|
+
STAR, STAR_ASSIGN, TYPE_EXTENSION_AND"/>
|
106
|
+
</module>
|
107
|
+
</module>
|
108
|
+
</module>
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
|
-
#Wed Jan 13 12:41:02 JST 2016
|
2
|
-
distributionBase=GRADLE_USER_HOME
|
3
|
-
distributionPath=wrapper/dists
|
4
|
-
zipStoreBase=GRADLE_USER_HOME
|
5
|
-
zipStorePath=wrapper/dists
|
6
|
-
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
|
1
|
+
#Wed Jan 13 12:41:02 JST 2016
|
2
|
+
distributionBase=GRADLE_USER_HOME
|
3
|
+
distributionPath=wrapper/dists
|
4
|
+
zipStoreBase=GRADLE_USER_HOME
|
5
|
+
zipStorePath=wrapper/dists
|
6
|
+
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
|
data/gradlew
CHANGED
File without changes
|
data/lib/embulk/output/s3.rb
CHANGED
File without changes
|
data/settings.gradle
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rootProject.name = 'embulk-output-s3'
|
1
|
+
rootProject.name = 'embulk-output-s3'
|
@@ -1,301 +1,298 @@
|
|
1
|
-
package org.embulk.output;
|
2
|
-
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import
|
6
|
-
import
|
7
|
-
import
|
8
|
-
import
|
9
|
-
import
|
10
|
-
|
11
|
-
import org.embulk.config.
|
12
|
-
import org.embulk.config.
|
13
|
-
import org.embulk.config.
|
14
|
-
import org.embulk.config.
|
15
|
-
import org.embulk.config.
|
16
|
-
import org.embulk.config.
|
17
|
-
import org.embulk.config.
|
18
|
-
import org.embulk.
|
19
|
-
import org.embulk.spi.
|
20
|
-
import org.embulk.spi.
|
21
|
-
import org.embulk.spi.
|
22
|
-
import org.embulk.spi.
|
23
|
-
import org.
|
24
|
-
|
25
|
-
|
26
|
-
import
|
27
|
-
import
|
28
|
-
import
|
29
|
-
import
|
30
|
-
import
|
31
|
-
import
|
32
|
-
|
33
|
-
public class S3FileOutputPlugin
|
34
|
-
implements FileOutputPlugin
|
35
|
-
{
|
36
|
-
public interface PluginTask
|
37
|
-
extends Task
|
38
|
-
{
|
39
|
-
@Config("path_prefix")
|
40
|
-
String getPathPrefix();
|
41
|
-
|
42
|
-
@Config("file_ext")
|
43
|
-
String getFileNameExtension();
|
44
|
-
|
45
|
-
@Config("sequence_format")
|
46
|
-
@ConfigDefault("\".%03d.%02d\"")
|
47
|
-
String getSequenceFormat();
|
48
|
-
|
49
|
-
@Config("bucket")
|
50
|
-
String getBucket();
|
51
|
-
|
52
|
-
@Config("endpoint")
|
53
|
-
@ConfigDefault("null")
|
54
|
-
Optional<String> getEndpoint();
|
55
|
-
|
56
|
-
@Config("access_key_id")
|
57
|
-
@ConfigDefault("null")
|
58
|
-
Optional<String> getAccessKeyId();
|
59
|
-
|
60
|
-
@Config("secret_access_key")
|
61
|
-
@ConfigDefault("null")
|
62
|
-
Optional<String> getSecretAccessKey();
|
63
|
-
|
64
|
-
@Config("tmp_path_prefix")
|
65
|
-
@ConfigDefault("\"embulk-output-s3-\"")
|
66
|
-
String getTempPathPrefix();
|
67
|
-
|
68
|
-
@Config("canned_acl")
|
69
|
-
@ConfigDefault("null")
|
70
|
-
Optional<CannedAccessControlList> getCannedAccessControlList();
|
71
|
-
}
|
72
|
-
|
73
|
-
public static class S3FileOutput
|
74
|
-
implements FileOutput,
|
75
|
-
TransactionalFileOutput
|
76
|
-
{
|
77
|
-
private final Logger log = Exec.getLogger(S3FileOutputPlugin.class);
|
78
|
-
|
79
|
-
private final String bucket;
|
80
|
-
private final String pathPrefix;
|
81
|
-
private final String sequenceFormat;
|
82
|
-
private final String fileNameExtension;
|
83
|
-
private final String tempPathPrefix;
|
84
|
-
private final Optional<CannedAccessControlList> cannedAccessControlListOptional;
|
85
|
-
|
86
|
-
private int taskIndex;
|
87
|
-
private int fileIndex;
|
88
|
-
private AmazonS3Client client;
|
89
|
-
private OutputStream current;
|
90
|
-
private Path tempFilePath;
|
91
|
-
|
92
|
-
private static AmazonS3Client newS3Client(PluginTask task)
|
93
|
-
{
|
94
|
-
AmazonS3Client client;
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
client = new AmazonS3Client(basicAWSCredentials, config);
|
104
|
-
}
|
105
|
-
else {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
}
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
this.
|
123
|
-
this.
|
124
|
-
this.
|
125
|
-
this.
|
126
|
-
this.
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
}
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
}
|
184
|
-
|
185
|
-
|
186
|
-
}
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
}
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
}
|
221
|
-
|
222
|
-
|
223
|
-
}
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
return new S3FileOutput(task, taskIndex);
|
300
|
-
}
|
301
|
-
}
|
1
|
+
package org.embulk.output;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
import java.io.OutputStream;
|
5
|
+
import java.nio.file.Files;
|
6
|
+
import java.nio.file.Path;
|
7
|
+
import java.util.IllegalFormatException;
|
8
|
+
import java.util.List;
|
9
|
+
import java.util.Locale;
|
10
|
+
|
11
|
+
import org.embulk.config.Config;
|
12
|
+
import org.embulk.config.ConfigDefault;
|
13
|
+
import org.embulk.config.ConfigDiff;
|
14
|
+
import org.embulk.config.ConfigException;
|
15
|
+
import org.embulk.config.ConfigSource;
|
16
|
+
import org.embulk.config.Task;
|
17
|
+
import org.embulk.config.TaskReport;
|
18
|
+
import org.embulk.config.TaskSource;
|
19
|
+
import org.embulk.spi.Buffer;
|
20
|
+
import org.embulk.spi.Exec;
|
21
|
+
import org.embulk.spi.FileOutput;
|
22
|
+
import org.embulk.spi.FileOutputPlugin;
|
23
|
+
import org.embulk.spi.TransactionalFileOutput;
|
24
|
+
import org.slf4j.Logger;
|
25
|
+
|
26
|
+
import com.amazonaws.ClientConfiguration;
|
27
|
+
import com.amazonaws.auth.BasicAWSCredentials;
|
28
|
+
import com.amazonaws.services.s3.AmazonS3Client;
|
29
|
+
import com.amazonaws.services.s3.model.CannedAccessControlList;
|
30
|
+
import com.amazonaws.services.s3.model.PutObjectRequest;
|
31
|
+
import com.google.common.base.Optional;
|
32
|
+
|
33
|
+
public class S3FileOutputPlugin
|
34
|
+
implements FileOutputPlugin
|
35
|
+
{
|
36
|
+
public interface PluginTask
|
37
|
+
extends Task
|
38
|
+
{
|
39
|
+
@Config("path_prefix")
|
40
|
+
String getPathPrefix();
|
41
|
+
|
42
|
+
@Config("file_ext")
|
43
|
+
String getFileNameExtension();
|
44
|
+
|
45
|
+
@Config("sequence_format")
|
46
|
+
@ConfigDefault("\".%03d.%02d\"")
|
47
|
+
String getSequenceFormat();
|
48
|
+
|
49
|
+
@Config("bucket")
|
50
|
+
String getBucket();
|
51
|
+
|
52
|
+
@Config("endpoint")
|
53
|
+
@ConfigDefault("null")
|
54
|
+
Optional<String> getEndpoint();
|
55
|
+
|
56
|
+
@Config("access_key_id")
|
57
|
+
@ConfigDefault("null")
|
58
|
+
Optional<String> getAccessKeyId();
|
59
|
+
|
60
|
+
@Config("secret_access_key")
|
61
|
+
@ConfigDefault("null")
|
62
|
+
Optional<String> getSecretAccessKey();
|
63
|
+
|
64
|
+
@Config("tmp_path_prefix")
|
65
|
+
@ConfigDefault("\"embulk-output-s3-\"")
|
66
|
+
String getTempPathPrefix();
|
67
|
+
|
68
|
+
@Config("canned_acl")
|
69
|
+
@ConfigDefault("null")
|
70
|
+
Optional<CannedAccessControlList> getCannedAccessControlList();
|
71
|
+
}
|
72
|
+
|
73
|
+
public static class S3FileOutput
|
74
|
+
implements FileOutput,
|
75
|
+
TransactionalFileOutput
|
76
|
+
{
|
77
|
+
private final Logger log = Exec.getLogger(S3FileOutputPlugin.class);
|
78
|
+
|
79
|
+
private final String bucket;
|
80
|
+
private final String pathPrefix;
|
81
|
+
private final String sequenceFormat;
|
82
|
+
private final String fileNameExtension;
|
83
|
+
private final String tempPathPrefix;
|
84
|
+
private final Optional<CannedAccessControlList> cannedAccessControlListOptional;
|
85
|
+
|
86
|
+
private int taskIndex;
|
87
|
+
private int fileIndex;
|
88
|
+
private AmazonS3Client client;
|
89
|
+
private OutputStream current;
|
90
|
+
private Path tempFilePath;
|
91
|
+
|
92
|
+
private static AmazonS3Client newS3Client(PluginTask task)
|
93
|
+
{
|
94
|
+
AmazonS3Client client;
|
95
|
+
|
96
|
+
// TODO: Support more configurations.
|
97
|
+
ClientConfiguration config = new ClientConfiguration();
|
98
|
+
|
99
|
+
if (task.getAccessKeyId().isPresent()) {
|
100
|
+
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(
|
101
|
+
task.getAccessKeyId().get(), task.getSecretAccessKey().get());
|
102
|
+
|
103
|
+
client = new AmazonS3Client(basicAWSCredentials, config);
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
// Use default credential provider chain.
|
107
|
+
client = new AmazonS3Client(config);
|
108
|
+
}
|
109
|
+
|
110
|
+
if (task.getEndpoint().isPresent()) {
|
111
|
+
client.setEndpoint(task.getEndpoint().get());
|
112
|
+
}
|
113
|
+
|
114
|
+
return client;
|
115
|
+
}
|
116
|
+
|
117
|
+
public S3FileOutput(PluginTask task, int taskIndex)
|
118
|
+
{
|
119
|
+
this.taskIndex = taskIndex;
|
120
|
+
this.client = newS3Client(task);
|
121
|
+
this.bucket = task.getBucket();
|
122
|
+
this.pathPrefix = task.getPathPrefix();
|
123
|
+
this.sequenceFormat = task.getSequenceFormat();
|
124
|
+
this.fileNameExtension = task.getFileNameExtension();
|
125
|
+
this.tempPathPrefix = task.getTempPathPrefix();
|
126
|
+
this.cannedAccessControlListOptional = task.getCannedAccessControlList();
|
127
|
+
}
|
128
|
+
|
129
|
+
private static Path newTempFile(String prefix)
|
130
|
+
throws IOException
|
131
|
+
{
|
132
|
+
return Files.createTempFile(prefix, null);
|
133
|
+
}
|
134
|
+
|
135
|
+
private void deleteTempFile()
|
136
|
+
{
|
137
|
+
if (tempFilePath == null) {
|
138
|
+
return;
|
139
|
+
}
|
140
|
+
|
141
|
+
try {
|
142
|
+
Files.delete(tempFilePath);
|
143
|
+
tempFilePath = null;
|
144
|
+
}
|
145
|
+
catch (IOException e) {
|
146
|
+
throw new RuntimeException(e);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
private String buildCurrentKey()
|
151
|
+
{
|
152
|
+
String sequence = String.format(sequenceFormat, taskIndex,
|
153
|
+
fileIndex);
|
154
|
+
return pathPrefix + sequence + fileNameExtension;
|
155
|
+
}
|
156
|
+
|
157
|
+
private void putFile(Path from, String key)
|
158
|
+
{
|
159
|
+
PutObjectRequest request = new PutObjectRequest(bucket, key, from.toFile());
|
160
|
+
if (cannedAccessControlListOptional.isPresent()) {
|
161
|
+
request.withCannedAcl(cannedAccessControlListOptional.get());
|
162
|
+
}
|
163
|
+
client.putObject(request);
|
164
|
+
}
|
165
|
+
|
166
|
+
private void closeCurrent()
|
167
|
+
{
|
168
|
+
if (current == null) {
|
169
|
+
return;
|
170
|
+
}
|
171
|
+
|
172
|
+
try {
|
173
|
+
putFile(tempFilePath, buildCurrentKey());
|
174
|
+
fileIndex++;
|
175
|
+
}
|
176
|
+
finally {
|
177
|
+
try {
|
178
|
+
current.close();
|
179
|
+
current = null;
|
180
|
+
}
|
181
|
+
catch (IOException e) {
|
182
|
+
throw new RuntimeException(e);
|
183
|
+
}
|
184
|
+
finally {
|
185
|
+
deleteTempFile();
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
@Override
|
191
|
+
public void nextFile()
|
192
|
+
{
|
193
|
+
closeCurrent();
|
194
|
+
|
195
|
+
try {
|
196
|
+
tempFilePath = newTempFile(tempPathPrefix);
|
197
|
+
|
198
|
+
log.info("Writing S3 file '{}'", buildCurrentKey());
|
199
|
+
|
200
|
+
current = Files.newOutputStream(tempFilePath);
|
201
|
+
}
|
202
|
+
catch (IOException e) {
|
203
|
+
throw new RuntimeException(e);
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
@Override
|
208
|
+
public void add(Buffer buffer)
|
209
|
+
{
|
210
|
+
if (current == null) {
|
211
|
+
throw new IllegalStateException(
|
212
|
+
"nextFile() must be called before poll()");
|
213
|
+
}
|
214
|
+
|
215
|
+
try {
|
216
|
+
current.write(buffer.array(), buffer.offset(), buffer.limit());
|
217
|
+
}
|
218
|
+
catch (IOException ex) {
|
219
|
+
throw new RuntimeException(ex);
|
220
|
+
}
|
221
|
+
finally {
|
222
|
+
buffer.release();
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
@Override
|
227
|
+
public void finish()
|
228
|
+
{
|
229
|
+
closeCurrent();
|
230
|
+
}
|
231
|
+
|
232
|
+
@Override
|
233
|
+
public void close()
|
234
|
+
{
|
235
|
+
closeCurrent();
|
236
|
+
}
|
237
|
+
|
238
|
+
@Override
|
239
|
+
public void abort()
|
240
|
+
{
|
241
|
+
deleteTempFile();
|
242
|
+
}
|
243
|
+
|
244
|
+
@Override
|
245
|
+
public TaskReport commit()
|
246
|
+
{
|
247
|
+
TaskReport report = Exec.newTaskReport();
|
248
|
+
return report;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
private void validateSequenceFormat(PluginTask task)
|
253
|
+
{
|
254
|
+
try {
|
255
|
+
@SuppressWarnings("unused")
|
256
|
+
String dontCare = String.format(Locale.ENGLISH,
|
257
|
+
task.getSequenceFormat(), 0, 0);
|
258
|
+
}
|
259
|
+
catch (IllegalFormatException ex) {
|
260
|
+
throw new ConfigException(
|
261
|
+
"Invalid sequence_format: parameter for file output plugin",
|
262
|
+
ex);
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
@Override
|
267
|
+
public ConfigDiff transaction(ConfigSource config, int taskCount,
|
268
|
+
Control control)
|
269
|
+
{
|
270
|
+
PluginTask task = config.loadConfig(PluginTask.class);
|
271
|
+
|
272
|
+
validateSequenceFormat(task);
|
273
|
+
|
274
|
+
return resume(task.dump(), taskCount, control);
|
275
|
+
}
|
276
|
+
|
277
|
+
@Override
|
278
|
+
public ConfigDiff resume(TaskSource taskSource, int taskCount,
|
279
|
+
Control control)
|
280
|
+
{
|
281
|
+
control.run(taskSource);
|
282
|
+
return Exec.newConfigDiff();
|
283
|
+
}
|
284
|
+
|
285
|
+
@Override
|
286
|
+
public void cleanup(TaskSource taskSource, int taskCount,
|
287
|
+
List<TaskReport> successTaskReports)
|
288
|
+
{
|
289
|
+
}
|
290
|
+
|
291
|
+
@Override
|
292
|
+
public TransactionalFileOutput open(TaskSource taskSource, int taskIndex)
|
293
|
+
{
|
294
|
+
PluginTask task = taskSource.loadTask(PluginTask.class);
|
295
|
+
|
296
|
+
return new S3FileOutput(task, taskIndex);
|
297
|
+
}
|
298
|
+
}
|