From fdebcd872a458436478c1cdd472a6cf716da61df Mon Sep 17 00:00:00 2001 From: "arnett, stu" Date: Thu, 2 Mar 2017 08:45:20 -0600 Subject: [PATCH 1/4] added optional "default values" object to ConfigUri, which will omit parameters if they are the same as the default values. --- .../java/com/emc/object/util/ConfigUri.java | 28 +++++++++++++++++-- .../com/emc/object/util/ConfigUriTest.java | 2 +- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/emc/object/util/ConfigUri.java b/src/main/java/com/emc/object/util/ConfigUri.java index 2adbed9e..4c282434 100644 --- a/src/main/java/com/emc/object/util/ConfigUri.java +++ b/src/main/java/com/emc/object/util/ConfigUri.java @@ -131,14 +131,32 @@ public ConfigUri(Class targetClass) { } public C parseUri(String configUri) { - return parseUri(configUri, false); + return parseUri(configUri, null); } - public C parseUri(String configUri, boolean strict) { + public C parseUri(String configUri, C defaults) { + return parseUri(configUri, defaults, false); + } + + public C parseUri(String configUri, C defaultObject, boolean strict) { try { URI uriObj = new URI(configUri); C object = targetClass.newInstance(); + // set defaults + if (defaultObject != null) { + // standard properties + for (PropertyDescriptor descriptor : paramPropertyMap.values()) { + Object defaultValue = descriptor.getReadMethod().invoke(defaultObject); + descriptor.getWriteMethod().invoke(object, defaultValue); + } + // map properties + for (PropertyDescriptor descriptor : mapPropertyMap.values()) { + Object defaultValue = descriptor.getReadMethod().invoke(defaultObject); + descriptor.getWriteMethod().invoke(object, defaultValue); + } + } + if (protocolProperty != null && uriObj.getScheme() != null) setPropertyValues(object, protocolProperty, Collections.singletonList(uriObj.getScheme())); @@ -186,8 +204,12 @@ public C parseUri(String configUri, boolean strict) { } public String generateUri(C object) { + return generateUri(object, null); + } + + public String generateUri(C object, C defaultObject) { try { - C defaultObject = targetClass.newInstance(); + if (defaultObject == null) defaultObject = targetClass.newInstance(); // collect parameters MultivaluedMap params = new MultivaluedMapImpl(); diff --git a/src/test/java/com/emc/object/util/ConfigUriTest.java b/src/test/java/com/emc/object/util/ConfigUriTest.java index ef77bec7..771bdd60 100644 --- a/src/test/java/com/emc/object/util/ConfigUriTest.java +++ b/src/test/java/com/emc/object/util/ConfigUriTest.java @@ -73,7 +73,7 @@ public void testConvertUri() { Assert.assertEquals(uri, dummyUri.generateUri(dummyConfig) + "&blah=blah"); try { - dummyUri.parseUri(uri, true); + dummyUri.parseUri(uri, null, true); Assert.fail("invalid parameter should fail with strict parsing"); } catch (IllegalArgumentException e) { // expected From af570593d51a0fcda478b2e9377519065baa22a8 Mon Sep 17 00:00:00 2001 From: "arnett, stu" Date: Thu, 2 Mar 2017 08:47:51 -0600 Subject: [PATCH 2/4] added target IfNoneMatch and IfMatch options to CopyObjectRequest --- .../object/s3/request/CopyObjectRequest.java | 82 ++++++++++++------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/emc/object/s3/request/CopyObjectRequest.java b/src/main/java/com/emc/object/s3/request/CopyObjectRequest.java index d17a6733..cf28167f 100644 --- a/src/main/java/com/emc/object/s3/request/CopyObjectRequest.java +++ b/src/main/java/com/emc/object/s3/request/CopyObjectRequest.java @@ -42,10 +42,13 @@ public class CopyObjectRequest extends S3ObjectRequest { private String sourceKey; private String sourceVersionId; - private Date ifModifiedSince; - private Date ifUnmodifiedSince; - private String ifMatch; - private String ifNoneMatch; + private Date ifSourceModifiedSince; + private Date ifSourceUnmodifiedSince; + private String ifSourceMatch; + private String ifSourceNoneMatch; + + private String ifTargetMatch; + private String ifTargetNoneMatch; private S3ObjectMetadata objectMetadata; private AccessControlList acl; @@ -65,12 +68,15 @@ public Map> getHeaders() { if (sourceVersionId != null) source += "?versionId=" + sourceVersionId; RestUtil.putSingle(headers, S3Constants.AMZ_COPY_SOURCE, source); - if (ifModifiedSince != null) - RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_MODIFIED_SINCE, ifModifiedSince); - if (ifUnmodifiedSince != null) - RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_UNMODIFIED_SINCE, ifUnmodifiedSince); - if (ifMatch != null) RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_MATCH, ifMatch); - if (ifNoneMatch != null) RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_NONE_MATCH, ifNoneMatch); + if (ifSourceModifiedSince != null) + RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_MODIFIED_SINCE, ifSourceModifiedSince); + if (ifSourceUnmodifiedSince != null) + RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_UNMODIFIED_SINCE, ifSourceUnmodifiedSince); + if (ifSourceMatch != null) RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_MATCH, ifSourceMatch); + if (ifSourceNoneMatch != null) + RestUtil.putSingle(headers, S3Constants.AMZ_SOURCE_NONE_MATCH, ifSourceNoneMatch); + if (ifTargetMatch != null) RestUtil.putSingle(headers, RestUtil.HEADER_IF_MATCH, ifTargetMatch); + if (ifTargetNoneMatch != null) RestUtil.putSingle(headers, RestUtil.HEADER_IF_NONE_MATCH, ifTargetNoneMatch); if (objectMetadata != null) { RestUtil.putSingle(headers, S3Constants.AMZ_METADATA_DIRECTIVE, "REPLACE"); headers.putAll(objectMetadata.toHeaders()); @@ -96,36 +102,52 @@ public void setSourceVersionId(String sourceVersionId) { this.sourceVersionId = sourceVersionId; } - public Date getIfModifiedSince() { - return ifModifiedSince; + public Date getIfSourceModifiedSince() { + return ifSourceModifiedSince; + } + + public void setIfSourceModifiedSince(Date ifSourceModifiedSince) { + this.ifSourceModifiedSince = ifSourceModifiedSince; + } + + public Date getIfSourceUnmodifiedSince() { + return ifSourceUnmodifiedSince; + } + + public void setIfSourceUnmodifiedSince(Date ifSourceUnmodifiedSince) { + this.ifSourceUnmodifiedSince = ifSourceUnmodifiedSince; + } + + public String getIfSourceMatch() { + return ifSourceMatch; } - public void setIfModifiedSince(Date ifModifiedSince) { - this.ifModifiedSince = ifModifiedSince; + public void setIfSourceMatch(String ifSourceMatch) { + this.ifSourceMatch = ifSourceMatch; } - public Date getIfUnmodifiedSince() { - return ifUnmodifiedSince; + public String getIfSourceNoneMatch() { + return ifSourceNoneMatch; } - public void setIfUnmodifiedSince(Date ifUnmodifiedSince) { - this.ifUnmodifiedSince = ifUnmodifiedSince; + public void setIfSourceNoneMatch(String ifSourceNoneMatch) { + this.ifSourceNoneMatch = ifSourceNoneMatch; } - public String getIfMatch() { - return ifMatch; + public String getIfTargetMatch() { + return ifTargetMatch; } - public void setIfMatch(String ifMatch) { - this.ifMatch = ifMatch; + public void setIfTargetMatch(String ifTargetMatch) { + this.ifTargetMatch = ifTargetMatch; } - public String getIfNoneMatch() { - return ifNoneMatch; + public String getIfTargetNoneMatch() { + return ifTargetNoneMatch; } - public void setIfNoneMatch(String ifNoneMatch) { - this.ifNoneMatch = ifNoneMatch; + public void setIfTargetNoneMatch(String ifTargetNoneMatch) { + this.ifTargetNoneMatch = ifTargetNoneMatch; } public S3ObjectMetadata getObjectMetadata() { @@ -158,22 +180,22 @@ public CopyObjectRequest withSourceVersionId(String sourceVersionId) { } public CopyObjectRequest withIfModifiedSince(Date ifModifiedSince) { - setIfModifiedSince(ifModifiedSince); + setIfSourceModifiedSince(ifModifiedSince); return this; } public CopyObjectRequest withIfUnmodifiedSince(Date ifUnmodifiedSince) { - setIfUnmodifiedSince(ifUnmodifiedSince); + setIfSourceUnmodifiedSince(ifUnmodifiedSince); return this; } public CopyObjectRequest withIfMatch(String ifMatch) { - setIfMatch(ifMatch); + setIfSourceMatch(ifMatch); return this; } public CopyObjectRequest withIfNoneMatch(String ifNoneMatch) { - setIfNoneMatch(ifNoneMatch); + setIfSourceNoneMatch(ifNoneMatch); return this; } From 99a47667319c62f460f6f26d9682c37b3e4260c6 Mon Sep 17 00:00:00 2001 From: "arnett, stu" Date: Thu, 2 Mar 2017 08:51:35 -0600 Subject: [PATCH 3/4] Fixed corner case where, if an encrypted write failed (even after retries), and the calling code re-sends the write using the *same request object*, the object is left in an unreadable (but correctable) state. --- .../com/emc/object/s3/jersey/CodecFilter.java | 17 ++- .../s3/S3EncryptionClientBasicTest.java | 105 +++++++++++++++++- .../s3/S3EncryptionUrlConnectionTest.java | 6 +- 3 files changed, 125 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/emc/object/s3/jersey/CodecFilter.java b/src/main/java/com/emc/object/s3/jersey/CodecFilter.java index c54b337d..b35d3683 100644 --- a/src/main/java/com/emc/object/s3/jersey/CodecFilter.java +++ b/src/main/java/com/emc/object/s3/jersey/CodecFilter.java @@ -41,6 +41,7 @@ import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -60,6 +61,7 @@ public CodecFilter(CodecChain encodeChain) { @Override public ClientResponse handle(ClientRequest request) throws ClientHandlerException { Map userMeta = (Map) request.getProperties().get(RestUtil.PROPERTY_USER_METADATA); + Map metaBackup = null; Boolean encode = (Boolean) request.getProperties().get(RestUtil.PROPERTY_ENCODE_ENTITY); if (encode != null && encode) { @@ -75,6 +77,9 @@ public ClientResponse handle(ClientRequest request) throws ClientHandlerExceptio SizeOverrideWriter.setEntitySize(-1L); } + // backup original metadata in case of an error + metaBackup = new HashMap(userMeta); + // we need pre-stream metadata from the encoder, but we don't have the entity output stream, so we'll use // a "dangling" output stream and connect it in the adapter // NOTE: we can't alter the headers in the adapt() method because they've already been a) signed and b) sent @@ -89,7 +94,17 @@ public ClientResponse handle(ClientRequest request) throws ClientHandlerExceptio } // execute request - ClientResponse response = getNext().handle(request); + ClientResponse response; + try { + response = getNext().handle(request); + } catch (RuntimeException e) { + if (encode != null && encode) { + // restore metadata from backup + userMeta.clear(); + userMeta.putAll(metaBackup); + } + throw e; + } // get user metadata from response headers MultivaluedMap headers = response.getHeaders(); diff --git a/src/test/java/com/emc/object/s3/S3EncryptionClientBasicTest.java b/src/test/java/com/emc/object/s3/S3EncryptionClientBasicTest.java index c63c6a71..f123865b 100644 --- a/src/test/java/com/emc/object/s3/S3EncryptionClientBasicTest.java +++ b/src/test/java/com/emc/object/s3/S3EncryptionClientBasicTest.java @@ -26,11 +26,13 @@ */ package com.emc.object.s3; +import com.emc.codec.CodecChain; import com.emc.codec.encryption.BasicKeyProvider; import com.emc.codec.encryption.EncryptionConstants; import com.emc.codec.encryption.EncryptionUtil; import com.emc.object.EncryptionConfig; import com.emc.object.s3.bean.*; +import com.emc.object.s3.jersey.FaultInjectionFilter; import com.emc.object.s3.jersey.S3EncryptionClient; import com.emc.object.s3.jersey.S3JerseyClient; import com.emc.object.s3.request.PutObjectRequest; @@ -43,6 +45,9 @@ import org.junit.Ignore; import org.junit.Test; +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; +import java.io.IOException; import java.io.InputStream; import java.security.KeyPair; import java.security.interfaces.RSAPrivateKey; @@ -58,6 +63,7 @@ public class S3EncryptionClientBasicTest extends S3JerseyClientTest { protected int keySize = 128; protected S3JerseyClient rclient; protected S3EncryptionClient eclient; + protected String encodeSpec; private BasicKeyProvider _keyProvider; private KeyPair _masterKey; @@ -71,7 +77,10 @@ protected String getTestBucketPrefix() { @Override public S3Client createS3Client() throws Exception { rclient = new S3JerseyClient(createS3Config()); - eclient = new S3EncryptionClient(createS3Config(), createEncryptionConfig()); + EncryptionConfig eConfig = createEncryptionConfig(); + eclient = new S3EncryptionClient(createS3Config(), eConfig); + encodeSpec = eConfig.getEncryptionSpec(); + if (eConfig.isCompressionEnabled()) encodeSpec = eConfig.getCompressionSpec() + "," + encodeSpec; return eclient; } @@ -262,6 +271,68 @@ public void testRekeyAcl() throws Exception { Assert.assertTrue(acl.getGrants().contains(new Grant(Group.ALL_USERS, Permission.FULL_CONTROL))); } + @Test + public void testErrorInStream() throws Exception { + byte[] data = "Error in the stream!!".getBytes(); + String key = "stream-error-test"; + + S3Config _config = createS3Config(); + _config.setFaultInjectionRate(1f); + S3Client _client = new S3EncryptionClient(_config, createEncryptionConfig()); + + try { + _client.putObject(getTestBucket(), key, data, null); + } catch (S3Exception e) { + Assert.assertEquals(FaultInjectionFilter.FAULT_INJECTION_ERROR_CODE, e.getErrorCode()); + } + } + + @Test + public void testRetries() throws Exception { + byte[] data = "Testing retries!!".getBytes(); + String key = "retry-test"; + + S3Config _config = createS3Config(); + _config.setFaultInjectionRate(0.4f); + _config.setRetryLimit(4); + S3Client _client = new S3EncryptionClient(_config, createEncryptionConfig()); + + // make sure we hit at least one error + for (int i = 0; i < 5; i++) { + _client.putObject(getTestBucket(), key, data, null); + S3ObjectMetadata metadata = rclient.getObjectMetadata(getTestBucket(), key); + Assert.assertEquals(encodeSpec, metadata.getUserMetadata(CodecChain.META_TRANSFORM_MODE)); + } + } + + @Test + public void testReuseRequestOnError() throws Exception { + byte[] data = "You can reuse the request object on errors".getBytes(); + String key = "request-reuse-test"; + InputStream stream = new ErrorStream(new ByteArrayInputStream(data)); + + PutObjectRequest request = new PutObjectRequest(getTestBucket(), key, stream); + + // first PUT + eclient.getS3Config().setRetryLimit(0); + try { + eclient.putObject(request); + Assert.fail("no error generated"); + } catch (Exception e) { + while (e.getCause() != null && e.getCause() != e) { + e = (Exception) e.getCause(); + } + if (!(e instanceof S3Exception)) throw e; + if (!e.getMessage().equals("foo")) throw e; + // second PUT + eclient.putObject(request); + } + + // check mode UMD + S3ObjectMetadata metadata = rclient.getObjectMetadata(getTestBucket(), key); + Assert.assertEquals(encodeSpec, metadata.getUserMetadata(CodecChain.META_TRANSFORM_MODE)); + } + // the following methods aren't supported in the encryption client @Ignore @@ -476,4 +547,36 @@ public void testPutObjectPreconditions() { @Override public void testCopyObjectSelf() throws Exception { } + + private class ErrorStream extends FilterInputStream { + private int callCount = 0; + + public ErrorStream(InputStream inputStream) { + super(inputStream); + } + + @Override + public int read(byte[] bytes) throws IOException { + return read(bytes, 0, bytes.length); + } + + @Override + public int read(byte[] bytes, int i, int i1) throws IOException { + incCallCount(); + return super.read(bytes, i, i1); + } + + @Override + public int read() throws IOException { + incCallCount(); + return super.read(); + } + + private void incCallCount() { + switch (callCount++) { + case 0: + throw new S3Exception("foo", 500); + } + } + } } diff --git a/src/test/java/com/emc/object/s3/S3EncryptionUrlConnectionTest.java b/src/test/java/com/emc/object/s3/S3EncryptionUrlConnectionTest.java index d73ad9e2..1c869d93 100644 --- a/src/test/java/com/emc/object/s3/S3EncryptionUrlConnectionTest.java +++ b/src/test/java/com/emc/object/s3/S3EncryptionUrlConnectionTest.java @@ -26,6 +26,7 @@ */ package com.emc.object.s3; +import com.emc.object.EncryptionConfig; import com.emc.object.ObjectConfig; import com.emc.object.s3.jersey.S3EncryptionClient; import com.emc.object.s3.jersey.S3JerseyClient; @@ -50,7 +51,10 @@ public S3Client createS3Client() throws Exception { System.setProperty("http.proxyPort", "" + proxyUri.getPort()); } rclient = new S3JerseyClient(config, new URLConnectionClientHandler()); - eclient = new S3EncryptionClient(config, new URLConnectionClientHandler(), createEncryptionConfig()); + EncryptionConfig eConfig = createEncryptionConfig(); + eclient = new S3EncryptionClient(config, new URLConnectionClientHandler(), eConfig); + encodeSpec = eConfig.getEncryptionSpec(); + if (eConfig.isCompressionEnabled()) encodeSpec = eConfig.getCompressionSpec() + "," + encodeSpec; return eclient; } } From ebb7face3d68098eecafed7740417d7fb3bf04c6 Mon Sep 17 00:00:00 2001 From: "arnett, stu" Date: Thu, 2 Mar 2017 10:32:31 -0600 Subject: [PATCH 4/4] updated common-build to 1.6 --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 53319 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 46 ++++++++++++----------- gradlew.bat | 8 ++-- 5 files changed, 32 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 40d91452..6ffaac4a 100644 --- a/build.gradle +++ b/build.gradle @@ -29,7 +29,7 @@ description = 'EMC Object Client for Java - provides REST access to object data ext.githubProjectName = 'ecs-object-client-java' buildscript { - ext.commonBuildVersion = '1.5' + ext.commonBuildVersion = '1.6' ext.commonBuildDir = "https://raw.githubusercontent.com/EMCECS/ecs-common-build/v$commonBuildVersion" apply from: "$commonBuildDir/ecs-publish.buildscript.gradle", to: buildscript } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 941144813d241db74e1bf25b6804c679fbe7f0a3..d3b83982b9b1bccad955349d702be9b884c6e049 100644 GIT binary patch delta 5479 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 A8~^|S delta 5809 zcma)Ac|6qJ_aBq(v2SCUY$3+JM~PxG_Uv0JLiR9r!elQ*d`N|;ELpPiXlz-=gisV& zvSybhkF8R_j~P#W=llKVcVDl0-TONCectDsd(S<0?gyWHEc)3o1|z*=#q!mPjgZ2FKv{ve$WkwyIEguYjV*zZXbdO)0PiZG~V zg!({&XGePT%bELfXpj)K%AKmv*OEY z&i3m@rek|R&od)k-56@9>$lstU>-DLZ*}t-g^VO3u?Aj1jH8mrsTvq8XAgDIMwirX zsdhT5o%2=S>%d=#?Leg`y$PdEA!|(w{{8#ezWu9{zkcj<+&b8^ZkI}Y9)v`)q7+@_Cv^m8&#ZPA3_Jw#x7r#n4R9rHYbm<-m75|s}E zHFs(pwx%8lU0W&nG3ZpNJn^(xo1&q`?b?B>{vUj@B*x)Bo?<9Q6^Ro+w!i(q? zYQYkIvwRh|IT}x$3yLujwbDIWB5@q40t=7oG_AK_l?dO>Jg#l~z zT5HMsN}IlQ>}BsohoEiyvXR336|@&k(x#R}PXraTSmi%KuXeFt7+3WGD^#m~su z4SKjnXGA7B*QEaAvQ&{Wh&KN=F`iq<=2u1@USRjq$-<0U#jW~`g^YZ4RaXF`O466; zg~2u&XAg(_RU5kg?Y@a~w;8B{b!>PjYyh%e@sAH|W2fygdFMu7*sJ3O)ZU_b_=@+m z@%Z{DGpsy0k=CKH{r=pqFdSmd@6o0{&27VC&F?lPn+G>l!;R2-_~bnub-yo+4};z6!^hLy)d?Ir=mr}P5Pr?L!Gb{a$Vum0fa4~hzXuA`E6| zrn2Z7le-c$mrFQ(JnuU*@r9*_;5^()7UY_1QgWDR{idrM^WjNzPXa6CzRkL}>)bA( zxOP%AirWI^$|E&vNLAt0m*&4y$ldVj^haK<8&)xQYtPQ4GFx;T+@x31eU!StevtD` zdcl}1OX*hT$ZZ-1B^g@)gFM?mDfPNV7~!LqvNkQ+X+FK2tQP&XL1aP?zVTqJGTBU8 zlt0q5Y=udavDT&Z>@7z1uRpCc2LC}SBx@#Y96&Ms2PgNss1v2tvkMlcE_m58uk4k7 zic(tyGViT-sYZ+3&oz{Ol0LdJc8aYsMd}pn-Ow&mW=_qG;OLz@6BvOyHB?-ry6x*- z&M~&}*1ulTrp&F=?k6lt*nhXf<=Qdc$5S<<*EYRQuQ7U+htvVAtaKVn6-~ zB_g@IHMkMNE!G>!CNf??!E!*Xx>8Kntc=M;@S7*e@y#%5-B$hc7# zQ=U$1H4u{B;BYl1**CCljQ$rDX@$)Xmcd$7e}Tml%VVF$bBFpM*nNf~! z6K>=2v@e(CN>P>Uc=b@B zq~val^QH+MU&72RIux3dIBkj!h3BN;oHemLxCO_bq1^b5DmvTSGYQ6_qOsEWcQNH1 z8|KD8AJN%zWKJ?IWy*%?&3oZDvN@ZN<99d0TG1l0d>tFe)4?L~4KxgiRtcBTuQA>> zV^)ZlvDd|nd<%-kqBMKaep;<5dcXlvuzgG3v>n*Wz-z@V6c&j1I%Kd3p*&rbYCVkQ zX-7oiGPDb@Rh}As{0IF&3-SAY6yJq~@j2YQSrcb!%kA9vpQ_C+?p$}bRtS}kO%H2B zEGsYvkIT^SK8@@&+bxZJo10!ZiuuXh{vNN}LyJ{?A<5>yDLv(^ICjs!g3Bj^?&%tL z<*LR|V0zPacX4rScJ|xx{BTsQzCmUZLtX%u-RnCown3h6t0<)I@uoBC<|jm&hk;*z zV9SePRxh3U&mQOo7=?fDd;jPBb-Aa%JrKT=IOjUVk?GN6&so@{LBsU)}E(&rys>WzB$k#}D( zrsoSu!ytd*iPp^$Bg%FZ5#boJ$9KiPBTbBWv#NA= zo=Rmpeq&(R?)nSH;cbiyKFfJC5U zL~!96JxlhA7Jty4b4FE(g`X&)-OG=+z4MQI6VA{c&%0KZHlAmgtyX#E8VWJq zK4~_NkBx89L#-t=%#TuHie~5=b$rOPlR2t8oQ5-$RuR0<_u|+Vp+9vzY2^D(>NMp| z3+c_%7WgOFrFv!9Qxr~28=S!*xz~OAuO;q5QSlK1Ha3ozmHvc3_S3I~k|E2fx@~sQ- zE~*KEqO2BQM0yGBsVnQ(pReglj|@o$yEl=a+LVu&+WNM<=PzqbrLu*^i%NRzOt%-= zgtdHiBVQe`m2lN8#B@$LMV7CY4nCS)?g?iR@kn6v9u6RrOPKvJai-g=0aY_|5JXoh zW=a3rJIr$on{h6{qFZ*Y@}18Qe#>NU3+1>$7@|C+m~V!2fzFS=W4$_Dx41l-jLwJs z7&0P4ZOgstRr<-T^G>Rpt%lch$(YSaYHms3*c zWSdsK*Olz_XZ&RWXTEnI7QHlDf3I3oHk`Jmpcl}IOy4o|dU9s|gwa`@4MijQ2sER4RHJjm zWW!kzk?$-wb~oN4fFZS^!OJK-Wm0d*6PO6;%u)NoyZej0Uzq2!upiaqR994ao-FieTdMLpIog?BL*>a8ICTR2 zKi$kn>l*8>@%9gDamM8a+ZYFjb+nkpOe#nG$_TzFCzqzfq~6cdF;M>GnkulkZPBZ- zdtp-5Q9NiJn|5+4bVgw*o4G7!mOPPuaIhi^+ z1q<&0dSe+m8HG79M0dZgfs|;SfwZoEm(B-+zOK(=V!h&BZwzYZp#Kq@HE7Gu8~3&k zv;`*vdTseIhU%W}{7j8o>0&M%4i0?vpDl{IPa2oQV(%gyUqL;#_x&F^ddaI)%d3=y z2NWtMruplqeB9%gQZp(Nmbe6|yZ!up#QANq?=qPh8{30R#sPOtk&G6Rz(9AIdEXA? zDXf_1rfbJ}`l}<7>2L%7FD^*6>$6TXqK0oWd=>Ow+T<6PJ4tn{Imu6^B^VkDT5^Y< zuQ0pFxRsH-vd%E^J=URp`t66a|n{ zCRwfTTuFphlewjm5wRKWywt?eOJCk&#L-y5nWGU`$N&XVwvO39(pZgnPeqh<+ zdyr6k#EeQRWFgLO=58Fx=AKO+jb0bjk`remN}xwJ;>y;KWIL9}o@~ z)u0`3A0>JPDYJngBjc%@1&P&=F#KLw^-@n4J4y znIUE70nWFbB@mK)5FsJlXCe@aGxGp_ZFIz)m}rATCD;ja#&%8u0m+krgrJ2J1hRuK z2o}Jr{fGe54u^8`69_8Wxrn5_pbRZfko{~ICXi|m{Vg;IhA7AhfgngoZz%)nZQOue z2b`!J-T{X`L=u$CI|K<~|EaA1z48FC*&$0XKvH2z4EUNKd3{)Lg@{HHad2puCBcZa zB?HidBd+i7$_o;Z=FA6R2PemWc!2&?Ob7%F=69=!aIyp5*}?(tPC5eca0c8fLSsDY ziAm~q4M^(bAslL;yb}!f8nF3>3;5hAOq4O;;ZPw*;DnOkeO)w#q%6w+XZ+2 z>~FHe|Tq6GAv*@5yNqDPB@^k22WTSyNik|iPe=>{rr z1LAHR09Q8=e2&BA7an{$#(@V+l?0sTL12IF&JAFWz})WamAxSA80el73AoPhw<{aI zOut?EZ2v)I8dUHEEgXI_{I}Iad<-Ng&;|1TW)}$Qx|9l@k%#o)Blce;*w;j`-vlgVRMhK%L(>xpgz-JHL|F?cLnebV0pOsANM_5ZHt-CLPZW%g^jNPwAt;-? z;U!qrdgrv73Iemh_(*{>c}H$j0^E6Y68~8z5A!fcc*e{QtT1p|2t_wtL7YtwOo3*&qk4~eC~Do}wN zkmxy1w05Zv4jry0kkD2i{~wnDh|0sm75)JdohBhVUJp$5X%R`p`{B^Fmjn{G{-aZp i0LnBQ39{~fVZy?ZUSxmRY9hv3z-vvG^6INY;r{_ \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then diff --git a/gradlew.bat b/gradlew.bat index 8a0b282a..832fdb60 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,7 +46,7 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args