embulk-input-gcs 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +4 -4
- data/CHANGELOG.md +4 -0
- data/build.gradle +41 -12
- data/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/gradle/wrapper/gradle-wrapper.properties +2 -2
- data/gradlew +41 -33
- data/gradlew.bat +4 -10
- data/src/main/java/org/embulk/input/gcs/AuthUtils.java +108 -0
- data/src/main/java/org/embulk/input/gcs/FileList.java +12 -9
- data/src/main/java/org/embulk/input/gcs/GcsFileInput.java +46 -126
- data/src/main/java/org/embulk/input/gcs/GcsFileInputPlugin.java +3 -38
- data/src/main/java/org/embulk/input/gcs/PluginTask.java +1 -29
- data/src/main/java/org/embulk/input/gcs/RetryUtils.java +153 -0
- data/src/main/java/org/embulk/input/gcs/SingleFileProvider.java +30 -63
- data/src/test/java/org/embulk/input/gcs/TestAuthUtils.java +153 -0
- data/src/test/java/org/embulk/input/gcs/TestGcsFileInputPlugin.java +42 -94
- data/src/test/java/org/embulk/input/gcs/TestInputStreamReopener.java +145 -0
- data/src/test/java/org/embulk/input/gcs/TestRetryUtils.java +164 -0
- data/src/test/resources/secrets.tar.enc +0 -0
- metadata +53 -28
- data/secretkeys.tar +0 -0
- data/secretkeys.tar.enc +0 -0
- data/src/main/java/org/embulk/input/gcs/GcsAuthentication.java +0 -206
- data/src/test/java/org/embulk/input/gcs/TestGcsAuthentication.java +0 -185
- data/src/test/resources/secretkeys.tar.enc +0 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
package org.embulk.input.gcs;
|
2
|
+
|
3
|
+
import com.google.cloud.ReadChannel;
|
4
|
+
import com.google.cloud.RestorableState;
|
5
|
+
import com.google.cloud.storage.Blob;
|
6
|
+
import com.google.cloud.storage.Storage;
|
7
|
+
import com.google.common.base.Charsets;
|
8
|
+
import com.google.common.io.Files;
|
9
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
10
|
+
import org.embulk.EmbulkTestRuntime;
|
11
|
+
import org.embulk.spi.util.ResumableInputStream;
|
12
|
+
import org.junit.Rule;
|
13
|
+
import org.junit.Test;
|
14
|
+
import org.mockito.Mockito;
|
15
|
+
|
16
|
+
import java.io.ByteArrayOutputStream;
|
17
|
+
import java.io.File;
|
18
|
+
import java.io.IOException;
|
19
|
+
import java.nio.ByteBuffer;
|
20
|
+
import java.nio.channels.FileChannel;
|
21
|
+
import java.nio.file.Paths;
|
22
|
+
|
23
|
+
import static org.junit.Assert.assertEquals;
|
24
|
+
import static org.junit.Assert.fail;
|
25
|
+
import static org.mockito.ArgumentMatchers.any;
|
26
|
+
import static org.mockito.ArgumentMatchers.eq;
|
27
|
+
|
28
|
+
public class TestInputStreamReopener
|
29
|
+
{
|
30
|
+
private static class MockReadChannel implements ReadChannel
|
31
|
+
{
|
32
|
+
private FileChannel ch;
|
33
|
+
|
34
|
+
MockReadChannel(FileChannel ch)
|
35
|
+
{
|
36
|
+
this.ch = ch;
|
37
|
+
}
|
38
|
+
|
39
|
+
@Override
|
40
|
+
public boolean isOpen()
|
41
|
+
{
|
42
|
+
return this.ch.isOpen();
|
43
|
+
}
|
44
|
+
|
45
|
+
@Override
|
46
|
+
public void close()
|
47
|
+
{
|
48
|
+
try {
|
49
|
+
this.ch.close();
|
50
|
+
}
|
51
|
+
catch (IOException ignored) {
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
@Override
|
56
|
+
public void seek(long position) throws IOException
|
57
|
+
{
|
58
|
+
this.ch.position(position);
|
59
|
+
}
|
60
|
+
|
61
|
+
@Override
|
62
|
+
public void setChunkSize(int chunkSize)
|
63
|
+
{
|
64
|
+
// no-op
|
65
|
+
}
|
66
|
+
|
67
|
+
@Override
|
68
|
+
public RestorableState<ReadChannel> capture()
|
69
|
+
{
|
70
|
+
return null;
|
71
|
+
}
|
72
|
+
|
73
|
+
@Override
|
74
|
+
public int read(ByteBuffer dst) throws IOException
|
75
|
+
{
|
76
|
+
return this.ch.read(dst);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
private static final String SAMPLE_PATH = TestInputStreamReopener.class.getResource("/sample_01.csv").getPath();
|
81
|
+
|
82
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
83
|
+
@Rule
|
84
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
85
|
+
|
86
|
+
@Test
|
87
|
+
public void testResume()
|
88
|
+
{
|
89
|
+
final String bucket = "any_bucket";
|
90
|
+
final String key = "any_file";
|
91
|
+
|
92
|
+
final Storage client = mockStorage();
|
93
|
+
|
94
|
+
final SingleFileProvider.InputStreamReopener reopener = new SingleFileProvider.InputStreamReopener(client, bucket, key);
|
95
|
+
final byte[] buf = new byte[200];
|
96
|
+
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
97
|
+
try (final ResumableInputStream ris = new ResumableInputStream(reopener)) {
|
98
|
+
int len;
|
99
|
+
while ((len = ris.read(buf)) != -1) {
|
100
|
+
out.write(buf, 0, len);
|
101
|
+
}
|
102
|
+
// read from resumable input stream
|
103
|
+
String content = out.toString("UTF-8");
|
104
|
+
// assert content
|
105
|
+
assertString(content);
|
106
|
+
}
|
107
|
+
catch (IOException e) {
|
108
|
+
e.printStackTrace();
|
109
|
+
fail("Should not throw");
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
private Storage mockStorage()
|
114
|
+
{
|
115
|
+
Blob blob = Mockito.mock(Blob.class);
|
116
|
+
// mock Storage to return ReadChannel
|
117
|
+
Storage client = Mockito.mock(Storage.class);
|
118
|
+
Mockito.doReturn(blob).when(client).get(eq("any_bucket"), eq("any_file"));
|
119
|
+
// to return new instance every time (can't re-use channel, because it'll be closed)
|
120
|
+
Mockito.doAnswer(invocation -> new MockReadChannel(mockChannel())).when(blob).reader();
|
121
|
+
return client;
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Return a mock FileChannel, with simulated error during reads
|
126
|
+
*
|
127
|
+
* @return
|
128
|
+
* @throws IOException
|
129
|
+
*/
|
130
|
+
private static FileChannel mockChannel() throws IOException
|
131
|
+
{
|
132
|
+
FileChannel ch = Mockito.spy(FileChannel.open(Paths.get(SAMPLE_PATH)));
|
133
|
+
// success -> error -> success -> error...
|
134
|
+
Mockito.doCallRealMethod()
|
135
|
+
.doThrow(new IOException("Fake IOException, going to resume"))
|
136
|
+
.when(ch).read(any(ByteBuffer.class));
|
137
|
+
return ch;
|
138
|
+
}
|
139
|
+
|
140
|
+
private static void assertString(final String actual) throws IOException
|
141
|
+
{
|
142
|
+
final String expected = Files.asCharSource(new File(SAMPLE_PATH), Charsets.UTF_8).read();
|
143
|
+
assertEquals(expected, actual);
|
144
|
+
}
|
145
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
package org.embulk.input.gcs;
|
2
|
+
|
3
|
+
import com.google.api.client.auth.oauth2.TokenResponseException;
|
4
|
+
import com.google.api.client.googleapis.json.GoogleJsonError;
|
5
|
+
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
6
|
+
import com.google.api.client.http.HttpHeaders;
|
7
|
+
import com.google.api.client.http.HttpRequest;
|
8
|
+
import com.google.api.client.http.HttpTransport;
|
9
|
+
import com.google.api.client.http.LowLevelHttpRequest;
|
10
|
+
import com.google.api.client.http.LowLevelHttpResponse;
|
11
|
+
import com.google.api.client.json.Json;
|
12
|
+
import com.google.api.client.json.jackson2.JacksonFactory;
|
13
|
+
import com.google.api.client.testing.http.HttpTesting;
|
14
|
+
import com.google.api.client.testing.http.MockHttpTransport;
|
15
|
+
import com.google.api.client.testing.http.MockLowLevelHttpRequest;
|
16
|
+
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
|
17
|
+
import com.google.cloud.storage.StorageException;
|
18
|
+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
19
|
+
import org.embulk.EmbulkTestRuntime;
|
20
|
+
import org.embulk.spi.Exec;
|
21
|
+
import org.junit.Before;
|
22
|
+
import org.junit.Rule;
|
23
|
+
import org.junit.Test;
|
24
|
+
import org.mockito.Mockito;
|
25
|
+
|
26
|
+
import java.io.IOException;
|
27
|
+
|
28
|
+
import static org.embulk.input.gcs.RetryUtils.withRetry;
|
29
|
+
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
30
|
+
import static org.junit.Assert.assertEquals;
|
31
|
+
import static org.junit.Assert.assertFalse;
|
32
|
+
import static org.junit.Assert.assertNull;
|
33
|
+
import static org.junit.Assert.assertThat;
|
34
|
+
import static org.junit.Assert.assertTrue;
|
35
|
+
|
36
|
+
public class TestRetryUtils
|
37
|
+
{
|
38
|
+
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
39
|
+
@Rule
|
40
|
+
public EmbulkTestRuntime runtime = new EmbulkTestRuntime();
|
41
|
+
|
42
|
+
private RetryUtils.DefaultRetryable<Object> mock;
|
43
|
+
|
44
|
+
@Before
|
45
|
+
public void setUp()
|
46
|
+
{
|
47
|
+
mock = new RetryUtils.DefaultRetryable<Object>()
|
48
|
+
{
|
49
|
+
@Override
|
50
|
+
public Object call()
|
51
|
+
{
|
52
|
+
return null;
|
53
|
+
}
|
54
|
+
};
|
55
|
+
}
|
56
|
+
|
57
|
+
@Test
|
58
|
+
public void testRetryable() throws IOException
|
59
|
+
{
|
60
|
+
// verify that #isRetryable() returns false for below cases:
|
61
|
+
// - GoogleJsonResponseException && details.code == 4xx
|
62
|
+
assertFalse(mock.isRetryableException(fakeJsonException(400, "fake_400_ex", null)));
|
63
|
+
// - TokenResponseException && statusCode == 4xx
|
64
|
+
assertFalse(mock.isRetryableException(fakeTokenException(400, "{}")));
|
65
|
+
assertFalse(mock.isRetryableException(fakeTokenException(401, "{\"foo\":\"bar\"}")));
|
66
|
+
assertFalse(mock.isRetryableException(fakeTokenException(403, "{ \"error_description\": \"Invalid...\"}")));
|
67
|
+
// return true
|
68
|
+
// - GoogleJsonResponseException && details.code = 5xx
|
69
|
+
assertTrue(mock.isRetryableException(fakeJsonException(500, "fake_500_ex", null)));
|
70
|
+
// - GoogleJsonResponseException && details == null && content != null
|
71
|
+
assertTrue(mock.isRetryableException(fakeJsonExceptionWithoutDetails(400, "fake_400_ex", "this content will make it retry-able")));
|
72
|
+
// - TokenResponseException && statusCode = 5xx
|
73
|
+
assertTrue(mock.isRetryableException(fakeTokenException(500, "{}")));
|
74
|
+
// - TokenResponseException && details.errorDescription contains 'Invalid JWT'
|
75
|
+
assertTrue(mock.isRetryableException(fakeTokenException(403, "{ \"error_description\": \"Invalid JWT...\"}")));
|
76
|
+
}
|
77
|
+
|
78
|
+
@Test
|
79
|
+
public void testWithRetry() throws Exception
|
80
|
+
{
|
81
|
+
mock = Mockito.spy(mock);
|
82
|
+
Exception ex = new StorageException(403, "Fake Exception");
|
83
|
+
Mockito.doThrow(ex).doThrow(ex).doReturn(null).when(mock).call();
|
84
|
+
|
85
|
+
Object result = withRetry(params(), mock);
|
86
|
+
assertNull(result);
|
87
|
+
Mockito.verify(mock, Mockito.times(3)).call();
|
88
|
+
}
|
89
|
+
|
90
|
+
@Test
|
91
|
+
public void testWithRetryGiveUp()
|
92
|
+
{
|
93
|
+
final String expectMsg = "Will retry and give up";
|
94
|
+
mock = new RetryUtils.DefaultRetryable<Object>()
|
95
|
+
{
|
96
|
+
@Override
|
97
|
+
public Object call()
|
98
|
+
{
|
99
|
+
throw new IllegalStateException(expectMsg);
|
100
|
+
}
|
101
|
+
};
|
102
|
+
try {
|
103
|
+
withRetry(params(), mock);
|
104
|
+
}
|
105
|
+
catch (RuntimeException e) {
|
106
|
+
// root cause -> RetryGiveUpException -> RuntimeException
|
107
|
+
Throwable rootCause = e.getCause().getCause();
|
108
|
+
assertEquals(expectMsg, rootCause.getMessage());
|
109
|
+
assertThat(rootCause, instanceOf(IllegalStateException.class));
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
private static RetryUtils.Task params()
|
114
|
+
{
|
115
|
+
return Exec.newConfigSource().set("initial_retry_interval_millis", 1).loadConfig(RetryUtils.Task.class);
|
116
|
+
}
|
117
|
+
|
118
|
+
private static GoogleJsonResponseException fakeJsonException(final int code, final String message, final String content)
|
119
|
+
{
|
120
|
+
GoogleJsonResponseException.Builder builder = new GoogleJsonResponseException.Builder(code, message, new HttpHeaders());
|
121
|
+
builder.setContent(content);
|
122
|
+
return new GoogleJsonResponseException(builder, fakeJsonError(code, message));
|
123
|
+
}
|
124
|
+
|
125
|
+
private static GoogleJsonResponseException fakeJsonExceptionWithoutDetails(final int code, final String message, final String content)
|
126
|
+
{
|
127
|
+
GoogleJsonResponseException.Builder builder = new GoogleJsonResponseException.Builder(code, message, new HttpHeaders());
|
128
|
+
builder.setContent(content);
|
129
|
+
return new GoogleJsonResponseException(builder, null);
|
130
|
+
}
|
131
|
+
|
132
|
+
private static GoogleJsonError fakeJsonError(final int code, final String message)
|
133
|
+
{
|
134
|
+
GoogleJsonError error = new GoogleJsonError();
|
135
|
+
error.setCode(code);
|
136
|
+
error.setMessage(message);
|
137
|
+
return error;
|
138
|
+
}
|
139
|
+
|
140
|
+
private static TokenResponseException fakeTokenException(final int code, final String content) throws IOException
|
141
|
+
{
|
142
|
+
HttpTransport transport = new MockHttpTransport() {
|
143
|
+
@Override
|
144
|
+
public LowLevelHttpRequest buildRequest(String method, String url)
|
145
|
+
{
|
146
|
+
return new MockLowLevelHttpRequest() {
|
147
|
+
@Override
|
148
|
+
public LowLevelHttpResponse execute()
|
149
|
+
{
|
150
|
+
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
|
151
|
+
response.addHeader("custom_header", "value");
|
152
|
+
response.setStatusCode(code);
|
153
|
+
response.setContentType(Json.MEDIA_TYPE);
|
154
|
+
response.setContent(content);
|
155
|
+
return response;
|
156
|
+
}
|
157
|
+
};
|
158
|
+
}
|
159
|
+
};
|
160
|
+
HttpRequest request = transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
|
161
|
+
request.setThrowExceptionOnExecuteError(false);
|
162
|
+
return TokenResponseException.from(JacksonFactory.getDefaultInstance(), request.execute());
|
163
|
+
}
|
164
|
+
}
|
Binary file
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: embulk-input-gcs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Satoshi Akama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- - ~>
|
16
|
+
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: '1.0'
|
19
19
|
name: bundler
|
@@ -21,13 +21,13 @@ dependencies:
|
|
21
21
|
type: :development
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '10.0'
|
33
33
|
name: rake
|
@@ -35,21 +35,56 @@ dependencies:
|
|
35
35
|
type: :development
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
-
description: Reads files stored on Google Cloud Storage (Standard, Durable Reduced
|
41
|
+
description: Reads files stored on Google Cloud Storage (Standard, Durable Reduced
|
42
|
+
Availability or Nearline)
|
42
43
|
email:
|
43
44
|
- satoshiakama@gmail.com
|
44
45
|
executables: []
|
45
46
|
extensions: []
|
46
47
|
extra_rdoc_files: []
|
47
48
|
files:
|
48
|
-
- .gitignore
|
49
|
-
- .travis.yml
|
49
|
+
- ".gitignore"
|
50
|
+
- ".travis.yml"
|
50
51
|
- CHANGELOG.md
|
51
52
|
- README.md
|
52
53
|
- build.gradle
|
54
|
+
- classpath/animal-sniffer-annotations-1.14.jar
|
55
|
+
- classpath/api-common-1.7.0.jar
|
56
|
+
- classpath/checker-compat-qual-2.5.2.jar
|
57
|
+
- classpath/commons-codec-1.10.jar
|
58
|
+
- classpath/commons-logging-1.2.jar
|
59
|
+
- classpath/embulk-input-gcs-0.3.1-shadow.jar
|
60
|
+
- classpath/error_prone_annotations-2.1.3.jar
|
61
|
+
- classpath/gax-1.35.1.jar
|
62
|
+
- classpath/gax-httpjson-0.52.1.jar
|
63
|
+
- classpath/google-api-client-1.27.0.jar
|
64
|
+
- classpath/google-api-services-storage-v1-rev20181013-1.27.0.jar
|
65
|
+
- classpath/google-auth-library-credentials-0.12.0.jar
|
66
|
+
- classpath/google-auth-library-oauth2-http-0.12.0.jar
|
67
|
+
- classpath/google-cloud-core-1.56.0.jar
|
68
|
+
- classpath/google-cloud-core-http-1.56.0.jar
|
69
|
+
- classpath/google-http-client-1.27.0.jar
|
70
|
+
- classpath/google-http-client-appengine-1.27.0.jar
|
71
|
+
- classpath/google-http-client-jackson2-1.27.0.jar
|
72
|
+
- classpath/google-oauth-client-1.27.0.jar
|
73
|
+
- classpath/grpc-context-1.12.0.jar
|
74
|
+
- classpath/gson-2.7.jar
|
75
|
+
- classpath/httpclient-4.5.5.jar
|
76
|
+
- classpath/httpcore-4.4.9.jar
|
77
|
+
- classpath/j2objc-annotations-1.1.jar
|
78
|
+
- classpath/jackson-core-2.9.6.jar
|
79
|
+
- classpath/javax.annotation-api-1.2.jar
|
80
|
+
- classpath/jsr305-3.0.2.jar
|
81
|
+
- classpath/opencensus-api-0.15.0.jar
|
82
|
+
- classpath/opencensus-contrib-http-util-0.15.0.jar
|
83
|
+
- classpath/proto-google-common-protos-1.12.0.jar
|
84
|
+
- classpath/proto-google-iam-v1-0.12.0.jar
|
85
|
+
- classpath/protobuf-java-3.6.1.jar
|
86
|
+
- classpath/protobuf-java-util-3.6.1.jar
|
87
|
+
- classpath/threetenbp-1.3.3.jar
|
53
88
|
- config/checkstyle/checkstyle.xml
|
54
89
|
- config/checkstyle/default.xml
|
55
90
|
- gradle/wrapper/gradle-wrapper.jar
|
@@ -57,31 +92,21 @@ files:
|
|
57
92
|
- gradlew
|
58
93
|
- gradlew.bat
|
59
94
|
- lib/embulk/input/gcs.rb
|
60
|
-
- secretkeys.tar
|
61
|
-
- secretkeys.tar.enc
|
62
95
|
- settings.gradle
|
96
|
+
- src/main/java/org/embulk/input/gcs/AuthUtils.java
|
63
97
|
- src/main/java/org/embulk/input/gcs/FileList.java
|
64
|
-
- src/main/java/org/embulk/input/gcs/GcsAuthentication.java
|
65
98
|
- src/main/java/org/embulk/input/gcs/GcsFileInput.java
|
66
99
|
- src/main/java/org/embulk/input/gcs/GcsFileInputPlugin.java
|
67
100
|
- src/main/java/org/embulk/input/gcs/PluginTask.java
|
101
|
+
- src/main/java/org/embulk/input/gcs/RetryUtils.java
|
68
102
|
- src/main/java/org/embulk/input/gcs/SingleFileProvider.java
|
69
|
-
- src/test/java/org/embulk/input/gcs/
|
103
|
+
- src/test/java/org/embulk/input/gcs/TestAuthUtils.java
|
70
104
|
- src/test/java/org/embulk/input/gcs/TestGcsFileInputPlugin.java
|
105
|
+
- src/test/java/org/embulk/input/gcs/TestInputStreamReopener.java
|
106
|
+
- src/test/java/org/embulk/input/gcs/TestRetryUtils.java
|
71
107
|
- src/test/resources/sample_01.csv
|
72
108
|
- src/test/resources/sample_02.csv
|
73
|
-
- src/test/resources/
|
74
|
-
- classpath/google-api-client-1.21.0.jar
|
75
|
-
- classpath/httpclient-4.0.1.jar
|
76
|
-
- classpath/jsr305-1.3.9.jar
|
77
|
-
- classpath/commons-logging-1.1.1.jar
|
78
|
-
- classpath/google-api-services-storage-v1-rev59-1.21.0.jar
|
79
|
-
- classpath/google-http-client-1.21.0.jar
|
80
|
-
- classpath/google-oauth-client-1.21.0.jar
|
81
|
-
- classpath/commons-codec-1.3.jar
|
82
|
-
- classpath/google-http-client-jackson2-1.21.0.jar
|
83
|
-
- classpath/httpcore-4.0.1.jar
|
84
|
-
- classpath/embulk-input-gcs-0.3.0.jar
|
109
|
+
- src/test/resources/secrets.tar.enc
|
85
110
|
homepage: https://github.com/embulk/embulk-input-gcs
|
86
111
|
licenses:
|
87
112
|
- Apache-2.0
|
@@ -92,17 +117,17 @@ require_paths:
|
|
92
117
|
- lib
|
93
118
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
119
|
requirements:
|
95
|
-
- -
|
120
|
+
- - ">="
|
96
121
|
- !ruby/object:Gem::Version
|
97
122
|
version: '0'
|
98
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
124
|
requirements:
|
100
|
-
- -
|
125
|
+
- - ">="
|
101
126
|
- !ruby/object:Gem::Version
|
102
127
|
version: '0'
|
103
128
|
requirements: []
|
104
129
|
rubyforge_project:
|
105
|
-
rubygems_version: 2.
|
130
|
+
rubygems_version: 2.6.13
|
106
131
|
signing_key:
|
107
132
|
specification_version: 4
|
108
133
|
summary: Google Cloud Storage input plugin for Embulk
|