diff --git a/config/releaser.yml b/config/releaser.yml index 28b930b7b1..3b7005f0ac 100644 --- a/config/releaser.yml +++ b/config/releaser.yml @@ -1 +1,3 @@ -releaser.maven.buildCommand: ./scripts/noIntegration.sh \ No newline at end of file +releaser.maven.buildCommand: ./scripts/noIntegration.sh +releaser.gradle.gradlePropsSubstitution: + verifierVersion: spring-cloud-contract \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java index 8b8c544059..6331ca6417 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/AetherStubDownloader.java @@ -19,10 +19,17 @@ package org.springframework.cloud.contract.stubrunner; import java.io.File; import java.io.IOException; import java.net.URI; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Queue; +import java.util.concurrent.LinkedBlockingQueue; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; @@ -52,6 +59,13 @@ import static org.springframework.cloud.contract.stubrunner.util.ZipCategory.unz */ public class AetherStubDownloader implements StubDownloader { + /** + * There are problems with removal of stubs unpacked to a temporary folder. + * That's why we're creating a bounded in-memory storage of unpacked files + * and later we register a shutdown hook to remove all these files. + */ + private static final Queue TEMP_FILES_LOG = new LinkedBlockingQueue<>(1000); + private static final Logger log = LoggerFactory.getLogger(AetherStubDownloader.class); private static final String TEMP_DIR_PREFIX = "contracts"; @@ -84,6 +98,7 @@ public class AetherStubDownloader implements StubDownloader { this.repositorySystem = newRepositorySystem(); this.session = newSession(this.repositorySystem, stubRunnerOptions.workOffline); this.workOffline = stubRunnerOptions.workOffline; + registerShutdownHook(); } private boolean remoteReposMissing() { @@ -106,6 +121,7 @@ public class AetherStubDownloader implements StubDownloader { log.error("Remote repositories for stubs are not specified and work offline flag wasn't passed"); } this.workOffline = false; + registerShutdownHook(); } private List remoteRepositories(StubRunnerOptions stubRunnerOptions) { @@ -247,7 +263,49 @@ public class AetherStubDownloader implements StubDownloader { tmpDirWhereStubsWillBeUnzipped.deleteOnExit(); log.info("Unpacking stub from JAR [URI: " + stubJarUri + "]"); unzipTo(new File(stubJarUri), tmpDirWhereStubsWillBeUnzipped); + TEMP_FILES_LOG.add(tmpDirWhereStubsWillBeUnzipped); return tmpDirWhereStubsWillBeUnzipped; } + private void registerShutdownHook() { + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + cleanup(); + } + }); + } + + private void cleanup() { + try { + for (File file : TEMP_FILES_LOG) { + if (file.isDirectory()) { + Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Removing unzipped file [" + file + "]"); + } + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (log.isTraceEnabled()) { + log.trace("Removing unzipped dir [" + dir + "]"); + } + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } else { + Files.delete(file.toPath()); + } + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed to remove temporary file", e); + } + } + } } \ No newline at end of file diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java index 44691ea2d7..7cd47a15ea 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/ClasspathStubProvider.java @@ -2,6 +2,7 @@ package org.springframework.cloud.contract.stubrunner; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.invoke.MethodHandles; import java.nio.file.Files; import java.nio.file.Path; @@ -88,7 +89,9 @@ public class ClasspathStubProvider implements StubDownloaderBuilder { new File(tmp, relativePathWithoutFile).toPath()); File newFile = new File(directory.toFile(), resource.getFilename()); if (!newFile.exists() && !isDirectory(resource)) { - Files.copy(resource.getInputStream(), newFile.toPath()); + try (InputStream stream = resource.getInputStream()) { + Files.copy(stream, newFile.toPath()); + } } if (log.isDebugEnabled()) { log.debug("Stored file [" + newFile + "]"); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/WiremockMappingDescriptor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/WiremockMappingDescriptor.java deleted file mode 100644 index 5a7a759c96..0000000000 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/WiremockMappingDescriptor.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2013-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.stubrunner; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.Charset; - -import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubMapping; -import org.springframework.util.StreamUtils; - -import com.github.tomakehurst.wiremock.stubbing.StubMapping; - -/** - * Represents a single JSON file that was found in the folder with potential WireMock - * stubs - */ -class WiremockMappingDescriptor { - - final File descriptor; - - public WiremockMappingDescriptor(File mappingDescriptor) { - this.descriptor = mappingDescriptor; - } - - public StubMapping getMapping() { - try { - return WireMockStubMapping.buildFrom(StreamUtils.copyToString( - new FileInputStream(this.descriptor), Charset.forName("UTF-8"))); - } - catch (IOException e) { - throw new IllegalStateException("Cannot read file", e); - } - } - - @Override - public String toString() { - return "WiremockMappingDescriptor [descriptor=" + this.descriptor + "]"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this.descriptor == null) ? 0 : this.descriptor.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - WiremockMappingDescriptor other = (WiremockMappingDescriptor) obj; - if (this.descriptor == null) { - if (other.descriptor != null) - return false; - } - else if (!this.descriptor.equals(other.descriptor)) - return false; - return true; - } -} diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java index 7ffbcb3695..dee873ee59 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/provider/wiremock/WireMockHttpServerStub.java @@ -1,9 +1,10 @@ package org.springframework.cloud.contract.stubrunner.provider.wiremock; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -130,9 +131,9 @@ public class WireMockHttpServerStub implements HttpServerStub { } StubMapping getMapping(File file) { - try { - return StubMapping.buildFrom(StreamUtils.copyToString( - new FileInputStream(file), Charset.forName("UTF-8"))); + try (InputStream stream = Files.newInputStream(file.toPath())) { + return StubMapping.buildFrom( + StreamUtils.copyToString(stream, Charset.forName("UTF-8"))); } catch (IOException e) { throw new IllegalStateException("Cannot read file", e); diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java index 9aecc485e9..03af8e75dc 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/util/ZipCategory.java @@ -17,9 +17,10 @@ package org.springframework.cloud.contract.stubrunner.util; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -55,28 +56,28 @@ public class ZipCategory { if (destination == null) destination = new File(self.getParent()); List unzippedFiles = new ArrayList<>(); - try { - ZipInputStream zipInput = new ZipInputStream(new FileInputStream(self)); - for (ZipEntry entry = zipInput.getNextEntry(); entry != null; entry = zipInput - .getNextEntry()) { - if (!entry.isDirectory()) { - final File file = new File(destination, entry.getName()); - if (file.getParentFile() != null) { - file.getParentFile().mkdirs(); + try (InputStream fileInputStream = Files.newInputStream(self.toPath())) { + try (ZipInputStream zipInput = new ZipInputStream(fileInputStream)) { + for (ZipEntry entry = zipInput.getNextEntry(); entry != null; entry = zipInput + .getNextEntry()) { + if (!entry.isDirectory()) { + final File file = new File(destination, entry.getName()); + if (file.getParentFile() != null) { + file.getParentFile().mkdirs(); + } + try (OutputStream output = Files.newOutputStream(file.toPath())) { + StreamUtils.copy(zipInput, output); + } + unzippedFiles.add(file); } - try (FileOutputStream output = new FileOutputStream(file)) { - StreamUtils.copy(zipInput, output); + else { + final File dir = new File(destination, entry.getName()); + dir.mkdirs(); + unzippedFiles.add(dir); } - unzippedFiles.add(file); - } - else { - final File dir = new File(destination, entry.getName()); - dir.mkdirs(); - unzippedFiles.add(dir); } } - } - catch (IOException e) { + } catch (IOException e) { throw new IllegalStateException("Cannot unzip archive", e); } return unzippedFiles; diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy index a7016d8fe6..f55114457b 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy @@ -16,6 +16,8 @@ package org.springframework.cloud.contract.verifier.converter +import java.nio.file.Files + import groovy.transform.CompileStatic import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.ContractConverter @@ -37,7 +39,8 @@ class YamlContractConverter implements ContractConverter> { @Override public Collection convertFrom(File file) { try { - YamlContract yamlContract = new Yaml().loadAs(new FileInputStream(file), YamlContract.class) + YamlContract yamlContract = new Yaml().loadAs( + Files.newInputStream(file.toPath()), YamlContract.class) return [Contract.make { request { method(yamlContract?.request?.method) diff --git a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java index 16289f8b31..c0a4036841 100644 --- a/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java +++ b/spring-cloud-contract-wiremock/src/main/java/org/springframework/cloud/contract/wiremock/restdocs/ContractDslSnippet.java @@ -1,11 +1,11 @@ package org.springframework.cloud.contract.wiremock.restdocs; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URI; +import java.nio.file.Files; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -136,7 +136,7 @@ public class ContractDslSnippet extends TemplatedSnippet { File output = new File(context.getOutputDirectory(), CONTRACTS_FOLDER + "/" + operation.getName() + ".groovy"); output.getParentFile().mkdirs(); - try (Writer writer = new OutputStreamWriter(new FileOutputStream(output))) { + try (Writer writer = new OutputStreamWriter(Files.newOutputStream(output.toPath()))) { writer.append(content); } }