embulk-output-s3 1.2.0 → 1.3.0
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 +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
|
+
}
|